summaryrefslogtreecommitdiff
path: root/spec/ruby/core/complex/plus_spec.rb
AgeCommit message (Expand)Author
2018-09-25Update to ruby/spec@241f9e7eregon
2018-03-04Update to ruby/spec@c1b568beregon
2017-09-20Move spec/rubyspec to spec/ruby for consistencyeregon
>9
-rw-r--r--.document5
-rw-r--r--.gdbinit63
-rw-r--r--.git-blame-ignore-revs5
-rw-r--r--.github/actions/setup/directories/action.yml137
-rw-r--r--.github/actions/setup/macos/action.yml24
-rw-r--r--.github/actions/setup/ubuntu/action.yml53
-rw-r--r--.github/actions/slack/action.yml39
-rw-r--r--.github/auto_request_review.yml13
-rw-r--r--.github/codeql/codeql-config.yml3
-rw-r--r--.github/dependabot.yml4
-rw-r--r--.github/workflows/annocheck.yml123
-rw-r--r--.github/workflows/auto_request_review.yml19
-rw-r--r--.github/workflows/baseruby.yml57
-rw-r--r--.github/workflows/bundled_gems.yml137
-rw-r--r--.github/workflows/check_dependencies.yml57
-rw-r--r--.github/workflows/check_misc.yml115
-rw-r--r--.github/workflows/codeql-analysis.yml132
-rw-r--r--.github/workflows/compilers.yml122
-rw-r--r--.github/workflows/dependabot_automerge.yml30
-rw-r--r--.github/workflows/macos.yml111
-rw-r--r--.github/workflows/mingw.yml124
-rw-r--r--.github/workflows/mjit-bindgen.yml104
-rw-r--r--.github/workflows/mjit.yml113
-rw-r--r--.github/workflows/publish.yml18
-rw-r--r--.github/workflows/rjit-bindgen.yml88
-rw-r--r--.github/workflows/rjit.yml117
-rw-r--r--.github/workflows/scorecards.yml28
-rw-r--r--.github/workflows/spec_guards.yml29
-rw-r--r--.github/workflows/ubuntu.yml143
-rw-r--r--.github/workflows/wasm.yml82
-rw-r--r--.github/workflows/windows.yml149
-rw-r--r--.github/workflows/yjit-macos.yml149
-rw-r--r--.github/workflows/yjit-ubuntu.yml188
-rw-r--r--.gitignore38
-rw-r--r--.travis.yml147
-rw-r--r--LEGAL28
-rw-r--r--NEWS.md1016
-rw-r--r--README.ja.md28
-rw-r--r--README.md19
-rw-r--r--addr2line.c817
-rw-r--r--addr2line.h4
-rw-r--r--array.c725
-rw-r--r--array.rb88
-rw-r--r--ast.c284
-rw-r--r--ast.rb20
-rw-r--r--benchmark/enum_sort_by.yml53
-rw-r--r--benchmark/lib/benchmark_driver/runner/mjit.rb34
-rw-r--r--benchmark/loop_generator.rb2
-rw-r--r--benchmark/mjit_exivar.yml18
-rw-r--r--benchmark/mjit_integer.yml32
-rw-r--r--benchmark/mjit_kernel.yml20
-rw-r--r--benchmark/mjit_leave.yml8
-rw-r--r--benchmark/mjit_opt_cc_insns.yml27
-rw-r--r--benchmark/mjit_struct_aref.yml10
-rw-r--r--benchmark/range_bsearch_bignum.yml10
-rw-r--r--benchmark/range_bsearch_endpointless.yml21
-rw-r--r--benchmark/range_bsearch_fixnum.yml10
-rw-r--r--benchmark/range_count.yml11
-rw-r--r--benchmark/range_overlap.yml19
-rw-r--r--benchmark/range_reverse_each.yml16
-rw-r--r--benchmark/regexp_dup.yml6
-rw-r--r--benchmark/regexp_new.yml7
-rw-r--r--benchmark/so_count_words.yml33
-rw-r--r--benchmark/so_meteor_contest.rb2
-rw-r--r--benchmark/string_concat.yml6
-rw-r--r--benchmark/string_rpartition.yml18
-rw-r--r--benchmark/vm_call_bmethod.yml37
-rw-r--r--benchmark/vm_call_method_missing.yml62
-rw-r--r--benchmark/vm_call_send_iseq.yml77
-rw-r--r--benchmark/vm_call_symproc.yml83
-rw-r--r--benchmark/vm_ivar_ic_miss.yml20
-rw-r--r--benchmark/vm_ivar_memoize.yml85
-rw-r--r--benchmark/vm_send_cfunc.yml15
-rw-r--r--bignum.c21
-rwxr-xr-xbin/gem2
-rwxr-xr-xbootstraptest/runner.rb4
-rw-r--r--bootstraptest/test_gc.rb2
-rw-r--r--bootstraptest/test_insns.rb14
-rw-r--r--bootstraptest/test_load.rb2
-rw-r--r--bootstraptest/test_ractor.rb163
-rw-r--r--bootstraptest/test_rjit.rb44
-rw-r--r--bootstraptest/test_syntax.rb4
-rw-r--r--bootstraptest/test_thread.rb19
-rw-r--r--bootstraptest/test_yjit.rb709
-rw-r--r--builtin.c9
-rw-r--r--builtin.h6
-rw-r--r--class.c131
-rw-r--r--common.mk3750
-rw-r--r--compar.c12
-rw-r--r--compile.c1857
-rw-r--r--complex.c17
-rw-r--r--configure.ac351
-rw-r--r--constant.h2
-rw-r--r--cont.c200
-rw-r--r--coroutine/amd64/Context.S42
-rw-r--r--coroutine/asyncify/Context.h8
-rw-r--r--coroutine/loongarch64/Context.S73
-rw-r--r--coroutine/loongarch64/Context.h46
-rw-r--r--coroutine/ppc/Context.S2
-rw-r--r--coroutine/ppc/Context.h2
-rw-r--r--coroutine/ppc64/Context.h2
-rw-r--r--cygwin/GNUmakefile.in6
-rw-r--r--darray.h183
-rw-r--r--debug.c140
-rw-r--r--debug_counter.c2
-rw-r--r--debug_counter.h59
-rw-r--r--defs/gmake.mk177
-rw-r--r--defs/id.def2
-rw-r--r--defs/tags.mk18
-rw-r--r--defs/universal.mk5
-rw-r--r--dir.c788
-rw-r--r--dir.rb377
-rw-r--r--dln.c6
-rw-r--r--dln_find.c2
-rw-r--r--doc/.document1
-rw-r--r--doc/ChangeLog-0.06_to_0.52 (renamed from doc/ChangeLog/ChangeLog-0.06_to_0.52)0
-rw-r--r--doc/ChangeLog-0.50_to_0.60 (renamed from doc/ChangeLog/ChangeLog-0.50_to_0.60)0
-rw-r--r--doc/ChangeLog-0.60_to_1.1 (renamed from doc/ChangeLog/ChangeLog-0.60_to_1.1)0
-rw-r--r--doc/ChangeLog-1.8.0 (renamed from doc/ChangeLog/ChangeLog-1.8.0)0
-rw-r--r--doc/ChangeLog-1.9.3 (renamed from doc/ChangeLog/ChangeLog-1.9.3)0
-rw-r--r--doc/ChangeLog-2.0.0 (renamed from doc/ChangeLog/ChangeLog-2.0.0)0
-rw-r--r--doc/ChangeLog-2.1.0 (renamed from doc/ChangeLog/ChangeLog-2.1.0)0
-rw-r--r--doc/ChangeLog-2.2.0 (renamed from doc/ChangeLog/ChangeLog-2.2.0)0
-rw-r--r--doc/ChangeLog-2.3.0 (renamed from doc/ChangeLog/ChangeLog-2.3.0)0
-rw-r--r--doc/ChangeLog-2.4.0 (renamed from doc/ChangeLog/ChangeLog-2.4.0)0
-rw-r--r--doc/ChangeLog-YARV (renamed from doc/ChangeLog/ChangeLog-YARV)0
-rw-r--r--doc/NEWS/NEWS-3.2.0.md820
-rw-r--r--doc/command_injection.rdoc2
-rw-r--r--doc/contributing/building_ruby.md122
-rw-r--r--doc/contributing/documentation_guide.md109
-rw-r--r--doc/contributing/glossary.md41
-rw-r--r--doc/contributing/making_changes_to_stdlibs.md2
-rw-r--r--doc/contributing/testing_ruby.md36
-rw-r--r--doc/csv/options/common/col_sep.rdoc6
-rw-r--r--doc/csv/options/common/row_sep.rdoc9
-rw-r--r--doc/csv/options/generating/write_converters.rdoc8
-rw-r--r--doc/csv/options/generating/write_headers.rdoc2
-rw-r--r--doc/csv/options/parsing/liberal_parsing.rdoc23
-rw-r--r--doc/csv/recipes/filtering.rdoc2
-rw-r--r--doc/csv/recipes/generating.rdoc4
-rw-r--r--doc/csv/recipes/parsing.rdoc4
-rw-r--r--doc/csv/recipes/recipes.rdoc2
-rw-r--r--doc/distribution.md47
-rw-r--r--doc/encodings.rdoc10
-rw-r--r--doc/extension.ja.rdoc10
-rw-r--r--doc/extension.rdoc162
-rw-r--r--doc/globals.rdoc491
-rw-r--r--doc/irb/irb.rd.ja4
-rw-r--r--doc/maintainers.md520
-rw-r--r--doc/maintainers.rdoc424
-rw-r--r--doc/mjit/mjit.md39
-rw-r--r--doc/optparse/argument_converters.rdoc70
-rw-r--r--doc/optparse/option_params.rdoc4
-rw-r--r--doc/optparse/tutorial.rdoc70
-rw-r--r--doc/packed_data.rdoc41
-rw-r--r--doc/ractor.md8
-rw-r--r--doc/rdoc/markup_reference.rb6
-rw-r--r--doc/regexp.rdoc1710
-rw-r--r--doc/regexp/methods.rdoc41
-rw-r--r--doc/regexp/unicode_properties.rdoc678
-rw-r--r--doc/reline/face.md108
-rw-r--r--doc/rjit/README.md53
-rw-r--r--doc/standard_library.rdoc18
-rw-r--r--doc/string/encode.rdoc47
-rw-r--r--doc/string/length.rdoc1
-rw-r--r--doc/syntax.rdoc3
-rw-r--r--doc/syntax/assignment.rdoc6
-rw-r--r--doc/syntax/comments.rdoc2
-rw-r--r--doc/syntax/control_expressions.rdoc68
-rw-r--r--doc/syntax/literals.rdoc12
-rw-r--r--doc/syntax/modules_and_classes.rdoc28
-rw-r--r--doc/syntax/operators.rdoc75
-rw-r--r--doc/syntax/pattern_matching.rdoc28
-rw-r--r--doc/syntax/refinements.rdoc2
-rw-r--r--doc/transcode.rdoc52
-rw-r--r--doc/windows.md233
-rw-r--r--doc/yjit/yjit.md79
-rw-r--r--enc/Makefile.in2
-rw-r--r--enc/depend207
-rw-r--r--enc/trans/big5-uao-tbl.rb2
-rw-r--r--enc/trans/cp850-tbl.rb2
-rw-r--r--enc/trans/cp852-tbl.rb2
-rw-r--r--enc/trans/cp855-tbl.rb2
-rw-r--r--enc/trans/gbk-tbl.rb2
-rw-r--r--enc/trans/ibm437-tbl.rb2
-rw-r--r--enc/trans/ibm775-tbl.rb2
-rw-r--r--enc/trans/ibm852-tbl.rb2
-rw-r--r--enc/trans/ibm855-tbl.rb2
-rw-r--r--enc/trans/ibm857-tbl.rb2
-rw-r--r--enc/trans/ibm860-tbl.rb2
-rw-r--r--enc/trans/ibm861-tbl.rb2
-rw-r--r--enc/trans/ibm862-tbl.rb2
-rw-r--r--enc/trans/ibm863-tbl.rb2
-rw-r--r--enc/trans/ibm865-tbl.rb2
-rw-r--r--enc/trans/ibm866-tbl.rb2
-rw-r--r--enc/trans/ibm869-tbl.rb2
-rw-r--r--enc/trans/koi8-r-tbl.rb2
-rw-r--r--enc/trans/koi8-u-tbl.rb2
-rw-r--r--enc/trans/maccroatian-tbl.rb2
-rw-r--r--enc/trans/maccyrillic-tbl.rb2
-rw-r--r--enc/trans/macgreek-tbl.rb2
-rw-r--r--enc/trans/maciceland-tbl.rb2
-rw-r--r--enc/trans/macroman-tbl.rb2
-rw-r--r--enc/trans/macromania-tbl.rb2
-rw-r--r--enc/trans/macturkish-tbl.rb2
-rw-r--r--enc/trans/macukraine-tbl.rb2
-rw-r--r--enc/trans/windows-1250-tbl.rb2
-rw-r--r--enc/trans/windows-1251-tbl.rb2
-rw-r--r--enc/trans/windows-1252-tbl.rb2
-rw-r--r--enc/trans/windows-1253-tbl.rb2
-rw-r--r--enc/trans/windows-1254-tbl.rb2
-rw-r--r--enc/trans/windows-1256-tbl.rb2
-rw-r--r--enc/trans/windows-1257-tbl.rb2
-rw-r--r--enc/trans/windows-874-tbl.rb2
-rw-r--r--enc/unicode/15.0.0/name2ctype.h2
-rw-r--r--encoding.c43
-rw-r--r--enum.c265
-rw-r--r--enumerator.c93
-rw-r--r--error.c397
-rw-r--r--eval.c66
-rw-r--r--eval_error.c26
-rw-r--r--eval_intern.h4
-rw-r--r--ext/-test-/RUBY_ALIGNOF/depend3
-rw-r--r--ext/-test-/arith_seq/beg_len_step/depend3
-rw-r--r--ext/-test-/arith_seq/extract/depend3
-rw-r--r--ext/-test-/array/concat/depend3
-rw-r--r--ext/-test-/array/resize/depend3
-rw-r--r--ext/-test-/bignum/depend21
-rw-r--r--ext/-test-/bug-14834/depend3
-rw-r--r--ext/-test-/bug-3571/depend3
-rw-r--r--ext/-test-/bug-5832/depend3
-rw-r--r--ext/-test-/bug_reporter/depend3
-rw-r--r--ext/-test-/class/depend6
-rw-r--r--ext/-test-/debug/depend9
-rw-r--r--ext/-test-/debug/profile_frames.c21
-rw-r--r--ext/-test-/dln/empty/depend3
-rw-r--r--ext/-test-/enumerator_kw/depend3
-rw-r--r--ext/-test-/exception/depend12
-rw-r--r--ext/-test-/fatal/depend3
-rw-r--r--ext/-test-/file/depend9
-rw-r--r--ext/-test-/float/depend6
-rw-r--r--ext/-test-/funcall/depend3
-rw-r--r--ext/-test-/gvl/call_without_gvl/depend3
-rw-r--r--ext/-test-/hash/depend6
-rw-r--r--ext/-test-/integer/depend9
-rw-r--r--ext/-test-/iseq_load/depend3
-rw-r--r--ext/-test-/iter/depend9
-rw-r--r--ext/-test-/load/dot.dot/depend3
-rw-r--r--ext/-test-/load/protect/depend3
-rw-r--r--ext/-test-/marshal/compat/depend3
-rw-r--r--ext/-test-/marshal/internal_ivar/depend3
-rw-r--r--ext/-test-/marshal/usr/depend3
-rw-r--r--ext/-test-/memory_status/depend3
-rw-r--r--ext/-test-/memory_view/depend3
-rw-r--r--ext/-test-/method/depend6
-rw-r--r--ext/-test-/notimplement/depend3
-rw-r--r--ext/-test-/num2int/depend3
-rw-r--r--ext/-test-/path_to_class/depend3
-rw-r--r--ext/-test-/popen_deadlock/depend3
-rw-r--r--ext/-test-/postponed_job/depend3
-rw-r--r--ext/-test-/printf/depend3
-rw-r--r--ext/-test-/proc/depend9
-rw-r--r--ext/-test-/random/depend9
-rw-r--r--ext/-test-/rational/depend3
-rw-r--r--ext/-test-/rb_call_super_kw/depend3
-rw-r--r--ext/-test-/recursion/depend3
-rw-r--r--ext/-test-/regexp/depend6
-rw-r--r--ext/-test-/scan_args/depend3
-rw-r--r--ext/-test-/st/foreach/depend3
-rw-r--r--ext/-test-/st/foreach/foreach.c30
-rw-r--r--ext/-test-/st/numhash/depend3
-rw-r--r--ext/-test-/st/update/depend3
-rw-r--r--ext/-test-/string/cstr.c14
-rw-r--r--ext/-test-/string/depend222
-rw-r--r--ext/-test-/string/enc_dummy.c15
-rw-r--r--ext/-test-/string/fstring.c14
-rw-r--r--ext/-test-/struct/data.c13
-rw-r--r--ext/-test-/struct/depend171
-rw-r--r--ext/-test-/symbol/depend6
-rw-r--r--ext/-test-/thread/instrumentation/depend3
-rw-r--r--ext/-test-/thread/instrumentation/instrumentation.c9
-rw-r--r--ext/-test-/thread_fd/depend3
-rw-r--r--ext/-test-/time/depend9
-rw-r--r--ext/-test-/tracepoint/depend6
-rw-r--r--ext/-test-/typeddata/depend3
-rw-r--r--ext/-test-/vm/depend3
-rw-r--r--ext/-test-/wait/depend3
-rw-r--r--ext/.document6
-rw-r--r--ext/Setup3
-rw-r--r--ext/Setup.atheos6
-rw-r--r--ext/Setup.nt6
-rw-r--r--ext/bigdecimal/bigdecimal.c159
-rw-r--r--ext/bigdecimal/bigdecimal.gemspec40
-rw-r--r--ext/bigdecimal/depend7
-rw-r--r--ext/bigdecimal/extconf.rb25
-rw-r--r--ext/bigdecimal/lib/bigdecimal.rb6
-rw-r--r--ext/bigdecimal/lib/bigdecimal/util.rb10
-rw-r--r--ext/cgi/escape/depend3
-rw-r--r--ext/cgi/escape/escape.c2
-rw-r--r--ext/cgi/escape/extconf.rb6
-rw-r--r--ext/continuation/depend3
-rw-r--r--ext/coverage/coverage.c5
-rw-r--r--ext/coverage/depend17
-rw-r--r--ext/date/date_core.c23
-rw-r--r--ext/date/depend12
-rw-r--r--ext/date/lib/date.rb2
-rw-r--r--ext/digest/bubblebabble/depend3
-rw-r--r--ext/digest/depend3
-rw-r--r--ext/digest/digest.h3
-rw-r--r--ext/digest/md5/depend6
-rw-r--r--ext/digest/rmd160/depend6
-rw-r--r--ext/digest/sha1/depend6
-rw-r--r--ext/digest/sha2/depend6
-rw-r--r--ext/etc/depend3
-rw-r--r--ext/etc/etc.c20
-rw-r--r--ext/etc/extconf.rb14
-rwxr-xr-xext/extmk.rb45
-rw-r--r--ext/fcntl/depend3
-rw-r--r--ext/fcntl/fcntl.c6
-rw-r--r--ext/fcntl/fcntl.gemspec12
-rw-r--r--ext/fiddle/closure.c33
-rw-r--r--ext/fiddle/conversions.c55
-rw-r--r--ext/fiddle/conversions.h2
-rw-r--r--ext/fiddle/depend24
-rw-r--r--ext/fiddle/extconf.rb5
-rw-r--r--ext/fiddle/fiddle.c53
-rw-r--r--ext/fiddle/fiddle.h18
-rw-r--r--ext/fiddle/function.c9
-rw-r--r--ext/fiddle/handle.c9
-rw-r--r--ext/fiddle/lib/fiddle/cparser.rb28
-rw-r--r--ext/fiddle/lib/fiddle/import.rb2
-rw-r--r--ext/fiddle/lib/fiddle/pack.rb12
-rw-r--r--ext/fiddle/lib/fiddle/value.rb28
-rw-r--r--ext/fiddle/lib/fiddle/version.rb2
-rw-r--r--ext/fiddle/pointer.c50
-rwxr-xr-xext/fiddle/win32/libffi-config.rb10
-rw-r--r--ext/io/console/.document2
-rw-r--r--ext/io/console/console.c645
-rw-r--r--ext/io/console/depend5
-rw-r--r--ext/io/console/extconf.rb13
-rw-r--r--ext/io/console/io-console.gemspec20
-rw-r--r--ext/io/console/win32_vk.inc327
-rw-r--r--ext/io/console/win32_vk.list2
-rw-r--r--ext/io/nonblock/depend3
-rw-r--r--ext/io/nonblock/extconf.rb7
-rw-r--r--ext/io/nonblock/nonblock.c71
-rw-r--r--ext/io/wait/depend3
-rw-r--r--ext/io/wait/extconf.rb3
-rw-r--r--ext/io/wait/wait.c11
-rw-r--r--ext/json/generator/depend3
-rw-r--r--ext/json/generator/generator.c1
-rw-r--r--ext/json/json.gemspec6
-rw-r--r--ext/json/lib/json/add/bigdecimal.rb7
-rw-r--r--ext/json/lib/json/add/range.rb29
-rw-r--r--ext/json/lib/json/common.rb28
-rw-r--r--ext/json/parser/depend3
-rw-r--r--ext/json/parser/extconf.rb4
-rw-r--r--ext/json/parser/parser.c4792
-rw-r--r--ext/json/parser/parser.rl161
-rw-r--r--ext/monitor/depend3
-rw-r--r--ext/monitor/lib/monitor.rb13
-rw-r--r--ext/monitor/monitor.c2
-rw-r--r--ext/nkf/depend3
-rw-r--r--ext/nkf/nkf.c3
-rw-r--r--ext/nkf/nkf.gemspec13
-rw-r--r--ext/objspace/depend56
-rw-r--r--ext/objspace/lib/objspace.rb35
-rw-r--r--ext/objspace/object_tracing.c2
-rw-r--r--ext/objspace/objspace.c7
-rw-r--r--ext/objspace/objspace_dump.c27
-rw-r--r--ext/openssl/History.md40
-rw-r--r--ext/openssl/depend322
-rw-r--r--ext/openssl/extconf.rb43
-rw-r--r--ext/openssl/lib/openssl/buffering.rb7
-rw-r--r--ext/openssl/lib/openssl/digest.rb6
-rw-r--r--ext/openssl/lib/openssl/ssl.rb20
-rw-r--r--ext/openssl/lib/openssl/version.rb2
-rw-r--r--ext/openssl/openssl.gemspec20
-rw-r--r--ext/openssl/ossl.c268
-rw-r--r--ext/openssl/ossl.h11
-rw-r--r--ext/openssl/ossl_bn.c2
-rw-r--r--ext/openssl/ossl_cipher.c2
-rw-r--r--ext/openssl/ossl_config.c2
-rw-r--r--ext/openssl/ossl_digest.c2
-rw-r--r--ext/openssl/ossl_engine.c2
-rw-r--r--ext/openssl/ossl_hmac.c2
-rw-r--r--ext/openssl/ossl_kdf.c2
-rw-r--r--ext/openssl/ossl_ns_spki.c2
-rw-r--r--ext/openssl/ossl_ocsp.c12
-rw-r--r--ext/openssl/ossl_pkcs12.c2
-rw-r--r--ext/openssl/ossl_pkcs7.c6
-rw-r--r--ext/openssl/ossl_pkey.c261
-rw-r--r--ext/openssl/ossl_pkey_dh.c29
-rw-r--r--ext/openssl/ossl_pkey_dsa.c65
-rw-r--r--ext/openssl/ossl_pkey_ec.c74
-rw-r--r--ext/openssl/ossl_pkey_rsa.c81
-rw-r--r--ext/openssl/ossl_provider.c211
-rw-r--r--ext/openssl/ossl_provider.h5
-rw-r--r--ext/openssl/ossl_ssl.c148
-rw-r--r--ext/openssl/ossl_ssl_session.c2
-rw-r--r--ext/openssl/ossl_ts.c6
-rw-r--r--ext/openssl/ossl_x509attr.c2
-rw-r--r--ext/openssl/ossl_x509cert.c2
-rw-r--r--ext/openssl/ossl_x509crl.c2
-rw-r--r--ext/openssl/ossl_x509ext.c20
-rw-r--r--ext/openssl/ossl_x509name.c2
-rw-r--r--ext/openssl/ossl_x509req.c2
-rw-r--r--ext/openssl/ossl_x509revoked.c2
-rw-r--r--ext/openssl/ossl_x509store.c17
-rw-r--r--ext/pathname/depend3
-rw-r--r--ext/pathname/lib/pathname.rb2
-rw-r--r--ext/pathname/pathname.c28
-rw-r--r--ext/pathname/pathname.gemspec11
-rw-r--r--ext/psych/depend15
-rw-r--r--ext/psych/extconf.rb2
-rw-r--r--ext/psych/lib/psych.rb42
-rw-r--r--ext/psych/lib/psych/class_loader.rb2
-rw-r--r--ext/psych/lib/psych/tree_builder.rb4
-rw-r--r--ext/psych/lib/psych/versions.rb4
-rw-r--r--ext/psych/lib/psych/visitors/yaml_tree.rb4
-rw-r--r--ext/psych/psych.gemspec50
-rw-r--r--ext/pty/depend3
-rw-r--r--ext/pty/pty.c54
-rw-r--r--ext/racc/cparse/README11
-rw-r--r--ext/racc/cparse/cparse.c861
-rw-r--r--ext/racc/cparse/depend162
-rw-r--r--ext/racc/cparse/extconf.rb9
-rw-r--r--ext/rbconfig/sizeof/depend6
-rw-r--r--ext/readline/.gitignore1
-rw-r--r--ext/readline/README10
-rw-r--r--ext/readline/README.ja386
-rw-r--r--ext/readline/depend175
-rw-r--r--ext/readline/depend-gem4
-rw-r--r--ext/readline/extconf.rb112
-rw-r--r--ext/readline/readline-ext.gemspec22
-rw-r--r--ext/readline/readline.c2144
-rw-r--r--ext/ripper/README1
-rw-r--r--ext/ripper/depend563
-rw-r--r--ext/ripper/eventids2.c12
-rw-r--r--ext/ripper/eventids2.h8
-rw-r--r--ext/ripper/extconf.rb15
-rw-r--r--ext/ripper/lib/ripper/lexer.rb7
-rw-r--r--ext/ripper/ripper_init.c.tmpl618
-rw-r--r--ext/ripper/ripper_init.h8
-rw-r--r--ext/ripper/tools/dsl.rb21
-rw-r--r--ext/ripper/tools/generate.rb39
-rw-r--r--ext/ripper/tools/preproc.rb70
-rw-r--r--ext/socket/ancdata.c4
-rw-r--r--ext/socket/depend300
-rw-r--r--ext/socket/extconf.rb27
-rw-r--r--ext/socket/getaddrinfo.c3
-rw-r--r--ext/socket/init.c20
-rw-r--r--ext/socket/raddrinfo.c515
-rw-r--r--ext/socket/rubysocket.h2
-rw-r--r--ext/socket/socket.c3
-rw-r--r--ext/socket/unixsocket.c2
-rw-r--r--ext/stringio/depend3
-rw-r--r--ext/stringio/extconf.rb1
-rw-r--r--ext/stringio/stringio.c227
-rw-r--r--ext/stringio/stringio.gemspec8
-rw-r--r--ext/strscan/depend3
-rw-r--r--ext/strscan/extconf.rb4
-rw-r--r--ext/strscan/strscan.c2
-rw-r--r--ext/syslog/depend3
-rw-r--r--ext/syslog/syslog.c4
-rw-r--r--ext/syslog/syslog.gemspec9
-rw-r--r--ext/win32/lib/win32/registry.rb13
-rw-r--r--ext/win32ole/win32ole.c2
-rw-r--r--ext/win32ole/win32ole.gemspec12
-rw-r--r--ext/zlib/depend3
-rw-r--r--ext/zlib/extconf.rb17
-rw-r--r--ext/zlib/zlib.c8
-rw-r--r--ext/zlib/zlib.gemspec2
-rw-r--r--file.c514
-rw-r--r--gc.c2808
-rw-r--r--gc.h147
-rw-r--r--gc.rb102
-rw-r--r--gem_prelude.rb2
-rw-r--r--gems/bundled_gems31
-rw-r--r--gems/lib/envutil.rb1
-rw-r--r--gems/lib/rake/extensiontask.rb2
-rw-r--r--hash.c800
-rw-r--r--id_table.c6
-rw-r--r--include/ruby/backward/2/attributes.h24
-rw-r--r--include/ruby/debug.h25
-rw-r--r--include/ruby/fiber/scheduler.h78
-rw-r--r--include/ruby/intern.h1
-rw-r--r--include/ruby/internal/abi.h2
-rw-r--r--include/ruby/internal/anyargs.h22
-rw-r--r--include/ruby/internal/attr/nonstring.h32
-rw-r--r--include/ruby/internal/attr/packed_struct.h43
-rw-r--r--include/ruby/internal/config.h4
-rw-r--r--include/ruby/internal/core/rarray.h198
-rw-r--r--include/ruby/internal/core/rfile.h4
-rw-r--r--include/ruby/internal/core/rhash.h13
-rw-r--r--include/ruby/internal/core/rmatch.h14
-rw-r--r--include/ruby/internal/core/robject.h26
-rw-r--r--include/ruby/internal/core/rstring.h118
-rw-r--r--include/ruby/internal/core/rtypeddata.h57
-rw-r--r--include/ruby/internal/dllexport.h34
-rw-r--r--include/ruby/internal/encoding/encoding.h17
-rw-r--r--include/ruby/internal/encoding/string.h2
-rw-r--r--include/ruby/internal/error.h36
-rw-r--r--include/ruby/internal/event.h5
-rw-r--r--include/ruby/internal/fl_type.h71
-rw-r--r--include/ruby/internal/gc.h779
-rw-r--r--include/ruby/internal/has/c_attribute.h12
-rw-r--r--include/ruby/internal/intern/bignum.h2
-rw-r--r--include/ruby/internal/intern/error.h2
-rw-r--r--include/ruby/internal/intern/gc.h392
-rw-r--r--include/ruby/internal/intern/process.h9
-rw-r--r--include/ruby/internal/intern/re.h5
-rw-r--r--include/ruby/internal/intern/signal.h6
-rw-r--r--include/ruby/internal/intern/struct.h30
-rw-r--r--include/ruby/internal/newobj.h4
-rw-r--r--include/ruby/internal/rgengc.h443
-rw-r--r--include/ruby/io.h102
-rw-r--r--include/ruby/io/buffer.h10
-rw-r--r--include/ruby/memory_view.h4
-rw-r--r--include/ruby/onigmo.h4
-rw-r--r--include/ruby/re.h25
-rw-r--r--include/ruby/ruby.h25
-rw-r--r--include/ruby/st.h4
-rw-r--r--include/ruby/thread.h34
-rw-r--r--include/ruby/thread_native.h5
-rw-r--r--include/ruby/util.h9
-rw-r--r--include/ruby/version.h2
-rw-r--r--include/ruby/win32.h15
-rw-r--r--inits.c12
-rw-r--r--insns.def91
-rw-r--r--internal.h1
-rw-r--r--internal/array.h32
-rw-r--r--internal/basic_operators.h3
-rw-r--r--internal/bignum.h2
-rw-r--r--internal/bits.h31
-rw-r--r--internal/class.h87
-rw-r--r--internal/cmdlineopt.h12
-rw-r--r--internal/compile.h3
-rw-r--r--internal/error.h26
-rw-r--r--internal/eval.h1
-rw-r--r--internal/gc.h230
-rw-r--r--internal/hash.h93
-rw-r--r--internal/imemo.h4
-rw-r--r--internal/io.h99
-rw-r--r--internal/numeric.h2
-rw-r--r--internal/object.h2
-rw-r--r--internal/parse.h97
-rw-r--r--internal/proc.h2
-rw-r--r--internal/process.h15
-rw-r--r--internal/range.h4
-rw-r--r--internal/rational.h1
-rw-r--r--internal/re.h4
-rw-r--r--internal/ruby_parser.h69
-rw-r--r--internal/sanitizers.h4
-rw-r--r--internal/signal.h4
-rw-r--r--internal/string.h17
-rw-r--r--internal/struct.h44
-rw-r--r--internal/thread.h23
-rw-r--r--internal/time.h5
-rw-r--r--internal/variable.h56
-rw-r--r--internal/vm.h23
-rw-r--r--io.c769
-rw-r--r--io.rb13
-rw-r--r--io_buffer.c206
-rw-r--r--iseq.c480
-rw-r--r--iseq.h20
-rw-r--r--kernel.rb160
-rw-r--r--lib/English.gemspec4
-rw-r--r--lib/English.rb60
-rw-r--r--lib/abbrev.gemspec11
-rw-r--r--lib/abbrev.rb1
-rw-r--r--lib/base64.gemspec13
-rw-r--r--lib/base64.rb373
-rw-r--r--lib/benchmark.gemspec30
-rw-r--r--lib/benchmark.rb2
-rw-r--r--lib/benchmark/benchmark.gemspec29
-rw-r--r--lib/benchmark/version.rb4
-rw-r--r--lib/bundled_gems.rb134
-rw-r--r--lib/bundler.rb20
-rw-r--r--lib/bundler/build_metadata.rb2
-rw-r--r--lib/bundler/checksum.rb235
-rw-r--r--lib/bundler/cli.rb2
-rw-r--r--lib/bundler/cli/check.rb2
-rw-r--r--lib/bundler/cli/gem.rb9
-rw-r--r--lib/bundler/cli/info.rb2
-rw-r--r--lib/bundler/cli/install.rb4
-rw-r--r--lib/bundler/cli/issue.rb2
-rw-r--r--lib/bundler/cli/lock.rb49
-rw-r--r--lib/bundler/cli/open.rb12
-rw-r--r--lib/bundler/cli/show.rb4
-rw-r--r--lib/bundler/cli/update.rb1
-rw-r--r--lib/bundler/compact_index_client/cache.rb6
-rw-r--r--lib/bundler/compact_index_client/gem_parser.rb10
-rw-r--r--lib/bundler/compact_index_client/updater.rb7
-rw-r--r--lib/bundler/constants.rb2
-rw-r--r--lib/bundler/current_ruby.rb24
-rw-r--r--lib/bundler/definition.rb77
-rw-r--r--lib/bundler/dependency.rb3
-rw-r--r--lib/bundler/digest.rb2
-rw-r--r--lib/bundler/endpoint_specification.rb9
-rw-r--r--lib/bundler/env.rb8
-rw-r--r--lib/bundler/errors.rb58
-rw-r--r--lib/bundler/fetcher.rb71
-rw-r--r--lib/bundler/fetcher/base.rb4
-rw-r--r--lib/bundler/fetcher/compact_index.rb8
-rw-r--r--lib/bundler/fetcher/dependency.rb2
-rw-r--r--lib/bundler/friendly_errors.rb6
-rw-r--r--lib/bundler/gem_helpers.rb7
-rw-r--r--lib/bundler/gem_version_promoter.rb4
-rw-r--r--lib/bundler/index.rb96
-rw-r--r--lib/bundler/injector.rb2
-rw-r--r--lib/bundler/installer/gem_installer.rb10
-rw-r--r--lib/bundler/installer/parallel_installer.rb26
-rw-r--r--lib/bundler/installer/standalone.rb19
-rw-r--r--lib/bundler/lazy_specification.rb25
-rw-r--r--lib/bundler/lockfile_generator.rb8
-rw-r--r--lib/bundler/lockfile_parser.rb136
-rw-r--r--lib/bundler/man/bundle-add.12
-rw-r--r--lib/bundler/man/bundle-binstubs.12
-rw-r--r--lib/bundler/man/bundle-cache.12
-rw-r--r--lib/bundler/man/bundle-check.12
-rw-r--r--lib/bundler/man/bundle-clean.12
-rw-r--r--lib/bundler/man/bundle-config.15
-rw-r--r--lib/bundler/man/bundle-config.1.ronn6
-rw-r--r--lib/bundler/man/bundle-console.12
-rw-r--r--lib/bundler/man/bundle-doctor.12
-rw-r--r--lib/bundler/man/bundle-exec.14
-rw-r--r--lib/bundler/man/bundle-exec.1.ronn5
-rw-r--r--lib/bundler/man/bundle-gem.12
-rw-r--r--lib/bundler/man/bundle-help.12
-rw-r--r--lib/bundler/man/bundle-info.12
-rw-r--r--lib/bundler/man/bundle-init.12
-rw-r--r--lib/bundler/man/bundle-inject.12
-rw-r--r--lib/bundler/man/bundle-install.12
-rw-r--r--lib/bundler/man/bundle-list.12
-rw-r--r--lib/bundler/man/bundle-lock.12
-rw-r--r--lib/bundler/man/bundle-open.12
-rw-r--r--lib/bundler/man/bundle-outdated.12
-rw-r--r--lib/bundler/man/bundle-platform.12
-rw-r--r--lib/bundler/man/bundle-plugin.134
-rw-r--r--lib/bundler/man/bundle-plugin.1.ronn10
-rw-r--r--lib/bundler/man/bundle-pristine.12
-rw-r--r--lib/bundler/man/bundle-remove.12
-rw-r--r--lib/bundler/man/bundle-show.12
-rw-r--r--lib/bundler/man/bundle-update.12
-rw-r--r--lib/bundler/man/bundle-version.12
-rw-r--r--lib/bundler/man/bundle-viz.12
-rw-r--r--lib/bundler/man/bundle.12
-rw-r--r--lib/bundler/man/gemfile.521
-rw-r--r--lib/bundler/man/gemfile.5.ronn9
-rw-r--r--lib/bundler/match_platform.rb2
-rw-r--r--lib/bundler/plugin.rb13
-rw-r--r--lib/bundler/plugin/api/source.rb3
-rw-r--r--lib/bundler/plugin/index.rb8
-rw-r--r--lib/bundler/resolver.rb55
-rw-r--r--lib/bundler/resolver/package.rb5
-rw-r--r--lib/bundler/retry.rb2
-rw-r--r--lib/bundler/ruby_dsl.rb25
-rw-r--r--lib/bundler/ruby_version.rb9
-rw-r--r--lib/bundler/rubygems_ext.rb46
-rw-r--r--lib/bundler/rubygems_gem_installer.rb87
-rw-r--r--lib/bundler/rubygems_integration.rb43
-rw-r--r--lib/bundler/self_manager.rb32
-rw-r--r--lib/bundler/settings.rb113
-rw-r--r--lib/bundler/shared_helpers.rb17
-rw-r--r--lib/bundler/source.rb2
-rw-r--r--lib/bundler/source/git.rb1
-rw-r--r--lib/bundler/source/git/git_proxy.rb52
-rw-r--r--lib/bundler/source/metadata.rb32
-rw-r--r--lib/bundler/source/path.rb1
-rw-r--r--lib/bundler/source/rubygems.rb51
-rw-r--r--lib/bundler/spec_set.rb11
-rw-r--r--lib/bundler/stub_specification.rb7
-rw-r--r--lib/bundler/templates/newgem/README.md.tt6
-rw-r--r--lib/bundler/templates/newgem/Rakefile.tt8
-rw-r--r--lib/bundler/templates/newgem/github/workflows/main.yml.tt2
-rw-r--r--lib/bundler/templates/newgem/newgem.gemspec.tt2
-rw-r--r--lib/bundler/templates/newgem/standard.yml.tt2
-rw-r--r--lib/bundler/ui/shell.rb2
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb2
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb1
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb30
-rw-r--r--lib/bundler/vendor/thor/lib/thor.rb163
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions.rb30
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/create_file.rb5
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/directory.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb18
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb19
-rw-r--r--lib/bundler/vendor/thor/lib/thor/base.rb154
-rw-r--r--lib/bundler/vendor/thor/lib/thor/command.rb17
-rw-r--r--lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/error.rb41
-rw-r--r--lib/bundler/vendor/thor/lib/thor/group.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/invocation.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/nested_context.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/argument.rb21
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/arguments.rb50
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/option.rb35
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/options.rb50
-rw-r--r--lib/bundler/vendor/thor/lib/thor/rake_compat.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/runner.rb70
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/basic.rb176
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/color.rb50
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb29
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/html.rb48
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb49
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb134
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/terminal.rb42
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb38
-rw-r--r--lib/bundler/vendor/thor/lib/thor/util.rb15
-rw-r--r--lib/bundler/vendor/thor/lib/thor/version.rb2
-rw-r--r--lib/bundler/version.rb2
-rw-r--r--lib/bundler/yaml_serializer.rb20
-rw-r--r--lib/cgi.rb2
-rw-r--r--lib/cgi/cookie.rb5
-rw-r--r--lib/cgi/session.rb2
-rw-r--r--lib/cgi/util.rb20
-rw-r--r--lib/csv.rb27
-rw-r--r--lib/csv/delete_suffix.rb18
-rw-r--r--lib/csv/match_p.rb20
-rw-r--r--lib/csv/parser.rb13
-rw-r--r--lib/csv/version.rb2
-rw-r--r--lib/delegate.gemspec29
-rw-r--r--lib/delegate.rb2
-rw-r--r--lib/delegate/delegate.gemspec29
-rw-r--r--lib/did_you_mean.rb4
-rw-r--r--lib/drb/drb.rb3
-rw-r--r--lib/drb/ssl.rb10
-rw-r--r--lib/drb/version.rb2
-rw-r--r--lib/erb.gemspec2
-rw-r--r--lib/erb.rb4
-rw-r--r--lib/erb/compiler.rb1
-rw-r--r--lib/erb/def_method.rb1
-rw-r--r--lib/erb/util.rb1
-rw-r--r--lib/erb/version.rb2
-rw-r--r--lib/error_highlight/base.rb31
-rw-r--r--lib/fileutils.rb30
-rw-r--r--lib/find.gemspec11
-rw-r--r--lib/find.rb2
-rw-r--r--lib/getoptlong.gemspec30
-rw-r--r--lib/getoptlong.rb4
-rw-r--r--lib/getoptlong/getoptlong.gemspec30
-rw-r--r--lib/ipaddr.rb40
-rw-r--r--lib/irb.rb562
-rw-r--r--lib/irb/cmd/chws.rb10
-rw-r--r--lib/irb/cmd/debug.rb128
-rw-r--r--lib/irb/cmd/edit.rb13
-rw-r--r--lib/irb/cmd/fork.rb40
-rw-r--r--lib/irb/cmd/help.rb64
-rw-r--r--lib/irb/cmd/irb_info.rb33
-rw-r--r--lib/irb/cmd/load.rb6
-rw-r--r--lib/irb/cmd/ls.rb47
-rw-r--r--lib/irb/cmd/nop.rb34
-rw-r--r--lib/irb/cmd/pushws.rb12
-rw-r--r--lib/irb/cmd/show_cmds.rb20
-rw-r--r--lib/irb/cmd/show_doc.rb48
-rw-r--r--lib/irb/cmd/show_source.rb81
-rw-r--r--lib/irb/cmd/subirb.rb62
-rw-r--r--lib/irb/color.rb16
-rw-r--r--lib/irb/color_printer.rb7
-rw-r--r--lib/irb/completion.rb228
-rw-r--r--lib/irb/context.rb121
-rw-r--r--lib/irb/debug.rb112
-rw-r--r--lib/irb/debug/ui.rb103
-rw-r--r--lib/irb/easter-egg.rb22
-rw-r--r--lib/irb/ext/change-ws.rb6
-rw-r--r--lib/irb/ext/eval_history.rb149
-rw-r--r--lib/irb/ext/history.rb155
-rw-r--r--lib/irb/ext/loader.rb34
-rw-r--r--lib/irb/ext/multi-irb.rb6
-rw-r--r--lib/irb/ext/save-history.rb130
-rw-r--r--lib/irb/ext/tracer.rb14
-rw-r--r--lib/irb/ext/use-loader.rb6
-rw-r--r--lib/irb/ext/workspaces.rb6
-rw-r--r--lib/irb/extend-command.rb109
-rw-r--r--lib/irb/frame.rb6
-rw-r--r--lib/irb/help.rb10
-rw-r--r--lib/irb/history.rb76
-rw-r--r--lib/irb/init.rb65
-rw-r--r--lib/irb/input-method.rb425
-rw-r--r--lib/irb/inspector.rb22
-rw-r--r--lib/irb/irb.gemspec10
-rw-r--r--lib/irb/lc/error.rb6
-rw-r--r--lib/irb/lc/help-message7
-rw-r--r--lib/irb/lc/ja/encoding_aliases.rb13
-rw-r--r--lib/irb/lc/ja/error.rb8
-rw-r--r--lib/irb/lc/ja/help-message3
-rw-r--r--lib/irb/locale.rb60
-rw-r--r--lib/irb/magic-file.rb38
-rw-r--r--lib/irb/nesting_parser.rb227
-rw-r--r--lib/irb/notifier.rb6
-rw-r--r--lib/irb/output-method.rb6
-rw-r--r--lib/irb/pager.rb86
-rw-r--r--lib/irb/ruby-lex.rb1148
-rw-r--r--lib/irb/ruby_logo.aa43
-rw-r--r--lib/irb/source_finder.rb64
-rw-r--r--lib/irb/src_encoding.rb7
-rw-r--r--lib/irb/statement.rb80
-rw-r--r--lib/irb/type_completion/completor.rb235
-rw-r--r--lib/irb/type_completion/methods.rb13
-rw-r--r--lib/irb/type_completion/scope.rb412
-rw-r--r--lib/irb/type_completion/type_analyzer.rb1169
-rw-r--r--lib/irb/type_completion/types.rb426
-rw-r--r--lib/irb/version.rb10
-rw-r--r--lib/irb/workspace.rb23
-rw-r--r--lib/irb/ws-for-case-2.rb6
-rw-r--r--lib/irb/xmp.rb6
-rw-r--r--lib/logger.rb42
-rw-r--r--lib/logger/logger.gemspec6
-rw-r--r--lib/logger/severity.rb19
-rw-r--r--lib/logger/version.rb2
-rw-r--r--lib/mkmf.rb160
-rw-r--r--lib/mutex_m.gemspec1
-rw-r--r--lib/mutex_m.rb14
-rw-r--r--lib/net/http.rb2
-rw-r--r--lib/net/net-protocol.gemspec2
-rw-r--r--lib/net/protocol.rb2
-rw-r--r--lib/observer.gemspec32
-rw-r--r--lib/observer.rb2
-rw-r--r--lib/observer/observer.gemspec32
-rw-r--r--lib/open-uri.gemspec11
-rw-r--r--lib/open-uri.rb4
-rw-r--r--lib/open3.rb860
-rw-r--r--lib/open3/open3.gemspec2
-rw-r--r--lib/open3/version.rb2
-rw-r--r--lib/optparse.rb37
-rw-r--r--lib/ostruct.gemspec24
-rw-r--r--lib/ostruct.rb14
-rw-r--r--lib/ostruct/ostruct.gemspec27
-rw-r--r--lib/pp.gemspec11
-rw-r--r--lib/pp.rb8
-rw-r--r--lib/prettyprint.gemspec11
-rw-r--r--lib/prettyprint.rb6
-rw-r--r--lib/prism.rb82
-rw-r--r--lib/prism/debug.rb195
-rw-r--r--lib/prism/desugar_compiler.rb206
-rw-r--r--lib/prism/ffi.rb328
-rw-r--r--lib/prism/lex_compat.rb882
-rw-r--r--lib/prism/node_ext.rb152
-rw-r--r--lib/prism/node_inspector.rb68
-rw-r--r--lib/prism/pack.rb224
-rw-r--r--lib/prism/parse_result.rb429
-rw-r--r--lib/prism/parse_result/comments.rb177
-rw-r--r--lib/prism/parse_result/newlines.rb64
-rw-r--r--lib/prism/pattern.rb250
-rw-r--r--lib/prism/prism.gemspec123
-rw-r--r--lib/prism/ripper_compat.rb192
-rw-r--r--lib/pstore.gemspec32
-rw-r--r--lib/pstore.rb14
-rw-r--r--lib/pstore/pstore.gemspec32
-rw-r--r--lib/racc.rb6
-rw-r--r--lib/racc/compat.rb33
-rw-r--r--lib/racc/debugflags.rb60
-rw-r--r--lib/racc/exception.rb16
-rw-r--r--lib/racc/grammar.rb1118
-rw-r--r--lib/racc/grammarfileparser.rb561
-rw-r--r--lib/racc/info.rb17
-rw-r--r--lib/racc/iset.rb92
-rw-r--r--lib/racc/logfilegenerator.rb212
-rw-r--r--lib/racc/parser-text.rb637
-rw-r--r--lib/racc/parser.rb632
-rw-r--r--lib/racc/parserfilegenerator.rb468
-rw-r--r--lib/racc/racc.gemspec58
-rw-r--r--lib/racc/sourcetext.rb35
-rw-r--r--lib/racc/state.rb972
-rw-r--r--lib/racc/statetransitiontable.rb311
-rw-r--r--lib/racc/static.rb5
-rw-r--r--lib/random/formatter.rb132
-rw-r--r--lib/rdoc/alias.rb1
-rw-r--r--lib/rdoc/anon_class.rb1
-rw-r--r--lib/rdoc/any_method.rb15
-rw-r--r--lib/rdoc/attr.rb1
-rw-r--r--lib/rdoc/class_module.rb1
-rw-r--r--lib/rdoc/comment.rb61
-rw-r--r--lib/rdoc/constant.rb1
-rw-r--r--lib/rdoc/context/section.rb1
-rw-r--r--lib/rdoc/cross_reference.rb1
-rw-r--r--lib/rdoc/encoding.rb7
-rw-r--r--lib/rdoc/erb_partial.rb1
-rw-r--r--lib/rdoc/erbio.rb9
-rw-r--r--lib/rdoc/extend.rb1
-rw-r--r--lib/rdoc/generator/darkfish.rb8
-rw-r--r--lib/rdoc/generator/json_index.rb4
-rw-r--r--lib/rdoc/generator/markup.rb1
-rw-r--r--lib/rdoc/generator/ri.rb1
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml2
-rw-r--r--lib/rdoc/generator/template/darkfish/class.rhtml6
-rw-r--r--lib/rdoc/generator/template/darkfish/css/rdoc.css40
-rw-r--r--lib/rdoc/generator/template/darkfish/js/darkfish.js13
-rw-r--r--lib/rdoc/generator/template/darkfish/js/search.js6
-rw-r--r--lib/rdoc/generator/template/darkfish/table_of_contents.rhtml9
-rw-r--r--lib/rdoc/generator/template/json_index/js/navigation.js16
-rw-r--r--lib/rdoc/ghost_method.rb1
-rw-r--r--lib/rdoc/include.rb1
-rw-r--r--lib/rdoc/markdown.rb2
-rw-r--r--lib/rdoc/markdown/entities.rb1
-rw-r--r--lib/rdoc/markup/attr_changer.rb1
-rw-r--r--lib/rdoc/markup/attr_span.rb1
-rw-r--r--lib/rdoc/markup/attribute_manager.rb23
-rw-r--r--lib/rdoc/markup/attributes.rb1
-rw-r--r--lib/rdoc/markup/blank_line.rb1
-rw-r--r--lib/rdoc/markup/block_quote.rb1
-rw-r--r--lib/rdoc/markup/document.rb1
-rw-r--r--lib/rdoc/markup/formatter.rb1
-rw-r--r--lib/rdoc/markup/hard_break.rb1
-rw-r--r--lib/rdoc/markup/heading.rb1
-rw-r--r--lib/rdoc/markup/include.rb1
-rw-r--r--lib/rdoc/markup/indented_paragraph.rb1
-rw-r--r--lib/rdoc/markup/list.rb1
-rw-r--r--lib/rdoc/markup/list_item.rb1
-rw-r--r--lib/rdoc/markup/paragraph.rb1
-rw-r--r--lib/rdoc/markup/raw.rb1
-rw-r--r--lib/rdoc/markup/regexp_handling.rb1
-rw-r--r--lib/rdoc/markup/rule.rb1
-rw-r--r--lib/rdoc/markup/to_ansi.rb1
-rw-r--r--lib/rdoc/markup/to_html.rb5
-rw-r--r--lib/rdoc/markup/to_html_crossref.rb1
-rw-r--r--lib/rdoc/markup/to_html_snippet.rb1
-rw-r--r--lib/rdoc/markup/to_joined_paragraph.rb5
-rw-r--r--lib/rdoc/markup/to_label.rb1
-rw-r--r--lib/rdoc/markup/to_markdown.rb1
-rw-r--r--lib/rdoc/markup/to_rdoc.rb1
-rw-r--r--lib/rdoc/markup/to_table_of_contents.rb1
-rw-r--r--lib/rdoc/markup/to_test.rb1
-rw-r--r--lib/rdoc/markup/to_tt_only.rb1
-rw-r--r--lib/rdoc/markup/verbatim.rb1
-rw-r--r--lib/rdoc/meta_method.rb1
-rw-r--r--lib/rdoc/method_attr.rb1
-rw-r--r--lib/rdoc/mixin.rb1
-rw-r--r--lib/rdoc/normal_class.rb1
-rw-r--r--lib/rdoc/normal_module.rb1
-rw-r--r--lib/rdoc/options.rb5
-rw-r--r--lib/rdoc/parser/changelog.rb1
-rw-r--r--lib/rdoc/parser/markdown.rb2
-rw-r--r--lib/rdoc/parser/rd.rb1
-rw-r--r--lib/rdoc/parser/ripper_state_lex.rb2
-rw-r--r--lib/rdoc/parser/ruby.rb8
-rw-r--r--lib/rdoc/parser/ruby_tools.rb2
-rw-r--r--lib/rdoc/parser/text.rb1
-rw-r--r--lib/rdoc/rd/block_parser.rb658
-rw-r--r--lib/rdoc/rd/inline.rb1
-rw-r--r--lib/rdoc/rd/inline_parser.rb656
-rw-r--r--lib/rdoc/rdoc.gemspec6
-rw-r--r--lib/rdoc/rdoc.rb6
-rw-r--r--lib/rdoc/require.rb1
-rw-r--r--lib/rdoc/ri/driver.rb17
-rw-r--r--lib/rdoc/ri/store.rb1
-rw-r--r--lib/rdoc/single_class.rb1
-rw-r--r--lib/rdoc/stats/quiet.rb1
-rw-r--r--lib/rdoc/stats/verbose.rb2
-rw-r--r--lib/rdoc/store.rb45
-rw-r--r--lib/rdoc/task.rb30
-rw-r--r--lib/rdoc/token_stream.rb1
-rw-r--r--lib/rdoc/top_level.rb1
-rw-r--r--lib/rdoc/version.rb2
-rw-r--r--lib/reline.rb179
-rw-r--r--lib/reline/ansi.rb127
-rw-r--r--lib/reline/config.rb4
-rw-r--r--lib/reline/face.rb157
-rw-r--r--lib/reline/general_io.rb13
-rw-r--r--lib/reline/key_stroke.rb57
-rw-r--r--lib/reline/line_editor.rb520
-rw-r--r--lib/reline/terminfo.rb16
-rw-r--r--lib/reline/unicode.rb83
-rw-r--r--lib/reline/unicode/east_asian_width.rb150
-rw-r--r--lib/reline/version.rb2
-rw-r--r--lib/reline/windows.rb6
-rw-r--r--lib/resolv.gemspec11
-rw-r--r--lib/resolv.rb22
-rw-r--r--lib/rinda/rinda.gemspec11
-rw-r--r--lib/rinda/rinda.rb2
-rw-r--r--lib/ruby_vm/mjit/c_pointer.rb329
-rw-r--r--lib/ruby_vm/mjit/c_type.rb91
-rw-r--r--lib/ruby_vm/mjit/compiler.rb952
-rw-r--r--lib/ruby_vm/mjit/hooks.rb32
-rw-r--r--lib/ruby_vm/rjit/assembler.rb1129
-rw-r--r--lib/ruby_vm/rjit/block.rb11
-rw-r--r--lib/ruby_vm/rjit/branch_stub.rb24
-rw-r--r--lib/ruby_vm/rjit/c_pointer.rb360
-rw-r--r--lib/ruby_vm/rjit/c_type.rb91
-rw-r--r--lib/ruby_vm/rjit/code_block.rb87
-rw-r--r--lib/ruby_vm/rjit/compiler.rb509
-rw-r--r--lib/ruby_vm/rjit/context.rb377
-rw-r--r--lib/ruby_vm/rjit/entry_stub.rb7
-rw-r--r--lib/ruby_vm/rjit/exit_compiler.rb164
-rw-r--r--lib/ruby_vm/rjit/hooks.rb36
-rw-r--r--lib/ruby_vm/rjit/insn_compiler.rb5947
-rw-r--r--lib/ruby_vm/rjit/invariants.rb155
-rw-r--r--lib/ruby_vm/rjit/jit_state.rb65
-rw-r--r--lib/ruby_vm/rjit/stats.rb188
-rw-r--r--lib/ruby_vm/rjit/type.rb221
-rw-r--r--lib/rubygems.rb73
-rw-r--r--lib/rubygems/available_set.rb10
-rw-r--r--lib/rubygems/basic_specification.rb60
-rw-r--r--lib/rubygems/bundler_version_finder.rb4
-rw-r--r--lib/rubygems/command.rb59
-rw-r--r--lib/rubygems/command_manager.rb6
-rw-r--r--lib/rubygems/commands/build_command.rb4
-rw-r--r--lib/rubygems/commands/cert_command.rb9
-rw-r--r--lib/rubygems/commands/check_command.rb12
-rw-r--r--lib/rubygems/commands/cleanup_command.rb20
-rw-r--r--lib/rubygems/commands/contents_command.rb8
-rw-r--r--lib/rubygems/commands/dependency_command.rb12
-rw-r--r--lib/rubygems/commands/environment_command.rb8
-rw-r--r--lib/rubygems/commands/exec_command.rb2
-rw-r--r--lib/rubygems/commands/help_command.rb10
-rw-r--r--lib/rubygems/commands/install_command.rb14
-rw-r--r--lib/rubygems/commands/open_command.rb4
-rw-r--r--lib/rubygems/commands/owner_command.rb20
-rw-r--r--lib/rubygems/commands/pristine_command.rb8
-rw-r--r--lib/rubygems/commands/push_command.rb4
-rw-r--r--lib/rubygems/commands/query_command.rb5
-rw-r--r--lib/rubygems/commands/setup_command.rb30
-rw-r--r--lib/rubygems/commands/sources_command.rb24
-rw-r--r--lib/rubygems/commands/specification_command.rb22
-rw-r--r--lib/rubygems/commands/stale_command.rb4
-rw-r--r--lib/rubygems/commands/uninstall_command.rb28
-rw-r--r--lib/rubygems/commands/unpack_command.rb20
-rw-r--r--lib/rubygems/commands/update_command.rb22
-rw-r--r--lib/rubygems/commands/yank_command.rb4
-rw-r--r--lib/rubygems/compatibility.rb11
-rw-r--r--lib/rubygems/config_file.rb85
-rw-r--r--lib/rubygems/core_ext/kernel_gem.rb6
-rw-r--r--lib/rubygems/core_ext/kernel_require.rb68
-rw-r--r--lib/rubygems/core_ext/kernel_warn.rb9
-rw-r--r--lib/rubygems/core_ext/tcpsocket_init.rb2
-rw-r--r--lib/rubygems/defaults.rb8
-rw-r--r--lib/rubygems/dependency.rb26
-rw-r--r--lib/rubygems/dependency_installer.rb31
-rw-r--r--lib/rubygems/dependency_list.rb2
-rw-r--r--lib/rubygems/deprecate.rb34
-rw-r--r--lib/rubygems/doctor.rb14
-rw-r--r--lib/rubygems/errors.rb10
-rw-r--r--lib/rubygems/exceptions.rb5
-rw-r--r--lib/rubygems/ext/builder.rb19
-rw-r--r--lib/rubygems/ext/cargo_builder.rb12
-rw-r--r--lib/rubygems/ext/ext_conf_builder.rb4
-rw-r--r--lib/rubygems/ext/rake_builder.rb2
-rw-r--r--lib/rubygems/gem_runner.rb14
-rw-r--r--lib/rubygems/gemcutter_utilities.rb29
-rw-r--r--lib/rubygems/indexer.rb11
-rw-r--r--lib/rubygems/install_update_options.rb37
-rw-r--r--lib/rubygems/installer.rb99
-rw-r--r--lib/rubygems/installer_uninstaller_utils.rb2
-rw-r--r--lib/rubygems/local_remote_options.rb19
-rw-r--r--lib/rubygems/mock_gem_ui.rb86
-rw-r--r--lib/rubygems/name_tuple.rb14
-rw-r--r--lib/rubygems/package.rb58
-rw-r--r--lib/rubygems/package/digest_io.rb2
-rw-r--r--lib/rubygems/package/old.rb2
-rw-r--r--lib/rubygems/package/tar_header.rb14
-rw-r--r--lib/rubygems/package/tar_reader.rb24
-rw-r--r--lib/rubygems/package/tar_reader/entry.rb47
-rw-r--r--lib/rubygems/package/tar_writer.rb10
-rw-r--r--lib/rubygems/path_support.rb34
-rw-r--r--lib/rubygems/platform.rb97
-rw-r--r--lib/rubygems/query_utils.rb26
-rw-r--r--lib/rubygems/remote_fetcher.rb30
-rw-r--r--lib/rubygems/request.rb27
-rw-r--r--lib/rubygems/request/connection_pools.rb4
-rw-r--r--lib/rubygems/request_set.rb11
-rw-r--r--lib/rubygems/request_set/gem_dependency_api.rb23
-rw-r--r--lib/rubygems/request_set/lockfile.rb12
-rw-r--r--lib/rubygems/request_set/lockfile/parser.rb18
-rw-r--r--lib/rubygems/request_set/lockfile/tokenizer.rb32
-rw-r--r--lib/rubygems/requirement.rb12
-rw-r--r--lib/rubygems/resolver.rb19
-rw-r--r--lib/rubygems/resolver/activation_request.rb10
-rw-r--r--lib/rubygems/resolver/api_set.rb3
-rw-r--r--lib/rubygems/resolver/api_set/gem_parser.rb10
-rw-r--r--lib/rubygems/resolver/api_specification.rb2
-rw-r--r--lib/rubygems/resolver/best_set.rb2
-rw-r--r--lib/rubygems/resolver/composed_set.rb2
-rw-r--r--lib/rubygems/resolver/conflict.rb16
-rw-r--r--lib/rubygems/resolver/index_set.rb8
-rw-r--r--lib/rubygems/resolver/index_specification.rb4
-rw-r--r--lib/rubygems/resolver/installed_specification.rb2
-rw-r--r--lib/rubygems/resolver/installer_set.rb11
-rw-r--r--lib/rubygems/resolver/local_specification.rb2
-rw-r--r--lib/rubygems/resolver/lock_set.rb2
-rw-r--r--lib/rubygems/s3_uri_signer.rb8
-rw-r--r--lib/rubygems/safe_marshal.rb74
-rw-r--r--lib/rubygems/safe_marshal/elements.rb138
-rw-r--r--lib/rubygems/safe_marshal/reader.rb306
-rw-r--r--lib/rubygems/safe_marshal/visitors/stream_printer.rb31
-rw-r--r--lib/rubygems/safe_marshal/visitors/to_ruby.rb385
-rw-r--r--lib/rubygems/safe_marshal/visitors/visitor.rb74
-rw-r--r--lib/rubygems/safe_yaml.rb33
-rw-r--r--lib/rubygems/security.rb34
-rw-r--r--lib/rubygems/security/policies.rb2
-rw-r--r--lib/rubygems/security/policy.rb18
-rw-r--r--lib/rubygems/security/signer.rb14
-rw-r--r--lib/rubygems/security/trust_dir.rb18
-rw-r--r--lib/rubygems/security_option.rb2
-rw-r--r--lib/rubygems/source.rb25
-rw-r--r--lib/rubygems/source/git.rb2
-rw-r--r--lib/rubygems/source/installed.rb2
-rw-r--r--lib/rubygems/source/local.rb83
-rw-r--r--lib/rubygems/source/lock.rb4
-rw-r--r--lib/rubygems/source/specific_file.rb1
-rw-r--r--lib/rubygems/source/vendor.rb2
-rw-r--r--lib/rubygems/source_list.rb14
-rw-r--r--lib/rubygems/spec_fetcher.rb80
-rw-r--r--lib/rubygems/specification.rb290
-rw-r--r--lib/rubygems/specification_policy.rb104
-rw-r--r--lib/rubygems/stub_specification.rb31
-rw-r--r--lib/rubygems/text.rb3
-rw-r--r--lib/rubygems/uninstaller.rb22
-rw-r--r--lib/rubygems/update_suggestion.rb10
-rw-r--r--lib/rubygems/uri_formatter.rb2
-rw-r--r--lib/rubygems/user_interaction.rb36
-rw-r--r--lib/rubygems/util.rb8
-rw-r--r--lib/rubygems/util/licenses.rb263
-rw-r--r--lib/rubygems/util/list.rb4
-rw-r--r--lib/rubygems/validator.rb20
-rw-r--r--lib/rubygems/version.rb67
-rw-r--r--lib/rubygems/version_option.rb7
-rw-r--r--lib/rubygems/yaml_serializer.rb93
-rw-r--r--lib/securerandom.gemspec11
-rw-r--r--lib/securerandom.rb14
-rw-r--r--lib/set.rb32
-rw-r--r--lib/set/set.gemspec13
-rw-r--r--lib/shellwords.gemspec12
-rw-r--r--lib/shellwords.rb2
-rw-r--r--lib/singleton.gemspec30
-rw-r--r--lib/singleton.rb9
-rw-r--r--lib/singleton/singleton.gemspec30
-rw-r--r--lib/syntax_suggest/core_ext.rb2
-rw-r--r--lib/syntax_suggest/pathname_from_message.rb2
-rw-r--r--lib/tempfile.gemspec13
-rw-r--r--lib/tempfile.rb77
-rw-r--r--lib/time.gemspec13
-rw-r--r--lib/time.rb3
-rw-r--r--lib/timeout.gemspec32
-rw-r--r--lib/timeout.rb38
-rw-r--r--lib/timeout/timeout.gemspec30
-rw-r--r--lib/tmpdir.gemspec4
-rw-r--r--lib/tmpdir.rb16
-rw-r--r--lib/tsort.gemspec11
-rw-r--r--lib/tsort.rb3
-rw-r--r--lib/un.gemspec11
-rw-r--r--lib/un.rb4
-rw-r--r--lib/uri/common.rb390
-rw-r--r--lib/uri/generic.rb16
-rw-r--r--lib/uri/rfc3986_parser.rb126
-rw-r--r--lib/uri/uri.gemspec18
-rw-r--r--lib/uri/version.rb2
-rw-r--r--lib/weakref.gemspec34
-rw-r--r--lib/weakref.rb2
-rw-r--r--lib/weakref/weakref.gemspec34
-rw-r--r--lib/yaml.rb1
-rw-r--r--lib/yaml/store.rb2
-rw-r--r--lib/yaml/yaml.gemspec13
-rwxr-xr-xlibexec/irb2
-rwxr-xr-xlibexec/racc320
-rw-r--r--load.c58
-rw-r--r--main.c9
-rw-r--r--man/irb.17
-rw-r--r--man/ruby.178
-rw-r--r--marshal.c34
-rw-r--r--math.c82
-rw-r--r--method.h4
-rw-r--r--mini_builtin.c22
-rw-r--r--misc/.vscode/launch.json13
-rw-r--r--misc/.vscode/settings.json8
-rw-r--r--misc/.vscode/tasks.json14
-rw-r--r--misc/README1
-rw-r--r--misc/gdb.py181
-rwxr-xr-xmisc/lldb_cruby.py63
-rw-r--r--misc/lldb_rb/commands/heap_page_command.py4
-rw-r--r--misc/lldb_rb/commands/print_flags_command.py31
-rw-r--r--misc/lldb_rb/commands/rb_id2str_command.py49
-rw-r--r--misc/lldb_rb/commands/rp_command.py15
-rw-r--r--misc/lldb_rb/constants.py2
-rw-r--r--misc/lldb_rb/lldb_interface.py7
-rw-r--r--misc/lldb_rb/rb_base_command.py24
-rw-r--r--misc/lldb_rb/rb_heap_structs.py143
-rw-r--r--misc/lldb_rb/utils.py490
-rw-r--r--missing/dtoa.c11
-rw-r--r--missing/explicit_bzero.c5
-rw-r--r--missing/procstat_vm.c34
-rw-r--r--mjit.c1999
-rw-r--r--mjit.h145
-rw-r--r--mjit.rb37
-rw-r--r--mjit_c.c43
-rw-r--r--mjit_c.h97
-rw-r--r--mjit_c.rb807
-rw-r--r--node.c1412
-rw-r--r--node.h544
-rw-r--r--node_dump.c1123
-rw-r--r--numeric.c256
-rw-r--r--numeric.rb359
-rw-r--r--object.c452
-rw-r--r--pack.c8
-rw-r--r--parse.y18480
-rw-r--r--parser_bits.h564
-rw-r--r--parser_node.h32
-rw-r--r--parser_st.c163
-rw-r--r--parser_st.h162
-rw-r--r--parser_value.h106
-rw-r--r--prelude.rb2
-rw-r--r--prism/api_pack.c267
-rw-r--r--prism/config.yml2558
-rw-r--r--prism/defines.h77
-rw-r--r--prism/diagnostic.c291
-rw-r--r--prism/diagnostic.h265
-rw-r--r--prism/enc/pm_big5.c53
-rw-r--r--prism/enc/pm_encoding.h186
-rw-r--r--prism/enc/pm_euc_jp.c59
-rw-r--r--prism/enc/pm_gbk.c62
-rw-r--r--prism/enc/pm_shift_jis.c57
-rw-r--r--prism/enc/pm_tables.c743
-rw-r--r--prism/enc/pm_unicode.c2369
-rw-r--r--prism/enc/pm_windows_31j.c57
-rw-r--r--prism/extension.c991
-rw-r--r--prism/extension.h18
-rw-r--r--prism/node.h57
-rw-r--r--prism/options.c170
-rw-r--r--prism/options.h204
-rw-r--r--prism/pack.c493
-rw-r--r--prism/pack.h152
-rw-r--r--prism/parser.h690
-rw-r--r--prism/prettyprint.h26
-rw-r--r--prism/prism.c16543
-rw-r--r--prism/prism.h274
-rw-r--r--prism/regexp.c638
-rw-r--r--prism/regexp.h33
-rw-r--r--prism/templates/ext/prism/api_node.c.erb218
-rw-r--r--prism/templates/include/prism/ast.h.erb200
-rw-r--r--prism/templates/lib/prism/compiler.rb.erb41
-rw-r--r--prism/templates/lib/prism/dispatcher.rb.erb89
-rw-r--r--prism/templates/lib/prism/dsl.rb.erb45
-rw-r--r--prism/templates/lib/prism/mutation_compiler.rb.erb19
-rw-r--r--prism/templates/lib/prism/node.rb.erb249
-rw-r--r--prism/templates/lib/prism/serialize.rb.erb308
-rw-r--r--prism/templates/lib/prism/visitor.rb.erb50
-rw-r--r--prism/templates/src/node.c.erb162
-rw-r--r--prism/templates/src/prettyprint.c.erb188
-rw-r--r--prism/templates/src/serialize.c.erb347
-rw-r--r--prism/templates/src/token_type.c.erb20
-rwxr-xr-xprism/templates/template.rb449
-rw-r--r--prism/util/pm_buffer.c170
-rw-r--r--prism/util/pm_buffer.h138
-rw-r--r--prism/util/pm_char.c318
-rw-r--r--prism/util/pm_char.h205
-rw-r--r--prism/util/pm_constant_pool.c296
-rw-r--r--prism/util/pm_constant_pool.h191
-rw-r--r--prism/util/pm_list.c49
-rw-r--r--prism/util/pm_list.h97
-rw-r--r--prism/util/pm_memchr.c35
-rw-r--r--prism/util/pm_memchr.h29
-rw-r--r--prism/util/pm_newline_list.c96
-rw-r--r--prism/util/pm_newline_list.h104
-rw-r--r--prism/util/pm_state_stack.c25
-rw-r--r--prism/util/pm_state_stack.h42
-rw-r--r--prism/util/pm_string.c210
-rw-r--r--prism/util/pm_string.h150
-rw-r--r--prism/util/pm_string_list.c28
-rw-r--r--prism/util/pm_string_list.h44
-rw-r--r--prism/util/pm_strncasecmp.c24
-rw-r--r--prism/util/pm_strncasecmp.h32
-rw-r--r--prism/util/pm_strpbrk.c72
-rw-r--r--prism/util/pm_strpbrk.h43
-rw-r--r--prism/version.h29
-rw-r--r--prism_compile.c3814
-rw-r--r--prism_compile.h18
-rw-r--r--prism_init.c9
-rw-r--r--probes_helper.h2
-rw-r--r--proc.c279
-rw-r--r--process.c3027
-rw-r--r--ractor.c1852
-rw-r--r--ractor.rb371
-rw-r--r--ractor_core.h95
-rw-r--r--range.c356
-rw-r--r--rational.c21
-rw-r--r--re.c502
-rw-r--r--regcomp.c116
-rw-r--r--regenc.c2
-rw-r--r--regenc.h5
-rw-r--r--regexec.c993
-rw-r--r--regint.h49
-rw-r--r--regparse.c181
-rw-r--r--regparse.h3
-rw-r--r--rjit.c477
-rw-r--r--rjit.h103
-rw-r--r--rjit.rb41
-rw-r--r--rjit_c.c541
-rw-r--r--rjit_c.h165
-rw-r--r--rjit_c.rb1691
-rw-r--r--ruby-runner.c31
-rw-r--r--ruby.c922
-rw-r--r--ruby_parser.c911
-rw-r--r--rubyparser.h1403
-rw-r--r--sample/all-ruby-quine.rb24
-rw-r--r--sample/dir.rb11
-rw-r--r--scheduler.c104
-rw-r--r--shape.c810
-rw-r--r--shape.h130
-rw-r--r--signal.c172
-rw-r--r--siphash.c3
-rw-r--r--spec/README.md8
-rw-r--r--spec/bundler/bundler/bundler_spec.rb26
-rw-r--r--spec/bundler/bundler/definition_spec.rb14
-rw-r--r--spec/bundler/bundler/dependency_spec.rb9
-rw-r--r--spec/bundler/bundler/digest_spec.rb4
-rw-r--r--spec/bundler/bundler/env_spec.rb4
-rw-r--r--spec/bundler/bundler/fetcher_spec.rb66
-rw-r--r--spec/bundler/bundler/installer/parallel_installer_spec.rb46
-rw-r--r--spec/bundler/bundler/lockfile_parser_spec.rb75
-rw-r--r--spec/bundler/bundler/plugin/api/source_spec.rb4
-rw-r--r--spec/bundler/bundler/plugin_spec.rb4
-rw-r--r--spec/bundler/bundler/ruby_dsl_spec.rb76
-rw-r--r--spec/bundler/bundler/settings/validator_spec.rb6
-rw-r--r--spec/bundler/bundler/shared_helpers_spec.rb41
-rw-r--r--spec/bundler/bundler/source/git/git_proxy_spec.rb104
-rw-r--r--spec/bundler/bundler/specifications/foo.gemspec13
-rw-r--r--spec/bundler/bundler/stub_specification_spec.rb11
-rw-r--r--spec/bundler/bundler/yaml_serializer_spec.rb42
-rw-r--r--spec/bundler/cache/gems_spec.rb18
-rw-r--r--spec/bundler/commands/add_spec.rb16
-rw-r--r--spec/bundler/commands/cache_spec.rb12
-rw-r--r--spec/bundler/commands/check_spec.rb9
-rw-r--r--spec/bundler/commands/clean_spec.rb2
-rw-r--r--spec/bundler/commands/doctor_spec.rb7
-rw-r--r--spec/bundler/commands/exec_spec.rb6
-rw-r--r--spec/bundler/commands/install_spec.rb151
-rw-r--r--spec/bundler/commands/lock_spec.rb319
-rw-r--r--spec/bundler/commands/newgem_spec.rb38
-rw-r--r--spec/bundler/commands/open_spec.rb6
-rw-r--r--spec/bundler/commands/update_spec.rb68
-rw-r--r--spec/bundler/commands/viz_spec.rb6
-rw-r--r--spec/bundler/install/allow_offline_install_spec.rb2
-rw-r--r--spec/bundler/install/bundler_spec.rb10
-rw-r--r--spec/bundler/install/deploy_spec.rb18
-rw-r--r--spec/bundler/install/gemfile/force_ruby_platform_spec.rb28
-rw-r--r--spec/bundler/install/gemfile/gemspec_spec.rb52
-rw-r--r--spec/bundler/install/gemfile/git_spec.rb4
-rw-r--r--spec/bundler/install/gemfile/install_if_spec.rb6
-rw-r--r--spec/bundler/install/gemfile/path_spec.rb29
-rw-r--r--spec/bundler/install/gemfile/platform_spec.rb33
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb310
-rw-r--r--spec/bundler/install/gemfile/specific_platform_spec.rb143
-rw-r--r--spec/bundler/install/gems/compact_index_spec.rb55
-rw-r--r--spec/bundler/install/gems/flex_spec.rb11
-rw-r--r--spec/bundler/install/gems/resolving_spec.rb75
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb16
-rw-r--r--spec/bundler/install/git_spec.rb31
-rw-r--r--spec/bundler/install/yanked_spec.rb4
-rw-r--r--spec/bundler/lock/lockfile_spec.rb185
-rw-r--r--spec/bundler/plugins/source/example_spec.rb6
-rw-r--r--spec/bundler/plugins/uninstall_spec.rb25
-rw-r--r--spec/bundler/quality_spec.rb12
-rw-r--r--spec/bundler/realworld/edgecases_spec.rb9
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile.lock2
-rw-r--r--spec/bundler/resolver/basic_spec.rb34
-rw-r--r--spec/bundler/runtime/platform_spec.rb20
-rw-r--r--spec/bundler/runtime/self_management_spec.rb35
-rw-r--r--spec/bundler/runtime/setup_spec.rb34
-rw-r--r--spec/bundler/spec_helper.rb7
-rw-r--r--spec/bundler/support/activate.rb9
-rw-r--r--spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb3
-rw-r--r--spec/bundler/support/artifice/fail.rb4
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index.rb12
-rw-r--r--spec/bundler/support/artifice/used_cassettes.txt20908
-rw-r--r--spec/bundler/support/builders.rb4
-rw-r--r--spec/bundler/support/bundle.rb7
-rw-r--r--spec/bundler/support/checksums.rb78
-rw-r--r--spec/bundler/support/helpers.rb32
-rw-r--r--spec/bundler/support/indexes.rb12
-rw-r--r--spec/bundler/support/path.rb7
-rw-r--r--spec/bundler/support/rubygems_ext.rb1
-rw-r--r--spec/bundler/update/git_spec.rb4
-rw-r--r--spec/bundler/update/redownload_spec.rb10
-rw-r--r--spec/default.mspec74
-rw-r--r--spec/lib/formatter_overrides.rb6
-rw-r--r--spec/lib/spec_coverage.rb1
-rwxr-xr-xspec/mspec/lib/mspec/commands/mspec.rb5
-rw-r--r--spec/mspec/lib/mspec/helpers/io.rb4
-rw-r--r--spec/mspec/lib/mspec/helpers/ruby_exe.rb54
-rw-r--r--spec/mspec/lib/mspec/matchers/complain.rb2
-rw-r--r--spec/mspec/lib/mspec/runner/actions/timeout.rb64
-rw-r--r--spec/mspec/lib/mspec/runner/mspec.rb5
-rw-r--r--spec/mspec/lib/mspec/utils/options.rb2
-rw-r--r--spec/mspec/lib/mspec/utils/warnings.rb43
-rw-r--r--spec/mspec/spec/commands/mspec_spec.rb27
-rw-r--r--spec/mspec/spec/helpers/ruby_exe_spec.rb10
-rw-r--r--spec/mspec/spec/runner/context_spec.rb2
-rwxr-xr-xspec/mspec/tool/check_require_spec_helper.rb34
-rw-r--r--spec/mspec/tool/remove_old_guards.rb51
-rwxr-xr-xspec/mspec/tool/tag_from_output.rb10
-rw-r--r--spec/ruby/.mspec.constants1
-rw-r--r--spec/ruby/.rubocop.yml6
-rw-r--r--spec/ruby/.rubocop_todo.yml1
-rw-r--r--spec/ruby/CONTRIBUTING.md15
-rw-r--r--spec/ruby/README.md11
-rw-r--r--spec/ruby/command_line/backtrace_limit_spec.rb44
-rw-r--r--spec/ruby/command_line/dash_a_spec.rb4
-rw-r--r--spec/ruby/command_line/dash_l_spec.rb8
-rw-r--r--spec/ruby/command_line/dash_n_spec.rb8
-rw-r--r--spec/ruby/command_line/dash_p_spec.rb4
-rw-r--r--spec/ruby/command_line/dash_upper_f_spec.rb2
-rw-r--r--spec/ruby/command_line/dash_upper_u_spec.rb7
-rw-r--r--spec/ruby/command_line/dash_v_spec.rb2
-rw-r--r--spec/ruby/command_line/fixtures/bin/embedded_ruby.txt2
-rw-r--r--spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rbbin90 -> 121 bytes-rw-r--r--spec/ruby/command_line/rubyopt_spec.rb14
-rw-r--r--spec/ruby/core/argf/bytes_spec.rb16
-rw-r--r--spec/ruby/core/argf/chars_spec.rb16
-rw-r--r--spec/ruby/core/argf/codepoints_spec.rb16
-rw-r--r--spec/ruby/core/argf/lines_spec.rb16
-rw-r--r--spec/ruby/core/argf/readpartial_spec.rb2
-rw-r--r--spec/ruby/core/array/all_spec.rb13
-rw-r--r--spec/ruby/core/array/any_spec.rb12
-rw-r--r--spec/ruby/core/array/assoc_spec.rb2
-rw-r--r--spec/ruby/core/array/bsearch_index_spec.rb4
-rw-r--r--spec/ruby/core/array/count_spec.rb11
-rw-r--r--spec/ruby/core/array/delete_if_spec.rb30
-rw-r--r--spec/ruby/core/array/drop_spec.rb12
-rw-r--r--spec/ruby/core/array/drop_while_spec.rb16
-rw-r--r--spec/ruby/core/array/each_index_spec.rb18
-rw-r--r--spec/ruby/core/array/each_spec.rb5
-rw-r--r--spec/ruby/core/array/fill_spec.rb82
-rw-r--r--spec/ruby/core/array/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/array/flatten_spec.rb24
-rw-r--r--spec/ruby/core/array/initialize_spec.rb4
-rw-r--r--spec/ruby/core/array/intersect_spec.rb53
-rw-r--r--spec/ruby/core/array/multiply_spec.rb18
-rw-r--r--spec/ruby/core/array/new_spec.rb4
-rw-r--r--spec/ruby/core/array/none_spec.rb13
-rw-r--r--spec/ruby/core/array/one_spec.rb13
-rw-r--r--spec/ruby/core/array/pack/c_spec.rb4
-rw-r--r--spec/ruby/core/array/pack/shared/basic.rb2
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb16
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb36
-rw-r--r--spec/ruby/core/array/pack/shared/unicode.rb4
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb4
-rw-r--r--spec/ruby/core/array/plus_spec.rb21
-rw-r--r--spec/ruby/core/array/product_spec.rb5
-rw-r--r--spec/ruby/core/array/reject_spec.rb15
-rw-r--r--spec/ruby/core/array/reverse_each_spec.rb16
-rw-r--r--spec/ruby/core/array/rindex_spec.rb17
-rw-r--r--spec/ruby/core/array/sample_spec.rb4
-rw-r--r--spec/ruby/core/array/shared/collect.rb32
-rw-r--r--spec/ruby/core/array/shared/index.rb4
-rw-r--r--spec/ruby/core/array/shared/intersection.rb3
-rw-r--r--spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb25
-rw-r--r--spec/ruby/core/array/shared/keep_if.rb35
-rw-r--r--spec/ruby/core/array/shared/select.rb3
-rw-r--r--spec/ruby/core/array/shared/slice.rb400
-rw-r--r--spec/ruby/core/array/shuffle_spec.rb14
-rw-r--r--spec/ruby/core/array/slice_spec.rb60
-rw-r--r--spec/ruby/core/array/sort_by_spec.rb33
-rw-r--r--spec/ruby/core/array/sum_spec.rb21
-rw-r--r--spec/ruby/core/array/take_spec.rb12
-rw-r--r--spec/ruby/core/array/take_while_spec.rb16
-rw-r--r--spec/ruby/core/array/to_h_spec.rb6
-rw-r--r--spec/ruby/core/array/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/array/uniq_spec.rb46
-rw-r--r--spec/ruby/core/basicobject/fixtures/classes.rb228
-rw-r--r--spec/ruby/core/basicobject/instance_eval_spec.rb124
-rw-r--r--spec/ruby/core/basicobject/method_missing_spec.rb1
-rw-r--r--spec/ruby/core/binding/eval_spec.rb99
-rw-r--r--spec/ruby/core/binding/source_location_spec.rb5
-rw-r--r--spec/ruby/core/class/dup_spec.rb3
-rw-r--r--spec/ruby/core/complex/inspect_spec.rb19
-rw-r--r--spec/ruby/core/complex/to_s_spec.rb10
-rw-r--r--spec/ruby/core/data/constants_spec.rb16
-rw-r--r--spec/ruby/core/data/define_spec.rb36
-rw-r--r--spec/ruby/core/data/fixtures/classes.rb5
-rw-r--r--spec/ruby/core/data/initialize_spec.rb58
-rw-r--r--spec/ruby/core/dir/exist_spec.rb8
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb68
-rw-r--r--spec/ruby/core/dir/glob_spec.rb138
-rw-r--r--spec/ruby/core/dir/home_spec.rb33
-rw-r--r--spec/ruby/core/dir/shared/chroot.rb4
-rw-r--r--spec/ruby/core/dir/shared/exist.rb8
-rw-r--r--spec/ruby/core/dir/shared/glob.rb26
-rw-r--r--spec/ruby/core/encoding/converter/primitive_convert_spec.rb4
-rw-r--r--spec/ruby/core/encoding/default_external_spec.rb8
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/replicate_spec.rb8
-rw-r--r--spec/ruby/core/encoding/to_s_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb1
-rw-r--r--spec/ruby/core/enumerable/all_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/any_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/chunk_spec.rb5
-rw-r--r--spec/ruby/core/enumerable/grep_spec.rb49
-rw-r--r--spec/ruby/core/enumerable/grep_v_spec.rb49
-rw-r--r--spec/ruby/core/enumerable/none_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/one_spec.rb7
-rw-r--r--spec/ruby/core/enumerable/shared/inject.rb44
-rw-r--r--spec/ruby/core/enumerable/sum_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb13
-rw-r--r--spec/ruby/core/enumerator/chain/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/chain/inspect_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/each_spec.rb18
-rw-r--r--spec/ruby/core/enumerator/generator/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/initialize_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/inspect_spec.rb5
-rw-r--r--spec/ruby/core/enumerator/lazy/compact_spec.rb5
-rw-r--r--spec/ruby/core/enumerator/lazy/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/new_spec.rb47
-rw-r--r--spec/ruby/core/enumerator/product/each_spec.rb73
-rw-r--r--spec/ruby/core/enumerator/product/initialize_copy_spec.rb54
-rw-r--r--spec/ruby/core/enumerator/product/initialize_spec.rb33
-rw-r--r--spec/ruby/core/enumerator/product/inspect_spec.rb22
-rw-r--r--spec/ruby/core/enumerator/product/rewind_spec.rb64
-rw-r--r--spec/ruby/core/enumerator/product/size_spec.rb64
-rw-r--r--spec/ruby/core/enumerator/product_spec.rb93
-rw-r--r--spec/ruby/core/enumerator/rewind_spec.rb4
-rw-r--r--spec/ruby/core/env/clone_spec.rb23
-rw-r--r--spec/ruby/core/env/delete_spec.rb16
-rw-r--r--spec/ruby/core/env/dup_spec.rb11
-rw-r--r--spec/ruby/core/env/except_spec.rb44
-rw-r--r--spec/ruby/core/env/index_spec.rb14
-rw-r--r--spec/ruby/core/env/indexes_spec.rb1
-rw-r--r--spec/ruby/core/env/indices_spec.rb1
-rw-r--r--spec/ruby/core/env/key_spec.rb32
-rw-r--r--spec/ruby/core/env/shared/include.rb7
-rw-r--r--spec/ruby/core/env/shared/key.rb31
-rw-r--r--spec/ruby/core/env/shared/value.rb7
-rw-r--r--spec/ruby/core/env/slice_spec.rb10
-rw-r--r--spec/ruby/core/env/to_a_spec.rb5
-rw-r--r--spec/ruby/core/exception/case_compare_spec.rb2
-rw-r--r--spec/ruby/core/exception/detailed_message_spec.rb43
-rw-r--r--spec/ruby/core/exception/equal_value_spec.rb14
-rw-r--r--spec/ruby/core/exception/fixtures/common.rb4
-rw-r--r--spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb22
-rw-r--r--spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb25
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb49
-rw-r--r--spec/ruby/core/exception/no_method_error_spec.rb79
-rw-r--r--spec/ruby/core/exception/top_level_spec.rb12
-rw-r--r--spec/ruby/core/false/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/fiber/blocking_spec.rb68
-rw-r--r--spec/ruby/core/fiber/inspect_spec.rb36
-rw-r--r--spec/ruby/core/fiber/kill_spec.rb90
-rw-r--r--spec/ruby/core/fiber/raise_spec.rb28
-rw-r--r--spec/ruby/core/fiber/resume_spec.rb15
-rw-r--r--spec/ruby/core/fiber/storage_spec.rb103
-rw-r--r--spec/ruby/core/file/absolute_path_spec.rb2
-rw-r--r--spec/ruby/core/file/atime_spec.rb2
-rw-r--r--spec/ruby/core/file/ctime_spec.rb2
-rw-r--r--spec/ruby/core/file/dirname_spec.rb39
-rw-r--r--spec/ruby/core/file/exist_spec.rb8
-rw-r--r--spec/ruby/core/file/flock_spec.rb4
-rw-r--r--spec/ruby/core/file/mtime_spec.rb2
-rw-r--r--spec/ruby/core/file/new_spec.rb63
-rw-r--r--spec/ruby/core/file/open_spec.rb11
-rw-r--r--spec/ruby/core/file/realpath_spec.rb4
-rw-r--r--spec/ruby/core/file/shared/fnmatch.rb47
-rw-r--r--spec/ruby/core/file/utime_spec.rb26
-rw-r--r--spec/ruby/core/float/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/float/round_spec.rb2
-rw-r--r--spec/ruby/core/gc/auto_compact_spec.rb36
-rw-r--r--spec/ruby/core/hash/compact_spec.rb24
-rw-r--r--spec/ruby/core/hash/constructor_spec.rb18
-rw-r--r--spec/ruby/core/hash/except_spec.rb50
-rw-r--r--spec/ruby/core/hash/fetch_spec.rb2
-rw-r--r--spec/ruby/core/hash/fetch_values_spec.rb2
-rw-r--r--spec/ruby/core/hash/index_spec.rb9
-rw-r--r--spec/ruby/core/hash/new_spec.rb13
-rw-r--r--spec/ruby/core/hash/ruby2_keywords_hash_spec.rb24
-rw-r--r--spec/ruby/core/hash/shared/each.rb37
-rw-r--r--spec/ruby/core/hash/shared/equal.rb90
-rw-r--r--spec/ruby/core/hash/to_a_spec.rb10
-rw-r--r--spec/ruby/core/hash/to_proc_spec.rb16
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb32
-rw-r--r--spec/ruby/core/hash/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/integer/bit_and_spec.rb2
-rw-r--r--spec/ruby/core/integer/bit_or_spec.rb6
-rw-r--r--spec/ruby/core/integer/bit_xor_spec.rb4
-rw-r--r--spec/ruby/core/integer/ceildiv_spec.rb22
-rw-r--r--spec/ruby/core/integer/left_shift_spec.rb32
-rw-r--r--spec/ruby/core/integer/right_shift_spec.rb32
-rw-r--r--spec/ruby/core/integer/shared/arithmetic_coerce.rb20
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb12
-rw-r--r--spec/ruby/core/integer/zero_spec.rb12
-rw-r--r--spec/ruby/core/io/binread_spec.rb10
-rw-r--r--spec/ruby/core/io/bytes_spec.rb47
-rw-r--r--spec/ruby/core/io/chars_spec.rb30
-rw-r--r--spec/ruby/core/io/codepoints_spec.rb38
-rw-r--r--spec/ruby/core/io/copy_stream_spec.rb33
-rw-r--r--spec/ruby/core/io/eof_spec.rb2
-rw-r--r--spec/ruby/core/io/flush_spec.rb10
-rw-r--r--spec/ruby/core/io/foreach_spec.rb19
-rw-r--r--spec/ruby/core/io/getbyte_spec.rb16
-rw-r--r--spec/ruby/core/io/gets_spec.rb71
-rw-r--r--spec/ruby/core/io/initialize_spec.rb11
-rw-r--r--spec/ruby/core/io/lines_spec.rb46
-rw-r--r--spec/ruby/core/io/new_spec.rb8
-rw-r--r--spec/ruby/core/io/nonblock_spec.rb46
-rw-r--r--spec/ruby/core/io/open_spec.rb13
-rw-r--r--spec/ruby/core/io/pread_spec.rb79
-rw-r--r--spec/ruby/core/io/pwrite_spec.rb32
-rw-r--r--spec/ruby/core/io/read_spec.rb129
-rw-r--r--spec/ruby/core/io/readline_spec.rb12
-rw-r--r--spec/ruby/core/io/readlines_spec.rb39
-rw-r--r--spec/ruby/core/io/select_spec.rb15
-rw-r--r--spec/ruby/core/io/shared/binwrite.rb13
-rw-r--r--spec/ruby/core/io/shared/each.rb20
-rw-r--r--spec/ruby/core/io/shared/new.rb50
-rw-r--r--spec/ruby/core/io/shared/readlines.rb20
-rw-r--r--spec/ruby/core/io/shared/write.rb65
-rw-r--r--spec/ruby/core/io/syswrite_spec.rb1
-rw-r--r--spec/ruby/core/io/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/io/ungetc_spec.rb16
-rw-r--r--spec/ruby/core/io/write_nonblock_spec.rb1
-rw-r--r--spec/ruby/core/io/write_spec.rb159
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb4
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb25
-rw-r--r--spec/ruby/core/kernel/__dir___spec.rb16
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb61
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb86
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb6
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb48
-rw-r--r--spec/ruby/core/kernel/exec_spec.rb4
-rw-r--r--spec/ruby/core/kernel/exit_spec.rb10
-rw-r--r--spec/ruby/core/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/core/kernel/initialize_clone_spec.rb10
-rw-r--r--spec/ruby/core/kernel/initialize_copy_spec.rb9
-rw-r--r--spec/ruby/core/kernel/iterator_spec.rb14
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb74
-rw-r--r--spec/ruby/core/kernel/method_spec.rb21
-rw-r--r--spec/ruby/core/kernel/open_spec.rb87
-rw-r--r--spec/ruby/core/kernel/printf_spec.rb7
-rw-r--r--spec/ruby/core/kernel/proc_spec.rb18
-rw-r--r--spec/ruby/core/kernel/require_relative_spec.rb8
-rw-r--r--spec/ruby/core/kernel/require_spec.rb20
-rw-r--r--spec/ruby/core/kernel/shared/load.rb38
-rw-r--r--spec/ruby/core/kernel/shared/require.rb82
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb4
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb49
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb28
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb16
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb16
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb20
-rw-r--r--spec/ruby/core/kernel/test_spec.rb4
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb18
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb18
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb16
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb18
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb141
-rw-r--r--spec/ruby/core/main/private_spec.rb12
-rw-r--r--spec/ruby/core/main/public_spec.rb12
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb222
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb96
-rw-r--r--spec/ruby/core/marshal/shared/load.rb289
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb95
-rw-r--r--spec/ruby/core/matchdata/captures_spec.rb13
-rw-r--r--spec/ruby/core/matchdata/deconstruct_keys_spec.rb65
-rw-r--r--spec/ruby/core/matchdata/deconstruct_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/element_reference_spec.rb13
-rw-r--r--spec/ruby/core/matchdata/named_captures_spec.rb12
-rw-r--r--spec/ruby/core/matchdata/post_match_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/pre_match_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/shared/captures.rb13
-rw-r--r--spec/ruby/core/matchdata/to_a_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/to_s_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/values_at_spec.rb4
-rw-r--r--spec/ruby/core/math/cos_spec.rb26
-rw-r--r--spec/ruby/core/method/compose_spec.rb3
-rw-r--r--spec/ruby/core/method/parameters_spec.rb16
-rw-r--r--spec/ruby/core/method/private_spec.rb11
-rw-r--r--spec/ruby/core/method/protected_spec.rb11
-rw-r--r--spec/ruby/core/method/public_spec.rb11
-rw-r--r--spec/ruby/core/method/shared/to_s.rb30
-rw-r--r--spec/ruby/core/method/source_location_spec.rb9
-rw-r--r--spec/ruby/core/method/super_method_spec.rb10
-rw-r--r--spec/ruby/core/module/alias_method_spec.rb20
-rw-r--r--spec/ruby/core/module/attr_accessor_spec.rb16
-rw-r--r--spec/ruby/core/module/attr_reader_spec.rb16
-rw-r--r--spec/ruby/core/module/attr_spec.rb22
-rw-r--r--spec/ruby/core/module/attr_writer_spec.rb16
-rw-r--r--spec/ruby/core/module/const_added_spec.rb35
-rw-r--r--spec/ruby/core/module/const_defined_spec.rb21
-rw-r--r--spec/ruby/core/module/const_get_spec.rb2
-rw-r--r--spec/ruby/core/module/const_set_spec.rb18
-rw-r--r--spec/ruby/core/module/const_source_location_spec.rb14
-rw-r--r--spec/ruby/core/module/define_method_spec.rb46
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb26
-rw-r--r--spec/ruby/core/module/fixtures/module.rb4
-rw-r--r--spec/ruby/core/module/method_added_spec.rb73
-rw-r--r--spec/ruby/core/module/module_function_spec.rb136
-rw-r--r--spec/ruby/core/module/name_spec.rb54
-rw-r--r--spec/ruby/core/module/prepend_spec.rb39
-rw-r--r--spec/ruby/core/module/private_class_method_spec.rb14
-rw-r--r--spec/ruby/core/module/public_class_method_spec.rb20
-rw-r--r--spec/ruby/core/module/refine_spec.rb2
-rw-r--r--spec/ruby/core/module/refinements_spec.rb45
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb23
-rw-r--r--spec/ruby/core/module/set_temporary_name_spec.rb68
-rw-r--r--spec/ruby/core/module/shared/class_eval.rb6
-rw-r--r--spec/ruby/core/module/shared/set_visibility.rb28
-rw-r--r--spec/ruby/core/module/undefined_instance_methods_spec.rb26
-rw-r--r--spec/ruby/core/module/used_refinements_spec.rb87
-rw-r--r--spec/ruby/core/mutex/lock_spec.rb4
-rw-r--r--spec/ruby/core/mutex/owned_spec.rb18
-rw-r--r--spec/ruby/core/nil/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/numeric/clone_spec.rb10
-rw-r--r--spec/ruby/core/numeric/fdiv_spec.rb1
-rw-r--r--spec/ruby/core/numeric/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/numeric/quo_spec.rb1
-rw-r--r--spec/ruby/core/numeric/remainder_spec.rb3
-rw-r--r--spec/ruby/core/numeric/shared/quo.rb7
-rw-r--r--spec/ruby/core/numeric/shared/step.rb8
-rw-r--r--spec/ruby/core/numeric/step_spec.rb85
-rw-r--r--spec/ruby/core/objectspace/define_finalizer_spec.rb78
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/delete_spec.rb40
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb26
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb71
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb14
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb17
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/key_spec.rb33
-rw-r--r--spec/ruby/core/objectspace/weakmap/delete_spec.rb30
-rw-r--r--spec/ruby/core/proc/compose_spec.rb46
-rw-r--r--spec/ruby/core/proc/eql_spec.rb8
-rw-r--r--spec/ruby/core/proc/equal_value_spec.rb8
-rw-r--r--spec/ruby/core/proc/lambda_spec.rb8
-rw-r--r--spec/ruby/core/proc/new_spec.rb35
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb26
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb22
-rw-r--r--spec/ruby/core/proc/shared/dup.rb8
-rw-r--r--spec/ruby/core/proc/shared/equal.rb17
-rw-r--r--spec/ruby/core/proc/source_location_spec.rb13
-rw-r--r--spec/ruby/core/process/argv0_spec.rb25
-rw-r--r--spec/ruby/core/process/constants_spec.rb8
-rw-r--r--spec/ruby/core/process/daemon_spec.rb3
-rw-r--r--spec/ruby/core/process/detach_spec.rb14
-rw-r--r--spec/ruby/core/process/exec_spec.rb44
-rw-r--r--spec/ruby/core/process/exit_spec.rb2
-rw-r--r--spec/ruby/core/process/fixtures/argv0.rb6
-rw-r--r--spec/ruby/core/process/spawn_spec.rb2
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb158
-rw-r--r--spec/ruby/core/process/times_spec.rb20
-rw-r--r--spec/ruby/core/process/wait2_spec.rb4
-rw-r--r--spec/ruby/core/process/wait_spec.rb2
-rw-r--r--spec/ruby/core/process/warmup_spec.rb11
-rw-r--r--spec/ruby/core/queue/deq_spec.rb7
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb33
-rw-r--r--spec/ruby/core/queue/pop_spec.rb7
-rw-r--r--spec/ruby/core/queue/shift_spec.rb7
-rw-r--r--spec/ruby/core/random/bytes_spec.rb1
-rw-r--r--spec/ruby/core/random/default_spec.rb24
-rw-r--r--spec/ruby/core/random/new_spec.rb1
-rw-r--r--spec/ruby/core/range/cover_spec.rb4
-rw-r--r--spec/ruby/core/range/frozen_spec.rb34
-rw-r--r--spec/ruby/core/range/include_spec.rb4
-rw-r--r--spec/ruby/core/range/initialize_spec.rb15
-rw-r--r--spec/ruby/core/range/max_spec.rb18
-rw-r--r--spec/ruby/core/range/minmax_spec.rb24
-rw-r--r--spec/ruby/core/range/new_spec.rb14
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb1
-rw-r--r--spec/ruby/core/range/size_spec.rb4
-rw-r--r--spec/ruby/core/range/step_spec.rb52
-rw-r--r--spec/ruby/core/rational/abs_spec.rb1
-rw-r--r--spec/ruby/core/rational/ceil_spec.rb1
-rw-r--r--spec/ruby/core/rational/coerce_spec.rb1
-rw-r--r--spec/ruby/core/rational/comparison_spec.rb1
-rw-r--r--spec/ruby/core/rational/denominator_spec.rb1
-rw-r--r--spec/ruby/core/rational/div_spec.rb1
-rw-r--r--spec/ruby/core/rational/divide_spec.rb1
-rw-r--r--spec/ruby/core/rational/divmod_spec.rb1
-rw-r--r--spec/ruby/core/rational/equal_value_spec.rb1
-rw-r--r--spec/ruby/core/rational/exponent_spec.rb1
-rw-r--r--spec/ruby/core/rational/fdiv_spec.rb1
-rw-r--r--spec/ruby/core/rational/floor_spec.rb1
-rw-r--r--spec/ruby/core/rational/hash_spec.rb1
-rw-r--r--spec/ruby/core/rational/inspect_spec.rb1
-rw-r--r--spec/ruby/core/rational/integer_spec.rb1
-rw-r--r--spec/ruby/core/rational/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/rational/modulo_spec.rb1
-rw-r--r--spec/ruby/core/rational/multiply_spec.rb1
-rw-r--r--spec/ruby/core/rational/numerator_spec.rb1
-rw-r--r--spec/ruby/core/rational/plus_spec.rb1
-rw-r--r--spec/ruby/core/rational/quo_spec.rb1
-rw-r--r--spec/ruby/core/rational/remainder_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_f_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_i_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_r_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_s_spec.rb1
-rw-r--r--spec/ruby/core/rational/truncate_spec.rb1
-rw-r--r--spec/ruby/core/rational/zero_spec.rb1
-rw-r--r--spec/ruby/core/refinement/extend_object_spec.rb6
-rw-r--r--spec/ruby/core/refinement/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/refinement/import_methods_spec.rb235
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb17
-rw-r--r--spec/ruby/core/regexp/initialize_spec.rb12
-rw-r--r--spec/ruby/core/regexp/linear_time_spec.rb25
-rw-r--r--spec/ruby/core/regexp/shared/new.rb4
-rw-r--r--spec/ruby/core/regexp/try_convert_spec.rb6
-rw-r--r--spec/ruby/core/regexp/union_spec.rb51
-rw-r--r--spec/ruby/core/signal/signame_spec.rb12
-rw-r--r--spec/ruby/core/signal/trap_spec.rb19
-rw-r--r--spec/ruby/core/sizedqueue/append_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/deq_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/enq_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/pop_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/push_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/shift_spec.rb7
-rw-r--r--spec/ruby/core/string/append_spec.rb1
-rw-r--r--spec/ruby/core/string/byteindex_spec.rb300
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb359
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb133
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb15
-rw-r--r--spec/ruby/core/string/casecmp_spec.rb10
-rw-r--r--spec/ruby/core/string/center_spec.rb25
-rw-r--r--spec/ruby/core/string/chars_spec.rb1
-rw-r--r--spec/ruby/core/string/chomp_spec.rb15
-rw-r--r--spec/ruby/core/string/chop_spec.rb12
-rw-r--r--spec/ruby/core/string/concat_spec.rb1
-rw-r--r--spec/ruby/core/string/dedup_spec.rb2
-rw-r--r--spec/ruby/core/string/delete_prefix_spec.rb15
-rw-r--r--spec/ruby/core/string/delete_spec.rb12
-rw-r--r--spec/ruby/core/string/delete_suffix_spec.rb15
-rw-r--r--spec/ruby/core/string/downcase_spec.rb12
-rw-r--r--spec/ruby/core/string/dump_spec.rb12
-rw-r--r--spec/ruby/core/string/each_char_spec.rb1
-rw-r--r--spec/ruby/core/string/each_grapheme_cluster_spec.rb11
-rw-r--r--spec/ruby/core/string/encode_spec.rb4
-rw-r--r--spec/ruby/core/string/grapheme_clusters_spec.rb1
-rw-r--r--spec/ruby/core/string/gsub_spec.rb21
-rw-r--r--spec/ruby/core/string/index_spec.rb18
-rw-r--r--spec/ruby/core/string/ljust_spec.rb25
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb18
-rw-r--r--spec/ruby/core/string/plus_spec.rb5
-rw-r--r--spec/ruby/core/string/reverse_spec.rb18
-rw-r--r--spec/ruby/core/string/rindex_spec.rb18
-rw-r--r--spec/ruby/core/string/rjust_spec.rb25
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb10
-rw-r--r--spec/ruby/core/string/scan_spec.rb10
-rw-r--r--spec/ruby/core/string/scrub_spec.rb36
-rw-r--r--spec/ruby/core/string/shared/byte_index_common.rb63
-rw-r--r--spec/ruby/core/string/shared/concat.rb32
-rw-r--r--spec/ruby/core/string/shared/dedup.rb8
-rw-r--r--spec/ruby/core/string/shared/each_line.rb18
-rw-r--r--spec/ruby/core/string/shared/partition.rb34
-rw-r--r--spec/ruby/core/string/shared/slice.rb114
-rw-r--r--spec/ruby/core/string/shared/strip.rb18
-rw-r--r--spec/ruby/core/string/shared/succ.rb18
-rw-r--r--spec/ruby/core/string/shared/to_a.rb9
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb2
-rw-r--r--spec/ruby/core/string/slice_spec.rb93
-rw-r--r--spec/ruby/core/string/split_spec.rb112
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb12
-rw-r--r--spec/ruby/core/string/start_with_spec.rb17
-rw-r--r--spec/ruby/core/string/strip_spec.rb16
-rw-r--r--spec/ruby/core/string/sub_spec.rb21
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb15
-rw-r--r--spec/ruby/core/string/to_c_spec.rb12
-rw-r--r--spec/ruby/core/string/tr_s_spec.rb21
-rw-r--r--spec/ruby/core/string/tr_spec.rb21
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb20
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb28
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb4
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack_spec.rb2
-rw-r--r--spec/ruby/core/string/upcase_spec.rb12
-rw-r--r--spec/ruby/core/string/uplus_spec.rb3
-rw-r--r--spec/ruby/core/string/upto_spec.rb6
-rw-r--r--spec/ruby/core/string/valid_encoding_spec.rb10
-rw-r--r--spec/ruby/core/struct/constants_spec.rb15
-rw-r--r--spec/ruby/core/struct/deconstruct_keys_spec.rb2
-rw-r--r--spec/ruby/core/struct/fixtures/classes.rb6
-rw-r--r--spec/ruby/core/struct/initialize_spec.rb10
-rw-r--r--spec/ruby/core/struct/inspect_spec.rb5
-rw-r--r--spec/ruby/core/struct/keyword_init_spec.rb19
-rw-r--r--spec/ruby/core/struct/new_spec.rb19
-rw-r--r--spec/ruby/core/struct/shared/inspect.rb35
-rw-r--r--spec/ruby/core/symbol/casecmp_spec.rb8
-rw-r--r--spec/ruby/core/symbol/inspect_spec.rb2
-rw-r--r--spec/ruby/core/symbol/name_spec.rb24
-rw-r--r--spec/ruby/core/symbol/to_proc_spec.rb39
-rw-r--r--spec/ruby/core/thread/backtrace/location/path_spec.rb2
-rw-r--r--spec/ruby/core/thread/each_caller_location_spec.rb49
-rw-r--r--spec/ruby/core/thread/exclusive_spec.rb49
-rw-r--r--spec/ruby/core/thread/ignore_deadlock_spec.rb26
-rw-r--r--spec/ruby/core/thread/kill_spec.rb4
-rw-r--r--spec/ruby/core/thread/native_thread_id_spec.rb40
-rw-r--r--spec/ruby/core/thread/report_on_exception_spec.rb44
-rw-r--r--spec/ruby/core/thread/shared/exit.rb19
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb44
-rw-r--r--spec/ruby/core/time/new_spec.rb200
-rw-r--r--spec/ruby/core/time/now_spec.rb66
-rw-r--r--spec/ruby/core/time/succ_spec.rb39
-rw-r--r--spec/ruby/core/time/utc_spec.rb10
-rw-r--r--spec/ruby/core/time/zone_spec.rb11
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb8
-rw-r--r--spec/ruby/core/tracepoint/inspect_spec.rb8
-rw-r--r--spec/ruby/core/tracepoint/path_spec.rb31
-rw-r--r--spec/ruby/core/true/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/unboundmethod/bind_call_spec.rb8
-rw-r--r--spec/ruby/core/unboundmethod/bind_spec.rb8
-rw-r--r--spec/ruby/core/unboundmethod/fixtures/classes.rb4
-rw-r--r--spec/ruby/core/unboundmethod/private_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/protected_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/public_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/source_location_spec.rb9
-rw-r--r--spec/ruby/core/unboundmethod/super_method_spec.rb10
-rw-r--r--spec/ruby/core/warning/element_reference_spec.rb13
-rw-r--r--spec/ruby/core/warning/element_set_spec.rb20
-rw-r--r--spec/ruby/core/warning/warn_spec.rb103
-rw-r--r--spec/ruby/fixtures/code/d/load_fixture.rb.rb1
-rw-r--r--spec/ruby/fixtures/constants.rb3
-rw-r--r--spec/ruby/language/END_spec.rb26
-rw-r--r--spec/ruby/language/alias_spec.rb20
-rw-r--r--spec/ruby/language/block_spec.rb172
-rw-r--r--spec/ruby/language/case_spec.rb104
-rw-r--r--spec/ruby/language/class_spec.rb18
-rw-r--r--spec/ruby/language/class_variable_spec.rb56
-rw-r--r--spec/ruby/language/constants_spec.rb38
-rw-r--r--spec/ruby/language/defined_spec.rb26
-rw-r--r--spec/ruby/language/delegation_spec.rb38
-rw-r--r--spec/ruby/language/file_spec.rb12
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rbbin120 -> 181 bytes-rw-r--r--spec/ruby/language/fixtures/super.rb14
-rw-r--r--spec/ruby/language/fixtures/variables.rb72
-rw-r--r--spec/ruby/language/hash_spec.rb60
-rw-r--r--spec/ruby/language/if_spec.rb43
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb554
-rw-r--r--spec/ruby/language/lambda_spec.rb68
-rw-r--r--spec/ruby/language/method_spec.rb731
-rw-r--r--spec/ruby/language/module_spec.rb18
-rw-r--r--spec/ruby/language/numbered_parameters_spec.rb53
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb276
-rw-r--r--spec/ruby/language/predefined_spec.rb45
-rw-r--r--spec/ruby/language/proc_spec.rb26
-rw-r--r--spec/ruby/language/regexp/character_classes_spec.rb10
-rw-r--r--spec/ruby/language/regexp/repetition_spec.rb8
-rw-r--r--spec/ruby/language/regexp_spec.rb8
-rw-r--r--spec/ruby/language/safe_spec.rb28
-rw-r--r--spec/ruby/language/send_spec.rb36
-rw-r--r--spec/ruby/language/singleton_class_spec.rb17
-rw-r--r--spec/ruby/language/source_encoding_spec.rb2
-rw-r--r--spec/ruby/language/string_spec.rb24
-rw-r--r--spec/ruby/language/super_spec.rb23
-rw-r--r--spec/ruby/language/symbol_spec.rb4
-rw-r--r--spec/ruby/language/undef_spec.rb9
-rw-r--r--spec/ruby/language/variables_spec.rb99
-rw-r--r--spec/ruby/language/yield_spec.rb31
-rw-r--r--spec/ruby/library/English/English_spec.rb16
-rw-r--r--spec/ruby/library/bigdecimal/add_spec.rb4
-rw-r--r--spec/ruby/library/bigdecimal/remainder_spec.rb28
-rw-r--r--spec/ruby/library/bigdecimal/round_spec.rb4
-rw-r--r--spec/ruby/library/bigdecimal/shared/to_int.rb2
-rw-r--r--spec/ruby/library/bigdecimal/to_s_spec.rb27
-rw-r--r--spec/ruby/library/cgi/escapeURIComponent_spec.rb57
-rw-r--r--spec/ruby/library/cgi/initialize_spec.rb2
-rw-r--r--spec/ruby/library/coverage/running_spec.rb2
-rw-r--r--spec/ruby/library/coverage/supported_spec.rb32
-rw-r--r--spec/ruby/library/date/deconstruct_keys_spec.rb44
-rw-r--r--spec/ruby/library/date/new_spec.rb1
-rw-r--r--spec/ruby/library/date/parse_spec.rb10
-rw-r--r--spec/ruby/library/date/shared/new_bang.rb14
-rw-r--r--spec/ruby/library/date/strftime_spec.rb6
-rw-r--r--spec/ruby/library/datetime/deconstruct_keys_spec.rb46
-rw-r--r--spec/ruby/library/datetime/rfc2822_spec.rb4
-rw-r--r--spec/ruby/library/datetime/strftime_spec.rb5
-rw-r--r--spec/ruby/library/datetime/to_time_spec.rb4
-rw-r--r--spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb1
-rw-r--r--spec/ruby/library/digest/md5/shared/sample.rb17
-rw-r--r--spec/ruby/library/erb/new_spec.rb2
-rw-r--r--spec/ruby/library/etc/confstr_spec.rb2
-rw-r--r--spec/ruby/library/etc/passwd_spec.rb2
-rw-r--r--spec/ruby/library/etc/sysconf_spec.rb2
-rw-r--r--spec/ruby/library/etc/sysconfdir_spec.rb2
-rw-r--r--spec/ruby/library/etc/systmpdir_spec.rb2
-rw-r--r--spec/ruby/library/expect/expect_spec.rb3
-rw-r--r--spec/ruby/library/fiber/current_spec.rb21
-rw-r--r--spec/ruby/library/fiber/resume_spec.rb35
-rw-r--r--spec/ruby/library/fiber/transfer_spec.rb56
-rw-r--r--spec/ruby/library/io-wait/fixtures/classes.rb12
-rw-r--r--spec/ruby/library/io-wait/wait_spec.rb144
-rw-r--r--spec/ruby/library/ipaddr/new_spec.rb10
-rw-r--r--spec/ruby/library/logger/device/close_spec.rb15
-rw-r--r--spec/ruby/library/logger/device/write_spec.rb15
-rw-r--r--spec/ruby/library/matrix/unitary_spec.rb6
-rw-r--r--spec/ruby/library/monitor/exit_spec.rb10
-rw-r--r--spec/ruby/library/net/ftp/shared/getbinaryfile.rb4
-rw-r--r--spec/ruby/library/net/ftp/shared/gettextfile.rb2
-rw-r--r--spec/ruby/library/net/ftp/shared/putbinaryfile.rb4
-rw-r--r--spec/ruby/library/net/ftp/shared/puttextfile.rb2
-rw-r--r--spec/ruby/library/net/ftp/storbinary_spec.rb2
-rw-r--r--spec/ruby/library/net/ftp/storlines_spec.rb2
-rw-r--r--spec/ruby/library/net/http/http/get_spec.rb16
-rw-r--r--spec/ruby/library/objectspace/dump_all_spec.rb112
-rw-r--r--spec/ruby/library/objectspace/dump_spec.rb70
-rw-r--r--spec/ruby/library/openssl/config/freeze_spec.rb22
-rw-r--r--spec/ruby/library/openssl/digest/append_spec.rb6
-rw-r--r--spec/ruby/library/openssl/digest/block_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_spec.rb62
-rw-r--r--spec/ruby/library/openssl/digest/initialize_spec.rb141
-rw-r--r--spec/ruby/library/openssl/digest/name_spec.rb16
-rw-r--r--spec/ruby/library/openssl/digest/reset_spec.rb36
-rw-r--r--spec/ruby/library/openssl/digest/shared/update.rb123
-rw-r--r--spec/ruby/library/openssl/digest/update_spec.rb6
-rw-r--r--spec/ruby/library/openssl/digest_spec.rb63
-rw-r--r--spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb185
-rw-r--r--spec/ruby/library/openssl/kdf/scrypt_spec.rb209
-rw-r--r--spec/ruby/library/openssl/random/shared/random_bytes.rb2
-rw-r--r--spec/ruby/library/pathname/relative_path_from_spec.rb4
-rw-r--r--spec/ruby/library/rexml/attribute/clone_spec.rb14
-rw-r--r--spec/ruby/library/rexml/attribute/element_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attribute/equal_value_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attribute/hash_spec.rb16
-rw-r--r--spec/ruby/library/rexml/attribute/initialize_spec.rb32
-rw-r--r--spec/ruby/library/rexml/attribute/inspect_spec.rb22
-rw-r--r--spec/ruby/library/rexml/attribute/namespace_spec.rb27
-rw-r--r--spec/ruby/library/rexml/attribute/node_type_spec.rb13
-rw-r--r--spec/ruby/library/rexml/attribute/prefix_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attribute/remove_spec.rb23
-rw-r--r--spec/ruby/library/rexml/attribute/to_s_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/to_string_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/value_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/write_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attribute/xpath_spec.rb22
-rw-r--r--spec/ruby/library/rexml/attributes/add_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/append_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/delete_all_spec.rb34
-rw-r--r--spec/ruby/library/rexml/attributes/delete_spec.rb30
-rw-r--r--spec/ruby/library/rexml/attributes/each_attribute_spec.rb25
-rw-r--r--spec/ruby/library/rexml/attributes/each_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attributes/element_reference_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attributes/element_set_spec.rb28
-rw-r--r--spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attributes/get_attribute_spec.rb32
-rw-r--r--spec/ruby/library/rexml/attributes/initialize_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attributes/length_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/namespaces_spec.rb9
-rw-r--r--spec/ruby/library/rexml/attributes/prefixes_spec.rb27
-rw-r--r--spec/ruby/library/rexml/attributes/shared/add.rb17
-rw-r--r--spec/ruby/library/rexml/attributes/shared/length.rb13
-rw-r--r--spec/ruby/library/rexml/attributes/size_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/to_a_spec.rb22
-rw-r--r--spec/ruby/library/rexml/cdata/clone_spec.rb13
-rw-r--r--spec/ruby/library/rexml/cdata/initialize_spec.rb27
-rw-r--r--spec/ruby/library/rexml/cdata/shared/to_s.rb11
-rw-r--r--spec/ruby/library/rexml/cdata/to_s_spec.rb10
-rw-r--r--spec/ruby/library/rexml/cdata/value_spec.rb10
-rw-r--r--spec/ruby/library/rexml/document/add_element_spec.rb34
-rw-r--r--spec/ruby/library/rexml/document/add_spec.rb60
-rw-r--r--spec/ruby/library/rexml/document/clone_spec.rb23
-rw-r--r--spec/ruby/library/rexml/document/doctype_spec.rb18
-rw-r--r--spec/ruby/library/rexml/document/encoding_spec.rb25
-rw-r--r--spec/ruby/library/rexml/document/expanded_name_spec.rb19
-rw-r--r--spec/ruby/library/rexml/document/new_spec.rb39
-rw-r--r--spec/ruby/library/rexml/document/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/document/root_spec.rb15
-rw-r--r--spec/ruby/library/rexml/document/stand_alone_spec.rb22
-rw-r--r--spec/ruby/library/rexml/document/version_spec.rb17
-rw-r--r--spec/ruby/library/rexml/document/write_spec.rb38
-rw-r--r--spec/ruby/library/rexml/document/xml_decl_spec.rb18
-rw-r--r--spec/ruby/library/rexml/element/add_attribute_spec.rb44
-rw-r--r--spec/ruby/library/rexml/element/add_attributes_spec.rb25
-rw-r--r--spec/ruby/library/rexml/element/add_element_spec.rb41
-rw-r--r--spec/ruby/library/rexml/element/add_namespace_spec.rb26
-rw-r--r--spec/ruby/library/rexml/element/add_text_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/attribute_spec.rb20
-rw-r--r--spec/ruby/library/rexml/element/attributes_spec.rb22
-rw-r--r--spec/ruby/library/rexml/element/cdatas_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/clone_spec.rb32
-rw-r--r--spec/ruby/library/rexml/element/comments_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/delete_attribute_spec.rb42
-rw-r--r--spec/ruby/library/rexml/element/delete_element_spec.rb52
-rw-r--r--spec/ruby/library/rexml/element/delete_namespace_spec.rb28
-rw-r--r--spec/ruby/library/rexml/element/document_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb38
-rw-r--r--spec/ruby/library/rexml/element/each_element_with_text_spec.rb34
-rw-r--r--spec/ruby/library/rexml/element/element_reference_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/get_text_spec.rb21
-rw-r--r--spec/ruby/library/rexml/element/has_attributes_spec.rb20
-rw-r--r--spec/ruby/library/rexml/element/has_elements_spec.rb21
-rw-r--r--spec/ruby/library/rexml/element/has_text_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/inspect_spec.rb30
-rw-r--r--spec/ruby/library/rexml/element/instructions_spec.rb24
-rw-r--r--spec/ruby/library/rexml/element/namespace_spec.rb30
-rw-r--r--spec/ruby/library/rexml/element/namespaces_spec.rb35
-rw-r--r--spec/ruby/library/rexml/element/new_spec.rb38
-rw-r--r--spec/ruby/library/rexml/element/next_element_spec.rb22
-rw-r--r--spec/ruby/library/rexml/element/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/element/prefixes_spec.rb26
-rw-r--r--spec/ruby/library/rexml/element/previous_element_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/raw_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/root_spec.rb31
-rw-r--r--spec/ruby/library/rexml/element/text_spec.rb49
-rw-r--r--spec/ruby/library/rexml/element/texts_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/whitespace_spec.rb26
-rw-r--r--spec/ruby/library/rexml/node/each_recursive_spec.rb24
-rw-r--r--spec/ruby/library/rexml/node/find_first_recursive_spec.rb28
-rw-r--r--spec/ruby/library/rexml/node/index_in_parent_spec.rb18
-rw-r--r--spec/ruby/library/rexml/node/next_sibling_node_spec.rb24
-rw-r--r--spec/ruby/library/rexml/node/parent_spec.rb23
-rw-r--r--spec/ruby/library/rexml/node/previous_sibling_node_spec.rb24
-rw-r--r--spec/ruby/library/rexml/shared/each_element.rb36
-rw-r--r--spec/ruby/library/rexml/shared/elements_to_a.rb34
-rw-r--r--spec/ruby/library/rexml/text/append_spec.rb13
-rw-r--r--spec/ruby/library/rexml/text/clone_spec.rb13
-rw-r--r--spec/ruby/library/rexml/text/comparison_spec.rb28
-rw-r--r--spec/ruby/library/rexml/text/empty_spec.rb15
-rw-r--r--spec/ruby/library/rexml/text/indent_text_spec.rb26
-rw-r--r--spec/ruby/library/rexml/text/inspect_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/new_spec.rb51
-rw-r--r--spec/ruby/library/rexml/text/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/normalize_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/read_with_substitution_spec.rb15
-rw-r--r--spec/ruby/library/rexml/text/to_s_spec.rb20
-rw-r--r--spec/ruby/library/rexml/text/unnormalize_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/value_spec.rb40
-rw-r--r--spec/ruby/library/rexml/text/wrap_spec.rb23
-rw-r--r--spec/ruby/library/rexml/text/write_with_substitution_spec.rb36
-rw-r--r--spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb2
-rw-r--r--spec/ruby/library/set/comparison_spec.rb56
-rw-r--r--spec/ruby/library/set/divide_spec.rb35
-rw-r--r--spec/ruby/library/set/each_spec.rb1
-rw-r--r--spec/ruby/library/set/enumerable/to_set_spec.rb8
-rw-r--r--spec/ruby/library/set/initialize_clone_spec.rb22
-rw-r--r--spec/ruby/library/set/join_spec.rb42
-rw-r--r--spec/ruby/library/set/shared/inspect.rb20
-rw-r--r--spec/ruby/library/set/sortedset/add_spec.rb42
-rw-r--r--spec/ruby/library/set/sortedset/append_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/case_equality_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/classify_spec.rb30
-rw-r--r--spec/ruby/library/set/sortedset/clear_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/collect_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/constructor_spec.rb18
-rw-r--r--spec/ruby/library/set/sortedset/delete_if_spec.rb41
-rw-r--r--spec/ruby/library/set/sortedset/delete_spec.rb40
-rw-r--r--spec/ruby/library/set/sortedset/difference_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/divide_spec.rb37
-rw-r--r--spec/ruby/library/set/sortedset/each_spec.rb29
-rw-r--r--spec/ruby/library/set/sortedset/empty_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/eql_spec.rb19
-rw-r--r--spec/ruby/library/set/sortedset/equal_value_spec.rb16
-rw-r--r--spec/ruby/library/set/sortedset/exclusion_spec.rb21
-rw-r--r--spec/ruby/library/set/sortedset/filter_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/flatten_merge_spec.rb11
-rw-r--r--spec/ruby/library/set/sortedset/flatten_spec.rb47
-rw-r--r--spec/ruby/library/set/sortedset/hash_spec.rb16
-rw-r--r--spec/ruby/library/set/sortedset/include_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/initialize_spec.rb33
-rw-r--r--spec/ruby/library/set/sortedset/inspect_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/intersection_spec.rb14
-rw-r--r--spec/ruby/library/set/sortedset/keep_if_spec.rb34
-rw-r--r--spec/ruby/library/set/sortedset/length_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/map_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/member_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/merge_spec.rb22
-rw-r--r--spec/ruby/library/set/sortedset/minus_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/plus_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/pretty_print_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/proper_subset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/proper_superset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/reject_spec.rb45
-rw-r--r--spec/ruby/library/set/sortedset/replace_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/select_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/shared/add.rb14
-rw-r--r--spec/ruby/library/set/sortedset/shared/collect.rb20
-rw-r--r--spec/ruby/library/set/sortedset/shared/difference.rb15
-rw-r--r--spec/ruby/library/set/sortedset/shared/include.rb7
-rw-r--r--spec/ruby/library/set/sortedset/shared/intersection.rb15
-rw-r--r--spec/ruby/library/set/sortedset/shared/length.rb6
-rw-r--r--spec/ruby/library/set/sortedset/shared/select.rb35
-rw-r--r--spec/ruby/library/set/sortedset/shared/union.rb15
-rw-r--r--spec/ruby/library/set/sortedset/size_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/sortedset_spec.rb24
-rw-r--r--spec/ruby/library/set/sortedset/subset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/subtract_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/superset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/to_a_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/union_spec.rb14
-rw-r--r--spec/ruby/library/set/to_s_spec.rb1
-rw-r--r--spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_spec.rb19
-rw-r--r--spec/ruby/library/socket/basicsocket/send_spec.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/shutdown_spec.rb20
-rw-r--r--spec/ruby/library/socket/fixtures/classes.rb6
-rw-r--r--spec/ruby/library/socket/ipsocket/getaddress_spec.rb2
-rw-r--r--spec/ruby/library/socket/shared/partially_closable_sockets.rb2
-rw-r--r--spec/ruby/library/socket/socket/new_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/tcpsocket/initialize_spec.rb21
-rw-r--r--spec/ruby/library/socket/tcpsocket/open_spec.rb1
-rw-r--r--spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpsocket/shared/new.rb16
-rw-r--r--spec/ruby/library/socket/udpsocket/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixserver/accept_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixserver/for_fd_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixserver/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/unixserver/open_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixserver/shared/new.rb26
-rw-r--r--spec/ruby/library/socket/unixsocket/addr_spec.rb5
-rw-r--r--spec/ruby/library/socket/unixsocket/inspect_spec.rb4
-rw-r--r--spec/ruby/library/socket/unixsocket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixsocket/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/unixsocket/open_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/pair_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/partially_closable_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/path_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/peeraddr_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/recv_io_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/recvfrom_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/send_io_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/shared/new.rb28
-rw-r--r--spec/ruby/library/stringio/append_spec.rb7
-rw-r--r--spec/ruby/library/stringio/bytes_spec.rb29
-rw-r--r--spec/ruby/library/stringio/chars_spec.rb29
-rw-r--r--spec/ruby/library/stringio/codepoints_spec.rb19
-rw-r--r--spec/ruby/library/stringio/initialize_spec.rb13
-rw-r--r--spec/ruby/library/stringio/lines_spec.rb53
-rw-r--r--spec/ruby/library/stringio/new_spec.rb8
-rw-r--r--spec/ruby/library/stringio/reopen_spec.rb30
-rw-r--r--spec/ruby/library/stringio/set_encoding_spec.rb8
-rw-r--r--spec/ruby/library/stringio/shared/each.rb4
-rw-r--r--spec/ruby/library/stringio/shared/sysread.rb2
-rw-r--r--spec/ruby/library/stringio/shared/write.rb28
-rw-r--r--spec/ruby/library/time/to_datetime_spec.rb5
-rw-r--r--spec/ruby/library/uri/generic/host_spec.rb7
-rw-r--r--spec/ruby/library/uri/generic/to_s_spec.rb7
-rw-r--r--spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/_invoke_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/codepage_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/connect_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/const_load_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/constants_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/create_guid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/invoke_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/locale_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_method_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/setproperty_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/visible_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/default_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/input_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/optional_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/retval_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/guid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progids_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/variables_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/visible_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/value_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb1
-rw-r--r--spec/ruby/library/yaml/fixtures/common.rb2
-rw-r--r--spec/ruby/library/zlib/deflate/new_spec.rb1
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_line_spec.rb1
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_spec.rb1
-rw-r--r--spec/ruby/library/zlib/gzipreader/mtime_spec.rb11
-rw-r--r--spec/ruby/library/zlib/gzipreader/new_spec.rb1
-rw-r--r--spec/ruby/library/zlib/inflate/finish_spec.rb1
-rw-r--r--spec/ruby/library/zlib/inflate/new_spec.rb1
-rw-r--r--spec/ruby/optional/capi/class_spec.rb32
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb30
-rw-r--r--spec/ruby/optional/capi/exception_spec.rb34
-rw-r--r--spec/ruby/optional/capi/ext/class_spec.c8
-rw-r--r--spec/ruby/optional/capi/ext/debug_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/encoding_spec.c23
-rw-r--r--spec/ruby/optional/capi/ext/exception_spec.c19
-rw-r--r--spec/ruby/optional/capi/ext/gc_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/hash_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/integer_spec.c5
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c73
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c19
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c36
-rw-r--r--spec/ruby/optional/capi/ext/proc_spec.c15
-rw-r--r--spec/ruby/optional/capi/ext/range_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h11
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c31
-rw-r--r--spec/ruby/optional/capi/ext/struct_spec.c13
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c5
-rw-r--r--spec/ruby/optional/capi/ext/tracepoint_spec.c2
-rw-r--r--spec/ruby/optional/capi/fixtures/kernel.rb19
-rw-r--r--spec/ruby/optional/capi/hash_spec.rb16
-rw-r--r--spec/ruby/optional/capi/io_spec.rb98
-rw-r--r--spec/ruby/optional/capi/kernel_spec.rb135
-rw-r--r--spec/ruby/optional/capi/object_spec.rb12
-rw-r--r--spec/ruby/optional/capi/proc_spec.rb53
-rw-r--r--spec/ruby/optional/capi/string_spec.rb63
-rw-r--r--spec/ruby/optional/capi/thread_spec.rb28
-rw-r--r--spec/ruby/optional/capi/time_spec.rb5
-rw-r--r--spec/ruby/optional/capi/util_spec.rb93
-rw-r--r--spec/ruby/security/cve_2014_8080_spec.rb34
-rw-r--r--spec/ruby/security/cve_2017_17742_spec.rb37
-rw-r--r--spec/ruby/shared/file/exist.rb5
-rw-r--r--spec/ruby/shared/kernel/at_exit.rb67
-rw-r--r--spec/ruby/shared/kernel/fixtures/END.rb3
-rw-r--r--spec/ruby/shared/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/shared/process/exit.rb6
-rw-r--r--spec/ruby/shared/queue/deque.rb23
-rw-r--r--spec/ruby/shared/rational/Rational.rb9
-rw-r--r--spec/ruby/shared/rational/marshal_dump.rb5
-rw-r--r--spec/ruby/shared/rational/marshal_load.rb5
-rw-r--r--spec/ruby/shared/rational/quo.rb5
-rw-r--r--spec/ruby/shared/rational/truncate.rb26
-rw-r--r--spec/ruby/shared/sizedqueue/enque.rb24
-rw-r--r--spec/ruby/shared/string/start_with.rb12
-rw-r--r--spec/ruby/shared/string/times.rb18
-rw-r--r--spec/ruby/shared/types/rb_num2dbl_fails.rb17
-rw-r--r--spec/ruby/spec_helper.rb2
-rw-r--r--spec/syntax_suggest/integration/ruby_command_line_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/pathname_from_message_spec.rb9
-rw-r--r--sprintf.c5
-rw-r--r--st.c200
-rw-r--r--string.c974
-rw-r--r--string.rb6
-rw-r--r--struct.c154
-rw-r--r--symbol.c50
-rw-r--r--symbol.h5
-rw-r--r--symbol.rb2
-rw-r--r--template/Doxyfile.tmpl363
-rw-r--r--template/GNUmakefile.in1
-rw-r--r--template/Makefile.in135
-rw-r--r--template/builtin_binary.inc.tmpl10
-rw-r--r--template/configure-ext.mk.tmpl2
-rw-r--r--template/extinit.c.tmpl2
-rw-r--r--template/exts.mk.tmpl2
-rw-r--r--template/fake.rb.in6
-rw-r--r--template/id.c.tmpl3
-rw-r--r--template/id.h.tmpl9
-rw-r--r--template/prelude.c.tmpl35
-rw-r--r--template/ruby.pc.in2
-rwxr-xr-xtemplate/unicode_properties.rdoc.tmpl59
-rw-r--r--test/-ext-/bug_reporter/test_bug_reporter.rb17
-rw-r--r--test/-ext-/debug/test_profile_frames.rb63
-rw-r--r--test/-ext-/iseq_load/test_iseq_load.rb2
-rw-r--r--test/-ext-/string/test_capacity.rb8
-rw-r--r--test/-ext-/string/test_fstring.rb12
-rw-r--r--test/-ext-/string/test_too_many_dummy_encodings.rb15
-rw-r--r--test/-ext-/struct/test_data.rb18
-rw-r--r--test/-ext-/symbol/test_type.rb5
-rw-r--r--test/.excludes/TestArraySubclass.rb1
-rw-r--r--test/.excludes/TestThread.rb18
-rw-r--r--test/bigdecimal/test_bigdecimal.rb33
-rw-r--r--test/cgi/test_cgi_util.rb31
-rw-r--r--test/coverage/test_coverage.rb64
-rw-r--r--test/csv/helper.rb2
-rw-r--r--test/csv/interface/test_read.rb6
-rw-r--r--test/csv/parse/test_general.rb27
-rw-r--r--test/csv/parse/test_inputs_scanner.rb2
-rw-r--r--test/csv/parse/test_row_separator.rb2
-rw-r--r--test/csv/parse/test_skip_lines.rb10
-rw-r--r--test/csv/test_encodings.rb8
-rw-r--r--test/csv/write/test_general.rb2
-rw-r--r--test/did_you_mean/core_ext/test_name_error_extension.rb4
-rw-r--r--test/drb/drbtest.rb2
-rw-r--r--test/drb/test_drbssl.rb4
-rw-r--r--test/drb/ut_array_drbssl.rb4
-rw-r--r--test/error_highlight/test_error_highlight.rb180
-rw-r--r--test/excludes/TestArray.rb (renamed from test/.excludes/TestArray.rb)0
-rw-r--r--test/excludes/TestException.rb (renamed from test/.excludes/TestException.rb)0
-rw-r--r--test/excludes/TestGem.rb (renamed from test/.excludes/TestGem.rb)0
-rw-r--r--test/excludes/TestIO_Console.rb (renamed from test/.excludes/TestIO_Console.rb)0
-rw-r--r--test/excludes/TestISeq.rb (renamed from test/.excludes/TestISeq.rb)0
-rw-r--r--test/excludes/TestThread.rb14
-rw-r--r--test/excludes/TestThreadQueue.rb (renamed from test/.excludes/TestThreadQueue.rb)0
-rw-r--r--test/excludes/_appveyor/TestArray.rb (renamed from test/.excludes/_appveyor/TestArray.rb)0
-rw-r--r--test/fiber/scheduler.rb130
-rw-r--r--test/fiber/test_enumerator.rb8
-rw-r--r--test/fiber/test_io.rb15
-rw-r--r--test/fiber/test_io_buffer.rb41
-rw-r--r--test/fiber/test_scheduler.rb43
-rw-r--r--test/fiber/test_thread.rb2
-rw-r--r--test/fiddle/test_c_struct_entry.rb8
-rw-r--r--test/fiddle/test_closure.rb12
-rw-r--r--test/fiddle/test_cparser.rb40
-rw-r--r--test/fiddle/test_func.rb17
-rw-r--r--test/fiddle/test_pointer.rb16
-rw-r--r--test/fileutils/test_fileutils.rb8
-rw-r--r--test/fixtures/fake_sorted_set_gem/sorted_set.rb (renamed from test/set/fixtures/fake_sorted_set_gem/sorted_set.rb)0
-rw-r--r--test/io/console/test_io_console.rb10
-rw-r--r--test/irb/helper.rb145
-rw-r--r--test/irb/test_cmd.rb882
-rw-r--r--test/irb/test_color.rb62
-rw-r--r--test/irb/test_color_printer.rb19
-rw-r--r--test/irb/test_completion.rb279
-rw-r--r--test/irb/test_context.rb203
-rw-r--r--test/irb/test_debug_cmd.rb331
-rw-r--r--test/irb/test_eval_history.rb68
-rw-r--r--test/irb/test_evaluation.rb44
-rw-r--r--test/irb/test_history.rb224
-rw-r--r--test/irb/test_init.rb18
-rw-r--r--test/irb/test_input_method.rb114
-rw-r--r--test/irb/test_irb.rb748
-rw-r--r--test/irb/test_locale.rb118
-rw-r--r--test/irb/test_nesting_parser.rb303
-rw-r--r--test/irb/test_option.rb2
-rw-r--r--test/irb/test_raise_no_backtrace_exception.rb2
-rw-r--r--test/irb/test_ruby_lex.rb815
-rw-r--r--test/irb/test_workspace.rb3
-rw-r--r--test/irb/type_completion/test_scope.rb114
-rw-r--r--test/irb/type_completion/test_type_analyze.rb699
-rw-r--r--test/irb/type_completion/test_type_completor.rb183
-rw-r--r--test/irb/type_completion/test_types.rb91
-rw-r--r--test/irb/yamatanooroti/test_rendering.rb573
-rw-r--r--test/json/json_addition_test.rb4
-rw-r--r--test/json/json_common_interface_test.rb2
-rw-r--r--test/json/json_encoding_test.rb6
-rw-r--r--test/json/json_ext_parser_test.rb2
-rw-r--r--test/json/json_fixtures_test.rb2
-rw-r--r--[-rwxr-xr-x]test/json/json_generator_test.rb29
-rw-r--r--test/json/json_generic_object_test.rb2
-rw-r--r--test/json/json_parser_test.rb12
-rw-r--r--test/json/json_string_matching_test.rb2
-rw-r--r--test/json/ractor_test.rb2
-rw-r--r--test/lib/!Nothing_to_test.rb5
-rw-r--r--test/lib/jit_support.rb93
-rw-r--r--test/logger/test_severity.rb32
-rw-r--r--test/mkmf/base.rb7
-rw-r--r--test/mkmf/test_config.rb29
-rw-r--r--test/mkmf/test_configuration.rb39
-rw-r--r--test/mkmf/test_flags.rb6
-rw-r--r--test/net/fixtures/Makefile6
-rw-r--r--test/net/fixtures/cacert.pem44
-rw-r--r--test/net/fixtures/server.crt99
-rw-r--r--test/net/fixtures/server.key55
-rw-r--r--test/net/http/test_http.rb12
-rw-r--r--test/net/http/test_https.rb6
-rw-r--r--test/objspace/test_objspace.rb91
-rw-r--r--test/open-uri/test_open-uri.rb13
-rw-r--r--test/openssl/test_asn1.rb8
-rw-r--r--test/openssl/test_bn.rb4
-rw-r--r--test/openssl/test_cipher.rb2
-rw-r--r--test/openssl/test_config.rb12
-rw-r--r--test/openssl/test_digest.rb2
-rw-r--r--test/openssl/test_engine.rb38
-rw-r--r--test/openssl/test_fips.rb40
-rw-r--r--test/openssl/test_ns_spki.rb6
-rw-r--r--test/openssl/test_ossl.rb13
-rw-r--r--test/openssl/test_pkcs12.rb4
-rw-r--r--test/openssl/test_pkey.rb84
-rw-r--r--test/openssl/test_pkey_dsa.rb2
-rw-r--r--test/openssl/test_pkey_ec.rb29
-rw-r--r--test/openssl/test_pkey_rsa.rb2
-rw-r--r--test/openssl/test_provider.rb67
-rw-r--r--test/openssl/test_ssl.rb38
-rw-r--r--test/openssl/test_ssl_session.rb2
-rw-r--r--test/openssl/test_x509ext.rb37
-rw-r--r--test/openssl/test_x509req.rb7
-rw-r--r--test/openssl/utils.rb53
-rw-r--r--test/optparse/test_getopts.rb16
-rw-r--r--test/ostruct/test_ostruct.rb19
-rw-r--r--test/prism/bom_test.rb59
-rw-r--r--test/prism/comments_test.rb152
-rw-r--r--test/prism/compiler_test.rb30
-rw-r--r--test/prism/constant_path_node_test.rb29
-rw-r--r--test/prism/desugar_compiler_test.rb86
-rw-r--r--test/prism/dispatcher_test.rb46
-rw-r--r--test/prism/encoding_test.rb106
-rw-r--r--test/prism/errors_test.rb1448
-rw-r--r--test/prism/fixtures/alias.txt23
-rw-r--r--test/prism/fixtures/arithmetic.txt13
-rw-r--r--test/prism/fixtures/arrays.txt118
-rw-r--r--test/prism/fixtures/begin_ensure.txt21
-rw-r--r--test/prism/fixtures/begin_rescue.txt79
-rw-r--r--test/prism/fixtures/blocks.txt54
-rw-r--r--test/prism/fixtures/boolean_operators.txt5
-rw-r--r--test/prism/fixtures/booleans.txt3
-rw-r--r--test/prism/fixtures/break.txt25
-rw-r--r--test/prism/fixtures/case.txt32
-rw-r--r--test/prism/fixtures/classes.txt35
-rw-r--r--test/prism/fixtures/comments.txt24
-rw-r--r--test/prism/fixtures/constants.txt184
-rw-r--r--test/prism/fixtures/dash_heredocs.txt63
-rw-r--r--test/prism/fixtures/defined.txt7
-rw-r--r--test/prism/fixtures/dos_endings.txt20
-rw-r--r--test/prism/fixtures/embdoc_no_newline_at_end.txt2
-rw-r--r--test/prism/fixtures/endless_methods.txt5
-rw-r--r--test/prism/fixtures/endless_range_in_conditional.txt3
-rw-r--r--test/prism/fixtures/for.txt19
-rw-r--r--test/prism/fixtures/global_variables.txt93
-rw-r--r--test/prism/fixtures/hashes.txt26
-rw-r--r--test/prism/fixtures/heredoc_with_escaped_newline_at_start.txt7
-rw-r--r--test/prism/fixtures/heredoc_with_trailing_newline.txt2
-rw-r--r--test/prism/fixtures/heredocs_nested.txt9
-rw-r--r--test/prism/fixtures/heredocs_with_ignored_newlines.txt14
-rw-r--r--test/prism/fixtures/heredocs_with_ignored_newlines_and_non_empty.txt4
-rw-r--r--test/prism/fixtures/if.txt42
-rw-r--r--test/prism/fixtures/indented_file_end.txt4
-rw-r--r--test/prism/fixtures/integer_operations.txt63
-rw-r--r--test/prism/fixtures/keyword_method_names.txt29
-rw-r--r--test/prism/fixtures/keywords.txt11
-rw-r--r--test/prism/fixtures/lambda.txt11
-rw-r--r--test/prism/fixtures/method_calls.txt147
-rw-r--r--test/prism/fixtures/methods.txt170
-rw-r--r--test/prism/fixtures/modules.txt18
-rw-r--r--test/prism/fixtures/newline_terminated.txtbin212 -> 0 bytes-rw-r--r--test/prism/fixtures/next.txt24
-rw-r--r--test/prism/fixtures/nils.txt13
-rw-r--r--test/prism/fixtures/non_alphanumeric_methods.txt105
-rw-r--r--test/prism/fixtures/not.txt37
-rw-r--r--test/prism/fixtures/numbers.txt63
-rw-r--r--test/prism/fixtures/patterns.txt192
-rw-r--r--test/prism/fixtures/procs.txt27
-rw-r--r--test/prism/fixtures/range_begin_open_exclusive.txt1
-rw-r--r--test/prism/fixtures/range_begin_open_inclusive.txt1
-rw-r--r--test/prism/fixtures/range_end_open_exclusive.txt1
-rw-r--r--test/prism/fixtures/range_end_open_inclusive.txt1
-rw-r--r--test/prism/fixtures/ranges.txt17
-rw-r--r--test/prism/fixtures/regex.txt33
-rw-r--r--test/prism/fixtures/rescue.txt31
-rw-r--r--test/prism/fixtures/return.txt24
-rw-r--r--test/prism/fixtures/seattlerb/BEGIN.txt1
-rw-r--r--test/prism/fixtures/seattlerb/README.rdoc113
-rw-r--r--test/prism/fixtures/seattlerb/TestRubyParserShared.txt92
-rw-r--r--test/prism/fixtures/seattlerb/__ENCODING__.txt1
-rw-r--r--test/prism/fixtures/seattlerb/alias_gvar_backref.txt1
-rw-r--r--test/prism/fixtures/seattlerb/alias_resword.txt1
-rw-r--r--test/prism/fixtures/seattlerb/and_multi.txt3
-rw-r--r--test/prism/fixtures/seattlerb/aref_args_assocs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/aref_args_lit_assocs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/args_kw_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/array_line_breaks.txt4
-rw-r--r--test/prism/fixtures/seattlerb/array_lits_trailing_calls.txt3
-rw-r--r--test/prism/fixtures/seattlerb/assoc__bare.txt1
-rw-r--r--test/prism/fixtures/seattlerb/assoc_label.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attr_asgn_colon_id.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_array_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_array_lhs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_primary_dot_constant.txt1
-rw-r--r--test/prism/fixtures/seattlerb/backticks_interpolation_line.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bang_eq.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bdot2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bdot3.txt3
-rw-r--r--test/prism/fixtures/seattlerb/begin_ensure_no_bodies.txt3
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_else_ensure_bodies.txt9
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_else_ensure_no_bodies.txt9
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_ensure_no_bodies.txt4
-rw-r--r--test/prism/fixtures/seattlerb/block_arg__bare.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_arg_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_optional.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_scope2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_no_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt2_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_break.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_defn_call_block_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/block_call_dot_op2_brace_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_dot_op2_cmd_args_do_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_operation_colon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_operation_dot.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_paren_call_block_call.txt2
-rw-r--r--test/prism/fixtures/seattlerb/block_command_operation_colon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_command_operation_dot.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_anon_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_arg_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kwarg_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kwarg_lvar_multiple.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_next.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_optarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_paren_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_reg_optarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_return.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_splat_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug169.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug179.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug190.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug191.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug202.txt2
-rw-r--r--test/prism/fixtures/seattlerb/bug236.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug290.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug_187.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug_215.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_249.txt4
-rw-r--r--test/prism/fixtures/seattlerb/bug_and.txt4
-rw-r--r--test/prism/fixtures/seattlerb/bug_args__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn_outer_parens__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_call_arglist_parens.txt11
-rw-r--r--test/prism/fixtures/seattlerb/bug_case_when_regexp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_cond_pct.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_args_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_interp_array.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_masgn_right.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_not_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_op_asgn_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_and.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_assoc.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_assoc_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_args_assoc_quoted.txt5
-rw-r--r--test/prism/fixtures/seattlerb/call_args_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_args_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_block_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_lambda_block_call.txt2
-rw-r--r--test/prism/fixtures/seattlerb/call_array_lit_inline_hash.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_new.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_new_if_multiline.txt5
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_bang_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_bang_squiggle.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_begin_call_block_call.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_block_arg_named.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_carat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_colon2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_colon_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_div.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_dot_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_eq3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_gt.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_leading_dots.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_leading_dots_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/call_lt.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_lte.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_not.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_pipe.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_rshift.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_self_brackets.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_spaceship.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_stabby_do_end_with_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_stabby_with_braces_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_star.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_star2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_trailing_dots.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_unary_bang.txt1
-rw-r--r--test/prism/fixtures/seattlerb/case_in.txt111
-rw-r--r--test/prism/fixtures/seattlerb/case_in_31.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_37.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_42.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_42_2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_47.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_67.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_86.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_86_2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_const.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_const2.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_paren_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_const.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_else.txt7
-rw-r--r--test/prism/fixtures/seattlerb/case_in_find.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_find_array.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat.txt5
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_paren_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_paren_true.txt5
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_rest.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_rest_solo.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_if_unless_post_mod.txt6
-rw-r--r--test/prism/fixtures/seattlerb/case_in_multiple.txt6
-rw-r--r--test/prism/fixtures/seattlerb/case_in_or.txt5
-rw-r--r--test/prism/fixtures/seattlerb/class_comments.txt9
-rw-r--r--test/prism/fixtures/seattlerb/cond_unary_minus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_2_op_asgn_or2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_3_op_asgn_or.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_and1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_and2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_or.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dasgn_icky2.txt8
-rw-r--r--test/prism/fixtures/seattlerb/defined_eh_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_arg_asplat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_arg_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_args_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_comments.txt5
-rw-r--r--test/prism/fixtures/seattlerb/defn_endless_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_endless_command_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_forward_args__no_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwsplat_anon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_no_parens.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_val.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_no_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_eq2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_noargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_noargs_parentheses.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_rescue.txt13
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_last_arg.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_powarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_reg_opt_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_unary_not.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defns_reserved.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_as_arg_with_do_block_inside.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_comments.txt5
-rw-r--r--test/prism/fixtures/seattlerb/defs_endless_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_endless_command_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_kwarg.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner_eq2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner_rescue.txt13
-rw-r--r--test/prism/fixtures/seattlerb/difficult0_.txt4
-rw-r--r--test/prism/fixtures/seattlerb/difficult1_line_numbers.txt13
-rw-r--r--test/prism/fixtures/seattlerb/difficult1_line_numbers2.txt8
-rw-r--r--test/prism/fixtures/seattlerb/difficult2_.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_5.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__10.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__11.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__12.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__6.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__7.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__8.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__9.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult4__leading_dots.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult4__leading_dots2.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult6_.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult6__7.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult6__8.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult7_.txt5
-rw-r--r--test/prism/fixtures/seattlerb/do_bug.txt4
-rw-r--r--test/prism/fixtures/seattlerb/do_lambda.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dot2_nil__26.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dot3_nil__26.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_evstr_empty_end.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_lex_state.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dsym_esc_to_sym.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dsym_to_sym.txt3
-rw-r--r--test/prism/fixtures/seattlerb/eq_begin_line_numbers.txt6
-rw-r--r--test/prism/fixtures/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt3
-rw-r--r--test/prism/fixtures/seattlerb/evstr_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/evstr_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/expr_not_bang.txt1
-rw-r--r--test/prism/fixtures/seattlerb/f_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/f_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/flip2_env_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/float_with_if_modifier.txt1
-rw-r--r--test/prism/fixtures/seattlerb/heredoc__backslash_dos_format.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_backslash_nl.txt8
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_bad_hex_escape.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_bad_oct_escape.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_comma_arg.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_lineno.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_nested.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_blank_lines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_empty.txt2
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_interp.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_no_indent.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_tabs.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_tabs_extra.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_visually_blank_lines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_trailing_slash_continued_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_unicode.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes_windows.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_horrible_mix.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns_windows.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes_windows.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_not_global_interpolation.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns_windows.txt6
-rw-r--r--test/prism/fixtures/seattlerb/if_elsif.txt1
-rw-r--r--test/prism/fixtures/seattlerb/if_symbol.txt1
-rw-r--r--test/prism/fixtures/seattlerb/in_expr_no_case.txt1
-rw-r--r--test/prism/fixtures/seattlerb/index_0.txt1
-rw-r--r--test/prism/fixtures/seattlerb/index_0_opasgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/integer_with_if_modifier.txt1
-rw-r--r--test/prism/fixtures/seattlerb/interpolated_symbol_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/interpolated_word_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_10_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_10_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_11_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_11_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_2__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_5.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_6.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_7_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_7_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_8_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_8_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_9_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_9_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_kwarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_kwarg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/label_vs_string.txt2
-rw-r--r--test/prism/fixtures/seattlerb/lambda_do_vs_brace.txt7
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_arg_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_call_bracket_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_call_nobracket_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_ivar_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_lasgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_middle_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/magic_encoding_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/masgn_anon_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_colon_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_ident.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_colon2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_colon3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_double_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_lhs_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_splat_arg_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_star.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_var_star_var.txt1
-rw-r--r--test/prism/fixtures/seattlerb/messy_op_asgn_lineno.txt1
-rw-r--r--test/prism/fixtures/seattlerb/method_call_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/method_call_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_back_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_back_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_front_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_front_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_keyword.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_mid_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_mid_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/module_comments.txt10
-rw-r--r--test/prism/fixtures/seattlerb/multiline_hash_declaration.txt8
-rw-r--r--test/prism/fixtures/seattlerb/non_interpolated_symbol_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/non_interpolated_word_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_dot_ident_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_index_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_const_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_val_dot_ident_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_def_special_name.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_if_not_canonical.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_if_not_noncanonical.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_comment.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_comment_leading_newlines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_multiline_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_ivar_arg_no_parens_line_break.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_ivar_line_break_paren.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_no_args.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_complex.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_no_parens.txt6
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_no_parens_args.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot2.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot2_open.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot3.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot3_open.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dstr_escaped_newline.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dstr_soft_newline.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_evstr_after_break.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_hash_lit.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_evstr.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_hardnewline.txt7
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_regexp_chars.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_iter_call_no_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_iter_call_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_multiline_str.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_multiline_str_literal_n.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_newlines.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_op_asgn.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_postexe.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_preexe.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_rescue.txt8
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_return.txt6
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_str_with_newline_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_to_ary.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_trailing_newlines.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_opt_call_args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_opt_call_args_lit_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_019.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_044.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_051.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_058.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_058_2.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_069.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_076.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_until_not_canonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_until_not_noncanonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_while_not_canonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_while_not_noncanonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/pctW_lineno.txt5
-rw-r--r--test/prism/fixtures/seattlerb/pct_Q_backslash_nl.txt2
-rw-r--r--test/prism/fixtures/seattlerb/pct_nl.txt3
-rw-r--r--test/prism/fixtures/seattlerb/pct_w_heredoc_interp_nested.txt4
-rw-r--r--test/prism/fixtures/seattlerb/pipe_semicolon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/pipe_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qWords_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_empty_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_interp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/quoted_symbol_hash_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/quoted_symbol_keys.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qw_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qw_escape_term.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qwords_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/read_escape_unicode_curlies.txt1
-rw-r--r--test/prism/fixtures/seattlerb/read_escape_unicode_h4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp.txt9
-rw-r--r--test/prism/fixtures/seattlerb/regexp_esc_C_slash.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_esc_u.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_escape_extended.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_unicode_curlies.txt3
-rw-r--r--test/prism/fixtures/seattlerb/required_kwarg_no_value.txt2
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_ensure_result.txt5
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_no_raise.txt9
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_raised.txt5
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_rescued.txt9
-rw-r--r--test/prism/fixtures/seattlerb/rescue_in_block.txt4
-rw-r--r--test/prism/fixtures/seattlerb/rescue_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/return_call_assocs.txt11
-rw-r--r--test/prism/fixtures/seattlerb/rhs_asgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/ruby21_numbers.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_attrasgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_attrasgn_constant.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_after_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_dot_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_operator.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_rhs_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_calls.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_op_asgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_op_asgn2.txt2
-rw-r--r--test/prism/fixtures/seattlerb/slashy_newlines_within_string.txt7
-rw-r--r--test/prism/fixtures/seattlerb/stabby_arg_no_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_iter_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_iter_call_no_target_with_arg.txt4
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_proc_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_backslashes.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_evstr_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_heredoc_interp.txt5
-rw-r--r--test/prism/fixtures/seattlerb/str_interp_ternary_or_label.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_lit_concat_bad_encodings.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_newline_hash_line_number.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_Q_nested.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_nested_nested.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_q.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_str_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/super_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbol_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbol_list.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_empty_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_interp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/thingy.txt3
-rw-r--r--test/prism/fixtures/seattlerb/uminus_float.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_minus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_plus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_plus_on_literal.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_tilde.txt1
-rw-r--r--test/prism/fixtures/seattlerb/utf8_bom.txt3
-rw-r--r--test/prism/fixtures/seattlerb/when_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/words_interp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/yield_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/yield_call_assocs.txt11
-rw-r--r--test/prism/fixtures/seattlerb/yield_empty_parens.txt1
-rw-r--r--test/prism/fixtures/single_quote_heredocs.txt3
-rw-r--r--test/prism/fixtures/spanning_heredoc.txt55
-rw-r--r--test/prism/fixtures/strings.txt105
-rw-r--r--test/prism/fixtures/super.txt17
-rw-r--r--test/prism/fixtures/symbols.txt93
-rw-r--r--test/prism/fixtures/ternary_operator.txt15
-rw-r--r--test/prism/fixtures/tilde_heredocs.txt97
-rw-r--r--test/prism/fixtures/undef.txt17
-rw-r--r--test/prism/fixtures/unescaping.txt9
-rw-r--r--test/prism/fixtures/unless.txt14
-rw-r--r--test/prism/fixtures/unparser/LICENSE20
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/alias.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/assignment.txt53
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/block.txt96
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/case.txt37
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/class.txt35
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/control.txt15
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/def.txt134
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/defined.txt3
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/defs.txt40
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/dstr.txt37
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/empty.txt0
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/empty_begin.txt1
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/flipflop.txt6
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/for.txt12
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/hookexe.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/if.txt36
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/kwbegin.txt80
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/lambda.txt13
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/literal.txt91
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/module.txt16
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/opasgn.txt24
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/pattern.txt41
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/pragma.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/range.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/rescue.txt3
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/send.txt84
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/27.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/30.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/31.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/32.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/singletons.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/super.txt21
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/unary.txt8
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/undef.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/variables.txt10
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/while.txt73
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/yield.txt3
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/and.txt8
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/block.txt26
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/def.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/dstr.txt127
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/kwbegin.txt42
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/literal.txt14
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/send.txt6
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/undef.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/while.txt25
-rw-r--r--test/prism/fixtures/until.txt11
-rw-r--r--test/prism/fixtures/variables.txt47
-rw-r--r--test/prism/fixtures/while.txt21
-rw-r--r--test/prism/fixtures/whitequark/LICENSE25
-rw-r--r--test/prism/fixtures/whitequark/__ENCODING__.txt1
-rw-r--r--test/prism/fixtures/whitequark/__ENCODING___legacy_.txt1
-rw-r--r--test/prism/fixtures/whitequark/alias.txt1
-rw-r--r--test/prism/fixtures/whitequark/alias_gvar.txt3
-rw-r--r--test/prism/fixtures/whitequark/ambiuous_quoted_label_in_ternary_operator.txt1
-rw-r--r--test/prism/fixtures/whitequark/and.txt3
-rw-r--r--test/prism/fixtures/whitequark/and_asgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/and_or_masgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/anonymous_blockarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/arg.txt3
-rw-r--r--test/prism/fixtures/whitequark/arg_duplicate_ignored.txt3
-rw-r--r--test/prism/fixtures/whitequark/arg_label.txt6
-rw-r--r--test/prism/fixtures/whitequark/arg_scope.txt1
-rw-r--r--test/prism/fixtures/whitequark/args.txt63
-rw-r--r--test/prism/fixtures/whitequark/args_args_assocs.txt3
-rw-r--r--test/prism/fixtures/whitequark/args_args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_args_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_args_star.txt3
-rw-r--r--test/prism/fixtures/whitequark/args_assocs.txt11
-rw-r--r--test/prism/fixtures/whitequark/args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_assocs_legacy.txt11
-rw-r--r--test/prism/fixtures/whitequark/args_block_pass.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_star.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_assocs.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_splat.txt5
-rw-r--r--test/prism/fixtures/whitequark/array_symbols.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_symbols_empty.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_symbols_interp.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_words.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_words_empty.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_words_interp.txt3
-rw-r--r--test/prism/fixtures/whitequark/asgn_cmd.txt3
-rw-r--r--test/prism/fixtures/whitequark/asgn_mrhs.txt5
-rw-r--r--test/prism/fixtures/whitequark/back_ref.txt1
-rw-r--r--test/prism/fixtures/whitequark/bang.txt1
-rw-r--r--test/prism/fixtures/whitequark/bang_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/begin_cmdarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/beginless_erange_after_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/beginless_irange_after_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/beginless_range.txt3
-rw-r--r--test/prism/fixtures/whitequark/blockarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/blockargs.txt71
-rw-r--r--test/prism/fixtures/whitequark/break.txt7
-rw-r--r--test/prism/fixtures/whitequark/break_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_435.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_447.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_452.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_466.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_473.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_480.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_481.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_ascii_8bit_in_literal.txt2
-rw-r--r--test/prism/fixtures/whitequark/bug_cmd_string_lookahead.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_cmdarg.txt5
-rw-r--r--test/prism/fixtures/whitequark/bug_def_no_paren_eql_begin.txt4
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_call_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_cmdarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_hash_brace.txt9
-rw-r--r--test/prism/fixtures/whitequark/bug_heredoc_do.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_interp_single.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_lambda_leakage.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_regex_verification.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_rescue_empty_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_while_not_parens_do.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_cond.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_cond_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_expr.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_expr_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_scoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_toplevel.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_unscoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/character.txt1
-rw-r--r--test/prism/fixtures/whitequark/class.txt3
-rw-r--r--test/prism/fixtures/whitequark/class_definition_in_while_cond.txt7
-rw-r--r--test/prism/fixtures/whitequark/class_super.txt1
-rw-r--r--test/prism/fixtures/whitequark/class_super_label.txt1
-rw-r--r--test/prism/fixtures/whitequark/comments_before_leading_dot__27.txt19
-rw-r--r--test/prism/fixtures/whitequark/complex.txt7
-rw-r--r--test/prism/fixtures/whitequark/cond_begin.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_begin_masgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_eflipflop.txt3
-rw-r--r--test/prism/fixtures/whitequark/cond_iflipflop.txt3
-rw-r--r--test/prism/fixtures/whitequark/cond_match_current_line.txt3
-rw-r--r--test/prism/fixtures/whitequark/const_op_asgn.txt9
-rw-r--r--test/prism/fixtures/whitequark/const_scoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/const_toplevel.txt1
-rw-r--r--test/prism/fixtures/whitequark/const_unscoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/cpath.txt3
-rw-r--r--test/prism/fixtures/whitequark/cvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/cvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/dedenting_heredoc.txt75
-rw-r--r--test/prism/fixtures/whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt4
-rw-r--r--test/prism/fixtures/whitequark/dedenting_non_interpolating_heredoc_line_continuation.txt4
-rw-r--r--test/prism/fixtures/whitequark/def.txt11
-rw-r--r--test/prism/fixtures/whitequark/defined.txt5
-rw-r--r--test/prism/fixtures/whitequark/defs.txt9
-rw-r--r--test/prism/fixtures/whitequark/empty_stmt.txt1
-rw-r--r--test/prism/fixtures/whitequark/endless_comparison_method.txt11
-rw-r--r--test/prism/fixtures/whitequark/endless_method.txt7
-rw-r--r--test/prism/fixtures/whitequark/endless_method_command_syntax.txt15
-rw-r--r--test/prism/fixtures/whitequark/endless_method_forwarded_args_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/endless_method_with_rescue_mod.txt3
-rw-r--r--test/prism/fixtures/whitequark/endless_method_without_args.txt7
-rw-r--r--test/prism/fixtures/whitequark/ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/ensure_empty.txt1
-rw-r--r--test/prism/fixtures/whitequark/false.txt1
-rw-r--r--test/prism/fixtures/whitequark/float.txt3
-rw-r--r--test/prism/fixtures/whitequark/for.txt3
-rw-r--r--test/prism/fixtures/whitequark/for_mlhs.txt1
-rw-r--r--test/prism/fixtures/whitequark/forward_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forward_arg_with_open_args.txt27
-rw-r--r--test/prism/fixtures/whitequark/forward_args_legacy.txt5
-rw-r--r--test/prism/fixtures/whitequark/forwarded_argument_with_kwrestarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_argument_with_restarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_kwrestarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_restarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/gvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/gvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_empty.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_hashrocket.txt3
-rw-r--r--test/prism/fixtures/whitequark/hash_kwsplat.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_label.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_label_end.txt5
-rw-r--r--test/prism/fixtures/whitequark/hash_pair_value_omission.txt5
-rw-r--r--test/prism/fixtures/whitequark/heredoc.txt14
-rw-r--r--test/prism/fixtures/whitequark/if.txt3
-rw-r--r--test/prism/fixtures/whitequark/if_else.txt3
-rw-r--r--test/prism/fixtures/whitequark/if_elsif.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_masgn__24.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_nl_then.txt2
-rw-r--r--test/prism/fixtures/whitequark/if_while_after_class__since_32.txt7
-rw-r--r--test/prism/fixtures/whitequark/int.txt5
-rw-r--r--test/prism/fixtures/whitequark/int___LINE__.txt1
-rw-r--r--test/prism/fixtures/whitequark/interp_digit_var.txt87
-rw-r--r--test/prism/fixtures/whitequark/ivar.txt1
-rw-r--r--test/prism/fixtures/whitequark/ivasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/keyword_argument_omission.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwbegin_compstmt.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwnilarg.txt5
-rw-r--r--test/prism/fixtures/whitequark/kwoptarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwrestarg_named.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwrestarg_unnamed.txt1
-rw-r--r--test/prism/fixtures/whitequark/lbrace_arg_after_command_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/lparenarg_after_lvar__since_25.txt3
-rw-r--r--test/prism/fixtures/whitequark/lvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/lvar_injecting_match.txt1
-rw-r--r--test/prism/fixtures/whitequark/lvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/masgn.txt5
-rw-r--r--test/prism/fixtures/whitequark/masgn_attr.txt5
-rw-r--r--test/prism/fixtures/whitequark/masgn_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/masgn_const.txt3
-rw-r--r--test/prism/fixtures/whitequark/masgn_nested.txt3
-rw-r--r--test/prism/fixtures/whitequark/masgn_splat.txt19
-rw-r--r--test/prism/fixtures/whitequark/method_definition_in_while_cond.txt7
-rw-r--r--test/prism/fixtures/whitequark/module.txt1
-rw-r--r--test/prism/fixtures/whitequark/multiple_pattern_matches.txt5
-rw-r--r--test/prism/fixtures/whitequark/newline_in_hash_argument.txt14
-rw-r--r--test/prism/fixtures/whitequark/next.txt7
-rw-r--r--test/prism/fixtures/whitequark/next_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/nil.txt1
-rw-r--r--test/prism/fixtures/whitequark/nil_expression.txt3
-rw-r--r--test/prism/fixtures/whitequark/non_lvar_injecting_match.txt1
-rw-r--r--test/prism/fixtures/whitequark/not.txt5
-rw-r--r--test/prism/fixtures/whitequark/not_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/not_masgn__24.txt1
-rw-r--r--test/prism/fixtures/whitequark/nth_ref.txt1
-rw-r--r--test/prism/fixtures/whitequark/numbered_args_after_27.txt7
-rw-r--r--test/prism/fixtures/whitequark/numparam_outside_block.txt9
-rw-r--r--test/prism/fixtures/whitequark/op_asgn.txt5
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_cmd.txt7
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_index.txt1
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_index_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/optarg.txt3
-rw-r--r--test/prism/fixtures/whitequark/or.txt3
-rw-r--r--test/prism/fixtures/whitequark/or_asgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_272.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_490.txt5
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_507.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_518.txt2
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_525.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_604.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_640.txt4
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_645.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_830.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_slash_slash_n_escaping_in_literals.txt62
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching__FILE__LINE_literals.txt4
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_blank_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_single_line.txt3
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt11
-rw-r--r--test/prism/fixtures/whitequark/postexe.txt1
-rw-r--r--test/prism/fixtures/whitequark/preexe.txt1
-rw-r--r--test/prism/fixtures/whitequark/procarg0.txt3
-rw-r--r--test/prism/fixtures/whitequark/range_exclusive.txt1
-rw-r--r--test/prism/fixtures/whitequark/range_inclusive.txt1
-rw-r--r--test/prism/fixtures/whitequark/rational.txt3
-rw-r--r--test/prism/fixtures/whitequark/redo.txt1
-rw-r--r--test/prism/fixtures/whitequark/regex_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/regex_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list_mrhs.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list_var.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_var.txt3
-rw-r--r--test/prism/fixtures/whitequark/rescue.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_else_ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_in_lambda_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_masgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_op_assign.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_without_begin_end.txt1
-rw-r--r--test/prism/fixtures/whitequark/restarg_named.txt1
-rw-r--r--test/prism/fixtures/whitequark/restarg_unnamed.txt1
-rw-r--r--test/prism/fixtures/whitequark/retry.txt1
-rw-r--r--test/prism/fixtures/whitequark/return.txt7
-rw-r--r--test/prism/fixtures/whitequark/return_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_10279.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_10653.txt5
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11107.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11380.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873.txt23
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873_a.txt39
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873_b.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11989.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11990.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12073.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12402.txt27
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12669.txt7
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12686.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_13547.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_14690.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_15789.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_9669.txt8
-rw-r--r--test/prism/fixtures/whitequark/sclass.txt1
-rw-r--r--test/prism/fixtures/whitequark/self.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_attr_asgn.txt7
-rw-r--r--test/prism/fixtures/whitequark/send_attr_asgn_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_binary_op.txt41
-rw-r--r--test/prism/fixtures/whitequark/send_block_chain_cmd.txt13
-rw-r--r--test/prism/fixtures/whitequark/send_block_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_call.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_asgn_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_lambda.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args_noparen.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args_shadow.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_op_asgn_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_plain.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_plain_cmd.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_self.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_self_block.txt7
-rw-r--r--test/prism/fixtures/whitequark/send_unary_op.txt5
-rw-r--r--test/prism/fixtures/whitequark/slash_newline_in_heredocs.txt13
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_block.txt5
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_call.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/space_args_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/string___FILE__.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_concat.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_dvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_plain.txt3
-rw-r--r--test/prism/fixtures/whitequark/super.txt5
-rw-r--r--test/prism/fixtures/whitequark/super_block.txt3
-rw-r--r--test/prism/fixtures/whitequark/symbol_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/symbol_plain.txt3
-rw-r--r--test/prism/fixtures/whitequark/ternary.txt1
-rw-r--r--test/prism/fixtures/whitequark/ternary_ambiguous_symbol.txt1
-rw-r--r--test/prism/fixtures/whitequark/trailing_forward_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/true.txt1
-rw-r--r--test/prism/fixtures/whitequark/unary_num_pow_precedence.txt5
-rw-r--r--test/prism/fixtures/whitequark/undef.txt1
-rw-r--r--test/prism/fixtures/whitequark/unless.txt3
-rw-r--r--test/prism/fixtures/whitequark/unless_else.txt3
-rw-r--r--test/prism/fixtures/whitequark/unless_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/until.txt3
-rw-r--r--test/prism/fixtures/whitequark/until_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/until_post.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_and_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_op_asgn.txt7
-rw-r--r--test/prism/fixtures/whitequark/var_op_asgn_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_or_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_multi.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_splat.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_then.txt1
-rw-r--r--test/prism/fixtures/whitequark/while.txt3
-rw-r--r--test/prism/fixtures/whitequark/while_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/while_post.txt1
-rw-r--r--test/prism/fixtures/whitequark/xstring_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/xstring_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/yield.txt7
-rw-r--r--test/prism/fixtures/whitequark/zsuper.txt1
-rw-r--r--test/prism/fixtures/xstring.txt7
-rw-r--r--test/prism/fixtures/yield.txt7
-rw-r--r--test/prism/fuzzer_test.rb61
-rw-r--r--test/prism/heredoc_dedent_test.rb27
-rw-r--r--test/prism/library_symbols_test.rb103
-rw-r--r--test/prism/locals_test.rb109
-rw-r--r--test/prism/location_test.rb878
-rw-r--r--test/prism/magic_comment_test.rb37
-rw-r--r--test/prism/memsize_test.rb17
-rw-r--r--test/prism/newline_test.rb93
-rw-r--r--test/prism/parameters_signature_test.rb91
-rw-r--r--test/prism/parse_comments_test.rb21
-rw-r--r--test/prism/parse_test.rb262
-rw-r--r--test/prism/pattern_test.rb132
-rw-r--r--test/prism/regexp_test.rb263
-rw-r--r--test/prism/ripper_compat_test.rb21
-rw-r--r--test/prism/ruby_api_test.rb80
-rw-r--r--test/prism/snapshots/alias.txt174
-rw-r--r--test/prism/snapshots/arithmetic.txt252
-rw-r--r--test/prism/snapshots/arrays.txt1614
-rw-r--r--test/prism/snapshots/begin_ensure.txt250
-rw-r--r--test/prism/snapshots/begin_rescue.txt699
-rw-r--r--test/prism/snapshots/blocks.txt759
-rw-r--r--test/prism/snapshots/boolean_operators.txt54
-rw-r--r--test/prism/snapshots/booleans.txt7
-rw-r--r--test/prism/snapshots/break.txt218
-rw-r--r--test/prism/snapshots/case.txt268
-rw-r--r--test/prism/snapshots/classes.txt358
-rw-r--r--test/prism/snapshots/comments.txt145
-rw-r--r--test/prism/snapshots/constants.txt1235
-rw-r--r--test/prism/snapshots/dash_heredocs.txt254
-rw-r--r--test/prism/snapshots/defined.txt73
-rw-r--r--test/prism/snapshots/dos_endings.txt105
-rw-r--r--test/prism/snapshots/embdoc_no_newline_at_end.txt5
-rw-r--r--test/prism/snapshots/endless_methods.txt103
-rw-r--r--test/prism/snapshots/endless_range_in_conditional.txt46
-rw-r--r--test/prism/snapshots/for.txt176
-rw-r--r--test/prism/snapshots/global_variables.txt168
-rw-r--r--test/prism/snapshots/hashes.txt355
-rw-r--r--test/prism/snapshots/heredoc_with_escaped_newline_at_start.txt67
-rw-r--r--test/prism/snapshots/heredoc_with_trailing_newline.txt11
-rw-r--r--test/prism/snapshots/heredocs_nested.txt39
-rw-r--r--test/prism/snapshots/heredocs_with_ignored_newlines.txt63
-rw-r--r--test/prism/snapshots/heredocs_with_ignored_newlines_and_non_empty.txt11
-rw-r--r--test/prism/snapshots/if.txt431
-rw-r--r--test/prism/snapshots/indented_file_end.txt18
-rw-r--r--test/prism/snapshots/integer_operations.txt569
-rw-r--r--test/prism/snapshots/keyword_method_names.txt171
-rw-r--r--test/prism/snapshots/keywords.txt12
-rw-r--r--test/prism/snapshots/lambda.txt195
-rw-r--r--test/prism/snapshots/method_calls.txt2220
-rw-r--r--test/prism/snapshots/methods.txt1684
-rw-r--r--test/prism/snapshots/modules.txt180
-rw-r--r--test/prism/snapshots/newline_terminated.txt107
-rw-r--r--test/prism/snapshots/next.txt131
-rw-r--r--test/prism/snapshots/nils.txt32
-rw-r--r--test/prism/snapshots/non_alphanumeric_methods.txt501
-rw-r--r--test/prism/snapshots/not.txt351
-rw-r--r--test/prism/snapshots/numbers.txt102
-rw-r--r--test/prism/snapshots/patterns.txt4502
-rw-r--r--test/prism/snapshots/procs.txt372
-rw-r--r--test/prism/snapshots/range_begin_open_exclusive.txt12
-rw-r--r--test/prism/snapshots/range_begin_open_inclusive.txt12
-rw-r--r--test/prism/snapshots/range_end_open_exclusive.txt12
-rw-r--r--test/prism/snapshots/range_end_open_inclusive.txt12
-rw-r--r--test/prism/snapshots/ranges.txt161
-rw-r--r--test/prism/snapshots/regex.txt243
-rw-r--r--test/prism/snapshots/rescue.txt383
-rw-r--r--test/prism/snapshots/return.txt137
-rw-r--r--test/prism/snapshots/seattlerb/BEGIN.txt14
-rw-r--r--test/prism/snapshots/seattlerb/TestRubyParserShared.txt335
-rw-r--r--test/prism/snapshots/seattlerb/__ENCODING__.txt6
-rw-r--r--test/prism/snapshots/seattlerb/alias_gvar_backref.txt13
-rw-r--r--test/prism/snapshots/seattlerb/alias_resword.txt19
-rw-r--r--test/prism/snapshots/seattlerb/and_multi.txt26
-rw-r--r--test/prism/snapshots/seattlerb/aref_args_assocs.txt19
-rw-r--r--test/prism/snapshots/seattlerb/aref_args_lit_assocs.txt21
-rw-r--r--test/prism/snapshots/seattlerb/args_kw_block.txt36
-rw-r--r--test/prism/snapshots/seattlerb/array_line_breaks.txt23
-rw-r--r--test/prism/snapshots/seattlerb/array_lits_trailing_calls.txt33
-rw-r--r--test/prism/snapshots/seattlerb/assoc__bare.txt30
-rw-r--r--test/prism/snapshots/seattlerb/assoc_label.txt31
-rw-r--r--test/prism/snapshots/seattlerb/attr_asgn_colon_id.txt22
-rw-r--r--test/prism/snapshots/seattlerb/attrasgn_array_arg.txt38
-rw-r--r--test/prism/snapshots/seattlerb/attrasgn_array_lhs.txt77
-rw-r--r--test/prism/snapshots/seattlerb/attrasgn_primary_dot_constant.txt30
-rw-r--r--test/prism/snapshots/seattlerb/backticks_interpolation_line.txt38
-rw-r--r--test/prism/snapshots/seattlerb/bang_eq.txt22
-rw-r--r--test/prism/snapshots/seattlerb/bdot2.txt37
-rw-r--r--test/prism/snapshots/seattlerb/bdot3.txt37
-rw-r--r--test/prism/snapshots/seattlerb/begin_ensure_no_bodies.txt16
-rw-r--r--test/prism/snapshots/seattlerb/begin_rescue_else_ensure_bodies.txt43
-rw-r--r--test/prism/snapshots/seattlerb/begin_rescue_else_ensure_no_bodies.txt27
-rw-r--r--test/prism/snapshots/seattlerb/begin_rescue_ensure_no_bodies.txt23
-rw-r--r--test/prism/snapshots/seattlerb/block_arg__bare.txt30
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_kwsplat.txt38
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_opt_arg_block.txt49
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_opt_splat.txt47
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_opt_splat_arg_block_omfg.txt53
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_optional.txt41
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_scope.txt38
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_scope2.txt40
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_splat_arg.txt42
-rw-r--r--test/prism/snapshots/seattlerb/block_args_kwargs.txt43
-rw-r--r--test/prism/snapshots/seattlerb/block_args_no_kwargs.txt37
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt1.txt55
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt2.txt48
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt2_2.txt65
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt3.txt72
-rw-r--r--test/prism/snapshots/seattlerb/block_break.txt55
-rw-r--r--test/prism/snapshots/seattlerb/block_call_defn_call_block_call.txt79
-rw-r--r--test/prism/snapshots/seattlerb/block_call_dot_op2_brace_block.txt99
-rw-r--r--test/prism/snapshots/seattlerb/block_call_dot_op2_cmd_args_do_block.txt112
-rw-r--r--test/prism/snapshots/seattlerb/block_call_operation_colon.txt54
-rw-r--r--test/prism/snapshots/seattlerb/block_call_operation_dot.txt54
-rw-r--r--test/prism/snapshots/seattlerb/block_call_paren_call_block_call.txt60
-rw-r--r--test/prism/snapshots/seattlerb/block_command_operation_colon.txt47
-rw-r--r--test/prism/snapshots/seattlerb/block_command_operation_dot.txt47
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_anon_splat_arg.txt45
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_arg_splat.txt45
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_arg_splat_arg.txt49
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_splat.txt45
-rw-r--r--test/prism/snapshots/seattlerb/block_kw.txt40
-rw-r--r--test/prism/snapshots/seattlerb/block_kw__required.txt37
-rw-r--r--test/prism/snapshots/seattlerb/block_kwarg_lvar.txt48
-rw-r--r--test/prism/snapshots/seattlerb/block_kwarg_lvar_multiple.txt57
-rw-r--r--test/prism/snapshots/seattlerb/block_next.txt55
-rw-r--r--test/prism/snapshots/seattlerb/block_opt_arg.txt43
-rw-r--r--test/prism/snapshots/seattlerb/block_opt_splat.txt45
-rw-r--r--test/prism/snapshots/seattlerb/block_opt_splat_arg_block_omfg.txt51
-rw-r--r--test/prism/snapshots/seattlerb/block_optarg.txt44
-rw-r--r--test/prism/snapshots/seattlerb/block_paren_splat.txt47
-rw-r--r--test/prism/snapshots/seattlerb/block_reg_optarg.txt46
-rw-r--r--test/prism/snapshots/seattlerb/block_return.txt55
-rw-r--r--test/prism/snapshots/seattlerb/block_scope.txt28
-rw-r--r--test/prism/snapshots/seattlerb/block_splat_reg.txt40
-rw-r--r--test/prism/snapshots/seattlerb/bug169.txt28
-rw-r--r--test/prism/snapshots/seattlerb/bug179.txt28
-rw-r--r--test/prism/snapshots/seattlerb/bug190.txt11
-rw-r--r--test/prism/snapshots/seattlerb/bug191.txt85
-rw-r--r--test/prism/snapshots/seattlerb/bug202.txt20
-rw-r--r--test/prism/snapshots/seattlerb/bug236.txt71
-rw-r--r--test/prism/snapshots/seattlerb/bug290.txt24
-rw-r--r--test/prism/snapshots/seattlerb/bug_187.txt59
-rw-r--r--test/prism/snapshots/seattlerb/bug_215.txt13
-rw-r--r--test/prism/snapshots/seattlerb/bug_249.txt84
-rw-r--r--test/prism/snapshots/seattlerb/bug_and.txt20
-rw-r--r--test/prism/snapshots/seattlerb/bug_args__19.txt56
-rw-r--r--test/prism/snapshots/seattlerb/bug_args_masgn.txt46
-rw-r--r--test/prism/snapshots/seattlerb/bug_args_masgn2.txt54
-rw-r--r--test/prism/snapshots/seattlerb/bug_args_masgn_outer_parens__19.txt52
-rw-r--r--test/prism/snapshots/seattlerb/bug_call_arglist_parens.txt104
-rw-r--r--test/prism/snapshots/seattlerb/bug_case_when_regexp.txt26
-rw-r--r--test/prism/snapshots/seattlerb/bug_comma.txt40
-rw-r--r--test/prism/snapshots/seattlerb/bug_cond_pct.txt21
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_args.txt35
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt35
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_interp_array.txt25
-rw-r--r--test/prism/snapshots/seattlerb/bug_masgn_right.txt46
-rw-r--r--test/prism/snapshots/seattlerb/bug_not_parens.txt25
-rw-r--r--test/prism/snapshots/seattlerb/bug_op_asgn_rescue.txt26
-rw-r--r--test/prism/snapshots/seattlerb/call_and.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_assoc.txt30
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_assoc_kwsplat.txt38
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_kwsplat.txt35
-rw-r--r--test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt98
-rw-r--r--test/prism/snapshots/seattlerb/call_args_assoc_trailing_comma.txt30
-rw-r--r--test/prism/snapshots/seattlerb/call_args_command.txt53
-rw-r--r--test/prism/snapshots/seattlerb/call_array_arg.txt34
-rw-r--r--test/prism/snapshots/seattlerb/call_array_block_call.txt39
-rw-r--r--test/prism/snapshots/seattlerb/call_array_lambda_block_call.txt40
-rw-r--r--test/prism/snapshots/seattlerb/call_array_lit_inline_hash.txt40
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc.txt28
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_new.txt31
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt52
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_trailing_comma.txt28
-rw-r--r--test/prism/snapshots/seattlerb/call_bang_command_call.txt40
-rw-r--r--test/prism/snapshots/seattlerb/call_bang_squiggle.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_begin_call_block_call.txt53
-rw-r--r--test/prism/snapshots/seattlerb/call_block_arg_named.txt28
-rw-r--r--test/prism/snapshots/seattlerb/call_carat.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_colon2.txt17
-rw-r--r--test/prism/snapshots/seattlerb/call_colon_parens.txt17
-rw-r--r--test/prism/snapshots/seattlerb/call_div.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_dot_parens.txt17
-rw-r--r--test/prism/snapshots/seattlerb/call_env.txt25
-rw-r--r--test/prism/snapshots/seattlerb/call_eq3.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_gt.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_kwsplat.txt25
-rw-r--r--test/prism/snapshots/seattlerb/call_leading_dots.txt35
-rw-r--r--test/prism/snapshots/seattlerb/call_leading_dots_comment.txt35
-rw-r--r--test/prism/snapshots/seattlerb/call_lt.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_lte.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_not.txt17
-rw-r--r--test/prism/snapshots/seattlerb/call_pipe.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_rshift.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_self_brackets.txt21
-rw-r--r--test/prism/snapshots/seattlerb/call_spaceship.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_stabby_do_end_with_block.txt39
-rw-r--r--test/prism/snapshots/seattlerb/call_stabby_with_braces_block.txt39
-rw-r--r--test/prism/snapshots/seattlerb/call_star.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_star2.txt22
-rw-r--r--test/prism/snapshots/seattlerb/call_trailing_comma.txt20
-rw-r--r--test/prism/snapshots/seattlerb/call_trailing_dots.txt35
-rw-r--r--test/prism/snapshots/seattlerb/call_unary_bang.txt17
-rw-r--r--test/prism/snapshots/seattlerb/case_in.txt892
-rw-r--r--test/prism/snapshots/seattlerb/case_in_31.txt46
-rw-r--r--test/prism/snapshots/seattlerb/case_in_37.txt55
-rw-r--r--test/prism/snapshots/seattlerb/case_in_42.txt42
-rw-r--r--test/prism/snapshots/seattlerb/case_in_42_2.txt39
-rw-r--r--test/prism/snapshots/seattlerb/case_in_47.txt48
-rw-r--r--test/prism/snapshots/seattlerb/case_in_67.txt31
-rw-r--r--test/prism/snapshots/seattlerb/case_in_86.txt49
-rw-r--r--test/prism/snapshots/seattlerb/case_in_86_2.txt49
-rw-r--r--test/prism/snapshots/seattlerb/case_in_array_pat_const.txt40
-rw-r--r--test/prism/snapshots/seattlerb/case_in_array_pat_const2.txt46
-rw-r--r--test/prism/snapshots/seattlerb/case_in_array_pat_paren_assign.txt46
-rw-r--r--test/prism/snapshots/seattlerb/case_in_const.txt27
-rw-r--r--test/prism/snapshots/seattlerb/case_in_else.txt38
-rw-r--r--test/prism/snapshots/seattlerb/case_in_find.txt45
-rw-r--r--test/prism/snapshots/seattlerb/case_in_find_array.txt42
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat.txt64
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_assign.txt76
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_paren_assign.txt47
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_paren_true.txt44
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_rest.txt52
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_rest_solo.txt40
-rw-r--r--test/prism/snapshots/seattlerb/case_in_if_unless_post_mod.txt62
-rw-r--r--test/prism/snapshots/seattlerb/case_in_multiple.txt56
-rw-r--r--test/prism/snapshots/seattlerb/case_in_or.txt36
-rw-r--r--test/prism/snapshots/seattlerb/class_comments.txt31
-rw-r--r--test/prism/snapshots/seattlerb/cond_unary_minus.txt13
-rw-r--r--test/prism/snapshots/seattlerb/const_2_op_asgn_or2.txt23
-rw-r--r--test/prism/snapshots/seattlerb/const_3_op_asgn_or.txt17
-rw-r--r--test/prism/snapshots/seattlerb/const_op_asgn_and1.txt18
-rw-r--r--test/prism/snapshots/seattlerb/const_op_asgn_and2.txt17
-rw-r--r--test/prism/snapshots/seattlerb/const_op_asgn_or.txt19
-rw-r--r--test/prism/snapshots/seattlerb/dasgn_icky2.txt61
-rw-r--r--test/prism/snapshots/seattlerb/defined_eh_parens.txt12
-rw-r--r--test/prism/snapshots/seattlerb/defn_arg_asplat_arg.txt34
-rw-r--r--test/prism/snapshots/seattlerb/defn_arg_forward_args.txt48
-rw-r--r--test/prism/snapshots/seattlerb/defn_args_forward_args.txt57
-rw-r--r--test/prism/snapshots/seattlerb/defn_comments.txt18
-rw-r--r--test/prism/snapshots/seattlerb/defn_endless_command.txt35
-rw-r--r--test/prism/snapshots/seattlerb/defn_endless_command_rescue.txt41
-rw-r--r--test/prism/snapshots/seattlerb/defn_forward_args.txt43
-rw-r--r--test/prism/snapshots/seattlerb/defn_forward_args__no_parens.txt43
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_env.txt53
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_kwarg.txt40
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_kwsplat.txt36
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_kwsplat_anon.txt36
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_lvar.txt40
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_no_parens.txt32
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_val.txt34
-rw-r--r--test/prism/snapshots/seattlerb/defn_no_kwargs.txt29
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner.txt46
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_eq2.txt45
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_noargs.txt30
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_noargs_parentheses.txt30
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_rescue.txt155
-rw-r--r--test/prism/snapshots/seattlerb/defn_opt_last_arg.txt32
-rw-r--r--test/prism/snapshots/seattlerb/defn_opt_reg.txt34
-rw-r--r--test/prism/snapshots/seattlerb/defn_opt_splat_arg.txt39
-rw-r--r--test/prism/snapshots/seattlerb/defn_powarg.txt30
-rw-r--r--test/prism/snapshots/seattlerb/defn_reg_opt_reg.txt40
-rw-r--r--test/prism/snapshots/seattlerb/defn_splat_arg.txt32
-rw-r--r--test/prism/snapshots/seattlerb/defn_unary_not.txt21
-rw-r--r--test/prism/snapshots/seattlerb/defns_reserved.txt19
-rw-r--r--test/prism/snapshots/seattlerb/defs_as_arg_with_do_block_inside.txt60
-rw-r--r--test/prism/snapshots/seattlerb/defs_comments.txt19
-rw-r--r--test/prism/snapshots/seattlerb/defs_endless_command.txt45
-rw-r--r--test/prism/snapshots/seattlerb/defs_endless_command_rescue.txt51
-rw-r--r--test/prism/snapshots/seattlerb/defs_kwarg.txt33
-rw-r--r--test/prism/snapshots/seattlerb/defs_oneliner.txt47
-rw-r--r--test/prism/snapshots/seattlerb/defs_oneliner_eq2.txt46
-rw-r--r--test/prism/snapshots/seattlerb/defs_oneliner_rescue.txt158
-rw-r--r--test/prism/snapshots/seattlerb/difficult0_.txt72
-rw-r--r--test/prism/snapshots/seattlerb/difficult1_line_numbers.txt252
-rw-r--r--test/prism/snapshots/seattlerb/difficult1_line_numbers2.txt75
-rw-r--r--test/prism/snapshots/seattlerb/difficult2_.txt68
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_.txt49
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_2.txt40
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_3.txt44
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_4.txt37
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_5.txt48
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__10.txt49
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__11.txt45
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__12.txt47
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__6.txt51
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__7.txt47
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__8.txt49
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__9.txt47
-rw-r--r--test/prism/snapshots/seattlerb/difficult4__leading_dots.txt25
-rw-r--r--test/prism/snapshots/seattlerb/difficult4__leading_dots2.txt14
-rw-r--r--test/prism/snapshots/seattlerb/difficult6_.txt58
-rw-r--r--test/prism/snapshots/seattlerb/difficult6__7.txt54
-rw-r--r--test/prism/snapshots/seattlerb/difficult6__8.txt54
-rw-r--r--test/prism/snapshots/seattlerb/difficult7_.txt90
-rw-r--r--test/prism/snapshots/seattlerb/do_bug.txt61
-rw-r--r--test/prism/snapshots/seattlerb/do_lambda.txt17
-rw-r--r--test/prism/snapshots/seattlerb/dot2_nil__26.txt20
-rw-r--r--test/prism/snapshots/seattlerb/dot3_nil__26.txt20
-rw-r--r--test/prism/snapshots/seattlerb/dstr_evstr.txt37
-rw-r--r--test/prism/snapshots/seattlerb/dstr_evstr_empty_end.txt25
-rw-r--r--test/prism/snapshots/seattlerb/dstr_lex_state.txt33
-rw-r--r--test/prism/snapshots/seattlerb/dstr_str.txt27
-rw-r--r--test/prism/snapshots/seattlerb/dsym_esc_to_sym.txt10
-rw-r--r--test/prism/snapshots/seattlerb/dsym_to_sym.txt33
-rw-r--r--test/prism/snapshots/seattlerb/eq_begin_line_numbers.txt9
-rw-r--r--test/prism/snapshots/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt49
-rw-r--r--test/prism/snapshots/seattlerb/evstr_evstr.txt41
-rw-r--r--test/prism/snapshots/seattlerb/evstr_str.txt31
-rw-r--r--test/prism/snapshots/seattlerb/expr_not_bang.txt38
-rw-r--r--test/prism/snapshots/seattlerb/f_kw.txt32
-rw-r--r--test/prism/snapshots/seattlerb/f_kw__required.txt29
-rw-r--r--test/prism/snapshots/seattlerb/flip2_env_lvar.txt36
-rw-r--r--test/prism/snapshots/seattlerb/float_with_if_modifier.txt15
-rw-r--r--test/prism/snapshots/seattlerb/heredoc__backslash_dos_format.txt17
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_backslash_nl.txt17
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_bad_hex_escape.txt17
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_bad_oct_escape.txt17
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_comma_arg.txt25
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_lineno.txt25
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_nested.txt39
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly.txt33
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt66
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_blank_lines.txt33
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_empty.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_interp.txt47
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_no_indent.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_tabs.txt27
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_tabs_extra.txt27
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_squiggly_visually_blank_lines.txt33
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_trailing_slash_continued_call.txt21
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_unicode.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_carriage_return_escapes.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_carriage_return_escapes_windows.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_extra_carriage_horrible_mix.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_extra_carriage_returns.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_extra_carriage_returns_windows.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes.txt26
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes_windows.txt26
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_not_global_interpolation.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_only_carriage_returns.txt11
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_with_only_carriage_returns_windows.txt11
-rw-r--r--test/prism/snapshots/seattlerb/if_elsif.txt21
-rw-r--r--test/prism/snapshots/seattlerb/if_symbol.txt29
-rw-r--r--test/prism/snapshots/seattlerb/in_expr_no_case.txt17
-rw-r--r--test/prism/snapshots/seattlerb/index_0.txt38
-rw-r--r--test/prism/snapshots/seattlerb/index_0_opasgn.txt36
-rw-r--r--test/prism/snapshots/seattlerb/integer_with_if_modifier.txt16
-rw-r--r--test/prism/snapshots/seattlerb/interpolated_symbol_array_line_breaks.txt21
-rw-r--r--test/prism/snapshots/seattlerb/interpolated_word_array_line_breaks.txt23
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_1.txt38
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_10_1.txt47
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_10_2.txt51
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_11_1.txt49
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_11_2.txt53
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_2__19.txt44
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_3.txt48
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_4.txt42
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_5.txt40
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_6.txt45
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_7_1.txt45
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_7_2.txt49
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_8_1.txt47
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_8_2.txt51
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_9_1.txt43
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_9_2.txt47
-rw-r--r--test/prism/snapshots/seattlerb/iter_kwarg.txt40
-rw-r--r--test/prism/snapshots/seattlerb/iter_kwarg_kwsplat.txt44
-rw-r--r--test/prism/snapshots/seattlerb/label_vs_string.txt34
-rw-r--r--test/prism/snapshots/seattlerb/lambda_do_vs_brace.txt95
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_arg_rescue_arg.txt19
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_call_bracket_rescue_arg.txt32
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_call_nobracket_rescue_arg.txt32
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_command.txt36
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_env.txt13
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_ivar_env.txt12
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_lasgn_command_call.txt32
-rw-r--r--test/prism/snapshots/seattlerb/lasgn_middle_splat.txt48
-rw-r--r--test/prism/snapshots/seattlerb/magic_encoding_comment.txt45
-rw-r--r--test/prism/snapshots/seattlerb/masgn_anon_splat_arg.txt29
-rw-r--r--test/prism/snapshots/seattlerb/masgn_arg_colon_arg.txt46
-rw-r--r--test/prism/snapshots/seattlerb/masgn_arg_ident.txt46
-rw-r--r--test/prism/snapshots/seattlerb/masgn_arg_splat_arg.txt35
-rw-r--r--test/prism/snapshots/seattlerb/masgn_colon2.txt40
-rw-r--r--test/prism/snapshots/seattlerb/masgn_colon3.txt33
-rw-r--r--test/prism/snapshots/seattlerb/masgn_command_call.txt44
-rw-r--r--test/prism/snapshots/seattlerb/masgn_double_paren.txt35
-rw-r--r--test/prism/snapshots/seattlerb/masgn_lhs_splat.txt29
-rw-r--r--test/prism/snapshots/seattlerb/masgn_paren.txt39
-rw-r--r--test/prism/snapshots/seattlerb/masgn_splat_arg.txt32
-rw-r--r--test/prism/snapshots/seattlerb/masgn_splat_arg_arg.txt35
-rw-r--r--test/prism/snapshots/seattlerb/masgn_star.txt18
-rw-r--r--test/prism/snapshots/seattlerb/masgn_var_star_var.txt32
-rw-r--r--test/prism/snapshots/seattlerb/messy_op_asgn_lineno.txt60
-rw-r--r--test/prism/snapshots/seattlerb/method_call_assoc_trailing_comma.txt38
-rw-r--r--test/prism/snapshots/seattlerb/method_call_trailing_comma.txt30
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_back_anonsplat.txt35
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_back_splat.txt38
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_front_anonsplat.txt35
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_front_splat.txt38
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_keyword.txt30
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_mid_anonsplat.txt44
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_mid_splat.txt47
-rw-r--r--test/prism/snapshots/seattlerb/mlhs_rescue.txt35
-rw-r--r--test/prism/snapshots/seattlerb/module_comments.txt29
-rw-r--r--test/prism/snapshots/seattlerb/multiline_hash_declaration.txt89
-rw-r--r--test/prism/snapshots/seattlerb/non_interpolated_symbol_array_line_breaks.txt21
-rw-r--r--test/prism/snapshots/seattlerb/non_interpolated_word_array_line_breaks.txt23
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_command_call.txt36
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_dot_ident_command_call.txt31
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_index_command_call.txt50
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_primary_colon_const_command_call.txt41
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier1.txt19
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_primary_colon_identifier_command_call.txt40
-rw-r--r--test/prism/snapshots/seattlerb/op_asgn_val_dot_ident_command_call.txt39
-rw-r--r--test/prism/snapshots/seattlerb/parse_def_special_name.txt18
-rw-r--r--test/prism/snapshots/seattlerb/parse_if_not_canonical.txt61
-rw-r--r--test/prism/snapshots/seattlerb/parse_if_not_noncanonical.txt61
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_block.txt29
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_block_inline_comment.txt35
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_block_inline_comment_leading_newlines.txt35
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_block_inline_multiline_comment.txt35
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_call_ivar_arg_no_parens_line_break.txt20
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_call_ivar_line_break_paren.txt20
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_call_no_args.txt59
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_defn_complex.txt64
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_defn_no_parens.txt31
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_defn_no_parens_args.txt28
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_dot2.txt49
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_dot2_open.txt37
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_dot3.txt49
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_dot3_open.txt37
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_dstr_escaped_newline.txt20
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_dstr_soft_newline.txt20
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_evstr_after_break.txt34
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_hash_lit.txt20
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_heredoc.txt43
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_heredoc_evstr.txt37
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_heredoc_hardnewline.txt22
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_heredoc_regexp_chars.txt33
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_iter_call_no_parens.txt72
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_iter_call_parens.txt72
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_multiline_str.txt13
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_multiline_str_literal_n.txt13
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_newlines.txt6
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_op_asgn.txt32
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_postexe.txt22
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_preexe.txt22
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_rescue.txt62
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_return.txt37
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_str_with_newline_escape.txt25
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_to_ary.txt39
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_trailing_newlines.txt25
-rw-r--r--test/prism/snapshots/seattlerb/parse_opt_call_args_assocs_comma.txt30
-rw-r--r--test/prism/snapshots/seattlerb/parse_opt_call_args_lit_comma.txt22
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_019.txt30
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_044.txt38
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_051.txt40
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_058.txt64
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_058_2.txt58
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_069.txt44
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_076.txt54
-rw-r--r--test/prism/snapshots/seattlerb/parse_until_not_canonical.txt49
-rw-r--r--test/prism/snapshots/seattlerb/parse_until_not_noncanonical.txt49
-rw-r--r--test/prism/snapshots/seattlerb/parse_while_not_canonical.txt49
-rw-r--r--test/prism/snapshots/seattlerb/parse_while_not_noncanonical.txt49
-rw-r--r--test/prism/snapshots/seattlerb/pctW_lineno.txt51
-rw-r--r--test/prism/snapshots/seattlerb/pct_Q_backslash_nl.txt11
-rw-r--r--test/prism/snapshots/seattlerb/pct_nl.txt17
-rw-r--r--test/prism/snapshots/seattlerb/pct_w_heredoc_interp_nested.txt49
-rw-r--r--test/prism/snapshots/seattlerb/pipe_semicolon.txt38
-rw-r--r--test/prism/snapshots/seattlerb/pipe_space.txt36
-rw-r--r--test/prism/snapshots/seattlerb/qWords_space.txt9
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols.txt24
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols_empty.txt9
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols_empty_space.txt9
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols_interp.txt52
-rw-r--r--test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt33
-rw-r--r--test/prism/snapshots/seattlerb/quoted_symbol_keys.txt23
-rw-r--r--test/prism/snapshots/seattlerb/qw_escape.txt11
-rw-r--r--test/prism/snapshots/seattlerb/qw_escape_term.txt11
-rw-r--r--test/prism/snapshots/seattlerb/qwords_empty.txt9
-rw-r--r--test/prism/snapshots/seattlerb/read_escape_unicode_curlies.txt11
-rw-r--r--test/prism/snapshots/seattlerb/read_escape_unicode_h4.txt11
-rw-r--r--test/prism/snapshots/seattlerb/regexp.txt35
-rw-r--r--test/prism/snapshots/seattlerb/regexp_esc_C_slash.txt11
-rw-r--r--test/prism/snapshots/seattlerb/regexp_esc_u.txt11
-rw-r--r--test/prism/snapshots/seattlerb/regexp_escape_extended.txt11
-rw-r--r--test/prism/snapshots/seattlerb/regexp_unicode_curlies.txt17
-rw-r--r--test/prism/snapshots/seattlerb/required_kwarg_no_value.txt32
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_ensure_result.txt56
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_no_raise.txt71
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_raised.txt51
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_rescued.txt76
-rw-r--r--test/prism/snapshots/seattlerb/rescue_in_block.txt47
-rw-r--r--test/prism/snapshots/seattlerb/rescue_parens.txt48
-rw-r--r--test/prism/snapshots/seattlerb/return_call_assocs.txt191
-rw-r--r--test/prism/snapshots/seattlerb/rhs_asgn.txt14
-rw-r--r--test/prism/snapshots/seattlerb/ruby21_numbers.txt23
-rw-r--r--test/prism/snapshots/seattlerb/safe_attrasgn.txt30
-rw-r--r--test/prism/snapshots/seattlerb/safe_attrasgn_constant.txt30
-rw-r--r--test/prism/snapshots/seattlerb/safe_call.txt25
-rw-r--r--test/prism/snapshots/seattlerb/safe_call_after_newline.txt25
-rw-r--r--test/prism/snapshots/seattlerb/safe_call_dot_parens.txt25
-rw-r--r--test/prism/snapshots/seattlerb/safe_call_newline.txt25
-rw-r--r--test/prism/snapshots/seattlerb/safe_call_operator.txt30
-rw-r--r--test/prism/snapshots/seattlerb/safe_call_rhs_newline.txt31
-rw-r--r--test/prism/snapshots/seattlerb/safe_calls.txt40
-rw-r--r--test/prism/snapshots/seattlerb/safe_op_asgn.txt40
-rw-r--r--test/prism/snapshots/seattlerb/safe_op_asgn2.txt34
-rw-r--r--test/prism/snapshots/seattlerb/slashy_newlines_within_string.txt57
-rw-r--r--test/prism/snapshots/seattlerb/stabby_arg_no_paren.txt27
-rw-r--r--test/prism/snapshots/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt44
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_iter_call.txt58
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_iter_call_no_target_with_arg.txt53
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_kw.txt31
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_kw__required.txt28
-rw-r--r--test/prism/snapshots/seattlerb/stabby_proc_scope.txt29
-rw-r--r--test/prism/snapshots/seattlerb/str_backslashes.txt24
-rw-r--r--test/prism/snapshots/seattlerb/str_double_double_escaped_newline.txt34
-rw-r--r--test/prism/snapshots/seattlerb/str_double_escaped_newline.txt34
-rw-r--r--test/prism/snapshots/seattlerb/str_double_newline.txt34
-rw-r--r--test/prism/snapshots/seattlerb/str_evstr.txt31
-rw-r--r--test/prism/snapshots/seattlerb/str_evstr_escape.txt37
-rw-r--r--test/prism/snapshots/seattlerb/str_heredoc_interp.txt31
-rw-r--r--test/prism/snapshots/seattlerb/str_interp_ternary_or_label.txt103
-rw-r--r--test/prism/snapshots/seattlerb/str_lit_concat_bad_encodings.txt20
-rw-r--r--test/prism/snapshots/seattlerb/str_newline_hash_line_number.txt13
-rw-r--r--test/prism/snapshots/seattlerb/str_pct_Q_nested.txt37
-rw-r--r--test/prism/snapshots/seattlerb/str_pct_nested_nested.txt39
-rw-r--r--test/prism/snapshots/seattlerb/str_pct_q.txt11
-rw-r--r--test/prism/snapshots/seattlerb/str_single_double_escaped_newline.txt34
-rw-r--r--test/prism/snapshots/seattlerb/str_single_escaped_newline.txt34
-rw-r--r--test/prism/snapshots/seattlerb/str_single_newline.txt34
-rw-r--r--test/prism/snapshots/seattlerb/str_str.txt27
-rw-r--r--test/prism/snapshots/seattlerb/str_str_str.txt33
-rw-r--r--test/prism/snapshots/seattlerb/super_arg.txt16
-rw-r--r--test/prism/snapshots/seattlerb/symbol_empty.txt10
-rw-r--r--test/prism/snapshots/seattlerb/symbol_list.txt49
-rw-r--r--test/prism/snapshots/seattlerb/symbols.txt24
-rw-r--r--test/prism/snapshots/seattlerb/symbols_empty.txt9
-rw-r--r--test/prism/snapshots/seattlerb/symbols_empty_space.txt9
-rw-r--r--test/prism/snapshots/seattlerb/symbols_interp.txt24
-rw-r--r--test/prism/snapshots/seattlerb/thingy.txt55
-rw-r--r--test/prism/snapshots/seattlerb/uminus_float.txt6
-rw-r--r--test/prism/snapshots/seattlerb/unary_minus.txt25
-rw-r--r--test/prism/snapshots/seattlerb/unary_plus.txt25
-rw-r--r--test/prism/snapshots/seattlerb/unary_plus_on_literal.txt20
-rw-r--r--test/prism/snapshots/seattlerb/unary_tilde.txt25
-rw-r--r--test/prism/snapshots/seattlerb/utf8_bom.txt20
-rw-r--r--test/prism/snapshots/seattlerb/when_splat.txt38
-rw-r--r--test/prism/snapshots/seattlerb/words_interp.txt27
-rw-r--r--test/prism/snapshots/seattlerb/yield_arg.txt15
-rw-r--r--test/prism/snapshots/seattlerb/yield_call_assocs.txt203
-rw-r--r--test/prism/snapshots/seattlerb/yield_empty_parens.txt10
-rw-r--r--test/prism/snapshots/single_quote_heredocs.txt11
-rw-r--r--test/prism/snapshots/spanning_heredoc.txt355
-rw-r--r--test/prism/snapshots/strings.txt517
-rw-r--r--test/prism/snapshots/super.txt119
-rw-r--r--test/prism/snapshots/symbols.txt398
-rw-r--r--test/prism/snapshots/ternary_operator.txt285
-rw-r--r--test/prism/snapshots/tilde_heredocs.txt381
-rw-r--r--test/prism/snapshots/undef.txt105
-rw-r--r--test/prism/snapshots/unescaping.txt33
-rw-r--r--test/prism/snapshots/unless.txt123
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/alias.txt27
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/assignment.txt1050
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/block.txt1382
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/case.txt431
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/class.txt232
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/control.txt135
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/def.txt1171
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/defined.txt52
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/defs.txt358
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/dstr.txt336
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/empty.txt5
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/empty_begin.txt9
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/flipflop.txt187
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/for.txt171
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/hookexe.txt49
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/if.txt268
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/kwbegin.txt490
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/lambda.txt143
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/literal.txt1113
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/module.txt106
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/opasgn.txt489
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/pattern.txt418
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/pragma.txt19
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/range.txt49
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/rescue.txt101
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/send.txt2162
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/27.txt46
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/30.txt83
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/31.txt87
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/32.txt103
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/singletons.txt9
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/super.txt277
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/unary.txt245
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/undef.txt26
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/variables.txt53
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/while.txt697
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/yield.txt56
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/and.txt233
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/block.txt189
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/def.txt90
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/dstr.txt563
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/kwbegin.txt259
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/literal.txt94
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/send.txt162
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/undef.txt26
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/while.txt277
-rw-r--r--test/prism/snapshots/until.txt104
-rw-r--r--test/prism/snapshots/variables.txt368
-rw-r--r--test/prism/snapshots/while.txt321
-rw-r--r--test/prism/snapshots/whitequark/__ENCODING__.txt6
-rw-r--r--test/prism/snapshots/whitequark/__ENCODING___legacy_.txt6
-rw-r--r--test/prism/snapshots/whitequark/alias.txt19
-rw-r--r--test/prism/snapshots/whitequark/alias_gvar.txt21
-rw-r--r--test/prism/snapshots/whitequark/ambiuous_quoted_label_in_ternary_operator.txt59
-rw-r--r--test/prism/snapshots/whitequark/and.txt53
-rw-r--r--test/prism/snapshots/whitequark/and_asgn.txt55
-rw-r--r--test/prism/snapshots/whitequark/and_or_masgn.txt93
-rw-r--r--test/prism/snapshots/whitequark/anonymous_blockarg.txt45
-rw-r--r--test/prism/snapshots/whitequark/arg.txt53
-rw-r--r--test/prism/snapshots/whitequark/arg_duplicate_ignored.txt55
-rw-r--r--test/prism/snapshots/whitequark/arg_label.txt112
-rw-r--r--test/prism/snapshots/whitequark/arg_scope.txt33
-rw-r--r--test/prism/snapshots/whitequark/args.txt993
-rw-r--r--test/prism/snapshots/whitequark/args_args_assocs.txt90
-rw-r--r--test/prism/snapshots/whitequark/args_args_assocs_comma.txt51
-rw-r--r--test/prism/snapshots/whitequark/args_args_comma.txt38
-rw-r--r--test/prism/snapshots/whitequark/args_args_star.txt90
-rw-r--r--test/prism/snapshots/whitequark/args_assocs.txt177
-rw-r--r--test/prism/snapshots/whitequark/args_assocs_comma.txt41
-rw-r--r--test/prism/snapshots/whitequark/args_assocs_legacy.txt177
-rw-r--r--test/prism/snapshots/whitequark/args_block_pass.txt28
-rw-r--r--test/prism/snapshots/whitequark/args_cmd.txt41
-rw-r--r--test/prism/snapshots/whitequark/args_star.txt70
-rw-r--r--test/prism/snapshots/whitequark/array_assocs.txt35
-rw-r--r--test/prism/snapshots/whitequark/array_plain.txt13
-rw-r--r--test/prism/snapshots/whitequark/array_splat.txt62
-rw-r--r--test/prism/snapshots/whitequark/array_symbols.txt19
-rw-r--r--test/prism/snapshots/whitequark/array_symbols_empty.txt13
-rw-r--r--test/prism/snapshots/whitequark/array_symbols_interp.txt64
-rw-r--r--test/prism/snapshots/whitequark/array_words.txt21
-rw-r--r--test/prism/snapshots/whitequark/array_words_empty.txt13
-rw-r--r--test/prism/snapshots/whitequark/array_words_interp.txt76
-rw-r--r--test/prism/snapshots/whitequark/asgn_cmd.txt55
-rw-r--r--test/prism/snapshots/whitequark/asgn_mrhs.txt83
-rw-r--r--test/prism/snapshots/whitequark/back_ref.txt7
-rw-r--r--test/prism/snapshots/whitequark/bang.txt25
-rw-r--r--test/prism/snapshots/whitequark/bang_cmd.txt38
-rw-r--r--test/prism/snapshots/whitequark/begin_cmdarg.txt49
-rw-r--r--test/prism/snapshots/whitequark/beginless_erange_after_newline.txt22
-rw-r--r--test/prism/snapshots/whitequark/beginless_irange_after_newline.txt22
-rw-r--r--test/prism/snapshots/whitequark/beginless_range.txt19
-rw-r--r--test/prism/snapshots/whitequark/blockarg.txt30
-rw-r--r--test/prism/snapshots/whitequark/blockargs.txt1259
-rw-r--r--test/prism/snapshots/whitequark/break.txt56
-rw-r--r--test/prism/snapshots/whitequark/break_block.txt40
-rw-r--r--test/prism/snapshots/whitequark/bug_435.txt37
-rw-r--r--test/prism/snapshots/whitequark/bug_447.txt53
-rw-r--r--test/prism/snapshots/whitequark/bug_452.txt62
-rw-r--r--test/prism/snapshots/whitequark/bug_466.txt67
-rw-r--r--test/prism/snapshots/whitequark/bug_473.txt32
-rw-r--r--test/prism/snapshots/whitequark/bug_480.txt36
-rw-r--r--test/prism/snapshots/whitequark/bug_481.txt49
-rw-r--r--test/prism/snapshots/whitequark/bug_ascii_8bit_in_literal.txt11
-rw-r--r--test/prism/snapshots/whitequark/bug_cmd_string_lookahead.txt30
-rw-r--r--test/prism/snapshots/whitequark/bug_cmdarg.txt102
-rw-r--r--test/prism/snapshots/whitequark/bug_def_no_paren_eql_begin.txt18
-rw-r--r--test/prism/snapshots/whitequark/bug_do_block_in_call_args.txt50
-rw-r--r--test/prism/snapshots/whitequark/bug_do_block_in_cmdarg.txt40
-rw-r--r--test/prism/snapshots/whitequark/bug_do_block_in_hash_brace.txt370
-rw-r--r--test/prism/snapshots/whitequark/bug_heredoc_do.txt30
-rw-r--r--test/prism/snapshots/whitequark/bug_interp_single.txt33
-rw-r--r--test/prism/snapshots/whitequark/bug_lambda_leakage.txt37
-rw-r--r--test/prism/snapshots/whitequark/bug_regex_verification.txt11
-rw-r--r--test/prism/snapshots/whitequark/bug_rescue_empty_else.txt25
-rw-r--r--test/prism/snapshots/whitequark/bug_while_not_parens_do.txt28
-rw-r--r--test/prism/snapshots/whitequark/case_cond.txt33
-rw-r--r--test/prism/snapshots/whitequark/case_cond_else.txt45
-rw-r--r--test/prism/snapshots/whitequark/case_expr.txt43
-rw-r--r--test/prism/snapshots/whitequark/case_expr_else.txt59
-rw-r--r--test/prism/snapshots/whitequark/casgn_scoped.txt19
-rw-r--r--test/prism/snapshots/whitequark/casgn_toplevel.txt17
-rw-r--r--test/prism/snapshots/whitequark/casgn_unscoped.txt12
-rw-r--r--test/prism/snapshots/whitequark/character.txt11
-rw-r--r--test/prism/snapshots/whitequark/class.txt27
-rw-r--r--test/prism/snapshots/whitequark/class_definition_in_while_cond.txt171
-rw-r--r--test/prism/snapshots/whitequark/class_super.txt18
-rw-r--r--test/prism/snapshots/whitequark/class_super_label.txt34
-rw-r--r--test/prism/snapshots/whitequark/comments_before_leading_dot__27.txt85
-rw-r--r--test/prism/snapshots/whitequark/complex.txt23
-rw-r--r--test/prism/snapshots/whitequark/cond_begin.txt39
-rw-r--r--test/prism/snapshots/whitequark/cond_begin_masgn.txt51
-rw-r--r--test/prism/snapshots/whitequark/cond_eflipflop.txt77
-rw-r--r--test/prism/snapshots/whitequark/cond_iflipflop.txt77
-rw-r--r--test/prism/snapshots/whitequark/cond_match_current_line.txt33
-rw-r--r--test/prism/snapshots/whitequark/const_op_asgn.txt96
-rw-r--r--test/prism/snapshots/whitequark/const_scoped.txt13
-rw-r--r--test/prism/snapshots/whitequark/const_toplevel.txt11
-rw-r--r--test/prism/snapshots/whitequark/const_unscoped.txt7
-rw-r--r--test/prism/snapshots/whitequark/cpath.txt33
-rw-r--r--test/prism/snapshots/whitequark/cvar.txt7
-rw-r--r--test/prism/snapshots/whitequark/cvasgn.txt12
-rw-r--r--test/prism/snapshots/whitequark/dedenting_heredoc.txt485
-rw-r--r--test/prism/snapshots/whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt21
-rw-r--r--test/prism/snapshots/whitequark/dedenting_non_interpolating_heredoc_line_continuation.txt21
-rw-r--r--test/prism/snapshots/whitequark/def.txt83
-rw-r--r--test/prism/snapshots/whitequark/defined.txt42
-rw-r--r--test/prism/snapshots/whitequark/defs.txt90
-rw-r--r--test/prism/snapshots/whitequark/empty_stmt.txt5
-rw-r--r--test/prism/snapshots/whitequark/endless_comparison_method.txt215
-rw-r--r--test/prism/snapshots/whitequark/endless_method.txt145
-rw-r--r--test/prism/snapshots/whitequark/endless_method_command_syntax.txt388
-rw-r--r--test/prism/snapshots/whitequark/endless_method_forwarded_args_legacy.txt43
-rw-r--r--test/prism/snapshots/whitequark/endless_method_with_rescue_mod.txt52
-rw-r--r--test/prism/snapshots/whitequark/endless_method_without_args.txt85
-rw-r--r--test/prism/snapshots/whitequark/ensure.txt40
-rw-r--r--test/prism/snapshots/whitequark/ensure_empty.txt16
-rw-r--r--test/prism/snapshots/whitequark/false.txt6
-rw-r--r--test/prism/snapshots/whitequark/float.txt7
-rw-r--r--test/prism/snapshots/whitequark/for.txt83
-rw-r--r--test/prism/snapshots/whitequark/for_mlhs.txt56
-rw-r--r--test/prism/snapshots/whitequark/forward_arg.txt43
-rw-r--r--test/prism/snapshots/whitequark/forward_arg_with_open_args.txt394
-rw-r--r--test/prism/snapshots/whitequark/forward_args_legacy.txt99
-rw-r--r--test/prism/snapshots/whitequark/forwarded_argument_with_kwrestarg.txt55
-rw-r--r--test/prism/snapshots/whitequark/forwarded_argument_with_restarg.txt53
-rw-r--r--test/prism/snapshots/whitequark/forwarded_kwrestarg.txt50
-rw-r--r--test/prism/snapshots/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt60
-rw-r--r--test/prism/snapshots/whitequark/forwarded_restarg.txt48
-rw-r--r--test/prism/snapshots/whitequark/gvar.txt7
-rw-r--r--test/prism/snapshots/whitequark/gvasgn.txt12
-rw-r--r--test/prism/snapshots/whitequark/hash_empty.txt9
-rw-r--r--test/prism/snapshots/whitequark/hash_hashrocket.txt44
-rw-r--r--test/prism/snapshots/whitequark/hash_kwsplat.txt33
-rw-r--r--test/prism/snapshots/whitequark/hash_label.txt20
-rw-r--r--test/prism/snapshots/whitequark/hash_label_end.txt93
-rw-r--r--test/prism/snapshots/whitequark/hash_pair_value_omission.txt93
-rw-r--r--test/prism/snapshots/whitequark/heredoc.txt22
-rw-r--r--test/prism/snapshots/whitequark/if.txt61
-rw-r--r--test/prism/snapshots/whitequark/if_else.txt93
-rw-r--r--test/prism/snapshots/whitequark/if_elsif.txt61
-rw-r--r--test/prism/snapshots/whitequark/if_masgn__24.txt41
-rw-r--r--test/prism/snapshots/whitequark/if_mod.txt33
-rw-r--r--test/prism/snapshots/whitequark/if_nl_then.txt33
-rw-r--r--test/prism/snapshots/whitequark/if_while_after_class__since_32.txt117
-rw-r--r--test/prism/snapshots/whitequark/int.txt11
-rw-r--r--test/prism/snapshots/whitequark/int___LINE__.txt6
-rw-r--r--test/prism/snapshots/whitequark/interp_digit_var.txt249
-rw-r--r--test/prism/snapshots/whitequark/ivar.txt7
-rw-r--r--test/prism/snapshots/whitequark/ivasgn.txt12
-rw-r--r--test/prism/snapshots/whitequark/keyword_argument_omission.txt62
-rw-r--r--test/prism/snapshots/whitequark/kwarg.txt29
-rw-r--r--test/prism/snapshots/whitequark/kwbegin_compstmt.txt34
-rw-r--r--test/prism/snapshots/whitequark/kwnilarg.txt84
-rw-r--r--test/prism/snapshots/whitequark/kwoptarg.txt32
-rw-r--r--test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt55
-rw-r--r--test/prism/snapshots/whitequark/kwrestarg_named.txt30
-rw-r--r--test/prism/snapshots/whitequark/kwrestarg_unnamed.txt30
-rw-r--r--test/prism/snapshots/whitequark/lbrace_arg_after_command_args.txt53
-rw-r--r--test/prism/snapshots/whitequark/lparenarg_after_lvar__since_25.txt65
-rw-r--r--test/prism/snapshots/whitequark/lvar.txt15
-rw-r--r--test/prism/snapshots/whitequark/lvar_injecting_match.txt36
-rw-r--r--test/prism/snapshots/whitequark/lvasgn.txt16
-rw-r--r--test/prism/snapshots/whitequark/masgn.txt74
-rw-r--r--test/prism/snapshots/whitequark/masgn_attr.txt95
-rw-r--r--test/prism/snapshots/whitequark/masgn_cmd.txt35
-rw-r--r--test/prism/snapshots/whitequark/masgn_const.txt46
-rw-r--r--test/prism/snapshots/whitequark/masgn_nested.txt68
-rw-r--r--test/prism/snapshots/whitequark/masgn_splat.txt282
-rw-r--r--test/prism/snapshots/whitequark/method_definition_in_while_cond.txt197
-rw-r--r--test/prism/snapshots/whitequark/module.txt14
-rw-r--r--test/prism/snapshots/whitequark/multiple_pattern_matches.txt141
-rw-r--r--test/prism/snapshots/whitequark/newline_in_hash_argument.txt143
-rw-r--r--test/prism/snapshots/whitequark/next.txt56
-rw-r--r--test/prism/snapshots/whitequark/next_block.txt40
-rw-r--r--test/prism/snapshots/whitequark/nil.txt6
-rw-r--r--test/prism/snapshots/whitequark/nil_expression.txt16
-rw-r--r--test/prism/snapshots/whitequark/non_lvar_injecting_match.txt43
-rw-r--r--test/prism/snapshots/whitequark/not.txt55
-rw-r--r--test/prism/snapshots/whitequark/not_cmd.txt38
-rw-r--r--test/prism/snapshots/whitequark/not_masgn__24.txt45
-rw-r--r--test/prism/snapshots/whitequark/nth_ref.txt7
-rw-r--r--test/prism/snapshots/whitequark/numbered_args_after_27.txt135
-rw-r--r--test/prism/snapshots/whitequark/numparam_outside_block.txt114
-rw-r--r--test/prism/snapshots/whitequark/op_asgn.txt71
-rw-r--r--test/prism/snapshots/whitequark/op_asgn_cmd.txt178
-rw-r--r--test/prism/snapshots/whitequark/op_asgn_index.txt35
-rw-r--r--test/prism/snapshots/whitequark/op_asgn_index_cmd.txt56
-rw-r--r--test/prism/snapshots/whitequark/optarg.txt68
-rw-r--r--test/prism/snapshots/whitequark/or.txt53
-rw-r--r--test/prism/snapshots/whitequark/or_asgn.txt55
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_272.txt41
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_490.txt106
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_507.txt35
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_518.txt18
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_525.txt63
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_604.txt57
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_640.txt11
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_645.txt34
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_830.txt11
-rw-r--r--test/prism/snapshots/whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt19
-rw-r--r--test/prism/snapshots/whitequark/parser_slash_slash_n_escaping_in_literals.txt127
-rw-r--r--test/prism/snapshots/whitequark/pattern_matching__FILE__LINE_literals.txt50
-rw-r--r--test/prism/snapshots/whitequark/pattern_matching_blank_else.txt28
-rw-r--r--test/prism/snapshots/whitequark/pattern_matching_else.txt32
-rw-r--r--test/prism/snapshots/whitequark/pattern_matching_single_line.txt43
-rw-r--r--test/prism/snapshots/whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt221
-rw-r--r--test/prism/snapshots/whitequark/postexe.txt14
-rw-r--r--test/prism/snapshots/whitequark/preexe.txt14
-rw-r--r--test/prism/snapshots/whitequark/procarg0.txt75
-rw-r--r--test/prism/snapshots/whitequark/range_exclusive.txt14
-rw-r--r--test/prism/snapshots/whitequark/range_inclusive.txt14
-rw-r--r--test/prism/snapshots/whitequark/rational.txt12
-rw-r--r--test/prism/snapshots/whitequark/redo.txt6
-rw-r--r--test/prism/snapshots/whitequark/regex_interp.txt38
-rw-r--r--test/prism/snapshots/whitequark/regex_plain.txt11
-rw-r--r--test/prism/snapshots/whitequark/resbody_list.txt45
-rw-r--r--test/prism/snapshots/whitequark/resbody_list_mrhs.txt55
-rw-r--r--test/prism/snapshots/whitequark/resbody_list_var.txt56
-rw-r--r--test/prism/snapshots/whitequark/resbody_var.txt86
-rw-r--r--test/prism/snapshots/whitequark/rescue.txt43
-rw-r--r--test/prism/snapshots/whitequark/rescue_else.txt59
-rw-r--r--test/prism/snapshots/whitequark/rescue_else_ensure.txt75
-rw-r--r--test/prism/snapshots/whitequark/rescue_ensure.txt59
-rw-r--r--test/prism/snapshots/whitequark/rescue_in_lambda_block.txt26
-rw-r--r--test/prism/snapshots/whitequark/rescue_mod.txt29
-rw-r--r--test/prism/snapshots/whitequark/rescue_mod_asgn.txt35
-rw-r--r--test/prism/snapshots/whitequark/rescue_mod_masgn.txt41
-rw-r--r--test/prism/snapshots/whitequark/rescue_mod_op_assign.txt36
-rw-r--r--test/prism/snapshots/whitequark/rescue_without_begin_end.txt59
-rw-r--r--test/prism/snapshots/whitequark/restarg_named.txt30
-rw-r--r--test/prism/snapshots/whitequark/restarg_unnamed.txt30
-rw-r--r--test/prism/snapshots/whitequark/retry.txt6
-rw-r--r--test/prism/snapshots/whitequark/return.txt56
-rw-r--r--test/prism/snapshots/whitequark/return_block.txt40
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_10279.txt29
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_10653.txt167
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11107.txt48
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11380.txt51
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11873.txt767
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11873_a.txt1211
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11873_b.txt98
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11989.txt24
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11990.txt33
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12073.txt91
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12402.txt565
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12669.txt129
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12686.txt39
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_13547.txt31
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_14690.txt59
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_15789.txt114
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_9669.txt55
-rw-r--r--test/prism/snapshots/whitequark/sclass.txt25
-rw-r--r--test/prism/snapshots/whitequark/self.txt6
-rw-r--r--test/prism/snapshots/whitequark/send_attr_asgn.txt102
-rw-r--r--test/prism/snapshots/whitequark/send_attr_asgn_conditional.txt30
-rw-r--r--test/prism/snapshots/whitequark/send_binary_op.txt530
-rw-r--r--test/prism/snapshots/whitequark/send_block_chain_cmd.txt318
-rw-r--r--test/prism/snapshots/whitequark/send_block_conditional.txt31
-rw-r--r--test/prism/snapshots/whitequark/send_call.txt55
-rw-r--r--test/prism/snapshots/whitequark/send_conditional.txt25
-rw-r--r--test/prism/snapshots/whitequark/send_index.txt32
-rw-r--r--test/prism/snapshots/whitequark/send_index_asgn.txt34
-rw-r--r--test/prism/snapshots/whitequark/send_index_asgn_legacy.txt34
-rw-r--r--test/prism/snapshots/whitequark/send_index_cmd.txt51
-rw-r--r--test/prism/snapshots/whitequark/send_index_legacy.txt32
-rw-r--r--test/prism/snapshots/whitequark/send_lambda.txt43
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_args.txt49
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_args_noparen.txt54
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_args_shadow.txt31
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_legacy.txt12
-rw-r--r--test/prism/snapshots/whitequark/send_op_asgn_conditional.txt26
-rw-r--r--test/prism/snapshots/whitequark/send_plain.txt65
-rw-r--r--test/prism/snapshots/whitequark/send_plain_cmd.txt104
-rw-r--r--test/prism/snapshots/whitequark/send_self.txt40
-rw-r--r--test/prism/snapshots/whitequark/send_self_block.txt74
-rw-r--r--test/prism/snapshots/whitequark/send_unary_op.txt65
-rw-r--r--test/prism/snapshots/whitequark/slash_newline_in_heredocs.txt27
-rw-r--r--test/prism/snapshots/whitequark/space_args_arg.txt26
-rw-r--r--test/prism/snapshots/whitequark/space_args_arg_block.txt106
-rw-r--r--test/prism/snapshots/whitequark/space_args_arg_call.txt36
-rw-r--r--test/prism/snapshots/whitequark/space_args_arg_newline.txt26
-rw-r--r--test/prism/snapshots/whitequark/space_args_block.txt28
-rw-r--r--test/prism/snapshots/whitequark/space_args_cmd.txt47
-rw-r--r--test/prism/snapshots/whitequark/string___FILE__.txt7
-rw-r--r--test/prism/snapshots/whitequark/string_concat.txt29
-rw-r--r--test/prism/snapshots/whitequark/string_dvar.txt36
-rw-r--r--test/prism/snapshots/whitequark/string_interp.txt37
-rw-r--r--test/prism/snapshots/whitequark/string_plain.txt17
-rw-r--r--test/prism/snapshots/whitequark/super.txt49
-rw-r--r--test/prism/snapshots/whitequark/super_block.txt48
-rw-r--r--test/prism/snapshots/whitequark/symbol_interp.txt37
-rw-r--r--test/prism/snapshots/whitequark/symbol_plain.txt15
-rw-r--r--test/prism/snapshots/whitequark/ternary.txt33
-rw-r--r--test/prism/snapshots/whitequark/ternary_ambiguous_symbol.txt48
-rw-r--r--test/prism/snapshots/whitequark/trailing_forward_arg.txt52
-rw-r--r--test/prism/snapshots/whitequark/true.txt6
-rw-r--r--test/prism/snapshots/whitequark/unary_num_pow_precedence.txt74
-rw-r--r--test/prism/snapshots/whitequark/undef.txt36
-rw-r--r--test/prism/snapshots/whitequark/unless.txt61
-rw-r--r--test/prism/snapshots/whitequark/unless_else.txt93
-rw-r--r--test/prism/snapshots/whitequark/unless_mod.txt33
-rw-r--r--test/prism/snapshots/whitequark/until.txt61
-rw-r--r--test/prism/snapshots/whitequark/until_mod.txt33
-rw-r--r--test/prism/snapshots/whitequark/until_post.txt42
-rw-r--r--test/prism/snapshots/whitequark/var_and_asgn.txt13
-rw-r--r--test/prism/snapshots/whitequark/var_op_asgn.txt53
-rw-r--r--test/prism/snapshots/whitequark/var_op_asgn_cmd.txt28
-rw-r--r--test/prism/snapshots/whitequark/var_or_asgn.txt13
-rw-r--r--test/prism/snapshots/whitequark/when_multi.txt49
-rw-r--r--test/prism/snapshots/whitequark/when_splat.txt69
-rw-r--r--test/prism/snapshots/whitequark/when_then.txt43
-rw-r--r--test/prism/snapshots/whitequark/while.txt61
-rw-r--r--test/prism/snapshots/whitequark/while_mod.txt33
-rw-r--r--test/prism/snapshots/whitequark/while_post.txt42
-rw-r--r--test/prism/snapshots/whitequark/xstring_interp.txt37
-rw-r--r--test/prism/snapshots/whitequark/xstring_plain.txt10
-rw-r--r--test/prism/snapshots/whitequark/yield.txt51
-rw-r--r--test/prism/snapshots/whitequark/zsuper.txt7
-rw-r--r--test/prism/snapshots/xstring.txt52
-rw-r--r--test/prism/snapshots/yield.txt39
-rw-r--r--test/prism/test_helper.rb91
-rw-r--r--test/prism/unescape_test.rb235
-rw-r--r--test/prism/version_test.rb11
-rw-r--r--test/psych/test_encoding.rb4
-rw-r--r--test/psych/test_numeric.rb9
-rw-r--r--test/psych/test_parser.rb23
-rw-r--r--test/psych/test_psych.rb7
-rw-r--r--test/psych/test_yaml.rb32
-rw-r--r--test/psych/visitors/test_emitter.rb16
-rw-r--r--test/psych/visitors/test_yaml_tree.rb8
-rw-r--r--test/racc/assets/cadenza.y170
-rw-r--r--test/racc/assets/cast.y926
-rw-r--r--test/racc/assets/chk.y126
-rw-r--r--test/racc/assets/conf.y16
-rw-r--r--test/racc/assets/csspool.y729
-rw-r--r--test/racc/assets/digraph.y29
-rw-r--r--test/racc/assets/echk.y118
-rw-r--r--test/racc/assets/edtf.y583
-rw-r--r--test/racc/assets/err.y60
-rw-r--r--test/racc/assets/error_recovery.y35
-rw-r--r--test/racc/assets/expect.y7
-rw-r--r--test/racc/assets/firstline.y4
-rw-r--r--test/racc/assets/huia.y318
-rw-r--r--test/racc/assets/ichk.y102
-rw-r--r--test/racc/assets/ifelse.y14
-rw-r--r--test/racc/assets/intp.y546
-rw-r--r--test/racc/assets/journey.y47
-rw-r--r--test/racc/assets/liquor.y313
-rw-r--r--test/racc/assets/machete.y423
-rw-r--r--test/racc/assets/macruby.y2197
-rw-r--r--test/racc/assets/mailp.y437
-rw-r--r--test/racc/assets/mediacloth.y599
-rw-r--r--test/racc/assets/mof.y649
-rw-r--r--test/racc/assets/namae.y302
-rw-r--r--test/racc/assets/nasl.y626
-rw-r--r--test/racc/assets/newsyn.y25
-rw-r--r--test/racc/assets/noend.y4
-rw-r--r--test/racc/assets/nokogiri-css.y255
-rw-r--r--test/racc/assets/nonass.y41
-rw-r--r--test/racc/assets/normal.y27
-rw-r--r--test/racc/assets/norule.y4
-rw-r--r--test/racc/assets/nullbug1.y25
-rw-r--r--test/racc/assets/nullbug2.y15
-rw-r--r--test/racc/assets/opal.y1807
-rw-r--r--test/racc/assets/opt.y123
-rw-r--r--test/racc/assets/percent.y35
-rw-r--r--test/racc/assets/php_serialization.y98
-rw-r--r--test/racc/assets/recv.y97
-rw-r--r--test/racc/assets/riml.y665
-rw-r--r--test/racc/assets/rrconf.y14
-rw-r--r--test/racc/assets/ruby18.y1943
-rw-r--r--test/racc/assets/ruby19.y2174
-rw-r--r--test/racc/assets/ruby20.y2350
-rw-r--r--test/racc/assets/ruby21.y2359
-rw-r--r--test/racc/assets/ruby22.y2381
-rw-r--r--test/racc/assets/scan.y72
-rw-r--r--test/racc/assets/syntax.y50
-rw-r--r--test/racc/assets/tp_plus.y622
-rw-r--r--test/racc/assets/twowaysql.y278
-rw-r--r--test/racc/assets/unterm.y5
-rw-r--r--test/racc/assets/useless.y12
-rw-r--r--test/racc/assets/yyerr.y46
-rw-r--r--test/racc/bench.y36
-rw-r--r--test/racc/case.rb111
-rw-r--r--test/racc/infini.y8
-rw-r--r--test/racc/regress/README.txt7
-rw-r--r--test/racc/regress/cadenza796
-rw-r--r--test/racc/regress/cast3945
-rw-r--r--test/racc/regress/csspool2314
-rw-r--r--test/racc/regress/edtf1794
-rw-r--r--test/racc/regress/huia1681
-rw-r--r--test/racc/regress/journey222
-rw-r--r--test/racc/regress/liquor885
-rw-r--r--test/racc/regress/machete833
-rw-r--r--test/racc/regress/mediacloth1463
-rw-r--r--test/racc/regress/mof1368
-rw-r--r--test/racc/regress/namae634
-rw-r--r--test/racc/regress/nasl2548
-rw-r--r--test/racc/regress/nokogiri-css836
-rw-r--r--test/racc/regress/opal10107
-rw-r--r--test/racc/regress/php_serialization336
-rw-r--r--test/racc/regress/riml4037
-rw-r--r--test/racc/regress/ruby189945
-rw-r--r--test/racc/regress/ruby2211180
-rw-r--r--test/racc/regress/tp_plus1933
-rw-r--r--test/racc/regress/twowaysql556
-rw-r--r--test/racc/scandata/brace7
-rw-r--r--test/racc/scandata/gvar1
-rw-r--r--test/racc/scandata/normal4
-rw-r--r--test/racc/scandata/percent18
-rw-r--r--test/racc/scandata/slash10
-rw-r--r--test/racc/src.intp34
-rw-r--r--test/racc/start.y20
-rw-r--r--test/racc/test_chk_y.rb52
-rw-r--r--test/racc/test_grammar_file_parser.rb15
-rw-r--r--test/racc/test_racc_command.rb339
-rw-r--r--test/racc/test_scan_y.rb52
-rw-r--r--test/racc/testscanner.rb51
-rw-r--r--test/rdoc/support/text_formatter_test_case.rb1
-rw-r--r--test/rdoc/test_rdoc_any_method.rb38
-rw-r--r--test/rdoc/test_rdoc_comment.rb9
-rw-r--r--test/rdoc/test_rdoc_context_section.rb1
-rw-r--r--test/rdoc/test_rdoc_generator_darkfish.rb35
-rw-r--r--test/rdoc/test_rdoc_generator_markup.rb1
-rw-r--r--test/rdoc/test_rdoc_markup.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_attribute_manager.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_attributes.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_document.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_hard_break.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_heading.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_include.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_indented_paragraph.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_paragraph.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_raw.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_ansi.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_html.rb5
-rw-r--r--test/rdoc/test_rdoc_markup_to_joined_paragraph.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_label.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_markdown.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_rdoc.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_table_of_contents.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_tt_only.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_verbatim.rb1
-rw-r--r--test/rdoc/test_rdoc_options.rb20
-rw-r--r--test/rdoc/test_rdoc_parser_c.rb1
-rw-r--r--test/rdoc/test_rdoc_parser_changelog.rb1
-rw-r--r--test/rdoc/test_rdoc_parser_markdown.rb1
-rw-r--r--test/rdoc/test_rdoc_parser_rd.rb1
-rw-r--r--test/rdoc/test_rdoc_parser_ruby.rb15
-rw-r--r--test/rdoc/test_rdoc_parser_simple.rb1
-rw-r--r--test/rdoc/test_rdoc_rd.rb1
-rw-r--r--test/rdoc/test_rdoc_rd_inline.rb1
-rw-r--r--test/rdoc/test_rdoc_ri_paths.rb1
-rw-r--r--test/rdoc/test_rdoc_single_class.rb1
-rw-r--r--test/rdoc/test_rdoc_stats.rb1
-rw-r--r--test/rdoc/test_rdoc_store.rb8
-rw-r--r--test/rdoc/test_rdoc_task.rb9
-rw-r--r--test/rdoc/test_rdoc_token_stream.rb1
-rw-r--r--test/rdoc/xref_data.rb1
-rw-r--r--test/rdoc/xref_test_case.rb1
-rw-r--r--test/readline/helper.rb29
-rw-r--r--test/readline/test_readline.rb955
-rw-r--r--test/readline/test_readline_history.rb292
-rw-r--r--test/reline/helper.rb80
-rw-r--r--test/reline/test_ansi_with_terminfo.rb112
-rw-r--r--test/reline/test_ansi_without_terminfo.rb77
-rw-r--r--test/reline/test_config.rb21
-rw-r--r--test/reline/test_face.rb198
-rw-r--r--test/reline/test_history.rb2
-rw-r--r--test/reline/test_key_actor_emacs.rb33
-rw-r--r--test/reline/test_key_actor_vi.rb2
-rw-r--r--test/reline/test_key_stroke.rb26
-rw-r--r--test/reline/test_line_editor.rb13
-rw-r--r--test/reline/test_macro.rb2
-rw-r--r--test/reline/test_reline.rb14
-rw-r--r--test/reline/test_reline_key.rb1
-rw-r--r--test/reline/test_string_processing.rb2
-rw-r--r--test/reline/test_unicode.rb40
-rw-r--r--test/reline/test_within_pipe.rb8
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl45
-rw-r--r--test/reline/yamatanooroti/termination_checker.rb38
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb427
-rw-r--r--test/resolv/test_dns.rb7
-rw-r--r--test/resolv/test_resource.rb8
-rw-r--r--test/rinda/test_rinda.rb4
-rw-r--r--test/ripper/assert_parse_files.rb25
-rw-r--r--test/ripper/dummyparser.rb53
-rw-r--r--test/ripper/test_lexer.rb53
-rw-r--r--test/ripper/test_parser_events.rb5
-rw-r--r--test/ripper/test_ripper.rb7
-rw-r--r--test/ripper/test_scanner_events.rb26
-rw-r--r--test/ripper/test_sexp.rb26
-rw-r--r--test/ruby/enc/test_case_comprehensive.rb2
-rw-r--r--test/ruby/enc/test_emoji_breaks.rb2
-rw-r--r--test/ruby/enc/test_grapheme_breaks.rb2
-rw-r--r--test/ruby/enc/test_regex_casefold.rb2
-rw-r--r--test/ruby/rjit/test_assembler.rb366
-rw-r--r--test/ruby/test_argf.rb1
-rw-r--r--test/ruby/test_arity.rb1
-rw-r--r--test/ruby/test_assignment.rb10
-rw-r--r--test/ruby/test_ast.rb175
-rw-r--r--test/ruby/test_autoload.rb5
-rw-r--r--test/ruby/test_backtrace.rb6
-rw-r--r--test/ruby/test_beginendblock.rb9
-rw-r--r--test/ruby/test_call.rb980
-rw-r--r--test/ruby/test_class.rb11
-rw-r--r--test/ruby/test_clone.rb7
-rw-r--r--test/ruby/test_comparable.rb10
-rw-r--r--test/ruby/test_compile_prism.rb1109
-rw-r--r--test/ruby/test_complex.rb40
-rw-r--r--test/ruby/test_data.rb17
-rw-r--r--test/ruby/test_default_gems.rb19
-rw-r--r--test/ruby/test_defined.rb14
-rw-r--r--test/ruby/test_dir.rb90
-rw-r--r--test/ruby/test_econv.rb2
-rw-r--r--test/ruby/test_encoding.rb50
-rw-r--r--test/ruby/test_enum.rb12
-rw-r--r--test/ruby/test_enumerator.rb21
-rw-r--r--test/ruby/test_env.rb16
-rw-r--r--test/ruby/test_eval.rb7
-rw-r--r--test/ruby/test_exception.rb21
-rw-r--r--test/ruby/test_fiber.rb2
-rw-r--r--test/ruby/test_file_exhaustive.rb9
-rw-r--r--test/ruby/test_float.rb31
-rw-r--r--test/ruby/test_gc.rb362
-rw-r--r--test/ruby/test_gc_compact.rb79
-rw-r--r--test/ruby/test_hash.rb96
-rw-r--r--test/ruby/test_integer.rb75
-rw-r--r--test/ruby/test_integer_comb.rb23
-rw-r--r--test/ruby/test_io.rb188
-rw-r--r--test/ruby/test_io_buffer.rb96
-rw-r--r--test/ruby/test_io_m17n.rb104
-rw-r--r--test/ruby/test_iseq.rb53
-rw-r--r--test/ruby/test_keyword.rb10
-rw-r--r--test/ruby/test_lambda.rb26
-rw-r--r--test/ruby/test_lazy_enumerator.rb5
-rw-r--r--test/ruby/test_m17n.rb18
-rw-r--r--test/ruby/test_marshal.rb10
-rw-r--r--test/ruby/test_math.rb10
-rw-r--r--test/ruby/test_method.rb71
-rw-r--r--test/ruby/test_mjit.rb1327
-rw-r--r--test/ruby/test_mjit_debug.rb17
-rw-r--r--test/ruby/test_module.rb27
-rw-r--r--test/ruby/test_nomethod_error.rb2
-rw-r--r--test/ruby/test_object.rb12
-rw-r--r--test/ruby/test_optimization.rb2
-rw-r--r--test/ruby/test_pack.rb54
-rw-r--r--test/ruby/test_parse.rb217
-rw-r--r--test/ruby/test_pattern_matching.rb18
-rw-r--r--test/ruby/test_proc.rb74
-rw-r--r--test/ruby/test_process.rb261
-rw-r--r--test/ruby/test_random_formatter.rb55
-rw-r--r--test/ruby/test_range.rb222
-rw-r--r--test/ruby/test_refinement.rb30
-rw-r--r--test/ruby/test_regexp.rb272
-rw-r--r--test/ruby/test_require.rb31
-rw-r--r--test/ruby/test_require_lib.rb31
-rw-r--r--test/ruby/test_rubyoptions.rb270
-rw-r--r--test/ruby/test_rubyvm_mjit.rb105
-rw-r--r--test/ruby/test_settracefunc.rb144
-rw-r--r--test/ruby/test_shapes.rb504
-rw-r--r--test/ruby/test_signal.rb43
-rw-r--r--test/ruby/test_sprintf.rb12
-rw-r--r--test/ruby/test_stack.rb1
-rw-r--r--test/ruby/test_string.rb533
-rw-r--r--test/ruby/test_string_memory.rb55
-rw-r--r--test/ruby/test_struct.rb22
-rw-r--r--test/ruby/test_super.rb29
-rw-r--r--test/ruby/test_syntax.rb75
-rw-r--r--test/ruby/test_system.rb13
-rw-r--r--test/ruby/test_thread.rb41
-rw-r--r--test/ruby/test_thread_cv.rb6
-rw-r--r--test/ruby/test_thread_queue.rb34
-rw-r--r--test/ruby/test_time.rb9
-rw-r--r--test/ruby/test_time_tz.rb8
-rw-r--r--test/ruby/test_transcode.rb498
-rw-r--r--test/ruby/test_variable.rb105
-rw-r--r--test/ruby/test_vm_dump.rb2
-rw-r--r--test/ruby/test_weakkeymap.rb140
-rw-r--r--test/ruby/test_weakmap.rb44
-rw-r--r--test/ruby/test_yjit.rb332
-rw-r--r--test/ruby/test_yjit_exit_locations.rb20
-rw-r--r--test/rubygems/bundler_test_gem.rb31
-rw-r--r--test/rubygems/helper.rb279
-rw-r--r--test/rubygems/installer_test_case.rb10
-rw-r--r--test/rubygems/mock_gem_ui.rb86
-rw-r--r--test/rubygems/package/tar_test_case.rb6
-rw-r--r--test/rubygems/plugin/exception/rubygems_plugin.rb4
-rw-r--r--test/rubygems/plugin/scripterror/rubygems_plugin.rb4
-rw-r--r--test/rubygems/test_config.rb4
-rw-r--r--test/rubygems/test_deprecate.rb8
-rw-r--r--test/rubygems/test_gem.rb159
-rw-r--r--test/rubygems/test_gem_available_set.rb6
-rw-r--r--test/rubygems/test_gem_bundler_version_finder.rb2
-rw-r--r--test/rubygems/test_gem_command.rb45
-rw-r--r--test/rubygems/test_gem_command_manager.rb68
-rw-r--r--test/rubygems/test_gem_commands_build_command.rb15
-rw-r--r--test/rubygems/test_gem_commands_cert_command.rb67
-rw-r--r--test/rubygems/test_gem_commands_cleanup_command.rb8
-rw-r--r--test/rubygems/test_gem_commands_contents_command.rb14
-rw-r--r--test/rubygems/test_gem_commands_environment_command.rb49
-rw-r--r--test/rubygems/test_gem_commands_exec_command.rb78
-rw-r--r--test/rubygems/test_gem_commands_generate_index_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_help_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_info_command.rb12
-rw-r--r--test/rubygems/test_gem_commands_install_command.rb97
-rw-r--r--test/rubygems/test_gem_commands_mirror.rb2
-rw-r--r--test/rubygems/test_gem_commands_open_command.rb13
-rw-r--r--test/rubygems/test_gem_commands_owner_command.rb22
-rw-r--r--test/rubygems/test_gem_commands_pristine_command.rb14
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb17
-rw-r--r--test/rubygems/test_gem_commands_query_command.rb64
-rw-r--r--test/rubygems/test_gem_commands_server_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_setup_command.rb28
-rw-r--r--test/rubygems/test_gem_commands_signin_command.rb24
-rw-r--r--test/rubygems/test_gem_commands_signout_command.rb6
-rw-r--r--test/rubygems/test_gem_commands_specification_command.rb30
-rw-r--r--test/rubygems/test_gem_commands_stale_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_uninstall_command.rb30
-rw-r--r--test/rubygems/test_gem_commands_unpack_command.rb8
-rw-r--r--test/rubygems/test_gem_commands_which_command.rb12
-rw-r--r--test/rubygems/test_gem_commands_yank_command.rb6
-rw-r--r--test/rubygems/test_gem_config_file.rb66
-rw-r--r--test/rubygems/test_gem_dependency.rb9
-rw-r--r--test/rubygems/test_gem_dependency_installer.rb107
-rw-r--r--test/rubygems/test_gem_dependency_list.rb12
-rw-r--r--test/rubygems/test_gem_dependency_resolution_error.rb14
-rw-r--r--test/rubygems/test_gem_ext_builder.rb146
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder.rb10
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock40
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock30
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder_unit.rb2
-rw-r--r--test/rubygems/test_gem_ext_cmake_builder.rb14
-rw-r--r--test/rubygems/test_gem_ext_configure_builder.rb2
-rw-r--r--test/rubygems/test_gem_ext_ext_conf_builder.rb17
-rw-r--r--test/rubygems/test_gem_ext_rake_builder.rb22
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb31
-rw-r--r--test/rubygems/test_gem_indexer.rb25
-rw-r--r--test/rubygems/test_gem_install_update_options.rb39
-rw-r--r--test/rubygems/test_gem_installer.rb141
-rw-r--r--test/rubygems/test_gem_name_tuple.rb33
-rw-r--r--test/rubygems/test_gem_package.rb275
-rw-r--r--test/rubygems/test_gem_package_old.rb6
-rw-r--r--test/rubygems/test_gem_package_tar_header.rb21
-rw-r--r--test/rubygems/test_gem_package_tar_reader.rb25
-rw-r--r--test/rubygems/test_gem_package_tar_reader_entry.rb72
-rw-r--r--test/rubygems/test_gem_package_tar_writer.rb88
-rw-r--r--test/rubygems/test_gem_platform.rb22
-rw-r--r--test/rubygems/test_gem_rdoc.rb4
-rw-r--r--test/rubygems/test_gem_remote_fetcher.rb157
-rw-r--r--test/rubygems/test_gem_request.rb67
-rw-r--r--test/rubygems/test_gem_request_connection_pools.rb4
-rw-r--r--test/rubygems/test_gem_request_set.rb46
-rw-r--r--test/rubygems/test_gem_request_set_gem_dependency_api.rb66
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_parser.rb16
-rw-r--r--test/rubygems/test_gem_requirement.rb4
-rw-r--r--test/rubygems/test_gem_resolver.rb78
-rw-r--r--test/rubygems/test_gem_resolver_activation_request.rb14
-rw-r--r--test/rubygems/test_gem_resolver_api_set.rb63
-rw-r--r--test/rubygems/test_gem_resolver_best_set.rb34
-rw-r--r--test/rubygems/test_gem_resolver_conflict.rb10
-rw-r--r--test/rubygems/test_gem_resolver_dependency_request.rb24
-rw-r--r--test/rubygems/test_gem_resolver_git_specification.rb3
-rw-r--r--test/rubygems/test_gem_resolver_index_set.rb28
-rw-r--r--test/rubygems/test_gem_resolver_index_specification.rb9
-rw-r--r--test/rubygems/test_gem_resolver_installer_set.rb22
-rw-r--r--test/rubygems/test_gem_resolver_lock_set.rb6
-rw-r--r--test/rubygems/test_gem_resolver_lock_specification.rb14
-rw-r--r--test/rubygems/test_gem_resolver_vendor_specification.rb3
-rw-r--r--test/rubygems/test_gem_safe_marshal.rb381
-rw-r--r--test/rubygems/test_gem_security.rb60
-rw-r--r--test/rubygems/test_gem_security_policy.rb36
-rw-r--r--test/rubygems/test_gem_security_signer.rb18
-rw-r--r--test/rubygems/test_gem_security_trust_dir.rb18
-rw-r--r--test/rubygems/test_gem_silent_ui.rb2
-rw-r--r--test/rubygems/test_gem_source.rb20
-rw-r--r--test/rubygems/test_gem_source_git.rb6
-rw-r--r--test/rubygems/test_gem_source_installed.rb2
-rw-r--r--test/rubygems/test_gem_source_local.rb4
-rw-r--r--test/rubygems/test_gem_source_lock.rb2
-rw-r--r--test/rubygems/test_gem_source_specific_file.rb4
-rw-r--r--test/rubygems/test_gem_source_subpath_problem.rb2
-rw-r--r--test/rubygems/test_gem_source_vendor.rb2
-rw-r--r--test/rubygems/test_gem_spec_fetcher.rb12
-rw-r--r--test/rubygems/test_gem_specification.rb260
-rw-r--r--test/rubygems/test_gem_stream_ui.rb4
-rw-r--r--test/rubygems/test_gem_stub_specification.rb2
-rw-r--r--test/rubygems/test_gem_uninstaller.rb28
-rw-r--r--test/rubygems/test_gem_update_suggestion.rb150
-rw-r--r--test/rubygems/test_gem_util.rb14
-rw-r--r--test/rubygems/test_gem_version.rb6
-rw-r--r--test/rubygems/test_kernel.rb4
-rw-r--r--test/rubygems/test_remote_fetch_error.rb2
-rw-r--r--test/rubygems/test_require.rb26
-rw-r--r--test/rubygems/test_rubygems.rb2
-rw-r--r--test/rubygems/utilities.rb13
-rw-r--r--test/runner.rb9
-rw-r--r--test/set/test_set.rb892
-rw-r--r--test/socket/test_socket.rb22
-rw-r--r--test/socket/test_tcp.rb2
-rw-r--r--test/socket/test_unix.rb68
-rw-r--r--test/stringio/test_stringio.rb38
-rw-r--r--test/test_extlibs.rb2
-rw-r--r--test/test_ipaddr.rb20
-rw-r--r--test/test_mutex_m.rb21
-rw-r--r--test/test_open3.rb10
-rw-r--r--test/test_pp.rb13
-rw-r--r--test/test_set.rb879
-rw-r--r--test/test_singleton.rb21
-rw-r--r--test/test_sorted_set.rb (renamed from test/set/test_sorted_set.rb)0
-rw-r--r--test/test_tempfile.rb27
-rw-r--r--test/test_timeout.rb110
-rw-r--r--test/test_tmpdir.rb16
-rw-r--r--test/test_trick.rb59
-rw-r--r--test/test_unicode_normalize.rb2
-rw-r--r--test/uri/test_common.rb10
-rw-r--r--test/uri/test_ftp.rb10
-rw-r--r--test/uri/test_generic.rb22
-rw-r--r--test/uri/test_http.rb8
-rw-r--r--test/uri/test_ldap.rb8
-rw-r--r--test/uri/test_parser.rb8
-rw-r--r--test/uri/test_ws.rb8
-rw-r--r--test/uri/test_wss.rb8
-rw-r--r--test/win32ole/test_win32ole.rb2
-rw-r--r--test/zlib/test_zlib.rb23
-rw-r--r--thread.c708
-rw-r--r--thread_none.c60
-rw-r--r--thread_none.h1
-rw-r--r--thread_pthread.c3233
-rw-r--r--thread_pthread.h121
-rw-r--r--thread_pthread_mn.c855
-rw-r--r--thread_sync.c264
-rw-r--r--thread_win32.c198
-rw-r--r--thread_win32.h7
-rw-r--r--time.c322
-rw-r--r--timev.rb2
-rw-r--r--tool/bundler/dev_gems.rb3
-rw-r--r--tool/bundler/dev_gems.rb.lock57
-rw-r--r--tool/bundler/rubocop_gems.rb2
-rw-r--r--tool/bundler/rubocop_gems.rb.lock73
-rw-r--r--tool/bundler/standard_gems.rb.lock81
-rw-r--r--tool/bundler/test_gems.rb2
-rw-r--r--tool/bundler/test_gems.rb.lock45
-rw-r--r--tool/ci_functions.sh29
-rwxr-xr-xtool/darwin-ar6
-rwxr-xr-xtool/darwin-cc3
-rw-r--r--tool/downloader.rb1
-rwxr-xr-xtool/enc-case-folding.rb6
-rwxr-xr-xtool/enc-unicode.rb101
-rwxr-xr-xtool/extlibs.rb2
-rwxr-xr-xtool/fetch-bundled_gems.rb10
-rwxr-xr-xtool/gen-github-release.rb59
-rwxr-xr-xtool/leaked-globals44
-rw-r--r--tool/lib/bundled_gem.rb65
-rw-r--r--tool/lib/colorize.rb4
-rw-r--r--tool/lib/core_assertions.rb41
-rw-r--r--tool/lib/envutil.rb31
-rw-r--r--tool/lib/memory_status.rb2
-rw-r--r--tool/lib/output.rb12
-rw-r--r--tool/lib/test/unit.rb108
-rw-r--r--tool/lib/test/unit/parallel.rb4
-rw-r--r--tool/lib/test/unit/testcase.rb19
-rw-r--r--tool/lib/vcs.rb59
-rw-r--r--tool/lrama/LEGAL.md11
-rw-r--r--tool/lrama/MIT21
-rwxr-xr-xtool/lrama/exe/lrama6
-rw-r--r--tool/lrama/lib/lrama.rb18
-rw-r--r--tool/lrama/lib/lrama/bitmap.rb29
-rw-r--r--tool/lrama/lib/lrama/command.rb46
-rw-r--r--tool/lrama/lib/lrama/context.rb519
-rw-r--r--tool/lrama/lib/lrama/counterexamples.rb283
-rw-r--r--tool/lrama/lib/lrama/counterexamples/derivation.rb63
-rw-r--r--tool/lrama/lib/lrama/counterexamples/example.rb124
-rw-r--r--tool/lrama/lib/lrama/counterexamples/path.rb69
-rw-r--r--tool/lrama/lib/lrama/counterexamples/state_item.rb6
-rw-r--r--tool/lrama/lib/lrama/counterexamples/triple.rb21
-rw-r--r--tool/lrama/lib/lrama/digraph.rb51
-rw-r--r--tool/lrama/lib/lrama/grammar.rb822
-rw-r--r--tool/lrama/lib/lrama/grammar/auxiliary.rb7
-rw-r--r--tool/lrama/lib/lrama/grammar/code.rb122
-rw-r--r--tool/lrama/lib/lrama/grammar/error_token.rb9
-rw-r--r--tool/lrama/lib/lrama/grammar/percent_code.rb12
-rw-r--r--tool/lrama/lib/lrama/grammar/precedence.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/printer.rb9
-rw-r--r--tool/lrama/lib/lrama/grammar/reference.rb22
-rw-r--r--tool/lrama/lib/lrama/grammar/rule.rb39
-rw-r--r--tool/lrama/lib/lrama/grammar/symbol.rb87
-rw-r--r--tool/lrama/lib/lrama/grammar/union.rb10
-rw-r--r--tool/lrama/lib/lrama/lexer.rb173
-rw-r--r--tool/lrama/lib/lrama/lexer/token.rb26
-rw-r--r--tool/lrama/lib/lrama/lexer/token/char.rb8
-rw-r--r--tool/lrama/lib/lrama/lexer/token/ident.rb8
-rw-r--r--tool/lrama/lib/lrama/lexer/token/parameterizing.rb19
-rw-r--r--tool/lrama/lib/lrama/lexer/token/tag.rb8
-rw-r--r--tool/lrama/lib/lrama/lexer/token/user_code.rb14
-rw-r--r--tool/lrama/lib/lrama/option_parser.rb128
-rw-r--r--tool/lrama/lib/lrama/options.rb24
-rw-r--r--tool/lrama/lib/lrama/output.rb417
-rw-r--r--tool/lrama/lib/lrama/parser.rb1844
-rw-r--r--tool/lrama/lib/lrama/report.rb2
-rw-r--r--tool/lrama/lib/lrama/report/duration.rb25
-rw-r--r--tool/lrama/lib/lrama/report/profile.rb25
-rw-r--r--tool/lrama/lib/lrama/state.rb166
-rw-r--r--tool/lrama/lib/lrama/state/reduce.rb35
-rw-r--r--tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb9
-rw-r--r--tool/lrama/lib/lrama/state/resolved_conflict.rb29
-rw-r--r--tool/lrama/lib/lrama/state/shift.rb13
-rw-r--r--tool/lrama/lib/lrama/state/shift_reduce_conflict.rb9
-rw-r--r--tool/lrama/lib/lrama/states.rb556
-rw-r--r--tool/lrama/lib/lrama/states/item.rb79
-rw-r--r--tool/lrama/lib/lrama/states_reporter.rb323
-rw-r--r--tool/lrama/lib/lrama/type.rb4
-rw-r--r--tool/lrama/lib/lrama/version.rb3
-rw-r--r--tool/lrama/lib/lrama/warning.rb25
-rw-r--r--tool/lrama/template/bison/_yacc.h71
-rw-r--r--tool/lrama/template/bison/yacc.c2049
-rw-r--r--tool/lrama/template/bison/yacc.h40
-rw-r--r--tool/m4/ruby_stack_grow_direction.m42
-rw-r--r--tool/m4/ruby_universal_arch.m44
-rwxr-xr-xtool/make-snapshot42
-rwxr-xr-xtool/merger.rb186
-rwxr-xr-xtool/mjit/bindgen.rb435
-rw-r--r--tool/mjit_archflag.sh40
-rw-r--r--tool/mjit_tabs.rb67
-rw-r--r--tool/mk_builtin_loader.rb73
-rwxr-xr-xtool/mkconfig.rb18
-rwxr-xr-xtool/rbinstall.rb24
-rw-r--r--tool/rbs_skip_tests24
-rwxr-xr-xtool/redmine-backporter.rb154
-rwxr-xr-xtool/rjit/bindgen.rb663
-rw-r--r--tool/ruby_vm/helpers/c_escape.rb5
-rw-r--r--tool/ruby_vm/models/attribute.rb2
-rwxr-xr-xtool/ruby_vm/models/bare_instructions.rb16
-rw-r--r--tool/ruby_vm/models/c_expr.rb6
-rw-r--r--tool/ruby_vm/models/operands_unifications.rb8
-rw-r--r--tool/ruby_vm/views/_comptime_insn_stack_increase.erb2
-rw-r--r--tool/ruby_vm/views/_insn_entry.erb9
-rw-r--r--tool/ruby_vm/views/_leaf_helpers.erb2
-rw-r--r--tool/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb40
-rw-r--r--tool/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb14
-rw-r--r--tool/ruby_vm/views/mjit_sp_inc.inc.erb17
-rw-r--r--tool/ruby_vm/views/opt_sc.inc.erb40
-rw-r--r--tool/ruby_vm/views/optinsn.inc.erb4
-rw-r--r--tool/rubyspec_temp.rb13
-rwxr-xr-xtool/runruby.rb3
-rwxr-xr-xtool/sync_default_gems.rb494
-rw-r--r--tool/test-bundled-gems.rb8
-rw-r--r--tool/test-coverage.rb21
-rw-r--r--tool/test/runner.rb2
-rwxr-xr-xtool/test/test_sync_default_gems.rb193
-rw-r--r--tool/test/testunit/test4test_load_failure.rb1
-rw-r--r--tool/test/testunit/test4test_timeout.rb15
-rw-r--r--tool/test/testunit/test_hideskip.rb4
-rw-r--r--tool/test/testunit/test_load_failure.rb23
-rw-r--r--tool/test/testunit/test_parallel.rb27
-rw-r--r--tool/test/testunit/test_sorting.rb2
-rw-r--r--tool/test/testunit/test_timeout.rb10
-rw-r--r--tool/test/testunit/tests_for_parallel/slow_helper.rb7
-rw-r--r--tool/test/testunit/tests_for_parallel/test4test_slow_0.rb5
-rw-r--r--tool/test/testunit/tests_for_parallel/test4test_slow_1.rb5
-rw-r--r--tool/test/webrick/test_httpserver.rb2
-rw-r--r--tool/test/webrick/test_server.rb2
-rw-r--r--tool/transform_mjit_header.rb319
-rwxr-xr-xtool/update-NEWS-gemlist.rb41
-rwxr-xr-xtool/update-bundled_gems.rb39
-rwxr-xr-xtool/update-deps51
-rwxr-xr-xtool/ytab.sed80
-rw-r--r--trace_point.rb7
-rw-r--r--transcode.c19
-rw-r--r--transient_heap.c991
-rw-r--r--transient_heap.h65
-rw-r--r--universal_parser.c375
-rw-r--r--util.c15
-rw-r--r--variable.c1162
-rw-r--r--variable.h14
-rw-r--r--version.c91
-rw-r--r--version.h14
-rw-r--r--vm.c637
-rw-r--r--vm_args.c162
-rw-r--r--vm_backtrace.c111
-rw-r--r--vm_callinfo.h110
-rw-r--r--vm_core.h233
-rw-r--r--vm_dump.c420
-rw-r--r--vm_eval.c220
-rw-r--r--vm_exec.c59
-rw-r--r--vm_exec.h36
-rw-r--r--vm_insnhelper.c1346
-rw-r--r--vm_insnhelper.h41
-rw-r--r--vm_method.c92
-rw-r--r--vm_opts.h6
-rw-r--r--vm_sync.c123
-rw-r--r--vm_trace.c144
-rw-r--r--vsnprintf.c2
-rw-r--r--warning.rb4
-rw-r--r--wasm/setjmp.c67
-rw-r--r--wasm/setjmp.h2
-rw-r--r--weakmap.c930
-rw-r--r--win32/.document1
-rw-r--r--win32/Makefile.sub85
-rw-r--r--win32/README.win32149
-rw-r--r--win32/file.c27
-rw-r--r--win32/file.h3
-rwxr-xr-xwin32/mkexports.rb3
-rw-r--r--win32/setup.mak11
-rw-r--r--win32/win32.c206
-rw-r--r--win32/winmain.c4
-rw-r--r--yjit.c217
-rw-r--r--yjit.h24
-rw-r--r--yjit.rb338
-rw-r--r--yjit/Cargo.lock7
-rw-r--r--yjit/Cargo.toml11
-rw-r--r--yjit/bindgen/Cargo.lock159
-rw-r--r--yjit/bindgen/Cargo.toml2
-rw-r--r--yjit/bindgen/src/main.rs62
-rw-r--r--yjit/not_gmake.mk6
-rw-r--r--yjit/src/asm/arm64/arg/bitmask_imm.rs4
-rw-r--r--yjit/src/asm/arm64/arg/condition.rs2
-rw-r--r--yjit/src/asm/arm64/arg/truncate.rs4
-rw-r--r--yjit/src/asm/arm64/inst/madd.rs73
-rw-r--r--yjit/src/asm/arm64/inst/mod.rs4
-rw-r--r--yjit/src/asm/arm64/inst/smulh.rs60
-rw-r--r--yjit/src/asm/arm64/mod.rs40
-rw-r--r--yjit/src/asm/mod.rs165
-rw-r--r--yjit/src/asm/x86_64/mod.rs80
-rw-r--r--yjit/src/asm/x86_64/tests.rs20
-rw-r--r--yjit/src/backend/arm64/mod.rs573
-rw-r--r--yjit/src/backend/ir.rs655
-rw-r--r--yjit/src/backend/mod.rs6
-rw-r--r--yjit/src/backend/tests.rs47
-rw-r--r--yjit/src/backend/x86_64/mod.rs594
-rw-r--r--yjit/src/codegen.rs6822
-rw-r--r--yjit/src/core.rs2719
-rw-r--r--yjit/src/cruby.rs95
-rw-r--r--yjit/src/cruby_bindings.inc.rs484
-rw-r--r--yjit/src/disasm.rs138
-rw-r--r--yjit/src/invariants.rs206
-rw-r--r--yjit/src/options.rs175
-rw-r--r--yjit/src/stats.rs422
-rw-r--r--yjit/src/utils.rs41
-rw-r--r--yjit/src/virtualmem.rs90
-rw-r--r--yjit/src/yjit.rs133
-rw-r--r--yjit/yjit.mk46
4981 files changed, 191543 insertions, 269635 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 0a25dceab4..05ff204541 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -20,7 +20,7 @@ skip_commits:
- '**/*.[1-8]'
- '**/*.ronn'
environment:
- ruby_version: "25-%Platform%"
+ ruby_version: "24-%Platform%"
matrix:
# Test only the oldest supported version because AppVeyor is unstable, its concurrency
# is limited, and compatibility issues that happen only in newer versions are rare.
@@ -48,6 +48,7 @@ for:
- cd C:\Tools\vcpkg
- git pull -q
- .\bootstrap-vcpkg.bat
+ - ps: Start-FileDownload 'https://github.com/microsoft/vcpkg-tool/releases/download/2023-08-09/vcpkg.exe' -FileName 'C:\Tools\vcpkg\vcpkg.exe'
- cd %APPVEYOR_BUILD_FOLDER%
- vcpkg --triplet %Platform%-windows install --x-use-aria2 libffi libyaml readline zlib
- CALL SET vcvars=%%^VS%VS%COMNTOOLS^%%..\..\VC\vcvarsall.bat
@@ -94,7 +95,7 @@ for:
- nmake -l "TESTOPTS=-v -q" test-basic
- >-
nmake -l "TESTOPTS=--timeout-scale=3.0
- --excludes=../test/.excludes/_appveyor -j%JOBS%
+ --excludes=../test/excludes/_appveyor -j%JOBS%
--exclude win32ole
--exclude test_bignum
--exclude test_syntax
@@ -104,7 +105,7 @@ for:
# separately execute tests without -j which may crash worker with -j.
- >-
nmake -l
- "TESTOPTS=--timeout-scale=3.0 --excludes=../test/.excludes/_appveyor"
+ "TESTOPTS=--timeout-scale=3.0 --excludes=../test/excludes/_appveyor"
TESTS="
../test/win32ole
../test/ruby/test_bignum.rb
@@ -112,7 +113,7 @@ for:
../test/open-uri/test_open-uri.rb
../test/rubygems/test_bundled_ca.rb
" test-all
- - nmake -l test-spec # not using `-j` because sometimes `mspec -j` silently dies on Windows
+ - nmake -l test-spec MSPECOPT=-fs # not using `-j` because sometimes `mspec -j` silently dies on Windows
notifications:
- provider: Webhook
method: POST
diff --git a/.document b/.document
index e875e42546..3a6b0c238c 100644
--- a/.document
+++ b/.document
@@ -18,7 +18,7 @@ gc.rb
io.rb
kernel.rb
marshal.rb
-rjit.rb
+mjit.rb
numeric.rb
nilclass.rb
pack.rb
@@ -48,4 +48,7 @@ COPYING.ja
LEGAL
+# win32/README.win32 linked from README.md
+win32
+
doc
diff --git a/.gdbinit b/.gdbinit
index 7dd3336e28..34d044caf6 100644
--- a/.gdbinit
+++ b/.gdbinit
@@ -67,7 +67,7 @@ define rp
printf "%sT_OBJECT%s: ", $color_type, $color_end
print ((struct RObject *)($arg0))->basic
if ($flags & ROBJECT_EMBED)
- print/x *((VALUE*)((struct RObject*)($arg0))->as.ary) @ (rb_shape_get_shape($arg0)->capacity)
+ print/x *((VALUE*)((struct RObject*)($arg0))->as.ary) @ (ROBJECT_EMBED_LEN_MAX+0)
else
print (((struct RObject *)($arg0))->as.heap)
if (((struct RObject*)($arg0))->as.heap.numiv) > 0
@@ -104,8 +104,8 @@ define rp
(($rsflags & (RUBY_FL_USER2|RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6)) >> RUBY_FL_USHIFT+2)
set print address off
output *(char *)(($rsflags & RUBY_FL_USER1) ? \
- ((struct RString*)$regsrc)->as.heap.ptr : \
- ((struct RString*)$regsrc)->as.ary) @ $len
+ ((struct RString*)$regsrc)->as.heap.ptr : \
+ ((struct RString*)$regsrc)->as.ary) @ $len
set print address on
printf " len:%ld ", $len
if $flags & RUBY_FL_USER6
@@ -126,26 +126,26 @@ define rp
printf "%sT_ARRAY%s: len=%ld ", $color_type, $color_end, $len
printf "(embed) "
if ($len == 0)
- printf "{(empty)} "
+ printf "{(empty)} "
else
- print/x *((VALUE*)((struct RArray*)($arg0))->as.ary) @ $len
- printf " "
+ print/x *((VALUE*)((struct RArray*)($arg0))->as.ary) @ $len
+ printf " "
end
else
set $len = ((struct RArray*)($arg0))->as.heap.len
printf "%sT_ARRAY%s: len=%ld ", $color_type, $color_end, $len
if ($flags & RUBY_FL_USER2)
- printf "(shared) shared="
- output/x ((struct RArray*)($arg0))->as.heap.aux.shared_root
- printf " "
+ printf "(shared) shared="
+ output/x ((struct RArray*)($arg0))->as.heap.aux.shared_root
+ printf " "
else
- printf "(ownership) capa=%ld ", ((struct RArray*)($arg0))->as.heap.aux.capa
+ printf "(ownership) capa=%ld ", ((struct RArray*)($arg0))->as.heap.aux.capa
end
if ($len == 0)
- printf "{(empty)} "
+ printf "{(empty)} "
else
- print/x *((VALUE*)((struct RArray*)($arg0))->as.heap.ptr) @ $len
- printf " "
+ print/x *((VALUE*)((struct RArray*)($arg0))->as.heap.ptr) @ $len
+ printf " "
end
end
print (struct RArray *)($arg0)
@@ -445,8 +445,8 @@ define output_string
(($flags & (RUBY_FL_USER2|RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6)) >> RUBY_FL_USHIFT+2)
if $len > 0
output *(char *)(($flags & RUBY_FL_USER1) ? \
- ((struct RString*)($arg0))->as.heap.ptr : \
- ((struct RString*)($arg0))->as.ary) @ $len
+ ((struct RString*)($arg0))->as.heap.ptr : \
+ ((struct RString*)($arg0))->as.ary) @ $len
else
output ""
end
@@ -459,8 +459,8 @@ define print_string
(($flags & (RUBY_FL_USER2|RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6)) >> RUBY_FL_USHIFT+2)
if $len > 0
printf "%s", *(char *)(($flags & RUBY_FL_USER1) ? \
- ((struct RString*)($arg0))->as.heap.ptr : \
- ((struct RString*)($arg0))->as.ary) @ $len
+ ((struct RString*)($arg0))->as.heap.ptr : \
+ ((struct RString*)($arg0))->as.ary) @ $len
end
end
@@ -689,6 +689,11 @@ define nd_stts
end
+define nd_entry
+ printf "%su3.entry%s: ", $color_highlite, $color_end
+ p ($arg0).u3.entry
+end
+
define nd_vid
printf "%su1.id%s: ", $color_highlite, $color_end
p ($arg0).u1.id
@@ -863,22 +868,22 @@ define rb_numtable_entry
set $rb_numtable_p = $rb_numtable_tbl->as.packed.bins
while $rb_numtable_p && $rb_numtable_p < $rb_numtable_tbl->as.packed.bins+$rb_numtable_tbl->num_entries
if $rb_numtable_p.k == $rb_numtable_id
- set $rb_numtable_key = $rb_numtable_p.k
- set $rb_numtable_rec = $rb_numtable_p.v
- set $rb_numtable_p = 0
+ set $rb_numtable_key = $rb_numtable_p.k
+ set $rb_numtable_rec = $rb_numtable_p.v
+ set $rb_numtable_p = 0
else
- set $rb_numtable_p = $rb_numtable_p + 1
+ set $rb_numtable_p = $rb_numtable_p + 1
end
end
else
set $rb_numtable_p = $rb_numtable_tbl->as.big.bins[st_numhash($rb_numtable_id) % $rb_numtable_tbl->num_bins]
while $rb_numtable_p
if $rb_numtable_p->key == $rb_numtable_id
- set $rb_numtable_key = $rb_numtable_p->key
- set $rb_numtable_rec = $rb_numtable_p->record
- set $rb_numtable_p = 0
+ set $rb_numtable_key = $rb_numtable_p->key
+ set $rb_numtable_rec = $rb_numtable_p->record
+ set $rb_numtable_p = 0
else
- set $rb_numtable_p = $rb_numtable_p->next
+ set $rb_numtable_p = $rb_numtable_p->next
end
end
end
@@ -956,7 +961,7 @@ define iseq
set $operand_size = ((INSN*)($arg0))->operand_size
set $operands = ((INSN*)($arg0))->operands
while $i < $operand_size
- rp $operands[$i++]
+ rp $operands[$i++]
end
end
end
@@ -1274,9 +1279,9 @@ document rb_count_objects
Counts all objects grouped by type.
end
-# Details: https://github.com/ruby/ruby/wiki/Machine-Instructions-Trace-with-GDB
+# Details: https://bugs.ruby-lang.org/projects/ruby-master/wiki/MachineInstructionsTraceWithGDB
define trace_machine_instructions
- set logging enabled
+ set logging on
set height 0
set width 0
display/i $pc
@@ -1343,5 +1348,3 @@ define print_flags
printf "RUBY_FL_USER17 : %s\n", ((struct RBasic*)($arg0))->flags & RUBY_FL_USER17 ? "1" : "0"
printf "RUBY_FL_USER18 : %s\n", ((struct RBasic*)($arg0))->flags & RUBY_FL_USER18 ? "1" : "0"
end
-
-source misc/gdb.py
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 1bf7db40ad..6c5eac5a0f 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -5,7 +5,6 @@
# Expand tabs
5b21e94bebed90180d8ff63dad03b8b948361089
-c5e9af9c9d890578182a21e7b71b50334cd5579e
# Enable Style/StringLiterals cop for RubyGems/Bundler
d7ffd3fea402239b16833cc434404a7af82d44f3
@@ -22,7 +21,3 @@ f28287d34c03f472ffe90ea262bdde9affd4b965
# Make benchmark indentation consistent
fc4acf8cae82e5196186d3278d831f2438479d91
-
-# Make prism_compile.c indentation consistent
-40b2c8e5e7e6e5f83cee9276dc9c1922a69292d6
-d2c5867357ed88eccc28c2b3bd4a46e206e7ff85
diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml
deleted file mode 100644
index 359e5c0d37..0000000000
--- a/.github/actions/setup/directories/action.yml
+++ /dev/null
@@ -1,137 +0,0 @@
-name: Setup directories etc.
-description: >-
- Set up the source code and build directories (plus some
- environmental tweaks)
-
-inputs:
- srcdir:
- required: false
- default: ${{ github.workspace }}
- description: >-
- Directory to (re-)checkout source codes. This will be created
- if absent. If there is no `configure` file that is also
- generated inside.
-
- builddir:
- required: false
- default: ${{ github.workspace }}
- description: >-
- Where binaries and other generated contents go. This will be
- created if absent.
-
- makeup:
- required: false
- type: boolean
- # Note that `default: false` evaluates to a string constant
- # `'false'`, which is a truthy value :sigh:
- # https://github.com/actions/runner/issues/2238
- default: ''
- description: >-
- If set to true, additionally runs `make up`.
-
- checkout:
- required: false
- type: boolean
- default: true
- description: >-
- If set to '' (false), skip running actions/checkout. This is useful when
- you don't want to overwrite a GitHub token that is already set up.
-
- dummy-files:
- required: false
- type: boolean
- default: ''
- description: >-
- If set to true, creates dummy files in build dir.
-
-outputs: {} # nothing?
-
-runs:
- using: composite
-
- steps:
- # Note that `shell: bash` works on both Windows and Linux, but not
- # `shell: sh`. This is because GitHub hosted Windows runners have
- # their bash manually installed.
- - shell: bash
- run: |
- mkdir -p ${{ inputs.srcdir }}
- mkdir -p ${{ inputs.builddir }}
-
- # Did you know that actions/checkout works without git(1)? We are
- # checking that here.
- - id: which
- shell: bash
- run: |
- echo "git=`command -v git`" >> "$GITHUB_OUTPUT"
- echo "sudo=`command -v sudo`" >> "$GITHUB_OUTPUT"
- echo "autoreconf=`command -v autoreconf`" >> "$GITHUB_OUTPUT"
-
- - if: steps.which.outputs.git
- shell: bash
- run: |
- git config --global core.autocrlf false
- git config --global core.eol lf
- git config --global advice.detachedHead 0
- git config --global init.defaultBranch garbage
-
- - if: inputs.checkout
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- path: ${{ inputs.srcdir }}
-
- - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
- with:
- path: ${{ inputs.srcdir }}/.downloaded-cache
- key: downloaded-cache
-
- - if: steps.which.outputs.autoreconf
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: ./autogen.sh
-
- # This is for MinGW.
- - if: runner.os == 'Windows'
- shell: bash
- run: echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV
-
- - if: runner.os == 'Linux'
- shell: bash
- run: echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> "$GITHUB_ENV"
-
- # macOS' GNU make is so old that they doesn't understand `GNUMAKEFLAGS`.
- - if: runner.os == 'macOS'
- shell: bash
- run: echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> "$GITHUB_ENV"
-
- - if: inputs.makeup
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: |
- touch config.status
- touch .rbconfig.time
- sed -f tool/prereq.status template/Makefile.in > Makefile
- sed -f tool/prereq.status template/GNUmakefile.in > GNUmakefile
- make up
-
- # Cleanup, runs even on failure
- - if: always() && inputs.makeup
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: rm -f config.status Makefile rbconfig.rb .rbconfig.time
-
- - if: steps.which.outputs.sudo
- shell: bash
- run: |
- sudo chmod -R go-w /usr/share
- chmod -v go-w $HOME $HOME/.config || :
- sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
-
- - if: inputs.dummy-files == 'true'
- shell: bash
- working-directory: ${{ inputs.builddir }}
- run: |
- : Create dummy files in build dir
- for basename in {a..z} {A..Z} {0..9} foo bar test zzz; do
- echo > ${basename}.rb "raise %(do not load ${basename}.rb)"
- done
diff --git a/.github/actions/setup/macos/action.yml b/.github/actions/setup/macos/action.yml
deleted file mode 100644
index 3649a64876..0000000000
--- a/.github/actions/setup/macos/action.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: Setup macOS environment
-description: >-
- Installs necessary packages via Homebrew.
-
-inputs: {} # nothing?
-
-outputs: {} # nothing?
-
-runs:
- using: composite
-
- steps:
- - name: brew
- shell: bash
- run: |
- brew install --quiet gmp libffi openssl@1.1 zlib autoconf automake libtool readline
-
- - name: Set ENV
- shell: bash
- run: |
- for lib in openssl@1.1 readline; do
- CONFIGURE_ARGS="${CONFIGURE_ARGS:+$CONFIGURE_ARGS }--with-${lib%@*}-dir=$(brew --prefix $lib)"
- done
- echo CONFIGURE_ARGS="${CONFIGURE_ARGS}" >> $GITHUB_ENV
diff --git a/.github/actions/setup/ubuntu/action.yml b/.github/actions/setup/ubuntu/action.yml
deleted file mode 100644
index a9e5b41951..0000000000
--- a/.github/actions/setup/ubuntu/action.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-name: Setup ubuntu environment
-description: >-
- At the beginning there was no way but to copy & paste `apt-get`
- everywhere. But now that we have composite actions, it seems better
- merge them into one.
-
-inputs:
- arch:
- required: false
- default: ''
- description: >-
- Architecture. Because we run this on a GitHub-hosted runner
- acceptable value for this input is very limited.
-
-outputs:
- arch:
- value: ${{ steps.uname.outputs.uname }}
- description: >-
- Actual architecture. This could be different from the one
- passed to the `inputs.arch`. For instance giving `i386` to this
- action yields `i686`.
-
-runs:
- using: composite
-
- steps:
- - name: set SETARCH
- shell: bash
- run: echo "SETARCH=${setarch}" >> "$GITHUB_ENV"
- env:
- setarch: ${{ inputs.arch && format('setarch {0} --', inputs.arch) }}
-
- - id: uname
- name: uname
- shell: bash
- run: |
- echo uname=`${SETARCH} uname -m` >> "$GITHUB_OUTPUT"
- echo dpkg=`${SETARCH} uname -m | sed s/686/386/` >> "$GITHUB_OUTPUT"
-
- - name: apt-get
- shell: bash
- env:
- arch: ${{ inputs.arch && format(':{0}', steps.uname.outputs.dpkg) || '' }}
- run: |
- set -x
- ${arch:+sudo dpkg --add-architecture ${arch#:}}
- sudo apt-get update -qq || :
- sudo apt-get install --no-install-recommends -qq -y -o=Dpkg::Use-Pty=0 \
- ${arch:+cross}build-essential${arch/:/-} \
- libssl-dev${arch} libyaml-dev${arch} libreadline6-dev${arch} \
- zlib1g-dev${arch} libncurses5-dev${arch} libffi-dev${arch} \
- autoconf ruby
- sudo apt-get install -qq -y pkg-config${arch} || :
diff --git a/.github/actions/slack/action.yml b/.github/actions/slack/action.yml
deleted file mode 100644
index c98be085a8..0000000000
--- a/.github/actions/slack/action.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: Post a message to slack
-description: >-
- We have our ruby/action-slack webhook. However its arguments are
- bit verbose to be listed in every workflow files. Better merge them
- into one.
-
-inputs:
- SLACK_WEBHOOK_URL:
- required: true
- description: >-
- The URL to post the payload. This is an input because it tends
- to be stored in a secrets valut and a composite action cannot
- look into one.
-
- label:
- required: false
- description: >-
- Human-readable description of the run, something like "DEBUG=1".
- This need not be unique among runs.
-
-outputs: {} # Nothing?
-
-runs:
- using: composite
-
- steps:
- - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
- with:
- payload: |
- {
- "ci": "GitHub Actions",
- "env": "${{ github.workflow }}${{ inputs.label && format(' / {0}', inputs.label) }}",
- "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
- "commit": "${{ github.sha }}",
- "branch": "${{ github.ref_name }}"
- }
- env:
- SLACK_WEBHOOK_URL: ${{ inputs.SLACK_WEBHOOK_URL }}
- if: ${{github.event_name == 'push' && startsWith(github.repository, 'ruby/')}}
diff --git a/.github/auto_request_review.yml b/.github/auto_request_review.yml
deleted file mode 100644
index 8726df577d..0000000000
--- a/.github/auto_request_review.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-files:
- 'yjit*': [team:yjit]
- 'yjit/**/*': [team:yjit]
- 'yjit/src/cruby_bindings.inc.rs': []
- 'doc/yjit/*': [team:yjit]
- 'bootstraptest/test_yjit*': [team:yjit]
- 'test/ruby/test_yjit*': [team:yjit]
-options:
- ignore_draft: true
- # This currently doesn't work as intended. We want to skip reviews when only
- # cruby_bingings.inc.rs is modified, but this skips reviews even when other
- # yjit files are modified as well. To be enabled after fixing the behavior.
- #last_files_match_only: true
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
new file mode 100644
index 0000000000..91f82b842b
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,3 @@
+name: "CodeQL config for the Ruby language"
+
+languages: cpp
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 70a73430d7..bc63aca35b 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,6 +1,6 @@
version: 2
updates:
- package-ecosystem: 'github-actions'
- directory: '/.github'
+ directory: '/'
schedule:
- interval: 'daily'
+ interval: 'monthly'
diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml
deleted file mode 100644
index 582285afa8..0000000000
--- a/.github/workflows/annocheck.yml
+++ /dev/null
@@ -1,123 +0,0 @@
-name: Annocheck
-
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- compile:
- name: gcc-11 annocheck
-
- runs-on: ubuntu-latest
-
- container:
- image: ghcr.io/ruby/ruby-ci-image:gcc-11
- options: --user root
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
- env:
- CONFIGURE_TTY: never
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUBY_DEBUG: ci rgengc
- RUBY_TESTOPTS: >-
- -q
- --color=always
- --tty=no
- # FIXME: Drop skipping options
- # https://bugs.ruby-lang.org/issues/18061
- # https://sourceware.org/annobin/annobin.html/Test-pie.html
- TEST_ANNOCHECK_OPTS: '--skip-pie --skip-gaps'
-
- steps:
- - run: id
- working-directory:
-
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
-
- # Minimal flags to pass the check.
- # -g0 disables backtraces when SEGV. Do not set that.
- - name: Run configure
- run: >
- ../src/configure -C
- --enable-debug-env
- --disable-install-doc
- --with-ext=-test-/cxxanyargs,+
- --without-valgrind
- --without-jemalloc
- --without-gmp
- --with-gcc="gcc-11 -fcf-protection -Wa,--generate-missing-build-notes=yes"
- --enable-shared
- debugflags=-ggdb3
- optflags=-O2
- LDFLAGS=-Wl,-z,now
-
- - run: make showflags
-
- - run: make
-
- - run: make test
-
- - run: make install
-
- - run: make test-tool
-
- ### test-all doesn't work: https://github.com/ruby/ruby/actions/runs/4340112185/jobs/7578344307
- # - run: make test-all TESTS='-- ruby -ext-'
-
- ### test-spec doesn't work: https://github.com/ruby/ruby/actions/runs/4340193212/jobs/7578505652
- # - run: make test-spec
- # env:
- # CHECK_LEAKS: true
-
- - run: make test-annocheck
-
- - uses: ./.github/actions/slack
- with:
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/auto_request_review.yml b/.github/workflows/auto_request_review.yml
deleted file mode 100644
index d9eb774e3f..0000000000
--- a/.github/workflows/auto_request_review.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: Auto Request Review
-on:
- pull_request_target:
- types: [opened, ready_for_review, reopened]
-
-permissions:
- contents: read
-
-jobs:
- auto-request-review:
- name: Auto Request Review
- runs-on: ubuntu-latest
- if: ${{ github.repository == 'ruby/ruby' }}
- steps:
- - name: Request review based on files changes and/or groups the author belongs to
- uses: necojackarc/auto-request-review@6a51cebffe2c084705d9a7b394abd802e0119633 # v0.12.0
- with:
- # scope: public_repo
- token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml
index 6102c61ad0..ebaafe3bf0 100644
--- a/.github/workflows/baseruby.yml
+++ b/.github/workflows/baseruby.yml
@@ -33,49 +33,48 @@ permissions:
jobs:
baseruby:
name: BASERUBY
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
strategy:
matrix:
ruby:
- - ruby-2.5
+ - ruby-2.2
+# - ruby-2.3
+# - ruby-2.4
+# - ruby-2.5
# - ruby-2.6
# - ruby-2.7
- ruby-3.0
- ruby-3.1
- - ruby-3.2
steps:
- - uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
-
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- makeup: true
-
+ - run: echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - run: sudo apt-get install build-essential autoconf bison libyaml-dev
+ - run: ./autogen.sh
- run: ./configure --disable-install-doc
-
+ - run: make common-srcs
+ - run: make incs
- run: make all
-
- run: make test
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.ruby }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / BASERUBY @ ${{ matrix.ruby }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml
index 943140e9ef..070c0fa1dd 100644
--- a/.github/workflows/bundled_gems.yml
+++ b/.github/workflows/bundled_gems.yml
@@ -2,17 +2,17 @@ name: bundled_gems
on:
push:
- branches: ['master']
+ branches: [ "master" ]
paths:
- '.github/workflows/bundled_gems.yml'
- 'gems/bundled_gems'
pull_request:
- branches: ['master']
+ branches: [ "master" ]
paths:
- '.github/workflows/bundled_gems.yml'
- 'gems/bundled_gems'
merge_group:
- branches: ['master']
+ branches: [ "master" ]
paths:
- '.github/workflows/bundled_gems.yml'
- 'gems/bundled_gems'
@@ -20,34 +20,36 @@ on:
- cron: '45 6 * * *'
workflow_dispatch:
-permissions: # added using https://github.com/step-security/secure-workflows
+permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
update:
permissions:
- contents: write # for Git to git push
-
+ contents: write # for Git to git push
if: ${{ github.event_name != 'schedule' || github.repository == 'ruby/ruby' }}
-
name: update ${{ github.workflow }}
-
runs-on: ubuntu-latest
-
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
-
- - uses: ./.github/actions/setup/directories
- with:
- # Skip overwriting MATZBOT_GITHUB_TOKEN
- checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
- name: Set ENV
run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
echo "TODAY=$(date +%F)" >> $GITHUB_ENV
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache-${{ github.sha }}
+ restore-keys: |
+ downloaded-cache
+
- name: Download previous gems list
run: |
data=bundled_gems.json
@@ -56,76 +58,109 @@ jobs:
curl -O -R -z ./$data https://stdgems.org/$data
- name: Update bundled gems list
- id: bundled_gems
run: |
- ruby -i~ tool/update-bundled_gems.rb gems/bundled_gems >> $GITHUB_OUTPUT
+ ruby -i~ tool/update-bundled_gems.rb gems/bundled_gems
- name: Maintain updated gems list in NEWS
run: |
- ruby tool/update-NEWS-gemlist.rb bundled
+ #!ruby
+ require 'json'
+ news = File.read("NEWS.md")
+ prev = news[/since the \*+(\d+\.\d+\.\d+)\*+/, 1]
+ prevs = [prev, prev.sub(/\.\d+\z/, '')]
+ %W[bundled].each do |type|
+ last = JSON.parse(File.read("#{type}_gems.json"))['gems'].filter_map do |g|
+ v = g['versions'].values_at(*prevs).compact.first
+ g = g['gem']
+ g = 'RubyGems' if g == 'rubygems'
+ [g, v] if v
+ end.to_h
+ changed = File.foreach("gems/#{type}_gems").filter_map do |l|
+ next if l.start_with?("#")
+ g, v = l.split(" ", 3)
+ [g, v] unless last[g] == v
+ end
+ changed, added = changed.partition {|g, _| last[g]}
+ news.sub!(/^\*( +)The following #{type} gems? are updated\.\n+\K(?: \1\*( +).*\n)*/) do
+ mark = "#{$1} *#{$2}"
+ changed.map {|g, v|"#{mark}#{g} #{v}\n"}.join("")
+ end or next
+ news.sub!(/^\*( +)The following default gems are now bundled gems\.\n+\K(?: \1\*( +).*\n)*/) do
+ mark = "#{$1} *#{$2}"
+ added.map {|g, v|"#{mark}#{g} #{v}\n"}.join("")
+ end or next unless added.empty?
+ File.write("NEWS.md", news)
+ end
+ shell: ruby {0}
- name: Check diffs
id: diff
run: |
- news= gems=
- git diff --color --no-ext-diff --ignore-submodules --exit-code -- NEWS.md ||
- news=true
- git diff --color --no-ext-diff --ignore-submodules --exit-code -- gems/bundled_gems ||
- gems=true
- git add -- NEWS.md gems/bundled_gems
- echo news=$news >> $GITHUB_OUTPUT
- echo gems=$gems >> $GITHUB_OUTPUT
- echo update=${news:-$gems} >> $GITHUB_OUTPUT
+ git add -- NEWS.md
+ git diff --no-ext-diff --ignore-submodules --quiet -- gems/bundled_gems
+ continue-on-error: true
- name: Install libraries
- uses: ./.github/actions/setup/ubuntu
- if: ${{ steps.diff.outputs.gems }}
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
+ if: ${{ steps.diff.outcome == 'failure' }}
- name: Build
run: |
./autogen.sh
./configure -C --disable-install-doc
make
- if: ${{ steps.diff.outputs.gems }}
+ if: ${{ steps.diff.outcome == 'failure' }}
- name: Prepare bundled gems
run: |
make -s prepare-gems
- if: ${{ steps.diff.outputs.gems }}
+ if: ${{ steps.diff.outcome == 'failure' }}
- name: Test bundled gems
run: |
make -s test-bundled-gems
+ git add -- gems/bundled_gems
timeout-minutes: 30
env:
- RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
- if: ${{ steps.diff.outputs.gems }}
+ RUBY_TESTOPTS: "-q --tty=no"
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ if: ${{ steps.diff.outcome == 'failure' }}
+
+ - name: Show diffs
+ id: show
+ run: |
+ git diff --cached --color --no-ext-diff --ignore-submodules --exit-code --
+ continue-on-error: true
- name: Commit
run: |
git pull --ff-only origin ${GITHUB_REF#refs/heads/}
- message="Update bundled gems list"
- if [ -z "${gems}" ]; then
- git commit --message="${message} at ${GITHUB_SHA:0:30} [ci skip]"
+ message="Update bundled gems list at "
+ if [ ${{ steps.diff.outcome }} = success ]; then
+ git commit --message="${message}${GITHUB_SHA:0:30} [ci skip]"
else
- git commit --message="${message} as of ${TODAY}"
+ git commit --message="${message}${TODAY}"
fi
git push origin ${GITHUB_REF#refs/heads/}
env:
- TODAY: ${{ steps.bundled_gems.outputs.latest_date || env.TODAY }}
EMAIL: svn-admin@ruby-lang.org
GIT_AUTHOR_NAME: git
GIT_COMMITTER_NAME: git
- gems: ${{ steps.diff.outputs.gems }}
- if: >-
- ${{
- github.repository == 'ruby/ruby' &&
- !startsWith(github.event_name, 'pull') &&
- steps.diff.outputs.update
- }}
-
- - uses: ./.github/actions/slack
+ if: ${{ github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull') && steps.show.outcome == 'failure' }}
+
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / update",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml
index 4da0b3696c..79b2916feb 100644
--- a/.github/workflows/check_dependencies.yml
+++ b/.github/workflows/check_dependencies.yml
@@ -33,41 +33,46 @@ jobs:
update-deps:
strategy:
matrix:
- os: [ubuntu-20.04]
+ os: [ubuntu-22.04]
fail-fast: true
-
runs-on: ${{ matrix.os }}
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
- - uses: ./.github/actions/setup/ubuntu
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
if: ${{ contains(matrix.os, 'ubuntu') }}
-
- - uses: ./.github/actions/setup/macos
+ - name: Install libraries
+ run: |
+ brew install gmp libffi openssl@1.1 zlib autoconf automake libtool readline
if: ${{ contains(matrix.os, 'macos') }}
-
- - uses: ./.github/actions/setup/directories
-
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache
+ - run: ./autogen.sh
- name: Run configure
run: ./configure -C --disable-install-doc --disable-rubygems --with-gcc 'optflags=-O0' 'debugflags=-save-temps=obj -g'
-
- run: make all golf
-
- run: ruby tool/update-deps --fix
-
- run: git diff --no-ext-diff --ignore-submodules --exit-code
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.os }} / Dependencies need to update
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ matrix.os }} / Dependencies need to update",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml
deleted file mode 100644
index d8f73d26ec..0000000000
--- a/.github/workflows/check_misc.yml
+++ /dev/null
@@ -1,115 +0,0 @@
-name: Miscellaneous checks
-on: [push, pull_request, merge_group]
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- checks:
- permissions:
- contents: write # for Git to git push
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
-
- - uses: ./.github/actions/setup/directories
- with:
- makeup: true
- # Skip overwriting MATZBOT_GITHUB_TOKEN
- checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
-
- - name: Check if C-sources are US-ASCII
- run: |
- grep -r -n --include='*.[chyS]' --include='*.asm' $'[^\t-~]' -- . && exit 1 || :
-
- - name: Check for trailing spaces
- run: |
- git grep -I -n $'[\t ]$' -- '*.rb' '*.[chy]' '*.rs' '*.yml' && exit 1 || :
- git grep -n $'^[\t ][\t ]*$' -- '*.md' && exit 1 || :
-
- - name: Check for bash specific substitution in configure.ac
- run: |
- git grep -n '\${[A-Za-z_0-9]*/' -- configure.ac && exit 1 || :
-
- - name: Check for header macros
- run: |
- fail=
- for header in ruby/*.h; do
- git grep -l -F -e $header -e HAVE_`echo $header | tr a-z./ A-Z__` -- . > /dev/null && continue
- fail=1
- echo $header
- done
- exit $fail
- working-directory: include
-
- - id: gems
- run: true
- if: ${{ github.ref == 'refs/heads/master' }}
-
- - name: Download previous gems list
- run: |
- data=default_gems.json
- mkdir -p .downloaded-cache
- ln -s .downloaded-cache/$data .
- curl -O -R -z ./$data https://stdgems.org/$data
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Make default gems list
- run: |
- #!ruby
- require 'rubygems'
- $:.unshift "lib"
- rgver = File.foreach("lib/rubygems.rb") do |line|
- break $1 if /^\s*VERSION\s*=\s*"([^"]+)"/ =~ line
- end
- gems = Dir.glob("{ext,lib}/**/*.gemspec").map do |f|
- spec = Gem::Specification.load(f)
- "#{spec.name} #{spec.version}"
- end.sort
- File.open("gems/default_gems", "w") do |f|
- f.puts "RubyGems #{rgver}"
- f.puts gems
- end
- shell: ruby --disable=gems {0}
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Maintain updated gems list in NEWS
- run: |
- ruby tool/update-NEWS-gemlist.rb default
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Check diffs
- id: diff
- run: |
- git diff --color --no-ext-diff --ignore-submodules --exit-code NEWS.md ||
- echo update=true >> $GITHUB_OUTPUT
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Commit
- run: |
- git pull --ff-only origin ${GITHUB_REF#refs/heads/}
- git commit --message="Update default gems list at ${GITHUB_SHA:0:30} [ci skip]" NEWS.md
- git push origin ${GITHUB_REF#refs/heads/}
- env:
- EMAIL: svn-admin@ruby-lang.org
- GIT_AUTHOR_NAME: git
- GIT_COMMITTER_NAME: git
- if: >-
- ${{
- github.repository == 'ruby/ruby' &&
- !startsWith(github.event_name, 'pull') &&
- steps.diff.outputs.update
- }}
-
- - uses: ./.github/actions/slack
- with:
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 4c6e9fd639..8dba76fbe2 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -1,21 +1,20 @@
-name: 'CodeQL'
+name: "Code scanning - action"
on:
- push:
- branches: ['master']
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
+ # push:
+ # paths-ignore:
+ # - 'doc/**'
+ # - '**/man'
+ # - '**.md'
+ # - '**.rdoc'
+ # - '**/.document'
+ # pull_request:
+ # paths-ignore:
+ # - 'doc/**'
+ # - '**/man'
+ # - '**.md'
+ # - '**.rdoc'
+ # - '**/.document'
schedule:
- cron: '0 12 * * *'
workflow_dispatch:
@@ -24,88 +23,53 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-permissions: # added using https://github.com/step-security/secure-workflows
+permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
+ CodeQL-Build:
+
+ # CodeQL runs on ubuntu-latest and windows-latest
permissions:
- actions: read # for github/codeql-action/init to get workflow details
- contents: read # for actions/checkout to fetch code
- security-events: write # for github/codeql-action/autobuild to send a status report
+ actions: read # for github/codeql-action/init to get workflow details
+ contents: read # for actions/checkout to fetch code
+ security-events: write # for github/codeql-action/autobuild to send a status report
+ runs-on: ubuntu-latest
# CodeQL fails to run pull requests from dependabot due to missing write access to upload results.
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') && github.event.head_commit.pusher.name != 'dependabot[bot]' }}
env:
enable_install_doc: no
- strategy:
- fail-fast: false
- matrix:
- language: ['cpp', 'ruby']
-
steps:
- - name: Checkout repository
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
- - name: Install libraries
- uses: ./.github/actions/setup/ubuntu
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
- - uses: ./.github/actions/setup/directories
+ - name: Checkout repository
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - name: Remove an obsolete rubygems vendored file
- run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache
- - name: Initialize CodeQL
- uses: github/codeql-action/init@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
- with:
- languages: ${{ matrix.language }}
+ - name: Remove an obsolete rubygems vendored file
+ run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
- - name: Autobuild
- uses: github/codeql-action/autobuild@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
+ with:
+ config-file: ./.github/codeql/codeql-config.yml
+ trap-caching: false
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
- with:
- category: '/language:${{ matrix.language }}'
- upload: False
- output: sarif-results
- ram: 8192
- # CodeQL randomly hits `OutOfMemoryError "Java heap space"`.
- # GitHub recommends running a larger runner to fix it, but we don't pay for it.
- continue-on-error: true
+ - name: Set ENV
+ run: echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
- - name: filter-sarif
- uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # v1.0
- with:
- patterns: |
- +**/*.rb
- -lib/uri/mailto.rb:rb/overly-large-range
- -lib/uri/rfc3986_parser.rb:rb/overly-large-range
- -lib/bundler/vendor/uri/lib/uri/mailto.rb:rb/overly-large-range
- -lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb:rb/overly-large-range
- -test/ruby/test_io.rb:rb/non-constant-kernel-open
- -test/open-uri/test_open-uri.rb:rb/non-constant-kernel-open
- -test/open-uri/test_ssl.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/binread_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/readlines_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/foreach_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/write_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/read_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/kernel/open_spec.rb:rb/non-constant-kernel-open
- input: sarif-results/${{ matrix.language }}.sarif
- output: sarif-results/${{ matrix.language }}.sarif
- if: ${{ matrix.language == 'ruby' }}
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
- - name: Upload SARIF
- uses: github/codeql-action/upload-sarif@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
- with:
- sarif_file: sarif-results/${{ matrix.language }}.sarif
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml
index 0262c70ef8..caf12cc0f4 100644
--- a/.github/workflows/compilers.yml
+++ b/.github/workflows/compilers.yml
@@ -12,14 +12,12 @@ on:
paths-ignore:
- 'doc/**'
- '**/man'
- - '**.md'
- '**.rdoc'
- '**/.document'
merge_group:
paths-ignore:
- 'doc/**'
- '**/man'
- - '**.md'
- '**.rdoc'
- '**/.document'
@@ -31,7 +29,7 @@ concurrency:
# environment variables (plus the "echo $GITHUB_ENV" hack) is to reroute that
# restriction.
env:
- default_cc: clang-17
+ default_cc: clang-15
append_cc: ''
# -O1 is faster than -O3 in our tests... Majority of time are consumed trying
@@ -52,8 +50,13 @@ env:
--without-jemalloc
--without-gmp
+ UPDATE_UNICODE: >-
+ UNICODE_FILES=.
+ UNICODE_PROPERTY_FILES=.
+ UNICODE_AUXILIARY_FILES=.
+ UNICODE_EMOJI_FILES=.
CONFIGURE_TTY: never
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
RUBY_DEBUG: ci rgengc
RUBY_TESTOPTS: >-
-q
@@ -71,7 +74,6 @@ jobs:
env:
- {}
entry:
- - { name: gcc-13, env: { default_cc: gcc-13 } }
- { name: gcc-12, env: { default_cc: gcc-12 } }
- { name: gcc-11, env: { default_cc: gcc-11 } }
- { name: gcc-10, env: { default_cc: gcc-10 } }
@@ -85,8 +87,6 @@ jobs:
optflags: '-O2'
shared: disable
# check: true
- - { name: clang-18, env: { default_cc: clang-18 } }
- - { name: clang-17, env: { default_cc: clang-17 } }
- { name: clang-16, env: { default_cc: clang-16 } }
- { name: clang-15, env: { default_cc: clang-15 } }
- { name: clang-14, env: { default_cc: clang-14 } }
@@ -107,8 +107,6 @@ jobs:
shared: disable
# check: true
- - { name: ext/Setup }
-
# - { name: aarch64-linux-gnu, crosshost: aarch64-linux-gnu, container: crossbuild-essential-arm64 }
# - { name: arm-linux-gnueabi, crosshost: arm-linux-gnueabi }
# - { name: arm-linux-gnueabihf, crosshost: arm-linux-gnueabihf }
@@ -124,17 +122,15 @@ jobs:
# warning generates a lot of noise from use of ANYARGS in
# rb_define_method() and friends.
# See: https://github.com/llvm/llvm-project/commit/11da1b53d8cd3507959022cd790d5a7ad4573d94
- - { name: c99, env: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
-# - { name: c11, env: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
-# - { name: c17, env: { CFLAGS: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { name: c23, env: { CFLAGS: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+ - { name: c99, env: { append_cc: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+# - { name: c11, env: { append_cc: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+# - { name: c17, env: { append_cc: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+ - { name: c2x, env: { append_cc: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- { name: c++98, env: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
# - { name: c++11, env: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
# - { name: c++14, env: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
# - { name: c++17, env: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
-# - { name: c++20, env: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
-# - { name: c++23, env: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { name: c++26, env: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
+ - { name: c++2a, env: { CXXFLAGS: '-std=c++2a -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- { name: '-O0', env: { optflags: '-O0 -march=x86-64 -mtune=generic' } }
# - { name: '-O3', env: { optflags: '-O3 -march=x86-64 -mtune=generic' }, check: true }
@@ -144,7 +140,7 @@ jobs:
- { name: valgrind, env: { append_configure: '--with-valgrind' } }
- { name: 'coroutine=ucontext', env: { append_configure: '--with-coroutine=ucontext' } }
- { name: 'coroutine=pthread', env: { append_configure: '--with-coroutine=pthread' } }
- - { name: disable-jit, env: { append_configure: '--disable-yjit --disable-rjit' } }
+ - { name: disable-jit-support, env: { append_configure: '--disable-jit-support' } }
- { name: disable-dln, env: { append_configure: '--disable-dln' } }
- { name: enable-mkmf-verbose, env: { append_configure: '--enable-mkmf-verbose' } }
- { name: disable-rubygems, env: { append_configure: '--disable-rubygems' } }
@@ -168,27 +164,31 @@ jobs:
# - { name: SYMBOL_DEBUG, env: { cppflags: '-DSYMBOL_DEBUG' } }
# - { name: RGENGC_CHECK_MODE, env: { cppflags: '-DRGENGC_CHECK_MODE' } }
+# - { name: TRANSIENT_HEAP_CHECK_MODE, env: { cppflags: '-DTRANSIENT_HEAP_CHECK_MODE' } }
# - { name: VM_CHECK_MODE, env: { cppflags: '-DVM_CHECK_MODE' } }
-# - { name: USE_EMBED_CI=0, env: { cppflags: '-DUSE_EMBED_CI=0' } }
- - name: USE_FLONUM=0
+ - { name: USE_EMBED_CI=0, env: { cppflags: '-DUSE_EMBED_CI=0' } }
+ - name: USE_FLONUM=0,
env:
cppflags: '-DUSE_FLONUM=0'
# yjit requires FLONUM for the pointer tagging scheme
append_configure: '--disable-yjit'
# - { name: USE_GC_MALLOC_OBJ_INFO_DETAILS, env: { cppflags: '-DUSE_GC_MALLOC_OBJ_INFO_DETAILS' } }
-# - { name: USE_LAZY_LOAD, env: { cppflags: '-DUSE_LAZY_LOAD' } }
+ - { name: USE_LAZY_LOAD, env: { cppflags: '-DUSE_LAZY_LOAD' } }
+# - { name: USE_RINCGC=0, env: { cppflags: '-DUSE_RINCGC=0' } }
# - { name: USE_SYMBOL_GC=0, env: { cppflags: '-DUSE_SYMBOL_GC=0' } }
# - { name: USE_THREAD_CACHE=0, env: { cppflags: '-DUSE_THREAD_CACHE=0' } }
- - { name: USE_RUBY_DEBUG_LOG=1, env: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' } }
+# - { name: USE_TRANSIENT_HEAP=0, env: { cppflags: '-DUSE_TRANSIENT_HEAP=0' } }
+# - { name: USE_RUBY_DEBUG_LOG=1, env: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' } }
+ - { name: USE_RVARGC=0, env: { cppflags: '-DUSE_RVARGC=0' } }
+# - { name: USE_RVARGC=1, env: { cppflags: '-DUSE_RVARGC=1' } }
# - { name: USE_DEBUG_COUNTER, env: { cppflags: '-DUSE_DEBUG_COUNTER=1', RUBY_DEBUG_COUNTER_DISABLE: '1' } }
- - { name: SHARABLE_MIDDLE_SUBSTRING, env: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' } }
-# - { name: DEBUG_FIND_TIME_NUMGUESS, env: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' } }
-# - { name: DEBUG_INTEGER_PACK, env: { cppflags: '-DDEBUG_INTEGER_PACK' } }
+ - { name: DEBUG_FIND_TIME_NUMGUESS, env: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' } }
+ - { name: DEBUG_INTEGER_PACK, env: { cppflags: '-DDEBUG_INTEGER_PACK' } }
# - { name: ENABLE_PATH_CHECK, env: { cppflags: '-DENABLE_PATH_CHECK' } }
-# - { name: GC_DEBUG_STRESS_TO_CLASS, env: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' } }
+ - { name: GC_DEBUG_STRESS_TO_CLASS, env: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' } }
# - { name: GC_ENABLE_LAZY_SWEEP=0, env: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' } }
# - { name: GC_PROFILE_DETAIL_MEMOTY, env: { cppflags: '-DGC_PROFILE_DETAIL_MEMOTY' } }
# - { name: GC_PROFILE_MORE_DETAIL, env: { cppflags: '-DGC_PROFILE_MORE_DETAIL' } }
@@ -201,50 +201,39 @@ jobs:
# - { name: RGENGC_ESTIMATE_OLDMALLOC, env: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' } }
# - { name: RGENGC_FORCE_MAJOR_GC, env: { cppflags: '-DRGENGC_FORCE_MAJOR_GC' } }
# - { name: RGENGC_OBJ_INFO, env: { cppflags: '-DRGENGC_OBJ_INFO' } }
+# - { name: RGENGC_OLD_NEWOBJ_CHECK, env: { cppflags: '-DRGENGC_OLD_NEWOBJ_CHECK' } }
# - { name: RGENGC_PROFILE, env: { cppflags: '-DRGENGC_PROFILE' } }
# - { name: VM_DEBUG_BP_CHECK, env: { cppflags: '-DVM_DEBUG_BP_CHECK' } }
# - { name: VM_DEBUG_VERIFY_METHOD_CACHE, env: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' } }
- - { name: enable-yjit, env: { append_configure: '--enable-yjit --disable-rjit' } }
- - { name: enable-rjit, env: { append_configure: '--enable-rjit --disable-yjit' } }
+ - { name: MJIT_FORCE_ENABLE, env: { cppflags: '-DMJIT_FORCE_ENABLE' } }
- { name: YJIT_FORCE_ENABLE, env: { cppflags: '-DYJIT_FORCE_ENABLE' } }
-# - { name: RJIT_FORCE_ENABLE, env: { cppflags: '-DRJIT_FORCE_ENABLE' } }
- - { name: UNIVERSAL_PARSER, env: { cppflags: '-DUNIVERSAL_PARSER' } }
name: ${{ matrix.entry.name }}
-
runs-on: ubuntu-latest
-
container:
- image: ghcr.io/ruby/ruby-ci-image:${{ matrix.entry.container || matrix.entry.env.default_cc || 'clang-17' }}
+ image: ghcr.io/ruby/ruby-ci-image:${{ matrix.entry.container || matrix.entry.env.default_cc || 'clang-15' }}
options: --user root
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
env: ${{ matrix.entry.env || matrix.env }}
-
steps:
- run: id
working-directory:
-
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - run: mkdir build
+ working-directory:
+ - name: setenv
+ run: |
+ echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- srcdir: src
- builddir: build
- makeup: true
-
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
run: >
../src/configure -C ${default_configure} ${append_configure}
@@ -254,39 +243,38 @@ jobs:
matrix.entry.crosshost || '"${default_cc}${append_cc:+ $append_cc}"'
}}
--${{ matrix.entry.shared || 'enable' }}-shared
-
- - name: Add to ext/Setup # statically link just the etc extension
- run: mkdir ext && echo etc >> ext/Setup
- if: ${{ matrix.entry.name == 'ext/Setup' }}
-
+ - run: make extract-extlibs
+ - run: make incs
- run: make showflags
-
- run: make
-
+ - run: make leaked-globals
- run: make test
-
- run: make install
if: ${{ matrix.entry.check }}
-
- run: make test-tool
if: ${{ matrix.entry.check }}
-
- run: make test-all TESTS='-- ruby -ext-'
if: ${{ matrix.entry.check }}
-
- run: make test-spec
env:
CHECK_LEAKS: true
if: ${{ matrix.entry.check }}
-
- run: make test-annocheck
if: ${{ matrix.entry.check && endsWith(matrix.entry.name, 'annocheck') }}
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.entry.name }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.entry.name }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml
deleted file mode 100644
index 6259199b11..0000000000
--- a/.github/workflows/dependabot_automerge.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-# from https://github.com/gofiber/swagger/blob/main/.github/workflows/dependabot_automerge.yml
-name: Dependabot auto-merge
-on:
- pull_request_target:
-
-jobs:
- automerge:
- runs-on: ubuntu-latest
-
- if: ${{ github.actor == 'dependabot[bot]' }}
-
- steps:
- - name: Dependabot metadata
- uses: dependabot/fetch-metadata@c9c4182bf1b97f5224aee3906fd373f6b61b4526 # v1.6.0
- id: metadata
-
- - name: Wait for status checks
- uses: lewagon/wait-on-check-action@e106e5c43e8ca1edea6383a39a01c5ca495fd812 # v1.3.1
- with:
- repo-token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
- ref: ${{ github.event.pull_request.head.sha || github.sha }}
- check-regexp: 'make \(check, .*\)'
- wait-interval: 30
-
- - name: Auto-merge for Dependabot PRs
- if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch' }}
- run: gh pr merge --auto --rebase "$PR_URL"
- env:
- PR_URL: ${{ github.event.pull_request.html_url }}
- GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 363ef8566e..d8dc58b119 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -8,8 +8,12 @@ on:
- '**.rdoc'
- '**/.document'
pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
merge_group:
paths-ignore:
- 'doc/**'
@@ -29,83 +33,80 @@ jobs:
make:
strategy:
matrix:
- test_task: ['check']
- configure: ['']
- os: ${{ fromJSON(format('["macos-11","macos-12"{0}]', (github.repository == 'ruby/ruby' && ',"macos-arm-oss"' || ''))) }}
+ test_task: ["check"] # "test-bundler-parallel", "test-bundled-gems"
+ os:
+ - macos-13
+ - macos-14
+ - macos-15
fail-fast: false
-
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
-
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
runs-on: ${{ matrix.os }}
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - run: mkdir build
+ working-directory:
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - name: Install libraries
- uses: ./.github/actions/setup/macos
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- srcdir: src
- builddir: build
- makeup: true
- dummy-files: ${{ matrix.test_task == 'check' }}
-
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Install libraries
+ run: |
+ brew install gmp libffi openssl@1.1 zlib autoconf automake libtool readline bison
+ working-directory: src
+ - name: Set ENV
+ run: |
+ echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> $GITHUB_ENV
+ echo "PATH="/usr/local/opt/bison/bin:/opt/homebrew/opt/bison/bin:$PATH"" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
- run: ../src/configure -C --disable-install-doc ${{ matrix.configure }}
-
+ run: ../src/configure -C --disable-install-doc --with-openssl-dir=$(brew --prefix openssl@1.1) --with-readline-dir=$(brew --prefix readline)
+ - run: make incs
- run: make prepare-gems
if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- run: make
-
+ - run: make leaked-globals
+ if: ${{ matrix.test_task == 'check' }}
- name: make ${{ matrix.test_task }}
run: |
make -s ${{ matrix.test_task }} ${TESTS:+TESTS=`echo "$TESTS" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|'`}
- timeout-minutes: 60
+ timeout-minutes: 40
env:
- RUBY_TESTOPTS: '-q --tty=no'
+ RUBY_TESTOPTS: "-q --tty=no"
TESTS: ${{ matrix.test_task == 'check' && matrix.skipped_tests || '' }}
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
- PRECHECK_BUNDLED_GEMS: 'no'
-
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ PRECHECK_BUNDLED_GEMS: "no"
- name: make skipped tests
run: |
make -s test-all TESTS=`echo "$TESTS" | sed 's| |$$/ -n/|g;s|^|-n/|;s|$|$$/|'`
env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
+ GNUMAKEFLAGS: ""
+ RUBY_TESTOPTS: "-v --tty=no"
TESTS: ${{ matrix.skipped_tests }}
- PRECHECK_BUNDLED_GEMS: 'no'
+ PRECHECK_BUNDLED_GEMS: "no"
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests != '' }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.os }} / ${{ matrix.test_task }} ${{ matrix.configure }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ matrix.os }} / ${{ matrix.test_task }}${{ matrix.configure }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: macos-latest
- needs: [make]
- steps:
- - run: exit 1
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index 5ddcb59e76..0df917d3d8 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -35,42 +35,50 @@ permissions:
jobs:
make:
runs-on: windows-2022
-
name: ${{ github.workflow }} (${{ matrix.msystem }})
-
env:
MSYSTEM: ${{ matrix.msystem }}
MSYS2_ARCH: x86_64
- CHOST: 'x86_64-w64-mingw32'
- CFLAGS: '-march=x86-64 -mtune=generic -O3 -pipe'
- CXXFLAGS: '-march=x86-64 -mtune=generic -O3 -pipe'
- CPPFLAGS: '-D_FORTIFY_SOURCE=2 -D__USE_MINGW_ANSI_STDIO=1 -DFD_SETSIZE=2048'
- LDFLAGS: '-pipe'
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
-
+ CHOST: "x86_64-w64-mingw32"
+ CFLAGS: "-march=x86-64 -mtune=generic -O3 -pipe"
+ CXXFLAGS: "-march=x86-64 -mtune=generic -O3 -pipe"
+ CPPFLAGS: "-D_FORTIFY_SOURCE=2 -D__USE_MINGW_ANSI_STDIO=1 -DFD_SETSIZE=2048"
+ LDFLAGS: "-pipe"
+ UPDATE_UNICODE: "UNICODE_FILES=. UNICODE_PROPERTY_FILES=. UNICODE_AUXILIARY_FILES=. UNICODE_EMOJI_FILES=."
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
strategy:
matrix:
include:
# To mitigate flakiness of MinGW CI, we test only one runtime that newer MSYS2 uses.
- - msystem: 'UCRT64'
+ - msystem: "UCRT64"
base_ruby: head
- test_task: 'check'
- test-all-opts: '--name=!/TestObjSpace#test_reachable_objects_during_iteration/'
+ test_task: "check"
+ test-all-opts: "--name=!/TestObjSpace#test_reachable_objects_during_iteration/"
fail-fast: false
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
+ - run: mkdir build
+ working-directory:
+ - name: git config
+ run: |
+ git config --global core.autocrlf false
+ git config --global core.eol lf
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
- name: Set up Ruby & MSYS2
- uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
ruby-version: ${{ matrix.base_ruby }}
+ - name: set env
+ run: |
+ echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV
- name: where check
run: |
@@ -78,57 +86,59 @@ jobs:
mv /c/Windows/System32/libcrypto-1_1-x64.dll /c/Windows/System32/libcrypto-1_1-x64.dll_
mv /c/Windows/System32/libssl-1_1-x64.dll /c/Windows/System32/libssl-1_1-x64.dll_
result=true
- for e in gcc.exe ragel.exe make.exe libcrypto-1_1-x64.dll libssl-1_1-x64.dll; do
- echo ::group::$'\033[93m'$e$'\033[m'
+ for e in gcc.exe ragel.exe make.exe bison.exe libcrypto-1_1-x64.dll libssl-1_1-x64.dll; do
+ echo '##['group']'$'\033[93m'$e$'\033[m'
where $e || result=false
- echo ::endgroup::
+ echo '##['endgroup']'
done
$result
- working-directory:
- name: version check
run: |
# show version
result=true
- for e in gcc ragel make "openssl version"; do
+ for e in gcc ragel make bison "openssl version"; do
case "$e" in *" "*) ;; *) e="$e --version";; esac
- echo ::group::$'\033[93m'$e$'\033[m'
+ echo '##['group']'$'\033[93m'$e$'\033[m'
$e || result=false
- echo ::endgroup::
+ echo '##['endgroup']'
done
$result
- working-directory:
-
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
+ - name: autogen
+ run: |
+ ./autogen.sh
+ working-directory: src
- name: configure
run: >
../src/configure --disable-install-doc --prefix=/.
--build=$CHOST --host=$CHOST --target=$CHOST
+ - name: update
+ run: |
+ make incs
+
+ - name: download gems
+ run: |
+ make update-gems
+
- name: make all
timeout-minutes: 30
- run: make
+ run: |
+ make
+
+ - run: make leaked-globals
- name: make install
- run: make DESTDIR=../install install-nodoc
+ run: |
+ make DESTDIR=../install install-nodoc
- name: test
- timeout-minutes: 30
- run: make test
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
- if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test' }}
+ timeout-minutes: 5
+ run: |
+ make test
+ if: ${{matrix.test_task == 'check' || matrix.test_task == 'test'}}
- name: test-all
timeout-minutes: 45
@@ -141,19 +151,27 @@ jobs:
--retry --job-status=normal --show-skip --timeout-scale=1.5
${{ matrix.test-all-opts }}
BUNDLER_VERSION:
- if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test-all' || StartsWith(matrix.test_task, 'test/') }}
+ if: ${{matrix.test_task == 'check' || matrix.test_task == 'test-all' || StartsWith(matrix.test_task, 'test/')}}
- name: test-spec
timeout-minutes: 10
run: |
make ${{ StartsWith(matrix.test_task, 'spec/') && matrix.test_task || 'test-spec' }}
- if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test-spec' || StartsWith(matrix.test_task, 'spec/') }}
+ if: ${{matrix.test_task == 'check' || matrix.test_task == 'test-spec' || StartsWith(matrix.test_task, 'spec/')}}
- - uses: ./src/.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.msystem }} / ${{ matrix.test_task }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} ${{ matrix.msystem }} / ${{ matrix.test_task }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/mjit-bindgen.yml b/.github/workflows/mjit-bindgen.yml
new file mode 100644
index 0000000000..26f8a1b2aa
--- /dev/null
+++ b/.github/workflows/mjit-bindgen.yml
@@ -0,0 +1,104 @@
+name: MJIT bindgen
+on:
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+
+concurrency:
+ group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
+ cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
+
+permissions:
+ contents: read
+
+jobs:
+ make:
+ strategy:
+ matrix:
+ include:
+ - task: mjit-bindgen
+ fail-fast: false
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
+ steps:
+ - run: mkdir build
+ working-directory:
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y \
+ build-essential \
+ libssl-dev libyaml-dev libreadline6-dev \
+ zlib1g-dev libncurses5-dev libffi-dev \
+ libclang1-14 \
+ bison autoconf
+ sudo apt-get install -q -y pkg-config || :
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
+ with:
+ ruby-version: '3.1'
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - run: ./autogen.sh
+ working-directory: src
+ - name: Run configure
+ run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install --enable-yjit=dev_nodebug
+ - run: make incs
+ - run: make
+ - run: make install
+ - run: make ${{ matrix.task }}
+ - run: git diff --exit-code
+ working-directory: src
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
+ with:
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ matrix.os }} / ${{ matrix.test_task }}${{ matrix.configure }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() && github.event_name == 'push' }}
+
+defaults:
+ run:
+ working-directory: build
diff --git a/.github/workflows/mjit.yml b/.github/workflows/mjit.yml
new file mode 100644
index 0000000000..6f7181489a
--- /dev/null
+++ b/.github/workflows/mjit.yml
@@ -0,0 +1,113 @@
+name: MJIT
+on:
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '**.[1-8]'
+ - '**.ronn'
+ merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '**.[1-8]'
+ - '**.ronn'
+
+concurrency:
+ group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
+ cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
+
+permissions:
+ contents: read
+
+jobs:
+ make:
+ strategy:
+ matrix:
+ test_task: [check] # to make job names consistent
+ mjit_opts: [--mjit-wait]
+ fail-fast: false
+ runs-on: ubuntu-latest
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
+ env:
+ TESTOPTS: '-q --tty=no'
+ RUN_OPTS: '--disable-gems ${{ matrix.mjit_opts }} --mjit-debug=-ggdb3'
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ steps:
+ - run: mkdir build
+ working-directory:
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
+ - name: Run configure
+ run: ../src/configure -C --disable-install-doc cppflags=-DVM_CHECK_MODE
+ - run: make incs
+ - run: make
+ - run: sudo make -s install
+ - name: Run test
+ run: |
+ unset GNUMAKEFLAGS
+ make -s test RUN_OPTS="$RUN_OPTS"
+ timeout-minutes: 60
+ # - name: Run test-all
+ # run: |
+ # ulimit -c unlimited
+ # make -s test-all RUN_OPTS="$RUN_OPTS"
+ # timeout-minutes: 60
+ - name: Run test-spec
+ run: |
+ unset GNUMAKEFLAGS
+ make -s test-spec RUN_OPTS="$RUN_OPTS"
+ timeout-minutes: 60
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
+ with:
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.test_task }} ${{ matrix.mjit_opts }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() && github.event_name == 'push' }}
+
+defaults:
+ run:
+ working-directory: build
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000000..5d4474d978
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,18 @@
+name: Start release workflow
+on:
+ push:
+ tags:
+ - '*'
+
+jobs:
+ notify:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Build release package
+ run: |
+ curl -L -X POST \
+ -H "Authorization: Bearer ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}" \
+ -H "Accept: application/vnd.github+json" \
+ -H "X-GitHub-Api-Version: 2022-11-28" \
+ https://api.github.com/repos/ruby/actions/dispatches \
+ -d '{"event_type": "${{ github.ref }}"}'
diff --git a/.github/workflows/rjit-bindgen.yml b/.github/workflows/rjit-bindgen.yml
deleted file mode 100644
index 8da2815b06..0000000000
--- a/.github/workflows/rjit-bindgen.yml
+++ /dev/null
@@ -1,88 +0,0 @@
-name: RJIT bindgen
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- make:
- strategy:
- matrix:
- include:
- - task: rjit-bindgen
- fail-fast: false
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
- steps:
- - name: Set up Ruby
- uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0
- with:
- ruby-version: '3.1'
-
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
-
- - name: Run configure
- run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install --enable-yjit=dev_nodebug
-
- - run: make
-
- - run: make install
-
- - run: make ${{ matrix.task }}
-
- - run: git diff --exit-code
- working-directory: src
-
- - uses: ./.github/actions/slack
- with:
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/rjit.yml b/.github/workflows/rjit.yml
deleted file mode 100644
index 53c29959eb..0000000000
--- a/.github/workflows/rjit.yml
+++ /dev/null
@@ -1,117 +0,0 @@
-name: RJIT
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- make:
- strategy:
- matrix:
- # main variables included in the job name
- test_task: [check]
- run_opts: ['--rjit-call-threshold=1']
- arch: ['']
- fail-fast: false
-
- env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUBY_DEBUG: ci
- SETARCH: ${{ matrix.arch && format('setarch {0}', matrix.arch) }}
-
- runs-on: ubuntu-22.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
-
- - name: Run configure
- env:
- arch: ${{ matrix.arch }}
- run: >-
- $SETARCH ../src/configure -C --disable-install-doc cppflags=-DRUBY_DEBUG
- ${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
-
- - run: $SETARCH make
-
- - name: make test
- run: |
- $SETARCH make -s test RUN_OPTS="$RUN_OPTS"
- timeout-minutes: 30
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
- RUN_OPTS: ${{ matrix.run_opts }}
-
- - name: make test-all
- run: |
- $SETARCH make -s test-all RUN_OPTS="$RUN_OPTS"
- timeout-minutes: 40
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-q --tty=no'
- RUN_OPTS: ${{ matrix.run_opts }}
-
- - name: make test-spec
- run: |
- $SETARCH make -s test-spec RUN_OPTS="$RUN_OPTS"
- timeout-minutes: 10
- env:
- GNUMAKEFLAGS: ''
- RUN_OPTS: ${{ matrix.run_opts }}
-
- - uses: ./.github/actions/slack
- with:
- label: ${{ matrix.run_opts }}
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 51ce54a518..c12a95362d 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -11,8 +11,8 @@ on:
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '22 4 * * 2'
- # push:
- # branches: [ "master" ]
+ push:
+ branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
@@ -31,13 +31,13 @@ jobs:
# actions: read
steps:
- - name: 'Checkout code'
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: "Checkout code"
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- - name: 'Run analysis'
- uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@ea651e62978af7915d09fe2e282747c798bf2dab # v2.4.1
with:
results_file: results.sarif
results_format: sarif
@@ -58,15 +58,15 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- # - name: "Upload artifact"
- # uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
- # with:
- # name: SARIF file
- # path: results.sarif
- # retention-days: 5
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- - name: 'Upload to code-scanning'
- uses: github/codeql-action/upload-sarif@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.1.27
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.27
with:
sarif_file: results.sarif
diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml
index e14e7818a6..4521195a2b 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -6,13 +6,10 @@ on:
- 'spec/**'
- '!spec/*.md'
pull_request:
- paths-ignore:
+ paths:
- 'spec/**'
- '!spec/*.md'
merge_group:
- paths-ignore:
- - 'spec/**'
- - '!spec/*.md'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -25,13 +22,15 @@ jobs:
rubyspec:
name: Rubyspec
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
+ || contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
+ || contains(github.event.pull_request.title, 'Document')
+ || contains(github.event.pull_request.labels.*.name, 'Document')
|| (github.event_name == 'push' && github.actor == 'dependabot[bot]')
)}}
@@ -40,14 +39,13 @@ jobs:
# Specs from ruby/spec should still run on all supported Ruby versions.
# This also ensures the needed ruby_version_is guards are there, see spec/README.md.
ruby:
- - ruby-3.0
- ruby-3.1
- ruby-3.2
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
@@ -58,9 +56,16 @@ jobs:
working-directory: spec/ruby
env:
CHECK_LEAKS: true
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.ruby }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / rubyspec @ ${{ matrix.ruby }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
if: ${{ failure() }}
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index fa9eb9fef6..4fbca1170e 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -8,8 +8,12 @@ on:
- '**.rdoc'
- '**/.document'
pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
merge_group:
paths-ignore:
- 'doc/**'
@@ -29,104 +33,113 @@ jobs:
make:
strategy:
matrix:
+ # main variables included in the job name
test_task: [check]
+ configure: [cppflags=-DRUBY_DEBUG] # default to use more assertions
arch: ['']
- configure: ['cppflags=-DVM_CHECK_MODE']
- # specifying other jobs with `include` to avoid redundant tests
+ # specify all jobs with `include` to avoid testing duplicated things
include:
- test_task: check
- arch: i686
- test_task: check
- configure: '--disable-yjit'
+ arch: i686
+ configure: '' # test without -DRUBY_DEBUG as well
- test_task: check
- configure: '--enable-shared --enable-load-relative'
+ configure: "--enable-shared --enable-load-relative"
- test_task: test-all TESTS=--repeat-count=2
- - test_task: test-all
- configure: 'cppflags=-DUNIVERSAL_PARSER'
- test_task: test-bundler-parallel
- test_task: test-bundled-gems
fail-fast: false
-
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
RUBY_DEBUG: ci
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ SETARCH: ${{ matrix.arch && format('setarch {0}', matrix.arch) }}
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
+ - run: mkdir build
+ working-directory:
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: Install libraries
+ env:
+ arch: ${{matrix.arch}}
+ run: |
+ set -x
+ arch=${arch:+:${arch/i[3-6]86/i386}}
+ ${arch:+sudo dpkg --add-architecture ${arch#:}}
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y \
+ ${arch:+cross}build-essential${arch/:/-} \
+ libssl-dev${arch} libyaml-dev${arch} libreadline6-dev${arch} \
+ zlib1g-dev${arch} libncurses5-dev${arch} libffi-dev${arch} \
+ bison autoconf ruby
+ sudo apt-get install -q -y pkg-config${arch} || :
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- arch: ${{ matrix.arch }}
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- srcdir: src
- builddir: build
- makeup: true
- dummy-files: ${{ matrix.test_task == 'check' }}
-
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
env:
- arch: ${{ matrix.arch }}
- configure: ${{ matrix.configure }}
+ arch: ${{matrix.arch}}
run: >-
- $SETARCH ../src/configure -C --disable-install-doc ${configure:-cppflags=-DRUBY_DEBUG}
+ $SETARCH ../src/configure -C --disable-install-doc ${{ matrix.configure }}
${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
-
+ - run: $SETARCH make incs
- run: $SETARCH make prepare-gems
if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- run: $SETARCH make
-
+ - run: $SETARCH make leaked-globals
+ if: ${{ matrix.test_task == 'check' }}
+ - name: Create dummy files in build dir
+ run: |
+ $SETARCH ./miniruby -e '(("a".."z").to_a+("A".."Z").to_a+("0".."9").to_a+%w[foo bar test zzz]).each{|basename|File.write("#{basename}.rb", "raise %(do not load #{basename}.rb)")}'
+ if: ${{ matrix.test_task == 'check' }}
- name: make ${{ matrix.test_task }}
- run: >-
- $SETARCH make -s ${{ matrix.test_task }}
- ${TESTS:+TESTS=`echo "$TESTS" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|'`}
- ${{ !contains(matrix.test_task, 'bundle') && 'RUBYOPT=-w' || '' }}
+ run: |
+ $SETARCH make -s ${{ matrix.test_task }} ${TESTS:+TESTS=`echo "$TESTS" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|'`}
timeout-minutes: 40
env:
- RUBY_TESTOPTS: '-q --tty=no'
+ RUBY_TESTOPTS: "-q --tty=no"
TESTS: ${{ matrix.test_task == 'check' && matrix.skipped_tests || '' }}
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
- PRECHECK_BUNDLED_GEMS: 'no'
-
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ PRECHECK_BUNDLED_GEMS: "no"
- name: make skipped tests
run: |
$SETARCH make -s test-all TESTS=`echo "$TESTS" | sed 's| |$$/ -n/|g;s|^|-n/|;s|$|$$/|'`
env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
+ GNUMAKEFLAGS: ""
+ RUBY_TESTOPTS: "-v --tty=no"
TESTS: ${{ matrix.skipped_tests }}
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests != '' }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: ubuntu-latest
- needs: [make]
- steps:
- - run: exit 1
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml
index 9f8f292b8b..27920b5821 100644
--- a/.github/workflows/wasm.yml
+++ b/.github/workflows/wasm.yml
@@ -26,7 +26,7 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-permissions: # added using https://github.com/step-security/secure-workflows
+permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
@@ -35,50 +35,38 @@ jobs:
matrix:
entry:
# # wasmtime can't compile non-optimized Asyncified binary due to locals explosion
-# - { name: O0-debuginfo, optflags: '-O0', debugflags: '-g', wasmoptflags: '-O1' }
-# - { name: O1, optflags: '-O1', debugflags: '' , wasmoptflags: '-O1' }
- - { name: O2, optflags: '-O2', debugflags: '', wasmoptflags: '-O2' }
-# - { name: O3, optflags: '-O3', debugflags: '' , wasmoptflags: '-O3' }
+# - { name: O0-debuginfo, optflags: "-O0", debugflags: "-g", wasmoptflags: "-O1" }
+# - { name: O1, optflags: "-O1", debugflags: "" , wasmoptflags: "-O1" }
+ - { name: O2, optflags: "-O2", debugflags: "" , wasmoptflags: "-O2" }
+# - { name: O3, optflags: "-O3", debugflags: "" , wasmoptflags: "-O3" }
# # -O4 is equivalent to -O3 in clang, but it's different in wasm-opt
-# - { name: O4, optflags: '-O3', debugflags: '' , wasmoptflags: '-O4' }
-# - { name: Oz, optflags: '-Oz', debugflags: '' , wasmoptflags: '-Oz' }
+# - { name: O4, optflags: "-O3", debugflags: "" , wasmoptflags: "-O4" }
+# - { name: Oz, optflags: "-Oz", debugflags: "" , wasmoptflags: "-Oz" }
fail-fast: false
-
env:
RUBY_TESTOPTS: '-q --tty=no'
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
WASI_SDK_VERSION_MAJOR: 14
WASI_SDK_VERSION_MINOR: 0
BINARYEN_VERSION: 109
WASMTIME_VERSION: v0.33.0
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
+ - run: mkdir build
+ working-directory:
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- srcdir: src
- builddir: build
- makeup: true
-
+ path: src
- name: Install libraries
run: |
set -ex
sudo apt-get update -q || :
- sudo apt-get install --no-install-recommends -q -y ruby make autoconf git wget
+ sudo apt-get install --no-install-recommends -q -y ruby bison make autoconf git wget
wasi_sdk_deb="wasi-sdk_${WASI_SDK_VERSION_MAJOR}.${WASI_SDK_VERSION_MINOR}_amd64.deb"
wget "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION_MAJOR}/${wasi_sdk_deb}"
@@ -97,17 +85,29 @@ jobs:
wget -O - "$binaryen_url" | tar xfz -
sudo ln -fs "$PWD/binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt" /usr/local/bin/wasm-opt
working-directory: src
-
- name: Set ENV
run: |
+ echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> $GITHUB_ENV
echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
+
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
+ with:
+ ruby-version: '3.0'
+ bundler: none
+
+ - name: Download config.guess with wasi version
+ run: |
+ rm tool/config.guess tool/config.sub
+ ruby tool/downloader.rb -d tool -e gnu config.guess config.sub
+ working-directory: src
- name: Run configure
run: |
../src/configure \
--host wasm32-unknown-wasi \
--with-static-linked-ext \
- --with-ext=bigdecimal,ripper,monitor,stringio,pathname \
LDFLAGS=" \
-Xlinker --stack-first \
-Xlinker -z -Xlinker stack-size=16777216 \
@@ -118,22 +118,28 @@ jobs:
# miniruby may not be built when cross-compling
- run: make mini ruby
-
- name: Run basictest
run: wasmtime run ./../build/miniruby --mapdir /::./ -- basictest/test.rb
working-directory: src
-
- name: Run bootstraptest (no thread)
run: |
NO_THREAD_TESTS="$(grep -L Thread -R ./bootstraptest | awk -F/ '{ print $NF }' | uniq | sed -n 's/test_\(.*\).rb/\1/p' | paste -s -d, -)"
ruby ./bootstraptest/runner.rb --ruby="$(which wasmtime) run $PWD/../build/ruby --mapdir /::./ -- " --verbose "--sets=$NO_THREAD_TESTS"
working-directory: src
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.entry.name }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.name }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 982f855345..c2bd4881c2 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -34,163 +34,114 @@ jobs:
strategy:
matrix:
include:
- - vs: 2019
- vs: 2022
+ vcvers: -vcvars_ver=14.2
fail-fast: false
-
- runs-on: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ runs-on: windows-${{ matrix.vs }}
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
name: VisualStudio ${{ matrix.vs }}
-
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- OS_VER: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
- # FIXME: This is a workaround for the vcpkg's issue present as of openssl 3.1.1
- # where OpenSSL's default modules directory is incorrectly set to C:\vcpkg\packages\openssl_x64-windows\bin
- # cf. https://github.com/ruby/openssl/pull/635#issuecomment-1596833720
- OPENSSL_MODULES: C:\vcpkg\installed\x64-windows\bin
-
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ PATCH: C:\msys64\usr\bin\patch.exe
+ OS_VER: windows-${{ matrix.vs }}
steps:
- run: md build
working-directory:
-
- - name: find tools
- id: find-tools
- run: |
- ::- find needed tools
- set NEEDS=
- for %%I in (%NEEDED_TOOLS%) do if "%%~$PATH:I" == "" (
- call set NEEDS=%%NEEDS%% %%~nI
- ) else (
- echo %%I: %%~$PATH:I
- )
- echo.needs=%NEEDS%>>%GITHUB_OUTPUT%
- if "%NEEDS%" == "" (
- echo [debug] All needed tools found
- ) else (
- echo [warning^]Needs%NEEDS%
- )
- env:
- NEEDED_TOOLS: >-
- patch.exe
-
- - uses: msys2/setup-msys2@d40200dc2db4c351366b048a9565ad82919e1c24 # v2
+ - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # v2.27.0
id: setup-msys2
with:
update: true
- install: >-
- ${{ steps.find-tools.outputs.needs }}
- if: ${{ steps.find-tools.outputs.needs != '' }}
-
- - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- with:
- path: C:\vcpkg\downloads
- key: ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}-${{ github.sha }}
- restore-keys: |
- ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}-
- ${{ runner.os }}-vcpkg-download-
-
- - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
+ install: bison patch
+ - name: patch path
+ shell: msys2 {0}
+ run: echo PATCH=$(cygpath -wa $(command -v patch)) >> $GITHUB_ENV
+ if: ${{ steps.setup-msys2.outcome == 'success' }}
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: C:\vcpkg\installed
- key: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-${{ github.sha }}
+ key: ${{ runner.os }}-vcpkg-installed-windows-${{ matrix.vs }}-${{ github.sha }}
restore-keys: |
- ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-
- ${{ runner.os }}-vcpkg-installed-
-
+ ${{ runner.os }}-vcpkg-installed-windows-${{ matrix.vs }}-
+ ${{ runner.os }}-vcpkg-installed-windows-
- name: Install libraries with vcpkg
run: |
- vcpkg --triplet x64-windows install libffi libyaml openssl readline zlib
-
- - name: Install libraries with scoop
- run: |
iex "& {$(irm get.scoop.sh)} -RunAsAdmin"
Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
- shell: pwsh
-
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ scoop install cmake@3.31.6
+ vcpkg --triplet x64-windows install libffi libyaml openssl readline zlib
+ shell:
+ pwsh
+ - name: git config
+ run: |
+ git config --global core.autocrlf false
+ git config --global core.eol lf
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- srcdir: src
- builddir: build
-
+ path: src/.downloaded-cache
+ key: downloaded-cache
- name: setup env
# %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
# https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
+ # msys2/setup-msys2 installs MSYS2 to D:/a/_temp/msys64/usr/bin
run: |
- set VS=${{ matrix.vs }}
- set VCVARS=${{ matrix.vcvars || '' }}
+ set Path=D:/a/_temp/msys64/usr/bin;%Path%
if not "%VCVARS%" == "" goto :vcset
- set VCVARS="C:\Program Files (x86)\Microsoft Visual Studio\%VS%\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
- if not exist %VCVARS% set VCVARS="C:\Program Files\Microsoft Visual Studio\%VS%\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ set VCVARS="C:\Program Files (x86)\Microsoft Visual Studio\${{ matrix.vs }}\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ if not exist %VCVARS% set VCVARS="C:\Program Files\Microsoft Visual Studio\${{ matrix.vs }}\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
:vcset
set | C:\msys64\usr\bin\sort > old.env
- call %VCVARS%
- nmake -f nul
+ call %VCVARS% ${{ matrix.vcvers || ''}}
set TMP=%USERPROFILE%\AppData\Local\Temp
set TEMP=%USERPROFILE%\AppData\Local\Temp
- set MAKEFLAGS=l
set /a TEST_JOBS=(15 * %NUMBER_OF_PROCESSORS% / 10) > nul
set | C:\msys64\usr\bin\sort > new.env
C:\msys64\usr\bin\comm -13 old.env new.env >> %GITHUB_ENV%
del *.env
-
- name: compiler version
run: cl
-
- name: link libraries
run: |
for %%I in (C:\vcpkg\installed\x64-windows\bin\*.dll) do (
if not %%~nI == readline mklink %%~nxI %%I
)
- # We use OpenSSL instealled by vcpkg instead
- - name: disable system OpenSSL
- run: |
for %%I in (libcrypto-1_1-x64 libssl-1_1-x64) do (
ren c:\Windows\System32\%%I.dll %%I.dll_
)
- # windows-2019 image doesn't have OpenSSL as of 2023/9/14
- if: ${{ matrix.vs != 2019 }}
-
- name: Configure
run: >-
../src/win32/configure.bat --disable-install-doc
--with-opt-dir=C:/vcpkg/installed/x64-windows
-
- run: nmake incs
-
- run: nmake extract-extlibs
-
- run: nmake
-
+ env:
+ YACC: bison.exe
- run: nmake test
timeout-minutes: 5
-
- run: nmake test-spec
timeout-minutes: 10
-
- run: nmake test-all
env:
- RUBY_TESTOPTS: -j${{ env.TEST_JOBS || 4 }} --job-status=normal
+ RUBY_TESTOPTS: -j${{env.TEST_JOBS}} --job-status=normal
timeout-minutes: 60
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: VS${{ matrix.vs }} / ${{ matrix.test_task || 'check' }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "VS${{ matrix.vs }} / ${{ matrix.test_task || 'check' }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml
deleted file mode 100644
index c8f21cfa7e..0000000000
--- a/.github/workflows/yjit-macos.yml
+++ /dev/null
@@ -1,149 +0,0 @@
-name: YJIT macOS Arm64
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- cargo:
- name: cargo test
-
- runs-on: macos-arm-oss
-
- if: >-
- ${{github.repository == 'ruby/ruby' &&
- !(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
- - run: RUST_BACKTRACE=1 cargo test
- working-directory: yjit
-
- # Also compile and test with all features enabled
- - run: RUST_BACKTRACE=1 cargo test --all-features
- working-directory: yjit
-
- # Check that we can build in release mode too
- - run: cargo build --release
- working-directory: yjit
-
- make:
- strategy:
- matrix:
- include:
- - test_task: 'check'
- configure: '--enable-yjit'
- yjit_opts: '--yjit'
- - test_task: 'check'
- configure: '--enable-yjit=dev'
- yjit_opts: '--yjit-call-threshold=1 --yjit-verify-ctx --yjit-code-gc'
- fail-fast: false
-
- env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUN_OPTS: ${{ matrix.yjit_opts }}
-
- runs-on: macos-arm-oss
-
- if: >-
- ${{github.repository == 'ruby/ruby' &&
- !(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - name: Install libraries
- uses: ./.github/actions/setup/macos
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
- dummy-files: ${{ matrix.test_task == 'check' }}
-
- - name: Run configure
- run: ../src/configure -C --disable-install-doc ${{ matrix.configure }}
-
- - run: make prepare-gems
- if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- - run: make
-
- - name: Enable YJIT through ENV
- run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
-
- - name: make ${{ matrix.test_task }}
- run: |
- make -s ${{ matrix.test_task }} ${TESTS:+TESTS=`echo "$TESTS" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|'`}
- timeout-minutes: 60
- env:
- RUBY_TESTOPTS: '-q --tty=no'
- TESTS: ${{ matrix.test_task == 'check' && matrix.skipped_tests || '' }}
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
- PRECHECK_BUNDLED_GEMS: 'no'
-
- - name: make skipped tests
- run: |
- make -s test-all TESTS=`echo "$TESTS" | sed 's| |$$/ -n/|g;s|^|-n/|;s|$|$$/|'`
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
- TESTS: ${{ matrix.skipped_tests }}
- PRECHECK_BUNDLED_GEMS: 'no'
- if: ${{ matrix.test_task == 'check' && matrix.skipped_tests != '' }}
- continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
-
- - uses: ./.github/actions/slack
- with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }} ${{ matrix.yjit_opts }}
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() && github.repository == 'ruby/ruby' }}
- name: ${{ github.workflow }} result
- runs-on: macos-arm-oss
- needs: [make]
- steps:
- - run: exit 1
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml
index d29aaccdfb..0b7b9046e9 100644
--- a/.github/workflows/yjit-ubuntu.yml
+++ b/.github/workflows/yjit-ubuntu.yml
@@ -8,8 +8,12 @@ on:
- '**.rdoc'
- '**/.document'
pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
merge_group:
paths-ignore:
- 'doc/**'
@@ -27,58 +31,22 @@ permissions:
jobs:
cargo:
- name: cargo test
-
+ name: Rust cargo test
# GitHub Action's image seems to already contain a Rust 1.58.0.
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# For now we can't run cargo test --offline because it complains about the
# capstone dependency, even though the dependency is optional
#- run: cargo test --offline
-
- run: RUST_BACKTRACE=1 cargo test
working-directory: yjit
-
# Also compile and test with all features enabled
- run: RUST_BACKTRACE=1 cargo test --all-features
working-directory: yjit
-
# Check that we can build in release mode too
- run: cargo build --release
working-directory: yjit
-
- lint:
- name: cargo clippy
-
- # GitHub Action's image seems to already contain a Rust 1.58.0.
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
- # Check that we don't have linting errors in release mode, too
- - run: cargo clippy --all-targets --all-features
- working-directory: yjit
-
make:
strategy:
fail-fast: false
@@ -86,114 +54,116 @@ jobs:
include:
- test_task: 'yjit-bindgen'
hint: 'To fix: use patch in logs'
- configure: '--with-gcc=clang-12 --enable-yjit=dev'
+ configure: '--with-gcc=clang-14 --enable-yjit=dev'
+ libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1'
- - test_task: 'check'
+ - test_task: "check"
# YJIT should be automatically built in release mode on x86-64 Linux with rustc present
#configure: "--enable-yjit RUSTC='rustc +1.58.0'"
configure: "RUSTC='rustc +1.58.0'"
- rust_version: '1.58.0'
+ rust_version: "1.58.0"
- - test_task: 'check'
- configure: '--enable-yjit=dev'
+ - test_task: "check"
+ configure: "--enable-yjit=dev"
- - test_task: 'check'
- configure: '--enable-yjit=dev'
- yjit_opts: '--yjit-call-threshold=1 --yjit-verify-ctx --yjit-code-gc'
+ - test_task: "check"
+ configure: "--enable-yjit=dev"
+ yjit_opts: "--yjit-call-threshold=1 --yjit-verify-ctx"
- - test_task: 'test-bundled-gems'
- configure: '--enable-yjit=dev'
+ - test_task: "test-all TESTS=--repeat-count=2"
+ configure: "--enable-yjit=dev"
- - test_task: 'yjit-bench'
- configure: '--enable-yjit=dev'
- yjit_bench_opts: '--yjit-stats'
+ - test_task: "test-bundled-gems"
+ configure: "--enable-yjit=dev"
+ - test_task: "yjit-bench"
+ configure: "--enable-yjit=dev"
+ yjit_bench_opts: "--yjit-stats"
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
RUN_OPTS: ${{ matrix.yjit_opts }}
YJIT_BENCH_OPTS: ${{ matrix.yjit_bench_opts }}
RUBY_DEBUG: ci
BUNDLE_JOBS: 8 # for yjit-bench
- RUST_BACKTRACE: 1
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Documentation')
- || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
- )}}
-
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
- dummy-files: ${{ matrix.test_task == 'check' }}
-
+ - run: mkdir build
+ working-directory:
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
- name: Install Rust
if: ${{ matrix.rust_version }}
run: rustup install ${{ matrix.rust_version }} --profile minimal
-
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install ${{ matrix.configure }}
-
- run: make incs
-
- run: make prepare-gems
if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- - run: make
-
+ - run: make -j
+ - run: make leaked-globals
+ if: ${{ matrix.test_task == 'check' }}
+ - name: Create dummy files in build dir
+ run: |
+ ./miniruby -e '(("a".."z").to_a+("A".."Z").to_a+("0".."9").to_a+%w[foo bar test zzz]).each{|basename|File.write("#{basename}.rb", "raise %(do not load #{basename}.rb)")}'
+ if: ${{ matrix.test_task == 'check' }}
- name: Enable YJIT through ENV
run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
-
# Check that the binary was built with YJIT
- name: Check YJIT enabled
run: ./miniruby --yjit -v | grep "+YJIT"
-
- name: make ${{ matrix.test_task }}
- run: make -s -j ${{ matrix.test_task }} RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug YJIT_BENCH_OPTS="$YJIT_BENCH_OPTS" YJIT_BINDGEN_DIFF_OPTS="$YJIT_BINDGEN_DIFF_OPTS"
+ run: make -s -j ${{ matrix.test_task }} RUN_OPTS="$RUN_OPTS" YJIT_BENCH_OPTS="$YJIT_BENCH_OPTS"
timeout-minutes: 60
env:
- RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'rbs'
- PRECHECK_BUNDLED_GEMS: 'no'
- SYNTAX_SUGGEST_TIMEOUT: '5'
- YJIT_BINDGEN_DIFF_OPTS: '--exit-code'
+ RUBY_TESTOPTS: "-q --tty=no"
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ PRECHECK_BUNDLED_GEMS: "no"
+ LIBCLANG_PATH: ${{ matrix.libclang_path }}
continue-on-error: ${{ matrix.test_task == 'yjit-bench' }}
-
- name: Show ${{ github.event.pull_request.base.ref }} GitHub URL for yjit-bench comparison
run: echo "https://github.com/${BASE_REPO}/commit/${BASE_SHA}"
env:
BASE_REPO: ${{ github.event.pull_request.base.repo.full_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
if: ${{ matrix.test_task == 'yjit-bench' && startsWith(github.event_name, 'pull') }}
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.test_task }} ${{ matrix.configure }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: ubuntu-latest
- needs: [make]
- steps:
- - run: exit 1
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.gitignore b/.gitignore
index f30842adb5..99d32a1825 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,7 +50,6 @@ y.tab.c
*.gcno
*.gcov
*.vscode
-!misc/.vscode
lcov*.info
# /
@@ -124,7 +123,6 @@ lcov*.info
/repack
/revision.h
/revision.tmp
-/ripper.tmp.y
/riscos
/rubicon
/ruby
@@ -205,10 +203,8 @@ lcov*.info
# /ext/ripper/
/ext/ripper/eventids1.c
-/ext/ripper/eventids1.h
/ext/ripper/.eventids2-check
/ext/ripper/eventids2table.c
-/ext/ripper/ripper_init.c
/ext/ripper/ripper.*
/ext/ripper/ids1
/ext/ripper/ids2
@@ -230,9 +226,8 @@ lcov*.info
# /misc/
/misc/**/__pycache__
-# for `make test-bundler`
+# /spec/bundler
/.rspec_status
-/tool/bundler/*.lock
# /tool/
/tool/config.guess
@@ -241,12 +236,11 @@ lcov*.info
# /win32/
/win32/*.ico
-# RJIT
-/include/ruby-*/*/rb_rjit_min_header-*.h
-/lib/ruby_vm/rjit/instruction.rb
-/lib/ruby_vm/rjit/instruction.rb
-/rjit_config.h
-/rb_rjit_header.h*
+# MJIT
+/include/ruby-*/*/rb_mjit_min_header-*.h
+/lib/ruby_vm/mjit/instruction.rb
+/mjit_config.h
+/rb_mjit_header.h
# YJIT
/yjit-bench
@@ -254,23 +248,3 @@ lcov*.info
# /wasm/
/wasm/tests/*.wasm
-
-# prism
-/lib/prism/compiler.rb
-/lib/prism/dispatcher.rb
-/lib/prism/dsl.rb
-/lib/prism/mutation_compiler.rb
-/lib/prism/node.rb
-/lib/prism/serialize.rb
-/lib/prism/visitor.rb
-/prism/api_node.c
-/prism/ast.h
-/prism/node.c
-/prism/prettyprint.c
-/prism/serialize.c
-/prism/token_type.c
-
-# tool/update-NEWS-gemlist.rb
-/bundled_gems.json
-/default_gems.json
-/gems/default_gems
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 6d942d1425..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-# -*- YAML -*-
-# Copyright (C) 2011 Urabe, Shyouhei. All rights reserved.
-#
-# This file is a part of the programming language Ruby. Permission is hereby
-# granted, to either redistribute or modify this file, provided that the
-# conditions mentioned in the file COPYING are met. Consult the file for
-# details.
-
-# When you see Travis CI issues, or you are interested in understanding how to
-# manage, please check the link below.
-# https://github.com/ruby/ruby/wiki/CI-Servers#travis-ci
-
-# We enable Travis on the specific branches or forked repositories here.
-if: (repo = ruby/ruby AND (branch = master OR branch =~ /^ruby_\d_\d$/)) OR repo != ruby/ruby OR commit_message !~ /\[DOC\]/
-
-language: c
-
-os: linux
-
-dist: jammy
-
-git:
- quiet: true
-
-env:
- global:
- - NPROC="$(nproc)"
- - JOBS="-j${NPROC}"
- # SETARCH are overridden when necessary. See below.
- - SETARCH=
- # https://github.com/travis-ci/travis-build/blob/e411371dda21430a60f61b8f3f57943d2fe4d344/lib/travis/build/bash/travis_apt_get_options.bash#L7
- - travis_apt_get_options='--allow-downgrades --allow-remove-essential --allow-change-held-packages'
- - travis_apt_get_options="-yq --no-install-suggests --no-install-recommends $travis_apt_get_options"
- # -g0 disables backtraces when SEGV. Do not set that.
- - debugflags=-ggdb3
- - RUBY_TESTOPTS="$JOBS -q --tty=no"
-
-.org.ruby-lang.ci.matrix-definitions:
- - &gcc-11
- compiler: gcc-11
- before_install:
- - tool/travis_retry.sh sudo bash -c "rm -rf '${TRAVIS_ROOT}/var/lib/apt/lists/'* && exec apt-get update -yq"
- - >-
- tool/travis_retry.sh sudo -E apt-get $travis_apt_get_options install
- gcc-11
- g++-11
- libffi-dev
- libncurses-dev
- libncursesw5-dev
- libreadline-dev
- libssl-dev
- libyaml-dev
- openssl
- zlib1g-dev
- - gcc-11 --version
- - &arm64-linux
- name: arm64-linux
- arch: arm64
- <<: *gcc-11
- - &ppc64le-linux
- name: ppc64le-linux
- arch: ppc64le
- <<: *gcc-11
- - &s390x-linux
- name: s390x-linux
- arch: s390x
- <<: *gcc-11
- env:
- # Avoid possible test failures with the zlib applying the following patch
- # on s390x CPU architecture.
- # https://github.com/madler/zlib/pull/410
- - DFLTCC=0
- - &arm32-linux
- name: arm32-linux
- arch: arm64
- # https://packages.ubuntu.com/jammy/crossbuild-essential-armhf
- compiler: arm-linux-gnueabihf-gcc
- env:
- - SETARCH='setarch linux32 --verbose --32bit'
- # Still keep the -O1 for only arm32, while we want to test with the
- # default optflags -O3.
- # Because bootstraptest/test_ractor.rb fails with segfualt with the
- # default -O3.
- # https://bugs.ruby-lang.org/issues/19981
- - optflags=-O1
- before_install:
- - sudo dpkg --add-architecture armhf
- - tool/travis_retry.sh sudo bash -c "rm -rf '${TRAVIS_ROOT}/var/lib/apt/lists/'* && exec apt-get update -yq"
- - >-
- tool/travis_retry.sh sudo -E apt-get $travis_apt_get_options install
- crossbuild-essential-armhf
- libc6:armhf
- libstdc++-10-dev:armhf
- libffi-dev:armhf
- libncurses-dev:armhf
- libncursesw5-dev:armhf
- libreadline-dev:armhf
- libssl-dev:armhf
- libyaml-dev:armhf
- linux-libc-dev:armhf
- zlib1g-dev:armhf
-
-matrix:
- include:
- - <<: *arm64-linux
- - <<: *ppc64le-linux
- - <<: *s390x-linux
- # FIXME: lib/rubygems/util.rb:104 glob_files_in_dir -
- # <internal:dir>:411:in glob: File name too long - (Errno::ENAMETOOLONG)
- # https://github.com/rubygems/rubygems/issues/7132
- - <<: *arm32-linux
- allow_failures:
- # Allow failures for the unstable jobs.
- # - name: arm64-linux
- # - name: ppc64le-linux
- # - name: s390x-linux
- # The 2nd arm64 pipeline may be unstable.
- # - name: arm32-linux
- fast_finish: true
-
-before_script:
- - ./autogen.sh
- - mkdir build
- - cd build
- - $SETARCH ../configure -C --disable-install-doc --prefix=$(pwd)/install
- - $SETARCH make -s $JOBS
- - make -s $JOBS install
- # Useful info to report issues to the Ruby.
- - $SETARCH $(pwd)/install/bin/ruby -v
- # Useful info To report issues to the RubyGems.
- - $SETARCH $(pwd)/install/bin/gem env
-
-script:
- - $SETARCH make -s test
- - ../tool/travis_wait.sh $SETARCH make -s test-all RUBYOPT="-w"
- - $SETARCH make -s test-spec
-
-# We want to be notified when something happens.
-notifications:
- webhooks:
- urls:
- # ruby-lang slack: ruby/simpler-alerts-bot (travis)
- - secure: mRsoS/UbqDkKkW5p3AEqM27d4SZnV6Gsylo3bm8T/deltQzTsGzZwrm7OIBXZv0UFZdE68XmPlyHfZFLSP2V9QZ7apXMf9/vw0GtcSe1gchtnjpAPF6lYBn7nMCbVPPx9cS0dwL927fjdRM1vj7IKZ2bk4F0lAJ25R25S6teqdk=
- on_success: never
- on_failure: always
- email:
- - jaruga@ruby-lang.org
diff --git a/LEGAL b/LEGAL
index e352c55ee5..0423d57ac9 100644
--- a/LEGAL
+++ b/LEGAL
@@ -748,7 +748,8 @@ mentioned below.
[ext/psych]
[test/psych]
- The files under these directories are under the following license.
+ The files under these directories are under the following license, except for
+ ext/psych/yaml.
>>>
Copyright 2009:: Aaron Patterson, et al.
@@ -771,6 +772,31 @@ mentioned below.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+[ext/psych/yaml]
+
+ The files under this directory are under the following license.
+
+ >>>
+ Copyright (c) 2006:: Kirill Simonov
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ this software and associated documentation files (the "Software"), to deal in
+ the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
[ext/pty/pty.c]
>>>
diff --git a/NEWS.md b/NEWS.md
index 240f6f4008..f6c3c6fc97 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,314 +1,820 @@
-# NEWS for Ruby 3.3.0
+# NEWS for Ruby 3.2.0
This document is a list of user-visible feature changes
-since the **3.2.0** release, except for bug fixes.
+since the **3.1.0** release, except for bug fixes.
Note that each entry is kept to a minimum, see links for details.
## Language changes
-## Command line options
-
-* A new `performance` warning category was introduced.
- They are not displayed by default even in verbose mode.
- Turn them on with `-W:performance` or `Warning[:performance] = true`. [[Feature #19538]]
-* The `RUBY_GC_HEAP_INIT_SLOTS` environment variable has been deprecated and
- removed. Environment variables `RUBY_GC_HEAP_%d_INIT_SLOTS` should be
- used instead. [[Feature #19785]]
+* Anonymous rest and keyword rest arguments can now be passed as
+ arguments, instead of just used in method parameters.
+ [[Feature #18351]]
+
+ ```ruby
+ def foo(*)
+ bar(*)
+ end
+ def baz(**)
+ quux(**)
+ end
+ ```
+
+* A proc that accepts a single positional argument and keywords will
+ no longer autosplat. [[Bug #18633]]
+
+ ```ruby
+ proc{|a, **k| a}.call([1, 2])
+ # Ruby 3.1 and before
+ # => 1
+ # Ruby 3.2 and after
+ # => [1, 2]
+ ```
+
+* Constant assignment evaluation order for constants set on explicit
+ objects has been made consistent with single attribute assignment
+ evaluation order. With this code:
+
+ ```ruby
+ foo::BAR = baz
+ ```
+
+ `foo` is now called before `baz`. Similarly, for multiple assignments
+ to constants, left-to-right evaluation order is used. With this
+ code:
+
+ ```ruby
+ foo1::BAR1, foo2::BAR2 = baz1, baz2
+ ```
+
+ The following evaluation order is now used:
+
+ 1. `foo1`
+ 2. `foo2`
+ 3. `baz1`
+ 4. `baz2`
+
+ [[Bug #15928]]
+
+* "Find pattern" is no longer experimental.
+ [[Feature #18585]]
+
+* Methods taking a rest parameter (like `*args`) and wishing to delegate keyword
+ arguments through `foo(*args)` must now be marked with `ruby2_keywords`
+ (if not already the case). In other words, all methods wishing to delegate
+ keyword arguments through `*args` must now be marked with `ruby2_keywords`,
+ with no exception. This will make it easier to transition to other ways of
+ delegation once a library can require Ruby 3+. Previously, the `ruby2_keywords`
+ flag was kept if the receiving method took `*args`, but this was a bug and an
+ inconsistency. A good technique to find the potentially-missing `ruby2_keywords`
+ is to run the test suite, for where it fails find the last method which must
+ receive keyword arguments, use `puts nil, caller, nil` there, and check each
+ method/block on the call chain which must delegate keywords is correctly marked
+ as `ruby2_keywords`. [[Bug #18625]] [[Bug #16466]]
+
+ ```ruby
+ def target(**kw)
+ end
+
+ # Accidentally worked without ruby2_keywords in Ruby 2.7-3.1, ruby2_keywords
+ # needed in 3.2+. Just like (*args, **kwargs) or (...) would be needed on
+ # both #foo and #bar when migrating away from ruby2_keywords.
+ ruby2_keywords def bar(*args)
+ target(*args)
+ end
+
+ ruby2_keywords def foo(*args)
+ bar(*args)
+ end
+
+ foo(k: 1)
+ ```
## Core classes updates
Note: We're only listing outstanding class updates.
-* Array
+* Fiber
+
+ * Introduce Fiber.[] and Fiber.[]= for inheritable fiber storage.
+ Introduce Fiber#storage and Fiber#storage= (experimental) for
+ getting and resetting the current storage. Introduce
+ `Fiber.new(storage:)` for setting the storage when creating a
+ fiber. [[Feature #19078]]
+
+ Existing Thread and Fiber local variables can be tricky to use.
+ Thread-local variables are shared between all fibers, making it
+ hard to isolate, while Fiber-local variables can be hard to
+ share. It is often desirable to define unit of execution
+ ("execution context") such that some state is shared between all
+ fibers and threads created in that context. This is what Fiber
+ storage provides.
+
+ ```ruby
+ def log(message)
+ puts "#{Fiber[:request_id]}: #{message}"
+ end
- * Array#pack now raises ArgumentError for unknown directives. [[Bug #19150]]
+ def handle_requests
+ while request = read_request
+ Fiber.schedule do
+ Fiber[:request_id] = SecureRandom.uuid
-* Dir
+ request.messages.each do |message|
+ Fiber.schedule do
+ log("Handling #{message}") # Log includes inherited request_id.
+ end
+ end
+ end
+ end
+ end
+ ```
- * Dir.for_fd added for returning a Dir object for the directory specified
- by the provided directory file descriptor. [[Feature #19347]]
- * Dir.fchdir added for changing the directory to the directory specified
- by the provided directory file descriptor. [[Feature #19347]]
- * Dir#chdir added for changing the directory to the directory specified by
- the provided `Dir` object. [[Feature #19347]]
+ You should generally consider Fiber storage for any state which
+ you want to be shared implicitly between all fibers and threads
+ created in a given context, e.g. a connection pool, a request
+ id, a logger level, environment variables, configuration, etc.
-* MatchData
+* Fiber::Scheduler
- * MatchData#named_captures now accepts optional `symbolize_names`
- keyword. [[Feature #19591]]
+ * Introduce `Fiber::Scheduler#io_select` for non-blocking IO.select.
+ [[Feature #19060]]
-* Module
+* IO
+
+ * Introduce IO#timeout= and IO#timeout which can cause
+ IO::TimeoutError to be raised if a blocking operation exceeds the
+ specified timeout. [[Feature #18630]]
+
+ ```ruby
+ STDIN.timeout = 1
+ STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
+ ```
+
+ * Introduce `IO.new(..., path:)` and promote `File#path` to `IO#path`.
+ [[Feature #19036]]
+
+* Class
+
+ * Class#attached_object, which returns the object for which
+ the receiver is the singleton class. Raises TypeError if the
+ receiver is not a singleton class.
+ [[Feature #12084]]
+
+ ```ruby
+ class Foo; end
+
+ Foo.singleton_class.attached_object #=> Foo
+ Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370>
+ Foo.attached_object #=> TypeError: `Foo' is not a singleton class
+ nil.singleton_class.attached_object #=> TypeError: `NilClass' is not a singleton class
+ ```
+
+* Data
+
+ * New core class to represent simple immutable value object. The class is
+ similar to Struct and partially shares an implementation, but has more
+ lean and strict API. [[Feature #16122]]
+
+ ```ruby
+ Measure = Data.define(:amount, :unit)
+ distance = Measure.new(100, 'km') #=> #<data Measure amount=100, unit="km">
+ weight = Measure.new(amount: 50, unit: 'kg') #=> #<data Measure amount=50, unit="kg">
+ weight.with(amount: 40) #=> #<data Measure amount=40, unit="kg">
+ weight.amount #=> 50
+ weight.amount = 40 #=> NoMethodError: undefined method `amount='
+ ```
+
+* Encoding
+
+ * Encoding#replicate has been deprecated and will be removed in 3.3. [[Feature #18949]]
+ * The dummy `Encoding::UTF_16` and `Encoding::UTF_32` encodings no longer
+ try to dynamically guess the endian based on a byte order mark.
+ Use `Encoding::UTF_16BE`/`UTF_16LE` and `Encoding::UTF_32BE`/`UTF_32LE` instead.
+ This change speeds up getting the encoding of a String. [[Feature #18949]]
+ * Limit maximum encoding set size by 256.
+ If exceeding maximum size, `EncodingError` will be raised. [[Feature #18949]]
+
+* Enumerator
+
+ * Enumerator.product has been added. Enumerator::Product is the implementation. [[Feature #18685]]
+
+* Exception
+
+ * Exception#detailed_message has been added.
+ The default error printer calls this method on the Exception object
+ instead of #message. [[Feature #18564]]
+
+* Hash
+
+ * Hash#shift now always returns nil if the hash is
+ empty, instead of returning the default value or
+ calling the default proc. [[Bug #16908]]
+
+* Integer
- * Module#set_temporary_name added for setting a temporary name for a
- module. [[Feature #19521]]
+ * Integer#ceildiv has been added. [[Feature #18809]]
-* ObjectSpace::WeakKeyMap
+* Kernel
- * New core class to build collections with weak references.
- The class use equality semantic to lookup keys like a regular hash,
- but it doesn't hold strong references on the keys. [[Feature #18498]]
+ * Kernel#binding raises RuntimeError if called from a non-Ruby frame
+ (such as a method defined in C). [[Bug #18487]]
+
+* MatchData
+
+ * MatchData#byteoffset has been added. [[Feature #13110]]
+ * MatchData#deconstruct has been added. [[Feature #18821]]
+ * MatchData#deconstruct_keys has been added. [[Feature #18821]]
+
+* Module
+
+ * Module.used_refinements has been added. [[Feature #14332]]
+ * Module#refinements has been added. [[Feature #12737]]
+ * Module#const_added has been added. [[Feature #17881]]
+ * Module#undefined_instance_methods has been added. [[Feature #12655]]
* Proc
- * Now Proc#dup and Proc#clone call `#initialize_dup` and `#initialize_clone`
- hooks respectively. [[Feature #19362]]
-* Process.warmup
+ * Proc#dup returns an instance of subclass. [[Bug #17545]]
+ * Proc#parameters now accepts lambda keyword. [[Feature #15357]]
- * Notify the Ruby virtual machine that the boot sequence is finished,
- and that now is a good time to optimize the application. This is useful
- for long running applications. The actual optimizations performed are entirely
- implementation specific and may change in the future without notice. [[Feature #18885]]
+* Process
+ * Added `RLIMIT_NPTS` constant to FreeBSD platform
-* Process::Status
+* Regexp
- * Process::Status#& and Process::Status#>> are deprecated. [[Bug #19868]]
+ * The cache-based optimization is introduced.
+ Many (but not all) Regexp matching is now in linear time, which
+ will prevent regular expression denial of service (ReDoS)
+ vulnerability. [[Feature #19104]]
-* Range
+ * Regexp.linear_time? is introduced. [[Feature #19194]]
- * Range#reverse_each can now process beginless ranges with an Integer endpoint. [[Feature #18515]]
+ * Regexp.new now supports passing the regexp flags not only as an Integer,
+ but also as a String. Unknown flags raise ArgumentError.
+ Otherwise, anything other than `true`, `false`, `nil` or Integer will be warned.
+ [[Feature #18788]]
+
+ * Regexp.timeout= has been added. Also, Regexp.new new supports timeout keyword.
+ See [[Feature #17837]]
* Refinement
- * Add Refinement#target as an alternative of Refinement#refined_class.
- Refinement#refined_class is deprecated and will be removed in Ruby
- 3.4. [[Feature #19714]]
+ * Refinement#refined_class has been added. [[Feature #12737]]
+
+* RubyVM::AbstractSyntaxTree
+
+ * Add `error_tolerant` option for `parse`, `parse_file` and `of`. [[Feature #19013]]
+ With this option
+
+ 1. SyntaxError is suppressed
+ 2. AST is returned for invalid input
+ 3. `end` is complemented when a parser reaches to the end of input but `end` is insufficient
+ 4. `end` is treated as keyword based on indent
+
+ ```ruby
+ # Without error_tolerant option
+ root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY)
+ def m
+ a = 10
+ if
+ end
+ RUBY
+ # => <internal:ast>:33:in `parse': syntax error, unexpected `end' (SyntaxError)
+
+ # With error_tolerant option
+ root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
+ def m
+ a = 10
+ if
+ end
+ RUBY
+ p root # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-4:3>
+
+ # `end` is treated as keyword based on indent
+ root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
+ module Z
+ class Foo
+ foo.
+ end
+
+ def bar
+ end
+ end
+ RUBY
+ p root.children[-1].children[-1].children[-1].children[-2..-1]
+ # => [#<RubyVM::AbstractSyntaxTree::Node:CLASS@2:2-4:5>, #<RubyVM::AbstractSyntaxTree::Node:DEFN@6:2-7:5>]
+ ```
+
+ * Add `keep_tokens` option for `parse`, `parse_file` and `of`. Add `#tokens` and `#all_tokens`
+ for RubyVM::AbstractSyntaxTree::Node [[Feature #19070]]
+
+ ```ruby
+ root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2", keep_tokens: true)
+ root.tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...]
+ root.tokens.map{_1[2]}.join # => "x = 1 + 2"
+ ```
+
+* Set
+
+ * Set is now available as a built-in class without the need for `require "set"`. [[Feature #16989]]
+ It is currently autoloaded via the Set constant or a call to Enumerable#to_set.
* String
- * String#unpack now raises ArgumentError for unknown directives. [[Bug #19150]]
- * String#bytesplice now accepts new arguments index/length or range of the
- source string to be copied. [[Feature #19314]]
+ * String#byteindex and String#byterindex have been added. [[Feature #13110]]
+ * Update Unicode to Version 15.0.0 and Emoji Version 15.0. [[Feature #18639]]
+ (also applies to Regexp)
+ * String#bytesplice has been added. [[Feature #18598]]
+ * String#dedup has been added as an alias to String#-@. [[Feature #18595]]
+
+* Struct
+
+ * A Struct class can also be initialized with keyword arguments
+ without `keyword_init: true` on Struct.new [[Feature #16806]]
+
+ ```ruby
+ Post = Struct.new(:id, :name)
+ Post.new(1, "hello") #=> #<struct Post id=1, name="hello">
+ # From Ruby 3.2, the following code also works without keyword_init: true.
+ Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">
+ ```
+
+* Thread
+
+ * Thread.each_caller_location is added. [[Feature #16663]]
+
+* Thread::Queue
+
+ * Thread::Queue#pop(timeout: sec) is added. [[Feature #18774]]
+
+* Thread::SizedQueue
+
+ * Thread::SizedQueue#pop(timeout: sec) is added. [[Feature #18774]]
+ * Thread::SizedQueue#push(timeout: sec) is added. [[Feature #18944]]
+
+* Time
+
+ * Time#deconstruct_keys is added, allowing to use Time instances
+ in pattern-matching expressions [[Feature #19071]]
+
+ * Time.new now can parse a string like generated by Time#inspect
+ and return a Time instance based on the given argument.
+ [[Feature #18033]]
+
+* SyntaxError
+ * SyntaxError#path has been added. [[Feature #19138]]
* TracePoint
- * TracePoint supports `rescue` event. When the raised exception was rescued,
- the TracePoint will fire the hook. `rescue` event only supports Ruby-level
- `rescue`. [[Feature #19572]]
+ * TracePoint#binding now returns `nil` for `c_call`/`c_return` TracePoints.
+ [[Bug #18487]]
+ * TracePoint#enable `target_thread` keyword argument now defaults to the
+ current thread if a block is given and `target` and `target_line` keyword
+ arguments are not passed. [[Bug #16889]]
+
+* UnboundMethod
+
+ * `UnboundMethod#==` returns `true` if the actual method is same. For example,
+ `String.instance_method(:object_id) == Array.instance_method(:object_id)`
+ returns `true`. [[Feature #18798]]
+
+ * `UnboundMethod#inspect` does not show the receiver of `instance_method`.
+ For example `String.instance_method(:object_id).inspect` returns
+ `"#<UnboundMethod: Kernel#object_id()>"`
+ (was `"#<UnboundMethod: String(Kernel)#object_id()>"`).
+
+* GC
+
+ * Expose `need_major_gc` via `GC.latest_gc_info`. [GH-6791]
+
+* ObjectSpace
+
+ * `ObjectSpace.dump_all` dump shapes as well. [GH-6868]
## Stdlib updates
-* RubyGems and Bundler warn if users require gem that is scheduled to become the bundled gems
- in the future version of Ruby. [[Feature #19351]] [[Feature #19776]] [[Feature #19843]]
-
- Targeted libraries are:
- * abbrev
- * base64
- * bigdecimal
- * csv
- * drb
- * getoptlong
- * mutex_m
- * nkf
- * observer
- * racc
- * resolv-replace
- * rinda
- * syslog
-
-* Socket#recv and Socket#recv_nonblock returns `nil` instead of an empty string on closed
- connections. Socket#recvmsg and Socket#recvmsg_nonblock returns `nil` instead of an empty packet on closed
- connections. [[Bug #19012]]
-
-* Random::Formatter#alphanumeric is extended to accept optional `chars`
- keyword argument. [[Feature #18183]]
-
-The following default gem is added.
-
-* prism 0.17.1
-
-The following default gems are updated.
-
-* RubyGems 3.5.0.dev
-* base64 0.2.0
-* benchmark 0.3.0
-* bigdecimal 3.1.5
-* bundler 2.5.0.dev
-* cgi 0.4.0
-* csv 3.2.8
-* date 3.3.4
-* delegate 0.3.1
-* drb 2.2.0
-* english 0.8.0
-* erb 4.0.3
-* etc 1.4.3.dev.1
-* fcntl 1.1.0
-* fiddle 1.1.2
-* fileutils 1.7.2
-* find 0.2.0
-* getoptlong 0.2.1
-* io-console 0.6.1.dev.1
-* irb 1.9.0
-* logger 1.6.0
-* mutex_m 0.2.0
-* net-http 0.4.0
-* net-protocol 0.2.2
-* nkf 0.1.3
-* observer 0.1.2
-* open-uri 0.4.0
-* open3 0.2.0
-* openssl 3.2.0
-* optparse 0.4.0
-* ostruct 0.6.0
-* pathname 0.3.0
-* pp 0.5.0
-* prettyprint 0.2.0
-* pstore 0.1.3
-* psych 5.1.1.1
-* rdoc 6.6.0
-* reline 0.4.0
-* rinda 0.2.0
-* securerandom 0.3.0
-* shellwords 0.2.0
-* singleton 0.2.0
-* stringio 3.1.0
-* strscan 3.0.8
-* syntax_suggest 1.1.0
-* tempfile 0.2.0
-* time 0.3.0
-* timeout 0.4.1
-* tmpdir 0.2.0
-* tsort 0.2.0
-* un 0.3.0
-* uri 0.13.0
-* weakref 0.1.3
-* win32ole 1.8.10
-* yaml 0.3.0
-* zlib 3.1.0
-
-The following bundled gem is promoted from default gems.
-
-* racc 1.7.3
-
-The following bundled gems are updated.
-
-* minitest 5.20.0
-* rake 13.1.0
-* test-unit 3.6.1
-* rexml 3.2.6
-* rss 0.3.0
-* net-imap 0.4.4
-* net-smtp 0.4.0
-* rbs 3.2.2
-* typeprof 0.21.8
-* debug 1.8.0
-
-See GitHub releases like [Logger](https://github.com/ruby/logger/releases) or
-changelog for details of the default gems or bundled gems.
+* Bundler
+
+ * Bundler now uses [PubGrub] resolver instead of [Molinillo] for performance improvement.
+ * Add --ext=rust support to bundle gem for creating simple gems with Rust extensions.
+ [[GH-rubygems-6149]]
+ * Make cloning git repos faster [[GH-rubygems-4475]]
+
+* RubyGems
+
+ * Add mswin support for cargo builder. [[GH-rubygems-6167]]
+
+* CGI
+
+ * `CGI.escapeURIComponent` and `CGI.unescapeURIComponent` are added.
+ [[Feature #18822]]
+
+* Coverage
+
+ * `Coverage.setup` now accepts `eval: true`. By this, `eval` and related methods are
+ able to generate code coverage. [[Feature #19008]]
+
+ * `Coverage.supported?(mode)` enables detection of what coverage modes are
+ supported. [[Feature #19026]]
+
+* Date
+
+ * Added `Date#deconstruct_keys` and `DateTime#deconstruct_keys` same as [[Feature #19071]]
+
+* ERB
+
+ * `ERB::Util.html_escape` is made faster than `CGI.escapeHTML`.
+ * It no longer allocates a String object when no character needs to be escaped.
+ * It skips calling `#to_s` method when an argument is already a String.
+ * `ERB::Escape.html_escape` is added as an alias to `ERB::Util.html_escape`,
+ which has not been monkey-patched by Rails.
+ * `ERB::Util.url_encode` is made faster using `CGI.escapeURIComponent`.
+ * `-S` option is removed from `erb` command.
+
+* FileUtils
+
+ * Add FileUtils.ln_sr method and `relative:` option to FileUtils.ln_s.
+ [[Feature #18925]]
+
+* IRB
+
+ * debug.gem integration commands have been added: `debug`, `break`, `catch`,
+ `next`, `delete`, `step`, `continue`, `finish`, `backtrace`, `info`
+ * They work even if you don't have `gem "debug"` in your Gemfile.
+ * See also: [What's new in Ruby 3.2's IRB?](https://st0012.dev/whats-new-in-ruby-3-2-irb)
+ * More Pry-like commands and features have been added.
+ * `edit` and `show_cmds` (like Pry's `help`) are added.
+ * `ls` takes `-g` or `-G` option to filter out outputs.
+ * `show_source` is aliased from `$` and accepts unquoted inputs.
+ * `whereami` is aliased from `@`.
+
+* Net::Protocol
+
+ * Improve `Net::BufferedIO` performance. [[GH-net-protocol-14]]
+
+* Pathname
+
+ * Added `Pathname#lutime`. [[GH-pathname-20]]
+
+* Socket
+
+ * Added the following constants for supported platforms.
+ * `SO_INCOMING_CPU`
+ * `SO_INCOMING_NAPI_ID`
+ * `SO_RTABLE`
+ * `SO_SETFIB`
+ * `SO_USER_COOKIE`
+ * `TCP_KEEPALIVE`
+ * `TCP_CONNECTION_INFO`
+
+* SyntaxSuggest
+
+ * The feature of `syntax_suggest` formerly `dead_end` is integrated in Ruby.
+ [[Feature #18159]]
+
+* UNIXSocket
+
+ * Add support for UNIXSocket on Windows. Emulate anonymous sockets. Add
+ support for File.socket? and File::Stat#socket? where possible.
+ [[Feature #19135]]
+
+* The following default gems are updated.
+
+ * RubyGems 3.4.1
+ * abbrev 0.1.1
+ * benchmark 0.2.1
+ * bigdecimal 3.1.3
+ * bundler 2.4.1
+ * cgi 0.3.6
+ * csv 3.2.6
+ * date 3.3.3
+ * delegate 0.3.0
+ * did_you_mean 1.6.3
+ * digest 3.1.1
+ * drb 2.1.1
+ * english 0.7.2
+ * erb 4.0.2
+ * error_highlight 0.5.1
+ * etc 1.4.2
+ * fcntl 1.0.2
+ * fiddle 1.1.1
+ * fileutils 1.7.0
+ * forwardable 1.3.3
+ * getoptlong 0.2.0
+ * io-console 0.6.0
+ * io-nonblock 0.2.0
+ * io-wait 0.3.0
+ * ipaddr 1.2.5
+ * irb 1.6.2
+ * json 2.6.3
+ * logger 1.5.3
+ * mutex_m 0.1.2
+ * net-http 0.4.0
+ * net-protocol 0.2.1
+ * nkf 0.1.2
+ * open-uri 0.3.0
+ * open3 0.1.2
+ * openssl 3.1.0
+ * optparse 0.3.1
+ * ostruct 0.5.5
+ * pathname 0.2.1
+ * pp 0.4.0
+ * pstore 0.1.2
+ * psych 5.0.1
+ * racc 1.6.2
+ * rdoc 6.5.0
+ * readline-ext 0.1.5
+ * reline 0.3.2
+ * resolv 0.2.2
+ * resolv-replace 0.1.1
+ * securerandom 0.2.2
+ * set 1.0.3
+ * stringio 3.0.4
+ * strscan 3.0.5
+ * syntax_suggest 1.0.2
+ * syslog 0.1.1
+ * tempfile 0.1.3
+ * time 0.2.1
+ * timeout 0.3.1
+ * tmpdir 0.1.3
+ * tsort 0.1.1
+ * un 0.2.1
+ * uri 0.12.0
+ * weakref 0.1.2
+ * win32ole 1.8.9
+ * yaml 0.2.1
+ * zlib 3.0.0
+
+* The following bundled gems are updated.
+
+ * minitest 5.16.3
+ * power_assert 2.0.3
+ * test-unit 3.5.7
+ * net-ftp 0.2.0
+ * net-imap 0.3.4
+ * net-pop 0.1.2
+ * net-smtp 0.3.3
+ * rbs 2.8.2
+ * typeprof 0.21.3
+ * debug 1.7.1
+
+See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/logger/releases) or changelog for details of the default gems or bundled gems.
## Supported platforms
+* WebAssembly/WASI is added. See [wasm/README.md] and [ruby.wasm] for more details. [[Feature #18462]]
+
## Compatibility issues
+* `String#to_c` currently treat a sequence of underscores as an end of Complex
+ string. [[Bug #19087]]
+
+* Now `ENV.clone` raises `TypeError` as well as `ENV.dup` [[Bug #17767]]
+
+### Removed constants
+
+The following deprecated constants are removed.
+
+* `Fixnum` and `Bignum` [[Feature #12005]]
+* `Random::DEFAULT` [[Feature #17351]]
+* `Struct::Group`
+* `Struct::Passwd`
+
+### Removed methods
+
+The following deprecated methods are removed.
+
+* `Dir.exists?` [[Feature #17391]]
+* `File.exists?` [[Feature #17391]]
+* `Kernel#=~` [[Feature #15231]]
+* `Kernel#taint`, `Kernel#untaint`, `Kernel#tainted?`
+ [[Feature #16131]]
+* `Kernel#trust`, `Kernel#untrust`, `Kernel#untrusted?`
+ [[Feature #16131]]
+* `Method#public?`, `Method#private?`, `Method#protected?`,
+ `UnboundMethod#public?`, `UnboundMethod#private?`, `UnboundMethod#protected?`
+ [[Bug #18729]] [[Bug #18751]] [[Bug #18435]]
+
+### Source code incompatibility of extension libraries
+
+* Extension libraries provide PRNG, subclasses of Random, need updates.
+ See [PRNG update] below for more information. [[Bug #19100]]
+
+### Error printer
+
+* Ruby no longer escapes control characters and backslashes in an
+ error message. [[Feature #18367]]
+
+### Constant lookup when defining a class/module
+
+* When defining a class/module directly under the Object class by class/module
+ statement, if there is already a class/module defined by `Module#include`
+ with the same name, the statement was handled as "open class" in Ruby 3.1 or before.
+ Since Ruby 3.2, a new class is defined instead. [[Feature #18832]]
+
## Stdlib compatibility issues
-* `racc` is promoted to bundled gems.
- * You need to add `racc` to your `Gemfile` if you use `racc` under bundler environment.
-* `ext/readline` is retired
- * We have `reline` that is pure Ruby implementation compatible with `ext/readline` API. We rely on `reline` in the future. If you need to use `ext/readline`, you can install `ext/readline` via rubygems.org with `gem install readline-ext`.
- * We no longer need to install libraries like `libreadline` or `libedit`.
+* Psych no longer bundles libyaml sources.
+ And also Fiddle no longer bundles libffi sources.
+ Users need to install the libyaml/libffi library themselves via the package
+ manager like apt, yum, brew, etc.
+
+ Psych and fiddle supported the static build with specific version of libyaml
+ and libffi sources. You can build psych with libyaml-0.2.5 like this.
+
+ ```bash
+ $ ./configure --with-libyaml-source-dir=/path/to/libyaml-0.2.5
+ ```
+
+ And you can build fiddle with libffi-3.4.4 like this.
+
+ ```bash
+ $ ./configure --with-libffi-source-dir=/path/to/libffi-3.4.4
+ ```
+
+ [[Feature #18571]]
+
+* Check cookie name/path/domain characters in `CGI::Cookie`. [[CVE-2021-33621]]
+
+* `URI.parse` return empty string in host instead of nil. [[sec-156615]]
## C API updates
+### Updated C APIs
+
+The following APIs are updated.
+
+* PRNG update
+
+ `rb_random_interface_t` in ruby/random.h updated and versioned.
+ Extension libraries which use this interface and built for older
+ versions need to rebuild with adding `init_int32` function.
+
+### Added C APIs
+
+* `VALUE rb_hash_new_capa(long capa)` was added to created hashes with the desired capacity.
+* `rb_internal_thread_add_event_hook` and `rb_internal_thread_add_event_hook` were added to instrument threads scheduling.
+ The following events are available:
+ * `RUBY_INTERNAL_THREAD_EVENT_STARTED`
+ * `RUBY_INTERNAL_THREAD_EVENT_READY`
+ * `RUBY_INTERNAL_THREAD_EVENT_RESUMED`
+ * `RUBY_INTERNAL_THREAD_EVENT_SUSPENDED`
+ * `RUBY_INTERNAL_THREAD_EVENT_EXITED`
+* `rb_debug_inspector_current_depth` and `rb_debug_inspector_frame_depth` are added for debuggers.
+
+### Removed C APIs
+
+The following deprecated APIs are removed.
+
+* `rb_cData` variable.
+* "taintedness" and "trustedness" functions. [[Feature #16131]]
+
## Implementation improvements
-* `defined?(@ivar)` is optimized with Object Shapes.
-* Name resolution such as `Socket.getaddrinfo` can now be interrupted. [[Feature #19965]]
+* Fixed several race conditions in Kernel#autoload. [[Bug #18782]]
+* Cache invalidation for expressions referencing constants is now
+ more fine-grained. `RubyVM.stat(:global_constant_state)` was
+ removed because it was closely tied to the previous caching scheme
+ where setting any constant invalidates all caches in the system.
+ New keys, `:constant_cache_invalidations` and `:constant_cache_misses`,
+ were introduced to help with use cases for `:global_constant_state`.
+ [[Feature #18589]]
+* The cache-based optimization for Regexp matching is introduced.
+ [[Feature #19104]]
+* [Variable Width Allocation](https://shopify.engineering/ruby-variable-width-allocation)
+ is now enabled by default. [[Feature #18239]]
+* Added a new instance variable caching mechanism, called object shapes, which
+ improves inline cache hits for most objects and allows us to generate very
+ efficient JIT code. Objects whose instance variables are defined in a
+ consistent order will see the most performance benefits.
+ [[Feature #18776]]
+* Speed up marking instruction sequences by using a bitmap to find "markable"
+ objects. This change results in faster major collections.
+ [[Feature #18875]]
+
+## JIT
### YJIT
-* Major performance improvements over 3.2
- * Support for splat and rest arguments has been improved.
- * Registers are allocated for stack operations of the virtual machine.
- * More calls with optional arguments are compiled.
- * Exception handlers are also compiled.
- * Instance variables no longer exit to the interpreter
- with megamorphic object shapes.
- * Unsupported call types no longer exit to the interpreter.
- * `Integer#!=`, `String#!=`, `Kernel#block_given?`, `Kernel#is_a?`,
- `Kernel#instance_of?`, `Module#===` are specially optimized.
- * Now more than 3x faster than the interpreter on optcarrot!
-* Significantly improved memory usage over 3.2
- * Metadata for compiled code uses a lot less memory.
- * Generate more compact code on ARM64
-* Compilation speed is now slightly faster than 3.2.
-* Add `RubyVM::YJIT.enable` that can enable YJIT later
- * You can start YJIT without modifying command-line arguments or environment variables.
- * This can also be used to enable YJIT only once your application is
- done booting. `--yjit-disable` can be used if you want to use other
- YJIT options while disabling YJIT at boot.
-* Code GC now disabled by default, with `--yjit-exec-mem-size` treated as a hard limit
- * Can produce better copy-on-write behavior on forking web servers such as `unicorn`
- * Use the `--yjit-code-gc` option to automatically run code GC when YJIT reaches the size limit
-* `ratio_in_yjit` stat produced by `--yjit-stats` is now available in release builds,
- a special stats or dev build is no longer required to access most stats.
-* Exit tracing option now supports sampling
- * `--trace-exits-sample-rate=N`
-* More thorough testing and multiple bug fixes
-* `--yjit-stats=quiet` is added to avoid printing stats on exit.
-* `--yjit-perf` is added to facilitate profiling with Linux perf.
+* YJIT is no longer experimental
+ * Has been tested on production workloads for over a year and proven to be quite stable.
+* YJIT now supports both x86-64 and arm64/aarch64 CPUs on Linux, MacOS, BSD and other UNIX platforms.
+ * This release brings support for Mac M1/M2, AWS Graviton and Raspberry Pi 4.
+* Building YJIT now requires Rust 1.58.0+. [[Feature #18481]]
+ * In order to ensure that CRuby is built with YJIT, please install `rustc` >= 1.58.0
+ before running `./configure`
+ * Please reach out to the YJIT team should you run into any issues.
+* Physical memory for JIT code is lazily allocated. Unlike Ruby 3.1,
+ the RSS of a Ruby process is minimized because virtual memory pages
+ allocated by `--yjit-exec-mem-size` will not be mapped to physical
+ memory pages until actually utilized by JIT code.
+* Introduce Code GC that frees all code pages when the memory consumption
+ by JIT code reaches `--yjit-exec-mem-size`.
+ * `RubyVM::YJIT.runtime_stats` returns Code GC metrics in addition to
+ existing `inline_code_size` and `outlined_code_size` keys:
+ `code_gc_count`, `live_page_count`, `freed_page_count`, and `freed_code_size`.
+* Most of the statistics produced by `RubyVM::YJIT.runtime_stats` are now available in release builds.
+ * Simply run ruby with `--yjit-stats` to compute and dump stats (incurs some run-time overhead).
+* YJIT is now optimized to take advantage of object shapes. [[Feature #18776]]
+* Take advantage of finer-grained constant invalidation to invalidate less code when defining new constants. [[Feature #18589]]
+* The default `--yjit-exec-mem-size` is changed to 64 (MiB).
+* The default `--yjit-call-threshold` is changed to 30.
### MJIT
-* MJIT is removed.
- * `--disable-jit-support` is removed. Consider using `--disable-yjit --disable-rjit` instead.
-
-### RJIT
-
-* Introduced a pure-Ruby JIT compiler RJIT.
- * RJIT supports only x86\_64 architecture on Unix platforms.
- * Unlike MJIT, it doesn't require a C compiler at runtime.
-* RJIT exists only for experimental purposes.
- * You should keep using YJIT in production.
-
-### M:N Therad scheduler
-
-* M:N Thread scheduler is introduced. [[Feature #19842]]
- * Background: Ruby 1.8 and before, M:1 thread scheduler (M Ruby threads
- with 1 native thread. Called as User level threads or Green threads)
- is used. Ruby 1.9 and later, 1:1 thread scheduler (1 Ruby thread with
- 1 native thread). M:1 threads takes lower resources compare with 1:1
- threads because it needs only 1 native threads. However it is difficult
- to support context switching for all of blocking operation so 1:1
- threads are employed from Ruby 1.9. M:N thread scheduler uses N native
- threads for M Ruby threads (N is small number in general). It doesn't
- need same number of native threads as Ruby threads (similar to the M:1
- thread scheduler). Also our M:N threads supports blocking operations
- well same as 1:1 threads. See the ticket for more details.
- Our M:N thread scheduler refers on the gorotuine scheduler in the
- Go language.
- * In a ractor, only 1 thread can run in a same time because of
- implementation. Therefore, applications that use only one Ractor
- (most applications) M:N thread scheduler works as M:1 thread scheduler
- with further extension from Ruby 1.8.
- * M:N thread scheduler can introduce incompatibility for C-extensions,
- so it is disabled by default on the main Ractors.
- `RUBY_MN_THREADS=1` environment variable will enable it.
- On non-main Ractors, M:N thread scheduler is enabled (and can not
- disable it now).
- * `N` (the number of native threads) can be specified with `RUBY_MAX_CPU`
- environment variable. The default is 8.
- Note that more than `N` native threads are used to support many kind of
- blocking operations.
-
-[Feature #18183]: https://bugs.ruby-lang.org/issues/18183
-[Feature #18498]: https://bugs.ruby-lang.org/issues/18498
-[Feature #18515]: https://bugs.ruby-lang.org/issues/18515
-[Feature #18885]: https://bugs.ruby-lang.org/issues/18885
-[Bug #19012]: https://bugs.ruby-lang.org/issues/19012
-[Bug #19150]: https://bugs.ruby-lang.org/issues/19150
-[Feature #19314]: https://bugs.ruby-lang.org/issues/19314
-[Feature #19347]: https://bugs.ruby-lang.org/issues/19347
-[Feature #19351]: https://bugs.ruby-lang.org/issues/19351
-[Feature #19362]: https://bugs.ruby-lang.org/issues/19362
-[Feature #19521]: https://bugs.ruby-lang.org/issues/19521
-[Feature #19538]: https://bugs.ruby-lang.org/issues/19538
-[Feature #19572]: https://bugs.ruby-lang.org/issues/19572
-[Feature #19591]: https://bugs.ruby-lang.org/issues/19591
-[Feature #19714]: https://bugs.ruby-lang.org/issues/19714
-[Feature #19776]: https://bugs.ruby-lang.org/issues/19776
-[Feature #19785]: https://bugs.ruby-lang.org/issues/19785
-[Feature #19842]: https://bugs.ruby-lang.org/issues/19842
-[Feature #19843]: https://bugs.ruby-lang.org/issues/19843
-[Bug #19868]: https://bugs.ruby-lang.org/issues/19868
-[Feature #19965]: https://bugs.ruby-lang.org/issues/19965
+* The MJIT compiler is re-implemented in Ruby as `ruby_vm/mjit/compiler`.
+* MJIT compiler is executed under a forked Ruby process instead of
+ doing it in a native thread called MJIT worker. [[Feature #18968]]
+ * As a result, Microsoft Visual Studio (MSWIN) is no longer supported.
+* MinGW is no longer supported. [[Feature #18824]]
+* Rename `--mjit-min-calls` to `--mjit-call-threshold`.
+* Change default `--mjit-max-cache` back from 10000 to 100.
+
+[Feature #12005]: https://bugs.ruby-lang.org/issues/12005
+[Feature #12084]: https://bugs.ruby-lang.org/issues/12084
+[Feature #12655]: https://bugs.ruby-lang.org/issues/12655
+[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
+[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
+[Feature #14332]: https://bugs.ruby-lang.org/issues/14332
+[Feature #15231]: https://bugs.ruby-lang.org/issues/15231
+[Feature #15357]: https://bugs.ruby-lang.org/issues/15357
+[Bug #15928]: https://bugs.ruby-lang.org/issues/15928
+[Feature #16122]: https://bugs.ruby-lang.org/issues/16122
+[Feature #16131]: https://bugs.ruby-lang.org/issues/16131
+[Bug #16466]: https://bugs.ruby-lang.org/issues/16466
+[Feature #16663]: https://bugs.ruby-lang.org/issues/16663
+[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
+[Bug #16889]: https://bugs.ruby-lang.org/issues/16889
+[Bug #16908]: https://bugs.ruby-lang.org/issues/16908
+[Feature #16989]: https://bugs.ruby-lang.org/issues/16989
+[Feature #17351]: https://bugs.ruby-lang.org/issues/17351
+[Feature #17391]: https://bugs.ruby-lang.org/issues/17391
+[Bug #17545]: https://bugs.ruby-lang.org/issues/17545
+[Bug #17767]: https://bugs.ruby-lang.org/issues/17767
+[Feature #17837]: https://bugs.ruby-lang.org/issues/17837
+[Feature #17881]: https://bugs.ruby-lang.org/issues/17881
+[Feature #18033]: https://bugs.ruby-lang.org/issues/18033
+[Feature #18159]: https://bugs.ruby-lang.org/issues/18159
+[Feature #18239]: https://bugs.ruby-lang.org/issues/18239#note-17
+[Feature #18351]: https://bugs.ruby-lang.org/issues/18351
+[Feature #18367]: https://bugs.ruby-lang.org/issues/18367
+[Bug #18435]: https://bugs.ruby-lang.org/issues/18435
+[Feature #18462]: https://bugs.ruby-lang.org/issues/18462
+[Feature #18481]: https://bugs.ruby-lang.org/issues/18481
+[Bug #18487]: https://bugs.ruby-lang.org/issues/18487
+[Feature #18564]: https://bugs.ruby-lang.org/issues/18564
+[Feature #18571]: https://bugs.ruby-lang.org/issues/18571
+[Feature #18585]: https://bugs.ruby-lang.org/issues/18585
+[Feature #18589]: https://bugs.ruby-lang.org/issues/18589
+[Feature #18595]: https://bugs.ruby-lang.org/issues/18595
+[Feature #18598]: https://bugs.ruby-lang.org/issues/18598
+[Bug #18625]: https://bugs.ruby-lang.org/issues/18625
+[Feature #18630]: https://bugs.ruby-lang.org/issues/18630
+[Bug #18633]: https://bugs.ruby-lang.org/issues/18633
+[Feature #18639]: https://bugs.ruby-lang.org/issues/18639
+[Feature #18685]: https://bugs.ruby-lang.org/issues/18685
+[Bug #18729]: https://bugs.ruby-lang.org/issues/18729
+[Bug #18751]: https://bugs.ruby-lang.org/issues/18751
+[Feature #18774]: https://bugs.ruby-lang.org/issues/18774
+[Feature #18776]: https://bugs.ruby-lang.org/issues/18776
+[Bug #18782]: https://bugs.ruby-lang.org/issues/18782
+[Feature #18788]: https://bugs.ruby-lang.org/issues/18788
+[Feature #18798]: https://bugs.ruby-lang.org/issues/18798
+[Feature #18809]: https://bugs.ruby-lang.org/issues/18809
+[Feature #18821]: https://bugs.ruby-lang.org/issues/18821
+[Feature #18822]: https://bugs.ruby-lang.org/issues/18822
+[Feature #18824]: https://bugs.ruby-lang.org/issues/18824
+[Feature #18832]: https://bugs.ruby-lang.org/issues/18832
+[Feature #18875]: https://bugs.ruby-lang.org/issues/18875
+[Feature #18925]: https://bugs.ruby-lang.org/issues/18925
+[Feature #18944]: https://bugs.ruby-lang.org/issues/18944
+[Feature #18949]: https://bugs.ruby-lang.org/issues/18949
+[Feature #18968]: https://bugs.ruby-lang.org/issues/18968
+[Feature #19008]: https://bugs.ruby-lang.org/issues/19008
+[Feature #19013]: https://bugs.ruby-lang.org/issues/19013
+[Feature #19026]: https://bugs.ruby-lang.org/issues/19026
+[Feature #19036]: https://bugs.ruby-lang.org/issues/19036
+[Feature #19060]: https://bugs.ruby-lang.org/issues/19060
+[Feature #19070]: https://bugs.ruby-lang.org/issues/19070
+[Feature #19071]: https://bugs.ruby-lang.org/issues/19071
+[Feature #19078]: https://bugs.ruby-lang.org/issues/19078
+[Bug #19087]: https://bugs.ruby-lang.org/issues/19087
+[Bug #19100]: https://bugs.ruby-lang.org/issues/19100
+[Feature #19104]: https://bugs.ruby-lang.org/issues/19104
+[Feature #19135]: https://bugs.ruby-lang.org/issues/19135
+[Feature #19138]: https://bugs.ruby-lang.org/issues/19138
+[Feature #19194]: https://bugs.ruby-lang.org/issues/19194
+[Molinillo]: https://github.com/CocoaPods/Molinillo
+[PubGrub]: https://github.com/jhawthorn/pub_grub
+[GH-net-protocol-14]: https://github.com/ruby/net-protocol/pull/14
+[GH-pathname-20]: https://github.com/ruby/pathname/pull/20
+[GH-6791]: https://github.com/ruby/ruby/pull/6791
+[GH-6868]: https://github.com/ruby/ruby/pull/6868
+[GH-rubygems-4475]: https://github.com/rubygems/rubygems/pull/4475
+[GH-rubygems-6149]: https://github.com/rubygems/rubygems/pull/6149
+[GH-rubygems-6167]: https://github.com/rubygems/rubygems/pull/6167
+[sec-156615]: https://hackerone.com/reports/156615
+[CVE-2021-33621]: https://www.ruby-lang.org/en/news/2022/11/22/http-response-splitting-in-cgi-cve-2021-33621/
+[wasm/README.md]: https://github.com/ruby/ruby/blob/master/wasm/README.md
+[ruby.wasm]: https://github.com/ruby/ruby.wasm
diff --git a/README.ja.md b/README.ja.md
index 0d2d309fb8..93c0131690 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -1,10 +1,9 @@
[![Actions Status: MinGW](https://github.com/ruby/ruby/workflows/MinGW/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MinGW")
-[![Actions Status: RJIT](https://github.com/ruby/ruby/workflows/RJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"RJIT")
+[![Actions Status: MJIT](https://github.com/ruby/ruby/workflows/MJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MJIT")
[![Actions Status: Ubuntu](https://github.com/ruby/ruby/workflows/Ubuntu/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Ubuntu")
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0sy8rrxut4o0k960/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/ruby/branch/master)
[![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby)
-[![Cirrus Status](https://api.cirrus-ci.com/github/ruby/ruby.svg)](https://cirrus-ci.com/github/ruby/ruby/master)
# Rubyとは
@@ -26,7 +25,7 @@ Rubyはテキスト処理関係の能力などに優れ,Perlと同じくらい
* ダイナミックローディング (アーキテクチャによる)
* 移植性が高い.多くのUnix-like/POSIX互換プラットフォーム上で動くだけでなく,Windows, macOS,
Haikuなどの上でも動く cf.
- https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Platform+Maintainers
+ https://github.com/ruby/ruby/blob/master/doc/contributing.rdoc#platform-maintainers
## 入手法
@@ -50,6 +49,17 @@ https://www.ruby-lang.org/ja/downloads/
Rubyリポジトリの本来のmasterは https://git.ruby-lang.org/ruby.git にあります.
コミッタはこちらを使います.
+### Subversion
+
+古いRubyのバージョンのソースコードは次のコマンドでも取得できます.
+
+ $ svn co https://svn.ruby-lang.org/repos/ruby/branches/ruby_2_6/ ruby
+
+他のブランチの一覧は次のコマンドで見られます.
+
+ $ svn ls https://svn.ruby-lang.org/repos/ruby/branches/
+
+
## ホームページ
RubyのホームページのURLは
@@ -60,20 +70,20 @@ https://www.ruby-lang.org/
## メーリングリスト
-Rubyのメーリングリストがあります.参加希望の方は [ruby-list-request@ml.ruby-lang.org] まで件名に
+Rubyのメーリングリストがあります.参加希望の方は [ruby-list-request@ruby-lang.org] まで本文に
- join
+ subscribe
と書いて送って下さい.
Ruby開発者向けメーリングリストもあります.こちらではrubyのバグ,将来の仕様拡張など実装上の問題について議論されています.
-参加希望の方は [ruby-dev-request@ml.ruby-lang.org] までruby-listと同様の方法でメールしてください.
+参加希望の方は [ruby-dev-request@ruby-lang.org] までruby-listと同様の方法でメールしてください.
Ruby拡張モジュールについて話し合うruby-extメーリングリストと数学関係の話題について話し合うruby-mathメーリングリストと
英語でrubyについて話し合うruby-talkメーリングリストもあります.参加方法はどれも同じです.
-[ruby-list-request@ml.ruby-lang.org]: mailto:ruby-list-request@ml.ruby-lang.org?subject=join
-[ruby-dev-request@ml.ruby-lang.org]: mailto:ruby-dev-request@ml.ruby-lang.org?subject=join
+[ruby-list-request@ruby-lang.org]: mailto:ruby-list-request@ruby-lang.org?subject=Join%20Ruby%20Mailing%20List&body=subscribe
+[ruby-dev-request@ruby-lang.org]: mailto:ruby-dev-request@ruby-lang.org?subject=Join%20Ruby%20Mailing%20List&body=subscribe
## コンパイル・インストール
@@ -152,7 +162,7 @@ UNIXであれば `configure` がほとんどの差異を吸収してくれるは
## 配布条件
-[COPYING.ja](https://docs.ruby-lang.org/en/master/COPYING_ja.html) ファイルを参照してください.
+[COPYING.ja](COPYING.ja) ファイルを参照してください.
## フィードバック
diff --git a/README.md b/README.md
index 8fb3786691..c445448c71 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[![Actions Status: MinGW](https://github.com/ruby/ruby/workflows/MinGW/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MinGW")
-[![Actions Status: RJIT](https://github.com/ruby/ruby/workflows/RJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"RJIT")
+[![Actions Status: MJIT](https://github.com/ruby/ruby/workflows/MJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MJIT")
[![Actions Status: Ubuntu](https://github.com/ruby/ruby/workflows/Ubuntu/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Ubuntu")
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0sy8rrxut4o0k960/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/ruby/branch/master)
@@ -24,20 +24,15 @@ It is simple, straightforward, and extensible.
* Dynamic Loading of Object Files (on some architectures)
* Highly Portable (works on many Unix-like/POSIX compatible platforms as
well as Windows, macOS, etc.) cf.
- https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Platform+Maintainers
+ https://github.com/ruby/ruby/blob/master/doc/maintainers.rdoc#label-Platform+Maintainers
-## How to get Ruby
+## How to get Ruby with Git
For a complete list of ways to install Ruby, including using third-party tools
like rvm, see:
https://www.ruby-lang.org/en/downloads/
-You can download release packages and the snapshot of the repository. If you want to
-download whole versions of Ruby, please visit https://www.ruby-lang.org/en/downloads/releases/.
-
-### Download with Git
-
The mirror of the Ruby source tree can be checked out with the following command:
$ git clone https://github.com/ruby/ruby.git
@@ -52,7 +47,7 @@ if you are a committer.
## How to build
-See [Building Ruby](https://docs.ruby-lang.org/en/master/contributing/building_ruby_md.html)
+see [Building Ruby](doc/contributing/building_ruby.md)
## Ruby home page
@@ -68,11 +63,11 @@ https://www.ruby-lang.org/
There is a mailing list to discuss Ruby. To subscribe to this list, please
send the following phrase:
- join
+ subscribe
-in the mail subject (not body) to the address [ruby-talk-request@ml.ruby-lang.org].
+in the mail body (not subject) to the address [ruby-talk-request@ruby-lang.org].
-[ruby-talk-request@ml.ruby-lang.org]: mailto:ruby-talk-request@ml.ruby-lang.org?subject=join
+[ruby-talk-request@ruby-lang.org]: mailto:ruby-talk-request@ruby-lang.org?subject=Join%20Ruby%20Mailing%20List&body=subscribe
## Copying
diff --git a/addr2line.c b/addr2line.c
index 2a69dd0966..e5f25293e2 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -8,14 +8,10 @@
**********************************************************************/
-#if defined(__clang__) && defined(__has_warning)
-#if __has_warning("-Wgnu-empty-initializer")
+#if defined(__clang__)
#pragma clang diagnostic ignored "-Wgnu-empty-initializer"
-#endif
-#if __has_warning("-Wgcc-compat")
#pragma clang diagnostic ignored "-Wgcc-compat"
#endif
-#endif
#include "ruby/internal/config.h"
#include "ruby/defines.h"
@@ -61,21 +57,8 @@ void *alloca();
# endif
# endif /* AIX */
# endif /* HAVE_ALLOCA_H */
-# ifndef UNREACHABLE
-# define UNREACHABLE __builtin_unreachable()
-# endif
-# ifndef UNREACHABLE_RETURN
-# define UNREACHABLE_RETURN(_) __builtin_unreachable()
-# endif
#endif /* __GNUC__ */
-#ifndef UNREACHABLE
-# define UNREACHABLE abort()
-#endif
-#ifndef UNREACHABLE_RETURN
-# define UNREACHABLE_RETURN(_) return (abort(), (_))
-#endif
-
#ifdef HAVE_DLADDR
# include <dlfcn.h>
#endif
@@ -144,7 +127,7 @@ void *alloca();
#define DW_LNE_define_file 0x03
#define DW_LNE_set_discriminator 0x04 /* DWARF4 */
-#define kprintf(...) fprintf(errout, "" __VA_ARGS__)
+PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
typedef struct line_info {
const char *dirname;
@@ -201,7 +184,7 @@ obj_dwarf_section_at(obj_info_t *obj, int n)
&obj->debug_line_str
};
if (n < 0 || DWARF_SECTION_COUNT <= n) {
- UNREACHABLE_RETURN(0);
+ abort();
}
return ary[n];
}
@@ -254,7 +237,7 @@ sleb128(const char **p)
}
static const char *
-get_nth_dirname(unsigned long dir, const char *p, FILE *errout)
+get_nth_dirname(unsigned long dir, const char *p)
{
if (!dir--) {
return "";
@@ -271,14 +254,10 @@ get_nth_dirname(unsigned long dir, const char *p, FILE *errout)
return p;
}
-static const char *parse_ver5_debug_line_header(
- const char *p, int idx, uint8_t format,
- obj_info_t *obj, const char **out_path,
- uint64_t *out_directory_index, FILE *errout);
+static const char *parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, obj_info_t *obj, const char **out_path, uint64_t *out_directory_index);
static void
-fill_filename(int file, uint8_t format, uint16_t version, const char *include_directories,
- const char *filenames, line_info_t *line, obj_info_t *obj, FILE *errout)
+fill_filename(int file, uint8_t format, uint16_t version, const char *include_directories, const char *filenames, line_info_t *line, obj_info_t *obj)
{
int i;
const char *p = filenames;
@@ -287,9 +266,9 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di
if (version >= 5) {
const char *path;
uint64_t directory_index = -1;
- parse_ver5_debug_line_header(filenames, file, format, obj, &path, &directory_index, errout);
+ parse_ver5_debug_line_header(filenames, file, format, obj, &path, &directory_index);
line->filename = path;
- parse_ver5_debug_line_header(include_directories, (int)directory_index, format, obj, &path, NULL, errout);
+ parse_ver5_debug_line_header(include_directories, (int)directory_index, format, obj, &path, NULL);
line->dirname = path;
}
else {
@@ -311,7 +290,7 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di
if (i == file) {
line->filename = filename;
- line->dirname = get_nth_dirname(dir, include_directories, errout);
+ line->dirname = get_nth_dirname(dir, include_directories);
}
}
}
@@ -320,7 +299,7 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di
static void
fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
uint8_t format, uint16_t version, const char *include_directories, const char *filenames,
- obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t *obj, line_info_t *lines, int offset)
{
int i;
addr += obj->base_addr - obj->vmaddr;
@@ -329,7 +308,7 @@ fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
/* We assume one line code doesn't result >100 bytes of native code.
We may want more reliable way eventually... */
if (addr < a && a < addr + 100) {
- fill_filename(file, format, version, include_directories, filenames, &lines[i], obj, errout);
+ fill_filename(file, format, version, include_directories, filenames, &lines[i], obj);
lines[i].line = line;
}
}
@@ -354,7 +333,7 @@ struct LineNumberProgramHeader {
};
static int
-parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgramHeader *header, FILE *errout)
+parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgramHeader *header)
{
const char *p = *pp;
header->unit_length = *(uint32_t *)p;
@@ -400,7 +379,7 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr
if (header->version >= 5) {
header->include_directories = p;
- p = parse_ver5_debug_line_header(p, -1, header->format, obj, NULL, NULL, errout);
+ p = parse_ver5_debug_line_header(p, -1, header->format, obj, NULL, NULL);
header->filenames = p;
}
else {
@@ -427,7 +406,7 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr
static int
parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
- obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t *obj, line_info_t *lines, int offset)
{
const char *p = (const char *)*debug_line;
struct LineNumberProgramHeader header;
@@ -444,7 +423,7 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
/* int epilogue_begin = 0; */
/* unsigned int isa = 0; */
- if (parse_debug_line_header(obj, &p, &header, errout))
+ if (parse_debug_line_header(obj, &p, &header))
return -1;
is_stmt = header.default_is_stmt;
@@ -455,7 +434,7 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
header.version, \
header.include_directories, \
header.filenames, \
- obj, lines, offset, errout); \
+ obj, lines, offset); \
/*basic_block = prologue_end = epilogue_begin = 0;*/ \
} while (0)
@@ -555,11 +534,11 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
static int
parse_debug_line(int num_traces, void **traces,
const char *debug_line, unsigned long size,
- obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t *obj, line_info_t *lines, int offset)
{
const char *debug_line_end = debug_line + size;
while (debug_line < debug_line_end) {
- if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset, errout))
+ if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset))
return -1;
}
if (debug_line != debug_line_end) {
@@ -572,7 +551,7 @@ parse_debug_line(int num_traces, void **traces,
/* read file and fill lines */
static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout);
+ obj_info_t **objp, line_info_t *lines, int offset);
static void
append_obj(obj_info_t **objp)
@@ -600,7 +579,7 @@ append_obj(obj_info_t **objp)
// check the path pattern of "/usr/lib/debug/usr/bin/ruby.debug"
static void
follow_debuglink(const char *debuglink, int num_traces, void **traces,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
static const char global_debug_dir[] = "/usr/lib/debug";
const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
@@ -626,13 +605,13 @@ follow_debuglink(const char *debuglink, int num_traces, void **traces,
o2 = *objp;
o2->base_addr = o1->base_addr;
o2->path = o1->path;
- fill_lines(num_traces, traces, 0, objp, lines, offset, errout);
+ fill_lines(num_traces, traces, 0, objp, lines, offset);
}
// check the path pattern of "/usr/lib/debug/.build-id/ab/cdef1234.debug"
static void
follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_traces, void **traces,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
static const char global_debug_dir[] = "/usr/lib/debug/.build-id/";
const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
@@ -657,7 +636,7 @@ follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_tr
o2 = *objp;
o2->base_addr = o1->base_addr;
o2->path = o1->path;
- fill_lines(num_traces, traces, 0, objp, lines, offset, errout);
+ fill_lines(num_traces, traces, 0, objp, lines, offset);
}
#endif
@@ -861,11 +840,7 @@ enum
DW_FORM_addrx1 = 0x29,
DW_FORM_addrx2 = 0x2a,
DW_FORM_addrx3 = 0x2b,
- DW_FORM_addrx4 = 0x2c,
-
- /* GNU extensions for referring to .gnu_debugaltlink dwz-compressed info */
- DW_FORM_GNU_ref_alt = 0x1f20,
- DW_FORM_GNU_strp_alt = 0x1f21
+ DW_FORM_addrx4 = 0x2c
};
/* Range list entry encodings */
@@ -1083,13 +1058,13 @@ di_read_debug_abbrev_cu(DebugInfoReader *reader)
}
static int
-di_read_debug_line_cu(DebugInfoReader *reader, FILE *errout)
+di_read_debug_line_cu(DebugInfoReader *reader)
{
const char *p;
struct LineNumberProgramHeader header;
p = (const char *)reader->debug_line_cu_end;
- if (parse_debug_line_header(reader->obj, &p, &header, errout))
+ if (parse_debug_line_header(reader->obj, &p, &header))
return -1;
reader->debug_line_cu_end = (char *)header.cu_end;
@@ -1169,32 +1144,25 @@ resolve_strx(DebugInfoReader *reader, uint64_t idx)
return reader->obj->debug_str.ptr + off;
}
-static bool
-debug_info_reader_read_addr_value_member(DebugInfoReader *reader, DebugInfoValue *v, int size)
+static void
+debug_info_reader_read_addr_value(DebugInfoReader *reader, DebugInfoValue *v)
{
- if (size == 4) {
+ if (reader->address_size == 4) {
set_uint_value(v, read_uint32(&reader->p));
- } else if (size == 8) {
+ } else if (reader->address_size == 8) {
set_uint_value(v, read_uint64(&reader->p));
} else {
- return false;
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ abort();
}
- return true;
}
-#define debug_info_reader_read_addr_value(reader, v, mem) \
- if (!debug_info_reader_read_addr_value_member((reader), (v), (reader)->mem)) { \
- kprintf("unknown " #mem ":%d", (reader)->mem); \
- return false; \
- }
-
-
-static bool
-debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v, FILE *errout)
+static void
+debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v)
{
switch (form) {
case DW_FORM_addr:
- debug_info_reader_read_addr_value(reader, v, address_size);
+ debug_info_reader_read_addr_value(reader, v);
break;
case DW_FORM_block2:
v->size = read_uint16(&reader->p);
@@ -1249,9 +1217,16 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
if (reader->current_version <= 2) {
// DWARF Version 2 specifies that references have
// the same size as an address on the target system
- debug_info_reader_read_addr_value(reader, v, address_size);
+ debug_info_reader_read_addr_value(reader, v);
} else {
- debug_info_reader_read_addr_value(reader, v, format);
+ if (reader->format == 4) {
+ set_uint_value(v, read_uint32(&reader->p));
+ } else if (reader->format == 8) {
+ set_uint_value(v, read_uint64(&reader->p));
+ } else {
+ fprintf(stderr,"unknown format:%d", reader->format);
+ abort();
+ }
}
break;
case DW_FORM_ref1:
@@ -1352,28 +1327,20 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
case DW_FORM_addrx4:
set_addr_idx_value(v, read_uint32(&reader->p));
break;
- /* we have no support for actually reading the real values of these refs out
- * of the .gnu_debugaltlink dwz-compressed debuginfo at the moment, but "read"
- * them anyway so that we advance the reader by the right amount. */
- case DW_FORM_GNU_ref_alt:
- case DW_FORM_GNU_strp_alt:
- read_uint(reader);
- set_uint_value(v, 0);
- break;
case 0:
goto fail;
break;
}
- return true;
+ return;
fail:
- kprintf("%d: unsupported form: %#"PRIx64"\n", __LINE__, form);
- return false;
+ fprintf(stderr, "%d: unsupported form: %#"PRIx64"\n", __LINE__, form);
+ exit(1);
}
/* find abbrev in current compilation unit */
static const char *
-di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout)
+di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number)
{
const char *p;
if (abbrev_number < ABBREV_TABLE_SIZE) {
@@ -1386,8 +1353,8 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout)
di_skip_die_attributes(&p);
for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
if (n == 0) {
- kprintf("%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number);
- return NULL;
+ fprintf(stderr,"%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number);
+ exit(1);
}
uleb128(&p); /* tag */
p++; /* has_children */
@@ -1398,52 +1365,52 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout)
#if 0
static void
-hexdump0(const unsigned char *p, size_t n, FILE *errout)
+hexdump0(const unsigned char *p, size_t n)
{
size_t i;
- kprintf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
+ fprintf(stderr, " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
for (i=0; i < n; i++){
switch (i & 15) {
case 0:
- kprintf("%02" PRIdSIZE ": %02X ", i/16, p[i]);
+ fprintf(stderr, "%02" PRIdSIZE ": %02X ", i/16, p[i]);
break;
case 15:
- kprintf("%02X\n", p[i]);
+ fprintf(stderr, "%02X\n", p[i]);
break;
default:
- kprintf("%02X ", p[i]);
+ fprintf(stderr, "%02X ", p[i]);
break;
}
}
if ((i & 15) != 15) {
- kprintf("\n");
+ fprintf(stderr, "\n");
}
}
-#define hexdump(p,n,e) hexdump0((const unsigned char *)p, n, e)
+#define hexdump(p,n) hexdump0((const unsigned char *)p, n)
static void
-div_inspect(DebugInfoValue *v, FILE *errout)
+div_inspect(DebugInfoValue *v)
{
switch (v->type) {
case VAL_uint:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:%"PRIx64"\n",__LINE__,v->type,v->size,v->as.uint64);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:%"PRIx64"\n",__LINE__,v->type,v->size,v->as.uint64);
break;
case VAL_int:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:%"PRId64"\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:%"PRId64"\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
break;
case VAL_cstr:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
break;
case VAL_data:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:\n",__LINE__,v->type,v->size);
- hexdump(v->as.ptr, 16, errout);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:\n",__LINE__,v->type,v->size);
+ hexdump(v->as.ptr, 16);
break;
}
}
#endif
static DIE *
-di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout)
+di_read_die(DebugInfoReader *reader, DIE *die)
{
uint64_t abbrev_number = uleb128(&reader->p);
if (abbrev_number == 0) {
@@ -1451,7 +1418,7 @@ di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout)
return NULL;
}
- if (!(reader->q = di_find_abbrev(reader, abbrev_number, errout))) return NULL;
+ reader->q = di_find_abbrev(reader, abbrev_number);
die->pos = reader->p - reader->obj->debug_info.ptr - 1;
die->tag = (int)uleb128(&reader->q); /* tag */
@@ -1463,26 +1430,26 @@ di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout)
}
static DebugInfoValue *
-di_read_record(DebugInfoReader *reader, DebugInfoValue *vp, FILE *errout)
+di_read_record(DebugInfoReader *reader, DebugInfoValue *vp)
{
uint64_t at = uleb128(&reader->q);
uint64_t form = uleb128(&reader->q);
if (!at || !form) return NULL;
vp->at = at;
vp->form = form;
- if (!debug_info_reader_read_value(reader, form, vp, errout)) return NULL;
+ debug_info_reader_read_value(reader, form, vp);
return vp;
}
-static bool
-di_skip_records(DebugInfoReader *reader, FILE *errout)
+static void
+di_skip_records(DebugInfoReader *reader)
{
for (;;) {
- DebugInfoValue v = {{0}};
+ DebugInfoValue v = {{}};
uint64_t at = uleb128(&reader->q);
uint64_t form = uleb128(&reader->q);
- if (!at || !form) return true;
- if (!debug_info_reader_read_value(reader, form, &v, errout)) return false;
+ if (!at || !form) return;
+ debug_info_reader_read_value(reader, form, &v);
}
}
@@ -1494,14 +1461,13 @@ typedef struct addr_header {
/* uint8_t segment_selector_size; */
} addr_header_t;
-static bool
-addr_header_init(obj_info_t *obj, addr_header_t *header, FILE *errout)
-{
+static void
+addr_header_init(obj_info_t *obj, addr_header_t *header) {
const char *p = obj->debug_addr.ptr;
header->ptr = p;
- if (!p) return true;
+ if (!p) return;
header->unit_length = *(uint32_t *)p;
p += sizeof(uint32_t);
@@ -1515,12 +1481,7 @@ addr_header_init(obj_info_t *obj, addr_header_t *header, FILE *errout)
p += 2; /* version */
header->address_size = *p++;
- if (header->address_size != 4 && header->address_size != 8) {
- kprintf("unknown address_size:%d", header->address_size);
- return false;
- }
p++; /* segment_selector_size */
- return true;
}
static uint64_t
@@ -1540,12 +1501,11 @@ typedef struct rnglists_header {
uint32_t offset_entry_count;
} rnglists_header_t;
-static bool
-rnglists_header_init(obj_info_t *obj, rnglists_header_t *header, FILE *errout)
-{
+static void
+rnglists_header_init(obj_info_t *obj, rnglists_header_t *header) {
const char *p = obj->debug_rnglists.ptr;
- if (!p) return true;
+ if (!p) return;
header->unit_length = *(uint32_t *)p;
p += sizeof(uint32_t);
@@ -1559,13 +1519,8 @@ rnglists_header_init(obj_info_t *obj, rnglists_header_t *header, FILE *errout)
p += 2; /* version */
header->address_size = *p++;
- if (header->address_size != 4 && header->address_size != 8) {
- kprintf("unknown address_size:%d", header->address_size);
- return false;
- }
p++; /* segment_selector_size */
header->offset_entry_count = *(uint32_t *)p;
- return true;
}
typedef struct {
@@ -1609,23 +1564,26 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v, addr_header_t *addr_header, uint64_
}
static uint64_t
-read_dw_form_addr(DebugInfoReader *reader, const char **ptr, FILE *errout)
+read_dw_form_addr(DebugInfoReader *reader, const char **ptr)
{
const char *p = *ptr;
*ptr = p + reader->address_size;
if (reader->address_size == 4) {
return read_uint32(&p);
- } else {
+ } else if (reader->address_size == 8) {
return read_uint64(&p);
+ } else {
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ abort();
}
}
static uintptr_t
-ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_header_t *rnglists_header, FILE *errout)
+ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_header_t *rnglists_header)
{
if (ptr->high_pc_set) {
if (ptr->ranges_set || !ptr->low_pc_set) {
- return UINTPTR_MAX;
+ exit(1);
}
if (ptr->low_pc <= addr && addr <= ptr->high_pc) {
return (uintptr_t)ptr->low_pc;
@@ -1674,15 +1632,15 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h
to = (uintptr_t)base + uleb128(&p);
break;
case DW_RLE_base_address:
- base = read_dw_form_addr(reader, &p, errout);
+ base = read_dw_form_addr(reader, &p);
base_valid = true;
break;
case DW_RLE_start_end:
- from = (uintptr_t)read_dw_form_addr(reader, &p, errout);
- to = (uintptr_t)read_dw_form_addr(reader, &p, errout);
+ from = (uintptr_t)read_dw_form_addr(reader, &p);
+ to = (uintptr_t)read_dw_form_addr(reader, &p);
break;
case DW_RLE_start_length:
- from = (uintptr_t)read_dw_form_addr(reader, &p, errout);
+ from = (uintptr_t)read_dw_form_addr(reader, &p);
to = from + uleb128(&p);
break;
}
@@ -1690,7 +1648,7 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h
return from;
}
}
- return 0;
+ return false;
}
p = reader->obj->debug_ranges.ptr + ptr->ranges;
for (;;) {
@@ -1711,42 +1669,42 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h
return (uintptr_t)ptr->low_pc;
}
}
- return 0;
+ return false;
}
#if 0
static void
-ranges_inspect(DebugInfoReader *reader, ranges_t *ptr, FILE *errout)
+ranges_inspect(DebugInfoReader *reader, ranges_t *ptr)
{
if (ptr->high_pc_set) {
if (ptr->ranges_set || !ptr->low_pc_set) {
- kprintf("low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
- return;
+ fprintf(stderr,"low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
+ exit(1);
}
- kprintf("low_pc:%"PRIx64" high_pc:%"PRIx64"\n",ptr->low_pc,ptr->high_pc);
+ fprintf(stderr,"low_pc:%"PRIx64" high_pc:%"PRIx64"\n",ptr->low_pc,ptr->high_pc);
}
else if (ptr->ranges_set) {
char *p = reader->obj->debug_ranges.ptr + ptr->ranges;
- kprintf("low_pc:%"PRIx64" ranges:%"PRIx64" %lx ",ptr->low_pc,ptr->ranges, p-reader->obj->mapped);
+ fprintf(stderr,"low_pc:%"PRIx64" ranges:%"PRIx64" %lx ",ptr->low_pc,ptr->ranges, p-reader->obj->mapped);
for (;;) {
uintptr_t from = read_uintptr(&p);
uintptr_t to = read_uintptr(&p);
if (!from && !to) break;
- kprintf("%"PRIx64"-%"PRIx64" ",ptr->low_pc+from,ptr->low_pc+to);
+ fprintf(stderr,"%"PRIx64"-%"PRIx64" ",ptr->low_pc+from,ptr->low_pc+to);
}
- kprintf("\n");
+ fprintf(stderr,"\n");
}
else if (ptr->low_pc_set) {
- kprintf("low_pc:%"PRIx64"\n",ptr->low_pc);
+ fprintf(stderr,"low_pc:%"PRIx64"\n",ptr->low_pc);
}
else {
- kprintf("empty\n");
+ fprintf(stderr,"empty\n");
}
}
#endif
static int
-di_read_cu(DebugInfoReader *reader, FILE *errout)
+di_read_cu(DebugInfoReader *reader)
{
uint64_t unit_length;
uint16_t version;
@@ -1773,23 +1731,23 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
debug_abbrev_offset = read_uint(reader);
reader->address_size = read_uint8(&reader->p);
}
- if (reader->address_size != 4 && reader->address_size != 8) {
- kprintf("unknown address_size:%d", reader->address_size);
- return -1;
- }
reader->q0 = reader->obj->debug_abbrev.ptr + debug_abbrev_offset;
reader->level = 0;
di_read_debug_abbrev_cu(reader);
- if (di_read_debug_line_cu(reader, errout)) return -1;
+ if (di_read_debug_line_cu(reader)) return -1;
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER_BUILD_DATE)
+ /* Though DWARF specifies "the applicable base address defaults to the base
+ address of the compilation unit", but GCC seems to use zero as default */
+#else
do {
DIE die;
- if (!di_read_die(reader, &die, errout)) continue;
+ if (!di_read_die(reader, &die)) continue;
if (die.tag != DW_TAG_compile_unit) {
- if (!di_skip_records(reader, errout)) return -1;
+ di_skip_records(reader);
break;
}
@@ -1797,11 +1755,11 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
reader->current_addr_base = 0;
reader->current_rnglists_base = 0;
- DebugInfoValue low_pc = {{0}};
+ DebugInfoValue low_pc = {{}};
/* enumerate abbrev */
for (;;) {
- DebugInfoValue v = {{0}};
- if (!di_read_record(reader, &v, errout)) break;
+ DebugInfoValue v = {{}};
+ if (!di_read_record(reader, &v)) break;
switch (v.at) {
case DW_AT_low_pc:
// clang may output DW_AT_addr_base after DW_AT_low_pc.
@@ -1826,19 +1784,19 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
break;
case VAL_addr:
{
- addr_header_t header = {0};
- if (!addr_header_init(reader->obj, &header, errout)) return -1;
+ addr_header_t header;
+ addr_header_init(reader->obj, &header);
reader->current_low_pc = read_addr(&header, reader->current_addr_base, low_pc.as.addr_idx);
}
break;
}
} while (0);
-
+#endif
return 0;
}
static void
-read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line, FILE *errout)
+read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line)
{
const char *p = reader->p;
const char *q = reader->q;
@@ -1863,12 +1821,12 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o
default:
goto finish;
}
- if (!di_read_die(reader, &die, errout)) goto finish;
+ if (!di_read_die(reader, &die)) goto finish;
/* enumerate abbrev */
for (;;) {
- DebugInfoValue v = {{0}};
- if (!di_read_record(reader, &v, errout)) break;
+ DebugInfoValue v = {{}};
+ if (!di_read_record(reader, &v)) break;
switch (v.at) {
case DW_AT_name:
line->sname = get_cstr_value(&v);
@@ -1882,44 +1840,43 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o
reader->level = level;
}
-static bool
+static void
debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
- line_info_t *lines, int offset, FILE *errout)
-{
+ line_info_t *lines, int offset) {
- addr_header_t addr_header = {0};
- if (!addr_header_init(reader->obj, &addr_header, errout)) return false;
+ addr_header_t addr_header = {};
+ addr_header_init(reader->obj, &addr_header);
- rnglists_header_t rnglists_header = {0};
- if (!rnglists_header_init(reader->obj, &rnglists_header, errout)) return false;
+ rnglists_header_t rnglists_header = {};
+ rnglists_header_init(reader->obj, &rnglists_header);
while (reader->p < reader->cu_end) {
DIE die;
- ranges_t ranges = {0};
- line_info_t line = {0};
+ ranges_t ranges = {};
+ line_info_t line = {};
- if (!di_read_die(reader, &die, errout)) continue;
- /* kprintf("%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */
+ if (!di_read_die(reader, &die)) continue;
+ /* fprintf(stderr,"%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */
if (die.tag != DW_TAG_subprogram && die.tag != DW_TAG_inlined_subroutine) {
skip_die:
- if (!di_skip_records(reader, errout)) return false;
+ di_skip_records(reader);
continue;
}
/* enumerate abbrev */
for (;;) {
- DebugInfoValue v = {{0}};
+ DebugInfoValue v = {{}};
/* ptrdiff_t pos = reader->p - reader->p0; */
- if (!di_read_record(reader, &v, errout)) break;
- /* kprintf("\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */
- /* div_inspect(&v, errout); */
+ if (!di_read_record(reader, &v)) break;
+ /* fprintf(stderr,"\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */
+ /* div_inspect(&v); */
switch (v.at) {
case DW_AT_name:
line.sname = get_cstr_value(&v);
break;
case DW_AT_call_file:
- fill_filename((int)v.as.uint64, reader->debug_line_format, reader->debug_line_version, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj, errout);
+ fill_filename((int)v.as.uint64, reader->debug_line_format, reader->debug_line_version, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj);
break;
case DW_AT_call_line:
line.line = (int)v.as.uint64;
@@ -1935,19 +1892,18 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
/* 1 or 3 */
break; /* goto skip_die; */
case DW_AT_abstract_origin:
- read_abstract_origin(reader, v.form, v.as.uint64, &line, errout);
+ read_abstract_origin(reader, v.form, v.as.uint64, &line);
break; /* goto skip_die; */
}
}
- /* ranges_inspect(reader, &ranges, errout); */
- /* kprintf("%d:%tx: %x ",__LINE__,diepos,die.tag); */
+ /* ranges_inspect(reader, &ranges); */
+ /* fprintf(stderr,"%d:%tx: %x ",__LINE__,diepos,die.tag); */
for (int i=offset; i < num_traces; i++) {
uintptr_t addr = (uintptr_t)traces[i];
uintptr_t offset = addr - reader->obj->base_addr + reader->obj->vmaddr;
- uintptr_t saddr = ranges_include(reader, &ranges, offset, &rnglists_header, errout);
- if (saddr == UINTPTR_MAX) return false;
+ uintptr_t saddr = ranges_include(reader, &ranges, offset, &rnglists_header);
if (saddr) {
- /* kprintf("%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */
+ /* fprintf(stdout, "%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */
if (lines[i].sname) {
line_info_t *lp = malloc(sizeof(line_info_t));
memcpy(lp, &lines[i], sizeof(line_info_t));
@@ -1964,7 +1920,6 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
}
}
}
- return true;
}
// This function parses the following attributes of Line Number Program Header in DWARF 5:
@@ -1983,10 +1938,7 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
//
// It records DW_LNCT_path and DW_LNCT_directory_index at the index "idx".
static const char *
-parse_ver5_debug_line_header(const char *p, int idx, uint8_t format,
- obj_info_t *obj, const char **out_path,
- uint64_t *out_directory_index, FILE *errout)
-{
+parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, obj_info_t *obj, const char **out_path, uint64_t *out_directory_index) {
int i, j;
int entry_format_count = *(uint8_t *)p++;
const char *entry_format = p;
@@ -1996,17 +1948,17 @@ parse_ver5_debug_line_header(const char *p, int idx, uint8_t format,
int entry_count = (int)uleb128(&p);
- DebugInfoReader reader = {0};
+ DebugInfoReader reader;
debug_info_reader_init(&reader, obj);
reader.format = format;
reader.p = p;
for (j = 0; j < entry_count; j++) {
const char *format = entry_format;
for (i = 0; i < entry_format_count; i++) {
- DebugInfoValue v = {{0}};
+ DebugInfoValue v = {{}};
unsigned long dw_lnct = uleb128(&format);
unsigned long dw_form = uleb128(&format);
- if (!debug_info_reader_read_value(&reader, dw_form, &v, errout)) return 0;
+ debug_info_reader_read_value(&reader, dw_form, &v);
if (dw_lnct == 1 /* DW_LNCT_path */ && v.type == VAL_cstr && out_path)
*out_path = v.as.ptr + v.off;
if (dw_lnct == 2 /* DW_LNCT_directory_index */ && v.type == VAL_uint && out_directory_index)
@@ -2051,7 +2003,7 @@ fail:
/* read file and fill lines */
static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
int i, j;
char *shstr;
@@ -2211,10 +2163,9 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
debug_info_reader_init(&reader, obj);
i = 0;
while (reader.p < reader.pend) {
- /* kprintf("%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */
- if (di_read_cu(&reader, errout)) goto use_symtab;
- if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout))
- goto use_symtab;
+ /* fprintf(stderr, "%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */
+ if (di_read_cu(&reader)) goto use_symtab;
+ debug_info_read(&reader, num_traces, traces, lines, offset);
}
}
else {
@@ -2254,14 +2205,14 @@ use_symtab:
if (gnu_debuglink_shdr && check_debuglink) {
follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
num_traces, traces,
- objp, lines, offset, errout);
+ objp, lines, offset);
}
if (note_gnu_build_id && check_debuglink) {
ElfW(Nhdr) *nhdr = (ElfW(Nhdr)*) (file + note_gnu_build_id->sh_offset);
const char *build_id = (char *)(nhdr + 1) + nhdr->n_namesz;
follow_debuglink_build_id(build_id, nhdr->n_descsz,
num_traces, traces,
- objp, lines, offset, errout);
+ objp, lines, offset);
}
goto finish;
}
@@ -2269,7 +2220,7 @@ use_symtab:
if (parse_debug_line(num_traces, traces,
obj->debug_line.ptr,
obj->debug_line.size,
- obj, lines, offset, errout) == -1)
+ obj, lines, offset) == -1)
goto fail;
finish:
@@ -2281,7 +2232,7 @@ fail:
/* read file and fill lines */
static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
# ifdef __LP64__
# define LP(x) x##_64
@@ -2360,13 +2311,13 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
struct fat_header *fat = (struct fat_header *)file;
char *q = file + sizeof(*fat);
uint32_t nfat_arch = __builtin_bswap32(fat->nfat_arch);
- /* kprintf("%d: fat:%s %d\n",__LINE__, binary_filename,nfat_arch); */
+ /* fprintf(stderr,"%d: fat:%s %d\n",__LINE__, binary_filename,nfat_arch); */
for (uint32_t i = 0; i < nfat_arch; i++) {
struct fat_arch *arch = (struct fat_arch *)q;
cpu_type_t cputype = __builtin_bswap32(arch->cputype);
cpu_subtype_t cpusubtype = __builtin_bswap32(arch->cpusubtype);
uint32_t offset = __builtin_bswap32(arch->offset);
- /* kprintf("%d: fat %d %x/%x %x/%x\n",__LINE__, i, mhp->cputype,mhp->cpusubtype, cputype,cpusubtype); */
+ /* fprintf(stderr,"%d: fat %d %x/%x %x/%x\n",__LINE__, i, mhp->cputype,mhp->cpusubtype, cputype,cpusubtype); */
if (mhp->cputype == cputype &&
(cpu_subtype_t)(mhp->cpusubtype & ~CPU_SUBTYPE_MASK) == cpusubtype) {
p = file + offset;
@@ -2482,16 +2433,15 @@ found_mach_header:
DebugInfoReader reader;
debug_info_reader_init(&reader, obj);
while (reader.p < reader.pend) {
- if (di_read_cu(&reader, errout)) goto fail;
- if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout))
- goto fail;
+ if (di_read_cu(&reader)) goto fail;
+ debug_info_read(&reader, num_traces, traces, lines, offset);
}
}
if (parse_debug_line(num_traces, traces,
obj->debug_line.ptr,
obj->debug_line.size,
- obj, lines, offset, errout) == -1)
+ obj, lines, offset) == -1)
goto fail;
return dladdr_fbase;
@@ -2504,7 +2454,7 @@ fail:
#if defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/sysctl.h>
#endif
-/* ssize_t main_exe_path(FILE *errout)
+/* ssize_t main_exe_path(void)
*
* store the path of the main executable to `binary_filename`,
* and returns strlen(binary_filename).
@@ -2512,7 +2462,7 @@ fail:
*/
#if defined(__linux__) || defined(__NetBSD__)
static ssize_t
-main_exe_path(FILE *errout)
+main_exe_path(void)
{
# if defined(__linux__)
# define PROC_SELF_EXE "/proc/self/exe"
@@ -2526,7 +2476,7 @@ main_exe_path(FILE *errout)
}
#elif defined(__FreeBSD__) || defined(__DragonFly__)
static ssize_t
-main_exe_path(FILE *errout)
+main_exe_path(void)
{
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
size_t len = PATH_MAX;
@@ -2540,7 +2490,7 @@ main_exe_path(FILE *errout)
}
#elif defined(HAVE_LIBPROC_H)
static ssize_t
-main_exe_path(FILE *errout)
+main_exe_path(void)
{
int len = proc_pidpath(getpid(), binary_filename, PATH_MAX);
if (len == 0) return 0;
@@ -2552,7 +2502,7 @@ main_exe_path(FILE *errout)
#endif
static void
-print_line0(line_info_t *line, void *address, FILE *errout)
+print_line0(line_info_t *line, void *address)
{
uintptr_t addr = (uintptr_t)address;
uintptr_t d = addr - line->saddr;
@@ -2593,16 +2543,16 @@ print_line0(line_info_t *line, void *address, FILE *errout)
}
static void
-print_line(line_info_t *line, void *address, FILE *errout)
+print_line(line_info_t *line, void *address)
{
- print_line0(line, address, errout);
+ print_line0(line, address);
if (line->next) {
- print_line(line->next, NULL, errout);
+ print_line(line->next, NULL);
}
}
void
-rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
+rb_dump_backtrace_with_lines(int num_traces, void **traces)
{
int i;
/* async-signal unsafe */
@@ -2614,14 +2564,14 @@ rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
#ifdef HAVE_MAIN_EXE_PATH
char *main_path = NULL; /* used on printing backtrace */
ssize_t len;
- if ((len = main_exe_path(errout)) > 0) {
+ if ((len = main_exe_path()) > 0) {
main_path = (char *)alloca(len + 1);
if (main_path) {
uintptr_t addr;
memcpy(main_path, binary_filename, len+1);
append_obj(&obj);
obj->path = main_path;
- addr = fill_lines(num_traces, traces, 1, &obj, lines, -1, errout);
+ addr = fill_lines(num_traces, traces, 1, &obj, lines, -1);
if (addr != (uintptr_t)-1) {
dladdr_fbases[0] = (void *)addr;
}
@@ -2658,7 +2608,7 @@ rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
lines[i].saddr = (uintptr_t)info.dli_saddr;
}
strlcpy(binary_filename, path, PATH_MAX);
- if (fill_lines(num_traces, traces, 1, &obj, lines, i, errout) == (uintptr_t)-1)
+ if (fill_lines(num_traces, traces, 1, &obj, lines, i) == (uintptr_t)-1)
break;
}
next_line:
@@ -2667,7 +2617,7 @@ next_line:
/* output */
for (i = 0; i < num_traces; i++) {
- print_line(&lines[i], traces[i], errout);
+ print_line(&lines[i], traces[i]);
/* FreeBSD's backtrace may show _start and so on */
if (lines[i].sname && strcmp("main", lines[i].sname) == 0)
@@ -2701,8 +2651,435 @@ next_line:
free(dladdr_fbases);
}
-#undef kprintf
+/* From FreeBSD's lib/libstand/printf.c */
+/*-
+ * Copyright (c) 1986, 1988, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
+ */
+
+#include <stdarg.h>
+#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
+static inline int toupper(int c) { return ('A' <= c && c <= 'Z') ? (c&0x5f) : c; }
+#define hex2ascii(hex) (hex2ascii_data[hex])
+static const char hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+static inline int imax(int a, int b) { return (a > b ? a : b); }
+static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
+
+static void putce(int c)
+{
+ char s[1];
+ ssize_t ret;
+
+ s[0] = (char)c;
+ ret = write(2, s, 1);
+ (void)ret;
+}
+
+static int
+kprintf(const char *fmt, ...)
+{
+ va_list ap;
+ int retval;
+ va_start(ap, fmt);
+ retval = kvprintf(fmt, putce, NULL, 10, ap);
+ va_end(ap);
+ return retval;
+}
+
+/*
+ * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
+ * order; return an optional length and a pointer to the last character
+ * written in the buffer (i.e., the first character of the string).
+ * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
+ */
+static char *
+ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
+{
+ char *p, c;
+
+ p = nbuf;
+ *p = '\0';
+ do {
+ c = hex2ascii(num % base);
+ *++p = upper ? toupper(c) : c;
+ } while (num /= base);
+ if (lenp)
+ *lenp = (int)(p - nbuf);
+ return (p);
+}
+
+/*
+ * Scaled down version of printf(3).
+ *
+ * Two additional formats:
+ *
+ * The format %b is supported to decode error registers.
+ * Its usage is:
+ *
+ * printf("reg=%b\n", regval, "<base><arg>*");
+ *
+ * where <base> is the output base expressed as a control character, e.g.
+ * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
+ * the first of which gives the bit number to be inspected (origin 1), and
+ * the next characters (up to a control character, i.e. a character <= 32),
+ * give the name of the register. Thus:
+ *
+ * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
+ *
+ * would produce output:
+ *
+ * reg=3<BITTWO,BITONE>
+ *
+ * XXX: %D -- Hexdump, takes pointer and separator string:
+ * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
+ * ("%*D", len, ptr, " " -> XX XX XX XX ...
+ */
+static int
+kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
+{
+#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
+ char nbuf[MAXNBUF];
+ char *d;
+ const char *p, *percent, *q;
+ unsigned char *up;
+ int ch, n;
+ uintmax_t num;
+ int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
+ int cflag, hflag, jflag, tflag, zflag;
+ int dwidth, upper;
+ char padc;
+ int stop = 0, retval = 0;
+
+ num = 0;
+ if (!func)
+ d = (char *) arg;
+ else
+ d = NULL;
+
+ if (fmt == NULL)
+ fmt = "(fmt null)\n";
+
+ if (radix < 2 || radix > 36)
+ radix = 10;
+
+ for (;;) {
+ padc = ' ';
+ width = 0;
+ while ((ch = (unsigned char)*fmt++) != '%' || stop) {
+ if (ch == '\0')
+ return (retval);
+ PCHAR(ch);
+ }
+ percent = fmt - 1;
+ qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
+ sign = 0; dot = 0; dwidth = 0; upper = 0;
+ cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
+reswitch: switch (ch = (unsigned char)*fmt++) {
+ case '.':
+ dot = 1;
+ goto reswitch;
+ case '#':
+ sharpflag = 1;
+ goto reswitch;
+ case '+':
+ sign = 1;
+ goto reswitch;
+ case '-':
+ ladjust = 1;
+ goto reswitch;
+ case '%':
+ PCHAR(ch);
+ break;
+ case '*':
+ if (!dot) {
+ width = va_arg(ap, int);
+ if (width < 0) {
+ ladjust = !ladjust;
+ width = -width;
+ }
+ } else {
+ dwidth = va_arg(ap, int);
+ }
+ goto reswitch;
+ case '0':
+ if (!dot) {
+ padc = '0';
+ goto reswitch;
+ }
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (n = 0;; ++fmt) {
+ n = n * 10 + ch - '0';
+ ch = *fmt;
+ if (ch < '0' || ch > '9')
+ break;
+ }
+ if (dot)
+ dwidth = n;
+ else
+ width = n;
+ goto reswitch;
+ case 'b':
+ num = (unsigned int)va_arg(ap, int);
+ p = va_arg(ap, char *);
+ for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
+ PCHAR(*q--);
+
+ if (num == 0)
+ break;
+
+ for (tmp = 0; *p;) {
+ n = *p++;
+ if (num & (1 << (n - 1))) {
+ PCHAR(tmp ? ',' : '<');
+ for (; (n = *p) > ' '; ++p)
+ PCHAR(n);
+ tmp = 1;
+ } else
+ for (; *p > ' '; ++p)
+ continue;
+ }
+ if (tmp)
+ PCHAR('>');
+ break;
+ case 'c':
+ PCHAR(va_arg(ap, int));
+ break;
+ case 'D':
+ up = va_arg(ap, unsigned char *);
+ p = va_arg(ap, char *);
+ if (!width)
+ width = 16;
+ while(width--) {
+ PCHAR(hex2ascii(*up >> 4));
+ PCHAR(hex2ascii(*up & 0x0f));
+ up++;
+ if (width)
+ for (q=p;*q;q++)
+ PCHAR(*q);
+ }
+ break;
+ case 'd':
+ case 'i':
+ base = 10;
+ sign = 1;
+ goto handle_sign;
+ case 'h':
+ if (hflag) {
+ hflag = 0;
+ cflag = 1;
+ } else
+ hflag = 1;
+ goto reswitch;
+ case 'j':
+ jflag = 1;
+ goto reswitch;
+ case 'l':
+ if (lflag) {
+ lflag = 0;
+ qflag = 1;
+ } else
+ lflag = 1;
+ goto reswitch;
+ case 'n':
+ if (jflag)
+ *(va_arg(ap, intmax_t *)) = retval;
+ else if (qflag)
+ *(va_arg(ap, int64_t *)) = retval;
+ else if (lflag)
+ *(va_arg(ap, long *)) = retval;
+ else if (zflag)
+ *(va_arg(ap, size_t *)) = retval;
+ else if (hflag)
+ *(va_arg(ap, short *)) = retval;
+ else if (cflag)
+ *(va_arg(ap, char *)) = retval;
+ else
+ *(va_arg(ap, int *)) = retval;
+ break;
+ case 'o':
+ base = 8;
+ goto handle_nosign;
+ case 'p':
+ base = 16;
+ sharpflag = (width == 0);
+ sign = 0;
+ num = (uintptr_t)va_arg(ap, void *);
+ goto number;
+ case 'q':
+ qflag = 1;
+ goto reswitch;
+ case 'r':
+ base = radix;
+ if (sign)
+ goto handle_sign;
+ goto handle_nosign;
+ case 's':
+ p = va_arg(ap, char *);
+ if (p == NULL)
+ p = "(null)";
+ if (!dot)
+ n = (int)strlen (p);
+ else
+ for (n = 0; n < dwidth && p[n]; n++)
+ continue;
+
+ width -= n;
+
+ if (!ladjust && width > 0)
+ while (width--)
+ PCHAR(padc);
+ while (n--)
+ PCHAR(*p++);
+ if (ladjust && width > 0)
+ while (width--)
+ PCHAR(padc);
+ break;
+ case 't':
+ tflag = 1;
+ goto reswitch;
+ case 'u':
+ base = 10;
+ goto handle_nosign;
+ case 'X':
+ upper = 1;
+ case 'x':
+ base = 16;
+ goto handle_nosign;
+ case 'y':
+ base = 16;
+ sign = 1;
+ goto handle_sign;
+ case 'z':
+ zflag = 1;
+ goto reswitch;
+handle_nosign:
+ sign = 0;
+ if (jflag)
+ num = va_arg(ap, uintmax_t);
+ else if (qflag)
+ num = va_arg(ap, uint64_t);
+ else if (tflag)
+ num = va_arg(ap, ptrdiff_t);
+ else if (lflag)
+ num = va_arg(ap, unsigned long);
+ else if (zflag)
+ num = va_arg(ap, size_t);
+ else if (hflag)
+ num = (unsigned short)va_arg(ap, int);
+ else if (cflag)
+ num = (unsigned char)va_arg(ap, int);
+ else
+ num = va_arg(ap, unsigned int);
+ goto number;
+handle_sign:
+ if (jflag)
+ num = va_arg(ap, intmax_t);
+ else if (qflag)
+ num = va_arg(ap, int64_t);
+ else if (tflag)
+ num = va_arg(ap, ptrdiff_t);
+ else if (lflag)
+ num = va_arg(ap, long);
+ else if (zflag)
+ num = va_arg(ap, ssize_t);
+ else if (hflag)
+ num = (short)va_arg(ap, int);
+ else if (cflag)
+ num = (char)va_arg(ap, int);
+ else
+ num = va_arg(ap, int);
+number:
+ if (sign && (intmax_t)num < 0) {
+ neg = 1;
+ num = -(intmax_t)num;
+ }
+ p = ksprintn(nbuf, num, base, &n, upper);
+ tmp = 0;
+ if (sharpflag && num != 0) {
+ if (base == 8)
+ tmp++;
+ else if (base == 16)
+ tmp += 2;
+ }
+ if (neg)
+ tmp++;
+
+ if (!ladjust && padc == '0')
+ dwidth = width - tmp;
+ width -= tmp + imax(dwidth, n);
+ dwidth -= n;
+ if (!ladjust)
+ while (width-- > 0)
+ PCHAR(' ');
+ if (neg)
+ PCHAR('-');
+ if (sharpflag && num != 0) {
+ if (base == 8) {
+ PCHAR('0');
+ } else if (base == 16) {
+ PCHAR('0');
+ PCHAR('x');
+ }
+ }
+ while (dwidth-- > 0)
+ PCHAR('0');
+
+ while (*p)
+ PCHAR(*p--);
+
+ if (ladjust)
+ while (width-- > 0)
+ PCHAR(' ');
+
+ break;
+ default:
+ while (percent < fmt)
+ PCHAR(*percent++);
+ /*
+ * Since we ignore an formatting argument it is no
+ * longer safe to obey the remaining formatting
+ * arguments as the arguments will no longer match
+ * the format specs.
+ */
+ stop = 1;
+ break;
+ }
+ }
+#undef PCHAR
+}
#else /* defined(USE_ELF) */
#error not supported
#endif
diff --git a/addr2line.h b/addr2line.h
index ff8e476b92..f09b665800 100644
--- a/addr2line.h
+++ b/addr2line.h
@@ -12,10 +12,8 @@
#if (defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H))
-#include <stdio.h>
-
void
-rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout);
+rb_dump_backtrace_with_lines(int num_traces, void **traces);
#endif /* USE_ELF */
diff --git a/array.c b/array.c
index 1032696308..b76e9a64a3 100644
--- a/array.c
+++ b/array.c
@@ -28,6 +28,7 @@
#include "ruby/encoding.h"
#include "ruby/st.h"
#include "ruby/util.h"
+#include "transient_heap.h"
#include "builtin.h"
#if !ARRAY_DEBUG
@@ -46,8 +47,13 @@ VALUE rb_cArray;
* 2: RARRAY_SHARED_FLAG (equal to ELTS_SHARED)
* The array is shared. The buffer this array points to is owned by
* another array (the shared root).
+ * if USE_RVARGC
* 3-9: RARRAY_EMBED_LEN
* The length of the array when RARRAY_EMBED_FLAG is set.
+ * else
+ * 3-4: RARRAY_EMBED_LEN
+ * The length of the array when RARRAY_EMBED_FLAG is set.
+ * endif
* 12: RARRAY_SHARED_ROOT_FLAG
* The array is a shared root that does reference counting. The buffer
* this array points to is owned by this array but may be pointed to
@@ -57,6 +63,8 @@ VALUE rb_cArray;
* they cannot be modified. Not updating the reference count
* improves copy-on-write performance. Their reference count is
* assumed to be infinity.
+ * 13: RARRAY_TRANSIENT_FLAG
+ * The buffer of the array is allocated on the transient heap.
* 14: RARRAY_PTR_IN_USE_FLAG
* The buffer of the array is in use. This is only used during
* debugging.
@@ -94,6 +102,7 @@ should_be_T_ARRAY(VALUE ary)
#define FL_SET_EMBED(a) do { \
assert(!ARY_SHARED_P(a)); \
FL_SET((a), RARRAY_EMBED_FLAG); \
+ RARY_TRANSIENT_UNSET(a); \
ary_verify(a); \
} while (0)
@@ -152,6 +161,16 @@ should_be_T_ARRAY(VALUE ary)
RARRAY(ary)->as.heap.aux.capa = (n); \
} while (0)
+#define ARY_SET_SHARED(ary, value) do { \
+ const VALUE _ary_ = (ary); \
+ const VALUE _value_ = (value); \
+ assert(!ARY_EMBED_P(_ary_)); \
+ assert(ARY_SHARED_P(_ary_)); \
+ assert(!OBJ_FROZEN(_ary_)); \
+ assert(ARY_SHARED_ROOT_P(_value_) || OBJ_FROZEN(_value_)); \
+ RB_OBJ_WRITE(_ary_, &RARRAY(_ary_)->as.heap.aux.shared_root, _value_); \
+} while (0)
+
#define ARY_SHARED_ROOT_OCCUPIED(ary) (!OBJ_FROZEN(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1)
#define ARY_SET_SHARED_ROOT_REFCNT(ary, value) do { \
assert(ARY_SHARED_ROOT_P(ary)); \
@@ -162,6 +181,7 @@ should_be_T_ARRAY(VALUE ary)
#define FL_SET_SHARED_ROOT(ary) do { \
assert(!OBJ_FROZEN(ary)); \
assert(!ARY_EMBED_P(ary)); \
+ assert(!RARRAY_TRANSIENT_P(ary)); \
FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
} while (0)
@@ -178,9 +198,13 @@ ARY_SET(VALUE a, long i, VALUE v)
static long
ary_embed_capa(VALUE ary)
{
+#if USE_RVARGC
size_t size = rb_gc_obj_slot_size(ary) - offsetof(struct RArray, as.ary);
assert(size % sizeof(VALUE) == 0);
return size / sizeof(VALUE);
+#else
+ return RARRAY_EMBED_LEN_MAX;
+#endif
}
static size_t
@@ -192,7 +216,11 @@ ary_embed_size(long capa)
static bool
ary_embeddable_p(long capa)
{
+#if USE_RVARGC
return rb_gc_size_allocatable_p(ary_embed_size(capa));
+#else
+ return capa <= RARRAY_EMBED_LEN_MAX;
+#endif
}
bool
@@ -238,19 +266,20 @@ ary_verify_(VALUE ary, const char *file, int line)
if (ARY_SHARED_P(ary)) {
VALUE root = ARY_SHARED_ROOT(ary);
const VALUE *ptr = ARY_HEAP_PTR(ary);
- const VALUE *root_ptr = RARRAY_CONST_PTR(root);
+ const VALUE *root_ptr = RARRAY_CONST_PTR_TRANSIENT(root);
long len = ARY_HEAP_LEN(ary), root_len = RARRAY_LEN(root);
assert(ARY_SHARED_ROOT_P(root) || OBJ_FROZEN(root));
assert(root_ptr <= ptr && ptr + len <= root_ptr + root_len);
ary_verify(root);
}
else if (ARY_EMBED_P(ary)) {
+ assert(!RARRAY_TRANSIENT_P(ary));
assert(!ARY_SHARED_P(ary));
assert(RARRAY_LEN(ary) <= ary_embed_capa(ary));
}
else {
#if 1
- const VALUE *ptr = RARRAY_CONST_PTR(ary);
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
long i, len = RARRAY_LEN(ary);
volatile VALUE v;
if (len > 1) len = 1; /* check only HEAD */
@@ -261,6 +290,14 @@ ary_verify_(VALUE ary, const char *file, int line)
#endif
}
+#if USE_TRANSIENT_HEAP
+ if (RARRAY_TRANSIENT_P(ary)) {
+ assert(rb_transient_heap_managed_ptr_p(RARRAY_CONST_PTR_TRANSIENT(ary)));
+ }
+#endif
+
+ rb_transient_heap_verify();
+
return ary;
}
@@ -279,7 +316,7 @@ rb_ary_ptr_use_start(VALUE ary)
#if ARRAY_DEBUG
FL_SET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
#endif
- return (VALUE *)RARRAY_CONST_PTR(ary);
+ return (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary);
}
void
@@ -301,7 +338,7 @@ rb_mem_clear(VALUE *mem, long size)
static void
ary_mem_clear(VALUE ary, long beg, long size)
{
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
rb_mem_clear(ptr + beg, size);
});
}
@@ -317,7 +354,7 @@ memfill(register VALUE *mem, register long size, register VALUE val)
static void
ary_memfill(VALUE ary, long beg, long size, VALUE val)
{
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
memfill(ptr + beg, size, val);
RB_OBJ_WRITTEN(ary, Qundef, val);
});
@@ -330,13 +367,13 @@ ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_
if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) {
rb_gc_writebarrier_remember(buff_owner_ary);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMCPY(ptr+beg, argv, VALUE, argc);
});
}
else {
int i;
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
for (i=0; i<argc; i++) {
RB_OBJ_WRITE(buff_owner_ary, &ptr[i+beg], argv[i]);
}
@@ -351,46 +388,143 @@ ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
}
static VALUE *
-ary_heap_alloc(size_t capa)
+ary_heap_alloc(VALUE ary, size_t capa)
{
- return ALLOC_N(VALUE, capa);
+ VALUE *ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * capa);
+
+ if (ptr != NULL) {
+ RARY_TRANSIENT_SET(ary);
+ }
+ else {
+ RARY_TRANSIENT_UNSET(ary);
+ ptr = ALLOC_N(VALUE, capa);
+ }
+
+ return ptr;
}
static void
ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size)
{
- ruby_sized_xfree((void *)ptr, size);
+ if (RARRAY_TRANSIENT_P(ary)) {
+ /* ignore it */
+ }
+ else {
+ ruby_sized_xfree((void *)ptr, size);
+ }
}
static void
ary_heap_free(VALUE ary)
{
- ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
+ if (RARRAY_TRANSIENT_P(ary)) {
+ RARY_TRANSIENT_UNSET(ary);
+ }
+ else {
+ ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
+ }
}
static size_t
ary_heap_realloc(VALUE ary, size_t new_capa)
{
- SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, ARY_HEAP_CAPA(ary));
+ size_t alloc_capa = new_capa;
+ size_t old_capa = ARY_HEAP_CAPA(ary);
+
+ if (RARRAY_TRANSIENT_P(ary)) {
+ if (new_capa <= old_capa) {
+ /* do nothing */
+ alloc_capa = old_capa;
+ }
+ else {
+ VALUE *new_ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * new_capa);
+
+ if (new_ptr == NULL) {
+ new_ptr = ALLOC_N(VALUE, new_capa);
+ RARY_TRANSIENT_UNSET(ary);
+ }
+
+ MEMCPY(new_ptr, ARY_HEAP_PTR(ary), VALUE, old_capa);
+ ARY_SET_PTR(ary, new_ptr);
+ }
+ }
+ else {
+ SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, old_capa);
+ }
+ ary_verify(ary);
+
+ return alloc_capa;
+}
+
+#if USE_TRANSIENT_HEAP
+static inline void
+rb_ary_transient_heap_evacuate_(VALUE ary, int transient, int promote)
+{
+ if (transient) {
+ assert(!ARY_SHARED_ROOT_P(ary));
+
+ VALUE *new_ptr;
+ const VALUE *old_ptr = ARY_HEAP_PTR(ary);
+ long capa = ARY_HEAP_CAPA(ary);
+
+ assert(ARY_OWNS_HEAP_P(ary));
+ assert(RARRAY_TRANSIENT_P(ary));
+ assert(!ARY_PTR_USING_P(ary));
+
+ if (promote) {
+ new_ptr = ALLOC_N(VALUE, capa);
+ RARY_TRANSIENT_UNSET(ary);
+ }
+ else {
+ new_ptr = ary_heap_alloc(ary, capa);
+ }
+
+ MEMCPY(new_ptr, old_ptr, VALUE, capa);
+ /* do not use ARY_SET_PTR() because they assert !frozen */
+ RARRAY(ary)->as.heap.ptr = new_ptr;
+ }
+
ary_verify(ary);
+}
- return new_capa;
+void
+rb_ary_transient_heap_evacuate(VALUE ary, int promote)
+{
+ rb_ary_transient_heap_evacuate_(ary, RARRAY_TRANSIENT_P(ary), promote);
}
void
+rb_ary_detransient(VALUE ary)
+{
+ assert(RARRAY_TRANSIENT_P(ary));
+ rb_ary_transient_heap_evacuate_(ary, TRUE, TRUE);
+}
+#else
+void
+rb_ary_detransient(VALUE ary)
+{
+ /* do nothing */
+}
+#endif
+
+void
rb_ary_make_embedded(VALUE ary)
{
assert(rb_ary_embeddable_p(ary));
if (!ARY_EMBED_P(ary)) {
const VALUE *buf = ARY_HEAP_PTR(ary);
long len = ARY_HEAP_LEN(ary);
+ bool was_transient = RARRAY_TRANSIENT_P(ary);
+ // FL_SET_EMBED also unsets the transient flag
FL_SET_EMBED(ary);
ARY_SET_EMBED_LEN(ary, len);
MEMCPY((void *)ARY_EMBED_PTR(ary), (void *)buf, VALUE, len);
- ary_heap_free_ptr(ary, buf, len * sizeof(VALUE));
+ if (!was_transient) {
+ ary_heap_free_ptr(ary, buf, len * sizeof(VALUE));
+ }
}
}
@@ -405,7 +539,7 @@ ary_resize_capa(VALUE ary, long capacity)
size_t new_capa = capacity;
if (ARY_EMBED_P(ary)) {
long len = ARY_EMBED_LEN(ary);
- VALUE *ptr = ary_heap_alloc(capacity);
+ VALUE *ptr = ary_heap_alloc(ary, capacity);
MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
FL_UNSET_EMBED(ary);
@@ -509,15 +643,10 @@ rb_ary_increment_share(VALUE shared_root)
static void
rb_ary_set_shared(VALUE ary, VALUE shared_root)
{
- assert(!ARY_EMBED_P(ary));
- assert(!OBJ_FROZEN(ary));
- assert(ARY_SHARED_ROOT_P(shared_root) || OBJ_FROZEN(shared_root));
-
rb_ary_increment_share(shared_root);
FL_SET_SHARED(ary);
- RB_OBJ_WRITE(ary, &RARRAY(ary)->as.heap.aux.shared_root, shared_root);
-
RB_DEBUG_COUNTER_INC(obj_ary_shared_create);
+ ARY_SET_SHARED(ary, shared_root);
}
static inline void
@@ -545,18 +674,18 @@ rb_ary_cancel_sharing(VALUE ary)
ARY_SET_EMBED_LEN(ary, len);
}
else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) {
- long shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared_root);
+ long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root);
FL_UNSET_SHARED(ary);
- ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared_root));
+ ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared_root));
ARY_SET_CAPA(ary, shared_len);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr, ptr+shift, VALUE, len);
});
FL_SET_EMBED(shared_root);
rb_ary_decrement_share(shared_root);
}
else {
- VALUE *ptr = ary_heap_alloc(len);
+ VALUE *ptr = ary_heap_alloc(ary, len);
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
rb_ary_unshare(ary);
ARY_SET_CAPA(ary, len);
@@ -589,7 +718,7 @@ ary_ensure_room_for_push(VALUE ary, long add_len)
if (new_len > ary_embed_capa(ary)) {
VALUE shared_root = ARY_SHARED_ROOT(ary);
if (ARY_SHARED_ROOT_OCCUPIED(shared_root)) {
- if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR(shared_root) + new_len <= RARRAY_LEN(shared_root)) {
+ if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root) + new_len <= RARRAY_LEN(shared_root)) {
rb_ary_modify_check(ary);
ary_verify(ary);
@@ -667,9 +796,12 @@ ary_alloc_embed(VALUE klass, long capa)
{
size_t size = ary_embed_size(capa);
assert(rb_gc_size_allocatable_p(size));
- NEWOBJ_OF(ary, struct RArray, klass,
+#if !USE_RVARGC
+ assert(size <= sizeof(struct RArray));
+#endif
+ RVARGC_NEWOBJ_OF(ary, struct RArray, klass,
T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- size, 0);
+ size);
/* Created array is:
* FL_SET_EMBED((VALUE)ary);
* ARY_SET_EMBED_LEN((VALUE)ary, 0);
@@ -680,9 +812,9 @@ ary_alloc_embed(VALUE klass, long capa)
static VALUE
ary_alloc_heap(VALUE klass)
{
- NEWOBJ_OF(ary, struct RArray, klass,
+ RVARGC_NEWOBJ_OF(ary, struct RArray, klass,
T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- sizeof(struct RArray), 0);
+ sizeof(struct RArray));
return (VALUE)ary;
}
@@ -696,7 +828,7 @@ empty_ary_alloc(VALUE klass)
static VALUE
ary_new(VALUE klass, long capa)
{
- VALUE ary;
+ VALUE ary,*ptr;
if (capa < 0) {
rb_raise(rb_eArgError, "negative array size (or size too big)");
@@ -715,7 +847,8 @@ ary_new(VALUE klass, long capa)
ARY_SET_CAPA(ary, capa);
assert(!ARY_EMBED_P(ary));
- ARY_SET_PTR(ary, ary_heap_alloc(capa));
+ ptr = ary_heap_alloc(ary, capa);
+ ARY_SET_PTR(ary, ptr);
ARY_SET_HEAP_LEN(ary, 0);
}
@@ -753,7 +886,7 @@ VALUE
return ary;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_ary_tmp_new_from_values(VALUE klass, long n, const VALUE *elts)
{
VALUE ary;
@@ -778,9 +911,12 @@ ec_ary_alloc_embed(rb_execution_context_t *ec, VALUE klass, long capa)
{
size_t size = ary_embed_size(capa);
assert(rb_gc_size_allocatable_p(size));
- NEWOBJ_OF(ary, struct RArray, klass,
- T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- size, ec);
+#if !USE_RVARGC
+ assert(size <= sizeof(struct RArray));
+#endif
+ RB_RVARGC_EC_NEWOBJ_OF(ec, ary, struct RArray, klass,
+ T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
+ size);
/* Created array is:
* FL_SET_EMBED((VALUE)ary);
* ARY_SET_EMBED_LEN((VALUE)ary, 0);
@@ -791,16 +927,16 @@ ec_ary_alloc_embed(rb_execution_context_t *ec, VALUE klass, long capa)
static VALUE
ec_ary_alloc_heap(rb_execution_context_t *ec, VALUE klass)
{
- NEWOBJ_OF(ary, struct RArray, klass,
- T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- sizeof(struct RArray), ec);
+ RB_RVARGC_EC_NEWOBJ_OF(ec, ary, struct RArray, klass,
+ T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
+ sizeof(struct RArray));
return (VALUE)ary;
}
static VALUE
ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa)
{
- VALUE ary;
+ VALUE ary,*ptr;
if (capa < 0) {
rb_raise(rb_eArgError, "negative array size (or size too big)");
@@ -819,7 +955,8 @@ ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa)
ARY_SET_CAPA(ary, capa);
assert(!ARY_EMBED_P(ary));
- ARY_SET_PTR(ary, ary_heap_alloc(capa));
+ ptr = ary_heap_alloc(ary, capa);
+ ARY_SET_PTR(ary, ptr);
ARY_SET_HEAP_LEN(ary, 0);
}
@@ -844,6 +981,7 @@ VALUE
rb_ary_hidden_new(long capa)
{
VALUE ary = ary_new(0, capa);
+ rb_ary_transient_heap_evacuate(ary, TRUE);
return ary;
}
@@ -866,8 +1004,13 @@ rb_ary_free(VALUE ary)
RB_DEBUG_COUNTER_INC(obj_ary_extracapa);
}
- RB_DEBUG_COUNTER_INC(obj_ary_ptr);
- ary_heap_free(ary);
+ if (RARRAY_TRANSIENT_P(ary)) {
+ RB_DEBUG_COUNTER_INC(obj_ary_transient);
+ }
+ else {
+ RB_DEBUG_COUNTER_INC(obj_ary_ptr);
+ ary_heap_free(ary);
+ }
}
else {
RB_DEBUG_COUNTER_INC(obj_ary_embed);
@@ -895,6 +1038,7 @@ rb_ary_memsize(VALUE ary)
static VALUE
ary_make_shared(VALUE ary)
{
+ assert(USE_RVARGC || !ARY_EMBED_P(ary));
ary_verify(ary);
if (ARY_SHARED_P(ary)) {
@@ -905,11 +1049,14 @@ ary_make_shared(VALUE ary)
}
else if (OBJ_FROZEN(ary)) {
if (!ARY_EMBED_P(ary)) {
+ rb_ary_transient_heap_evacuate(ary, TRUE);
ary_shrink_capa(ary);
}
return ary;
}
else {
+ rb_ary_transient_heap_evacuate(ary, TRUE);
+
long capa = ARY_CAPA(ary);
long len = RARRAY_LEN(ary);
@@ -919,21 +1066,26 @@ ary_make_shared(VALUE ary)
FL_SET_SHARED_ROOT(shared);
if (ARY_EMBED_P(ary)) {
- VALUE *ptr = ary_heap_alloc(capa);
+ /* Cannot use ary_heap_alloc because we don't want to allocate
+ * on the transient heap. */
+ VALUE *ptr = ALLOC_N(VALUE, capa);
ARY_SET_PTR(shared, ptr);
- ary_memcpy(shared, 0, len, RARRAY_CONST_PTR(ary));
+ ary_memcpy(shared, 0, len, RARRAY_PTR(ary));
FL_UNSET_EMBED(ary);
ARY_SET_HEAP_LEN(ary, len);
ARY_SET_PTR(ary, ptr);
}
else {
- ARY_SET_PTR(shared, RARRAY_CONST_PTR(ary));
+ ARY_SET_PTR(shared, RARRAY_PTR(ary));
}
ARY_SET_LEN(shared, capa);
ary_mem_clear(shared, len, capa - len);
- rb_ary_set_shared(ary, shared);
+ ARY_SET_SHARED_ROOT_REFCNT(shared, 1);
+ FL_SET_SHARED(ary);
+ RB_DEBUG_COUNTER_INC(obj_ary_shared_create);
+ ARY_SET_SHARED(ary, shared);
ary_verify(shared);
ary_verify(ary);
@@ -951,7 +1103,7 @@ ary_make_substitution(VALUE ary)
VALUE subst = rb_ary_new_capa(len);
assert(ARY_EMBED_P(subst));
- ary_memcpy(subst, 0, len, RARRAY_CONST_PTR(ary));
+ ary_memcpy(subst, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_EMBED_LEN(subst, len);
return subst;
}
@@ -979,7 +1131,7 @@ rb_check_array_type(VALUE ary)
return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_check_to_array(VALUE ary)
{
return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_a);
@@ -1054,7 +1206,7 @@ rb_ary_s_new(int argc, VALUE *argv, VALUE klass)
* a.class # => Array
* a # => [:foo, "bar", 2]
*
- * With no block and a single Integer argument +size+,
+ * With no block and a single \Integer argument +size+,
* returns a new \Array of the given size
* whose elements are all +nil+:
*
@@ -1194,19 +1346,21 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
assert(len >= 0);
assert(offset+len <= RARRAY_LEN(ary));
- VALUE result = ary_alloc_heap(klass);
- size_t embed_capa = ary_embed_capa(result);
- if ((size_t)len <= embed_capa) {
- FL_SET_EMBED(result);
- ary_memcpy(result, 0, len, RARRAY_CONST_PTR(ary) + offset);
+ const size_t rarray_embed_capa_max = (sizeof(struct RArray) - offsetof(struct RArray, as.ary)) / sizeof(VALUE);
+
+ if ((size_t)len <= rarray_embed_capa_max && ary_embeddable_p(len)) {
+ VALUE result = ary_alloc_embed(klass, len);
+ ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset);
ARY_SET_EMBED_LEN(result, len);
+ return result;
}
else {
VALUE shared = ary_make_shared(ary);
+ VALUE result = ary_alloc_heap(klass);
assert(!ARY_EMBED_P(result));
- ARY_SET_PTR(result, RARRAY_CONST_PTR(ary));
+ ARY_SET_PTR(result, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_LEN(result, RARRAY_LEN(ary));
rb_ary_set_shared(result, shared);
@@ -1214,10 +1368,9 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
ARY_SET_LEN(result, len);
ary_verify(shared);
+ ary_verify(result);
+ return result;
}
-
- ary_verify(result);
- return result;
}
static VALUE
@@ -1228,7 +1381,7 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
assert(offset+len <= RARRAY_LEN(ary));
assert(step != 0);
- const VALUE *values = RARRAY_CONST_PTR(ary);
+ const VALUE *values = RARRAY_CONST_PTR_TRANSIENT(ary);
const long orig_len = len;
if (step > 0 && step >= len) {
@@ -1258,7 +1411,7 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
ARY_SET_EMBED_LEN(result, len);
}
else {
- RARRAY_PTR_USE(result, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(result, ptr, {
for (i = 0; i < len; ++i) {
RB_OBJ_WRITE(result, ptr+i, values[j]);
j += step;
@@ -1283,11 +1436,20 @@ enum ary_take_pos_flags
};
static VALUE
-ary_take_first_or_last_n(VALUE ary, long n, enum ary_take_pos_flags last)
+ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
{
- long len = RARRAY_LEN(ary);
+ long n;
+ long len;
long offset = 0;
+ argc = rb_check_arity(argc, 0, 1);
+ /* the case optional argument is omitted should be handled in
+ * callers of this function. if another arity case is added,
+ * this arity check needs to rewrite. */
+ RUBY_ASSERT_ALWAYS(argc == 1);
+
+ n = NUM2LONG(argv[0]);
+ len = RARRAY_LEN(ary);
if (n > len) {
n = len;
}
@@ -1300,17 +1462,6 @@ ary_take_first_or_last_n(VALUE ary, long n, enum ary_take_pos_flags last)
return ary_make_partial(ary, rb_cArray, offset, n);
}
-static VALUE
-ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
-{
- argc = rb_check_arity(argc, 0, 1);
- /* the case optional argument is omitted should be handled in
- * callers of this function. if another arity case is added,
- * this arity check needs to rewrite. */
- RUBY_ASSERT_ALWAYS(argc == 1);
- return ary_take_first_or_last_n(ary, NUM2LONG(argv[0]), last);
-}
-
/*
* call-seq:
* array << object -> self
@@ -1333,7 +1484,7 @@ rb_ary_push(VALUE ary, VALUE item)
{
long idx = RARRAY_LEN((ary_verify(ary), ary));
VALUE target_ary = ary_ensure_room_for_push(ary, 1);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
RB_OBJ_WRITE(target_ary, &ptr[idx], item);
});
ARY_SET_LEN(ary, idx + 1);
@@ -1368,6 +1519,8 @@ rb_ary_cat(VALUE ary, const VALUE *argv, long len)
* a1 = a.push([:baz, :bat], [:bam, :bad])
* a1 # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
*
+ * Array#append is an alias for Array#push.
+ *
* Related: #pop, #shift, #unshift.
*/
@@ -1412,7 +1565,7 @@ rb_ary_pop(VALUE ary)
*
* Returns +nil+ if the array is empty.
*
- * When a non-negative Integer argument +n+ is given and is in range,
+ * When a non-negative \Integer argument +n+ is given and is in range,
*
* removes and returns the last +n+ elements in a new \Array:
* a = [:foo, 'bar', 2]
@@ -1476,7 +1629,7 @@ rb_ary_shift(VALUE ary)
*
* Returns +nil+ if +self+ is empty.
*
- * When positive Integer argument +n+ is given, removes the first +n+ elements;
+ * When positive \Integer argument +n+ is given, removes the first +n+ elements;
* returns those elements in a new \Array:
*
* a = [:foo, 'bar', 2]
@@ -1512,7 +1665,7 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
return result;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_ary_behead(VALUE ary, long n)
{
if (n <= 0) {
@@ -1523,7 +1676,7 @@ rb_ary_behead(VALUE ary, long n)
if (!ARY_SHARED_P(ary)) {
if (ARY_EMBED_P(ary) || RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr, ptr + n, VALUE, RARRAY_LEN(ary) - n);
}); /* WB: no new reference */
ARY_INCREASE_LEN(ary, -n);
@@ -1584,12 +1737,12 @@ ary_modify_for_unshift(VALUE ary, int argc)
capa = ARY_CAPA(ary);
ary_make_shared(ary);
- head = sharedp = RARRAY_CONST_PTR(ary);
+ head = sharedp = RARRAY_CONST_PTR_TRANSIENT(ary);
return make_room_for_unshift(ary, head, (void *)sharedp, argc, capa, len);
}
else {
/* sliding items */
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr + argc, ptr, VALUE, len);
});
@@ -1621,8 +1774,8 @@ ary_ensure_room_for_unshift(VALUE ary, int argc)
return ary_modify_for_unshift(ary, argc);
}
else {
- const VALUE * head = RARRAY_CONST_PTR(ary);
- void *sharedp = (void *)RARRAY_CONST_PTR(shared_root);
+ const VALUE * head = RARRAY_CONST_PTR_TRANSIENT(ary);
+ void *sharedp = (void *)RARRAY_CONST_PTR_TRANSIENT(shared_root);
rb_ary_modify_check(ary);
return make_room_for_unshift(ary, head, sharedp, argc, capa, len);
@@ -1639,10 +1792,12 @@ ary_ensure_room_for_unshift(VALUE ary, int argc)
* a = [:foo, 'bar', 2]
* a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
*
+ * Array#prepend is an alias for Array#unshift.
+ *
* Related: #push, #pop, #shift.
*/
-VALUE
+static VALUE
rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
{
long len = RARRAY_LEN(ary);
@@ -1662,7 +1817,7 @@ rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
VALUE
rb_ary_unshift(VALUE ary, VALUE item)
{
- return rb_ary_unshift_m(1, &item, ary);
+ return rb_ary_unshift_m(1,&item,ary);
}
/* faster version - use this if you don't need to treat negative offset */
@@ -1726,7 +1881,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
*
* Returns elements from +self+; does not modify +self+.
*
- * When a single Integer argument +index+ is given, returns the element at offset +index+:
+ * When a single \Integer argument +index+ is given, returns the element at offset +index+:
*
* a = [:foo, 'bar', 2]
* a[0] # => :foo
@@ -1741,7 +1896,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
*
* If +index+ is out of range, returns +nil+.
*
- * When two Integer arguments +start+ and +length+ are given,
+ * When two \Integer arguments +start+ and +length+ are given,
* returns a new \Array of size +length+ containing successive elements beginning at offset +start+:
*
* a = [:foo, 'bar', 2]
@@ -1761,7 +1916,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
*
* If +length+ is negative, returns +nil+.
*
- * When a single Range argument +range+ is given,
+ * When a single \Range argument +range+ is given,
* treats <tt>range.min</tt> as +start+ above
* and <tt>range.size</tt> as +length+ above:
*
@@ -1815,6 +1970,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
* # Raises TypeError (no implicit conversion of Symbol into Integer):
* a[:foo]
*
+ * Array#slice is an alias for Array#[].
*/
VALUE
@@ -1838,7 +1994,7 @@ rb_ary_aref2(VALUE ary, VALUE b, VALUE e)
return rb_ary_subseq(ary, beg, len);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_ary_aref1(VALUE ary, VALUE arg)
{
long beg, len, step;
@@ -1864,7 +2020,7 @@ rb_ary_aref1(VALUE ary, VALUE arg)
* call-seq:
* array.at(index) -> object
*
- * Returns the element at Integer offset +index+; does not modify +self+.
+ * Returns the element at \Integer offset +index+; does not modify +self+.
* a = [:foo, 'bar', 2]
* a.at(0) # => :foo
* a.at(2) # => 2
@@ -1877,7 +2033,39 @@ rb_ary_at(VALUE ary, VALUE pos)
return rb_ary_entry(ary, NUM2LONG(pos));
}
-#if 0
+/*
+ * call-seq:
+ * array.first -> object or nil
+ * array.first(n) -> new_array
+ *
+ * Returns elements from +self+; does not modify +self+.
+ *
+ * When no argument is given, returns the first element:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first # => :foo
+ * a # => [:foo, "bar", 2]
+ *
+ * If +self+ is empty, returns +nil+.
+ *
+ * When non-negative \Integer argument +n+ is given,
+ * returns the first +n+ elements in a new \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first(2) # => [:foo, "bar"]
+ *
+ * If <tt>n >= array.size</tt>, returns all elements:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first(50) # => [:foo, "bar", 2]
+ *
+ * If <tt>n == 0</tt> returns an new empty \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first(0) # []
+ *
+ * Related: #last.
+ */
static VALUE
rb_ary_first(int argc, VALUE *argv, VALUE ary)
{
@@ -1889,26 +2077,48 @@ rb_ary_first(int argc, VALUE *argv, VALUE ary)
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
}
}
-#endif
-static VALUE
-ary_first(VALUE self)
-{
- return (RARRAY_LEN(self) == 0) ? Qnil : RARRAY_AREF(self, 0);
-}
-
-static VALUE
-ary_last(VALUE self)
-{
- long len = RARRAY_LEN(self);
- return (len == 0) ? Qnil : RARRAY_AREF(self, len-1);
-}
+/*
+ * call-seq:
+ * array.last -> object or nil
+ * array.last(n) -> new_array
+ *
+ * Returns elements from +self+; +self+ is not modified.
+ *
+ * When no argument is given, returns the last element:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last # => 2
+ * a # => [:foo, "bar", 2]
+ *
+ * If +self+ is empty, returns +nil+.
+ *
+ * When non-negative \Integer argument +n+ is given,
+ * returns the last +n+ elements in a new \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last(2) # => ["bar", 2]
+ *
+ * If <tt>n >= array.size</tt>, returns all elements:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last(50) # => [:foo, "bar", 2]
+ *
+ * If <tt>n == 0</tt>, returns an new empty \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last(0) # []
+ *
+ * Related: #first.
+ */
VALUE
-rb_ary_last(int argc, const VALUE *argv, VALUE ary) // used by parse.y
+rb_ary_last(int argc, const VALUE *argv, VALUE ary)
{
if (argc == 0) {
- return ary_last(ary);
+ long len = RARRAY_LEN(ary);
+ if (len == 0) return Qnil;
+ return RARRAY_AREF(ary, len-1);
}
else {
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
@@ -1923,7 +2133,7 @@ rb_ary_last(int argc, const VALUE *argv, VALUE ary) // used by parse.y
*
* Returns the element at offset +index+.
*
- * With the single Integer argument +index+,
+ * With the single \Integer argument +index+,
* returns the element at offset +index+:
*
* a = [:foo, 'bar', 2]
@@ -2013,6 +2223,8 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
* e # => #<Enumerator: [:foo, "bar", 2]:index>
* e.each {|element| element == 'bar' } # => 1
*
+ * Array#find_index is an alias for Array#index.
+ *
* Related: #rindex.
*/
@@ -2067,7 +2279,7 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary)
*
* Returns +nil+ if the block never returns a truthy value.
*
- * When neither an argument nor a block is given, returns a new Enumerator:
+ * When neither an argument nor a block is given, returns a new \Enumerator:
*
* a = [:foo, 'bar', 2, 'bar']
* e = a.rindex
@@ -2139,7 +2351,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
}
{
- const VALUE *optr = RARRAY_CONST_PTR(ary);
+ const VALUE *optr = RARRAY_CONST_PTR_TRANSIENT(ary);
rofs = (rptr >= optr && rptr < optr + olen) ? rptr - optr : -1;
}
@@ -2152,7 +2364,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
len = beg + rlen;
ary_mem_clear(ary, olen, beg - olen);
if (rlen > 0) {
- if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs;
+ if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs;
ary_memcpy0(ary, beg, rlen, rptr, target_ary);
}
ARY_SET_LEN(ary, len);
@@ -2170,25 +2382,20 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
}
if (len != rlen) {
- RARRAY_PTR_USE(ary, ptr,
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr,
MEMMOVE(ptr + beg + rlen, ptr + beg + len,
VALUE, olen - (beg + len)));
ARY_SET_LEN(ary, alen);
}
if (rlen > 0) {
- if (rofs == -1) {
- rb_gc_writebarrier_remember(ary);
- }
- else {
- /* In this case, we're copying from a region in this array, so
- * we don't need to fire the write barrier. */
- rptr = RARRAY_CONST_PTR(ary) + rofs;
- }
+ if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs;
+ /* give up wb-protected ary */
+ RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary);
/* do not use RARRAY_PTR() because it can causes GC.
* ary can contain T_NONE object because it is not cleared.
*/
- RARRAY_PTR_USE(ary, ptr,
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr,
MEMMOVE(ptr + beg, rptr, VALUE, rlen));
}
}
@@ -2233,8 +2440,9 @@ rb_ary_resize(VALUE ary, long len)
else if (len <= ary_embed_capa(ary)) {
const VALUE *ptr = ARY_HEAP_PTR(ary);
long ptr_capa = ARY_HEAP_SIZE(ary);
- bool is_malloc_ptr = !ARY_SHARED_P(ary);
+ bool is_malloc_ptr = !ARY_SHARED_P(ary) && !RARRAY_TRANSIENT_P(ary);
+ FL_UNSET(ary, RARRAY_TRANSIENT_FLAG);
FL_SET_EMBED(ary);
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); /* WB: no new reference */
@@ -2264,7 +2472,7 @@ static VALUE
ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
{
VALUE rpl = rb_ary_to_ary(val);
- rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR(rpl), RARRAY_LEN(rpl));
+ rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR_TRANSIENT(rpl), RARRAY_LEN(rpl));
RB_GC_GUARD(rpl);
return val;
}
@@ -2277,7 +2485,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
*
* Assigns elements in +self+; returns the given +object+.
*
- * When Integer argument +index+ is given, assigns +object+ to an element in +self+.
+ * When \Integer argument +index+ is given, assigns +object+ to an element in +self+.
*
* If +index+ is non-negative, assigns +object+ the element at offset +index+:
*
@@ -2297,7 +2505,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
* a[-1] = 'two' # => "two"
* a # => [:foo, "bar", "two"]
*
- * When Integer arguments +start+ and +length+ are given and +object+ is not an \Array,
+ * When \Integer arguments +start+ and +length+ are given and +object+ is not an \Array,
* removes <tt>length - 1</tt> elements beginning at offset +start+,
* and assigns +object+ at offset +start+:
*
@@ -2332,7 +2540,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
* a[1, 5] = 'foo' # => "foo"
* a # => [:foo, "foo"]
*
- * When Range argument +range+ is given and +object+ is an \Array,
+ * When \Range argument +range+ is given and +object+ is an \Array,
* removes <tt>length - 1</tt> elements beginning at offset +start+,
* and assigns +object+ at offset +start+:
*
@@ -2412,7 +2620,7 @@ rb_ary_aset(int argc, VALUE *argv, VALUE ary)
* call-seq:
* array.insert(index, *objects) -> self
*
- * Inserts given +objects+ before or after the element at Integer index +offset+;
+ * Inserts given +objects+ before or after the element at \Integer index +offset+;
* returns +self+.
*
* When +index+ is non-negative, inserts all given +objects+
@@ -2506,7 +2714,7 @@ ary_enum_length(VALUE ary, VALUE args, VALUE eobj)
* foo
* bar
*
- * When no block given, returns a new Enumerator:
+ * When no block given, returns a new \Enumerator:
* a = [:foo, 'bar', 2]
*
* e = a.each
@@ -2563,7 +2771,7 @@ rb_ary_each(VALUE ary)
* 0
* 1
*
- * When no block given, returns a new Enumerator:
+ * When no block given, returns a new \Enumerator:
*
* a = [:foo, 'bar', 2]
* e = a.each_index
@@ -2620,7 +2828,7 @@ rb_ary_each_index(VALUE ary)
* 2
* bar
*
- * When no block given, returns a new Enumerator:
+ * When no block given, returns a new \Enumerator:
*
* a = [:foo, 'bar', 2]
* e = a.reverse_each
@@ -2687,7 +2895,7 @@ rb_ary_dup(VALUE ary)
{
long len = RARRAY_LEN(ary);
VALUE dup = rb_ary_new2(len);
- ary_memcpy(dup, 0, len, RARRAY_CONST_PTR(ary));
+ ary_memcpy(dup, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_LEN(dup, len);
ary_verify(ary);
@@ -2840,7 +3048,7 @@ rb_ary_join(VALUE ary, VALUE sep)
* array.join ->new_string
* array.join(separator = $,) -> new_string
*
- * Returns the new String formed by joining the array elements after conversion.
+ * Returns the new \String formed by joining the array elements after conversion.
* For each element +element+:
*
* - Uses <tt>element.to_s</tt> if +element+ is not a <tt>kind_of?(Array)</tt>.
@@ -2900,12 +3108,13 @@ inspect_ary(VALUE ary, VALUE dummy, int recur)
* call-seq:
* array.inspect -> new_string
*
- * Returns the new String formed by calling method <tt>#inspect</tt>
+ * Returns the new \String formed by calling method <tt>#inspect</tt>
* on each array element:
*
* a = [:foo, 'bar', 2]
* a.inspect # => "[:foo, \"bar\", 2]"
*
+ * Array#to_s is an alias for Array#inspect.
*/
static VALUE
@@ -2958,18 +3167,18 @@ rb_ary_to_a(VALUE ary)
* array.to_h -> new_hash
* array.to_h {|item| ... } -> new_hash
*
- * Returns a new Hash formed from +self+.
+ * Returns a new \Hash formed from +self+.
*
* When a block is given, calls the block with each array element;
* the block must return a 2-element \Array whose two elements
- * form a key-value pair in the returned Hash:
+ * form a key-value pair in the returned \Hash:
*
* a = ['foo', :bar, 1, [2, 3], {baz: 4}]
* h = a.to_h {|item| [item, item] }
* h # => {"foo"=>"foo", :bar=>:bar, 1=>1, [2, 3]=>[2, 3], {:baz=>4}=>{:baz=>4}}
*
* When no block is given, +self+ must be an \Array of 2-element sub-arrays,
- * each sub-array is formed into a key-value pair in the new Hash:
+ * each sub-array is formed into a key-value pair in the new \Hash:
*
* [].to_h # => {}
* a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
@@ -3033,7 +3242,7 @@ rb_ary_reverse(VALUE ary)
rb_ary_modify(ary);
if (len > 1) {
- RARRAY_PTR_USE(ary, p1, {
+ RARRAY_PTR_USE_TRANSIENT(ary, p1, {
p2 = p1 + len - 1; /* points last item */
ary_reverse(p1, p2);
}); /* WB: no new reference */
@@ -3077,8 +3286,8 @@ rb_ary_reverse_m(VALUE ary)
VALUE dup = rb_ary_new2(len);
if (len > 0) {
- const VALUE *p1 = RARRAY_CONST_PTR(ary);
- VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1;
+ const VALUE *p1 = RARRAY_CONST_PTR_TRANSIENT(ary);
+ VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1;
do *p2-- = *p1++; while (--len > 0);
}
ARY_SET_LEN(dup, RARRAY_LEN(ary));
@@ -3120,7 +3329,7 @@ rb_ary_rotate(VALUE ary, long cnt)
if (cnt != 0) {
long len = RARRAY_LEN(ary);
if (len > 1 && (cnt = rotate_count(cnt, len)) > 0) {
- RARRAY_PTR_USE(ary, ptr, ary_rotate_ptr(ptr, len, cnt));
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, ary_rotate_ptr(ptr, len, cnt));
return ary;
}
}
@@ -3139,7 +3348,7 @@ rb_ary_rotate(VALUE ary, long cnt)
* a = [:foo, 'bar', 2, 'bar']
* a.rotate! # => ["bar", 2, "bar", :foo]
*
- * When given a non-negative Integer +count+,
+ * When given a non-negative \Integer +count+,
* rotates +count+ elements from the beginning to the end:
*
* a = [:foo, 'bar', 2]
@@ -3196,7 +3405,7 @@ rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
* a1 = a.rotate
* a1 # => ["bar", 2, "bar", :foo]
*
- * When given a non-negative Integer +count+,
+ * When given a non-negative \Integer +count+,
* returns a new \Array with +count+ elements rotated from the beginning to the end:
*
* a = [:foo, 'bar', 2]
@@ -3215,7 +3424,7 @@ rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
* a1 = a.rotate(0)
* a1 # => [:foo, "bar", 2]
*
- * When given a negative Integer +count+, rotates in the opposite direction,
+ * When given a negative \Integer +count+, rotates in the opposite direction,
* from end to beginning:
*
* a = [:foo, 'bar', 2]
@@ -3242,7 +3451,7 @@ rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary)
rotated = rb_ary_new2(len);
if (len > 0) {
cnt = rotate_count(cnt, len);
- ptr = RARRAY_CONST_PTR(ary);
+ ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
len -= cnt;
ary_memcpy(rotated, 0, len, ptr + cnt);
ary_memcpy(rotated, len, cnt, ptr);
@@ -3573,7 +3782,7 @@ sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, dummy))
* a.sort_by! {|element| element.size }
* a # => ["d", "cc", "bbb", "aaaa"]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = ['aaaa', 'bbb', 'cc', 'd']
* a.sort_by! # => #<Enumerator: ["aaaa", "bbb", "cc", "d"]:sort_by!>
@@ -3605,11 +3814,12 @@ rb_ary_sort_by_bang(VALUE ary)
* a1 = a.map {|element| element.class }
* a1 # => [Symbol, String, Integer]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* a = [:foo, 'bar', 2]
* a1 = a.map
* a1 # => #<Enumerator: [:foo, "bar", 2]:map>
*
+ * Array#collect is an alias for Array#map.
*/
static VALUE
@@ -3638,12 +3848,13 @@ rb_ary_collect(VALUE ary)
* a = [:foo, 'bar', 2]
* a.map! { |element| element.class } # => [Symbol, String, Integer]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2]
* a1 = a.map!
* a1 # => #<Enumerator: [:foo, "bar", 2]:map!>
*
+ * Array#collect! is an alias for Array#map!.
*/
static VALUE
@@ -3695,7 +3906,7 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
/* check if idx is Range */
else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) {
if (len > 0) {
- const VALUE *const src = RARRAY_CONST_PTR(ary);
+ const VALUE *const src = RARRAY_CONST_PTR_TRANSIENT(ary);
const long end = beg + len;
const long prevlen = RARRAY_LEN(result);
if (beg < olen) {
@@ -3718,7 +3929,7 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
* array.values_at(*indexes) -> new_array
*
* Returns a new \Array whose elements are the elements
- * of +self+ at the given Integer or Range +indexes+.
+ * of +self+ at the given \Integer or \Range +indexes+.
*
* For each positive +index+, returns the element at offset +index+:
*
@@ -3782,11 +3993,12 @@ rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
* a1 = a.select {|element| element.to_s.start_with?('b') }
* a1 # => ["bar", :bam]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2, :bam]
* a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
*
+ * Array#filter is an alias for Array#select.
*/
static VALUE
@@ -3841,7 +4053,7 @@ select_bang_ensure(VALUE a)
rb_ary_modify(ary);
if (i1 < len) {
tail = len - i1;
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr + i2, ptr + i1, VALUE, tail);
});
}
@@ -3865,11 +4077,12 @@ select_bang_ensure(VALUE a)
*
* Returns +nil+ if no elements were removed.
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2, :bam]
* a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
*
+ * Array#filter! is an alias for Array#select!.
*/
static VALUE
@@ -3896,7 +4109,7 @@ rb_ary_select_bang(VALUE ary)
* a = [:foo, 'bar', 2, :bam]
* a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2, :bam]
* a.keep_if # => #<Enumerator: [:foo, "bar", 2, :bam]:keep_if>
@@ -4028,7 +4241,7 @@ rb_ary_delete_at(VALUE ary, long pos)
rb_ary_modify(ary);
del = RARRAY_AREF(ary, pos);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1);
});
ARY_INCREASE_LEN(ary, -1);
@@ -4040,7 +4253,7 @@ rb_ary_delete_at(VALUE ary, long pos)
* call-seq:
* array.delete_at(index) -> deleted_object or nil
*
- * Deletes an element from +self+, per the given Integer +index+.
+ * Deletes an element from +self+, per the given \Integer +index+.
*
* When +index+ is non-negative, deletes the element at offset +index+:
*
@@ -4089,7 +4302,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
return rb_ary_new2(0);
}
else {
- VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR(ary)+pos);
+ VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR_TRANSIENT(ary)+pos);
rb_ary_splice(ary, pos, len, 0, 0);
return arg2;
}
@@ -4103,7 +4316,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
*
* Removes and returns elements from +self+.
*
- * When the only argument is an Integer +n+,
+ * When the only argument is an \Integer +n+,
* removes and returns the _nth_ element in +self+:
*
* a = [:foo, 'bar', 2]
@@ -4138,7 +4351,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
*
* If +length+ is negative, returns +nil+.
*
- * When the only argument is a Range object +range+,
+ * When the only argument is a \Range object +range+,
* treats <tt>range.min</tt> as +start+ above and <tt>range.size</tt> as +length+ above:
*
* a = [:foo, 'bar', 2]
@@ -4254,7 +4467,7 @@ ary_reject_bang(VALUE ary)
*
* Returns +nil+ if no elements removed.
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2]
* a.reject! # => #<Enumerator: [:foo, "bar", 2]:reject!>
@@ -4281,7 +4494,7 @@ rb_ary_reject_bang(VALUE ary)
* a1 = a.reject {|element| element.to_s.start_with?('b') }
* a1 # => [:foo, 2]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2]
* a.reject # => #<Enumerator: [:foo, "bar", 2]:reject>
@@ -4310,12 +4523,12 @@ rb_ary_reject(VALUE ary)
* a = [:foo, 'bar', 2, 'bat']
* a.delete_if {|element| element.to_s.start_with?('b') } # => [:foo, 2]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2]
* a.delete_if # => #<Enumerator: [:foo, "bar", 2]:delete_if>
*
- */
+3 */
static VALUE
rb_ary_delete_if(VALUE ary)
@@ -4530,14 +4743,15 @@ rb_ary_replace(VALUE copy, VALUE orig)
/* orig has enough space to embed the contents of orig. */
if (RARRAY_LEN(orig) <= ary_embed_capa(copy)) {
assert(ARY_EMBED_P(copy));
- ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig));
+ ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR_TRANSIENT(orig));
ARY_SET_EMBED_LEN(copy, RARRAY_LEN(orig));
}
+#if USE_RVARGC
/* orig is embedded but copy does not have enough space to embed the
* contents of orig. */
else if (ARY_EMBED_P(orig)) {
long len = ARY_EMBED_LEN(orig);
- VALUE *ptr = ary_heap_alloc(len);
+ VALUE *ptr = ary_heap_alloc(copy, len);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ptr);
@@ -4546,8 +4760,9 @@ rb_ary_replace(VALUE copy, VALUE orig)
// No allocation and exception expected that could leave `copy` in a
// bad state from the edits above.
- ary_memcpy(copy, 0, len, RARRAY_CONST_PTR(orig));
+ ary_memcpy(copy, 0, len, RARRAY_CONST_PTR_TRANSIENT(orig));
}
+#endif
/* Otherwise, orig is on heap and copy does not have enough space to embed
* the contents of orig. */
else {
@@ -4612,7 +4827,7 @@ rb_ary_clear(VALUE ary)
* a # => ["a", "b", "c", "d"]
* a.fill(:X) # => [:X, :X, :X, :X]
*
- * With arguments +obj+ and Integer +start+, and no block given,
+ * With arguments +obj+ and \Integer +start+, and no block given,
* replaces elements based on the given start.
*
* If +start+ is in range (<tt>0 <= start < array.size</tt>),
@@ -4640,7 +4855,7 @@ rb_ary_clear(VALUE ary)
* a = ['a', 'b', 'c', 'd']
* a.fill(:X, -50) # => [:X, :X, :X, :X]
*
- * With arguments +obj+, Integer +start+, and Integer +length+, and no block given,
+ * With arguments +obj+, \Integer +start+, and \Integer +length+, and no block given,
* replaces elements based on the given +start+ and +length+.
*
* If +start+ is in range, replaces +length+ elements beginning at offset +start+:
@@ -4666,7 +4881,7 @@ rb_ary_clear(VALUE ary)
* a.fill(:X, 1, 0) # => ["a", "b", "c", "d"]
* a.fill(:X, 1, -1) # => ["a", "b", "c", "d"]
*
- * With arguments +obj+ and Range +range+, and no block given,
+ * With arguments +obj+ and \Range +range+, and no block given,
* replaces elements based on the given range.
*
* If the range is positive and ascending (<tt>0 < range.begin <= range.end</tt>),
@@ -4878,8 +5093,8 @@ rb_ary_plus(VALUE x, VALUE y)
len = xlen + ylen;
z = rb_ary_new2(len);
- ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x));
- ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y));
+ ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR_TRANSIENT(x));
+ ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR_TRANSIENT(y));
ARY_SET_LEN(z, len);
return z;
}
@@ -4889,7 +5104,7 @@ ary_append(VALUE x, VALUE y)
{
long n = RARRAY_LEN(y);
if (n > 0) {
- rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR(y), n);
+ rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR_TRANSIENT(y), n);
}
RB_GC_GUARD(y);
return x;
@@ -4937,13 +5152,13 @@ rb_ary_concat(VALUE x, VALUE y)
* array * n -> new_array
* array * string_separator -> new_string
*
- * When non-negative argument Integer +n+ is given,
+ * When non-negative argument \Integer +n+ is given,
* returns a new \Array built by concatenating the +n+ copies of +self+:
*
* a = ['x', 'y']
* a * 3 # => ["x", "y", "x", "y", "x", "y"]
*
- * When String argument +string_separator+ is given,
+ * When \String argument +string_separator+ is given,
* equivalent to <tt>array.join(string_separator)</tt>:
*
* [0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {:foo=>0}"
@@ -4978,16 +5193,16 @@ rb_ary_times(VALUE ary, VALUE times)
ary2 = ary_new(rb_cArray, len);
ARY_SET_LEN(ary2, len);
- ptr = RARRAY_CONST_PTR(ary);
+ ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
t = RARRAY_LEN(ary);
if (0 < t) {
ary_memcpy(ary2, 0, t, ptr);
while (t <= len/2) {
- ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2));
+ ary_memcpy(ary2, t, t, RARRAY_CONST_PTR_TRANSIENT(ary2));
t *= 2;
}
if (t < len) {
- ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2));
+ ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR_TRANSIENT(ary2));
}
}
out:
@@ -5118,7 +5333,7 @@ rb_ary_equal(VALUE ary1, VALUE ary2)
return rb_equal(ary2, ary1);
}
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
- if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
+ if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
}
@@ -5158,27 +5373,10 @@ rb_ary_eql(VALUE ary1, VALUE ary2)
if (ary1 == ary2) return Qtrue;
if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
- if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
+ if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
}
-VALUE
-rb_ary_hash_values(long len, const VALUE *elements)
-{
- long i;
- st_index_t h;
- VALUE n;
-
- h = rb_hash_start(len);
- h = rb_hash_uint(h, (st_index_t)rb_ary_hash_values);
- for (i=0; i<len; i++) {
- n = rb_hash(elements[i]);
- h = rb_hash_uint(h, NUM2LONG(n));
- }
- h = rb_hash_end(h);
- return ST2FIX(h);
-}
-
/*
* call-seq:
* array.hash -> integer
@@ -5195,7 +5393,18 @@ rb_ary_hash_values(long len, const VALUE *elements)
static VALUE
rb_ary_hash(VALUE ary)
{
- return rb_ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary));
+ long i;
+ st_index_t h;
+ VALUE n;
+
+ h = rb_hash_start(RARRAY_LEN(ary));
+ h = rb_hash_uint(h, (st_index_t)rb_ary_hash);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ n = rb_hash(RARRAY_AREF(ary, i));
+ h = rb_hash_uint(h, NUM2LONG(n));
+ }
+ h = rb_hash_end(h);
+ return ST2FIX(h);
}
/*
@@ -5355,6 +5564,17 @@ ary_make_hash_by(VALUE ary)
return ary_add_hash_by(hash, ary);
}
+static inline void
+ary_recycle_hash(VALUE hash)
+{
+ assert(RBASIC_CLASS(hash) == 0);
+ if (RHASH_ST_TABLE_P(hash)) {
+ st_table *tbl = RHASH_ST_TABLE(hash);
+ st_free_table(tbl);
+ RHASH_ST_CLEAR(hash);
+ }
+}
+
/*
* call-seq:
* array - other_array -> new_array
@@ -5396,7 +5616,7 @@ rb_ary_diff(VALUE ary1, VALUE ary2)
if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue;
rb_ary_push(ary3, rb_ary_elt(ary1, i));
}
-
+ ary_recycle_hash(hash);
return ary3;
}
@@ -5459,8 +5679,7 @@ rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary)
* array & other_array -> new_array
*
* Returns a new \Array containing each element found in both +array+ and \Array +other_array+;
- * duplicates are omitted; items are compared using <tt>eql?</tt>
- * (items must also implement +hash+ correctly):
+ * duplicates are omitted; items are compared using <tt>eql?</tt>:
*
* [0, 1, 2, 3] & [1, 2] # => [1, 2]
* [0, 1, 0, 1] & [0, 1] # => [0, 1]
@@ -5503,6 +5722,7 @@ rb_ary_and(VALUE ary1, VALUE ary2)
rb_ary_push(ary3, v);
}
}
+ ary_recycle_hash(hash);
return ary3;
}
@@ -5513,8 +5733,7 @@ rb_ary_and(VALUE ary1, VALUE ary2)
*
* Returns a new \Array containing each element found both in +self+
* and in all of the given Arrays +other_arrays+;
- * duplicates are omitted; items are compared using <tt>eql?</tt>
- * (items must also implement +hash+ correctly):
+ * duplicates are omitted; items are compared using <tt>eql?</tt>:
*
* [0, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
* [0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
@@ -5590,11 +5809,11 @@ rb_ary_union_hash(VALUE hash, VALUE ary2)
static VALUE
rb_ary_or(VALUE ary1, VALUE ary2)
{
- VALUE hash;
+ VALUE hash, ary3;
ary2 = to_ary(ary2);
if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
- VALUE ary3 = rb_ary_new();
+ ary3 = rb_ary_new();
rb_ary_union(ary3, ary1);
rb_ary_union(ary3, ary2);
return ary3;
@@ -5603,7 +5822,9 @@ rb_ary_or(VALUE ary1, VALUE ary2)
hash = ary_make_hash(ary1);
rb_ary_union_hash(hash, ary2);
- return rb_hash_values(hash);
+ ary3 = rb_hash_values(hash);
+ ary_recycle_hash(hash);
+ return ary3;
}
/*
@@ -5627,7 +5848,7 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
{
int i;
long sum;
- VALUE hash;
+ VALUE hash, ary_union;
sum = RARRAY_LEN(ary);
for (i = 0; i < argc; i++) {
@@ -5636,7 +5857,7 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
}
if (sum <= SMALL_ARRAY_LEN) {
- VALUE ary_union = rb_ary_new();
+ ary_union = rb_ary_new();
rb_ary_union(ary_union, ary);
for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]);
@@ -5647,7 +5868,9 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
hash = ary_make_hash(ary);
for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]);
- return rb_hash_values(hash);
+ ary_union = rb_hash_values(hash);
+ ary_recycle_hash(hash);
+ return ary_union;
}
/*
@@ -5663,8 +5886,6 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
* a.intersect?(b) #=> true
* a.intersect?(c) #=> false
*
- * Array elements are compared using <tt>eql?</tt>
- * (items must also implement +hash+ correctly).
*/
static VALUE
@@ -5703,6 +5924,7 @@ rb_ary_intersect_p(VALUE ary1, VALUE ary2)
break;
}
}
+ ary_recycle_hash(hash);
return result;
}
@@ -5809,20 +6031,20 @@ ary_max_opt_string(VALUE ary, long i, VALUE vmax)
* - A new \Array of maximum-valued elements selected from +self+.
*
* When no block is given, each element in +self+ must respond to method <tt><=></tt>
- * with an Integer.
+ * with an \Integer.
*
* With no argument and no block, returns the element in +self+
* having the maximum value per method <tt><=></tt>:
*
* [0, 1, 2].max # => 2
*
- * With an argument Integer +n+ and no block, returns a new \Array with at most +n+ elements,
+ * With an argument \Integer +n+ and no block, returns a new \Array with at most +n+ elements,
* in descending order per method <tt><=></tt>:
*
* [0, 1, 2, 3].max(3) # => [3, 2, 1]
* [0, 1, 2, 3].max(6) # => [3, 2, 1, 0]
*
- * When a block is given, the block must return an Integer.
+ * When a block is given, the block must return an \Integer.
*
* With a block and no argument, calls the block <tt>self.size-1</tt> times to compare elements;
* returns the element having the maximum value per the block:
@@ -5977,14 +6199,14 @@ ary_min_opt_string(VALUE ary, long i, VALUE vmin)
* - A new \Array of minimum-valued elements selected from +self+.
*
* When no block is given, each element in +self+ must respond to method <tt><=></tt>
- * with an Integer.
+ * with an \Integer.
*
* With no argument and no block, returns the element in +self+
* having the minimum value per method <tt><=></tt>:
*
* [0, 1, 2].min # => 0
*
- * With Integer argument +n+ and no block, returns a new \Array with at most +n+ elements,
+ * With \Integer argument +n+ and no block, returns a new \Array with at most +n+ elements,
* in ascending order per method <tt><=></tt>:
*
* [0, 1, 2, 3].min(3) # => [0, 1, 2]
@@ -6052,13 +6274,13 @@ rb_ary_min(int argc, VALUE *argv, VALUE ary)
* from +self+, either per method <tt><=></tt> or per a given block:.
*
* When no block is given, each element in +self+ must respond to method <tt><=></tt>
- * with an Integer;
+ * with an \Integer;
* returns a new 2-element \Array containing the minimum and maximum values
* from +self+, per method <tt><=></tt>:
*
* [0, 1, 2].minmax # => [0, 2]
*
- * When a block is given, the block must return an Integer;
+ * When a block is given, the block must return an \Integer;
* the block is called <tt>self.size-1</tt> times to compare elements;
* returns a new 2-element \Array containing the minimum and maximum values
* from +self+, per the block:
@@ -6137,6 +6359,7 @@ rb_ary_uniq_bang(VALUE ary)
}
ary_resize_capa(ary, hash_size);
rb_hash_foreach(hash, push_value, ary);
+ ary_recycle_hash(hash);
return ary;
}
@@ -6181,6 +6404,9 @@ rb_ary_uniq(VALUE ary)
hash = ary_make_hash(ary);
uniq = rb_hash_values(hash);
}
+ if (hash) {
+ ary_recycle_hash(hash);
+ }
return uniq;
}
@@ -6201,14 +6427,14 @@ rb_ary_compact_bang(VALUE ary)
long n;
rb_ary_modify(ary);
- p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */
+ p = t = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary); /* WB: no new reference */
end = p + RARRAY_LEN(ary);
while (t < end) {
if (NIL_P(*t)) t++;
else *p++ = *t++;
}
- n = p - RARRAY_CONST_PTR(ary);
+ n = p - RARRAY_CONST_PTR_TRANSIENT(ary);
if (RARRAY_LEN(ary) == n) {
return Qnil;
}
@@ -6295,12 +6521,6 @@ rb_ary_count(int argc, VALUE *argv, VALUE ary)
static VALUE
flatten(VALUE ary, int level)
{
- static const rb_data_type_t flatten_memo_data_type = {
- .wrap_struct_name = "array_flatten_memo_data_type",
- .function = { NULL, (RUBY_DATA_FUNC)st_free_table },
- NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
- };
-
long i;
VALUE stack, result, tmp = 0, elt, vmemo;
st_table *memo = 0;
@@ -6318,7 +6538,7 @@ flatten(VALUE ary, int level)
}
result = ary_new(0, RARRAY_LEN(ary));
- ary_memcpy(result, 0, i, RARRAY_CONST_PTR(ary));
+ ary_memcpy(result, 0, i, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_LEN(result, i);
stack = ary_new(0, ARY_DEFAULT_SIZE);
@@ -6326,8 +6546,10 @@ flatten(VALUE ary, int level)
rb_ary_push(stack, LONG2NUM(i + 1));
if (level < 0) {
+ vmemo = rb_hash_new();
+ RBASIC_CLEAR_CLASS(vmemo);
memo = st_init_numtable();
- vmemo = TypedData_Wrap_Struct(0, &flatten_memo_data_type, memo);
+ rb_hash_st_table_set(vmemo, memo);
st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
st_insert(memo, (st_data_t)tmp, (st_data_t)Qtrue);
}
@@ -6396,7 +6618,7 @@ flatten(VALUE ary, int level)
* Replaces each nested \Array in +self+ with the elements from that \Array;
* returns +self+ if any changes, +nil+ otherwise.
*
- * With non-negative Integer argument +level+, flattens recursively through +level+ levels:
+ * With non-negative \Integer argument +level+, flattens recursively through +level+ levels:
*
* a = [ 0, [ 1, [2, 3], 4 ], 5 ]
* a.flatten!(1) # => [0, 1, [2, 3], 4, 5]
@@ -6450,7 +6672,7 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
* - Each non-Array element is unchanged.
* - Each \Array is replaced by its individual elements.
*
- * With non-negative Integer argument +level+, flattens recursively through +level+ levels:
+ * With non-negative \Integer argument +level+, flattens recursively through +level+ levels:
*
* a = [ 0, [ 1, [2, 3], 4 ], 5 ]
* a.flatten(0) # => [0, [1, [2, 3], 4], 5]
@@ -6506,7 +6728,7 @@ rb_ary_shuffle_bang(rb_execution_context_t *ec, VALUE ary, VALUE randgen)
while (i) {
long j = RAND_UPTO(i);
VALUE tmp;
- if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR(ary)) {
+ if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR_TRANSIENT(ary)) {
rb_raise(rb_eRuntimeError, "modified during shuffle");
}
tmp = ptr[--i];
@@ -6598,7 +6820,7 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
sorted[j] = idx[i] = k;
}
result = rb_ary_new_capa(n);
- RARRAY_PTR_USE(result, ptr_result, {
+ RARRAY_PTR_USE_TRANSIENT(result, ptr_result, {
for (i=0; i<n; i++) {
ptr_result[i] = RARRAY_AREF(ary, idx[i]);
}
@@ -6621,7 +6843,7 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
len = RARRAY_LEN(ary);
if (len <= max_idx) n = 0;
else if (n > len) n = len;
- RARRAY_PTR_USE(ary, ptr_ary, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr_ary, {
for (i=0; i<n; i++) {
long j2 = j = ptr_result[i];
long i2 = i;
@@ -6684,7 +6906,7 @@ rb_ary_cycle_size(VALUE self, VALUE args, VALUE eobj)
* array.cycle -> new_enumerator
* array.cycle(count) -> new_enumerator
*
- * When called with positive Integer argument +count+ and a block,
+ * When called with positive \Integer argument +count+ and a block,
* calls the block with each element, then does so again,
* until it has done so +count+ times; returns +nil+:
*
@@ -6703,7 +6925,7 @@ rb_ary_cycle_size(VALUE self, VALUE args, VALUE eobj)
* [0, 1].cycle {|element| puts element }
* [0, 1].cycle(nil) {|element| puts element }
*
- * When no block is given, returns a new Enumerator:
+ * When no block is given, returns a new \Enumerator:
*
* [0, 1].cycle(2) # => #<Enumerator: [0, 1]:cycle(2)>
* [0, 1].cycle # => # => #<Enumerator: [0, 1]:cycle>
@@ -6860,7 +7082,7 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* When invoked with a block, yield all permutations of elements of +self+; returns +self+.
* The order of permutations is indeterminate.
*
- * When a block and an in-range positive Integer argument +n+ (<tt>0 < n <= self.size</tt>)
+ * When a block and an in-range positive \Integer argument +n+ (<tt>0 < n <= self.size</tt>)
* are given, calls the block with all +n+-tuple permutations of +self+.
*
* Example:
@@ -6922,7 +7144,7 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* [2, 0, 1]
* [2, 1, 0]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [0, 1, 2]
* a.permutation # => #<Enumerator: [0, 1, 2]:permutation>
@@ -7006,7 +7228,7 @@ rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj)
* Calls the block, if given, with combinations of elements of +self+;
* returns +self+. The order of combinations is indeterminate.
*
- * When a block and an in-range positive Integer argument +n+ (<tt>0 < n <= self.size</tt>)
+ * When a block and an in-range positive \Integer argument +n+ (<tt>0 < n <= self.size</tt>)
* are given, calls the block with all +n+-tuple combinations of +self+.
*
* Example:
@@ -7045,7 +7267,7 @@ rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj)
* a.combination(-1) {|combination| fail 'Cannot happen' }
* a.combination(4) {|combination| fail 'Cannot happen' }
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [0, 1, 2]
* a.combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
@@ -7143,7 +7365,7 @@ rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* each permutation is an \Array;
* returns +self+. The order of the permutations is indeterminate.
*
- * When a block and a positive Integer argument +n+ are given, calls the block with each
+ * When a block and a positive \Integer argument +n+ are given, calls the block with each
* +n+-tuple repeated permutation of the elements of +self+.
* The number of permutations is <tt>self.size**n</tt>.
*
@@ -7180,7 +7402,7 @@ rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj)
*
* a.repeated_permutation(-1) {|permutation| fail 'Cannot happen' }
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [0, 1, 2]
* a.repeated_permutation(2) # => #<Enumerator: [0, 1, 2]:permutation(2)>
@@ -7275,7 +7497,7 @@ rb_ary_repeated_combination_size(VALUE ary, VALUE args, VALUE eobj)
* each combination is an \Array;
* returns +self+. The order of the combinations is indeterminate.
*
- * When a block and a positive Integer argument +n+ are given, calls the block with each
+ * When a block and a positive \Integer argument +n+ are given, calls the block with each
* +n+-tuple repeated combination of the elements of +self+.
* The number of combinations is <tt>(n+1)(n+2)/2</tt>.
*
@@ -7309,7 +7531,7 @@ rb_ary_repeated_combination_size(VALUE ary, VALUE args, VALUE eobj)
*
* a.repeated_combination(-1) {|combination| fail 'Cannot happen' }
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [0, 1, 2]
* a.repeated_combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
@@ -7517,7 +7739,7 @@ done:
* array.take(n) -> new_array
*
* Returns a new \Array containing the first +n+ element of +self+,
- * where +n+ is a non-negative Integer;
+ * where +n+ is a non-negative \Integer;
* does not modify +self+.
*
* Examples:
@@ -7557,7 +7779,7 @@ rb_ary_take(VALUE obj, VALUE n)
* a.take_while {|element| true } # => [0, 1, 2, 3, 4, 5]
* a # => [0, 1, 2, 3, 4, 5]
*
- * With no block given, returns a new Enumerator:
+ * With no block given, returns a new \Enumerator:
*
* [0, 1].take_while # => #<Enumerator: [0, 1]:take_while>
*
@@ -7580,7 +7802,7 @@ rb_ary_take_while(VALUE ary)
* array.drop(n) -> new_array
*
* Returns a new \Array containing all but the first +n+ element of +self+,
- * where +n+ is a non-negative Integer;
+ * where +n+ is a non-negative \Integer;
* does not modify +self+.
*
* Examples:
@@ -7621,7 +7843,7 @@ rb_ary_drop(VALUE ary, VALUE n)
* a = [0, 1, 2, 3, 4, 5]
* a.drop_while {|element| element < 3 } # => [3, 4, 5]
*
- * With no block given, returns a new Enumerator:
+ * With no block given, returns a new \Enumerator:
*
* [0, 1].drop_while # => # => #<Enumerator: [0, 1]:drop_while>
*
@@ -7647,9 +7869,6 @@ rb_ary_drop_while(VALUE ary)
*
* Returns +true+ if any element of +self+ meets a given criterion.
*
- * If +self+ has no element, returns +false+ and argument or block
- * are not used.
- *
* With no block given and no argument, returns +true+ if +self+ has any truthy element,
* +false+ otherwise:
*
@@ -7711,9 +7930,6 @@ rb_ary_any_p(int argc, VALUE *argv, VALUE ary)
*
* Returns +true+ if all elements of +self+ meet a given criterion.
*
- * If +self+ has no element, returns +true+ and argument or block
- * are not used.
- *
* With no block given and no argument, returns +true+ if +self+ contains only truthy elements,
* +false+ otherwise:
*
@@ -7999,12 +8215,6 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
n = 0;
r = Qundef;
-
- if (!FIXNUM_P(v) && !RB_BIGNUM_TYPE_P(v) && !RB_TYPE_P(v, T_RATIONAL)) {
- i = 0;
- goto init_is_a_value;
- }
-
for (i = 0; i < RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (block_given)
@@ -8089,7 +8299,6 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
}
goto has_some_value;
- init_is_a_value:
for (; i < RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (block_given)
@@ -8627,6 +8836,8 @@ Init_Array(void)
rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1);
rb_define_method(rb_cArray, "at", rb_ary_at, 1);
rb_define_method(rb_cArray, "fetch", rb_ary_fetch, -1);
+ rb_define_method(rb_cArray, "first", rb_ary_first, -1);
+ rb_define_method(rb_cArray, "last", rb_ary_last, -1);
rb_define_method(rb_cArray, "concat", rb_ary_concat_multi, -1);
rb_define_method(rb_cArray, "union", rb_ary_union_multi, -1);
rb_define_method(rb_cArray, "difference", rb_ary_difference_multi, -1);
diff --git a/array.rb b/array.rb
index d17f374235..b9fa9844e6 100644
--- a/array.rb
+++ b/array.rb
@@ -66,92 +66,4 @@ class Array
Primitive.ary_sample(random, n, ary)
end
end
-
- # call-seq:
- # array.first -> object or nil
- # array.first(n) -> new_array
- #
- # Returns elements from +self+; does not modify +self+.
- #
- # When no argument is given, returns the first element:
- #
- # a = [:foo, 'bar', 2]
- # a.first # => :foo
- # a # => [:foo, "bar", 2]
- #
- # If +self+ is empty, returns +nil+.
- #
- # When non-negative Integer argument +n+ is given,
- # returns the first +n+ elements in a new \Array:
- #
- # a = [:foo, 'bar', 2]
- # a.first(2) # => [:foo, "bar"]
- #
- # If <tt>n >= array.size</tt>, returns all elements:
- #
- # a = [:foo, 'bar', 2]
- # a.first(50) # => [:foo, "bar", 2]
- #
- # If <tt>n == 0</tt> returns an new empty \Array:
- #
- # a = [:foo, 'bar', 2]
- # a.first(0) # []
- #
- # Related: #last.
- def first n = unspecified = true
- if Primitive.mandatory_only?
- Primitive.attr! :leaf
- Primitive.cexpr! %q{ ary_first(self) }
- else
- if unspecified
- Primitive.cexpr! %q{ ary_first(self) }
- else
- Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_FIRST) }
- end
- end
- end
-
- # call-seq:
- # array.last -> object or nil
- # array.last(n) -> new_array
- #
- # Returns elements from +self+; +self+ is not modified.
- #
- # When no argument is given, returns the last element:
- #
- # a = [:foo, 'bar', 2]
- # a.last # => 2
- # a # => [:foo, "bar", 2]
- #
- # If +self+ is empty, returns +nil+.
- #
- # When non-negative Integer argument +n+ is given,
- # returns the last +n+ elements in a new \Array:
- #
- # a = [:foo, 'bar', 2]
- # a.last(2) # => ["bar", 2]
- #
- # If <tt>n >= array.size</tt>, returns all elements:
- #
- # a = [:foo, 'bar', 2]
- # a.last(50) # => [:foo, "bar", 2]
- #
- # If <tt>n == 0</tt>, returns an new empty \Array:
- #
- # a = [:foo, 'bar', 2]
- # a.last(0) # []
- #
- # Related: #first.
- def last n = unspecified = true
- if Primitive.mandatory_only?
- Primitive.attr! :leaf
- Primitive.cexpr! %q{ ary_last(self) }
- else
- if unspecified
- Primitive.cexpr! %q{ ary_last(self) }
- else
- Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_LAST) }
- end
- end
- end
end
diff --git a/ast.c b/ast.c
index 50a54a9f4b..adb7287ed3 100644
--- a/ast.c
+++ b/ast.c
@@ -1,6 +1,6 @@
/* indent-tabs-mode: nil */
#include "internal.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
#include "internal/symbol.h"
#include "internal/warnings.h"
#include "iseq.h"
@@ -97,7 +97,7 @@ rb_ast_parse_str(VALUE str, VALUE keep_script_lines, VALUE error_tolerant, VALUE
StringValue(str);
VALUE vparser = ast_parse_new();
- if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser, Qtrue);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
ast = rb_parser_compile_string_path(vparser, Qnil, str, 1);
@@ -117,10 +117,11 @@ rb_ast_parse_file(VALUE path, VALUE keep_script_lines, VALUE error_tolerant, VAL
rb_ast_t *ast = 0;
rb_encoding *enc = rb_utf8_encoding();
+ FilePathValue(path);
f = rb_file_open_str(path, "r");
rb_funcall(f, rb_intern("set_encoding"), 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
VALUE vparser = ast_parse_new();
- if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser, Qtrue);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
ast = rb_parser_compile_file_path(vparser, Qnil, f, 1);
@@ -148,7 +149,7 @@ rb_ast_parse_array(VALUE array, VALUE keep_script_lines, VALUE error_tolerant, V
array = rb_check_array_type(array);
VALUE vparser = ast_parse_new();
- if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser, Qtrue);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
ast = rb_parser_compile_generic(vparser, lex_array, Qnil, array, 1);
@@ -183,8 +184,8 @@ node_find(VALUE self, const int node_id)
extern VALUE rb_e_script;
-VALUE
-rb_script_lines_for(VALUE path, bool add)
+static VALUE
+script_lines(VALUE path)
{
VALUE hash, lines;
ID script_lines;
@@ -192,19 +193,10 @@ rb_script_lines_for(VALUE path, bool add)
if (!rb_const_defined_at(rb_cObject, script_lines)) return Qnil;
hash = rb_const_get_at(rb_cObject, script_lines);
if (!RB_TYPE_P(hash, T_HASH)) return Qnil;
- if (add) {
- rb_hash_aset(hash, path, lines = rb_ary_new());
- }
- else if (!RB_TYPE_P((lines = rb_hash_lookup(hash, path)), T_ARRAY)) {
- return Qnil;
- }
+ lines = rb_hash_lookup(hash, path);
+ if (!RB_TYPE_P(lines, T_ARRAY)) return Qnil;
return lines;
}
-static VALUE
-script_lines(VALUE path)
-{
- return rb_script_lines_for(path, false);
-}
static VALUE
node_id_for_backtrace_location(rb_execution_context_t *ec, VALUE module, VALUE location)
@@ -330,14 +322,14 @@ rb_ary_new_from_node_args(rb_ast_t *ast, long n, ...)
}
static VALUE
-dump_block(rb_ast_t *ast, const struct RNode_BLOCK *node)
+dump_block(rb_ast_t *ast, const NODE *node)
{
VALUE ary = rb_ary_new();
do {
rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
} while (node->nd_next &&
nd_type_p(node->nd_next, NODE_BLOCK) &&
- (node = RNODE_BLOCK(node->nd_next), 1));
+ (node = node->nd_next, 1));
if (node->nd_next) {
rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
}
@@ -346,13 +338,13 @@ dump_block(rb_ast_t *ast, const struct RNode_BLOCK *node)
}
static VALUE
-dump_array(rb_ast_t *ast, const struct RNode_LIST *node)
+dump_array(rb_ast_t *ast, const NODE *node)
{
VALUE ary = rb_ary_new();
rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
while (node->nd_next && nd_type_p(node->nd_next, NODE_LIST)) {
- node = RNODE_LIST(node->nd_next);
+ node = node->nd_next;
rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
}
rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
@@ -385,229 +377,211 @@ rest_arg(rb_ast_t *ast, const NODE *rest_arg)
static VALUE
node_children(rb_ast_t *ast, const NODE *node)
{
- char name[sizeof("$") + DECIMAL_SIZE_OF(long)];
+ char name[DECIMAL_SIZE_OF_BITS(sizeof(long) * CHAR_BIT) + 2]; /* including '$' */
enum node_type type = nd_type(node);
switch (type) {
case NODE_BLOCK:
- return dump_block(ast, RNODE_BLOCK(node));
+ return dump_block(ast, node);
case NODE_IF:
- return rb_ary_new_from_node_args(ast, 3, RNODE_IF(node)->nd_cond, RNODE_IF(node)->nd_body, RNODE_IF(node)->nd_else);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_cond, node->nd_body, node->nd_else);
case NODE_UNLESS:
- return rb_ary_new_from_node_args(ast, 3, RNODE_UNLESS(node)->nd_cond, RNODE_UNLESS(node)->nd_body, RNODE_UNLESS(node)->nd_else);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_cond, node->nd_body, node->nd_else);
case NODE_CASE:
- return rb_ary_new_from_node_args(ast, 2, RNODE_CASE(node)->nd_head, RNODE_CASE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_CASE2:
- return rb_ary_new_from_node_args(ast, 2, RNODE_CASE2(node)->nd_head, RNODE_CASE2(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_CASE3:
- return rb_ary_new_from_node_args(ast, 2, RNODE_CASE3(node)->nd_head, RNODE_CASE3(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_WHEN:
- return rb_ary_new_from_node_args(ast, 3, RNODE_WHEN(node)->nd_head, RNODE_WHEN(node)->nd_body, RNODE_WHEN(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_body, node->nd_next);
case NODE_IN:
- return rb_ary_new_from_node_args(ast, 3, RNODE_IN(node)->nd_head, RNODE_IN(node)->nd_body, RNODE_IN(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_body, node->nd_next);
case NODE_WHILE:
case NODE_UNTIL:
- return rb_ary_push(rb_ary_new_from_node_args(ast, 2, RNODE_WHILE(node)->nd_cond, RNODE_WHILE(node)->nd_body),
- RBOOL(RNODE_WHILE(node)->nd_state));
+ return rb_ary_push(rb_ary_new_from_node_args(ast, 2, node->nd_cond, node->nd_body),
+ RBOOL(node->nd_state));
case NODE_ITER:
case NODE_FOR:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ITER(node)->nd_iter, RNODE_ITER(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_iter, node->nd_body);
case NODE_FOR_MASGN:
- return rb_ary_new_from_node_args(ast, 1, RNODE_FOR_MASGN(node)->nd_var);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_var);
case NODE_BREAK:
- return rb_ary_new_from_node_args(ast, 1, RNODE_BREAK(node)->nd_stts);
case NODE_NEXT:
- return rb_ary_new_from_node_args(ast, 1, RNODE_NEXT(node)->nd_stts);
case NODE_RETURN:
- return rb_ary_new_from_node_args(ast, 1, RNODE_RETURN(node)->nd_stts);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_stts);
case NODE_REDO:
return rb_ary_new_from_node_args(ast, 0);
case NODE_RETRY:
return rb_ary_new_from_node_args(ast, 0);
case NODE_BEGIN:
- return rb_ary_new_from_node_args(ast, 1, RNODE_BEGIN(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_RESCUE:
- return rb_ary_new_from_node_args(ast, 3, RNODE_RESCUE(node)->nd_head, RNODE_RESCUE(node)->nd_resq, RNODE_RESCUE(node)->nd_else);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_resq, node->nd_else);
case NODE_RESBODY:
- return rb_ary_new_from_node_args(ast, 3, RNODE_RESBODY(node)->nd_args, RNODE_RESBODY(node)->nd_body, RNODE_RESBODY(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_args, node->nd_body, node->nd_head);
case NODE_ENSURE:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ENSURE(node)->nd_head, RNODE_ENSURE(node)->nd_ensr);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_ensr);
case NODE_AND:
case NODE_OR:
{
VALUE ary = rb_ary_new();
while (1) {
- rb_ary_push(ary, NEW_CHILD(ast, RNODE_AND(node)->nd_1st));
- if (!RNODE_AND(node)->nd_2nd || !nd_type_p(RNODE_AND(node)->nd_2nd, type))
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_1st));
+ if (!node->nd_2nd || !nd_type_p(node->nd_2nd, type))
break;
- node = RNODE_AND(node)->nd_2nd;
+ node = node->nd_2nd;
}
- rb_ary_push(ary, NEW_CHILD(ast, RNODE_AND(node)->nd_2nd));
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_2nd));
return ary;
}
case NODE_MASGN:
- if (NODE_NAMED_REST_P(RNODE_MASGN(node)->nd_args)) {
- return rb_ary_new_from_node_args(ast, 3, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head, RNODE_MASGN(node)->nd_args);
+ if (NODE_NAMED_REST_P(node->nd_args)) {
+ return rb_ary_new_from_node_args(ast, 3, node->nd_value, node->nd_head, node->nd_args);
}
else {
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_MASGN(node)->nd_value),
- NEW_CHILD(ast, RNODE_MASGN(node)->nd_head),
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_value),
+ NEW_CHILD(ast, node->nd_head),
no_name_rest());
}
case NODE_LASGN:
- if (NODE_REQUIRED_KEYWORD_P(RNODE_LASGN(node)->nd_value)) {
- return rb_ary_new_from_args(2, var_name(RNODE_LASGN(node)->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
- }
- return rb_ary_new_from_args(2, var_name(RNODE_LASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_LASGN(node)->nd_value));
case NODE_DASGN:
- if (NODE_REQUIRED_KEYWORD_P(RNODE_DASGN(node)->nd_value)) {
- return rb_ary_new_from_args(2, var_name(RNODE_DASGN(node)->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
- }
- return rb_ary_new_from_args(2, var_name(RNODE_DASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_DASGN(node)->nd_value));
case NODE_IASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_IASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_IASGN(node)->nd_value));
case NODE_CVASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_CVASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_CVASGN(node)->nd_value));
case NODE_GASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_GASGN(node)->nd_vid), NEW_CHILD(ast, RNODE_GASGN(node)->nd_value));
+ if (NODE_REQUIRED_KEYWORD_P(node)) {
+ return rb_ary_new_from_args(2, var_name(node->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
+ }
+ return rb_ary_new_from_args(2, var_name(node->nd_vid), NEW_CHILD(ast, node->nd_value));
case NODE_CDECL:
- if (RNODE_CDECL(node)->nd_vid) {
- return rb_ary_new_from_args(2, ID2SYM(RNODE_CDECL(node)->nd_vid), NEW_CHILD(ast, RNODE_CDECL(node)->nd_value));
+ if (node->nd_vid) {
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_vid), NEW_CHILD(ast, node->nd_value));
}
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_CDECL(node)->nd_else), ID2SYM(RNODE_COLON2(RNODE_CDECL(node)->nd_else)->nd_mid), NEW_CHILD(ast, RNODE_CDECL(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_else), ID2SYM(node->nd_else->nd_mid), NEW_CHILD(ast, node->nd_value));
case NODE_OP_ASGN1:
- return rb_ary_new_from_args(4, NEW_CHILD(ast, RNODE_OP_ASGN1(node)->nd_recv),
- ID2SYM(RNODE_OP_ASGN1(node)->nd_mid),
- NEW_CHILD(ast, RNODE_OP_ASGN1(node)->nd_index),
- NEW_CHILD(ast, RNODE_OP_ASGN1(node)->nd_rvalue));
+ return rb_ary_new_from_args(4, NEW_CHILD(ast, node->nd_recv),
+ ID2SYM(node->nd_mid),
+ NEW_CHILD(ast, node->nd_args->nd_head),
+ NEW_CHILD(ast, node->nd_args->nd_body));
case NODE_OP_ASGN2:
- return rb_ary_new_from_args(5, NEW_CHILD(ast, RNODE_OP_ASGN2(node)->nd_recv),
- RBOOL(RNODE_OP_ASGN2(node)->nd_aid),
- ID2SYM(RNODE_OP_ASGN2(node)->nd_vid),
- ID2SYM(RNODE_OP_ASGN2(node)->nd_mid),
- NEW_CHILD(ast, RNODE_OP_ASGN2(node)->nd_value));
+ return rb_ary_new_from_args(5, NEW_CHILD(ast, node->nd_recv),
+ RBOOL(node->nd_next->nd_aid),
+ ID2SYM(node->nd_next->nd_vid),
+ ID2SYM(node->nd_next->nd_mid),
+ NEW_CHILD(ast, node->nd_value));
case NODE_OP_ASGN_AND:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OP_ASGN_AND(node)->nd_head), ID2SYM(idANDOP),
- NEW_CHILD(ast, RNODE_OP_ASGN_AND(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head), ID2SYM(idANDOP),
+ NEW_CHILD(ast, node->nd_value));
case NODE_OP_ASGN_OR:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OP_ASGN_OR(node)->nd_head), ID2SYM(idOROP),
- NEW_CHILD(ast, RNODE_OP_ASGN_OR(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head), ID2SYM(idOROP),
+ NEW_CHILD(ast, node->nd_value));
case NODE_OP_CDECL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OP_CDECL(node)->nd_head),
- ID2SYM(RNODE_OP_CDECL(node)->nd_aid),
- NEW_CHILD(ast, RNODE_OP_CDECL(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head),
+ ID2SYM(node->nd_aid),
+ NEW_CHILD(ast, node->nd_value));
case NODE_CALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_CALL(node)->nd_recv),
- ID2SYM(RNODE_CALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_CALL(node)->nd_args));
case NODE_OPCALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_OPCALL(node)->nd_recv),
- ID2SYM(RNODE_OPCALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_OPCALL(node)->nd_args));
case NODE_QCALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_QCALL(node)->nd_recv),
- ID2SYM(RNODE_QCALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_QCALL(node)->nd_args));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv),
+ ID2SYM(node->nd_mid),
+ NEW_CHILD(ast, node->nd_args));
case NODE_FCALL:
- return rb_ary_new_from_args(2, ID2SYM(RNODE_FCALL(node)->nd_mid),
- NEW_CHILD(ast, RNODE_FCALL(node)->nd_args));
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_mid),
+ NEW_CHILD(ast, node->nd_args));
case NODE_VCALL:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_VCALL(node)->nd_mid));
+ return rb_ary_new_from_args(1, ID2SYM(node->nd_mid));
case NODE_SUPER:
- return rb_ary_new_from_node_args(ast, 1, RNODE_SUPER(node)->nd_args);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_args);
case NODE_ZSUPER:
return rb_ary_new_from_node_args(ast, 0);
case NODE_LIST:
- return dump_array(ast, RNODE_LIST(node));
+ case NODE_VALUES:
+ return dump_array(ast, node);
case NODE_ZLIST:
return rb_ary_new_from_node_args(ast, 0);
case NODE_HASH:
- return rb_ary_new_from_node_args(ast, 1, RNODE_HASH(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_YIELD:
- return rb_ary_new_from_node_args(ast, 1, RNODE_YIELD(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_LVAR:
- return rb_ary_new_from_args(1, var_name(RNODE_LVAR(node)->nd_vid));
case NODE_DVAR:
- return rb_ary_new_from_args(1, var_name(RNODE_DVAR(node)->nd_vid));
+ return rb_ary_new_from_args(1, var_name(node->nd_vid));
case NODE_IVAR:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_IVAR(node)->nd_vid));
case NODE_CONST:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
case NODE_CVAR:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_CVAR(node)->nd_vid));
case NODE_GVAR:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_GVAR(node)->nd_vid));
+ return rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
case NODE_NTH_REF:
- snprintf(name, sizeof(name), "$%ld", RNODE_NTH_REF(node)->nd_nth);
+ snprintf(name, sizeof(name), "$%ld", node->nd_nth);
return rb_ary_new_from_args(1, ID2SYM(rb_intern(name)));
case NODE_BACK_REF:
name[0] = '$';
- name[1] = (char)RNODE_BACK_REF(node)->nd_nth;
+ name[1] = (char)node->nd_nth;
name[2] = '\0';
return rb_ary_new_from_args(1, ID2SYM(rb_intern(name)));
case NODE_MATCH2:
- if (RNODE_MATCH2(node)->nd_args) {
- return rb_ary_new_from_node_args(ast, 3, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value, RNODE_MATCH2(node)->nd_args);
+ if (node->nd_args) {
+ return rb_ary_new_from_node_args(ast, 3, node->nd_recv, node->nd_value, node->nd_args);
}
- return rb_ary_new_from_node_args(ast, 2, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_value);
case NODE_MATCH3:
- return rb_ary_new_from_node_args(ast, 2, RNODE_MATCH3(node)->nd_recv, RNODE_MATCH3(node)->nd_value);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_value);
case NODE_MATCH:
case NODE_LIT:
case NODE_STR:
case NODE_XSTR:
- return rb_ary_new_from_args(1, RNODE_LIT(node)->nd_lit);
+ return rb_ary_new_from_args(1, node->nd_lit);
case NODE_ONCE:
- return rb_ary_new_from_node_args(ast, 1, RNODE_ONCE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_DSTR:
case NODE_DXSTR:
case NODE_DREGX:
case NODE_DSYM:
{
- struct RNode_LIST *n = RNODE_DSTR(node)->nd_next;
+ NODE *n = node->nd_next;
VALUE head = Qnil, next = Qnil;
if (n) {
head = NEW_CHILD(ast, n->nd_head);
next = NEW_CHILD(ast, n->nd_next);
}
- return rb_ary_new_from_args(3, RNODE_DSTR(node)->nd_lit, head, next);
+ return rb_ary_new_from_args(3, node->nd_lit, head, next);
}
case NODE_EVSTR:
- return rb_ary_new_from_node_args(ast, 1, RNODE_EVSTR(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_ARGSCAT:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ARGSCAT(node)->nd_head, RNODE_ARGSCAT(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_ARGSPUSH:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ARGSPUSH(node)->nd_head, RNODE_ARGSPUSH(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_SPLAT:
- return rb_ary_new_from_node_args(ast, 1, RNODE_SPLAT(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_BLOCK_PASS:
- return rb_ary_new_from_node_args(ast, 2, RNODE_BLOCK_PASS(node)->nd_head, RNODE_BLOCK_PASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_DEFN:
- return rb_ary_new_from_args(2, ID2SYM(RNODE_DEFN(node)->nd_mid), NEW_CHILD(ast, RNODE_DEFN(node)->nd_defn));
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_defn));
case NODE_DEFS:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_DEFS(node)->nd_recv), ID2SYM(RNODE_DEFS(node)->nd_mid), NEW_CHILD(ast, RNODE_DEFS(node)->nd_defn));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv), ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_defn));
case NODE_ALIAS:
- return rb_ary_new_from_node_args(ast, 2, RNODE_ALIAS(node)->nd_1st, RNODE_ALIAS(node)->nd_2nd);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_1st, node->nd_2nd);
case NODE_VALIAS:
- return rb_ary_new_from_args(2, ID2SYM(RNODE_VALIAS(node)->nd_alias), ID2SYM(RNODE_VALIAS(node)->nd_orig));
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_alias), ID2SYM(node->nd_orig));
case NODE_UNDEF:
- return rb_ary_new_from_node_args(ast, 1, RNODE_UNDEF(node)->nd_undef);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_undef);
case NODE_CLASS:
- return rb_ary_new_from_node_args(ast, 3, RNODE_CLASS(node)->nd_cpath, RNODE_CLASS(node)->nd_super, RNODE_CLASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_cpath, node->nd_super, node->nd_body);
case NODE_MODULE:
- return rb_ary_new_from_node_args(ast, 2, RNODE_MODULE(node)->nd_cpath, RNODE_MODULE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_cpath, node->nd_body);
case NODE_SCLASS:
- return rb_ary_new_from_node_args(ast, 2, RNODE_SCLASS(node)->nd_recv, RNODE_SCLASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_body);
case NODE_COLON2:
- return rb_ary_new_from_args(2, NEW_CHILD(ast, RNODE_COLON2(node)->nd_head), ID2SYM(RNODE_COLON2(node)->nd_mid));
+ return rb_ary_new_from_args(2, NEW_CHILD(ast, node->nd_head), ID2SYM(node->nd_mid));
case NODE_COLON3:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ return rb_ary_new_from_args(1, ID2SYM(node->nd_mid));
case NODE_DOT2:
case NODE_DOT3:
case NODE_FLIP2:
case NODE_FLIP3:
- return rb_ary_new_from_node_args(ast, 2, RNODE_DOT2(node)->nd_beg, RNODE_DOT2(node)->nd_end);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_beg, node->nd_end);
case NODE_SELF:
return rb_ary_new_from_node_args(ast, 0);
case NODE_NIL:
@@ -619,84 +593,84 @@ node_children(rb_ast_t *ast, const NODE *node)
case NODE_ERRINFO:
return rb_ary_new_from_node_args(ast, 0);
case NODE_DEFINED:
- return rb_ary_new_from_node_args(ast, 1, RNODE_DEFINED(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_POSTEXE:
- return rb_ary_new_from_node_args(ast, 1, RNODE_POSTEXE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_ATTRASGN:
- return rb_ary_new_from_args(3, NEW_CHILD(ast, RNODE_ATTRASGN(node)->nd_recv), ID2SYM(RNODE_ATTRASGN(node)->nd_mid), NEW_CHILD(ast, RNODE_ATTRASGN(node)->nd_args));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv), ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_args));
case NODE_LAMBDA:
- return rb_ary_new_from_node_args(ast, 1, RNODE_LAMBDA(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_OPT_ARG:
- return rb_ary_new_from_node_args(ast, 2, RNODE_OPT_ARG(node)->nd_body, RNODE_OPT_ARG(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_body, node->nd_next);
case NODE_KW_ARG:
- return rb_ary_new_from_node_args(ast, 2, RNODE_KW_ARG(node)->nd_body, RNODE_KW_ARG(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_body, node->nd_next);
case NODE_POSTARG:
- if (NODE_NAMED_REST_P(RNODE_POSTARG(node)->nd_1st)) {
- return rb_ary_new_from_node_args(ast, 2, RNODE_POSTARG(node)->nd_1st, RNODE_POSTARG(node)->nd_2nd);
+ if (NODE_NAMED_REST_P(node->nd_1st)) {
+ return rb_ary_new_from_node_args(ast, 2, node->nd_1st, node->nd_2nd);
}
return rb_ary_new_from_args(2, no_name_rest(),
- NEW_CHILD(ast, RNODE_POSTARG(node)->nd_2nd));
+ NEW_CHILD(ast, node->nd_2nd));
case NODE_ARGS:
{
- struct rb_args_info *ainfo = &RNODE_ARGS(node)->nd_ainfo;
+ struct rb_args_info *ainfo = node->nd_ainfo;
return rb_ary_new_from_args(10,
INT2NUM(ainfo->pre_args_num),
NEW_CHILD(ast, ainfo->pre_init),
- NEW_CHILD(ast, (NODE *)ainfo->opt_args),
+ NEW_CHILD(ast, ainfo->opt_args),
var_name(ainfo->first_post_arg),
INT2NUM(ainfo->post_args_num),
NEW_CHILD(ast, ainfo->post_init),
(ainfo->rest_arg == NODE_SPECIAL_EXCESSIVE_COMMA
? ID2SYM(rb_intern("NODE_SPECIAL_EXCESSIVE_COMMA"))
: var_name(ainfo->rest_arg)),
- (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast, (NODE *)ainfo->kw_args)),
+ (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast, ainfo->kw_args)),
(ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast, ainfo->kw_rest_arg)),
var_name(ainfo->block_arg));
}
case NODE_SCOPE:
{
- rb_ast_id_table_t *tbl = RNODE_SCOPE(node)->nd_tbl;
+ rb_ast_id_table_t *tbl = node->nd_tbl;
int i, size = tbl ? tbl->size : 0;
VALUE locals = rb_ary_new_capa(size);
for (i = 0; i < size; i++) {
rb_ary_push(locals, var_name(tbl->ids[i]));
}
- return rb_ary_new_from_args(3, locals, NEW_CHILD(ast, (NODE *)RNODE_SCOPE(node)->nd_args), NEW_CHILD(ast, RNODE_SCOPE(node)->nd_body));
+ return rb_ary_new_from_args(3, locals, NEW_CHILD(ast, node->nd_args), NEW_CHILD(ast, node->nd_body));
}
case NODE_ARYPTN:
{
- VALUE rest = rest_arg(ast, RNODE_ARYPTN(node)->rest_arg);
+ struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
+ VALUE rest = rest_arg(ast, apinfo->rest_arg);
return rb_ary_new_from_args(4,
- NEW_CHILD(ast, RNODE_ARYPTN(node)->nd_pconst),
- NEW_CHILD(ast, RNODE_ARYPTN(node)->pre_args),
+ NEW_CHILD(ast, node->nd_pconst),
+ NEW_CHILD(ast, apinfo->pre_args),
rest,
- NEW_CHILD(ast, RNODE_ARYPTN(node)->post_args));
+ NEW_CHILD(ast, apinfo->post_args));
}
case NODE_FNDPTN:
{
- VALUE pre_rest = rest_arg(ast, RNODE_FNDPTN(node)->pre_rest_arg);
- VALUE post_rest = rest_arg(ast, RNODE_FNDPTN(node)->post_rest_arg);
+ struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
+ VALUE pre_rest = rest_arg(ast, fpinfo->pre_rest_arg);
+ VALUE post_rest = rest_arg(ast, fpinfo->post_rest_arg);
return rb_ary_new_from_args(4,
- NEW_CHILD(ast, RNODE_FNDPTN(node)->nd_pconst),
+ NEW_CHILD(ast, node->nd_pconst),
pre_rest,
- NEW_CHILD(ast, RNODE_FNDPTN(node)->args),
+ NEW_CHILD(ast, fpinfo->args),
post_rest);
}
case NODE_HSHPTN:
{
- VALUE kwrest = RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD ? ID2SYM(rb_intern("NODE_SPECIAL_NO_REST_KEYWORD")) :
- NEW_CHILD(ast, RNODE_HSHPTN(node)->nd_pkwrestarg);
+ VALUE kwrest = node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD ? ID2SYM(rb_intern("NODE_SPECIAL_NO_REST_KEYWORD")) :
+ NEW_CHILD(ast, node->nd_pkwrestarg);
return rb_ary_new_from_args(3,
- NEW_CHILD(ast, RNODE_HSHPTN(node)->nd_pconst),
- NEW_CHILD(ast, RNODE_HSHPTN(node)->nd_pkwargs),
+ NEW_CHILD(ast, node->nd_pconst),
+ NEW_CHILD(ast, node->nd_pkwargs),
kwrest);
}
case NODE_ERROR:
return rb_ary_new_from_node_args(ast, 0);
case NODE_ARGS_AUX:
- case NODE_RIPPER:
- case NODE_RIPPER_VALUES:
case NODE_LAST:
break;
}
diff --git a/ast.rb b/ast.rb
index 51ee5b3d59..f3f72c747f 100644
--- a/ast.rb
+++ b/ast.rb
@@ -20,7 +20,7 @@
module RubyVM::AbstractSyntaxTree
# call-seq:
- # RubyVM::AbstractSyntaxTree.parse(string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.parse(string, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
#
# Parses the given _string_ into an abstract syntax tree,
# returning the root node of that tree.
@@ -53,14 +53,14 @@ module RubyVM::AbstractSyntaxTree
# # (ERROR@1:7-1:11),
# # (LASGN@1:12-1:15 :y (LIT@1:14-1:15 2))]
#
- # Note that parsing continues even after the errored expression.
+ # Note that parsing continues even after the errored expresion.
#
- def self.parse string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
+ def self.parse string, keep_script_lines: false, error_tolerant: false, keep_tokens: false
Primitive.ast_s_parse string, keep_script_lines, error_tolerant, keep_tokens
end
# call-seq:
- # RubyVM::AbstractSyntaxTree.parse_file(pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.parse_file(pathname, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
#
# Reads the file from _pathname_, then parses it like ::parse,
# returning the root node of the abstract syntax tree.
@@ -72,13 +72,13 @@ module RubyVM::AbstractSyntaxTree
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>
#
# See ::parse for explanation of keyword argument meaning and usage.
- def self.parse_file pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
+ def self.parse_file pathname, keep_script_lines: false, error_tolerant: false, keep_tokens: false
Primitive.ast_s_parse_file pathname, keep_script_lines, error_tolerant, keep_tokens
end
# call-seq:
- # RubyVM::AbstractSyntaxTree.of(proc, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
- # RubyVM::AbstractSyntaxTree.of(method, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.of(proc, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.of(method, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
#
# Returns AST nodes of the given _proc_ or _method_.
#
@@ -93,7 +93,7 @@ module RubyVM::AbstractSyntaxTree
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>
#
# See ::parse for explanation of keyword argument meaning and usage.
- def self.of body, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
+ def self.of body, keep_script_lines: false, error_tolerant: false, keep_tokens: false
Primitive.ast_s_of body, keep_script_lines, error_tolerant, keep_tokens
end
@@ -265,8 +265,8 @@ module RubyVM::AbstractSyntaxTree
lines = script_lines
if lines
lines = lines[first_lineno - 1 .. last_lineno - 1]
- lines[-1] = lines[-1].byteslice(0...last_column)
- lines[0] = lines[0].byteslice(first_column..-1)
+ lines[-1] = lines[-1][0...last_column]
+ lines[0] = lines[0][first_column..-1]
lines.join
else
nil
diff --git a/benchmark/enum_sort_by.yml b/benchmark/enum_sort_by.yml
deleted file mode 100644
index d386353888..0000000000
--- a/benchmark/enum_sort_by.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-prelude: |
- array_length = 2
- fixnum_array2 = array_length.times.to_a.map {rand(10000)}
- float_array2 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array2 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array2 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array2 =array_length.times.to_a.map {0}
-
- array_length = 10
- fixnum_array10 = array_length.times.to_a.map {rand(10000)}
- float_array10 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array10 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array10 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array10 =array_length.times.to_a.map {0}
-
- array_length = 1000
- fixnum_array1000 = array_length.times.to_a.map {rand(10000)}
- float_array1000 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array1000 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array1000 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array1000 =array_length.times.to_a.map {0}
-
- array_length = 100000
- fixnum_array100000 = array_length.times.to_a.map {rand(10000)}
- float_array100000 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array100000 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array100000 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array100000 =array_length.times.to_a.map {0}
-
-benchmark:
- fixnum_array2.sort_by: fixnum_array2.sort_by {|a| a}
- float_array2.sort_by: float_array2.sort_by {|a| a}
- string_length2.sort_by: string_array2.sort_by {|a| a.length}
- mix_array2.sort_by: mix_array2.sort_by {|a| a}
- all_zero2.sort_by: all_zero_array2.sort_by{|a| a}
-
- fixnum_array10.sort_by: fixnum_array10.sort_by {|a| a}
- float_array10.sort_by: float_array10.sort_by {|a| a}
- string_length10.sort_by: string_array10.sort_by {|a| a.length}
- mix_array10.sort_by: mix_array10.sort_by {|a| a}
- all_zero10.sort_by: all_zero_array10.sort_by{|a| a}
-
- fixnum_array1000.sort_by: fixnum_array1000.sort_by {|a| a}
- float_array1000.sort_by: float_array1000.sort_by {|a| a}
- string_length1000.sort_by: string_array1000.sort_by {|a| a.length}
- mix_array1000.sort_by: mix_array1000.sort_by {|a| a}
- all_zero1000.sort_by: all_zero_array1000.sort_by{|a| a}
-
- fixnum_array100000.sort_by: fixnum_array100000.sort_by {|a| a}
- float_array100000.sort_by: float_array100000.sort_by {|a| a}
- string_length100000.sort_by: string_array100000.sort_by {|a| a.length}
- mix_array100000.sort_by: mix_array100000.sort_by {|a| a}
- all_zero100000.sort_by: all_zero_array100000.sort_by{|a| a}
diff --git a/benchmark/lib/benchmark_driver/runner/mjit.rb b/benchmark/lib/benchmark_driver/runner/mjit.rb
new file mode 100644
index 0000000000..3a58a620de
--- /dev/null
+++ b/benchmark/lib/benchmark_driver/runner/mjit.rb
@@ -0,0 +1,34 @@
+require 'benchmark_driver/struct'
+require 'benchmark_driver/metric'
+require 'erb'
+
+# A runner to measure after-JIT performance easily
+class BenchmarkDriver::Runner::Mjit < BenchmarkDriver::Runner::Ips
+ # JobParser returns this, `BenchmarkDriver::Runner.runner_for` searches "*::Job"
+ Job = Class.new(BenchmarkDriver::DefaultJob)
+
+ # Dynamically fetched and used by `BenchmarkDriver::JobParser.parse`
+ JobParser = BenchmarkDriver::DefaultJobParser.for(klass: Job, metrics: [METRIC]).extend(Module.new{
+ def parse(**)
+ jobs = super
+ jobs.map do |job|
+ job = job.dup
+ job.prelude = "#{job.prelude}\n#{<<~EOS}"
+ if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?
+ __bmdv_ruby_i = 0
+ while __bmdv_ruby_i < 10000 # MJIT call threshold
+ #{job.script}
+ __bmdv_ruby_i += 1
+ end
+ RubyVM::MJIT.pause # compile
+ #{job.script}
+ RubyVM::MJIT.resume; RubyVM::MJIT.pause # recompile
+ #{job.script}
+ RubyVM::MJIT.resume; RubyVM::MJIT.pause # recompile 2
+ end
+ EOS
+ job
+ end
+ end
+ })
+end
diff --git a/benchmark/loop_generator.rb b/benchmark/loop_generator.rb
index 6a3194b670..d3375c744c 100644
--- a/benchmark/loop_generator.rb
+++ b/benchmark/loop_generator.rb
@@ -1,4 +1,4 @@
-max = 6000000
+max = 600000
if defined? Fiber
gen = (1..max).each
diff --git a/benchmark/mjit_exivar.yml b/benchmark/mjit_exivar.yml
new file mode 100644
index 0000000000..2584fa6410
--- /dev/null
+++ b/benchmark/mjit_exivar.yml
@@ -0,0 +1,18 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ class Bench < Hash
+ def initialize
+ @exivar = nil
+ end
+
+ def exivar
+ @exivar
+ end
+ end
+
+ bench = Bench.new
+
+benchmark:
+ mjit_exivar: bench.exivar
+
+loop_count: 200000000
diff --git a/benchmark/mjit_integer.yml b/benchmark/mjit_integer.yml
new file mode 100644
index 0000000000..a6b5c9ee16
--- /dev/null
+++ b/benchmark/mjit_integer.yml
@@ -0,0 +1,32 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_abs(int) int.abs end
+ def mjit_bit_length(int) int.bit_length end
+ def mjit_comp(int) ~int end
+ def mjit_even?(int) int.even? end
+ def mjit_integer?(int) int.integer? end
+ def mjit_magnitude(int) int.magnitude end
+ def mjit_odd?(int) int.odd? end
+ def mjit_ord(int) int.ord end
+ def mjit_size(int) int.size end
+ def mjit_to_i(int) int.to_i end
+ def mjit_to_int(int) int.to_int end
+ def mjit_uminus(int) -int end
+ def mjit_zero?(int) int.zero? end
+
+benchmark:
+ - mjit_abs(-1)
+ - mjit_bit_length(100)
+ - mjit_comp(1)
+ - mjit_even?(2)
+ - mjit_integer?(0)
+ - mjit_magnitude(-1)
+ - mjit_odd?(1)
+ - mjit_ord(1)
+ - mjit_size(1)
+ - mjit_to_i(1)
+ - mjit_to_int(1)
+ - mjit_uminus(1)
+ - mjit_zero?(0)
+
+loop_count: 40000000
diff --git a/benchmark/mjit_kernel.yml b/benchmark/mjit_kernel.yml
new file mode 100644
index 0000000000..7720e65c2c
--- /dev/null
+++ b/benchmark/mjit_kernel.yml
@@ -0,0 +1,20 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_class(obj)
+ obj.class
+ end
+
+ def mjit_frozen?(obj)
+ obj.frozen?
+ end
+
+ str = ""
+ fstr = "".freeze
+
+benchmark:
+ - mjit_class(self)
+ - mjit_class(1)
+ - mjit_frozen?(str)
+ - mjit_frozen?(fstr)
+
+loop_count: 40000000
diff --git a/benchmark/mjit_leave.yml b/benchmark/mjit_leave.yml
new file mode 100644
index 0000000000..9ac68b164b
--- /dev/null
+++ b/benchmark/mjit_leave.yml
@@ -0,0 +1,8 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def leave
+ nil
+ end
+benchmark:
+ mjit_leave: leave
+loop_count: 200000000
diff --git a/benchmark/mjit_opt_cc_insns.yml b/benchmark/mjit_opt_cc_insns.yml
new file mode 100644
index 0000000000..fed6d34bd5
--- /dev/null
+++ b/benchmark/mjit_opt_cc_insns.yml
@@ -0,0 +1,27 @@
+# opt_* insns using vm_method_cfunc_is with send-compatible operands:
+# * opt_nil_p
+# * opt_not
+# * opt_eq
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_nil?(obj)
+ obj.nil?
+ end
+
+ def mjit_not(obj)
+ !obj
+ end
+
+ def mjit_eq(a, b)
+ a == b
+ end
+
+benchmark:
+ - script: mjit_nil?(1)
+ loop_count: 40000000
+ - script: mjit_not(1)
+ loop_count: 40000000
+ - script: mjit_eq(1, nil)
+ loop_count: 8000000
+ - script: mjit_eq(nil, 1)
+ loop_count: 8000000
diff --git a/benchmark/mjit_struct_aref.yml b/benchmark/mjit_struct_aref.yml
new file mode 100644
index 0000000000..bfba1323f2
--- /dev/null
+++ b/benchmark/mjit_struct_aref.yml
@@ -0,0 +1,10 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_struct_aref(struct)
+ struct.aa
+ end
+ struct = Struct.new(:a0, :a1, :a2, :a3, :a4, :a5, :a6, :a7, :a8, :a9, :aa).new
+
+benchmark: mjit_struct_aref(struct)
+
+loop_count: 40000000
diff --git a/benchmark/range_bsearch_bignum.yml b/benchmark/range_bsearch_bignum.yml
deleted file mode 100644
index 5730c93fcf..0000000000
--- a/benchmark/range_bsearch_bignum.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-prelude: |
- first = 2**100
- last = 2**1000
- mid = (first + last) / 2
- r = first..last
-
-benchmark:
- first: r.bsearch { |x| x >= first }
- mid: r.bsearch { |x| x >= mid }
- last: r.bsearch { |x| x >= last }
diff --git a/benchmark/range_bsearch_endpointless.yml b/benchmark/range_bsearch_endpointless.yml
deleted file mode 100644
index 8d7bedb662..0000000000
--- a/benchmark/range_bsearch_endpointless.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-prelude: |
- re = (1..)
- rb = (..0)
-
-benchmark:
- 'endless 10**0': re.bsearch { |x| x >= 1 }
- 'endless 10**1': re.bsearch { |x| x >= 10 }
- 'endless 10**2': re.bsearch { |x| x >= 100 }
- 'endless 10**3': re.bsearch { |x| x >= 1000 }
- 'endless 10**4': re.bsearch { |x| x >= 10000 }
- 'endless 10**5': re.bsearch { |x| x >= 100000 }
- 'endless 10**10': re.bsearch { |x| x >= 10000000000 }
- 'endless 10**100': re.bsearch { |x| x >= 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }
- 'beginless -10**0': rb.bsearch { |x| x >= -1 }
- 'beginless -10**1': rb.bsearch { |x| x >= -10 }
- 'beginless -10**2': rb.bsearch { |x| x >= -100 }
- 'beginless -10**3': rb.bsearch { |x| x >= -1000 }
- 'beginless -10**4': rb.bsearch { |x| x >= -10000 }
- 'beginless -10**5': rb.bsearch { |x| x >= -100000 }
- 'beginless -10**10': rb.bsearch { |x| x >= -10000000000 }
- 'beginless -10**100': rb.bsearch { |x| x >= -10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }
diff --git a/benchmark/range_bsearch_fixnum.yml b/benchmark/range_bsearch_fixnum.yml
deleted file mode 100644
index 59416531b9..0000000000
--- a/benchmark/range_bsearch_fixnum.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-prelude: |
- first = 1
- last = 10000
- mid = (first + last) / 2
- r = first..last
-
-benchmark:
- first: r.bsearch { |x| x >= first }
- mid: r.bsearch { |x| x >= mid }
- last: r.bsearch { |x| x >= last }
diff --git a/benchmark/range_count.yml b/benchmark/range_count.yml
deleted file mode 100644
index 58f53a0236..0000000000
--- a/benchmark/range_count.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-prelude: |
- r_1 = 1..1
- r_1k = 1..1000
- r_1m = 1..1000000
- r_str = 'a'..'z'
-
-benchmark:
- 'int 1': r_1.count
- 'int 1K': r_1k.count
- 'int 1M': r_1m.count
- string: r_str.count
diff --git a/benchmark/range_overlap.yml b/benchmark/range_overlap.yml
deleted file mode 100644
index 700a00053c..0000000000
--- a/benchmark/range_overlap.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-prelude: |
- class Range
- unless method_defined?(:overlap?)
- def overlap?(other)
- other.begin == self.begin || cover?(other.begin) || other.cover?(self.begin)
- end
- end
- end
-
-benchmark:
- - (2..3).overlap?(1..1)
- - (2..3).overlap?(2..4)
- - (2..3).overlap?(4..5)
- - (2..3).overlap?(2..1)
- - (2..3).overlap?(0..1)
- - (2..3).overlap?(...1)
- - (2...3).overlap?(..2)
- - (2...3).overlap?(3...)
- - (2..3).overlap?('a'..'d')
diff --git a/benchmark/range_reverse_each.yml b/benchmark/range_reverse_each.yml
deleted file mode 100644
index a32efeccc6..0000000000
--- a/benchmark/range_reverse_each.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-prelude: |
- rf_1 = 0..1
- rf_1k = 0..1000
- rf_1m = 0..1000000
- big = 2**1000
- rb_1 = big..big+1
- rb_1k = big..big+1000
- rb_1m = big..big+1000000
-
-benchmark:
- "Fixnum 1": rf_1.reverse_each { _1 }
- "Fixnum 1K": rf_1k.reverse_each { _1 }
- "Fixnum 1M": rf_1m.reverse_each { _1 }
- "Bignum 1": rb_1.reverse_each { _1 }
- "Bignum 1K": rb_1k.reverse_each { _1 }
- "Bignum 1M": rb_1m.reverse_each { _1 }
diff --git a/benchmark/regexp_dup.yml b/benchmark/regexp_dup.yml
deleted file mode 100644
index 52f89991cd..0000000000
--- a/benchmark/regexp_dup.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-prelude: |
- str = "a" * 1000
- re = Regexp.new(str)
-
-benchmark:
- dup: re.dup
diff --git a/benchmark/regexp_new.yml b/benchmark/regexp_new.yml
deleted file mode 100644
index bc9ab3ca21..0000000000
--- a/benchmark/regexp_new.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-prelude: |
- str = "a" * 1000
- re = Regexp.new(str)
-
-benchmark:
- string: Regexp.new(str)
- regexp: Regexp.new(re)
diff --git a/benchmark/so_count_words.yml b/benchmark/so_count_words.yml
index f7322a8541..99683505f9 100644
--- a/benchmark/so_count_words.yml
+++ b/benchmark/so_count_words.yml
@@ -15,13 +15,13 @@ prelude: |
Newsgroups: rec.games.roguelike.nethack
X-Mailer: Mozilla 1.1N (Macintosh; I; 68K)
- Hello there, Izchak Miller was my father. When I was younger I spent
- many a night, hunched over the keyboard with a cup of tea, playing
- nethack with him and my brother. my dad was a philosopher with a strong
- weakness for fantasy/sci fi. I remember when he started to get involved
- with the Nethack team- my brother's Dungeons and Dragons monster book
- found a regular place beside my dad's desk. it's nice to see him living
- on in the game he loved so much :-).
+ Hello there, Izchak Miller was my father. When I was younger I spent
+ many a night, hunched over the keyboard with a cup of tea, playing
+ nethack with him and my brother. my dad was a philosopher with a strong
+ weakness for fantasy/sci fi. I remember when he started to get involved
+ with the Nethack team- my brother's Dungeons and Dragons monster book
+ found a regular place beside my dad's desk. it's nice to see him living
+ on in the game he loved so much :-).
Tamar Miller
The following is a really long word of 5000 characters:
@@ -38,9 +38,8 @@ prelude: |
13.times{
data << data
}
- File.write(wcinput, data)
+ open(wcinput, 'w'){|f| f.write data}
end
- at_exit {File.unlink(wcinput) rescue nil}
end
prepare_wc_input(wc_input_base)
@@ -50,16 +49,16 @@ benchmark:
# $Id: wc-ruby.code,v 1.4 2004/11/13 07:43:32 bfulgham Exp $
# http://www.bagley.org/~doug/shootout/
# with help from Paul Brannan
+ input = open(File.join(File.dirname($0), 'wc.input'), 'rb')
nl = nw = nc = 0
- File.open(File.join(File.dirname($0), 'wc.input'), 'rb') do |input|
- while tmp = input.read(4096)
- data = tmp << (input.gets || "")
- nc += data.length
- nl += data.count("\n")
- ((data.strip! || data).tr!("\n", " ") || data).squeeze!
- nw += data.count(" ") + 1
- end
+ while true
+ tmp = input.read(4096) or break
+ data = tmp << (input.gets || "")
+ nc += data.length
+ nl += data.count("\n")
+ ((data.strip! || data).tr!("\n", " ") || data).squeeze!
+ nw += data.count(" ") + 1
end
# STDERR.puts "#{nl} #{nw} #{nc}"
diff --git a/benchmark/so_meteor_contest.rb b/benchmark/so_meteor_contest.rb
index d8c8e3ab9c..8c136baa6c 100644
--- a/benchmark/so_meteor_contest.rb
+++ b/benchmark/so_meteor_contest.rb
@@ -447,7 +447,7 @@ end
# as an inverse. The inverse will ALWAYS be 3 one of the piece configurations that is exactly 3 rotations away
# (an odd number). Checking even vs odd then produces a higher probability of finding more pieces earlier
# in the cycle. We still need to keep checking all the permutations, but our probability of finding one will
-# diminish over time. Since we are TOLD how many to search for this lets us exit before checking all pieces
+# diminsh over time. Since we are TOLD how many to search for this lets us exit before checking all pieces
# this bennifit is very great when seeking small numbers of solutions and is 0 when looking for more than the
# maximum number
def find_top( rotation_skip)
diff --git a/benchmark/string_concat.yml b/benchmark/string_concat.yml
index da14692f5e..e65c00cca9 100644
--- a/benchmark/string_concat.yml
+++ b/benchmark/string_concat.yml
@@ -1,8 +1,6 @@
prelude: |
CHUNK = "a" * 64
UCHUNK = "é" * 32
- SHORT = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] / 2)
- LONG = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 2)
GC.disable # GC causes a lot of variance
benchmark:
binary_concat_7bit: |
@@ -45,7 +43,3 @@ benchmark:
"#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}" \
"#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}" \
"#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}"
- interpolation_same_size_pool: |
- buffer = "#{SHORT}#{SHORT}"
- interpolation_switching_size_pools: |
- buffer = "#{SHORT}#{LONG}"
diff --git a/benchmark/string_rpartition.yml b/benchmark/string_rpartition.yml
deleted file mode 100644
index 37e9d1b071..0000000000
--- a/benchmark/string_rpartition.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-prelude: |
- str1 = [*"a".."z",*"0".."9"].join("")
- str10 = str1 * 10 + ":"
- str100 = str1 * 100 + ":"
- str1000 = str1 * 1000 + ":"
- nonascii1 = [*"\u{e0}".."\u{ff}"].join("")
- nonascii10 = nonascii1 * 10 + ":"
- nonascii100 = nonascii1 * 100 + ":"
- nonascii1000 = nonascii1 * 1000 + ":"
-benchmark:
- rpartition-1: str1.rpartition(":")
- rpartition-10: str10.rpartition(":")
- rpartition-100: str100.rpartition(":")
- rpartition-1000: str1000.rpartition(":")
- rpartition-nonascii1: nonascii1.rpartition(":")
- rpartition-nonascii10: nonascii10.rpartition(":")
- rpartition-nonascii100: nonascii100.rpartition(":")
- rpartition-nonascii1000: nonascii1000.rpartition(":")
diff --git a/benchmark/vm_call_bmethod.yml b/benchmark/vm_call_bmethod.yml
deleted file mode 100644
index 40136e5aa4..0000000000
--- a/benchmark/vm_call_bmethod.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-prelude: |
- define_method(:a0){}
- define_method(:a1){|a| a}
- define_method(:s){|*a| a}
- define_method(:b){|kw: 1| kw}
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t100 = 100.times.to_a
- kw = {kw: 2}
-benchmark:
- bmethod_simple_0: |
- a0
- bmethod_simple_1: |
- a1(1)
- bmethod_simple_0_splat: |
- a0(*t0)
- bmethod_simple_1_splat: |
- a1(*t1)
- bmethod_no_splat: |
- s
- bmethod_0_splat: |
- s(*t0)
- bmethod_1_splat: |
- s(*t1)
- bmethod_10_splat: |
- s(*t10)
- bmethod_100_splat: |
- s(*t100)
- bmethod_kw: |
- b(kw: 1)
- bmethod_no_kw: |
- b
- bmethod_kw_splat: |
- b(**kw)
-loop_count: 6000000
diff --git a/benchmark/vm_call_method_missing.yml b/benchmark/vm_call_method_missing.yml
deleted file mode 100644
index f890796f11..0000000000
--- a/benchmark/vm_call_method_missing.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-prelude: |
- class A0
- def method_missing(m); m end
- end
- class A1
- def method_missing(m, a) a; end
- end
- class S
- def method_missing(m, *a) a; end
- end
- class B
- def method_missing(m, kw: 1) kw end
- end
- class SB
- def method_missing(m, *a, kw: 1) kw end
- end
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t200 = 200.times.to_a
- kw = {kw: 2}
-
- a0 = A0.new
- a1 = A1.new
- s = S.new
- b = B.new
- sb = SB.new
-benchmark:
- method_missing_simple_0: |
- a0.()
- method_missing_simple_1: |
- a1.x(1)
- method_missing_simple_0_splat: |
- a0.(*t0)
- method_missing_simple_1_splat: |
- a1.(*t1)
- method_missing_no_splat: |
- s.()
- method_missing_0_splat: |
- s.(*t0)
- method_missing_1_splat: |
- s.(*t1)
- method_missing_10_splat: |
- s.(*t10)
- method_missing_200_splat: |
- s.(*t200)
- method_missing_kw: |
- b.(kw: 1)
- method_missing_no_kw: |
- b.()
- method_missing_kw_splat: |
- b.(**kw)
- method_missing_0_splat_kw: |
- sb.(*t0, **kw)
- method_missing_1_splat_kw: |
- sb.(*t1, **kw)
- method_missing_10_splat_kw: |
- sb.(*t10, **kw)
- method_missing_200_splat_kw: |
- sb.(*t200, **kw)
-loop_count: 1000000
diff --git a/benchmark/vm_call_send_iseq.yml b/benchmark/vm_call_send_iseq.yml
deleted file mode 100644
index 60ff23c475..0000000000
--- a/benchmark/vm_call_send_iseq.yml
+++ /dev/null
@@ -1,77 +0,0 @@
-prelude: |
- def a0; end
- def a1(a) a; end
- def s(*a) a; end
- def b(kw: 1) kw end
- def sb(*a, kw: 1) kw end
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t200 = 200.times.to_a
-
- a0_t0 = [:a0, *t0]
- a1_t1 = [:a1, *t1]
- s_t0 = [:s, *t0]
- s_t1 = [:s, *t1]
- s_t10 = [:s, *t10]
- s_t200 = [:s, *t200]
- sb_t0 = [:sb, *t0]
- sb_t1 = [:sb, *t1]
- sb_t10 = [:sb, *t10]
- sb_t200 = [:sb, *t200]
- kw = {kw: 2}
-benchmark:
- send_simple_0: |
- send(:a0)
- send_simple_1: |
- send(:a1, 1)
- send_simple_0_splat: |
- send(:a0, *t0)
- send_simple_1_splat: |
- send(:a1, *t1)
- send_simple_0_splat_comb: |
- send(*a0_t0)
- send_simple_1_splat_comb: |
- send(*a1_t1)
- send_no_splat: |
- send(:s)
- send_0_splat: |
- send(:s, *t0)
- send_1_splat: |
- send(:s, *t1)
- send_10_splat: |
- send(:s, *t10)
- send_200_splat: |
- send(:s, *t200)
- send_0_splat_comb: |
- send(*s_t0)
- send_1_splat_comb: |
- send(*s_t1)
- send_10_splat_comb: |
- send(*s_t10)
- send_200_splat_comb: |
- send(*s_t200)
- send_kw: |
- send(:b, kw: 1)
- send_no_kw: |
- send(:b)
- send_kw_splat: |
- send(:b, **kw)
- send_0_splat_kw: |
- send(:sb, *t0, **kw)
- send_1_splat_kw: |
- send(:sb, *t1, **kw)
- send_10_splat_kw: |
- send(:sb, *t10, **kw)
- send_200_splat_kw: |
- send(:sb, *t200, **kw)
- send_0_splat_comb_kw: |
- send(*sb_t0, **kw)
- send_1_splat_comb_kw: |
- send(*sb_t1, **kw)
- send_10_splat_comb_kw: |
- send(*sb_t10, **kw)
- send_200_splat_comb_kw: |
- send(*sb_t200, **kw)
-loop_count: 3000000
diff --git a/benchmark/vm_call_symproc.yml b/benchmark/vm_call_symproc.yml
deleted file mode 100644
index 16e0ac579e..0000000000
--- a/benchmark/vm_call_symproc.yml
+++ /dev/null
@@ -1,83 +0,0 @@
-prelude: |
- def self.a0; end
- def self.a1(a) a; end
- def self.s(*a) a; end
- def self.b(kw: 1) kw end
- def self.sb(*a, kw: 1) kw end
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t200 = 200.times.to_a
-
- a0_t0 = [self, *t0]
- a1_t1 = [self, *t1]
- s_t0 = [self, *t0]
- s_t1 = [self, *t1]
- s_t10 = [self, *t10]
- s_t200 = [self, *t200]
- sb_t0 = [self, *t0]
- sb_t1 = [self, *t1]
- sb_t10 = [self, *t10]
- sb_t200 = [self, *t200]
- kw = {kw: 2}
-
- a0 = :a0.to_proc
- a1 = :a1.to_proc
- s = :s.to_proc
- b = :b.to_proc
- sb = :sb.to_proc
-benchmark:
- symproc_simple_0: |
- a0.(self)
- symproc_simple_1: |
- a1.(self, 1)
- symproc_simple_0_splat: |
- a0.(self, *t0)
- symproc_simple_1_splat: |
- a1.(self, *t1)
- symproc_simple_0_splat_comb: |
- a0.(*a0_t0)
- symproc_simple_1_splat_comb: |
- a1.(*a1_t1)
- symproc_no_splat: |
- s.(self)
- symproc_0_splat: |
- s.(self, *t0)
- symproc_1_splat: |
- s.(self, *t1)
- symproc_10_splat: |
- s.(self, *t10)
- symproc_200_splat: |
- s.(self, *t200)
- symproc_0_splat_comb: |
- s.(*s_t0)
- symproc_1_splat_comb: |
- s.(*s_t1)
- symproc_10_splat_comb: |
- s.(*s_t10)
- symproc_200_splat_comb: |
- s.(*s_t200)
- symproc_kw: |
- b.(self, kw: 1)
- symproc_no_kw: |
- b.(self)
- symproc_kw_splat: |
- b.(self, **kw)
- symproc_0_splat_kw: |
- sb.(self, *t0, **kw)
- symproc_1_splat_kw: |
- sb.(self, *t1, **kw)
- symproc_10_splat_kw: |
- sb.(self, *t10, **kw)
- symproc_200_splat_kw: |
- sb.(self, *t200, **kw)
- symproc_0_splat_comb_kw: |
- sb.(*sb_t0, **kw)
- symproc_1_splat_comb_kw: |
- sb.(*sb_t1, **kw)
- symproc_10_splat_comb_kw: |
- sb.(*sb_t10, **kw)
- symproc_200_splat_comb_kw: |
- sb.(*sb_t200, **kw)
-loop_count: 1000000
diff --git a/benchmark/vm_ivar_ic_miss.yml b/benchmark/vm_ivar_ic_miss.yml
deleted file mode 100644
index 944fb1a9e6..0000000000
--- a/benchmark/vm_ivar_ic_miss.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-prelude: |
- class Foo
- def initialize diverge
- if diverge
- @a = 1
- end
-
- @a0 = @a1 = @a2 = @a3 = @a4 = @a5 = @a6 = @a7 = @a8 = @a9 = @a10 = @a11 = @a12 = @a13 = @a14 = @a15 = @a16 = @a17 = @a18 = @a19 = @a20 = @a21 = @a22 = @a23 = @a24 = @a25 = @a26 = @a27 = @a28 = @a29 = @a30 = @a31 = @a32 = @a33 = @a34 = @a35 = @a36 = @a37 = @a38 = @a39 = @a40 = @a41 = @a42 = @a43 = @a44 = @a45 = @a46 = @a47 = @a48 = @a49 = @a50 = @a51 = @a52 = @a53 = @a54 = @a55 = @a56 = @a57 = @a58 = @a59 = @a60 = @a61 = @a62 = @a63 = @a64 = @a65 = @a66 = @a67 = @a68 = @a69 = @a70 = @a71 = @a72 = @a73 = @a74 = @b = 1
- end
-
- def b; @b; end
- end
-
- a = Foo.new false
- b = Foo.new true
-benchmark:
- vm_ivar_ic_miss: |
- a.b
- b.b
-loop_count: 30000000
diff --git a/benchmark/vm_ivar_memoize.yml b/benchmark/vm_ivar_memoize.yml
deleted file mode 100644
index 90f6b07f05..0000000000
--- a/benchmark/vm_ivar_memoize.yml
+++ /dev/null
@@ -1,85 +0,0 @@
-prelude: |
- IVARS = 60
- class Record
- def initialize(offset = false)
- @offset = 1 if offset
- @first = 0
- IVARS.times do |i|
- instance_variable_set("@ivar_#{i}", i)
- end
- end
-
- def first
- @first
- end
-
- def lazy_set
- @lazy_set ||= 123
- end
-
- def undef
- @undef
- end
- end
-
- Record.new # Need one alloc to right size
-
- BASE = Record.new
- LAZY = Record.new
- LAZY.lazy_set
-
- class Miss < Record
- @first = 0
- IVARS.times do |i|
- instance_variable_set("@i_#{i}", i)
- end
- end
-
- Miss.new # Need one alloc to right size
- MISS = Miss.new
-
- DIVERGENT = Record.new(true)
-
-benchmark:
- vm_ivar_stable_shape: |
- BASE.first
- BASE.first
- BASE.first
- BASE.first
- BASE.first
- BASE.first
- vm_ivar_memoize_unstable_shape: |
- BASE.first
- LAZY.first
- BASE.first
- LAZY.first
- BASE.first
- LAZY.first
- vm_ivar_memoize_unstable_shape_miss: |
- BASE.first
- MISS.first
- BASE.first
- MISS.first
- BASE.first
- MISS.first
- vm_ivar_unstable_undef: |
- BASE.undef
- LAZY.undef
- BASE.undef
- LAZY.undef
- BASE.undef
- LAZY.undef
- vm_ivar_divergent_shape: |
- BASE.first
- DIVERGENT.first
- BASE.first
- DIVERGENT.first
- BASE.first
- DIVERGENT.first
- vm_ivar_divergent_shape_imbalanced: |
- BASE.first
- DIVERGENT.first
- DIVERGENT.first
- DIVERGENT.first
- DIVERGENT.first
- DIVERGENT.first
diff --git a/benchmark/vm_send_cfunc.yml b/benchmark/vm_send_cfunc.yml
index 6f12b65176..b114ac317d 100644
--- a/benchmark/vm_send_cfunc.yml
+++ b/benchmark/vm_send_cfunc.yml
@@ -1,14 +1,3 @@
-prelude: |
- ary = []
- kw = {a: 1}
- empty_kw = {}
- kw_ary = [Hash.ruby2_keywords_hash(a: 1)]
- empty_kw_ary = [Hash.ruby2_keywords_hash({})]
benchmark:
- vm_send_cfunc: itself
- vm_send_cfunc_splat: itself(*ary)
- vm_send_cfunc_splat_kw_hash: equal?(*kw_ary)
- vm_send_cfunc_splat_empty_kw_hash: itself(*empty_kw_ary)
- vm_send_cfunc_splat_kw: equal?(*ary, **kw)
- vm_send_cfunc_splat_empty_kw: itself(*ary, **empty_kw)
-loop_count: 20000000
+ vm_send_cfunc: self.class
+loop_count: 100000000
diff --git a/bignum.c b/bignum.c
index e9bf37d206..cb2c3b6f07 100644
--- a/bignum.c
+++ b/bignum.c
@@ -48,14 +48,6 @@
#include "ruby/util.h"
#include "ruby_assert.h"
-static const bool debug_integer_pack = (
-#ifdef DEBUG_INTEGER_PACK
- DEBUG_INTEGER_PACK+0
-#else
- RUBY_DEBUG
-#endif
- ) != 0;
-
const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#ifndef SIZEOF_BDIGIT_DBL
@@ -1057,13 +1049,15 @@ integer_unpack_num_bdigits(size_t numwords, size_t wordsize, size_t nails, int *
if (numwords <= (SIZE_MAX - (BITSPERDIG-1)) / CHAR_BIT / wordsize) {
num_bdigits = integer_unpack_num_bdigits_small(numwords, wordsize, nails, nlp_bits_ret);
- if (debug_integer_pack) {
+#ifdef DEBUG_INTEGER_PACK
+ {
int nlp_bits1;
size_t num_bdigits1 = integer_unpack_num_bdigits_generic(numwords, wordsize, nails, &nlp_bits1);
assert(num_bdigits == num_bdigits1);
assert(*nlp_bits_ret == nlp_bits1);
(void)num_bdigits1;
}
+#endif
}
else {
num_bdigits = integer_unpack_num_bdigits_generic(numwords, wordsize, nails, nlp_bits_ret);
@@ -3029,8 +3023,7 @@ rb_big_resize(VALUE big, size_t len)
static VALUE
bignew_1(VALUE klass, size_t len, int sign)
{
- NEWOBJ_OF(big, struct RBignum, klass,
- T_BIGNUM | (RGENGC_WB_PROTECTED_BIGNUM ? FL_WB_PROTECTED : 0), sizeof(struct RBignum), 0);
+ NEWOBJ_OF(big, struct RBignum, klass, T_BIGNUM | (RGENGC_WB_PROTECTED_BIGNUM ? FL_WB_PROTECTED : 0));
VALUE bigv = (VALUE)big;
BIGNUM_SET_SIGN(bigv, sign);
if (len <= BIGNUM_EMBED_LEN_MAX) {
@@ -3429,13 +3422,15 @@ rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret)
if (numbytes <= SIZE_MAX / CHAR_BIT) {
numwords = absint_numwords_small(numbytes, nlz_bits_in_msbyte, word_numbits, &nlz_bits);
- if (debug_integer_pack) {
+#ifdef DEBUG_INTEGER_PACK
+ {
size_t numwords0, nlz_bits0;
numwords0 = absint_numwords_generic(numbytes, nlz_bits_in_msbyte, word_numbits, &nlz_bits0);
assert(numwords0 == numwords);
assert(nlz_bits0 == nlz_bits);
(void)numwords0;
}
+#endif
}
else {
numwords = absint_numwords_generic(numbytes, nlz_bits_in_msbyte, word_numbits, &nlz_bits);
@@ -4546,7 +4541,7 @@ rb_uint128t2big(uint128_t n)
return big;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_int128t2big(int128_t n)
{
int neg = 0;
diff --git a/bin/gem b/bin/gem
index 3ac1d9e623..1c16ea7ddd 100755
--- a/bin/gem
+++ b/bin/gem
@@ -1,6 +1,4 @@
#!/usr/bin/env ruby
-# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
diff --git a/bootstraptest/runner.rb b/bootstraptest/runner.rb
index c8ba824407..f9b3e919b8 100755
--- a/bootstraptest/runner.rb
+++ b/bootstraptest/runner.rb
@@ -118,7 +118,7 @@ BT = Class.new(bt) do
r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
end
- rescue
+ rescue => e
r.close if r
else
r.close_on_exec = true
@@ -669,7 +669,7 @@ end
def assert_finish(timeout_seconds, testsrc, message = '')
add_assertion testsrc, -> as do
- if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # for --jit-wait
+ if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait
timeout_seconds *= 3
end
diff --git a/bootstraptest/test_gc.rb b/bootstraptest/test_gc.rb
index 9f17e14814..eb68c9845e 100644
--- a/bootstraptest/test_gc.rb
+++ b/bootstraptest/test_gc.rb
@@ -14,7 +14,7 @@ ms = "a".."k"
o.send(meth)
end
end
-}, '[ruby-dev:39453]' unless ENV.fetch('RUN_OPTS', '').include?('rjit') # speed up RJIT CI
+}, '[ruby-dev:39453]'
assert_normal_exit %q{
a = []
diff --git a/bootstraptest/test_insns.rb b/bootstraptest/test_insns.rb
index d2e799f855..91fba9b011 100644
--- a/bootstraptest/test_insns.rb
+++ b/bootstraptest/test_insns.rb
@@ -214,11 +214,9 @@ tests = [
'true'.freeze
},
- [ 'opt_newarray_send', %q{ ![ ].hash.nil? }, ],
-
- [ 'opt_newarray_send', %q{ [ ].max.nil? }, ],
- [ 'opt_newarray_send', %q{ [1, x = 2, 3].max == 3 }, ],
- [ 'opt_newarray_send', <<-'},', ], # {
+ [ 'opt_newarray_max', %q{ [ ].max.nil? }, ],
+ [ 'opt_newarray_max', %q{ [1, x = 2, 3].max == 3 }, ],
+ [ 'opt_newarray_max', <<-'},', ], # {
class Array
def max
true
@@ -226,9 +224,9 @@ tests = [
end
[1, x = 2, 3].max
},
- [ 'opt_newarray_send', %q{ [ ].min.nil? }, ],
- [ 'opt_newarray_send', %q{ [3, x = 2, 1].min == 1 }, ],
- [ 'opt_newarray_send', <<-'},', ], # {
+ [ 'opt_newarray_min', %q{ [ ].min.nil? }, ],
+ [ 'opt_newarray_min', %q{ [3, x = 2, 1].min == 1 }, ],
+ [ 'opt_newarray_min', <<-'},', ], # {
class Array
def min
true
diff --git a/bootstraptest/test_load.rb b/bootstraptest/test_load.rb
index 3253582a32..e63c93a8f4 100644
--- a/bootstraptest/test_load.rb
+++ b/bootstraptest/test_load.rb
@@ -12,7 +12,7 @@ assert_equal 'ok', %q{
}
}.map {|t| t.value }
vs[0] == M && vs[1] == M ? :ok : :ng
-}, '[ruby-dev:32048]' unless ENV.fetch('RUN_OPTS', '').include?('rjit') # Thread seems to be switching during JIT. To be fixed later.
+}, '[ruby-dev:32048]'
assert_equal 'ok', %q{
%w[a a/foo b].each {|d| Dir.mkdir(d)}
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 7a71f6e071..67e66b03ee 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -283,7 +283,9 @@ assert_equal 30.times.map { 'ok' }.to_s, %q{
30.times.map{|i|
test i
}
-} unless (ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'arm64') # https://bugs.ruby-lang.org/issues/17878
+} unless ENV['RUN_OPTS'] =~ /--mjit-call-threshold=5/ || # This always fails with --mjit-wait --mjit-call-threshold=5
+ (ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'arm64') || # https://bugs.ruby-lang.org/issues/17878
+ true # too flaky everywhere http://ci.rvm.jp/results/trunk@ruby-sp1/4321096
# Exception for empty select
assert_match /specify at least one ractor/, %q{
@@ -514,9 +516,9 @@ assert_equal '[true, true, true]', %q{
end
}
received = []
- taken = []
+ take = []
yielded = []
- until received.size == RN && taken.size == RN && yielded.size == RN
+ until rs.empty?
r, v = Ractor.select(CR, *rs, yield_value: 'yield')
case r
when :receive
@@ -524,17 +526,11 @@ assert_equal '[true, true, true]', %q{
when :yield
yielded << v
else
- taken << v
+ take << v
rs.delete r
end
end
- r = [received == ['sendyield'] * RN,
- yielded == [nil] * RN,
- taken == ['take'] * RN,
- ]
-
- STDERR.puts [received, yielded, taken].inspect
- r
+ [received.all?('sendyield'), yielded.all?(nil), take.all?('take')]
}
# multiple Ractors can send to one Ractor
@@ -1476,6 +1472,21 @@ assert_equal "#{N}#{N}", %Q{
}.map{|r| r.take}.join
}
+# enc_table
+assert_equal "100", %Q{
+ Ractor.new do
+ loop do
+ Encoding.find("test-enc-#{rand(5_000)}").inspect
+ rescue ArgumentError => e
+ end
+ end
+
+ src = Encoding.find("UTF-8")
+ 100.times{|i|
+ src.replicate("test-enc-\#{i}")
+ }
+}
+
# Generic ivtbl
n = N/2
assert_equal "#{n}#{n}", %Q{
@@ -1494,9 +1505,8 @@ assert_equal "#{n}#{n}", %Q{
# NameError
assert_equal "ok", %q{
- obj = "".freeze # NameError refers the receiver indirectly
begin
- obj.bar
+ bar
rescue => err
end
begin
@@ -1532,7 +1542,7 @@ assert_equal "ok", %q{
1_000.times { idle_worker, tmp_reporter = Ractor.select(*workers) }
"ok"
-} unless ENV['RUN_OPTS'] =~ /rjit/ # flaky
+}
assert_equal "ok", %q{
def foo(*); ->{ super }; end
@@ -1570,7 +1580,6 @@ assert_equal "ok", %q{
end
}
-# check method cache invalidation
assert_equal "ok", %q{
module M
def foo
@@ -1610,134 +1619,10 @@ assert_equal "ok", %q{
"ok"
}
-# check method cache invalidation
-assert_equal 'true', %q{
- class C1; def self.foo = 1; end
- class C2; def self.foo = 2; end
- class C3; def self.foo = 3; end
- class C4; def self.foo = 5; end
- class C5; def self.foo = 7; end
- class C6; def self.foo = 11; end
- class C7; def self.foo = 13; end
- class C8; def self.foo = 17; end
-
- LN = 10_000
- RN = 10
- CS = [C1, C2, C3, C4, C5, C6, C7, C8]
- rs = RN.times.map{|i|
- Ractor.new(CS.shuffle){|cs|
- LN.times.sum{
- cs.inject(1){|r, c| r * c.foo} # c.foo invalidates method cache entry
- }
- }
- }
-
- n = CS.inject(1){|r, c| r * c.foo} * LN
- rs.map{|r| r.take} == Array.new(RN){n}
-}
-
-# check experimental warning
assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor is experimental/, %q{
Warning[:experimental] = $VERBOSE = true
STDERR.reopen(STDOUT)
eval("Ractor.new{}.take", nil, "test_ractor.rb", 1)
}
-## Ractor::Selector
-
-# Selector#empty? returns true
-assert_equal 'true', %q{
- s = Ractor::Selector.new
- s.empty?
-}
-
-# Selector#empty? returns false if there is target ractors
-assert_equal 'false', %q{
- s = Ractor::Selector.new
- s.add Ractor.new{}
- s.empty?
-}
-
-# Selector#clear removes all ractors from the waiting list
-assert_equal 'true', %q{
- s = Ractor::Selector.new
- s.add Ractor.new{10}
- s.add Ractor.new{20}
- s.clear
- s.empty?
-}
-
-# Selector#wait can wait multiple ractors
-assert_equal '[10, 20, true]', %q{
- s = Ractor::Selector.new
- s.add Ractor.new{10}
- s.add Ractor.new{20}
- r, v = s.wait
- vs = []
- vs << v
- r, v = s.wait
- vs << v
- [*vs.sort, s.empty?]
-}
-
-# Selector#wait can wait multiple ractors with receiving.
-assert_equal '30', %q{
- RN = 30
- rs = RN.times.map{
- Ractor.new{ :v }
- }
- s = Ractor::Selector.new(*rs)
-
- results = []
- until s.empty?
- results << s.wait
-
- # Note that s.wait can raise an exception because other Ractors/Threads
- # can take from the same ractors in the waiting set.
- # In this case there is no other takers so `s.wait` doesn't raise an error.
- end
-
- results.size
-}
-
-# Selector#wait can support dynamic addition
-yjit_enabled = ENV.key?('RUBY_YJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('yjit') || BT.ruby.include?('yjit')
-assert_equal '600', %q{
- RN = 100
- s = Ractor::Selector.new
- rs = RN.times.map{
- Ractor.new{
- Ractor.main << Ractor.new{ Ractor.yield :v3; :v4 }
- Ractor.main << Ractor.new{ Ractor.yield :v5; :v6 }
- Ractor.yield :v1
- :v2
- }
- }
-
- rs.each{|r| s.add(r)}
- h = {v1: 0, v2: 0, v3: 0, v4: 0, v5: 0, v6: 0}
-
- loop do
- case s.wait receive: true
- in :receive, r
- s.add r
- in r, v
- h[v] += 1
- break if h.all?{|k, v| v == RN}
- end
- end
-
- h.sum{|k, v| v}
-} unless yjit_enabled # http://ci.rvm.jp/results/trunk-yjit@ruby-sp2-docker/4466770
-
-# Selector should be GCed (free'ed) without trouble
-assert_equal 'ok', %q{
- RN = 30
- rs = RN.times.map{
- Ractor.new{ :v }
- }
- s = Ractor::Selector.new(*rs)
- :ok
-}
-
end # if !ENV['GITHUB_WORKFLOW']
diff --git a/bootstraptest/test_rjit.rb b/bootstraptest/test_rjit.rb
deleted file mode 100644
index 464af7a6e6..0000000000
--- a/bootstraptest/test_rjit.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# VM_CALL_OPT_SEND + VM_METHOD_TYPE_ATTRSET
-assert_equal '1', %q{
- class Foo
- attr_writer :foo
-
- def bar
- send(:foo=, 1)
- end
- end
-
- Foo.new.bar
-}
-
-# VM_CALL_OPT_SEND + OPTIMIZED_METHOD_TYPE_CALL
-assert_equal 'foo', %q{
- def bar(&foo)
- foo.send(:call)
- end
-
- bar { :foo }
-}
-
-# VM_CALL_OPT_SEND + OPTIMIZED_METHOD_TYPE_STRUCT_AREF
-assert_equal 'bar', %q{
- def bar(foo)
- foo.send(:bar)
- end
-
- bar(Struct.new(:bar).new(:bar))
-}
-
-# kwargs default w/ checkkeyword + locals (which shouldn't overwrite unspecified_bits)
-assert_equal '1', %q{
- def foo(bar: 1.to_s)
- _ = 1
- bar
- end
-
- def entry
- foo
- end
-
- entry
-}
diff --git a/bootstraptest/test_syntax.rb b/bootstraptest/test_syntax.rb
index 59fdae651f..948e2d7809 100644
--- a/bootstraptest/test_syntax.rb
+++ b/bootstraptest/test_syntax.rb
@@ -535,8 +535,8 @@ assert_syntax_error "unterminated string meets end of file", '().."', '[ruby-dev
assert_equal %q{[]}, %q{$&;[]}, '[ruby-dev:31068]'
assert_syntax_error "syntax error, unexpected *, expecting '}'", %q{{*0}}, '[ruby-dev:31072]'
assert_syntax_error "`@0' is not allowed as an instance variable name", %q{@0..0}, '[ruby-dev:31095]'
-assert_syntax_error "`$00' is not allowed as a global variable name", %q{$00..0}, '[ruby-dev:31100]'
-assert_syntax_error "`$00' is not allowed as a global variable name", %q{0..$00=1}
+assert_syntax_error "identifier $00 is not valid to get", %q{$00..0}, '[ruby-dev:31100]'
+assert_syntax_error "identifier $00 is not valid to set", %q{0..$00=1}
assert_equal %q{0}, %q{[*0];0}, '[ruby-dev:31102]'
assert_syntax_error "syntax error, unexpected ')'", %q{v0,(*,v1,) = 0}, '[ruby-dev:31104]'
assert_equal %q{1}, %q{
diff --git a/bootstraptest/test_thread.rb b/bootstraptest/test_thread.rb
index 18b4fcd2e9..5361828403 100644
--- a/bootstraptest/test_thread.rb
+++ b/bootstraptest/test_thread.rb
@@ -242,20 +242,6 @@ assert_equal 'true', %{
end
}
-assert_equal 'true', %{
- Thread.new{}.join
- begin
- Process.waitpid2 fork{
- Thread.new{
- sleep 0.1
- }.join
- }
- true
- rescue NotImplementedError
- true
- end
-}
-
assert_equal 'ok', %{
open("zzz_t1.rb", "w") do |f|
f.puts <<-END
@@ -293,7 +279,6 @@ assert_normal_exit %q{
exec "/"
}
-rjit_enabled = RUBY_DESCRIPTION.include?('+RJIT')
assert_normal_exit %q{
(0..10).map {
Thread.new {
@@ -304,7 +289,7 @@ assert_normal_exit %q{
}.each {|t|
t.join
}
-} unless rjit_enabled # flaky
+}
assert_equal 'ok', %q{
def m
@@ -498,7 +483,7 @@ assert_equal 'foo', %q{
[th1, th2].each {|t| t.join }
GC.start
f.call.source
-} unless rjit_enabled # flaky
+}
assert_normal_exit %q{
class C
def inspect
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index a2a05c45d7..5c655b8f25 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1,125 +1,3 @@
-# regression test for callee block handler overlapping with arguments
-assert_equal '3', %q{
- def foo(_req, *args) = args.last
-
- def call_foo = foo(0, 1, 2, 3, &->{})
-
- call_foo
-}
-
-# call leaf builtin with a block argument
-assert_equal '0', "0.abs(&nil)"
-
-# regression test for invokeblock iseq guard
-assert_equal 'ok', %q{
- return :ok unless defined?(GC.compact)
- def foo = yield
- 10.times do |i|
- ret = eval("foo { #{i} }")
- raise "failed at #{i}" unless ret == i
- GC.compact
- end
- :ok
-} unless defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # Not yet working on RJIT
-
-# regression test for overly generous guard elision
-assert_equal '[0, :sum, 0, :sum]', %q{
- # In faulty versions, the following happens:
- # 1. YJIT puts object on the temp stack with type knowledge
- # (CArray or CString) about RBASIC_CLASS(object).
- # 2. In iter=0, due to the type knowledge, YJIT generates
- # a call to sum() without any guard on RBASIC_CLASS(object).
- # 3. In iter=1, a singleton class is added to the object,
- # changing RBASIC_CLASS(object), falsifying the type knowledge.
- # 4. Because the code from (1) has no class guard, it is incorrectly
- # reused and the wrong method is invoked.
- # Putting a literal is important for gaining type knowledge.
- def carray(iter)
- array = []
- array.sum(iter.times { def array.sum(_) = :sum })
- end
-
- def cstring(iter)
- string = ""
- string.sum(iter.times { def string.sum(_) = :sum })
- end
-
- [carray(0), carray(1), cstring(0), cstring(1)]
-}
-
-# regression test for return type of Integer#/
-# It can return a T_BIGNUM when inputs are T_FIXNUM.
-assert_equal 0x3fffffffffffffff.to_s, %q{
- def call(fixnum_min)
- (fixnum_min / -1) - 1
- end
-
- call(-(2**62))
-}
-
-# regression test for return type of String#<<
-assert_equal 'Sub', %q{
- def call(sub) = (sub << sub).itself
-
- class Sub < String; end
-
- call(Sub.new('o')).class
-}
-
-# test splat filling required and feeding rest
-assert_equal '[0, 1, 2, [3, 4]]', %q{
- public def lead_rest(a, b, *rest)
- [self, a, b, rest]
- end
-
- def call(args) = 0.lead_rest(*args)
-
- call([1, 2, 3, 4])
-}
-
-# test missing opts are nil initialized
-assert_equal '[[0, 1, nil, 3], [0, 1, nil, 3], [0, 1, nil, 3, []], [0, 1, nil, 3, []]]', %q{
- public def lead_opts(a, b=binding.local_variable_get(:c), c=3)
- [self, a, b, c]
- end
-
- public def opts_rest(a=raise, b=binding.local_variable_get(:c), c=3, *rest)
- [self, a, b, c, rest]
- end
-
- def call(args)
- [
- 0.lead_opts(1),
- 0.lead_opts(*args),
-
- 0.opts_rest(1),
- 0.opts_rest(*args),
- ]
- end
-
- call([1])
-}
-
-# test filled optionals with unspecified keyword param
-assert_equal 'ok', %q{
- def opt_rest_opt_kw(_=1, *, k: :ok) = k
-
- def call = opt_rest_opt_kw(0)
-
- call
-}
-
-# test splat empty array with rest param
-assert_equal '[0, 1, 2, []]', %q{
- public def foo(a=1, b=2, *rest)
- [self, a, b, rest]
- end
-
- def call(args) = 0.foo(*args)
-
- call([])
-}
-
# Regression test for yielding with autosplat to block with
# optional parameters. https://github.com/Shopify/yjit/issues/313
assert_equal '[:a, :b, :a, :b]', %q{
@@ -148,7 +26,7 @@ assert_equal '[:ok]', %q{
# Used to crash due to GC run in rb_ensure_iv_list_size()
# not marking the newly allocated [:ok].
RegressionTest.new.extender.itself
-} unless RUBY_DESCRIPTION.include?('+RJIT') # Skip on RJIT since this uncovers a crash
+}
assert_equal 'true', %q{
# regression test for tracking type of locals for too long
@@ -231,53 +109,6 @@ assert_equal '[nil, nil, nil, nil, nil, nil]', %q{
end
}
-assert_equal '[nil, nil, nil, nil, nil, nil]', %q{
- # Tests defined? on non-heap objects
- [NilClass, TrueClass, FalseClass, Integer, Float, Symbol].each do |klass|
- klass.class_eval("def foo = defined?(@foo)")
- end
-
- [nil, true, false, 0xFABCAFE, 0.42, :cake].map do |instance|
- instance.foo
- instance.foo
- end
-}
-
-assert_equal '[nil, "instance-variable", nil, "instance-variable"]', %q{
- # defined? on object that changes shape between calls
- class Foo
- def foo
- defined?(@foo)
- end
-
- def add
- @foo = 1
- end
-
- def remove
- self.remove_instance_variable(:@foo)
- end
- end
-
- obj = Foo.new
- [obj.foo, (obj.add; obj.foo), (obj.remove; obj.foo), (obj.add; obj.foo)]
-}
-
-assert_equal '["instance-variable", 5]', %q{
- # defined? on object too complex for shape information
- class Foo
- def initialize
- 100.times { |i| instance_variable_set("@foo#{i}", i) }
- end
-
- def foo
- [defined?(@foo5), @foo5]
- end
- end
-
- Foo.new.foo
-}
-
assert_equal '0', %q{
# This is a regression test for incomplete invalidation from
# opt_setinlinecache. This test might be brittle, so
@@ -420,6 +251,8 @@ assert_equal 'string', %q{
# Check that exceptions work when getting global variable
assert_equal 'rescued', %q{
+ Warning[:deprecated] = true
+
module Warning
def warn(message)
raise
@@ -573,45 +406,6 @@ assert_equal 'false', %q{
less_than 2
}
-# BOP redefinition works on Integer#<=
-assert_equal 'false', %q{
- def le(x, y) = x <= y
-
- le(2, 2)
-
- class Integer
- def <=(_) = false
- end
-
- le(2, 2)
-}
-
-# BOP redefinition works on Integer#>
-assert_equal 'false', %q{
- def gt(x, y) = x > y
-
- gt(3, 2)
-
- class Integer
- def >(_) = false
- end
-
- gt(3, 2)
-}
-
-# BOP redefinition works on Integer#>=
-assert_equal 'false', %q{
- def ge(x, y) = x >= y
-
- ge(2, 2)
-
- class Integer
- def >=(_) = false
- end
-
- ge(2, 2)
-}
-
# Putobject, less-than operator, fixnums
assert_equal '2', %q{
def check_index(index)
@@ -1222,18 +1016,6 @@ assert_equal '[42, :default]', %q{
]
}
-# Test default value block for Hash with opt_aref_with
-assert_equal "false", %q{
- def index_with_string(h)
- h["foo"]
- end
-
- h = Hash.new { |h, k| k.frozen? }
-
- index_with_string(h)
- index_with_string(h)
-}
-
# A regression test for making sure cfp->sp is proper when
# hitting stubs. See :stub-sp-flush:
assert_equal 'ok', %q{
@@ -1856,24 +1638,6 @@ assert_equal 'true', %q{
jittable_method
}
-# test getbyte on string class
-assert_equal '[97, :nil, 97, :nil, :raised]', %q{
- def getbyte(s, i)
- byte = begin
- s.getbyte(i)
- rescue TypeError
- :raised
- end
-
- byte || :nil
- end
-
- getbyte("a", 0)
- getbyte("a", 0)
-
- [getbyte("a", 0), getbyte("a", 1), getbyte("a", -1), getbyte("a", -2), getbyte("a", "a")]
-} unless defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # Not yet working on RJIT
-
# Test << operator on string subclass
assert_equal 'abab', %q{
class MyString < String; end
@@ -2240,38 +2004,6 @@ assert_equal '[:A, :Btwo]', %q{
ins.foo
}
-# invokesuper with a block
-assert_equal 'true', %q{
- class A
- def foo = block_given?
- end
-
- class B < A
- def foo = super()
- end
-
- B.new.foo { }
- B.new.foo { }
-}
-
-# invokesuper in a block
-assert_equal '[0, 2]', %q{
- class A
- def foo(x) = x * 2
- end
-
- class B < A
- def foo
- 2.times.map do |x|
- super(x)
- end
- end
- end
-
- B.new.foo
- B.new.foo
-}
-
# Call to fixnum
assert_equal '[true, false]', %q{
def is_odd(obj)
@@ -2416,17 +2148,6 @@ assert_equal '[1, 2, nil]', %q{
expandarray_rhs_too_small
}
-assert_equal '[nil, 2, nil]', %q{
- def foo(arr)
- a, b, c = arr
- end
-
- a, b, c1 = foo([0, 1])
- a, b, c2 = foo([0, 1, 2])
- a, b, c3 = foo([0, 1])
- [c1, c2, c3]
-}
-
assert_equal '[1, [2]]', %q{
def expandarray_splat
a, *b = [1, 2]
@@ -2516,7 +2237,7 @@ assert_equal '[[:c_return, :String, :string_alias, "events_to_str"]]', %q{
events.compiled(events)
events
-} unless defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # RJIT calls extra Ruby methods
+} unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # MJIT calls extra Ruby methods
# test enabling a TracePoint that targets a particular line in a C method call
assert_equal '[true]', %q{
@@ -2598,7 +2319,7 @@ assert_equal '[[:c_call, :itself]]', %q{
tp.enable { shouldnt_compile }
events
-} unless defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # RJIT calls extra Ruby methods
+} unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # MJIT calls extra Ruby methods
# test enabling c_return tracing before compiling
assert_equal '[[:c_return, :itself, main]]', %q{
@@ -2613,7 +2334,7 @@ assert_equal '[[:c_return, :itself, main]]', %q{
tp.enable { shouldnt_compile }
events
-} unless defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # RJIT calls extra Ruby methods
+} unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # MJIT calls extra Ruby methods
# test c_call invalidation
assert_equal '[[:c_call, :itself]]', %q{
@@ -3800,420 +3521,10 @@ assert_equal 'ok', %q{
cw(4)
}
-assert_equal 'threw', %q{
- def foo(args)
- wrap(*args)
- rescue ArgumentError
- 'threw'
- end
-
- def wrap(a)
- [a]
- end
-
- foo([Hash.ruby2_keywords_hash({})])
-}
-
-assert_equal 'threw', %q{
- # C call
- def bar(args)
- Array(*args)
- rescue ArgumentError
- 'threw'
- end
-
- bar([Hash.ruby2_keywords_hash({})])
-}
-
-# Test instance_of? and is_a?
-assert_equal 'true', %q{
- 1.instance_of?(Integer) && 1.is_a?(Integer)
-}
-
-# Test instance_of? and is_a? for singleton classes
-assert_equal 'true', %q{
- a = []
- def a.test = :test
- a.instance_of?(Array) && a.is_a?(Array)
-}
-
-# Test instance_of? for singleton_class
-# Yes this does really return false
-assert_equal 'false', %q{
- a = []
- def a.test = :test
- a.instance_of?(a.singleton_class)
-}
-
-# Test is_a? for singleton_class
-assert_equal 'true', %q{
- a = []
- def a.test = :test
- a.is_a?(a.singleton_class)
-}
-
-# Test send with splat to a cfunc
-assert_equal 'true', %q{
- 1.send(:==, 1, *[])
-}
-
-# Test empty splat with cfunc
-assert_equal '2', %q{
- def foo
- Integer.sqrt(4, *[])
- end
- # call twice to deal with constant exiting
- foo
- foo
-}
-
-# Test non-empty splat with cfunc
-assert_equal 'Hello World', %q{
- def bar
- args = ["Hello "]
- greeting = "World"
- greeting.insert(0, *args)
- greeting
- end
- bar
-}
-
-# Regression: this creates a temp stack with > 127 elements
-assert_normal_exit %q{
- def foo(a)
- [
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a,
- ]
- end
-
- def entry
- foo(1)
- end
-
- entry
-}
-
-# Test that splat and rest combined
-# properly dupe the array
-assert_equal "[]", %q{
- def foo(*rest)
- rest << 1
- end
-
- def test(splat)
- foo(*splat)
- end
-
- EMPTY = []
- custom = Object.new
- def custom.to_a
- EMPTY
- end
-
- test(custom)
- test(custom)
- EMPTY
-}
-
-# Rest with send
-assert_equal '[1, 2, 3]', %q{
- def bar(x, *rest)
- rest.insert(0, x)
- end
- send(:bar, 1, 2, 3)
-}
-
-# Fix splat block arg bad compilation
-assert_equal "foo", %q{
- def literal(*args, &block)
- s = ''.dup
- literal_append(s, *args, &block)
- s
- end
-
- def literal_append(sql, v)
- sql << v
- end
-
- literal("foo")
-}
-
-# regression test for accidentally having a parameter truncated
-# due to Rust/C signature mismatch. Used to crash with
-# > [BUG] rb_vm_insn_addr2insn: invalid insn address ...
-# or
-# > ... `Err` value: TryFromIntError(())'
-assert_normal_exit %q{
- n = 16384
- eval(
- "def foo(arg); " + "_=arg;" * n + '_=1;' + "Object; end"
- )
- foo 1
-}
-
-# Regression test for CantCompile not using starting_ctx
-assert_normal_exit %q{
- class Integer
- def ===(other)
- false
- end
- end
-
- def my_func(x)
- case x
- when 1
- 1
- when 2
- 2
- else
- 3
- end
- end
-
- my_func(1)
-}
-
-# Regression test for CantCompile not using starting_ctx
-assert_equal "ArgumentError", %q{
- def literal(*args, &block)
- s = ''.dup
- args = [1, 2, 3]
- literal_append(s, *args, &block)
- s
- end
-
- def literal_append(sql, v)
- [sql.inspect, v.inspect]
- end
-
- begin
- literal("foo")
- rescue ArgumentError
- "ArgumentError"
- end
-}
-
-# Rest with block
-# Simplified code from railsbench
-assert_equal '[{"/a"=>"b", :as=>:c, :via=>:post}, [], nil]', %q{
- def match(path, *rest, &block)
- [path, rest, block]
- end
-
- def map_method(method, args, &block)
- options = args.last
- args.pop
- options[:via] = method
- match(*args, options, &block)
- end
+assert_normal_exit %{
+ class Bug20997
+ def foo(&) = self.class.name(&)
- def post(*args, &block)
- map_method(:post, args, &block)
- end
-
- post "/a" => "b", as: :c
-}
-
-# Test rest and kw_args
-assert_equal '[true, true, true, true]', %q{
- def my_func(*args, base: nil, sort: true)
- [args, base, sort]
- end
-
- def calling_my_func
- results = []
- results << (my_func("test") == [["test"], nil, true])
- results << (my_func("test", base: :base) == [["test"], :base, true])
- results << (my_func("test", sort: false) == [["test"], nil, false])
- results << (my_func("test", "other", base: :base) == [["test", "other"], :base, true])
- results
- end
- calling_my_func
-}
-
-# Test Integer#[] with 2 args
-assert_equal '0', %q{
- 3[0, 0]
-}
-
-# unspecified_bits + checkkeyword
-assert_equal '2', %q{
- def callee = 1
-
- # checkkeyword should see unspecified_bits=0 (use bar), not Integer 1 (set bar = foo).
- def foo(foo, bar: foo) = bar
-
- def entry(&block)
- # write 1 at stack[3]. Calling #callee spills stack[3].
- 1 + (1 + (1 + (1 + callee)))
- # &block is written to a register instead of stack[3]. When &block is popped and
- # unspecified_bits is pushed, it must be written to stack[3], not to a register.
- foo(1, bar: 2, &block)
- end
-
- entry # call branch_stub_hit (spill temps)
- entry # doesn't call branch_stub_hit (not spill temps)
-}
-
-# Test rest and optional_params
-assert_equal '[true, true, true, true]', %q{
- def my_func(stuff, base=nil, sort=true, *args)
- [stuff, base, sort, args]
- end
-
- def calling_my_func
- results = []
- results << (my_func("test") == ["test", nil, true, []])
- results << (my_func("test", :base) == ["test", :base, true, []])
- results << (my_func("test", :base, false) == ["test", :base, false, []])
- results << (my_func("test", :base, false, "other", "other") == ["test", :base, false, ["other", "other"]])
- results
- end
- calling_my_func
-}
-
-# Test rest and optional_params and splat
-assert_equal '[true, true, true, true, true]', %q{
- def my_func(stuff, base=nil, sort=true, *args)
- [stuff, base, sort, args]
- end
-
- def calling_my_func
- results = []
- splat = ["test"]
- results << (my_func(*splat) == ["test", nil, true, []])
- splat = [:base]
- results << (my_func("test", *splat) == ["test", :base, true, []])
- splat = [:base, false]
- results << (my_func("test", *splat) == ["test", :base, false, []])
- splat = [:base, false, "other", "other"]
- results << (my_func("test", *splat) == ["test", :base, false, ["other", "other"]])
- splat = ["test", :base, false, "other", "other"]
- results << (my_func(*splat) == ["test", :base, false, ["other", "other"]])
- results
- end
- calling_my_func
-}
-
-# Regresssion test: rest and optional and splat
-assert_equal 'true', %q{
- def my_func(base=nil, *args)
- [base, args]
- end
-
- def calling_my_func
- array = []
- my_func(:base, :rest1, *array) == [:base, [:rest1]]
- end
-
- calling_my_func
-}
-
-# Fix failed case for large splat
-assert_equal 'true', %q{
- def d(a, b=:b)
- end
-
- def calling_func
- ary = 1380888.times;
- d(*ary)
- end
- begin
- calling_func
- rescue ArgumentError
- true
- end
-} unless defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # Not yet working on RJIT
-
-# Regresssion test: register allocator on expandarray
-assert_equal '[]', %q{
- func = proc { [] }
- proc do
- _x, _y = func.call
- end.call
-}
-
-# Catch TAG_BREAK in a non-FINISH frame with JIT code
-assert_equal '1', %q{
- def entry
- catch_break
- end
-
- def catch_break
- while_true do
- break
- end
- 1
- end
-
- def while_true
- while true
- yield
- end
- end
-
- entry
-}
-
-assert_equal '6', %q{
- class Base
- def number = 1 + yield
- end
-
- class Sub < Base
- def number = super + 2
- end
-
- Sub.new.number { 3 }
-}
-
-# Integer multiplication and overflow
-assert_equal '[6, -6, 9671406556917033397649408, -9671406556917033397649408, 21267647932558653966460912964485513216]', %q{
- def foo(a, b)
- a * b
+ new.foo
end
-
- r1 = foo(2, 3)
- r2 = foo(2, -3)
- r3 = foo(2 << 40, 2 << 41)
- r4 = foo(2 << 40, -2 << 41)
- r5 = foo(1 << 62, 1 << 62)
-
- [r1, r2, r3, r4, r5]
-}
-
-# Integer multiplication and overflow (minimized regression test from test-basic)
-assert_equal '8515157028618240000', %q{2128789257154560000 * 4}
-
-# Inlined method calls
-assert_equal 'nil', %q{
- def putnil = nil
- def entry = putnil
- entry.inspect
-}
-assert_equal '1', %q{
- def putobject_1 = 1
- def entry = putobject_1
- entry
-}
-assert_equal 'false', %q{
- def putobject(_unused_arg1) = false
- def entry = putobject(nil)
- entry
-}
-assert_equal 'true', %q{
- def entry = yield
- entry { true }
}
diff --git a/builtin.c b/builtin.c
index b725d8b968..21fff95650 100644
--- a/builtin.c
+++ b/builtin.c
@@ -3,15 +3,15 @@
#include "iseq.h"
#include "builtin.h"
-#include "builtin_binary.inc"
-
-#ifndef BUILTIN_BINARY_SIZE
+#ifdef CROSS_COMPILING
#define INCLUDED_BY_BUILTIN_C 1
#include "mini_builtin.c"
#else
+#include "builtin_binary.inc"
+
static const unsigned char *
bin4feature(const struct builtin_binary *bb, const char *feature, size_t *psize)
{
@@ -39,7 +39,7 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
size_t size;
const unsigned char *bin = builtin_lookup(feature_name, &size);
if (! bin) {
- rb_bug("builtin_lookup: can not find %s", feature_name);
+ rb_bug("builtin_lookup: can not find %s\n", feature_name);
}
// load binary
@@ -48,7 +48,6 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
vm->builtin_function_table = table;
vm->builtin_inline_index = 0;
const rb_iseq_t *iseq = rb_iseq_ibf_load_bytes((const char *)bin, size);
- ASSUME(iseq); // otherwise an exception should have raised
vm->builtin_function_table = NULL;
// exec
diff --git a/builtin.h b/builtin.h
index 85fd1a009a..38ad5a1629 100644
--- a/builtin.h
+++ b/builtin.h
@@ -11,13 +11,17 @@ struct rb_builtin_function {
// for load
const int index;
const char * const name;
+
+ // for jit
+ void (*compiler)(VALUE, long, unsigned, bool);
};
-#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity) {\
+#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity, _compiler) {\
.name = _i < 0 ? NULL : #_name, \
.func_ptr = (void *)_fname, \
.argc = _arity, \
.index = _i, \
+ .compiler = _compiler, \
}
void rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table);
diff --git a/class.c b/class.c
index f730009709..cf0b7b821f 100644
--- a/class.c
+++ b/class.c
@@ -30,41 +30,7 @@
#include "ruby/st.h"
#include "vm_core.h"
-/* Flags of T_CLASS
- *
- * 2: RCLASS_SUPERCLASSES_INCLUDE_SELF
- * The RCLASS_SUPERCLASSES contains the class as the last element.
- * This means that this class owns the RCLASS_SUPERCLASSES list.
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID for the class.
- * endif
- */
-
-/* Flags of T_ICLASS
- *
- * 0: RICLASS_IS_ORIGIN
- * 3: RICLASS_ORIGIN_SHARED_MTBL
- * The T_ICLASS does not own the method table.
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID. This is set but not used.
- * endif
- */
-
-/* Flags of T_MODULE
- *
- * 1: RMODULE_ALLOCATED_BUT_NOT_INITIALIZED
- * Module has not been initialized.
- * 2: RCLASS_SUPERCLASSES_INCLUDE_SELF
- * See RCLASS_SUPERCLASSES_INCLUDE_SELF in T_CLASS.
- * 3: RMODULE_IS_REFINEMENT
- * Module is used for refinements.
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID for the module.
- * endif
- */
+#define id_attached id__attached__
#define METACLASS_OF(k) RBASIC(k)->klass
#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
@@ -229,13 +195,22 @@ rb_class_detach_module_subclasses(VALUE klass)
static VALUE
class_alloc(VALUE flags, VALUE klass)
{
- size_t alloc_size = sizeof(struct RClass) + sizeof(rb_classext_t);
+ size_t alloc_size = sizeof(struct RClass);
+
+#if RCLASS_EXT_EMBEDDED
+ alloc_size += sizeof(rb_classext_t);
+#endif
flags &= T_MASK;
+ flags |= FL_PROMOTED1 /* start from age == 2 */;
if (RGENGC_WB_PROTECTED_CLASS) flags |= FL_WB_PROTECTED;
- NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size, 0);
+ RVARGC_NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size);
+#if RCLASS_EXT_EMBEDDED
memset(RCLASS_EXT(obj), 0, sizeof(rb_classext_t));
+#else
+ obj->ptr = ZALLOC(rb_classext_t);
+#endif
/* ZALLOC
RCLASS_CONST_TBL(obj) = 0;
@@ -248,7 +223,7 @@ class_alloc(VALUE flags, VALUE klass)
*/
RCLASS_SET_ORIGIN((VALUE)obj, (VALUE)obj);
RB_OBJ_WRITE(obj, &RCLASS_REFINED_CLASS(obj), Qnil);
- RCLASS_SET_ALLOCATOR((VALUE)obj, 0);
+ RCLASS_ALLOCATOR(obj) = 0;
return (VALUE)obj;
}
@@ -435,8 +410,7 @@ struct cvc_table_copy_ctx {
};
static enum rb_id_table_iterator_result
-cvc_table_copy(ID id, VALUE val, void *data)
-{
+cvc_table_copy(ID id, VALUE val, void *data) {
struct cvc_table_copy_ctx *ctx = (struct cvc_table_copy_ctx *)data;
struct rb_cvar_class_tbl_entry * orig_entry;
orig_entry = (struct rb_cvar_class_tbl_entry *)val;
@@ -496,7 +470,7 @@ static bool ensure_origin(VALUE klass);
/**
* If this flag is set, that module is allocated but not initialized yet.
*/
-enum {RMODULE_ALLOCATED_BUT_NOT_INITIALIZED = RUBY_FL_USER1};
+enum {RMODULE_ALLOCATED_BUT_NOT_INITIALIZED = RUBY_FL_USER5};
static inline bool
RMODULE_UNINITIALIZED(VALUE module)
@@ -539,14 +513,14 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
/* cloned flag is refer at constant inline cache
* see vm_get_const_key_cref() in vm_insnhelper.c
*/
- RCLASS_EXT(clone)->cloned = true;
- RCLASS_EXT(orig)->cloned = true;
+ FL_SET(clone, RCLASS_CLONED);
+ FL_SET(orig , RCLASS_CLONED);
if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig));
rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone);
}
- RCLASS_SET_ALLOCATOR(clone, RCLASS_ALLOCATOR(orig));
+ RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(orig);
copy_tables(clone, orig);
if (RCLASS_M_TBL(orig)) {
struct clone_method_arg arg;
@@ -582,7 +556,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
prev_clone_p = clone_p;
RCLASS_M_TBL(clone_p) = RCLASS_M_TBL(p);
RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p);
- RCLASS_SET_ALLOCATOR(clone_p, RCLASS_ALLOCATOR(p));
+ RCLASS_ALLOCATOR(clone_p) = RCLASS_ALLOCATOR(p);
if (RB_TYPE_P(clone, T_CLASS)) {
RCLASS_SET_INCLUDER(clone_p, clone);
}
@@ -645,7 +619,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
// attached to an object other than `obj`. In which case `obj` does not have
// a material singleton class attached yet and there is no singleton class
// to clone.
- if (!(FL_TEST(klass, FL_SINGLETON) && RCLASS_ATTACHED_OBJECT(klass) == obj)) {
+ if (!(FL_TEST(klass, FL_SINGLETON) && rb_attr_get(klass, id_attached) == obj)) {
// nothing to clone
return klass;
}
@@ -667,6 +641,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
}
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
+ RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(klass);
rb_iv_tbl_copy(clone, klass);
if (RCLASS_CONST_TBL(klass)) {
struct clone_const_arg arg;
@@ -697,7 +672,7 @@ void
rb_singleton_class_attached(VALUE klass, VALUE obj)
{
if (FL_TEST(klass, FL_SINGLETON)) {
- RCLASS_SET_ATTACHED_OBJECT(klass, obj);
+ rb_class_ivar_set(klass, id_attached, obj);
}
}
@@ -711,13 +686,13 @@ rb_singleton_class_attached(VALUE klass, VALUE obj)
static int
rb_singleton_class_has_metaclass_p(VALUE sklass)
{
- return RCLASS_ATTACHED_OBJECT(METACLASS_OF(sklass)) == sklass;
+ return rb_attr_get(METACLASS_OF(sklass), id_attached) == sklass;
}
int
rb_singleton_class_internal_p(VALUE sklass)
{
- return (RB_TYPE_P(RCLASS_ATTACHED_OBJECT(sklass), T_CLASS) &&
+ return (RB_TYPE_P(rb_attr_get(sklass, id_attached), T_CLASS) &&
!rb_singleton_class_has_metaclass_p(sklass));
}
@@ -863,27 +838,6 @@ refinement_import_methods(int argc, VALUE *argv, VALUE refinement)
}
# endif
-/*!
- *--
- * \private
- * Initializes the world of objects and classes.
- *
- * At first, the function bootstraps the class hierarchy.
- * It initializes the most fundamental classes and their metaclasses.
- * - \c BasicObject
- * - \c Object
- * - \c Module
- * - \c Class
- * After the bootstrap step, the class hierarchy becomes as the following
- * diagram.
- *
- * \image html boottime-classes.png
- *
- * Then, the function defines classes, modules and methods as usual.
- * \ingroup class
- *++
- */
-
void
Init_class_hierarchy(void)
{
@@ -956,7 +910,7 @@ rb_define_class_id(ID id, VALUE super)
* \return the value \c Class#inherited's returns
* \pre Each of \a super and \a klass must be a \c Class object.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_class_inherited(VALUE super, VALUE klass)
{
ID inherited;
@@ -1004,7 +958,7 @@ rb_define_class_under(VALUE outer, const char *name, VALUE super)
}
VALUE
-rb_define_class_id_under(VALUE outer, ID id, VALUE super)
+rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super)
{
VALUE klass;
@@ -1021,8 +975,6 @@ rb_define_class_id_under(VALUE outer, ID id, VALUE super)
" (%"PRIsVALUE" is given but was %"PRIsVALUE")",
outer, rb_id2str(id), RCLASS_SUPER(klass), super);
}
- /* Class may have been defined in Ruby and not pin-rooted */
- rb_vm_add_root_module(klass);
return klass;
}
@@ -1034,12 +986,19 @@ rb_define_class_id_under(VALUE outer, ID id, VALUE super)
rb_set_class_path_string(klass, outer, rb_id2str(id));
rb_const_set(outer, id, klass);
rb_class_inherited(super, klass);
- rb_vm_add_root_module(klass);
return klass;
}
VALUE
+rb_define_class_id_under(VALUE outer, ID id, VALUE super)
+{
+ VALUE klass = rb_define_class_id_under_no_pin(outer, id, super);
+ rb_vm_add_root_module(klass);
+ return klass;
+}
+
+VALUE
rb_module_s_alloc(VALUE klass)
{
VALUE mod = class_alloc(T_MODULE, klass);
@@ -1186,8 +1145,8 @@ rb_include_module(VALUE klass, VALUE module)
iclass = iclass->next;
}
- int do_include = 1;
while (iclass) {
+ int do_include = 1;
VALUE check_class = iclass->klass;
/* During lazy sweeping, iclass->klass could be a dead object that
* has not yet been swept. */
@@ -1254,7 +1213,7 @@ static int
do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super, bool check_cyclic)
{
VALUE p, iclass, origin_stack = 0;
- int method_changed = 0, add_subclass;
+ int method_changed = 0;
long origin_len;
VALUE klass_origin = RCLASS_ORIGIN(klass);
VALUE original_klass = klass;
@@ -1318,7 +1277,6 @@ do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super
iclass = rb_include_class_new(module, super_class);
c = RCLASS_SET_SUPER(c, iclass);
RCLASS_SET_INCLUDER(iclass, klass);
- add_subclass = TRUE;
if (module != RCLASS_ORIGIN(module)) {
if (!origin_stack) origin_stack = rb_ary_hidden_new(2);
VALUE origin[2] = {iclass, RCLASS_ORIGIN(module)};
@@ -1329,14 +1287,11 @@ do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super
RCLASS_SET_ORIGIN(RARRAY_AREF(origin_stack, (origin_len -= 2)), iclass);
RICLASS_SET_ORIGIN_SHARED_MTBL(iclass);
rb_ary_resize(origin_stack, origin_len);
- add_subclass = FALSE;
}
- if (add_subclass) {
- VALUE m = module;
- if (BUILTIN_TYPE(m) == T_ICLASS) m = METACLASS_OF(m);
- rb_module_add_to_subclasses_list(m, iclass);
- }
+ VALUE m = module;
+ if (BUILTIN_TYPE(m) == T_ICLASS) m = METACLASS_OF(m);
+ rb_module_add_to_subclasses_list(m, iclass);
if (BUILTIN_TYPE(klass) == T_MODULE && FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
VALUE refined_class =
@@ -1706,7 +1661,7 @@ rb_class_attached_object(VALUE klass)
rb_raise(rb_eTypeError, "`%"PRIsVALUE"' is not a singleton class", klass);
}
- return RCLASS_ATTACHED_OBJECT(klass);
+ return rb_attr_get(klass, id_attached);
}
static void
@@ -2235,7 +2190,7 @@ singleton_class_of(VALUE obj)
klass = METACLASS_OF(obj);
if (!(FL_TEST(klass, FL_SINGLETON) &&
- RCLASS_ATTACHED_OBJECT(klass) == obj)) {
+ rb_attr_get(klass, id_attached) == obj)) {
klass = rb_make_metaclass(obj, klass);
}
@@ -2274,7 +2229,7 @@ rb_singleton_class_get(VALUE obj)
}
klass = METACLASS_OF(obj);
if (!FL_TEST(klass, FL_SINGLETON)) return Qnil;
- if (RCLASS_ATTACHED_OBJECT(klass) != obj) return Qnil;
+ if (rb_attr_get(klass, id_attached) != obj) return Qnil;
return klass;
}
@@ -2338,7 +2293,7 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
rb_attr(klass, rb_intern(name), read, write, FALSE);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_keyword_error_new(const char *error, VALUE keys)
{
long i = 0, len = RARRAY_LEN(keys);
diff --git a/common.mk b/common.mk
index d7ed7d77f6..126053c9c8 100644
--- a/common.mk
+++ b/common.mk
@@ -1,6 +1,4 @@
# -*- mode: makefile-gmake; indent-tabs-mode: t -*-
-# This fragment can be used with nmake.exe and with bsdmake.
-# Avoid features specific to GNU Make.
bin: $(PROGRAM) $(WPROGRAM)
lib: $(LIBRUBY)
@@ -45,15 +43,20 @@ RUN_OPTS = --disable-gems
# GITPULLOPTIONS = --no-tags
-PRISM_SRCDIR = $(srcdir)/prism
-INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir) -I$(PRISM_SRCDIR) -I$(UNICODE_HDR_DIR) $(incflags)
+INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir) -I$(UNICODE_HDR_DIR) $(incflags)
GEM_HOME =
GEM_PATH =
GEM_VENDOR =
BENCHMARK_DRIVER_GIT_URL = https://github.com/benchmark-driver/benchmark-driver
-BENCHMARK_DRIVER_GIT_REF = v0.16.3
+BENCHMARK_DRIVER_GIT_REF = v0.16.0
+SIMPLECOV_GIT_URL = https://github.com/colszowka/simplecov.git
+SIMPLECOV_GIT_REF = v0.17.0
+SIMPLECOV_HTML_GIT_URL = https://github.com/colszowka/simplecov-html.git
+SIMPLECOV_HTML_GIT_REF = v0.10.2
+DOCLIE_GIT_URL = https://github.com/ms-ati/docile.git
+DOCLIE_GIT_REF = v1.3.2
STATIC_RUBY = static-ruby
@@ -83,40 +86,6 @@ ENC_MK = enc.mk
MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \
RUBY="$(BOOTSTRAPRUBY)" MINIRUBY="$(BOOTSTRAPRUBY)" $(mflags)
-PRISM_BUILD_DIR = prism
-
-PRISM_FILES = prism/api_node.$(OBJEXT) \
- prism/api_pack.$(OBJEXT) \
- prism/diagnostic.$(OBJEXT) \
- prism/enc/pm_big5.$(OBJEXT) \
- prism/enc/pm_euc_jp.$(OBJEXT) \
- prism/enc/pm_gbk.$(OBJEXT) \
- prism/enc/pm_shift_jis.$(OBJEXT) \
- prism/enc/pm_tables.$(OBJEXT) \
- prism/enc/pm_unicode.$(OBJEXT) \
- prism/enc/pm_windows_31j.$(OBJEXT) \
- prism/extension.$(OBJEXT) \
- prism/node.$(OBJEXT) \
- prism/options.$(OBJEXT) \
- prism/pack.$(OBJEXT) \
- prism/prettyprint.$(OBJEXT) \
- prism/regexp.$(OBJEXT) \
- prism/serialize.$(OBJEXT) \
- prism/token_type.$(OBJEXT) \
- prism/util/pm_buffer.$(OBJEXT) \
- prism/util/pm_char.$(OBJEXT) \
- prism/util/pm_constant_pool.$(OBJEXT) \
- prism/util/pm_list.$(OBJEXT) \
- prism/util/pm_memchr.$(OBJEXT) \
- prism/util/pm_newline_list.$(OBJEXT) \
- prism/util/pm_state_stack.$(OBJEXT) \
- prism/util/pm_string.$(OBJEXT) \
- prism/util/pm_string_list.$(OBJEXT) \
- prism/util/pm_strncasecmp.$(OBJEXT) \
- prism/util/pm_strpbrk.$(OBJEXT) \
- prism/prism.$(OBJEXT) \
- prism_init.$(OBJEXT)
-
COMMONOBJS = array.$(OBJEXT) \
ast.$(OBJEXT) \
bignum.$(OBJEXT) \
@@ -145,15 +114,13 @@ COMMONOBJS = array.$(OBJEXT) \
marshal.$(OBJEXT) \
math.$(OBJEXT) \
memory_view.$(OBJEXT) \
- rjit.$(OBJEXT) \
- rjit_c.$(OBJEXT) \
+ mjit.$(OBJEXT) \
+ mjit_c.$(OBJEXT) \
node.$(OBJEXT) \
- node_dump.$(OBJEXT) \
numeric.$(OBJEXT) \
object.$(OBJEXT) \
pack.$(OBJEXT) \
parse.$(OBJEXT) \
- parser_st.$(OBJEXT) \
proc.$(OBJEXT) \
process.$(OBJEXT) \
ractor.$(OBJEXT) \
@@ -168,7 +135,6 @@ COMMONOBJS = array.$(OBJEXT) \
regparse.$(OBJEXT) \
regsyntax.$(OBJEXT) \
ruby.$(OBJEXT) \
- ruby_parser.$(OBJEXT) \
scheduler.$(OBJEXT) \
shape.$(OBJEXT) \
signal.$(OBJEXT) \
@@ -181,6 +147,7 @@ COMMONOBJS = array.$(OBJEXT) \
thread.$(OBJEXT) \
time.$(OBJEXT) \
transcode.$(OBJEXT) \
+ transient_heap.$(OBJEXT) \
util.$(OBJEXT) \
variable.$(OBJEXT) \
version.$(OBJEXT) \
@@ -189,81 +156,13 @@ COMMONOBJS = array.$(OBJEXT) \
vm_dump.$(OBJEXT) \
vm_sync.$(OBJEXT) \
vm_trace.$(OBJEXT) \
- weakmap.$(OBJEXT) \
- $(PRISM_FILES) \
$(YJIT_OBJ) \
- $(YJIT_LIBOBJ) \
$(COROUTINE_OBJ) \
$(DTRACE_OBJ) \
$(BUILTIN_ENCOBJS) \
$(BUILTIN_TRANSOBJS) \
$(MISSING)
-$(PRISM_FILES): $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/enc/.time $(PRISM_BUILD_DIR)/util/.time
-
-$(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/enc/.time $(PRISM_BUILD_DIR)/util/.time:
- $(Q) $(MAKEDIRS) $(@D)
- @$(NULLCMD) > $@
-
-main: $(srcdir)/lib/prism/compiler.rb
-srcs: $(srcdir)/lib/prism/compiler.rb
-$(srcdir)/lib/prism/compiler.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/compiler.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/compiler.rb $(srcdir)/lib/prism/compiler.rb
-
-main: $(srcdir)/lib/prism/dispatcher.rb
-srcs: $(srcdir)/lib/prism/dispatcher.rb
-$(srcdir)/lib/prism/dispatcher.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/dispatcher.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/dispatcher.rb $(srcdir)/lib/prism/dispatcher.rb
-
-main: $(srcdir)/lib/prism/dsl.rb
-srcs: $(srcdir)/lib/prism/dsl.rb
-$(srcdir)/lib/prism/dsl.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/dsl.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/dsl.rb $(srcdir)/lib/prism/dsl.rb
-
-main: $(srcdir)/lib/prism/mutation_compiler.rb
-srcs: $(srcdir)/lib/prism/mutation_compiler.rb
-$(srcdir)/lib/prism/mutation_compiler.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/mutation_compiler.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/mutation_compiler.rb $(srcdir)/lib/prism/mutation_compiler.rb
-
-main: $(srcdir)/lib/prism/node.rb
-srcs: $(srcdir)/lib/prism/node.rb
-$(srcdir)/lib/prism/node.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/node.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/node.rb $(srcdir)/lib/prism/node.rb
-
-main: $(srcdir)/lib/prism/serialize.rb
-srcs: $(srcdir)/lib/prism/serialize.rb
-$(srcdir)/lib/prism/serialize.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/serialize.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/serialize.rb $(srcdir)/lib/prism/serialize.rb
-
-main: $(srcdir)/lib/prism/visitor.rb
-srcs: $(srcdir)/lib/prism/visitor.rb
-$(srcdir)/lib/prism/visitor.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/visitor.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/visitor.rb $(srcdir)/lib/prism/visitor.rb
-
-srcs: prism/api_node.c
-prism/api_node.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/ext/prism/api_node.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb ext/prism/api_node.c $@
-
-srcs: prism/ast.h
-prism/ast.h: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/include/prism/ast.h.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb include/prism/ast.h $@
-
-srcs: prism/node.c
-prism/node.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/node.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/node.c $@
-
-srcs: prism/prettyprint.c
-prism/prettyprint.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/prettyprint.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/prettyprint.c $@
-
-srcs: prism/serialize.c
-prism/serialize.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/serialize.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/serialize.c $@
-
-srcs: prism/token_type.c
-prism/token_type.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/token_type.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/token_type.c $@
-
EXPORTOBJS = $(DLNOBJ) \
localeinit.$(OBJEXT) \
loadpath.$(OBJEXT) \
@@ -302,7 +201,7 @@ INSTALL_DATA_MODE = 0644
BOOTSTRAPRUBY_COMMAND = $(BOOTSTRAPRUBY) $(BOOTSTRAPRUBY_OPT)
TESTSDIR = $(srcdir)/test
TOOL_TESTSDIR = $(tooldir)/test
-TEST_EXCLUDES = --excludes-dir=$(TESTSDIR)/.excludes --name=!/memory_leak/
+TEST_EXCLUDES = --excludes-dir=$(TESTSDIR)/excludes --name=!/memory_leak/
TESTWORKDIR = testwork
TESTOPTS = $(RUBY_TESTOPTS)
@@ -326,7 +225,6 @@ YJIT_RUSTC_ARGS = --crate-name=yjit \
--crate-type=staticlib \
--edition=2021 \
-g \
- -C lto=thin \
-C opt-level=3 \
-C overflow-checks=on \
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
@@ -337,15 +235,45 @@ all: $(SHOWFLAGS) main docs
main: $(SHOWFLAGS) exts $(ENCSTATIC:static=lib)encs
@$(NULLCMD)
-main: $(srcdir)/lib/ruby_vm/rjit/instruction.rb
-srcs: $(srcdir)/lib/ruby_vm/rjit/instruction.rb
-$(srcdir)/lib/ruby_vm/rjit/instruction.rb: $(tooldir)/insns2vm.rb $(tooldir)/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb $(srcdir)/insns.def
+main: $(srcdir)/lib/ruby_vm/mjit/instruction.rb
+srcs: $(srcdir)/lib/ruby_vm/mjit/instruction.rb
+$(srcdir)/lib/ruby_vm/mjit/instruction.rb: $(tooldir)/insns2vm.rb $(tooldir)/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb $(srcdir)/insns.def
$(ECHO) generating $@
$(Q) $(BASERUBY) -Ku $(tooldir)/insns2vm.rb --basedir="$(srcdir)" $(INSNS2VMOPT) $@
-.PHONY: rjit-bindgen
-rjit-bindgen:
- $(Q) $(BASERUBY) -rrubygems -C $(srcdir)/tool/rjit bindgen.rb $(CURDIR)
+mjit-headers: $(MJIT_SUPPORT)-mjit-headers
+no-mjit-headers: PHONY
+yes-mjit-headers: mjit_config.h PHONY
+
+mjit.$(OBJEXT): mjit_config.h
+mjit_config.h: Makefile
+
+.PHONY: mjit-bindgen
+mjit-bindgen:
+ $(Q) $(BASERUBY) -rrubygems -C $(srcdir)/tool/mjit bindgen.rb $(CURDIR)
+
+# These rules using MJIT_HEADER_SUFFIX must be in common.mk, not
+# Makefile.in, in order to override the macro in defs/universal.mk.
+
+# Other `-Dxxx`s preceding `-DMJIT_HEADER` will be removed in transform_mjit_header.rb.
+# So `-DMJIT_HEADER` should be passed first when rb_mjit_header.h is generated.
+$(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time: probes.h vm.$(OBJEXT) \
+ $(TIMESTAMPDIR)/$(arch)/.time $(tooldir)/mjit_tabs.rb $(PREP) $(RBCONFIG)
+ $(ECHO) building $(@F:.time=.h)
+ $(Q)$(MINIRUBY) $(tooldir)/mjit_tabs.rb "$(MJIT_TABS)" \
+ $(CPP) -DMJIT_HEADER $(MJIT_HEADER_FLAGS) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(srcdir)/vm.c $(CPPOUTFLAG)$(@F:.time=.h).new
+ $(Q) $(IFCHANGE) "--timestamp=$@" $(@F:.time=.h) $(@F:.time=.h).new
+
+$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h: $(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time
+
+$(MJIT_MIN_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h: \
+ $(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time \
+ $(tooldir)/transform_mjit_header.rb $(PREP) \
+ $(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h
+ $(ECHO) building $@
+ $(Q)$(MINIRUBY) $(tooldir)/transform_mjit_header.rb "$(CC) $(CFLAGS) -w" $(MJIT_HEADER:.h=)$(MJIT_HEADER_ARCH).h $@
+ $(Q) $(MAKEDIRS) $(MJIT_HEADER_INSTALL_DIR)
+ $(Q) $(MAKE_LINK) $@ $(MJIT_HEADER_INSTALL_DIR)/$(@F)
.PHONY: showflags
exts enc trans: $(SHOWFLAGS)
@@ -401,8 +329,7 @@ configure-ext: $(EXTS_MK)
build-ext: $(EXTS_MK)
$(Q)$(MAKE) -f $(EXTS_MK) $(mflags) libdir="$(libdir)" LIBRUBY_EXTS=$(LIBRUBY_EXTS) \
- EXTENCS="$(ENCOBJS)" BASERUBY="$(BASERUBY)" MINIRUBY="$(MINIRUBY)" \
- UPDATE_LIBRARIES=no $(EXTSTATIC)
+ EXTENCS="$(ENCOBJS)" MINIRUBY="$(MINIRUBY)" UPDATE_LIBRARIES=no $(EXTSTATIC)
$(Q)$(MAKE) $(EXTS_NOTE)
exts-note: $(EXTS_MK)
@@ -445,8 +372,8 @@ Doxyfile: $(srcdir)/template/Doxyfile.tmpl $(PREP) $(tooldir)/generic_erb.rb $(R
$(Q) $(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ $(srcdir)/template/Doxyfile.tmpl \
--srcdir="$(srcdir)" --miniruby="$(MINIRUBY)"
-program: $(SHOWFLAGS) $(DOT_WAIT) $(PROGRAM)
-wprogram: $(SHOWFLAGS) $(DOT_WAIT) $(WPROGRAM)
+program: $(SHOWFLAGS) $(PROGRAM)
+wprogram: $(SHOWFLAGS) $(WPROGRAM)
mini: PHONY miniruby$(EXEEXT)
$(PROGRAM) $(WPROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP)
@@ -467,12 +394,12 @@ ruby.imp: $(COMMONOBJS)
$(NM) -Pgp $(COMMONOBJS) | \
awk 'BEGIN{print "#!"}; $$2~/^[A-TV-Z]$$/&&$$1!~/^$(SYMBOL_PREFIX)(Init_|InitVM_|ruby_static_id_|.*_threadptr_|rb_ec_)|^\./{print $$1}'; \
($(CHDIR) $(srcdir) && \
- exec sed -n '/^RJIT_FUNC_EXPORTED/!d;N;s/.*\n\(rb_[a-zA-Z_0-9]*\).*/$(SYMBOL_PREFIX)\1/p' cont.c gc.c thread*c vm*.c) \
+ exec sed -n '/^MJIT_FUNC_EXPORTED/!d;N;s/.*\n\(rb_[a-zA-Z_0-9]*\).*/$(SYMBOL_PREFIX)\1/p' cont.c gc.c thread*c vm*.c) \
} | \
sort -u -o $@
install: install-$(INSTALLDOC)
-docs: srcs-doc $(DOCTARGETS)
+docs: $(DOCTARGETS)
pkgconfig-data: $(ruby_pc)
$(ruby_pc): $(srcdir)/template/ruby.pc.in config.status
@@ -666,15 +593,15 @@ do-install-dbg: $(PROGRAM) pre-install-dbg
post-install-dbg::
@$(NULLCMD)
-rdoc: PHONY main srcs-doc
+rdoc: PHONY main
@echo Generating RDoc documentation
$(Q) $(RDOC) --ri --op "$(RDOCOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) "$(srcdir)"
-html: PHONY main srcs-doc
+html: PHONY main
@echo Generating RDoc HTML files
$(Q) $(RDOC) --op "$(HTMLOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) "$(srcdir)"
-rdoc-coverage: PHONY main srcs-doc
+rdoc-coverage: PHONY main
@echo Generating RDoc coverage report
$(Q) $(RDOC) --quiet -C $(RDOCFLAGS) "$(srcdir)"
@@ -712,11 +639,8 @@ clean-local:: clean-runnable
$(Q)$(RM) y.tab.c y.output encdb.h transdb.h config.log rbconfig.rb $(ruby_pc) $(COROUTINE_H:/Context.h=/.time)
$(Q)$(RM) probes.h probes.$(OBJEXT) probes.stamp ruby-glommed.$(OBJEXT) ruby.imp ChangeLog $(STATIC_RUBY)$(EXEEXT)
$(Q)$(RM) GNUmakefile.old Makefile.old $(arch)-fake.rb bisect.sh $(ENC_TRANS_D) builtin_binary.inc
- $(Q)$(RM) $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/*/.time
-$(Q)$(RMALL) yjit/target
- -$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine yjit \
- $(PRISM_BUILD_DIR)/*/ $(PRISM_BUILD_DIR) tmp \
- 2> $(NULL) || $(NULLCMD)
+ -$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine yjit 2> $(NULL) || $(NULLCMD)
bin/clean-runnable:: PHONY
$(Q)$(CHDIR) bin 2>$(NULL) && $(RM) $(PROGRAM) $(WPROGRAM) $(GORUBY)$(EXEEXT) bin/*.$(DLEXT) 2>$(NULL) || $(NULLCMD)
@@ -764,6 +688,8 @@ clean-srcs-local::
$(Q)$(RM) parse.c parse.h lex.c enc/trans/newline.c revision.h
$(Q)$(RM) id.c id.h probes.dmyh probes.h
$(Q)$(RM) encdb.h transdb.h verconf.h ruby-runner.h
+ $(Q)$(RM) mjit_config.h rb_mjit_header.h
+ $(Q)$(RM) $(MJIT_MIN_HEADER) $(MJIT_MIN_HEADER:.h=)$(MJIT_HEADER_SUFFIX:%=*).h
realclean-srcs-local:: clean-srcs-local
$(Q)$(CHDIR) $(srcdir) && $(RM) \
@@ -858,7 +784,7 @@ $(HAVE_BASERUBY:no=)$(arch)-fake.rb: miniruby$(EXEEXT)
# actually depending on other headers more.
$(arch:noarch=ignore)-fake.rb: $(top_srcdir)/revision.h $(top_srcdir)/version.h $(srcdir)/version.c
-$(arch:noarch=ignore)-fake.rb: {$(VPATH)}id.h {$(VPATH)}vm_opts.h $(REVISION_H)
+$(arch:noarch=ignore)-fake.rb: {$(VPATH)}id.h {$(VPATH)}vm_opts.h
$(arch:noarch=ignore)-fake.rb: $(srcdir)/template/fake.rb.in $(tooldir)/generic_erb.rb
$(ECHO) generating $@
@@ -870,7 +796,6 @@ $(arch:noarch=ignore)-fake.rb: $(srcdir)/template/fake.rb.in $(tooldir)/generic_
noarch-fake.rb: # prerequisite of yes-fake
$(Q) exit > $@
-# runner: BASERUBY, target: miniruby
btest: $(TEST_RUNNABLE)-btest
no-btest: PHONY
yes-btest: yes-fake miniruby$(EXEEXT) PHONY
@@ -878,7 +803,6 @@ yes-btest: yes-fake miniruby$(EXEEXT) PHONY
$(Q)$(gnumake_recursive)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY) $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(BTESTS)
$(ACTIONS_ENDGROUP)
-# runner: ruby, target: ruby
btest-ruby: $(TEST_RUNNABLE)-btest-ruby
no-btest-ruby: PHONY
yes-btest-ruby: prog PHONY
@@ -886,12 +810,6 @@ yes-btest-ruby: prog PHONY
$(Q)$(gnumake_recursive)$(exec) $(RUNRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(PROGRAM) -I$(srcdir)/lib $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(BTESTS)
$(ACTIONS_ENDGROUP)
-# runner: BASERUBY, target: ruby
-btest-bruby: prog PHONY
- $(ACTIONS_GROUP)
- $(Q)$(gnumake_recursive)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(PROGRAM) -I$(srcdir)/lib $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(BTESTS)
- $(ACTIONS_ENDGROUP)
-
rtest: yes-fake miniruby$(EXEEXT) PHONY
$(ACTIONS_GROUP)
$(Q)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY) $(RUN_OPTS)" --sets=ractor -v
@@ -930,15 +848,10 @@ test-sample: test-basic # backward compatibility for mswin-build
test-short: btest-ruby $(DOT_WAIT) test-knownbug $(DOT_WAIT) test-basic
test: test-short
-# Separate to skip updating encs and exts by `make -o test-precheck`
-# for GNU make.
-test-precheck: encs exts PHONY $(DOT_WAIT)
-yes-test-all-precheck: programs $(DOT_WAIT) test-precheck
-
# $ make test-all TESTOPTS="--help" displays more detail
# for example, make test-all TESTOPTS="-j2 -v -n test-name -- test-file-name"
test-all: $(TEST_RUNNABLE)-test-all
-yes-test-all: yes-test-all-precheck
+yes-test-all: programs PHONY
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TEST_EXCLUDES) $(TESTOPTS) $(TESTS)
$(ACTIONS_ENDGROUP)
@@ -980,14 +893,13 @@ $(RBCONFIG): $(tooldir)/mkconfig.rb config.status $(srcdir)/version.h $(srcdir)/
test-rubyspec: test-spec
yes-test-rubyspec: yes-test-spec
-yes-test-spec-precheck: yes-test-all-precheck yes-fake
+test-spec-precheck: programs yes-fake
test-spec: $(TEST_RUNNABLE)-test-spec
-yes-test-spec: yes-test-spec-precheck
+yes-test-spec: test-spec-precheck
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
- $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/rubyspec_temp \
- $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec $(MSPECOPT) $(SPECOPTS)
+ $(RUNRUBY) -r./$(arch)-fake $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec $(MSPECOPT) $(SPECOPTS)
$(ACTIONS_ENDGROUP)
no-test-spec:
@@ -1031,13 +943,18 @@ $(ENC_MK): $(srcdir)/enc/make_encmake.rb $(srcdir)/enc/Makefile.in $(srcdir)/enc
PHONY:
-{$(VPATH)}parse.c: {$(VPATH)}parse.y {$(VPATH)}id.h
+{$(VPATH)}parse.c: {$(VPATH)}parse.y $(tooldir)/ytab.sed {$(VPATH)}id.h
{$(VPATH)}parse.h: {$(VPATH)}parse.c
{$(srcdir)}.y.c:
$(ECHO) generating $@
- $(Q)$(BASERUBY) $(tooldir)/id2token.rb $(SRC_FILE) | \
- $(YACC) $(YFLAGS) -o$@ -H$*.h - parse.y
+ $(Q)$(BASERUBY) $(tooldir)/id2token.rb $(SRC_FILE) > parse.tmp.y
+ $(Q)$(YACC) -d $(YFLAGS) -o y.tab.c parse.tmp.y
+ $(Q)$(RM) parse.tmp.y
+ $(Q)sed -f $(tooldir)/ytab.sed -e "/^#/s|parse\.tmp\.[iy]|$(SRC_FILE)|" -e "/^#/s!y\.tab\.c!$@!" y.tab.c > $@.new
+ $(Q)$(MV) $@.new $@
+ $(Q)sed -e "/^#line.*y\.tab\.h/d;/^#line.*parse.*\.y/d" y.tab.h > $(@:.c=.h)
+ $(Q)$(RM) y.tab.c y.tab.h
$(PLATFORM_D):
$(Q) $(MAKEDIRS) $(PLATFORM_DIR) $(@D)
@@ -1122,7 +1039,7 @@ parse.$(OBJEXT): {$(VPATH)}parse.c
miniprelude.$(OBJEXT): {$(VPATH)}miniprelude.c
# dependencies for optional sources.
-compile.$(OBJEXT): {$(VPATH)}optunifs.inc
+compile.$(OBJEXT): {$(VPATH)}opt_sc.inc {$(VPATH)}optunifs.inc
win32/win32.$(OBJEXT): {$(VPATH)}win32/win32.c {$(VPATH)}win32/file.h \
{$(VPATH)}dln.h {$(VPATH)}dln_find.c {$(VPATH)}encindex.h \
@@ -1149,6 +1066,7 @@ INSNS2VMOPT = --srcdir="$(srcdir)"
srcs_vpath = {$(VPATH)}
inc_common_headers = $(tooldir)/ruby_vm/views/_copyright.erb $(tooldir)/ruby_vm/views/_notice.erb
+$(srcs_vpath)opt_sc.inc: $(tooldir)/ruby_vm/views/opt_sc.inc.erb $(inc_common_headers)
$(srcs_vpath)optinsn.inc: $(tooldir)/ruby_vm/views/optinsn.inc.erb $(inc_common_headers)
$(srcs_vpath)optunifs.inc: $(tooldir)/ruby_vm/views/optunifs.inc.erb $(inc_common_headers)
$(srcs_vpath)insns.inc: $(tooldir)/ruby_vm/views/insns.inc.erb $(inc_common_headers)
@@ -1160,6 +1078,7 @@ $(srcs_vpath)insns_info.inc: $(tooldir)/ruby_vm/views/insns_info.inc.erb $(inc_c
$(srcs_vpath)vmtc.inc: $(tooldir)/ruby_vm/views/vmtc.inc.erb $(inc_common_headers)
$(srcs_vpath)vm.inc: $(tooldir)/ruby_vm/views/vm.inc.erb $(inc_common_headers) \
$(tooldir)/ruby_vm/views/_insn_entry.erb $(tooldir)/ruby_vm/views/_trace_instruction.erb
+$(srcs_vpath)mjit_sp_inc.inc: $(tooldir)/ruby_vm/views/mjit_sp_inc.inc.erb
BUILTIN_RB_SRCS = \
$(srcdir)/ast.rb \
@@ -1168,8 +1087,8 @@ BUILTIN_RB_SRCS = \
$(srcdir)/numeric.rb \
$(srcdir)/io.rb \
$(srcdir)/marshal.rb \
- $(srcdir)/rjit.rb \
- $(srcdir)/rjit_c.rb \
+ $(srcdir)/mjit.rb \
+ $(srcdir)/mjit_c.rb \
$(srcdir)/pack.rb \
$(srcdir)/trace_point.rb \
$(srcdir)/warning.rb \
@@ -1192,16 +1111,9 @@ common-srcs: $(srcs_vpath)parse.c $(srcs_vpath)lex.c $(srcs_vpath)enc/trans/newl
missing-srcs: $(srcdir)/missing/des_tables.c
-srcs: common-srcs missing-srcs srcs-enc srcs-doc
-
-RIPPER_SRCS = $(srcdir)/ext/ripper/ripper.c \
- $(srcdir)/ext/ripper/ripper_init.c \
- $(srcdir)/ext/ripper/eventids1.h \
- $(srcdir)/ext/ripper/eventids1.c \
- $(srcdir)/ext/ripper/eventids2table.c \
- # RIPPER_SRCS
+srcs: common-srcs missing-srcs srcs-enc
-EXT_SRCS = ripper_srcs \
+EXT_SRCS = $(srcdir)/ext/ripper/ripper.c \
$(srcdir)/ext/rbconfig/sizeof/sizes.c \
$(srcdir)/ext/rbconfig/sizeof/limits.c \
$(srcdir)/ext/socket/constdefs.c \
@@ -1247,9 +1159,9 @@ id.c: $(tooldir)/generic_erb.rb $(srcdir)/template/id.c.tmpl $(srcdir)/defs/id.d
$(Q) $(BASERUBY) $(tooldir)/generic_erb.rb --output=$@ \
$(srcdir)/template/id.c.tmpl
-node_name.inc: $(tooldir)/node_name.rb $(srcdir)/rubyparser.h
+node_name.inc: $(tooldir)/node_name.rb $(srcdir)/node.h
$(ECHO) generating $@
- $(Q) $(BASERUBY) -n $(tooldir)/node_name.rb < $(srcdir)/rubyparser.h > $@
+ $(Q) $(BASERUBY) -n $(tooldir)/node_name.rb < $(srcdir)/node.h > $@
encdb.h: $(RBCONFIG) $(tooldir)/generic_erb.rb $(srcdir)/template/encdb.h.tmpl
$(ECHO) generating $@
@@ -1301,13 +1213,9 @@ preludes: {$(srcdir)}golf_prelude.c
$(ECHO) making $@
$(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $<
-$(BUILTIN_BINARY:yes=built)in_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.inc.tmpl
+builtin_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.inc.tmpl
$(Q) $(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ \
- $(srcdir)/template/builtin_binary.inc.tmpl
- -$(Q) sha256sum $@ 2> $(NULL) || $(NULLCMD)
-
-$(BUILTIN_BINARY:no=builtin)_binary.inc:
- $(Q) echo> $@ // empty $(@F)
+ $(srcdir)/template/builtin_binary.inc.tmpl -- --cross=$(CROSS_COMPILING)
$(BUILTIN_RB_INCS): $(top_srcdir)/tool/mk_builtin_loader.rb
@@ -1318,20 +1226,13 @@ $(REVISION_H)$(no_baseruby:no=~disabled~):
$(REVISION_H)$(yes_baseruby:yes=~disabled~):
$(Q) exit > $@
-# uncommon.mk: $(REVISION_H)
-# $(MKFILES): $(REVISION_H)
-
-ripper_srcs: $(RIPPER_SRCS)
-
-$(RIPPER_SRCS): $(srcdir)/parse.y $(srcdir)/defs/id.def
-$(RIPPER_SRCS): $(srcdir)/ext/ripper/tools/preproc.rb $(srcdir)/ext/ripper/tools/dsl.rb
-$(RIPPER_SRCS): $(srcdir)/ext/ripper/ripper_init.c.tmpl $(srcdir)/ext/ripper/eventids2.c
+$(srcdir)/ext/ripper/ripper.c: $(srcdir)/ext/ripper/tools/preproc.rb $(srcdir)/parse.y $(srcdir)/defs/id.def $(srcdir)/ext/ripper/depend
$(ECHO) generating $@
$(Q) $(CHDIR) $(@D) && \
$(CAT_DEPEND) depend | \
$(exec) $(MAKE) -f - $(mflags) \
- Q=$(Q) ECHO=$(ECHO) RM="$(RM1)" top_srcdir=../.. srcdir=. VPATH=../.. \
- RUBY="$(BASERUBY)" BASERUBY="$(BASERUBY)" PATH_SEPARATOR="$(PATH_SEPARATOR)" LANG=C
+ Q=$(Q) ECHO=$(ECHO) RM="$(RM1)" BISON="$(YACC)" top_srcdir=../.. srcdir=. VPATH=../.. \
+ RUBY="$(BASERUBY)" PATH_SEPARATOR="$(PATH_SEPARATOR)" LANG=C
$(srcdir)/ext/json/parser/parser.c: $(srcdir)/ext/json/parser/parser.rl $(srcdir)/ext/json/parser/prereq.mk
$(ECHO) generating $@
@@ -1421,10 +1322,9 @@ run.gdb:
echo ' quit' >> run.gdb
echo end >> run.gdb
-GDB = gdb
gdb: miniruby$(EXEEXT) run.gdb PHONY
- $(GDB) -x run.gdb --quiet --args $(MINIRUBY) $(RUNOPT0) $(TESTRUN_SCRIPT) $(RUNOPT)
+ gdb -x run.gdb --quiet --args $(MINIRUBY) $(RUNOPT0) $(TESTRUN_SCRIPT) $(RUNOPT)
gdb-ruby: $(PROGRAM) run.gdb PHONY
$(Q) $(RUNRUBY_COMMAND) $(RUNRUBY_DEBUGGER) -- $(RUNOPT0) $(TESTRUN_SCRIPT) $(RUNOPT)
@@ -1447,7 +1347,7 @@ dist:
up:: update-remote
-up$(DOT_WAIT)::
+up::
-$(Q)$(MAKE) $(mflags) Q=$(Q) REVISION_FORCE=PHONY ALWAYS_UPDATE_UNICODE= after-update
yes::
@@ -1474,10 +1374,6 @@ update-config_files: PHONY
$(Q) $(BASERUBY) -C "$(srcdir)" tool/downloader.rb -d tool --cache-dir=$(CACHE_DIR) -e gnu \
config.guess config.sub
-update-coverage: main PHONY
- $(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
- --install-dir .bundle --conservative "simplecov"
-
refresh-gems: update-bundled_gems prepare-gems
prepare-gems: $(HAVE_BASERUBY:yes=update-gems) $(HAVE_BASERUBY:yes=extract-gems)
extract-gems: $(HAVE_BASERUBY:yes=update-gems)
@@ -1504,28 +1400,14 @@ extract-gems$(gnumake:yes=-sequential): PHONY
-e 'gem, ver, _, rev = *$$F' \
-e 'next if !ver or /^#/=~gem' \
-e 'g = "#{gem}-#{ver}"' \
- -e 'unless File.directory?("#{d}/#{g}")' \
- -e 'if rev and File.exist?(gs = "gems/src/#{gem}/#{gem}.gemspec")' \
- -e 'BundledGem.build(gs, ver, "gems")' \
- -e 'end' \
+ -e 'if File.directory?("#{d}/#{g}")' \
+ -e 'elsif rev and File.exist?(gs = "gems/src/#{gem}/#{gem}.gemspec")' \
+ -e 'BundledGem.copy(gs, ".bundle")' \
+ -e 'else' \
-e 'BundledGem.unpack("gems/#{g}.gem", ".bundle")' \
-e 'end' \
gems/bundled_gems
-extract-gems$(gnumake:yes=-sequential): $(HAVE_GIT:yes=clone-bundled-gems-src)
-
-clone-bundled-gems-src: PHONY
- $(Q) $(BASERUBY) -C "$(srcdir)" \
- -Itool/lib -rbundled_gem -answ \
- -e 'BEGIN {git = $$git}' \
- -e 'gem, _, repo, rev = *$$F' \
- -e 'next if !rev or /^#/=~gem' \
- -e 'gemdir = "gems/src/#{gem}"' \
- -e 'BundledGem.checkout(gemdir, repo, rev, git: git)' \
- -e 'BundledGem.dummy_gemspec("#{gemdir}/#{gem}.gemspec")' \
- -- -git="$(GIT)" \
- gems/bundled_gems
-
outdate-bundled-gems: PHONY
$(Q) $(BASERUBY) $(tooldir)/$@.rb --make="$(MAKE)" --mflags="$(MFLAGS)" "$(srcdir)"
@@ -1555,7 +1437,7 @@ no-test-bundled-gems-prepare: no-test-bundled-gems-precheck
yes-test-bundled-gems-prepare: yes-test-bundled-gems-precheck
$(ACTIONS_GROUP)
$(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
- --install-dir .bundle --conservative "hoe" "json-schema" "test-unit-rr"
+ --install-dir .bundle --conservative "bundler" "minitest:~> 5" "test-unit" "rake" "hoe" "rexml" "json-schema:5.1.0" "test-unit-rr"
$(ACTIONS_ENDGROUP)
PREPARE_BUNDLED_GEMS = test-bundled-gems-prepare
@@ -1579,30 +1461,24 @@ no-test-syntax-suggest-prepare: no-test-syntax-suggest-precheck
yes-test-syntax-suggest-prepare: yes-test-syntax-suggest-precheck
$(ACTIONS_GROUP)
$(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
- --install-dir .bundle --conservative "rspec:~> 3"
+ --install-dir .bundle --conservative "bundler" "rake" "rspec:~> 3" #"ruby-prof"
$(ACTIONS_ENDGROUP)
RSPECOPTS =
SYNTAX_SUGGEST_SPECS =
-PREPARE_SYNTAX_SUGGEST = $(TEST_RUNNABLE)-test-syntax-suggest-prepare
+PREPARE_SYNTAX_SUGGEST = test-syntax-suggest-prepare
test-syntax-suggest: $(TEST_RUNNABLE)-test-syntax-suggest
-yes-test-syntax-suggest: $(PREPARE_SYNTAX_SUGGEST)
- $(ACTIONS_GROUP)
- $(XRUBY) -C $(srcdir) -Ispec/syntax_suggest:spec/lib .bundle/bin/rspec \
- --require rspec/expectations \
- --require spec_helper --require formatter_overrides --require spec_coverage \
- $(RSPECOPTS) spec/syntax_suggest/$(SYNTAX_SUGGEST_SPECS)
- $(ACTIONS_ENDGROUP)
+yes-test-syntax-suggest: yes-$(PREPARE_SYNTAX_SUGGEST)
+ $(XRUBY) -C $(srcdir) -Ispec/syntax_suggest .bundle/bin/rspec \
+ --require spec_helper $(RSPECOPTS) spec/syntax_suggest/$(SYNTAX_SUGGEST_SPECS)
no-test-syntax-suggest:
-check: $(DOT_WAIT) $(PREPARE_SYNTAX_SUGGEST) test-syntax-suggest
+check: $(DOT_WAIT) $(TEST_RUNNABLE)-$(PREPARE_SYNTAX_SUGGEST) test-syntax-suggest
test-bundler-precheck: $(TEST_RUNNABLE)-test-bundler-precheck
no-test-bundler-precheck:
yes-test-bundler-precheck: main $(arch)-fake.rb
-yes-test-bundler-parallel-precheck: yes-test-bundler-precheck
-test-bundler-prepare: $(TEST_RUNNABLE)-test-bundler-prepare
no-test-bundler-prepare: no-test-bundler-precheck
yes-test-bundler-prepare: yes-test-bundler-precheck
$(ACTIONS_GROUP)
@@ -1611,24 +1487,23 @@ yes-test-bundler-prepare: yes-test-bundler-precheck
-e 'ENV["BUNDLE_APP_CONFIG"] = File.expand_path(".bundle")' \
-e 'ENV["BUNDLE_PATH__SYSTEM"] = "true"' \
-e 'ENV["BUNDLE_WITHOUT"] = "lint doc"' \
- -e 'load "spec/bundler/support/bundle.rb"' -- install --quiet --gemfile=tool/bundler/dev_gems.rb
+ -e 'load "spec/bundler/support/bundle.rb"' -- install --gemfile=tool/bundler/dev_gems.rb
$(ACTIONS_ENDGROUP)
RSPECOPTS =
BUNDLER_SPECS =
-PREPARE_BUNDLER = $(TEST_RUNNABLE)-test-bundler-prepare
test-bundler: $(TEST_RUNNABLE)-test-bundler
-yes-test-bundler: $(PREPARE_BUNDLER)
+yes-test-bundler: yes-test-bundler-prepare
$(gnumake_recursive)$(XRUBY) \
-r./$(arch)-fake \
-e "exec(*ARGV)" -- \
- $(XRUBY) -C $(srcdir) -Ispec/bundler:spec/lib .bundle/bin/rspec \
- --require spec_helper --require formatter_overrides $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS)
+ $(XRUBY) -C $(srcdir) -Ispec/bundler .bundle/bin/rspec \
+ --require spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS)
no-test-bundler:
PARALLELRSPECOPTS = --runtime-log $(srcdir)/tmp/parallel_runtime_rspec.log
test-bundler-parallel: $(TEST_RUNNABLE)-test-bundler-parallel
-yes-test-bundler-parallel: $(PREPARE_BUNDLER)
+yes-test-bundler-parallel: yes-test-bundler-prepare
$(gnumake_recursive)$(XRUBY) \
-r./$(arch)-fake \
-e "ARGV[-1] = File.expand_path(ARGV[-1])" \
@@ -1636,9 +1511,9 @@ yes-test-bundler-parallel: $(PREPARE_BUNDLER)
$(XRUBY) -I$(srcdir)/spec/bundler \
-e "ENV['PARALLEL_TESTS_EXECUTABLE'] = ARGV.shift" \
-e "load ARGV.shift" \
- "$(XRUBY) -C $(srcdir) -Ispec/bundler:spec/lib .bundle/bin/rspec" \
+ "$(XRUBY) -C $(srcdir) -Ispec/bundler .bundle/bin/rspec" \
$(srcdir)/.bundle/bin/parallel_rspec \
- -o "--require spec_helper --require formatter_overrides" \
+ -o "--require spec_helper" \
$(PARALLELRSPECOPTS) $(srcdir)/spec/bundler/$(BUNDLER_SPECS)
no-test-bundler-parallel:
@@ -1788,16 +1663,6 @@ $(UNICODE_HDR_DIR)/name2ctype.h:
$(UNICODE_SRC_DATA_DIR) $(UNICODE_SRC_EMOJI_DATA_DIR) > $@.new
$(MV) $@.new $@
-srcs-doc: $(srcdir)/doc/regexp/unicode_properties.rdoc
-$(srcdir)/doc/regexp/$(ALWAYS_UPDATE_UNICODE:yes=unicode_properties.rdoc): \
- $(UNICODE_HDR_DIR)/name2ctype.h $(UNICODE_PROPERTY_FILES)
-
-$(srcdir)/doc/regexp/unicode_properties.rdoc:
- $(Q) $(BOOTSTRAPRUBY) $(tooldir)/generic_erb.rb -c -o $@ \
- $(srcdir)/template/unicode_properties.rdoc.tmpl \
- $(UNICODE_SRC_DATA_DIR) $(UNICODE_HDR_DIR)/name2ctype.h || \
- $(TOUCH) $@
-
# the next non-comment line was:
# $(UNICODE_HDR_DIR)/casefold.h: $(tooldir)/enc-case-folding.rb \
# but was changed to make sure CI works on systems that don't have gperf
@@ -1840,8 +1705,6 @@ info-arch: PHONY
@echo arch=$(arch)
exam: check
-exam: $(DOT_WAIT) test-bundler-parallel
-exam: $(DOT_WAIT) test-bundled-gems
love: sudo-precheck up all test exam install
@echo love is all you need
@@ -1863,7 +1726,7 @@ update-man-date: PHONY
ChangeLog:
$(ECHO) Generating $@
-$(Q) $(BASERUBY) -I"$(tooldir)/lib" -rvcs \
- -e 'VCS.detect(ARGV[0]).export_changelog(path: ARGV[1])' \
+ -e 'VCS.detect(ARGV[0]).export_changelog("@", nil, nil, ARGV[1])' \
"$(srcdir)" $@
HELP_EXTRA_TASKS = ""
@@ -1884,16 +1747,13 @@ help: PHONY
" runruby: runs test.rb by ruby you just built" \
" gdb: runs test.rb by miniruby under gdb" \
" gdb-ruby: runs test.rb by ruby under gdb" \
- " runirb: starts irb on built ruby (not installed ruby)" \
- " exam: equals make check test-bundler-parallel test-bundled-gems" \
- " check: equals make test test-tool test-all test-spec test-syntax-suggest" \
+ " check: equals make test test-tool test-all test-spec" \
" test: ruby core tests [BTESTS=<bootstraptest files>]" \
" test-all: all ruby tests [TESTOPTS=-j4 TESTS=<test files>]" \
" test-spec: run the Ruby spec suite [SPECOPTS=<specs, opts>]" \
" test-bundler: run the Bundler spec" \
" test-bundler-parallel: run the Bundler spec with parallel" \
- " test-syntax-suggest: run the SyntaxSuggest spec" \
- " test-bundled-gems: run the test suite of bundled gems [BUNDLED_GEMS=<gems>]" \
+ " test-bundled-gems: run the test suite of bundled gems" \
" test-tool: tests under the tool/test" \
" update-gems: download files of the bundled gems" \
" update-bundled_gems: update the latest version of bundled gems" \
@@ -1904,12 +1764,12 @@ help: PHONY
" install: install all ruby distributions" \
" install-nodoc: install without rdoc" \
" install-cross: install cross compiling stuff" \
- " clean: clean up to the state before build" \
- " distclean: clean up to the state before configure" \
+ " clean: clean for tarball" \
+ " distclean: clean for repository" \
" golf: build goruby for golfers" \
$(HELP_EXTRA_TASKS) \
"see DeveloperHowto for more detail: " \
- " https://github.com/ruby/ruby/wiki/Developer-How-To" \
+ " https://bugs.ruby-lang.org/projects/ruby/wiki/DeveloperHowto" \
$(MESSAGE_END)
$(CROSS_COMPILING:yes=)builtin.$(OBJEXT): {$(VPATH)}mini_builtin.c
@@ -1941,7 +1801,6 @@ addr2line.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -1971,10 +1830,6 @@ addr2line.$(OBJEXT): {$(VPATH)}internal/stdbool.h
addr2line.$(OBJEXT): {$(VPATH)}internal/warning_push.h
addr2line.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
addr2line.$(OBJEXT): {$(VPATH)}missing.h
-array.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-array.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-array.$(OBJEXT): $(CCAN_DIR)/list/list.h
-array.$(OBJEXT): $(CCAN_DIR)/str/str.h
array.$(OBJEXT): $(hdrdir)/ruby/ruby.h
array.$(OBJEXT): $(top_srcdir)/internal/array.h
array.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
@@ -1987,7 +1842,6 @@ array.$(OBJEXT): $(top_srcdir)/internal/enum.h
array.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
array.$(OBJEXT): $(top_srcdir)/internal/gc.h
array.$(OBJEXT): $(top_srcdir)/internal/hash.h
-array.$(OBJEXT): $(top_srcdir)/internal/imemo.h
array.$(OBJEXT): $(top_srcdir)/internal/numeric.h
array.$(OBJEXT): $(top_srcdir)/internal/object.h
array.$(OBJEXT): $(top_srcdir)/internal/proc.h
@@ -2000,7 +1854,6 @@ array.$(OBJEXT): $(top_srcdir)/internal/warnings.h
array.$(OBJEXT): {$(VPATH)}array.c
array.$(OBJEXT): {$(VPATH)}array.rbinc
array.$(OBJEXT): {$(VPATH)}assert.h
-array.$(OBJEXT): {$(VPATH)}atomic.h
array.$(OBJEXT): {$(VPATH)}backward/2/assume.h
array.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
array.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -2058,7 +1911,6 @@ array.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
array.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
array.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
array.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
array.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
array.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
array.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2127,6 +1979,7 @@ array.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
array.$(OBJEXT): {$(VPATH)}internal/intern/error.h
array.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
array.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
array.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
array.$(OBJEXT): {$(VPATH)}internal/intern/io.h
array.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2157,6 +2010,7 @@ array.$(OBJEXT): {$(VPATH)}internal/memory.h
array.$(OBJEXT): {$(VPATH)}internal/method.h
array.$(OBJEXT): {$(VPATH)}internal/module.h
array.$(OBJEXT): {$(VPATH)}internal/newobj.h
+array.$(OBJEXT): {$(VPATH)}internal/rgengc.h
array.$(OBJEXT): {$(VPATH)}internal/scan_args.h
array.$(OBJEXT): {$(VPATH)}internal/special_consts.h
array.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -2168,24 +2022,17 @@ array.$(OBJEXT): {$(VPATH)}internal/value_type.h
array.$(OBJEXT): {$(VPATH)}internal/variable.h
array.$(OBJEXT): {$(VPATH)}internal/warning_push.h
array.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-array.$(OBJEXT): {$(VPATH)}method.h
array.$(OBJEXT): {$(VPATH)}missing.h
-array.$(OBJEXT): {$(VPATH)}node.h
array.$(OBJEXT): {$(VPATH)}onigmo.h
array.$(OBJEXT): {$(VPATH)}oniguruma.h
array.$(OBJEXT): {$(VPATH)}probes.dmyh
array.$(OBJEXT): {$(VPATH)}probes.h
array.$(OBJEXT): {$(VPATH)}ruby_assert.h
-array.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-array.$(OBJEXT): {$(VPATH)}rubyparser.h
array.$(OBJEXT): {$(VPATH)}shape.h
array.$(OBJEXT): {$(VPATH)}st.h
array.$(OBJEXT): {$(VPATH)}subst.h
-array.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-array.$(OBJEXT): {$(VPATH)}thread_native.h
+array.$(OBJEXT): {$(VPATH)}transient_heap.h
array.$(OBJEXT): {$(VPATH)}util.h
-array.$(OBJEXT): {$(VPATH)}vm_core.h
-array.$(OBJEXT): {$(VPATH)}vm_opts.h
ast.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
ast.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
ast.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -2198,7 +2045,6 @@ ast.$(OBJEXT): $(top_srcdir)/internal/compilers.h
ast.$(OBJEXT): $(top_srcdir)/internal/gc.h
ast.$(OBJEXT): $(top_srcdir)/internal/imemo.h
ast.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ast.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
ast.$(OBJEXT): $(top_srcdir)/internal/serial.h
ast.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
ast.$(OBJEXT): $(top_srcdir)/internal/symbol.h
@@ -2265,7 +2111,6 @@ ast.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2334,6 +2179,7 @@ ast.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/error.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/io.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2364,6 +2210,7 @@ ast.$(OBJEXT): {$(VPATH)}internal/memory.h
ast.$(OBJEXT): {$(VPATH)}internal/method.h
ast.$(OBJEXT): {$(VPATH)}internal/module.h
ast.$(OBJEXT): {$(VPATH)}internal/newobj.h
+ast.$(OBJEXT): {$(VPATH)}internal/rgengc.h
ast.$(OBJEXT): {$(VPATH)}internal/scan_args.h
ast.$(OBJEXT): {$(VPATH)}internal/special_consts.h
ast.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -2383,7 +2230,6 @@ ast.$(OBJEXT): {$(VPATH)}onigmo.h
ast.$(OBJEXT): {$(VPATH)}oniguruma.h
ast.$(OBJEXT): {$(VPATH)}ruby_assert.h
ast.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-ast.$(OBJEXT): {$(VPATH)}rubyparser.h
ast.$(OBJEXT): {$(VPATH)}shape.h
ast.$(OBJEXT): {$(VPATH)}st.h
ast.$(OBJEXT): {$(VPATH)}subst.h
@@ -2392,13 +2238,7 @@ ast.$(OBJEXT): {$(VPATH)}thread_native.h
ast.$(OBJEXT): {$(VPATH)}util.h
ast.$(OBJEXT): {$(VPATH)}vm_core.h
ast.$(OBJEXT): {$(VPATH)}vm_opts.h
-bignum.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-bignum.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-bignum.$(OBJEXT): $(CCAN_DIR)/list/list.h
-bignum.$(OBJEXT): $(CCAN_DIR)/str/str.h
bignum.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/array.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
bignum.$(OBJEXT): $(top_srcdir)/internal/bignum.h
bignum.$(OBJEXT): $(top_srcdir)/internal/bits.h
bignum.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -2406,7 +2246,6 @@ bignum.$(OBJEXT): $(top_srcdir)/internal/compilers.h
bignum.$(OBJEXT): $(top_srcdir)/internal/complex.h
bignum.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
bignum.$(OBJEXT): $(top_srcdir)/internal/gc.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/imemo.h
bignum.$(OBJEXT): $(top_srcdir)/internal/numeric.h
bignum.$(OBJEXT): $(top_srcdir)/internal/object.h
bignum.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -2416,7 +2255,6 @@ bignum.$(OBJEXT): $(top_srcdir)/internal/variable.h
bignum.$(OBJEXT): $(top_srcdir)/internal/vm.h
bignum.$(OBJEXT): $(top_srcdir)/internal/warnings.h
bignum.$(OBJEXT): {$(VPATH)}assert.h
-bignum.$(OBJEXT): {$(VPATH)}atomic.h
bignum.$(OBJEXT): {$(VPATH)}backward/2/assume.h
bignum.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
bignum.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -2430,7 +2268,6 @@ bignum.$(OBJEXT): {$(VPATH)}bignum.c
bignum.$(OBJEXT): {$(VPATH)}config.h
bignum.$(OBJEXT): {$(VPATH)}constant.h
bignum.$(OBJEXT): {$(VPATH)}defines.h
-bignum.$(OBJEXT): {$(VPATH)}encoding.h
bignum.$(OBJEXT): {$(VPATH)}id.h
bignum.$(OBJEXT): {$(VPATH)}id_table.h
bignum.$(OBJEXT): {$(VPATH)}intern.h
@@ -2473,7 +2310,6 @@ bignum.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2506,15 +2342,6 @@ bignum.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
bignum.$(OBJEXT): {$(VPATH)}internal/ctype.h
bignum.$(OBJEXT): {$(VPATH)}internal/dllexport.h
bignum.$(OBJEXT): {$(VPATH)}internal/dosish.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
bignum.$(OBJEXT): {$(VPATH)}internal/error.h
bignum.$(OBJEXT): {$(VPATH)}internal/eval.h
bignum.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -2542,6 +2369,7 @@ bignum.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/error.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2572,6 +2400,7 @@ bignum.$(OBJEXT): {$(VPATH)}internal/memory.h
bignum.$(OBJEXT): {$(VPATH)}internal/method.h
bignum.$(OBJEXT): {$(VPATH)}internal/module.h
bignum.$(OBJEXT): {$(VPATH)}internal/newobj.h
+bignum.$(OBJEXT): {$(VPATH)}internal/rgengc.h
bignum.$(OBJEXT): {$(VPATH)}internal/scan_args.h
bignum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
bignum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -2583,23 +2412,13 @@ bignum.$(OBJEXT): {$(VPATH)}internal/value_type.h
bignum.$(OBJEXT): {$(VPATH)}internal/variable.h
bignum.$(OBJEXT): {$(VPATH)}internal/warning_push.h
bignum.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-bignum.$(OBJEXT): {$(VPATH)}method.h
bignum.$(OBJEXT): {$(VPATH)}missing.h
-bignum.$(OBJEXT): {$(VPATH)}node.h
-bignum.$(OBJEXT): {$(VPATH)}onigmo.h
-bignum.$(OBJEXT): {$(VPATH)}oniguruma.h
bignum.$(OBJEXT): {$(VPATH)}ruby_assert.h
-bignum.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-bignum.$(OBJEXT): {$(VPATH)}rubyparser.h
bignum.$(OBJEXT): {$(VPATH)}shape.h
bignum.$(OBJEXT): {$(VPATH)}st.h
bignum.$(OBJEXT): {$(VPATH)}subst.h
bignum.$(OBJEXT): {$(VPATH)}thread.h
-bignum.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-bignum.$(OBJEXT): {$(VPATH)}thread_native.h
bignum.$(OBJEXT): {$(VPATH)}util.h
-bignum.$(OBJEXT): {$(VPATH)}vm_core.h
-bignum.$(OBJEXT): {$(VPATH)}vm_opts.h
builtin.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
builtin.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
builtin.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -2632,7 +2451,6 @@ builtin.$(OBJEXT): {$(VPATH)}builtin_binary.inc
builtin.$(OBJEXT): {$(VPATH)}config.h
builtin.$(OBJEXT): {$(VPATH)}constant.h
builtin.$(OBJEXT): {$(VPATH)}defines.h
-builtin.$(OBJEXT): {$(VPATH)}encoding.h
builtin.$(OBJEXT): {$(VPATH)}id.h
builtin.$(OBJEXT): {$(VPATH)}id_table.h
builtin.$(OBJEXT): {$(VPATH)}intern.h
@@ -2675,7 +2493,6 @@ builtin.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2708,15 +2525,6 @@ builtin.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
builtin.$(OBJEXT): {$(VPATH)}internal/ctype.h
builtin.$(OBJEXT): {$(VPATH)}internal/dllexport.h
builtin.$(OBJEXT): {$(VPATH)}internal/dosish.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
builtin.$(OBJEXT): {$(VPATH)}internal/error.h
builtin.$(OBJEXT): {$(VPATH)}internal/eval.h
builtin.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -2744,6 +2552,7 @@ builtin.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/error.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/io.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2774,6 +2583,7 @@ builtin.$(OBJEXT): {$(VPATH)}internal/memory.h
builtin.$(OBJEXT): {$(VPATH)}internal/method.h
builtin.$(OBJEXT): {$(VPATH)}internal/module.h
builtin.$(OBJEXT): {$(VPATH)}internal/newobj.h
+builtin.$(OBJEXT): {$(VPATH)}internal/rgengc.h
builtin.$(OBJEXT): {$(VPATH)}internal/scan_args.h
builtin.$(OBJEXT): {$(VPATH)}internal/special_consts.h
builtin.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -2789,11 +2599,8 @@ builtin.$(OBJEXT): {$(VPATH)}iseq.h
builtin.$(OBJEXT): {$(VPATH)}method.h
builtin.$(OBJEXT): {$(VPATH)}missing.h
builtin.$(OBJEXT): {$(VPATH)}node.h
-builtin.$(OBJEXT): {$(VPATH)}onigmo.h
-builtin.$(OBJEXT): {$(VPATH)}oniguruma.h
builtin.$(OBJEXT): {$(VPATH)}ruby_assert.h
builtin.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-builtin.$(OBJEXT): {$(VPATH)}rubyparser.h
builtin.$(OBJEXT): {$(VPATH)}shape.h
builtin.$(OBJEXT): {$(VPATH)}st.h
builtin.$(OBJEXT): {$(VPATH)}subst.h
@@ -2880,7 +2687,6 @@ class.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
class.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
class.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
class.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
class.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
class.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
class.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2949,6 +2755,7 @@ class.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
class.$(OBJEXT): {$(VPATH)}internal/intern/error.h
class.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
class.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
class.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
class.$(OBJEXT): {$(VPATH)}internal/intern/io.h
class.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2979,6 +2786,7 @@ class.$(OBJEXT): {$(VPATH)}internal/memory.h
class.$(OBJEXT): {$(VPATH)}internal/method.h
class.$(OBJEXT): {$(VPATH)}internal/module.h
class.$(OBJEXT): {$(VPATH)}internal/newobj.h
+class.$(OBJEXT): {$(VPATH)}internal/rgengc.h
class.$(OBJEXT): {$(VPATH)}internal/scan_args.h
class.$(OBJEXT): {$(VPATH)}internal/special_consts.h
class.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -2997,7 +2805,6 @@ class.$(OBJEXT): {$(VPATH)}onigmo.h
class.$(OBJEXT): {$(VPATH)}oniguruma.h
class.$(OBJEXT): {$(VPATH)}ruby_assert.h
class.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-class.$(OBJEXT): {$(VPATH)}rubyparser.h
class.$(OBJEXT): {$(VPATH)}shape.h
class.$(OBJEXT): {$(VPATH)}st.h
class.$(OBJEXT): {$(VPATH)}subst.h
@@ -3069,7 +2876,6 @@ compar.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3138,6 +2944,7 @@ compar.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/error.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/io.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3168,6 +2975,7 @@ compar.$(OBJEXT): {$(VPATH)}internal/memory.h
compar.$(OBJEXT): {$(VPATH)}internal/method.h
compar.$(OBJEXT): {$(VPATH)}internal/module.h
compar.$(OBJEXT): {$(VPATH)}internal/newobj.h
+compar.$(OBJEXT): {$(VPATH)}internal/rgengc.h
compar.$(OBJEXT): {$(VPATH)}internal/scan_args.h
compar.$(OBJEXT): {$(VPATH)}internal/special_consts.h
compar.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -3215,28 +3023,6 @@ compile.$(OBJEXT): $(top_srcdir)/internal/thread.h
compile.$(OBJEXT): $(top_srcdir)/internal/variable.h
compile.$(OBJEXT): $(top_srcdir)/internal/vm.h
compile.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-compile.$(OBJEXT): $(top_srcdir)/prism/defines.h
-compile.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-compile.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-compile.$(OBJEXT): $(top_srcdir)/prism/node.h
-compile.$(OBJEXT): $(top_srcdir)/prism/options.h
-compile.$(OBJEXT): $(top_srcdir)/prism/pack.h
-compile.$(OBJEXT): $(top_srcdir)/prism/parser.h
-compile.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-compile.$(OBJEXT): $(top_srcdir)/prism/prism.h
-compile.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-compile.$(OBJEXT): $(top_srcdir)/prism_compile.c
compile.$(OBJEXT): {$(VPATH)}assert.h
compile.$(OBJEXT): {$(VPATH)}atomic.h
compile.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -3256,6 +3042,7 @@ compile.$(OBJEXT): {$(VPATH)}debug_counter.h
compile.$(OBJEXT): {$(VPATH)}defines.h
compile.$(OBJEXT): {$(VPATH)}encindex.h
compile.$(OBJEXT): {$(VPATH)}encoding.h
+compile.$(OBJEXT): {$(VPATH)}gc.h
compile.$(OBJEXT): {$(VPATH)}id.h
compile.$(OBJEXT): {$(VPATH)}id_table.h
compile.$(OBJEXT): {$(VPATH)}insns.def
@@ -3301,7 +3088,6 @@ compile.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3371,6 +3157,7 @@ compile.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/error.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/io.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3401,6 +3188,7 @@ compile.$(OBJEXT): {$(VPATH)}internal/memory.h
compile.$(OBJEXT): {$(VPATH)}internal/method.h
compile.$(OBJEXT): {$(VPATH)}internal/module.h
compile.$(OBJEXT): {$(VPATH)}internal/newobj.h
+compile.$(OBJEXT): {$(VPATH)}internal/rgengc.h
compile.$(OBJEXT): {$(VPATH)}internal/scan_args.h
compile.$(OBJEXT): {$(VPATH)}internal/special_consts.h
compile.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -3419,16 +3207,10 @@ compile.$(OBJEXT): {$(VPATH)}node.h
compile.$(OBJEXT): {$(VPATH)}onigmo.h
compile.$(OBJEXT): {$(VPATH)}oniguruma.h
compile.$(OBJEXT): {$(VPATH)}optinsn.inc
-compile.$(OBJEXT): {$(VPATH)}prism/ast.h
-compile.$(OBJEXT): {$(VPATH)}prism/prism.h
-compile.$(OBJEXT): {$(VPATH)}prism/version.h
-compile.$(OBJEXT): {$(VPATH)}prism_compile.c
-compile.$(OBJEXT): {$(VPATH)}prism_compile.h
compile.$(OBJEXT): {$(VPATH)}re.h
compile.$(OBJEXT): {$(VPATH)}regex.h
compile.$(OBJEXT): {$(VPATH)}ruby_assert.h
compile.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-compile.$(OBJEXT): {$(VPATH)}rubyparser.h
compile.$(OBJEXT): {$(VPATH)}shape.h
compile.$(OBJEXT): {$(VPATH)}st.h
compile.$(OBJEXT): {$(VPATH)}subst.h
@@ -3439,7 +3221,6 @@ compile.$(OBJEXT): {$(VPATH)}vm_callinfo.h
compile.$(OBJEXT): {$(VPATH)}vm_core.h
compile.$(OBJEXT): {$(VPATH)}vm_debug.h
compile.$(OBJEXT): {$(VPATH)}vm_opts.h
-compile.$(OBJEXT): {$(VPATH)}yjit.h
complex.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
complex.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
complex.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -3479,7 +3260,6 @@ complex.$(OBJEXT): {$(VPATH)}complex.c
complex.$(OBJEXT): {$(VPATH)}config.h
complex.$(OBJEXT): {$(VPATH)}constant.h
complex.$(OBJEXT): {$(VPATH)}defines.h
-complex.$(OBJEXT): {$(VPATH)}encoding.h
complex.$(OBJEXT): {$(VPATH)}id.h
complex.$(OBJEXT): {$(VPATH)}id_table.h
complex.$(OBJEXT): {$(VPATH)}intern.h
@@ -3522,7 +3302,6 @@ complex.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3555,15 +3334,6 @@ complex.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
complex.$(OBJEXT): {$(VPATH)}internal/ctype.h
complex.$(OBJEXT): {$(VPATH)}internal/dllexport.h
complex.$(OBJEXT): {$(VPATH)}internal/dosish.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
complex.$(OBJEXT): {$(VPATH)}internal/error.h
complex.$(OBJEXT): {$(VPATH)}internal/eval.h
complex.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -3591,6 +3361,7 @@ complex.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/error.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/io.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3621,6 +3392,7 @@ complex.$(OBJEXT): {$(VPATH)}internal/memory.h
complex.$(OBJEXT): {$(VPATH)}internal/method.h
complex.$(OBJEXT): {$(VPATH)}internal/module.h
complex.$(OBJEXT): {$(VPATH)}internal/newobj.h
+complex.$(OBJEXT): {$(VPATH)}internal/rgengc.h
complex.$(OBJEXT): {$(VPATH)}internal/scan_args.h
complex.$(OBJEXT): {$(VPATH)}internal/special_consts.h
complex.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -3635,11 +3407,8 @@ complex.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
complex.$(OBJEXT): {$(VPATH)}method.h
complex.$(OBJEXT): {$(VPATH)}missing.h
complex.$(OBJEXT): {$(VPATH)}node.h
-complex.$(OBJEXT): {$(VPATH)}onigmo.h
-complex.$(OBJEXT): {$(VPATH)}oniguruma.h
complex.$(OBJEXT): {$(VPATH)}ruby_assert.h
complex.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-complex.$(OBJEXT): {$(VPATH)}rubyparser.h
complex.$(OBJEXT): {$(VPATH)}shape.h
complex.$(OBJEXT): {$(VPATH)}st.h
complex.$(OBJEXT): {$(VPATH)}subst.h
@@ -3665,7 +3434,6 @@ cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
cont.$(OBJEXT): $(top_srcdir)/internal/serial.h
cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
cont.$(OBJEXT): $(top_srcdir)/internal/string.h
-cont.$(OBJEXT): $(top_srcdir)/internal/thread.h
cont.$(OBJEXT): $(top_srcdir)/internal/variable.h
cont.$(OBJEXT): $(top_srcdir)/internal/vm.h
cont.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -3689,6 +3457,7 @@ cont.$(OBJEXT): {$(VPATH)}defines.h
cont.$(OBJEXT): {$(VPATH)}encoding.h
cont.$(OBJEXT): {$(VPATH)}eval_intern.h
cont.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+cont.$(OBJEXT): {$(VPATH)}gc.h
cont.$(OBJEXT): {$(VPATH)}id.h
cont.$(OBJEXT): {$(VPATH)}id_table.h
cont.$(OBJEXT): {$(VPATH)}intern.h
@@ -3731,7 +3500,6 @@ cont.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3800,6 +3568,7 @@ cont.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/error.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/io.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3830,6 +3599,7 @@ cont.$(OBJEXT): {$(VPATH)}internal/memory.h
cont.$(OBJEXT): {$(VPATH)}internal/method.h
cont.$(OBJEXT): {$(VPATH)}internal/module.h
cont.$(OBJEXT): {$(VPATH)}internal/newobj.h
+cont.$(OBJEXT): {$(VPATH)}internal/rgengc.h
cont.$(OBJEXT): {$(VPATH)}internal/scan_args.h
cont.$(OBJEXT): {$(VPATH)}internal/special_consts.h
cont.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -3844,15 +3614,14 @@ cont.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
cont.$(OBJEXT): {$(VPATH)}iseq.h
cont.$(OBJEXT): {$(VPATH)}method.h
cont.$(OBJEXT): {$(VPATH)}missing.h
+cont.$(OBJEXT): {$(VPATH)}mjit.h
cont.$(OBJEXT): {$(VPATH)}node.h
cont.$(OBJEXT): {$(VPATH)}onigmo.h
cont.$(OBJEXT): {$(VPATH)}oniguruma.h
cont.$(OBJEXT): {$(VPATH)}ractor.h
cont.$(OBJEXT): {$(VPATH)}ractor_core.h
-cont.$(OBJEXT): {$(VPATH)}rjit.h
cont.$(OBJEXT): {$(VPATH)}ruby_assert.h
cont.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-cont.$(OBJEXT): {$(VPATH)}rubyparser.h
cont.$(OBJEXT): {$(VPATH)}shape.h
cont.$(OBJEXT): {$(VPATH)}st.h
cont.$(OBJEXT): {$(VPATH)}subst.h
@@ -3899,6 +3668,7 @@ debug.$(OBJEXT): {$(VPATH)}defines.h
debug.$(OBJEXT): {$(VPATH)}encindex.h
debug.$(OBJEXT): {$(VPATH)}encoding.h
debug.$(OBJEXT): {$(VPATH)}eval_intern.h
+debug.$(OBJEXT): {$(VPATH)}gc.h
debug.$(OBJEXT): {$(VPATH)}id.h
debug.$(OBJEXT): {$(VPATH)}id_table.h
debug.$(OBJEXT): {$(VPATH)}intern.h
@@ -3941,7 +3711,6 @@ debug.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4010,6 +3779,7 @@ debug.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/error.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/io.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4040,6 +3810,7 @@ debug.$(OBJEXT): {$(VPATH)}internal/memory.h
debug.$(OBJEXT): {$(VPATH)}internal/method.h
debug.$(OBJEXT): {$(VPATH)}internal/module.h
debug.$(OBJEXT): {$(VPATH)}internal/newobj.h
+debug.$(OBJEXT): {$(VPATH)}internal/rgengc.h
debug.$(OBJEXT): {$(VPATH)}internal/scan_args.h
debug.$(OBJEXT): {$(VPATH)}internal/special_consts.h
debug.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -4061,7 +3832,6 @@ debug.$(OBJEXT): {$(VPATH)}ractor.h
debug.$(OBJEXT): {$(VPATH)}ractor_core.h
debug.$(OBJEXT): {$(VPATH)}ruby_assert.h
debug.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-debug.$(OBJEXT): {$(VPATH)}rubyparser.h
debug.$(OBJEXT): {$(VPATH)}shape.h
debug.$(OBJEXT): {$(VPATH)}st.h
debug.$(OBJEXT): {$(VPATH)}subst.h
@@ -4127,7 +3897,6 @@ debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4187,6 +3956,7 @@ debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/error.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/io.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4217,6 +3987,7 @@ debug_counter.$(OBJEXT): {$(VPATH)}internal/memory.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/method.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/module.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/newobj.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/rgengc.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/scan_args.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/special_consts.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -4232,13 +4003,8 @@ debug_counter.$(OBJEXT): {$(VPATH)}missing.h
debug_counter.$(OBJEXT): {$(VPATH)}st.h
debug_counter.$(OBJEXT): {$(VPATH)}subst.h
debug_counter.$(OBJEXT): {$(VPATH)}thread_native.h
-dir.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-dir.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-dir.$(OBJEXT): $(CCAN_DIR)/list/list.h
-dir.$(OBJEXT): $(CCAN_DIR)/str/str.h
dir.$(OBJEXT): $(hdrdir)/ruby/ruby.h
dir.$(OBJEXT): $(top_srcdir)/internal/array.h
-dir.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
dir.$(OBJEXT): $(top_srcdir)/internal/class.h
dir.$(OBJEXT): $(top_srcdir)/internal/compilers.h
dir.$(OBJEXT): $(top_srcdir)/internal/dir.h
@@ -4246,7 +4012,6 @@ dir.$(OBJEXT): $(top_srcdir)/internal/encoding.h
dir.$(OBJEXT): $(top_srcdir)/internal/error.h
dir.$(OBJEXT): $(top_srcdir)/internal/file.h
dir.$(OBJEXT): $(top_srcdir)/internal/gc.h
-dir.$(OBJEXT): $(top_srcdir)/internal/imemo.h
dir.$(OBJEXT): $(top_srcdir)/internal/io.h
dir.$(OBJEXT): $(top_srcdir)/internal/object.h
dir.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -4256,7 +4021,6 @@ dir.$(OBJEXT): $(top_srcdir)/internal/variable.h
dir.$(OBJEXT): $(top_srcdir)/internal/vm.h
dir.$(OBJEXT): $(top_srcdir)/internal/warnings.h
dir.$(OBJEXT): {$(VPATH)}assert.h
-dir.$(OBJEXT): {$(VPATH)}atomic.h
dir.$(OBJEXT): {$(VPATH)}backward/2/assume.h
dir.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
dir.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -4316,7 +4080,6 @@ dir.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4385,6 +4148,7 @@ dir.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4415,6 +4179,7 @@ dir.$(OBJEXT): {$(VPATH)}internal/memory.h
dir.$(OBJEXT): {$(VPATH)}internal/method.h
dir.$(OBJEXT): {$(VPATH)}internal/module.h
dir.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dir.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dir.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dir.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dir.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -4427,23 +4192,14 @@ dir.$(OBJEXT): {$(VPATH)}internal/variable.h
dir.$(OBJEXT): {$(VPATH)}internal/warning_push.h
dir.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
dir.$(OBJEXT): {$(VPATH)}io.h
-dir.$(OBJEXT): {$(VPATH)}method.h
dir.$(OBJEXT): {$(VPATH)}missing.h
-dir.$(OBJEXT): {$(VPATH)}node.h
dir.$(OBJEXT): {$(VPATH)}onigmo.h
dir.$(OBJEXT): {$(VPATH)}oniguruma.h
-dir.$(OBJEXT): {$(VPATH)}ruby_assert.h
-dir.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-dir.$(OBJEXT): {$(VPATH)}rubyparser.h
dir.$(OBJEXT): {$(VPATH)}shape.h
dir.$(OBJEXT): {$(VPATH)}st.h
dir.$(OBJEXT): {$(VPATH)}subst.h
dir.$(OBJEXT): {$(VPATH)}thread.h
-dir.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-dir.$(OBJEXT): {$(VPATH)}thread_native.h
dir.$(OBJEXT): {$(VPATH)}util.h
-dir.$(OBJEXT): {$(VPATH)}vm_core.h
-dir.$(OBJEXT): {$(VPATH)}vm_opts.h
dln.$(OBJEXT): $(hdrdir)/ruby/ruby.h
dln.$(OBJEXT): $(top_srcdir)/internal/compilers.h
dln.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -4501,7 +4257,6 @@ dln.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4561,6 +4316,7 @@ dln.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4591,6 +4347,7 @@ dln.$(OBJEXT): {$(VPATH)}internal/memory.h
dln.$(OBJEXT): {$(VPATH)}internal/method.h
dln.$(OBJEXT): {$(VPATH)}internal/module.h
dln.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dln.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dln.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -4658,7 +4415,6 @@ dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4718,6 +4474,7 @@ dln_find.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4748,6 +4505,7 @@ dln_find.$(OBJEXT): {$(VPATH)}internal/memory.h
dln_find.$(OBJEXT): {$(VPATH)}internal/method.h
dln_find.$(OBJEXT): {$(VPATH)}internal/module.h
dln_find.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dln_find.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dln_find.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dln_find.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -4814,7 +4572,6 @@ dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4874,6 +4631,7 @@ dmydln.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4904,6 +4662,7 @@ dmydln.$(OBJEXT): {$(VPATH)}internal/memory.h
dmydln.$(OBJEXT): {$(VPATH)}internal/method.h
dmydln.$(OBJEXT): {$(VPATH)}internal/module.h
dmydln.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dmydln.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dmydln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dmydln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5041,6 +4800,7 @@ enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5071,6 +4831,7 @@ enc/ascii.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/method.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/module.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5198,6 +4959,7 @@ enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5228,6 +4990,7 @@ enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/method.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/module.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5355,6 +5118,7 @@ enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5385,6 +5149,7 @@ enc/unicode.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/method.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/module.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5523,6 +5288,7 @@ enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5553,6 +5319,7 @@ enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/method.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/module.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5691,6 +5458,7 @@ enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5721,6 +5489,7 @@ enc/utf_8.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/method.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/module.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5813,7 +5582,6 @@ encoding.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -5882,6 +5650,7 @@ encoding.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/error.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/io.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5912,6 +5681,7 @@ encoding.$(OBJEXT): {$(VPATH)}internal/memory.h
encoding.$(OBJEXT): {$(VPATH)}internal/method.h
encoding.$(OBJEXT): {$(VPATH)}internal/module.h
encoding.$(OBJEXT): {$(VPATH)}internal/newobj.h
+encoding.$(OBJEXT): {$(VPATH)}internal/rgengc.h
encoding.$(OBJEXT): {$(VPATH)}internal/scan_args.h
encoding.$(OBJEXT): {$(VPATH)}internal/special_consts.h
encoding.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -6014,7 +5784,6 @@ enum.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6083,6 +5852,7 @@ enum.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6113,6 +5883,7 @@ enum.$(OBJEXT): {$(VPATH)}internal/memory.h
enum.$(OBJEXT): {$(VPATH)}internal/method.h
enum.$(OBJEXT): {$(VPATH)}internal/module.h
enum.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enum.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enum.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -6157,7 +5928,6 @@ enumerator.$(OBJEXT): $(top_srcdir)/internal/serial.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/string.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/struct.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/variable.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/vm.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/warnings.h
enumerator.$(OBJEXT): {$(VPATH)}assert.h
@@ -6172,7 +5942,6 @@ enumerator.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
enumerator.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
enumerator.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
enumerator.$(OBJEXT): {$(VPATH)}config.h
-enumerator.$(OBJEXT): {$(VPATH)}constant.h
enumerator.$(OBJEXT): {$(VPATH)}defines.h
enumerator.$(OBJEXT): {$(VPATH)}encoding.h
enumerator.$(OBJEXT): {$(VPATH)}enumerator.c
@@ -6218,7 +5987,6 @@ enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6287,6 +6055,7 @@ enumerator.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6317,6 +6086,7 @@ enumerator.$(OBJEXT): {$(VPATH)}internal/memory.h
enumerator.$(OBJEXT): {$(VPATH)}internal/method.h
enumerator.$(OBJEXT): {$(VPATH)}internal/module.h
enumerator.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enumerator.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enumerator.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enumerator.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -6335,7 +6105,6 @@ enumerator.$(OBJEXT): {$(VPATH)}onigmo.h
enumerator.$(OBJEXT): {$(VPATH)}oniguruma.h
enumerator.$(OBJEXT): {$(VPATH)}ruby_assert.h
enumerator.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-enumerator.$(OBJEXT): {$(VPATH)}rubyparser.h
enumerator.$(OBJEXT): {$(VPATH)}shape.h
enumerator.$(OBJEXT): {$(VPATH)}st.h
enumerator.$(OBJEXT): {$(VPATH)}subst.h
@@ -6360,7 +6129,6 @@ error.$(OBJEXT): $(top_srcdir)/internal/imemo.h
error.$(OBJEXT): $(top_srcdir)/internal/io.h
error.$(OBJEXT): $(top_srcdir)/internal/load.h
error.$(OBJEXT): $(top_srcdir)/internal/object.h
-error.$(OBJEXT): $(top_srcdir)/internal/process.h
error.$(OBJEXT): $(top_srcdir)/internal/serial.h
error.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
error.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -6428,7 +6196,6 @@ error.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
error.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
error.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
error.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
error.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
error.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
error.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6497,6 +6264,7 @@ error.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
error.$(OBJEXT): {$(VPATH)}internal/intern/error.h
error.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
error.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
error.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
error.$(OBJEXT): {$(VPATH)}internal/intern/io.h
error.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6527,6 +6295,7 @@ error.$(OBJEXT): {$(VPATH)}internal/memory.h
error.$(OBJEXT): {$(VPATH)}internal/method.h
error.$(OBJEXT): {$(VPATH)}internal/module.h
error.$(OBJEXT): {$(VPATH)}internal/newobj.h
+error.$(OBJEXT): {$(VPATH)}internal/rgengc.h
error.$(OBJEXT): {$(VPATH)}internal/scan_args.h
error.$(OBJEXT): {$(VPATH)}internal/special_consts.h
error.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -6547,13 +6316,11 @@ error.$(OBJEXT): {$(VPATH)}onigmo.h
error.$(OBJEXT): {$(VPATH)}oniguruma.h
error.$(OBJEXT): {$(VPATH)}ruby_assert.h
error.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-error.$(OBJEXT): {$(VPATH)}rubyparser.h
error.$(OBJEXT): {$(VPATH)}shape.h
error.$(OBJEXT): {$(VPATH)}st.h
error.$(OBJEXT): {$(VPATH)}subst.h
error.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
error.$(OBJEXT): {$(VPATH)}thread_native.h
-error.$(OBJEXT): {$(VPATH)}util.h
error.$(OBJEXT): {$(VPATH)}vm_core.h
error.$(OBJEXT): {$(VPATH)}vm_opts.h
error.$(OBJEXT): {$(VPATH)}warning.rbinc
@@ -6604,6 +6371,7 @@ eval.$(OBJEXT): {$(VPATH)}eval_error.c
eval.$(OBJEXT): {$(VPATH)}eval_intern.h
eval.$(OBJEXT): {$(VPATH)}eval_jump.c
eval.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+eval.$(OBJEXT): {$(VPATH)}gc.h
eval.$(OBJEXT): {$(VPATH)}id.h
eval.$(OBJEXT): {$(VPATH)}id_table.h
eval.$(OBJEXT): {$(VPATH)}intern.h
@@ -6646,7 +6414,6 @@ eval.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6715,6 +6482,7 @@ eval.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/error.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/io.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6745,6 +6513,7 @@ eval.$(OBJEXT): {$(VPATH)}internal/memory.h
eval.$(OBJEXT): {$(VPATH)}internal/method.h
eval.$(OBJEXT): {$(VPATH)}internal/module.h
eval.$(OBJEXT): {$(VPATH)}internal/newobj.h
+eval.$(OBJEXT): {$(VPATH)}internal/rgengc.h
eval.$(OBJEXT): {$(VPATH)}internal/scan_args.h
eval.$(OBJEXT): {$(VPATH)}internal/special_consts.h
eval.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -6760,6 +6529,7 @@ eval.$(OBJEXT): {$(VPATH)}io.h
eval.$(OBJEXT): {$(VPATH)}iseq.h
eval.$(OBJEXT): {$(VPATH)}method.h
eval.$(OBJEXT): {$(VPATH)}missing.h
+eval.$(OBJEXT): {$(VPATH)}mjit.h
eval.$(OBJEXT): {$(VPATH)}node.h
eval.$(OBJEXT): {$(VPATH)}onigmo.h
eval.$(OBJEXT): {$(VPATH)}oniguruma.h
@@ -6768,10 +6538,8 @@ eval.$(OBJEXT): {$(VPATH)}probes.h
eval.$(OBJEXT): {$(VPATH)}probes_helper.h
eval.$(OBJEXT): {$(VPATH)}ractor.h
eval.$(OBJEXT): {$(VPATH)}ractor_core.h
-eval.$(OBJEXT): {$(VPATH)}rjit.h
eval.$(OBJEXT): {$(VPATH)}ruby_assert.h
eval.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-eval.$(OBJEXT): {$(VPATH)}rubyparser.h
eval.$(OBJEXT): {$(VPATH)}shape.h
eval.$(OBJEXT): {$(VPATH)}st.h
eval.$(OBJEXT): {$(VPATH)}subst.h
@@ -6796,10 +6564,6 @@ explicit_bzero.$(OBJEXT): {$(VPATH)}internal/config.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/dllexport.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
explicit_bzero.$(OBJEXT): {$(VPATH)}missing.h
-file.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-file.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-file.$(OBJEXT): $(CCAN_DIR)/list/list.h
-file.$(OBJEXT): $(CCAN_DIR)/str/str.h
file.$(OBJEXT): $(hdrdir)/ruby/ruby.h
file.$(OBJEXT): $(top_srcdir)/internal/array.h
file.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -6879,7 +6643,6 @@ file.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
file.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
file.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
file.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
file.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
file.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
file.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6948,6 +6711,7 @@ file.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
file.$(OBJEXT): {$(VPATH)}internal/intern/error.h
file.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
file.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
file.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
file.$(OBJEXT): {$(VPATH)}internal/intern/io.h
file.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6978,6 +6742,7 @@ file.$(OBJEXT): {$(VPATH)}internal/memory.h
file.$(OBJEXT): {$(VPATH)}internal/method.h
file.$(OBJEXT): {$(VPATH)}internal/module.h
file.$(OBJEXT): {$(VPATH)}internal/newobj.h
+file.$(OBJEXT): {$(VPATH)}internal/rgengc.h
file.$(OBJEXT): {$(VPATH)}internal/scan_args.h
file.$(OBJEXT): {$(VPATH)}internal/special_consts.h
file.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -6997,7 +6762,6 @@ file.$(OBJEXT): {$(VPATH)}shape.h
file.$(OBJEXT): {$(VPATH)}st.h
file.$(OBJEXT): {$(VPATH)}subst.h
file.$(OBJEXT): {$(VPATH)}thread.h
-file.$(OBJEXT): {$(VPATH)}thread_native.h
file.$(OBJEXT): {$(VPATH)}util.h
gc.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
gc.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
@@ -7010,7 +6774,6 @@ gc.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
gc.$(OBJEXT): $(top_srcdir)/internal/bignum.h
gc.$(OBJEXT): $(top_srcdir)/internal/bits.h
gc.$(OBJEXT): $(top_srcdir)/internal/class.h
-gc.$(OBJEXT): $(top_srcdir)/internal/compile.h
gc.$(OBJEXT): $(top_srcdir)/internal/compilers.h
gc.$(OBJEXT): $(top_srcdir)/internal/complex.h
gc.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -7049,13 +6812,13 @@ gc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
gc.$(OBJEXT): {$(VPATH)}builtin.h
gc.$(OBJEXT): {$(VPATH)}config.h
gc.$(OBJEXT): {$(VPATH)}constant.h
-gc.$(OBJEXT): {$(VPATH)}darray.h
gc.$(OBJEXT): {$(VPATH)}debug.h
gc.$(OBJEXT): {$(VPATH)}debug_counter.h
gc.$(OBJEXT): {$(VPATH)}defines.h
gc.$(OBJEXT): {$(VPATH)}encoding.h
gc.$(OBJEXT): {$(VPATH)}eval_intern.h
gc.$(OBJEXT): {$(VPATH)}gc.c
+gc.$(OBJEXT): {$(VPATH)}gc.h
gc.$(OBJEXT): {$(VPATH)}gc.rbinc
gc.$(OBJEXT): {$(VPATH)}id.h
gc.$(OBJEXT): {$(VPATH)}id_table.h
@@ -7099,7 +6862,6 @@ gc.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7169,6 +6931,7 @@ gc.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/error.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7199,6 +6962,7 @@ gc.$(OBJEXT): {$(VPATH)}internal/memory.h
gc.$(OBJEXT): {$(VPATH)}internal/method.h
gc.$(OBJEXT): {$(VPATH)}internal/module.h
gc.$(OBJEXT): {$(VPATH)}internal/newobj.h
+gc.$(OBJEXT): {$(VPATH)}internal/rgengc.h
gc.$(OBJEXT): {$(VPATH)}internal/scan_args.h
gc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
gc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -7214,6 +6978,7 @@ gc.$(OBJEXT): {$(VPATH)}io.h
gc.$(OBJEXT): {$(VPATH)}iseq.h
gc.$(OBJEXT): {$(VPATH)}method.h
gc.$(OBJEXT): {$(VPATH)}missing.h
+gc.$(OBJEXT): {$(VPATH)}mjit.h
gc.$(OBJEXT): {$(VPATH)}node.h
gc.$(OBJEXT): {$(VPATH)}onigmo.h
gc.$(OBJEXT): {$(VPATH)}oniguruma.h
@@ -7225,10 +6990,8 @@ gc.$(OBJEXT): {$(VPATH)}re.h
gc.$(OBJEXT): {$(VPATH)}regenc.h
gc.$(OBJEXT): {$(VPATH)}regex.h
gc.$(OBJEXT): {$(VPATH)}regint.h
-gc.$(OBJEXT): {$(VPATH)}rjit.h
gc.$(OBJEXT): {$(VPATH)}ruby_assert.h
gc.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-gc.$(OBJEXT): {$(VPATH)}rubyparser.h
gc.$(OBJEXT): {$(VPATH)}shape.h
gc.$(OBJEXT): {$(VPATH)}st.h
gc.$(OBJEXT): {$(VPATH)}subst.h
@@ -7236,6 +6999,7 @@ gc.$(OBJEXT): {$(VPATH)}symbol.h
gc.$(OBJEXT): {$(VPATH)}thread.h
gc.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
gc.$(OBJEXT): {$(VPATH)}thread_native.h
+gc.$(OBJEXT): {$(VPATH)}transient_heap.h
gc.$(OBJEXT): {$(VPATH)}util.h
gc.$(OBJEXT): {$(VPATH)}vm_callinfo.h
gc.$(OBJEXT): {$(VPATH)}vm_core.h
@@ -7253,7 +7017,6 @@ goruby.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
goruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
goruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
goruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
goruby.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -7274,7 +7037,6 @@ goruby.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
goruby.$(OBJEXT): {$(VPATH)}config.h
goruby.$(OBJEXT): {$(VPATH)}constant.h
goruby.$(OBJEXT): {$(VPATH)}defines.h
-goruby.$(OBJEXT): {$(VPATH)}encoding.h
goruby.$(OBJEXT): {$(VPATH)}golf_prelude.c
goruby.$(OBJEXT): {$(VPATH)}goruby.c
goruby.$(OBJEXT): {$(VPATH)}id.h
@@ -7318,8 +7080,8 @@ goruby.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7352,15 +7114,6 @@ goruby.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
goruby.$(OBJEXT): {$(VPATH)}internal/ctype.h
goruby.$(OBJEXT): {$(VPATH)}internal/dllexport.h
goruby.$(OBJEXT): {$(VPATH)}internal/dosish.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
goruby.$(OBJEXT): {$(VPATH)}internal/error.h
goruby.$(OBJEXT): {$(VPATH)}internal/eval.h
goruby.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -7388,6 +7141,7 @@ goruby.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/error.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7418,6 +7172,7 @@ goruby.$(OBJEXT): {$(VPATH)}internal/memory.h
goruby.$(OBJEXT): {$(VPATH)}internal/method.h
goruby.$(OBJEXT): {$(VPATH)}internal/module.h
goruby.$(OBJEXT): {$(VPATH)}internal/newobj.h
+goruby.$(OBJEXT): {$(VPATH)}internal/rgengc.h
goruby.$(OBJEXT): {$(VPATH)}internal/scan_args.h
goruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
goruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -7434,11 +7189,8 @@ goruby.$(OBJEXT): {$(VPATH)}main.c
goruby.$(OBJEXT): {$(VPATH)}method.h
goruby.$(OBJEXT): {$(VPATH)}missing.h
goruby.$(OBJEXT): {$(VPATH)}node.h
-goruby.$(OBJEXT): {$(VPATH)}onigmo.h
-goruby.$(OBJEXT): {$(VPATH)}oniguruma.h
goruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
goruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-goruby.$(OBJEXT): {$(VPATH)}rubyparser.h
goruby.$(OBJEXT): {$(VPATH)}shape.h
goruby.$(OBJEXT): {$(VPATH)}st.h
goruby.$(OBJEXT): {$(VPATH)}subst.h
@@ -7533,7 +7285,6 @@ hash.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7602,6 +7353,7 @@ hash.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/error.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/io.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7632,6 +7384,7 @@ hash.$(OBJEXT): {$(VPATH)}internal/memory.h
hash.$(OBJEXT): {$(VPATH)}internal/method.h
hash.$(OBJEXT): {$(VPATH)}internal/module.h
hash.$(OBJEXT): {$(VPATH)}internal/newobj.h
+hash.$(OBJEXT): {$(VPATH)}internal/rgengc.h
hash.$(OBJEXT): {$(VPATH)}internal/scan_args.h
hash.$(OBJEXT): {$(VPATH)}internal/special_consts.h
hash.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -7654,13 +7407,13 @@ hash.$(OBJEXT): {$(VPATH)}probes.h
hash.$(OBJEXT): {$(VPATH)}ractor.h
hash.$(OBJEXT): {$(VPATH)}ruby_assert.h
hash.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-hash.$(OBJEXT): {$(VPATH)}rubyparser.h
hash.$(OBJEXT): {$(VPATH)}shape.h
hash.$(OBJEXT): {$(VPATH)}st.h
hash.$(OBJEXT): {$(VPATH)}subst.h
hash.$(OBJEXT): {$(VPATH)}symbol.h
hash.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
hash.$(OBJEXT): {$(VPATH)}thread_native.h
+hash.$(OBJEXT): {$(VPATH)}transient_heap.h
hash.$(OBJEXT): {$(VPATH)}util.h
hash.$(OBJEXT): {$(VPATH)}vm_core.h
hash.$(OBJEXT): {$(VPATH)}vm_debug.h
@@ -7724,7 +7477,6 @@ inits.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7784,6 +7536,7 @@ inits.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/error.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/io.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7814,6 +7567,7 @@ inits.$(OBJEXT): {$(VPATH)}internal/memory.h
inits.$(OBJEXT): {$(VPATH)}internal/method.h
inits.$(OBJEXT): {$(VPATH)}internal/module.h
inits.$(OBJEXT): {$(VPATH)}internal/newobj.h
+inits.$(OBJEXT): {$(VPATH)}internal/rgengc.h
inits.$(OBJEXT): {$(VPATH)}internal/scan_args.h
inits.$(OBJEXT): {$(VPATH)}internal/special_consts.h
inits.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -7919,7 +7673,6 @@ io.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
io.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
io.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
io.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
io.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
io.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
io.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7988,6 +7741,7 @@ io.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
io.$(OBJEXT): {$(VPATH)}internal/intern/error.h
io.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
io.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
io.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
io.$(OBJEXT): {$(VPATH)}internal/intern/io.h
io.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8018,6 +7772,7 @@ io.$(OBJEXT): {$(VPATH)}internal/memory.h
io.$(OBJEXT): {$(VPATH)}internal/method.h
io.$(OBJEXT): {$(VPATH)}internal/module.h
io.$(OBJEXT): {$(VPATH)}internal/newobj.h
+io.$(OBJEXT): {$(VPATH)}internal/rgengc.h
io.$(OBJEXT): {$(VPATH)}internal/scan_args.h
io.$(OBJEXT): {$(VPATH)}internal/special_consts.h
io.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -8041,7 +7796,6 @@ io.$(OBJEXT): {$(VPATH)}oniguruma.h
io.$(OBJEXT): {$(VPATH)}ractor.h
io.$(OBJEXT): {$(VPATH)}ruby_assert.h
io.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-io.$(OBJEXT): {$(VPATH)}rubyparser.h
io.$(OBJEXT): {$(VPATH)}shape.h
io.$(OBJEXT): {$(VPATH)}st.h
io.$(OBJEXT): {$(VPATH)}subst.h
@@ -8051,10 +7805,6 @@ io.$(OBJEXT): {$(VPATH)}thread_native.h
io.$(OBJEXT): {$(VPATH)}util.h
io.$(OBJEXT): {$(VPATH)}vm_core.h
io.$(OBJEXT): {$(VPATH)}vm_opts.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/list/list.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/str/str.h
io_buffer.$(OBJEXT): $(hdrdir)/ruby/ruby.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/array.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -8122,7 +7872,6 @@ io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8191,6 +7940,7 @@ io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/error.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/io.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8221,6 +7971,7 @@ io_buffer.$(OBJEXT): {$(VPATH)}internal/memory.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/method.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/module.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/newobj.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/rgengc.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/scan_args.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/special_consts.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -8240,7 +7991,6 @@ io_buffer.$(OBJEXT): {$(VPATH)}onigmo.h
io_buffer.$(OBJEXT): {$(VPATH)}oniguruma.h
io_buffer.$(OBJEXT): {$(VPATH)}st.h
io_buffer.$(OBJEXT): {$(VPATH)}subst.h
-io_buffer.$(OBJEXT): {$(VPATH)}thread_native.h
iseq.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
iseq.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
iseq.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -8259,7 +8009,6 @@ iseq.$(OBJEXT): $(top_srcdir)/internal/gc.h
iseq.$(OBJEXT): $(top_srcdir)/internal/hash.h
iseq.$(OBJEXT): $(top_srcdir)/internal/imemo.h
iseq.$(OBJEXT): $(top_srcdir)/internal/parse.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
iseq.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
iseq.$(OBJEXT): $(top_srcdir)/internal/serial.h
iseq.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -8269,27 +8018,6 @@ iseq.$(OBJEXT): $(top_srcdir)/internal/thread.h
iseq.$(OBJEXT): $(top_srcdir)/internal/variable.h
iseq.$(OBJEXT): $(top_srcdir)/internal/vm.h
iseq.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/defines.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/node.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/options.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/pack.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/parser.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/prism.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
iseq.$(OBJEXT): {$(VPATH)}assert.h
iseq.$(OBJEXT): {$(VPATH)}atomic.h
iseq.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -8308,6 +8036,7 @@ iseq.$(OBJEXT): {$(VPATH)}debug_counter.h
iseq.$(OBJEXT): {$(VPATH)}defines.h
iseq.$(OBJEXT): {$(VPATH)}encoding.h
iseq.$(OBJEXT): {$(VPATH)}eval_intern.h
+iseq.$(OBJEXT): {$(VPATH)}gc.h
iseq.$(OBJEXT): {$(VPATH)}id.h
iseq.$(OBJEXT): {$(VPATH)}id_table.h
iseq.$(OBJEXT): {$(VPATH)}insns.def
@@ -8353,7 +8082,6 @@ iseq.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8422,6 +8150,7 @@ iseq.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/error.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/io.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8452,6 +8181,7 @@ iseq.$(OBJEXT): {$(VPATH)}internal/memory.h
iseq.$(OBJEXT): {$(VPATH)}internal/method.h
iseq.$(OBJEXT): {$(VPATH)}internal/module.h
iseq.$(OBJEXT): {$(VPATH)}internal/newobj.h
+iseq.$(OBJEXT): {$(VPATH)}internal/rgengc.h
iseq.$(OBJEXT): {$(VPATH)}internal/scan_args.h
iseq.$(OBJEXT): {$(VPATH)}internal/special_consts.h
iseq.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -8467,18 +8197,14 @@ iseq.$(OBJEXT): {$(VPATH)}iseq.c
iseq.$(OBJEXT): {$(VPATH)}iseq.h
iseq.$(OBJEXT): {$(VPATH)}method.h
iseq.$(OBJEXT): {$(VPATH)}missing.h
+iseq.$(OBJEXT): {$(VPATH)}mjit.h
iseq.$(OBJEXT): {$(VPATH)}node.h
+iseq.$(OBJEXT): {$(VPATH)}node_name.inc
iseq.$(OBJEXT): {$(VPATH)}onigmo.h
iseq.$(OBJEXT): {$(VPATH)}oniguruma.h
-iseq.$(OBJEXT): {$(VPATH)}prism/ast.h
-iseq.$(OBJEXT): {$(VPATH)}prism/prism.h
-iseq.$(OBJEXT): {$(VPATH)}prism/version.h
-iseq.$(OBJEXT): {$(VPATH)}prism_compile.h
iseq.$(OBJEXT): {$(VPATH)}ractor.h
-iseq.$(OBJEXT): {$(VPATH)}rjit.h
iseq.$(OBJEXT): {$(VPATH)}ruby_assert.h
iseq.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-iseq.$(OBJEXT): {$(VPATH)}rubyparser.h
iseq.$(OBJEXT): {$(VPATH)}shape.h
iseq.$(OBJEXT): {$(VPATH)}st.h
iseq.$(OBJEXT): {$(VPATH)}subst.h
@@ -8496,7 +8222,6 @@ load.$(OBJEXT): $(CCAN_DIR)/str/str.h
load.$(OBJEXT): $(hdrdir)/ruby/ruby.h
load.$(OBJEXT): $(top_srcdir)/internal/array.h
load.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-load.$(OBJEXT): $(top_srcdir)/internal/bits.h
load.$(OBJEXT): $(top_srcdir)/internal/compilers.h
load.$(OBJEXT): $(top_srcdir)/internal/dir.h
load.$(OBJEXT): $(top_srcdir)/internal/error.h
@@ -8505,7 +8230,6 @@ load.$(OBJEXT): $(top_srcdir)/internal/gc.h
load.$(OBJEXT): $(top_srcdir)/internal/imemo.h
load.$(OBJEXT): $(top_srcdir)/internal/load.h
load.$(OBJEXT): $(top_srcdir)/internal/parse.h
-load.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
load.$(OBJEXT): $(top_srcdir)/internal/serial.h
load.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
load.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -8573,7 +8297,6 @@ load.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
load.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
load.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
load.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
load.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
load.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
load.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8642,6 +8365,7 @@ load.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
load.$(OBJEXT): {$(VPATH)}internal/intern/error.h
load.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
load.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
load.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
load.$(OBJEXT): {$(VPATH)}internal/intern/io.h
load.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8672,6 +8396,7 @@ load.$(OBJEXT): {$(VPATH)}internal/memory.h
load.$(OBJEXT): {$(VPATH)}internal/method.h
load.$(OBJEXT): {$(VPATH)}internal/module.h
load.$(OBJEXT): {$(VPATH)}internal/newobj.h
+load.$(OBJEXT): {$(VPATH)}internal/rgengc.h
load.$(OBJEXT): {$(VPATH)}internal/scan_args.h
load.$(OBJEXT): {$(VPATH)}internal/special_consts.h
load.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -8694,7 +8419,6 @@ load.$(OBJEXT): {$(VPATH)}probes.dmyh
load.$(OBJEXT): {$(VPATH)}probes.h
load.$(OBJEXT): {$(VPATH)}ruby_assert.h
load.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-load.$(OBJEXT): {$(VPATH)}rubyparser.h
load.$(OBJEXT): {$(VPATH)}shape.h
load.$(OBJEXT): {$(VPATH)}st.h
load.$(OBJEXT): {$(VPATH)}subst.h
@@ -8756,7 +8480,6 @@ loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8816,6 +8539,7 @@ loadpath.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/error.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/io.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8846,6 +8570,7 @@ loadpath.$(OBJEXT): {$(VPATH)}internal/memory.h
loadpath.$(OBJEXT): {$(VPATH)}internal/method.h
loadpath.$(OBJEXT): {$(VPATH)}internal/module.h
loadpath.$(OBJEXT): {$(VPATH)}internal/newobj.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/rgengc.h
loadpath.$(OBJEXT): {$(VPATH)}internal/scan_args.h
loadpath.$(OBJEXT): {$(VPATH)}internal/special_consts.h
loadpath.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -8916,7 +8641,6 @@ localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8985,6 +8709,7 @@ localeinit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9015,6 +8740,7 @@ localeinit.$(OBJEXT): {$(VPATH)}internal/memory.h
localeinit.$(OBJEXT): {$(VPATH)}internal/method.h
localeinit.$(OBJEXT): {$(VPATH)}internal/module.h
localeinit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
localeinit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
localeinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
localeinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -9085,7 +8811,6 @@ main.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
main.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
main.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
main.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
main.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
main.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
main.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9145,6 +8870,7 @@ main.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
main.$(OBJEXT): {$(VPATH)}internal/intern/error.h
main.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
main.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
main.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
main.$(OBJEXT): {$(VPATH)}internal/intern/io.h
main.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9175,6 +8901,7 @@ main.$(OBJEXT): {$(VPATH)}internal/memory.h
main.$(OBJEXT): {$(VPATH)}internal/method.h
main.$(OBJEXT): {$(VPATH)}internal/module.h
main.$(OBJEXT): {$(VPATH)}internal/newobj.h
+main.$(OBJEXT): {$(VPATH)}internal/rgengc.h
main.$(OBJEXT): {$(VPATH)}internal/scan_args.h
main.$(OBJEXT): {$(VPATH)}internal/special_consts.h
main.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -9277,8 +9004,8 @@ marshal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9347,6 +9074,7 @@ marshal.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/error.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9377,6 +9105,7 @@ marshal.$(OBJEXT): {$(VPATH)}internal/memory.h
marshal.$(OBJEXT): {$(VPATH)}internal/method.h
marshal.$(OBJEXT): {$(VPATH)}internal/module.h
marshal.$(OBJEXT): {$(VPATH)}internal/newobj.h
+marshal.$(OBJEXT): {$(VPATH)}internal/rgengc.h
marshal.$(OBJEXT): {$(VPATH)}internal/scan_args.h
marshal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
marshal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -9398,7 +9127,6 @@ marshal.$(OBJEXT): {$(VPATH)}onigmo.h
marshal.$(OBJEXT): {$(VPATH)}oniguruma.h
marshal.$(OBJEXT): {$(VPATH)}ruby_assert.h
marshal.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-marshal.$(OBJEXT): {$(VPATH)}rubyparser.h
marshal.$(OBJEXT): {$(VPATH)}shape.h
marshal.$(OBJEXT): {$(VPATH)}st.h
marshal.$(OBJEXT): {$(VPATH)}subst.h
@@ -9474,7 +9202,6 @@ math.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
math.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
math.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
math.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
math.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
math.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
math.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9534,6 +9261,7 @@ math.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
math.$(OBJEXT): {$(VPATH)}internal/intern/error.h
math.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
math.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
math.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
math.$(OBJEXT): {$(VPATH)}internal/intern/io.h
math.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9564,6 +9292,7 @@ math.$(OBJEXT): {$(VPATH)}internal/memory.h
math.$(OBJEXT): {$(VPATH)}internal/method.h
math.$(OBJEXT): {$(VPATH)}internal/module.h
math.$(OBJEXT): {$(VPATH)}internal/newobj.h
+math.$(OBJEXT): {$(VPATH)}internal/rgengc.h
math.$(OBJEXT): {$(VPATH)}internal/scan_args.h
math.$(OBJEXT): {$(VPATH)}internal/special_consts.h
math.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -9580,24 +9309,13 @@ math.$(OBJEXT): {$(VPATH)}missing.h
math.$(OBJEXT): {$(VPATH)}shape.h
math.$(OBJEXT): {$(VPATH)}st.h
math.$(OBJEXT): {$(VPATH)}subst.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/list/list.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/str/str.h
memory_view.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/array.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/compilers.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/gc.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/hash.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/serial.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/variable.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/vm.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/warnings.h
memory_view.$(OBJEXT): {$(VPATH)}assert.h
-memory_view.$(OBJEXT): {$(VPATH)}atomic.h
memory_view.$(OBJEXT): {$(VPATH)}backward/2/assume.h
memory_view.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
memory_view.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -9611,8 +9329,6 @@ memory_view.$(OBJEXT): {$(VPATH)}config.h
memory_view.$(OBJEXT): {$(VPATH)}constant.h
memory_view.$(OBJEXT): {$(VPATH)}debug_counter.h
memory_view.$(OBJEXT): {$(VPATH)}defines.h
-memory_view.$(OBJEXT): {$(VPATH)}encoding.h
-memory_view.$(OBJEXT): {$(VPATH)}id.h
memory_view.$(OBJEXT): {$(VPATH)}id_table.h
memory_view.$(OBJEXT): {$(VPATH)}intern.h
memory_view.$(OBJEXT): {$(VPATH)}internal.h
@@ -9654,7 +9370,6 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9687,15 +9402,6 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
memory_view.$(OBJEXT): {$(VPATH)}internal/ctype.h
memory_view.$(OBJEXT): {$(VPATH)}internal/dllexport.h
memory_view.$(OBJEXT): {$(VPATH)}internal/dosish.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
memory_view.$(OBJEXT): {$(VPATH)}internal/error.h
memory_view.$(OBJEXT): {$(VPATH)}internal/eval.h
memory_view.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -9723,6 +9429,7 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/error.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/io.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9753,6 +9460,7 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/memory.h
memory_view.$(OBJEXT): {$(VPATH)}internal/method.h
memory_view.$(OBJEXT): {$(VPATH)}internal/module.h
memory_view.$(OBJEXT): {$(VPATH)}internal/newobj.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/rgengc.h
memory_view.$(OBJEXT): {$(VPATH)}internal/scan_args.h
memory_view.$(OBJEXT): {$(VPATH)}internal/special_consts.h
memory_view.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -9766,36 +9474,24 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/warning_push.h
memory_view.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
memory_view.$(OBJEXT): {$(VPATH)}memory_view.c
memory_view.$(OBJEXT): {$(VPATH)}memory_view.h
-memory_view.$(OBJEXT): {$(VPATH)}method.h
memory_view.$(OBJEXT): {$(VPATH)}missing.h
-memory_view.$(OBJEXT): {$(VPATH)}node.h
-memory_view.$(OBJEXT): {$(VPATH)}onigmo.h
-memory_view.$(OBJEXT): {$(VPATH)}oniguruma.h
-memory_view.$(OBJEXT): {$(VPATH)}ruby_assert.h
-memory_view.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-memory_view.$(OBJEXT): {$(VPATH)}rubyparser.h
memory_view.$(OBJEXT): {$(VPATH)}shape.h
memory_view.$(OBJEXT): {$(VPATH)}st.h
memory_view.$(OBJEXT): {$(VPATH)}subst.h
-memory_view.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-memory_view.$(OBJEXT): {$(VPATH)}thread_native.h
memory_view.$(OBJEXT): {$(VPATH)}util.h
-memory_view.$(OBJEXT): {$(VPATH)}vm_core.h
memory_view.$(OBJEXT): {$(VPATH)}vm_debug.h
-memory_view.$(OBJEXT): {$(VPATH)}vm_opts.h
memory_view.$(OBJEXT): {$(VPATH)}vm_sync.h
miniinit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
miniinit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
miniinit.$(OBJEXT): $(CCAN_DIR)/list/list.h
miniinit.$(OBJEXT): $(CCAN_DIR)/str/str.h
miniinit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-miniinit.$(OBJEXT): $(srcdir)/rjit_c.rb
+miniinit.$(OBJEXT): $(srcdir)/mjit_c.rb
miniinit.$(OBJEXT): $(top_srcdir)/internal/array.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/serial.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -9863,8 +9559,8 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9933,6 +9629,7 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9963,6 +9660,7 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/memory.h
miniinit.$(OBJEXT): {$(VPATH)}internal/method.h
miniinit.$(OBJEXT): {$(VPATH)}internal/module.h
miniinit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
miniinit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
miniinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
miniinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -9983,6 +9681,8 @@ miniinit.$(OBJEXT): {$(VPATH)}mini_builtin.c
miniinit.$(OBJEXT): {$(VPATH)}miniinit.c
miniinit.$(OBJEXT): {$(VPATH)}miniprelude.c
miniinit.$(OBJEXT): {$(VPATH)}missing.h
+miniinit.$(OBJEXT): {$(VPATH)}mjit.rb
+miniinit.$(OBJEXT): {$(VPATH)}mjit_c.rb
miniinit.$(OBJEXT): {$(VPATH)}nilclass.rb
miniinit.$(OBJEXT): {$(VPATH)}node.h
miniinit.$(OBJEXT): {$(VPATH)}numeric.rb
@@ -9991,11 +9691,8 @@ miniinit.$(OBJEXT): {$(VPATH)}oniguruma.h
miniinit.$(OBJEXT): {$(VPATH)}pack.rb
miniinit.$(OBJEXT): {$(VPATH)}prelude.rb
miniinit.$(OBJEXT): {$(VPATH)}ractor.rb
-miniinit.$(OBJEXT): {$(VPATH)}rjit.rb
-miniinit.$(OBJEXT): {$(VPATH)}rjit_c.rb
miniinit.$(OBJEXT): {$(VPATH)}ruby_assert.h
miniinit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-miniinit.$(OBJEXT): {$(VPATH)}rubyparser.h
miniinit.$(OBJEXT): {$(VPATH)}shape.h
miniinit.$(OBJEXT): {$(VPATH)}st.h
miniinit.$(OBJEXT): {$(VPATH)}subst.h
@@ -10009,6 +9706,441 @@ miniinit.$(OBJEXT): {$(VPATH)}vm_core.h
miniinit.$(OBJEXT): {$(VPATH)}vm_opts.h
miniinit.$(OBJEXT): {$(VPATH)}warning.rb
miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
+mjit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+mjit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+mjit.$(OBJEXT): $(CCAN_DIR)/list/list.h
+mjit.$(OBJEXT): $(CCAN_DIR)/str/str.h
+mjit.$(OBJEXT): $(hdrdir)/ruby.h
+mjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+mjit.$(OBJEXT): $(hdrdir)/ruby/version.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/array.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/class.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/file.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/process.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+mjit.$(OBJEXT): {$(VPATH)}assert.h
+mjit.$(OBJEXT): {$(VPATH)}atomic.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+mjit.$(OBJEXT): {$(VPATH)}builtin.h
+mjit.$(OBJEXT): {$(VPATH)}config.h
+mjit.$(OBJEXT): {$(VPATH)}constant.h
+mjit.$(OBJEXT): {$(VPATH)}debug.h
+mjit.$(OBJEXT): {$(VPATH)}debug_counter.h
+mjit.$(OBJEXT): {$(VPATH)}defines.h
+mjit.$(OBJEXT): {$(VPATH)}dln.h
+mjit.$(OBJEXT): {$(VPATH)}encoding.h
+mjit.$(OBJEXT): {$(VPATH)}gc.h
+mjit.$(OBJEXT): {$(VPATH)}id.h
+mjit.$(OBJEXT): {$(VPATH)}id_table.h
+mjit.$(OBJEXT): {$(VPATH)}insns.def
+mjit.$(OBJEXT): {$(VPATH)}insns.inc
+mjit.$(OBJEXT): {$(VPATH)}insns_info.inc
+mjit.$(OBJEXT): {$(VPATH)}intern.h
+mjit.$(OBJEXT): {$(VPATH)}internal.h
+mjit.$(OBJEXT): {$(VPATH)}internal/abi.h
+mjit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/assume.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+mjit.$(OBJEXT): {$(VPATH)}internal/cast.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+mjit.$(OBJEXT): {$(VPATH)}internal/config.h
+mjit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+mjit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+mjit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+mjit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+mjit.$(OBJEXT): {$(VPATH)}internal/error.h
+mjit.$(OBJEXT): {$(VPATH)}internal/eval.h
+mjit.$(OBJEXT): {$(VPATH)}internal/event.h
+mjit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+mjit.$(OBJEXT): {$(VPATH)}internal/gc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/glob.h
+mjit.$(OBJEXT): {$(VPATH)}internal/globals.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+mjit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+mjit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+mjit.$(OBJEXT): {$(VPATH)}internal/memory.h
+mjit.$(OBJEXT): {$(VPATH)}internal/method.h
+mjit.$(OBJEXT): {$(VPATH)}internal/module.h
+mjit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+mjit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+mjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+mjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+mjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+mjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+mjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+mjit.$(OBJEXT): {$(VPATH)}internal/value.h
+mjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+mjit.$(OBJEXT): {$(VPATH)}internal/variable.h
+mjit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+mjit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+mjit.$(OBJEXT): {$(VPATH)}iseq.h
+mjit.$(OBJEXT): {$(VPATH)}method.h
+mjit.$(OBJEXT): {$(VPATH)}missing.h
+mjit.$(OBJEXT): {$(VPATH)}mjit.c
+mjit.$(OBJEXT): {$(VPATH)}mjit.h
+mjit.$(OBJEXT): {$(VPATH)}mjit.rbinc
+mjit.$(OBJEXT): {$(VPATH)}mjit_c.h
+mjit.$(OBJEXT): {$(VPATH)}mjit_config.h
+mjit.$(OBJEXT): {$(VPATH)}node.h
+mjit.$(OBJEXT): {$(VPATH)}onigmo.h
+mjit.$(OBJEXT): {$(VPATH)}oniguruma.h
+mjit.$(OBJEXT): {$(VPATH)}ractor.h
+mjit.$(OBJEXT): {$(VPATH)}ractor_core.h
+mjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
+mjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+mjit.$(OBJEXT): {$(VPATH)}shape.h
+mjit.$(OBJEXT): {$(VPATH)}st.h
+mjit.$(OBJEXT): {$(VPATH)}subst.h
+mjit.$(OBJEXT): {$(VPATH)}thread.h
+mjit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+mjit.$(OBJEXT): {$(VPATH)}thread_native.h
+mjit.$(OBJEXT): {$(VPATH)}util.h
+mjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+mjit.$(OBJEXT): {$(VPATH)}vm_core.h
+mjit.$(OBJEXT): {$(VPATH)}vm_debug.h
+mjit.$(OBJEXT): {$(VPATH)}vm_opts.h
+mjit.$(OBJEXT): {$(VPATH)}vm_sync.h
+mjit.$(OBJEXT): {$(VPATH)}yjit.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/list/list.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/str/str.h
+mjit_c.$(OBJEXT): $(hdrdir)/ruby.h
+mjit_c.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+mjit_c.$(OBJEXT): $(srcdir)/mjit_c.rb
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/array.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/class.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/compile.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/gc.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/hash.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/object.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/serial.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/variable.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/vm.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+mjit_c.$(OBJEXT): {$(VPATH)}assert.h
+mjit_c.$(OBJEXT): {$(VPATH)}atomic.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+mjit_c.$(OBJEXT): {$(VPATH)}builtin.h
+mjit_c.$(OBJEXT): {$(VPATH)}config.h
+mjit_c.$(OBJEXT): {$(VPATH)}constant.h
+mjit_c.$(OBJEXT): {$(VPATH)}debug_counter.h
+mjit_c.$(OBJEXT): {$(VPATH)}defines.h
+mjit_c.$(OBJEXT): {$(VPATH)}id.h
+mjit_c.$(OBJEXT): {$(VPATH)}id_table.h
+mjit_c.$(OBJEXT): {$(VPATH)}insns.def
+mjit_c.$(OBJEXT): {$(VPATH)}insns.inc
+mjit_c.$(OBJEXT): {$(VPATH)}insns_info.inc
+mjit_c.$(OBJEXT): {$(VPATH)}intern.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/abi.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/assume.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/cast.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/config.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/ctype.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/dosish.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/error.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/eval.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/event.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/gc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/glob.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/globals.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/iterator.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/memory.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/method.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/module.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/newobj.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/rgengc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/symbol.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/value.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/value_type.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/variable.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+mjit_c.$(OBJEXT): {$(VPATH)}iseq.h
+mjit_c.$(OBJEXT): {$(VPATH)}method.h
+mjit_c.$(OBJEXT): {$(VPATH)}missing.h
+mjit_c.$(OBJEXT): {$(VPATH)}mjit.h
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.c
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.h
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.rb
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.rbinc
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_sp_inc.inc
+mjit_c.$(OBJEXT): {$(VPATH)}node.h
+mjit_c.$(OBJEXT): {$(VPATH)}ruby_assert.h
+mjit_c.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+mjit_c.$(OBJEXT): {$(VPATH)}shape.h
+mjit_c.$(OBJEXT): {$(VPATH)}st.h
+mjit_c.$(OBJEXT): {$(VPATH)}subst.h
+mjit_c.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+mjit_c.$(OBJEXT): {$(VPATH)}thread_native.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_core.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_exec.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_opts.h
+mjit_c.$(OBJEXT): {$(VPATH)}yjit.h
node.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
node.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
node.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -10039,7 +10171,6 @@ node.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
node.$(OBJEXT): {$(VPATH)}config.h
node.$(OBJEXT): {$(VPATH)}constant.h
node.$(OBJEXT): {$(VPATH)}defines.h
-node.$(OBJEXT): {$(VPATH)}encoding.h
node.$(OBJEXT): {$(VPATH)}id.h
node.$(OBJEXT): {$(VPATH)}id_table.h
node.$(OBJEXT): {$(VPATH)}intern.h
@@ -10082,7 +10213,6 @@ node.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
node.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
node.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
node.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
node.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
node.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
node.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10115,15 +10245,6 @@ node.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
node.$(OBJEXT): {$(VPATH)}internal/ctype.h
node.$(OBJEXT): {$(VPATH)}internal/dllexport.h
node.$(OBJEXT): {$(VPATH)}internal/dosish.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
node.$(OBJEXT): {$(VPATH)}internal/error.h
node.$(OBJEXT): {$(VPATH)}internal/eval.h
node.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -10151,6 +10272,7 @@ node.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
node.$(OBJEXT): {$(VPATH)}internal/intern/error.h
node.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
node.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
node.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
node.$(OBJEXT): {$(VPATH)}internal/intern/io.h
node.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -10181,6 +10303,7 @@ node.$(OBJEXT): {$(VPATH)}internal/memory.h
node.$(OBJEXT): {$(VPATH)}internal/method.h
node.$(OBJEXT): {$(VPATH)}internal/module.h
node.$(OBJEXT): {$(VPATH)}internal/newobj.h
+node.$(OBJEXT): {$(VPATH)}internal/rgengc.h
node.$(OBJEXT): {$(VPATH)}internal/scan_args.h
node.$(OBJEXT): {$(VPATH)}internal/special_consts.h
node.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -10196,12 +10319,8 @@ node.$(OBJEXT): {$(VPATH)}method.h
node.$(OBJEXT): {$(VPATH)}missing.h
node.$(OBJEXT): {$(VPATH)}node.c
node.$(OBJEXT): {$(VPATH)}node.h
-node.$(OBJEXT): {$(VPATH)}node_name.inc
-node.$(OBJEXT): {$(VPATH)}onigmo.h
-node.$(OBJEXT): {$(VPATH)}oniguruma.h
node.$(OBJEXT): {$(VPATH)}ruby_assert.h
node.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-node.$(OBJEXT): {$(VPATH)}rubyparser.h
node.$(OBJEXT): {$(VPATH)}shape.h
node.$(OBJEXT): {$(VPATH)}st.h
node.$(OBJEXT): {$(VPATH)}subst.h
@@ -10209,212 +10328,8 @@ node.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
node.$(OBJEXT): {$(VPATH)}thread_native.h
node.$(OBJEXT): {$(VPATH)}vm_core.h
node.$(OBJEXT): {$(VPATH)}vm_opts.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/list/list.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/str/str.h
-node_dump.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/array.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/hash.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/variable.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/vm.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-node_dump.$(OBJEXT): {$(VPATH)}assert.h
-node_dump.$(OBJEXT): {$(VPATH)}atomic.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-node_dump.$(OBJEXT): {$(VPATH)}config.h
-node_dump.$(OBJEXT): {$(VPATH)}constant.h
-node_dump.$(OBJEXT): {$(VPATH)}defines.h
-node_dump.$(OBJEXT): {$(VPATH)}encoding.h
-node_dump.$(OBJEXT): {$(VPATH)}id.h
-node_dump.$(OBJEXT): {$(VPATH)}id_table.h
-node_dump.$(OBJEXT): {$(VPATH)}intern.h
-node_dump.$(OBJEXT): {$(VPATH)}internal.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/abi.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/assume.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/cast.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/config.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/ctype.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/dosish.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/error.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/eval.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/event.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/gc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/glob.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/globals.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/iterator.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/memory.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/method.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/module.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/newobj.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/symbol.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/value.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/value_type.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/variable.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-node_dump.$(OBJEXT): {$(VPATH)}method.h
-node_dump.$(OBJEXT): {$(VPATH)}missing.h
-node_dump.$(OBJEXT): {$(VPATH)}node.h
-node_dump.$(OBJEXT): {$(VPATH)}node_dump.c
-node_dump.$(OBJEXT): {$(VPATH)}onigmo.h
-node_dump.$(OBJEXT): {$(VPATH)}oniguruma.h
-node_dump.$(OBJEXT): {$(VPATH)}ruby_assert.h
-node_dump.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-node_dump.$(OBJEXT): {$(VPATH)}rubyparser.h
-node_dump.$(OBJEXT): {$(VPATH)}shape.h
-node_dump.$(OBJEXT): {$(VPATH)}st.h
-node_dump.$(OBJEXT): {$(VPATH)}subst.h
-node_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-node_dump.$(OBJEXT): {$(VPATH)}thread_native.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_core.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
-numeric.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-numeric.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-numeric.$(OBJEXT): $(CCAN_DIR)/list/list.h
-numeric.$(OBJEXT): $(CCAN_DIR)/str/str.h
numeric.$(OBJEXT): $(hdrdir)/ruby/ruby.h
numeric.$(OBJEXT): $(top_srcdir)/internal/array.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
numeric.$(OBJEXT): $(top_srcdir)/internal/bignum.h
numeric.$(OBJEXT): $(top_srcdir)/internal/bits.h
numeric.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -10424,7 +10339,6 @@ numeric.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
numeric.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
numeric.$(OBJEXT): $(top_srcdir)/internal/gc.h
numeric.$(OBJEXT): $(top_srcdir)/internal/hash.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/imemo.h
numeric.$(OBJEXT): $(top_srcdir)/internal/numeric.h
numeric.$(OBJEXT): $(top_srcdir)/internal/object.h
numeric.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -10436,7 +10350,6 @@ numeric.$(OBJEXT): $(top_srcdir)/internal/variable.h
numeric.$(OBJEXT): $(top_srcdir)/internal/vm.h
numeric.$(OBJEXT): $(top_srcdir)/internal/warnings.h
numeric.$(OBJEXT): {$(VPATH)}assert.h
-numeric.$(OBJEXT): {$(VPATH)}atomic.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/assume.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -10493,7 +10406,6 @@ numeric.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10562,6 +10474,7 @@ numeric.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/error.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/io.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -10592,6 +10505,7 @@ numeric.$(OBJEXT): {$(VPATH)}internal/memory.h
numeric.$(OBJEXT): {$(VPATH)}internal/method.h
numeric.$(OBJEXT): {$(VPATH)}internal/module.h
numeric.$(OBJEXT): {$(VPATH)}internal/newobj.h
+numeric.$(OBJEXT): {$(VPATH)}internal/rgengc.h
numeric.$(OBJEXT): {$(VPATH)}internal/scan_args.h
numeric.$(OBJEXT): {$(VPATH)}internal/special_consts.h
numeric.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -10603,24 +10517,16 @@ numeric.$(OBJEXT): {$(VPATH)}internal/value_type.h
numeric.$(OBJEXT): {$(VPATH)}internal/variable.h
numeric.$(OBJEXT): {$(VPATH)}internal/warning_push.h
numeric.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-numeric.$(OBJEXT): {$(VPATH)}method.h
numeric.$(OBJEXT): {$(VPATH)}missing.h
-numeric.$(OBJEXT): {$(VPATH)}node.h
numeric.$(OBJEXT): {$(VPATH)}numeric.c
numeric.$(OBJEXT): {$(VPATH)}numeric.rbinc
numeric.$(OBJEXT): {$(VPATH)}onigmo.h
numeric.$(OBJEXT): {$(VPATH)}oniguruma.h
numeric.$(OBJEXT): {$(VPATH)}ruby_assert.h
-numeric.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-numeric.$(OBJEXT): {$(VPATH)}rubyparser.h
numeric.$(OBJEXT): {$(VPATH)}shape.h
numeric.$(OBJEXT): {$(VPATH)}st.h
numeric.$(OBJEXT): {$(VPATH)}subst.h
-numeric.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-numeric.$(OBJEXT): {$(VPATH)}thread_native.h
numeric.$(OBJEXT): {$(VPATH)}util.h
-numeric.$(OBJEXT): {$(VPATH)}vm_core.h
-numeric.$(OBJEXT): {$(VPATH)}vm_opts.h
object.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
object.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
object.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -10706,7 +10612,6 @@ object.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
object.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
object.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
object.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
object.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
object.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
object.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10775,6 +10680,7 @@ object.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
object.$(OBJEXT): {$(VPATH)}internal/intern/error.h
object.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
object.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
object.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
object.$(OBJEXT): {$(VPATH)}internal/intern/io.h
object.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -10805,6 +10711,7 @@ object.$(OBJEXT): {$(VPATH)}internal/memory.h
object.$(OBJEXT): {$(VPATH)}internal/method.h
object.$(OBJEXT): {$(VPATH)}internal/module.h
object.$(OBJEXT): {$(VPATH)}internal/newobj.h
+object.$(OBJEXT): {$(VPATH)}internal/rgengc.h
object.$(OBJEXT): {$(VPATH)}internal/scan_args.h
object.$(OBJEXT): {$(VPATH)}internal/special_consts.h
object.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -10828,7 +10735,6 @@ object.$(OBJEXT): {$(VPATH)}probes.dmyh
object.$(OBJEXT): {$(VPATH)}probes.h
object.$(OBJEXT): {$(VPATH)}ruby_assert.h
object.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-object.$(OBJEXT): {$(VPATH)}rubyparser.h
object.$(OBJEXT): {$(VPATH)}shape.h
object.$(OBJEXT): {$(VPATH)}st.h
object.$(OBJEXT): {$(VPATH)}subst.h
@@ -10838,26 +10744,17 @@ object.$(OBJEXT): {$(VPATH)}util.h
object.$(OBJEXT): {$(VPATH)}variable.h
object.$(OBJEXT): {$(VPATH)}vm_core.h
object.$(OBJEXT): {$(VPATH)}vm_opts.h
-pack.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-pack.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-pack.$(OBJEXT): $(CCAN_DIR)/list/list.h
-pack.$(OBJEXT): $(CCAN_DIR)/str/str.h
pack.$(OBJEXT): $(hdrdir)/ruby/ruby.h
pack.$(OBJEXT): $(top_srcdir)/internal/array.h
-pack.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
pack.$(OBJEXT): $(top_srcdir)/internal/bits.h
pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h
pack.$(OBJEXT): $(top_srcdir)/internal/gc.h
-pack.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-pack.$(OBJEXT): $(top_srcdir)/internal/serial.h
pack.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
pack.$(OBJEXT): $(top_srcdir)/internal/string.h
pack.$(OBJEXT): $(top_srcdir)/internal/symbol.h
pack.$(OBJEXT): $(top_srcdir)/internal/variable.h
-pack.$(OBJEXT): $(top_srcdir)/internal/vm.h
pack.$(OBJEXT): $(top_srcdir)/internal/warnings.h
pack.$(OBJEXT): {$(VPATH)}assert.h
-pack.$(OBJEXT): {$(VPATH)}atomic.h
pack.$(OBJEXT): {$(VPATH)}backward/2/assume.h
pack.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
pack.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -10872,7 +10769,6 @@ pack.$(OBJEXT): {$(VPATH)}config.h
pack.$(OBJEXT): {$(VPATH)}constant.h
pack.$(OBJEXT): {$(VPATH)}defines.h
pack.$(OBJEXT): {$(VPATH)}encoding.h
-pack.$(OBJEXT): {$(VPATH)}id.h
pack.$(OBJEXT): {$(VPATH)}id_table.h
pack.$(OBJEXT): {$(VPATH)}intern.h
pack.$(OBJEXT): {$(VPATH)}internal.h
@@ -10914,7 +10810,6 @@ pack.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10983,6 +10878,7 @@ pack.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/error.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/io.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -11013,6 +10909,7 @@ pack.$(OBJEXT): {$(VPATH)}internal/memory.h
pack.$(OBJEXT): {$(VPATH)}internal/method.h
pack.$(OBJEXT): {$(VPATH)}internal/module.h
pack.$(OBJEXT): {$(VPATH)}internal/newobj.h
+pack.$(OBJEXT): {$(VPATH)}internal/rgengc.h
pack.$(OBJEXT): {$(VPATH)}internal/scan_args.h
pack.$(OBJEXT): {$(VPATH)}internal/special_consts.h
pack.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -11024,32 +10921,18 @@ pack.$(OBJEXT): {$(VPATH)}internal/value_type.h
pack.$(OBJEXT): {$(VPATH)}internal/variable.h
pack.$(OBJEXT): {$(VPATH)}internal/warning_push.h
pack.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-pack.$(OBJEXT): {$(VPATH)}method.h
pack.$(OBJEXT): {$(VPATH)}missing.h
-pack.$(OBJEXT): {$(VPATH)}node.h
pack.$(OBJEXT): {$(VPATH)}onigmo.h
pack.$(OBJEXT): {$(VPATH)}oniguruma.h
pack.$(OBJEXT): {$(VPATH)}pack.c
pack.$(OBJEXT): {$(VPATH)}pack.rbinc
-pack.$(OBJEXT): {$(VPATH)}ruby_assert.h
-pack.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-pack.$(OBJEXT): {$(VPATH)}rubyparser.h
pack.$(OBJEXT): {$(VPATH)}shape.h
pack.$(OBJEXT): {$(VPATH)}st.h
pack.$(OBJEXT): {$(VPATH)}subst.h
-pack.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-pack.$(OBJEXT): {$(VPATH)}thread_native.h
pack.$(OBJEXT): {$(VPATH)}util.h
-pack.$(OBJEXT): {$(VPATH)}vm_core.h
-pack.$(OBJEXT): {$(VPATH)}vm_opts.h
-parse.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-parse.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-parse.$(OBJEXT): $(CCAN_DIR)/list/list.h
-parse.$(OBJEXT): $(CCAN_DIR)/str/str.h
parse.$(OBJEXT): $(hdrdir)/ruby.h
parse.$(OBJEXT): $(hdrdir)/ruby/ruby.h
parse.$(OBJEXT): $(top_srcdir)/internal/array.h
-parse.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
parse.$(OBJEXT): $(top_srcdir)/internal/bignum.h
parse.$(OBJEXT): $(top_srcdir)/internal/bits.h
parse.$(OBJEXT): $(top_srcdir)/internal/compile.h
@@ -11066,7 +10949,6 @@ parse.$(OBJEXT): $(top_srcdir)/internal/numeric.h
parse.$(OBJEXT): $(top_srcdir)/internal/parse.h
parse.$(OBJEXT): $(top_srcdir)/internal/rational.h
parse.$(OBJEXT): $(top_srcdir)/internal/re.h
-parse.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
parse.$(OBJEXT): $(top_srcdir)/internal/serial.h
parse.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
parse.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -11076,7 +10958,6 @@ parse.$(OBJEXT): $(top_srcdir)/internal/variable.h
parse.$(OBJEXT): $(top_srcdir)/internal/vm.h
parse.$(OBJEXT): $(top_srcdir)/internal/warnings.h
parse.$(OBJEXT): {$(VPATH)}assert.h
-parse.$(OBJEXT): {$(VPATH)}atomic.h
parse.$(OBJEXT): {$(VPATH)}backward/2/assume.h
parse.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
parse.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -11133,7 +11014,6 @@ parse.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -11202,6 +11082,7 @@ parse.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/error.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -11232,6 +11113,7 @@ parse.$(OBJEXT): {$(VPATH)}internal/memory.h
parse.$(OBJEXT): {$(VPATH)}internal/method.h
parse.$(OBJEXT): {$(VPATH)}internal/module.h
parse.$(OBJEXT): {$(VPATH)}internal/newobj.h
+parse.$(OBJEXT): {$(VPATH)}internal/rgengc.h
parse.$(OBJEXT): {$(VPATH)}internal/scan_args.h
parse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
parse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -11245,7 +11127,6 @@ parse.$(OBJEXT): {$(VPATH)}internal/warning_push.h
parse.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
parse.$(OBJEXT): {$(VPATH)}io.h
parse.$(OBJEXT): {$(VPATH)}lex.c
-parse.$(OBJEXT): {$(VPATH)}method.h
parse.$(OBJEXT): {$(VPATH)}missing.h
parse.$(OBJEXT): {$(VPATH)}node.h
parse.$(OBJEXT): {$(VPATH)}onigmo.h
@@ -11253,1148 +11134,17 @@ parse.$(OBJEXT): {$(VPATH)}oniguruma.h
parse.$(OBJEXT): {$(VPATH)}parse.c
parse.$(OBJEXT): {$(VPATH)}parse.h
parse.$(OBJEXT): {$(VPATH)}parse.y
-parse.$(OBJEXT): {$(VPATH)}parser_node.h
-parse.$(OBJEXT): {$(VPATH)}parser_st.h
parse.$(OBJEXT): {$(VPATH)}probes.dmyh
parse.$(OBJEXT): {$(VPATH)}probes.h
parse.$(OBJEXT): {$(VPATH)}ractor.h
parse.$(OBJEXT): {$(VPATH)}regenc.h
parse.$(OBJEXT): {$(VPATH)}regex.h
parse.$(OBJEXT): {$(VPATH)}ruby_assert.h
-parse.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-parse.$(OBJEXT): {$(VPATH)}rubyparser.h
parse.$(OBJEXT): {$(VPATH)}shape.h
parse.$(OBJEXT): {$(VPATH)}st.h
parse.$(OBJEXT): {$(VPATH)}subst.h
parse.$(OBJEXT): {$(VPATH)}symbol.h
-parse.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-parse.$(OBJEXT): {$(VPATH)}thread_native.h
parse.$(OBJEXT): {$(VPATH)}util.h
-parse.$(OBJEXT): {$(VPATH)}vm_core.h
-parse.$(OBJEXT): {$(VPATH)}vm_opts.h
-parser_st.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-parser_st.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-parser_st.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-parser_st.$(OBJEXT): {$(VPATH)}assert.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-parser_st.$(OBJEXT): {$(VPATH)}config.h
-parser_st.$(OBJEXT): {$(VPATH)}defines.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/assume.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/cast.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/config.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/dosish.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-parser_st.$(OBJEXT): {$(VPATH)}missing.h
-parser_st.$(OBJEXT): {$(VPATH)}parser_bits.h
-parser_st.$(OBJEXT): {$(VPATH)}parser_st.c
-parser_st.$(OBJEXT): {$(VPATH)}parser_st.h
-parser_st.$(OBJEXT): {$(VPATH)}parser_value.h
-parser_st.$(OBJEXT): {$(VPATH)}st.c
-prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h
-prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/api_node.$(OBJEXT): {$(VPATH)}assert.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism/api_node.$(OBJEXT): {$(VPATH)}config.h
-prism/api_node.$(OBJEXT): {$(VPATH)}defines.h
-prism/api_node.$(OBJEXT): {$(VPATH)}encoding.h
-prism/api_node.$(OBJEXT): {$(VPATH)}intern.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/config.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/error.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/event.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/method.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/module.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/value.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}missing.h
-prism/api_node.$(OBJEXT): {$(VPATH)}onigmo.h
-prism/api_node.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism/api_node.$(OBJEXT): {$(VPATH)}prism/api_node.c
-prism/api_node.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/api_node.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/api_node.$(OBJEXT): {$(VPATH)}st.h
-prism/api_node.$(OBJEXT): {$(VPATH)}subst.h
-prism/api_pack.$(OBJEXT): $(hdrdir)/ruby.h
-prism/api_pack.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/api_pack.c
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}assert.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}config.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}defines.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}encoding.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}intern.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/config.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/error.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/event.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/method.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/module.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/value.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}missing.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}onigmo.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}st.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}subst.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.c
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/diagnostic.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_ascii.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_ascii.$(OBJEXT): $(top_srcdir)/prism/enc/pm_ascii.c
-prism/enc/pm_ascii.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_ascii.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_big5.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_big5.$(OBJEXT): $(top_srcdir)/prism/enc/pm_big5.c
-prism/enc/pm_big5.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_big5.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_euc_jp.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_euc_jp.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_euc_jp.$(OBJEXT): $(top_srcdir)/prism/enc/pm_euc_jp.c
-prism/enc/pm_euc_jp.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_gbk.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_gbk.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_gbk.$(OBJEXT): $(top_srcdir)/prism/enc/pm_gbk.c
-prism/enc/pm_gbk.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_1.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_1.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_1.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_1.c
-prism/enc/pm_iso_8859_1.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_10.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_10.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_10.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_10.c
-prism/enc/pm_iso_8859_10.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_11.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_11.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_11.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_11.c
-prism/enc/pm_iso_8859_11.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_13.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_13.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_13.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_13.c
-prism/enc/pm_iso_8859_13.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_14.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_14.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_14.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_14.c
-prism/enc/pm_iso_8859_14.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_15.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_15.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_15.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_15.c
-prism/enc/pm_iso_8859_15.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_16.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_16.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_16.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_16.c
-prism/enc/pm_iso_8859_16.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_2.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_2.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_2.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_2.c
-prism/enc/pm_iso_8859_2.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_3.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_3.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_3.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_3.c
-prism/enc/pm_iso_8859_3.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_4.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_4.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_4.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_4.c
-prism/enc/pm_iso_8859_4.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_5.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_5.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_5.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_5.c
-prism/enc/pm_iso_8859_5.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_6.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_6.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_6.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_6.c
-prism/enc/pm_iso_8859_6.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_7.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_7.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_7.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_7.c
-prism/enc/pm_iso_8859_7.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_8.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_8.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_8.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_8.c
-prism/enc/pm_iso_8859_8.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_iso_8859_9.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_iso_8859_9.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_iso_8859_9.$(OBJEXT): $(top_srcdir)/prism/enc/pm_iso_8859_9.c
-prism/enc/pm_iso_8859_9.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_koi8_r.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_koi8_r.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_koi8_r.$(OBJEXT): $(top_srcdir)/prism/enc/pm_koi8_r.c
-prism/enc/pm_koi8_r.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_shared.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_shared.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_shared.$(OBJEXT): $(top_srcdir)/prism/enc/pm_shared.c
-prism/enc/pm_shared.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_shift_jis.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_shift_jis.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_shift_jis.$(OBJEXT): $(top_srcdir)/prism/enc/pm_shift_jis.c
-prism/enc/pm_shift_jis.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_tables.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_tables.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_tables.$(OBJEXT): $(top_srcdir)/prism/enc/pm_tables.c
-prism/enc/pm_tables.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_unicode.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_unicode.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_unicode.$(OBJEXT): $(top_srcdir)/prism/enc/pm_unicode.c
-prism/enc/pm_unicode.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_windows_1251.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_windows_1251.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_windows_1251.$(OBJEXT): $(top_srcdir)/prism/enc/pm_windows_1251.c
-prism/enc/pm_windows_1251.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_windows_1252.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_windows_1252.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_windows_1252.$(OBJEXT): $(top_srcdir)/prism/enc/pm_windows_1252.c
-prism/enc/pm_windows_1252.$(OBJEXT): {$(VPATH)}config.h
-prism/enc/pm_windows_31j.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/enc/pm_windows_31j.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/enc/pm_windows_31j.$(OBJEXT): $(top_srcdir)/prism/enc/pm_windows_31j.c
-prism/enc/pm_windows_31j.$(OBJEXT): {$(VPATH)}config.h
-prism/extension.$(OBJEXT): $(hdrdir)/ruby.h
-prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.c
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/extension.$(OBJEXT): {$(VPATH)}assert.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism/extension.$(OBJEXT): {$(VPATH)}config.h
-prism/extension.$(OBJEXT): {$(VPATH)}defines.h
-prism/extension.$(OBJEXT): {$(VPATH)}encoding.h
-prism/extension.$(OBJEXT): {$(VPATH)}intern.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/config.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/error.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/event.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/method.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/module.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/value.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism/extension.$(OBJEXT): {$(VPATH)}missing.h
-prism/extension.$(OBJEXT): {$(VPATH)}onigmo.h
-prism/extension.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism/extension.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/extension.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/extension.$(OBJEXT): {$(VPATH)}st.h
-prism/extension.$(OBJEXT): {$(VPATH)}subst.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/node.$(OBJEXT): {$(VPATH)}config.h
-prism/node.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/node.$(OBJEXT): {$(VPATH)}prism/node.c
-prism/options.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/options.$(OBJEXT): $(top_srcdir)/prism/options.c
-prism/options.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/pack.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/pack.$(OBJEXT): $(top_srcdir)/prism/pack.c
-prism/pack.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/pack.$(OBJEXT): {$(VPATH)}config.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/prettyprint.$(OBJEXT): {$(VPATH)}config.h
-prism/prettyprint.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/prettyprint.$(OBJEXT): {$(VPATH)}prism/prettyprint.c
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/prism.c
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/version.h
-prism/prism.$(OBJEXT): {$(VPATH)}config.h
-prism/prism.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/prism.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/regexp.c
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/regexp.$(OBJEXT): {$(VPATH)}config.h
-prism/regexp.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/serialize.$(OBJEXT): {$(VPATH)}config.h
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/serialize.c
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/token_type.$(OBJEXT): {$(VPATH)}config.h
-prism/token_type.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/token_type.$(OBJEXT): {$(VPATH)}prism/token_type.c
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.c
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/util/pm_buffer.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.c
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_char.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.c
-prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/util/pm_constant_pool.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.c
-prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/util/pm_list.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.c
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.c
-prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_newline_list.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_state_stack.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_state_stack.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.c
-prism/util/pm_state_stack.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/util/pm_state_stack.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.c
-prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/util/pm_string.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_string_list.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_string_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/util/pm_string_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.c
-prism/util/pm_string_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism/util/pm_string_list.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.c
-prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.c
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}config.h
-prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism_init.$(OBJEXT): $(hdrdir)/ruby.h
-prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism_init.c
-prism_init.$(OBJEXT): {$(VPATH)}assert.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism_init.$(OBJEXT): {$(VPATH)}config.h
-prism_init.$(OBJEXT): {$(VPATH)}defines.h
-prism_init.$(OBJEXT): {$(VPATH)}encoding.h
-prism_init.$(OBJEXT): {$(VPATH)}intern.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/config.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/error.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/event.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/method.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/module.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/value.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism_init.$(OBJEXT): {$(VPATH)}missing.h
-prism_init.$(OBJEXT): {$(VPATH)}onigmo.h
-prism_init.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism_init.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism_init.$(OBJEXT): {$(VPATH)}prism/version.h
-prism_init.$(OBJEXT): {$(VPATH)}prism_init.c
-prism_init.$(OBJEXT): {$(VPATH)}st.h
-prism_init.$(OBJEXT): {$(VPATH)}subst.h
proc.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
proc.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
proc.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -12407,6 +11157,7 @@ proc.$(OBJEXT): $(top_srcdir)/internal/compilers.h
proc.$(OBJEXT): $(top_srcdir)/internal/error.h
proc.$(OBJEXT): $(top_srcdir)/internal/eval.h
proc.$(OBJEXT): $(top_srcdir)/internal/gc.h
+proc.$(OBJEXT): $(top_srcdir)/internal/hash.h
proc.$(OBJEXT): $(top_srcdir)/internal/imemo.h
proc.$(OBJEXT): $(top_srcdir)/internal/object.h
proc.$(OBJEXT): $(top_srcdir)/internal/proc.h
@@ -12433,6 +11184,7 @@ proc.$(OBJEXT): {$(VPATH)}constant.h
proc.$(OBJEXT): {$(VPATH)}defines.h
proc.$(OBJEXT): {$(VPATH)}encoding.h
proc.$(OBJEXT): {$(VPATH)}eval_intern.h
+proc.$(OBJEXT): {$(VPATH)}gc.h
proc.$(OBJEXT): {$(VPATH)}id.h
proc.$(OBJEXT): {$(VPATH)}id_table.h
proc.$(OBJEXT): {$(VPATH)}intern.h
@@ -12475,7 +11227,6 @@ proc.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -12544,6 +11295,7 @@ proc.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/error.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -12574,6 +11326,7 @@ proc.$(OBJEXT): {$(VPATH)}internal/memory.h
proc.$(OBJEXT): {$(VPATH)}internal/method.h
proc.$(OBJEXT): {$(VPATH)}internal/module.h
proc.$(OBJEXT): {$(VPATH)}internal/newobj.h
+proc.$(OBJEXT): {$(VPATH)}internal/rgengc.h
proc.$(OBJEXT): {$(VPATH)}internal/scan_args.h
proc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
proc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -12594,7 +11347,6 @@ proc.$(OBJEXT): {$(VPATH)}oniguruma.h
proc.$(OBJEXT): {$(VPATH)}proc.c
proc.$(OBJEXT): {$(VPATH)}ruby_assert.h
proc.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-proc.$(OBJEXT): {$(VPATH)}rubyparser.h
proc.$(OBJEXT): {$(VPATH)}shape.h
proc.$(OBJEXT): {$(VPATH)}st.h
proc.$(OBJEXT): {$(VPATH)}subst.h
@@ -12622,7 +11374,6 @@ process.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
process.$(OBJEXT): $(top_srcdir)/internal/gc.h
process.$(OBJEXT): $(top_srcdir)/internal/hash.h
process.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-process.$(OBJEXT): $(top_srcdir)/internal/io.h
process.$(OBJEXT): $(top_srcdir)/internal/numeric.h
process.$(OBJEXT): $(top_srcdir)/internal/object.h
process.$(OBJEXT): $(top_srcdir)/internal/process.h
@@ -12695,7 +11446,6 @@ process.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
process.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
process.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
process.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
process.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
process.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
process.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -12764,6 +11514,7 @@ process.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
process.$(OBJEXT): {$(VPATH)}internal/intern/error.h
process.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
process.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
process.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
process.$(OBJEXT): {$(VPATH)}internal/intern/io.h
process.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -12794,6 +11545,7 @@ process.$(OBJEXT): {$(VPATH)}internal/memory.h
process.$(OBJEXT): {$(VPATH)}internal/method.h
process.$(OBJEXT): {$(VPATH)}internal/module.h
process.$(OBJEXT): {$(VPATH)}internal/newobj.h
+process.$(OBJEXT): {$(VPATH)}internal/rgengc.h
process.$(OBJEXT): {$(VPATH)}internal/scan_args.h
process.$(OBJEXT): {$(VPATH)}internal/special_consts.h
process.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -12808,15 +11560,14 @@ process.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
process.$(OBJEXT): {$(VPATH)}io.h
process.$(OBJEXT): {$(VPATH)}method.h
process.$(OBJEXT): {$(VPATH)}missing.h
+process.$(OBJEXT): {$(VPATH)}mjit.h
process.$(OBJEXT): {$(VPATH)}node.h
process.$(OBJEXT): {$(VPATH)}onigmo.h
process.$(OBJEXT): {$(VPATH)}oniguruma.h
process.$(OBJEXT): {$(VPATH)}process.c
process.$(OBJEXT): {$(VPATH)}ractor.h
-process.$(OBJEXT): {$(VPATH)}rjit.h
process.$(OBJEXT): {$(VPATH)}ruby_assert.h
process.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-process.$(OBJEXT): {$(VPATH)}rubyparser.h
process.$(OBJEXT): {$(VPATH)}shape.h
process.$(OBJEXT): {$(VPATH)}st.h
process.$(OBJEXT): {$(VPATH)}subst.h
@@ -12825,9 +11576,7 @@ process.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
process.$(OBJEXT): {$(VPATH)}thread_native.h
process.$(OBJEXT): {$(VPATH)}util.h
process.$(OBJEXT): {$(VPATH)}vm_core.h
-process.$(OBJEXT): {$(VPATH)}vm_debug.h
process.$(OBJEXT): {$(VPATH)}vm_opts.h
-process.$(OBJEXT): {$(VPATH)}vm_sync.h
ractor.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
ractor.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
ractor.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -12872,7 +11621,7 @@ ractor.$(OBJEXT): {$(VPATH)}constant.h
ractor.$(OBJEXT): {$(VPATH)}debug_counter.h
ractor.$(OBJEXT): {$(VPATH)}defines.h
ractor.$(OBJEXT): {$(VPATH)}encoding.h
-ractor.$(OBJEXT): {$(VPATH)}eval_intern.h
+ractor.$(OBJEXT): {$(VPATH)}gc.h
ractor.$(OBJEXT): {$(VPATH)}id.h
ractor.$(OBJEXT): {$(VPATH)}id_table.h
ractor.$(OBJEXT): {$(VPATH)}intern.h
@@ -12915,7 +11664,6 @@ ractor.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -12984,6 +11732,7 @@ ractor.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/error.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/io.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13014,6 +11763,7 @@ ractor.$(OBJEXT): {$(VPATH)}internal/memory.h
ractor.$(OBJEXT): {$(VPATH)}internal/method.h
ractor.$(OBJEXT): {$(VPATH)}internal/module.h
ractor.$(OBJEXT): {$(VPATH)}internal/newobj.h
+ractor.$(OBJEXT): {$(VPATH)}internal/rgengc.h
ractor.$(OBJEXT): {$(VPATH)}internal/scan_args.h
ractor.$(OBJEXT): {$(VPATH)}internal/special_consts.h
ractor.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -13027,6 +11777,7 @@ ractor.$(OBJEXT): {$(VPATH)}internal/warning_push.h
ractor.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
ractor.$(OBJEXT): {$(VPATH)}method.h
ractor.$(OBJEXT): {$(VPATH)}missing.h
+ractor.$(OBJEXT): {$(VPATH)}mjit.h
ractor.$(OBJEXT): {$(VPATH)}node.h
ractor.$(OBJEXT): {$(VPATH)}onigmo.h
ractor.$(OBJEXT): {$(VPATH)}oniguruma.h
@@ -13034,35 +11785,28 @@ ractor.$(OBJEXT): {$(VPATH)}ractor.c
ractor.$(OBJEXT): {$(VPATH)}ractor.h
ractor.$(OBJEXT): {$(VPATH)}ractor.rbinc
ractor.$(OBJEXT): {$(VPATH)}ractor_core.h
-ractor.$(OBJEXT): {$(VPATH)}rjit.h
ractor.$(OBJEXT): {$(VPATH)}ruby_assert.h
ractor.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-ractor.$(OBJEXT): {$(VPATH)}rubyparser.h
ractor.$(OBJEXT): {$(VPATH)}shape.h
ractor.$(OBJEXT): {$(VPATH)}st.h
ractor.$(OBJEXT): {$(VPATH)}subst.h
ractor.$(OBJEXT): {$(VPATH)}thread.h
ractor.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
ractor.$(OBJEXT): {$(VPATH)}thread_native.h
+ractor.$(OBJEXT): {$(VPATH)}transient_heap.h
ractor.$(OBJEXT): {$(VPATH)}variable.h
ractor.$(OBJEXT): {$(VPATH)}vm_core.h
ractor.$(OBJEXT): {$(VPATH)}vm_debug.h
ractor.$(OBJEXT): {$(VPATH)}vm_opts.h
ractor.$(OBJEXT): {$(VPATH)}vm_sync.h
ractor.$(OBJEXT): {$(VPATH)}yjit.h
-random.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-random.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-random.$(OBJEXT): $(CCAN_DIR)/list/list.h
-random.$(OBJEXT): $(CCAN_DIR)/str/str.h
random.$(OBJEXT): $(hdrdir)/ruby/ruby.h
random.$(OBJEXT): $(top_srcdir)/internal/array.h
-random.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
random.$(OBJEXT): $(top_srcdir)/internal/bignum.h
random.$(OBJEXT): $(top_srcdir)/internal/bits.h
random.$(OBJEXT): $(top_srcdir)/internal/compilers.h
random.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
random.$(OBJEXT): $(top_srcdir)/internal/gc.h
-random.$(OBJEXT): $(top_srcdir)/internal/imemo.h
random.$(OBJEXT): $(top_srcdir)/internal/numeric.h
random.$(OBJEXT): $(top_srcdir)/internal/random.h
random.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -13085,8 +11829,6 @@ random.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
random.$(OBJEXT): {$(VPATH)}config.h
random.$(OBJEXT): {$(VPATH)}constant.h
random.$(OBJEXT): {$(VPATH)}defines.h
-random.$(OBJEXT): {$(VPATH)}encoding.h
-random.$(OBJEXT): {$(VPATH)}id.h
random.$(OBJEXT): {$(VPATH)}id_table.h
random.$(OBJEXT): {$(VPATH)}intern.h
random.$(OBJEXT): {$(VPATH)}internal.h
@@ -13128,7 +11870,6 @@ random.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
random.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
random.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
random.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
random.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
random.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
random.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13161,15 +11902,6 @@ random.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
random.$(OBJEXT): {$(VPATH)}internal/ctype.h
random.$(OBJEXT): {$(VPATH)}internal/dllexport.h
random.$(OBJEXT): {$(VPATH)}internal/dosish.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
random.$(OBJEXT): {$(VPATH)}internal/error.h
random.$(OBJEXT): {$(VPATH)}internal/eval.h
random.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -13197,6 +11929,7 @@ random.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
random.$(OBJEXT): {$(VPATH)}internal/intern/error.h
random.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
random.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
random.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
random.$(OBJEXT): {$(VPATH)}internal/intern/io.h
random.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13227,6 +11960,7 @@ random.$(OBJEXT): {$(VPATH)}internal/memory.h
random.$(OBJEXT): {$(VPATH)}internal/method.h
random.$(OBJEXT): {$(VPATH)}internal/module.h
random.$(OBJEXT): {$(VPATH)}internal/newobj.h
+random.$(OBJEXT): {$(VPATH)}internal/rgengc.h
random.$(OBJEXT): {$(VPATH)}internal/scan_args.h
random.$(OBJEXT): {$(VPATH)}internal/special_consts.h
random.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -13238,27 +11972,17 @@ random.$(OBJEXT): {$(VPATH)}internal/value_type.h
random.$(OBJEXT): {$(VPATH)}internal/variable.h
random.$(OBJEXT): {$(VPATH)}internal/warning_push.h
random.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-random.$(OBJEXT): {$(VPATH)}method.h
random.$(OBJEXT): {$(VPATH)}missing.h
random.$(OBJEXT): {$(VPATH)}mt19937.c
-random.$(OBJEXT): {$(VPATH)}node.h
-random.$(OBJEXT): {$(VPATH)}onigmo.h
-random.$(OBJEXT): {$(VPATH)}oniguruma.h
random.$(OBJEXT): {$(VPATH)}ractor.h
random.$(OBJEXT): {$(VPATH)}random.c
random.$(OBJEXT): {$(VPATH)}random.h
-random.$(OBJEXT): {$(VPATH)}ruby_assert.h
random.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-random.$(OBJEXT): {$(VPATH)}rubyparser.h
random.$(OBJEXT): {$(VPATH)}shape.h
random.$(OBJEXT): {$(VPATH)}siphash.c
random.$(OBJEXT): {$(VPATH)}siphash.h
random.$(OBJEXT): {$(VPATH)}st.h
random.$(OBJEXT): {$(VPATH)}subst.h
-random.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-random.$(OBJEXT): {$(VPATH)}thread_native.h
-random.$(OBJEXT): {$(VPATH)}vm_core.h
-random.$(OBJEXT): {$(VPATH)}vm_opts.h
range.$(OBJEXT): $(hdrdir)/ruby/ruby.h
range.$(OBJEXT): $(top_srcdir)/internal/array.h
range.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
@@ -13333,7 +12057,6 @@ range.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
range.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
range.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
range.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
range.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
range.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
range.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13402,6 +12125,7 @@ range.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
range.$(OBJEXT): {$(VPATH)}internal/intern/error.h
range.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
range.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
range.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
range.$(OBJEXT): {$(VPATH)}internal/intern/io.h
range.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13432,6 +12156,7 @@ range.$(OBJEXT): {$(VPATH)}internal/memory.h
range.$(OBJEXT): {$(VPATH)}internal/method.h
range.$(OBJEXT): {$(VPATH)}internal/module.h
range.$(OBJEXT): {$(VPATH)}internal/newobj.h
+range.$(OBJEXT): {$(VPATH)}internal/rgengc.h
range.$(OBJEXT): {$(VPATH)}internal/scan_args.h
range.$(OBJEXT): {$(VPATH)}internal/special_consts.h
range.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -13450,13 +12175,8 @@ range.$(OBJEXT): {$(VPATH)}range.c
range.$(OBJEXT): {$(VPATH)}shape.h
range.$(OBJEXT): {$(VPATH)}st.h
range.$(OBJEXT): {$(VPATH)}subst.h
-rational.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-rational.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-rational.$(OBJEXT): $(CCAN_DIR)/list/list.h
-rational.$(OBJEXT): $(CCAN_DIR)/str/str.h
rational.$(OBJEXT): $(hdrdir)/ruby/ruby.h
rational.$(OBJEXT): $(top_srcdir)/internal/array.h
-rational.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
rational.$(OBJEXT): $(top_srcdir)/internal/bignum.h
rational.$(OBJEXT): $(top_srcdir)/internal/bits.h
rational.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -13464,7 +12184,6 @@ rational.$(OBJEXT): $(top_srcdir)/internal/compilers.h
rational.$(OBJEXT): $(top_srcdir)/internal/complex.h
rational.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
rational.$(OBJEXT): $(top_srcdir)/internal/gc.h
-rational.$(OBJEXT): $(top_srcdir)/internal/imemo.h
rational.$(OBJEXT): $(top_srcdir)/internal/numeric.h
rational.$(OBJEXT): $(top_srcdir)/internal/object.h
rational.$(OBJEXT): $(top_srcdir)/internal/rational.h
@@ -13474,7 +12193,6 @@ rational.$(OBJEXT): $(top_srcdir)/internal/variable.h
rational.$(OBJEXT): $(top_srcdir)/internal/vm.h
rational.$(OBJEXT): $(top_srcdir)/internal/warnings.h
rational.$(OBJEXT): {$(VPATH)}assert.h
-rational.$(OBJEXT): {$(VPATH)}atomic.h
rational.$(OBJEXT): {$(VPATH)}backward/2/assume.h
rational.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
rational.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -13487,7 +12205,6 @@ rational.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
rational.$(OBJEXT): {$(VPATH)}config.h
rational.$(OBJEXT): {$(VPATH)}constant.h
rational.$(OBJEXT): {$(VPATH)}defines.h
-rational.$(OBJEXT): {$(VPATH)}encoding.h
rational.$(OBJEXT): {$(VPATH)}id.h
rational.$(OBJEXT): {$(VPATH)}id_table.h
rational.$(OBJEXT): {$(VPATH)}intern.h
@@ -13530,7 +12247,6 @@ rational.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13563,15 +12279,6 @@ rational.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
rational.$(OBJEXT): {$(VPATH)}internal/ctype.h
rational.$(OBJEXT): {$(VPATH)}internal/dllexport.h
rational.$(OBJEXT): {$(VPATH)}internal/dosish.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
rational.$(OBJEXT): {$(VPATH)}internal/error.h
rational.$(OBJEXT): {$(VPATH)}internal/eval.h
rational.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -13599,6 +12306,7 @@ rational.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/error.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/io.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13629,6 +12337,7 @@ rational.$(OBJEXT): {$(VPATH)}internal/memory.h
rational.$(OBJEXT): {$(VPATH)}internal/method.h
rational.$(OBJEXT): {$(VPATH)}internal/module.h
rational.$(OBJEXT): {$(VPATH)}internal/newobj.h
+rational.$(OBJEXT): {$(VPATH)}internal/rgengc.h
rational.$(OBJEXT): {$(VPATH)}internal/scan_args.h
rational.$(OBJEXT): {$(VPATH)}internal/special_consts.h
rational.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -13640,30 +12349,15 @@ rational.$(OBJEXT): {$(VPATH)}internal/value_type.h
rational.$(OBJEXT): {$(VPATH)}internal/variable.h
rational.$(OBJEXT): {$(VPATH)}internal/warning_push.h
rational.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-rational.$(OBJEXT): {$(VPATH)}method.h
rational.$(OBJEXT): {$(VPATH)}missing.h
-rational.$(OBJEXT): {$(VPATH)}node.h
-rational.$(OBJEXT): {$(VPATH)}onigmo.h
-rational.$(OBJEXT): {$(VPATH)}oniguruma.h
rational.$(OBJEXT): {$(VPATH)}rational.c
rational.$(OBJEXT): {$(VPATH)}ruby_assert.h
-rational.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-rational.$(OBJEXT): {$(VPATH)}rubyparser.h
rational.$(OBJEXT): {$(VPATH)}shape.h
rational.$(OBJEXT): {$(VPATH)}st.h
rational.$(OBJEXT): {$(VPATH)}subst.h
-rational.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-rational.$(OBJEXT): {$(VPATH)}thread_native.h
-rational.$(OBJEXT): {$(VPATH)}vm_core.h
-rational.$(OBJEXT): {$(VPATH)}vm_opts.h
-re.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-re.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-re.$(OBJEXT): $(CCAN_DIR)/list/list.h
-re.$(OBJEXT): $(CCAN_DIR)/str/str.h
re.$(OBJEXT): $(hdrdir)/ruby.h
re.$(OBJEXT): $(hdrdir)/ruby/ruby.h
re.$(OBJEXT): $(top_srcdir)/internal/array.h
-re.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
re.$(OBJEXT): $(top_srcdir)/internal/bits.h
re.$(OBJEXT): $(top_srcdir)/internal/class.h
re.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -13679,10 +12373,8 @@ re.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
re.$(OBJEXT): $(top_srcdir)/internal/string.h
re.$(OBJEXT): $(top_srcdir)/internal/time.h
re.$(OBJEXT): $(top_srcdir)/internal/variable.h
-re.$(OBJEXT): $(top_srcdir)/internal/vm.h
re.$(OBJEXT): $(top_srcdir)/internal/warnings.h
re.$(OBJEXT): {$(VPATH)}assert.h
-re.$(OBJEXT): {$(VPATH)}atomic.h
re.$(OBJEXT): {$(VPATH)}backward/2/assume.h
re.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
re.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -13698,7 +12390,6 @@ re.$(OBJEXT): {$(VPATH)}defines.h
re.$(OBJEXT): {$(VPATH)}encindex.h
re.$(OBJEXT): {$(VPATH)}encoding.h
re.$(OBJEXT): {$(VPATH)}hrtime.h
-re.$(OBJEXT): {$(VPATH)}id.h
re.$(OBJEXT): {$(VPATH)}id_table.h
re.$(OBJEXT): {$(VPATH)}intern.h
re.$(OBJEXT): {$(VPATH)}internal.h
@@ -13740,7 +12431,6 @@ re.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
re.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
re.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
re.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
re.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
re.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
re.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13810,6 +12500,7 @@ re.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
re.$(OBJEXT): {$(VPATH)}internal/intern/error.h
re.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
re.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
re.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
re.$(OBJEXT): {$(VPATH)}internal/intern/io.h
re.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13840,6 +12531,7 @@ re.$(OBJEXT): {$(VPATH)}internal/memory.h
re.$(OBJEXT): {$(VPATH)}internal/method.h
re.$(OBJEXT): {$(VPATH)}internal/module.h
re.$(OBJEXT): {$(VPATH)}internal/newobj.h
+re.$(OBJEXT): {$(VPATH)}internal/rgengc.h
re.$(OBJEXT): {$(VPATH)}internal/scan_args.h
re.$(OBJEXT): {$(VPATH)}internal/special_consts.h
re.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -13851,9 +12543,7 @@ re.$(OBJEXT): {$(VPATH)}internal/value_type.h
re.$(OBJEXT): {$(VPATH)}internal/variable.h
re.$(OBJEXT): {$(VPATH)}internal/warning_push.h
re.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-re.$(OBJEXT): {$(VPATH)}method.h
re.$(OBJEXT): {$(VPATH)}missing.h
-re.$(OBJEXT): {$(VPATH)}node.h
re.$(OBJEXT): {$(VPATH)}onigmo.h
re.$(OBJEXT): {$(VPATH)}oniguruma.h
re.$(OBJEXT): {$(VPATH)}re.c
@@ -13861,17 +12551,10 @@ re.$(OBJEXT): {$(VPATH)}re.h
re.$(OBJEXT): {$(VPATH)}regenc.h
re.$(OBJEXT): {$(VPATH)}regex.h
re.$(OBJEXT): {$(VPATH)}regint.h
-re.$(OBJEXT): {$(VPATH)}ruby_assert.h
-re.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-re.$(OBJEXT): {$(VPATH)}rubyparser.h
re.$(OBJEXT): {$(VPATH)}shape.h
re.$(OBJEXT): {$(VPATH)}st.h
re.$(OBJEXT): {$(VPATH)}subst.h
-re.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-re.$(OBJEXT): {$(VPATH)}thread_native.h
re.$(OBJEXT): {$(VPATH)}util.h
-re.$(OBJEXT): {$(VPATH)}vm_core.h
-re.$(OBJEXT): {$(VPATH)}vm_opts.h
regcomp.$(OBJEXT): $(hdrdir)/ruby.h
regcomp.$(OBJEXT): $(hdrdir)/ruby/ruby.h
regcomp.$(OBJEXT): {$(VPATH)}assert.h
@@ -13924,7 +12607,6 @@ regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13984,6 +12666,7 @@ regcomp.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14014,6 +12697,7 @@ regcomp.$(OBJEXT): {$(VPATH)}internal/memory.h
regcomp.$(OBJEXT): {$(VPATH)}internal/method.h
regcomp.$(OBJEXT): {$(VPATH)}internal/module.h
regcomp.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regcomp.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regcomp.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regcomp.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -14085,7 +12769,6 @@ regenc.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14145,6 +12828,7 @@ regenc.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14175,6 +12859,7 @@ regenc.$(OBJEXT): {$(VPATH)}internal/memory.h
regenc.$(OBJEXT): {$(VPATH)}internal/method.h
regenc.$(OBJEXT): {$(VPATH)}internal/module.h
regenc.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regenc.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regenc.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regenc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regenc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -14245,7 +12930,6 @@ regerror.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14305,6 +12989,7 @@ regerror.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14335,6 +13020,7 @@ regerror.$(OBJEXT): {$(VPATH)}internal/memory.h
regerror.$(OBJEXT): {$(VPATH)}internal/method.h
regerror.$(OBJEXT): {$(VPATH)}internal/module.h
regerror.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regerror.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regerror.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regerror.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regerror.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -14405,7 +13091,6 @@ regexec.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14465,6 +13150,7 @@ regexec.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14495,6 +13181,7 @@ regexec.$(OBJEXT): {$(VPATH)}internal/memory.h
regexec.$(OBJEXT): {$(VPATH)}internal/method.h
regexec.$(OBJEXT): {$(VPATH)}internal/module.h
regexec.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regexec.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regexec.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regexec.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regexec.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -14569,7 +13256,6 @@ regparse.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14629,6 +13315,7 @@ regparse.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14659,6 +13346,7 @@ regparse.$(OBJEXT): {$(VPATH)}internal/memory.h
regparse.$(OBJEXT): {$(VPATH)}internal/method.h
regparse.$(OBJEXT): {$(VPATH)}internal/module.h
regparse.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regparse.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regparse.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regparse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regparse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -14730,7 +13418,6 @@ regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14790,6 +13477,7 @@ regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14820,6 +13508,7 @@ regsyntax.$(OBJEXT): {$(VPATH)}internal/memory.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/method.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/module.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -14838,461 +13527,6 @@ regsyntax.$(OBJEXT): {$(VPATH)}regint.h
regsyntax.$(OBJEXT): {$(VPATH)}regsyntax.c
regsyntax.$(OBJEXT): {$(VPATH)}st.h
regsyntax.$(OBJEXT): {$(VPATH)}subst.h
-rjit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-rjit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-rjit.$(OBJEXT): $(CCAN_DIR)/list/list.h
-rjit.$(OBJEXT): $(CCAN_DIR)/str/str.h
-rjit.$(OBJEXT): $(hdrdir)/ruby.h
-rjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-rjit.$(OBJEXT): $(hdrdir)/ruby/version.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/array.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/class.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/file.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/process.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/string.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/struct.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-rjit.$(OBJEXT): {$(VPATH)}assert.h
-rjit.$(OBJEXT): {$(VPATH)}atomic.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-rjit.$(OBJEXT): {$(VPATH)}builtin.h
-rjit.$(OBJEXT): {$(VPATH)}config.h
-rjit.$(OBJEXT): {$(VPATH)}constant.h
-rjit.$(OBJEXT): {$(VPATH)}debug.h
-rjit.$(OBJEXT): {$(VPATH)}debug_counter.h
-rjit.$(OBJEXT): {$(VPATH)}defines.h
-rjit.$(OBJEXT): {$(VPATH)}dln.h
-rjit.$(OBJEXT): {$(VPATH)}encoding.h
-rjit.$(OBJEXT): {$(VPATH)}id.h
-rjit.$(OBJEXT): {$(VPATH)}id_table.h
-rjit.$(OBJEXT): {$(VPATH)}insns.def
-rjit.$(OBJEXT): {$(VPATH)}insns.inc
-rjit.$(OBJEXT): {$(VPATH)}insns_info.inc
-rjit.$(OBJEXT): {$(VPATH)}intern.h
-rjit.$(OBJEXT): {$(VPATH)}internal.h
-rjit.$(OBJEXT): {$(VPATH)}internal/abi.h
-rjit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/assume.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-rjit.$(OBJEXT): {$(VPATH)}internal/cast.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-rjit.$(OBJEXT): {$(VPATH)}internal/config.h
-rjit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-rjit.$(OBJEXT): {$(VPATH)}internal/ctype.h
-rjit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-rjit.$(OBJEXT): {$(VPATH)}internal/dosish.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-rjit.$(OBJEXT): {$(VPATH)}internal/error.h
-rjit.$(OBJEXT): {$(VPATH)}internal/eval.h
-rjit.$(OBJEXT): {$(VPATH)}internal/event.h
-rjit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-rjit.$(OBJEXT): {$(VPATH)}internal/gc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/glob.h
-rjit.$(OBJEXT): {$(VPATH)}internal/globals.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-rjit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-rjit.$(OBJEXT): {$(VPATH)}internal/iterator.h
-rjit.$(OBJEXT): {$(VPATH)}internal/memory.h
-rjit.$(OBJEXT): {$(VPATH)}internal/method.h
-rjit.$(OBJEXT): {$(VPATH)}internal/module.h
-rjit.$(OBJEXT): {$(VPATH)}internal/newobj.h
-rjit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-rjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-rjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-rjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-rjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-rjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
-rjit.$(OBJEXT): {$(VPATH)}internal/value.h
-rjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
-rjit.$(OBJEXT): {$(VPATH)}internal/variable.h
-rjit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-rjit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-rjit.$(OBJEXT): {$(VPATH)}iseq.h
-rjit.$(OBJEXT): {$(VPATH)}method.h
-rjit.$(OBJEXT): {$(VPATH)}missing.h
-rjit.$(OBJEXT): {$(VPATH)}node.h
-rjit.$(OBJEXT): {$(VPATH)}onigmo.h
-rjit.$(OBJEXT): {$(VPATH)}oniguruma.h
-rjit.$(OBJEXT): {$(VPATH)}ractor.h
-rjit.$(OBJEXT): {$(VPATH)}ractor_core.h
-rjit.$(OBJEXT): {$(VPATH)}rjit.c
-rjit.$(OBJEXT): {$(VPATH)}rjit.h
-rjit.$(OBJEXT): {$(VPATH)}rjit.rbinc
-rjit.$(OBJEXT): {$(VPATH)}rjit_c.h
-rjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
-rjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-rjit.$(OBJEXT): {$(VPATH)}rubyparser.h
-rjit.$(OBJEXT): {$(VPATH)}shape.h
-rjit.$(OBJEXT): {$(VPATH)}st.h
-rjit.$(OBJEXT): {$(VPATH)}subst.h
-rjit.$(OBJEXT): {$(VPATH)}thread.h
-rjit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-rjit.$(OBJEXT): {$(VPATH)}thread_native.h
-rjit.$(OBJEXT): {$(VPATH)}util.h
-rjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-rjit.$(OBJEXT): {$(VPATH)}vm_core.h
-rjit.$(OBJEXT): {$(VPATH)}vm_debug.h
-rjit.$(OBJEXT): {$(VPATH)}vm_opts.h
-rjit.$(OBJEXT): {$(VPATH)}vm_sync.h
-rjit.$(OBJEXT): {$(VPATH)}yjit.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/list/list.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/str/str.h
-rjit_c.$(OBJEXT): $(hdrdir)/ruby.h
-rjit_c.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-rjit_c.$(OBJEXT): $(srcdir)/rjit_c.rb
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/array.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/class.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/compile.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/gc.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/hash.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/object.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/proc.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/serial.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/string.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/struct.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/variable.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/vm.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-rjit_c.$(OBJEXT): {$(VPATH)}assert.h
-rjit_c.$(OBJEXT): {$(VPATH)}atomic.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-rjit_c.$(OBJEXT): {$(VPATH)}builtin.h
-rjit_c.$(OBJEXT): {$(VPATH)}config.h
-rjit_c.$(OBJEXT): {$(VPATH)}constant.h
-rjit_c.$(OBJEXT): {$(VPATH)}debug.h
-rjit_c.$(OBJEXT): {$(VPATH)}debug_counter.h
-rjit_c.$(OBJEXT): {$(VPATH)}defines.h
-rjit_c.$(OBJEXT): {$(VPATH)}encoding.h
-rjit_c.$(OBJEXT): {$(VPATH)}id.h
-rjit_c.$(OBJEXT): {$(VPATH)}id_table.h
-rjit_c.$(OBJEXT): {$(VPATH)}insns.def
-rjit_c.$(OBJEXT): {$(VPATH)}insns.inc
-rjit_c.$(OBJEXT): {$(VPATH)}insns_info.inc
-rjit_c.$(OBJEXT): {$(VPATH)}intern.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/abi.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/assume.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/cast.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/config.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/ctype.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/dosish.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/error.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/eval.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/event.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/gc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/glob.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/globals.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/iterator.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/memory.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/method.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/module.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/newobj.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/symbol.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/value.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/value_type.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/variable.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-rjit_c.$(OBJEXT): {$(VPATH)}iseq.h
-rjit_c.$(OBJEXT): {$(VPATH)}method.h
-rjit_c.$(OBJEXT): {$(VPATH)}missing.h
-rjit_c.$(OBJEXT): {$(VPATH)}node.h
-rjit_c.$(OBJEXT): {$(VPATH)}onigmo.h
-rjit_c.$(OBJEXT): {$(VPATH)}oniguruma.h
-rjit_c.$(OBJEXT): {$(VPATH)}probes.dmyh
-rjit_c.$(OBJEXT): {$(VPATH)}probes.h
-rjit_c.$(OBJEXT): {$(VPATH)}probes_helper.h
-rjit_c.$(OBJEXT): {$(VPATH)}rjit.h
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.c
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.h
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.rb
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.rbinc
-rjit_c.$(OBJEXT): {$(VPATH)}ruby_assert.h
-rjit_c.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-rjit_c.$(OBJEXT): {$(VPATH)}rubyparser.h
-rjit_c.$(OBJEXT): {$(VPATH)}shape.h
-rjit_c.$(OBJEXT): {$(VPATH)}st.h
-rjit_c.$(OBJEXT): {$(VPATH)}subst.h
-rjit_c.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-rjit_c.$(OBJEXT): {$(VPATH)}thread_native.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_core.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_exec.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_opts.h
-rjit_c.$(OBJEXT): {$(VPATH)}yjit.h
ruby-runner.$(OBJEXT): {$(VPATH)}config.h
ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
@@ -15329,35 +13563,13 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/loadpath.h
ruby.$(OBJEXT): $(top_srcdir)/internal/missing.h
ruby.$(OBJEXT): $(top_srcdir)/internal/object.h
ruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/process.h
ruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
ruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
ruby.$(OBJEXT): $(top_srcdir)/internal/string.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/thread.h
ruby.$(OBJEXT): $(top_srcdir)/internal/variable.h
ruby.$(OBJEXT): $(top_srcdir)/internal/vm.h
ruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/defines.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/enc/pm_encoding.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/node.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/options.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/pack.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/parser.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/prism.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
ruby.$(OBJEXT): {$(VPATH)}assert.h
ruby.$(OBJEXT): {$(VPATH)}atomic.h
ruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -15418,7 +13630,6 @@ ruby.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -15487,6 +13698,7 @@ ruby.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/error.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -15517,6 +13729,7 @@ ruby.$(OBJEXT): {$(VPATH)}internal/memory.h
ruby.$(OBJEXT): {$(VPATH)}internal/method.h
ruby.$(OBJEXT): {$(VPATH)}internal/module.h
ruby.$(OBJEXT): {$(VPATH)}internal/newobj.h
+ruby.$(OBJEXT): {$(VPATH)}internal/rgengc.h
ruby.$(OBJEXT): {$(VPATH)}internal/scan_args.h
ruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
ruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -15532,17 +13745,13 @@ ruby.$(OBJEXT): {$(VPATH)}io.h
ruby.$(OBJEXT): {$(VPATH)}iseq.h
ruby.$(OBJEXT): {$(VPATH)}method.h
ruby.$(OBJEXT): {$(VPATH)}missing.h
+ruby.$(OBJEXT): {$(VPATH)}mjit.h
ruby.$(OBJEXT): {$(VPATH)}node.h
ruby.$(OBJEXT): {$(VPATH)}onigmo.h
ruby.$(OBJEXT): {$(VPATH)}oniguruma.h
-ruby.$(OBJEXT): {$(VPATH)}prism/ast.h
-ruby.$(OBJEXT): {$(VPATH)}prism/version.h
-ruby.$(OBJEXT): {$(VPATH)}prism_compile.h
-ruby.$(OBJEXT): {$(VPATH)}rjit.h
ruby.$(OBJEXT): {$(VPATH)}ruby.c
ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-ruby.$(OBJEXT): {$(VPATH)}rubyparser.h
ruby.$(OBJEXT): {$(VPATH)}shape.h
ruby.$(OBJEXT): {$(VPATH)}st.h
ruby.$(OBJEXT): {$(VPATH)}subst.h
@@ -15553,7 +13762,6 @@ ruby.$(OBJEXT): {$(VPATH)}util.h
ruby.$(OBJEXT): {$(VPATH)}vm_core.h
ruby.$(OBJEXT): {$(VPATH)}vm_opts.h
ruby.$(OBJEXT): {$(VPATH)}yjit.h
-ruby_parser.$(OBJEXT): {$(VPATH)}ruby_parser.c
scheduler.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
scheduler.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
scheduler.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -15628,7 +13836,6 @@ scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -15697,6 +13904,7 @@ scheduler.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/error.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/io.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -15727,6 +13935,7 @@ scheduler.$(OBJEXT): {$(VPATH)}internal/memory.h
scheduler.$(OBJEXT): {$(VPATH)}internal/method.h
scheduler.$(OBJEXT): {$(VPATH)}internal/module.h
scheduler.$(OBJEXT): {$(VPATH)}internal/newobj.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/rgengc.h
scheduler.$(OBJEXT): {$(VPATH)}internal/scan_args.h
scheduler.$(OBJEXT): {$(VPATH)}internal/special_consts.h
scheduler.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -15747,7 +13956,6 @@ scheduler.$(OBJEXT): {$(VPATH)}onigmo.h
scheduler.$(OBJEXT): {$(VPATH)}oniguruma.h
scheduler.$(OBJEXT): {$(VPATH)}ruby_assert.h
scheduler.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-scheduler.$(OBJEXT): {$(VPATH)}rubyparser.h
scheduler.$(OBJEXT): {$(VPATH)}scheduler.c
scheduler.$(OBJEXT): {$(VPATH)}shape.h
scheduler.$(OBJEXT): {$(VPATH)}st.h
@@ -15808,7 +14016,6 @@ setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -15868,6 +14075,7 @@ setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/error.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/io.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -15898,6 +14106,7 @@ setproctitle.$(OBJEXT): {$(VPATH)}internal/memory.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/method.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/module.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/newobj.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/rgengc.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/scan_args.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/special_consts.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -15923,12 +14132,10 @@ shape.$(OBJEXT): $(top_srcdir)/internal/array.h
shape.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
shape.$(OBJEXT): $(top_srcdir)/internal/class.h
shape.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-shape.$(OBJEXT): $(top_srcdir)/internal/error.h
shape.$(OBJEXT): $(top_srcdir)/internal/gc.h
shape.$(OBJEXT): $(top_srcdir)/internal/imemo.h
shape.$(OBJEXT): $(top_srcdir)/internal/serial.h
shape.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-shape.$(OBJEXT): $(top_srcdir)/internal/string.h
shape.$(OBJEXT): $(top_srcdir)/internal/symbol.h
shape.$(OBJEXT): $(top_srcdir)/internal/variable.h
shape.$(OBJEXT): $(top_srcdir)/internal/vm.h
@@ -15949,6 +14156,7 @@ shape.$(OBJEXT): {$(VPATH)}constant.h
shape.$(OBJEXT): {$(VPATH)}debug_counter.h
shape.$(OBJEXT): {$(VPATH)}defines.h
shape.$(OBJEXT): {$(VPATH)}encoding.h
+shape.$(OBJEXT): {$(VPATH)}gc.h
shape.$(OBJEXT): {$(VPATH)}id.h
shape.$(OBJEXT): {$(VPATH)}id_table.h
shape.$(OBJEXT): {$(VPATH)}intern.h
@@ -15991,7 +14199,6 @@ shape.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16060,6 +14267,7 @@ shape.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/error.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/io.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16090,6 +14298,7 @@ shape.$(OBJEXT): {$(VPATH)}internal/memory.h
shape.$(OBJEXT): {$(VPATH)}internal/method.h
shape.$(OBJEXT): {$(VPATH)}internal/module.h
shape.$(OBJEXT): {$(VPATH)}internal/newobj.h
+shape.$(OBJEXT): {$(VPATH)}internal/rgengc.h
shape.$(OBJEXT): {$(VPATH)}internal/scan_args.h
shape.$(OBJEXT): {$(VPATH)}internal/special_consts.h
shape.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -16108,7 +14317,6 @@ shape.$(OBJEXT): {$(VPATH)}onigmo.h
shape.$(OBJEXT): {$(VPATH)}oniguruma.h
shape.$(OBJEXT): {$(VPATH)}ruby_assert.h
shape.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-shape.$(OBJEXT): {$(VPATH)}rubyparser.h
shape.$(OBJEXT): {$(VPATH)}shape.c
shape.$(OBJEXT): {$(VPATH)}shape.h
shape.$(OBJEXT): {$(VPATH)}st.h
@@ -16129,7 +14337,6 @@ signal.$(OBJEXT): $(hdrdir)/ruby/ruby.h
signal.$(OBJEXT): $(top_srcdir)/internal/array.h
signal.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
signal.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-signal.$(OBJEXT): $(top_srcdir)/internal/error.h
signal.$(OBJEXT): $(top_srcdir)/internal/eval.h
signal.$(OBJEXT): $(top_srcdir)/internal/gc.h
signal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
@@ -16200,8 +14407,8 @@ signal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16270,6 +14477,7 @@ signal.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/error.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16300,6 +14508,7 @@ signal.$(OBJEXT): {$(VPATH)}internal/memory.h
signal.$(OBJEXT): {$(VPATH)}internal/method.h
signal.$(OBJEXT): {$(VPATH)}internal/module.h
signal.$(OBJEXT): {$(VPATH)}internal/newobj.h
+signal.$(OBJEXT): {$(VPATH)}internal/rgengc.h
signal.$(OBJEXT): {$(VPATH)}internal/scan_args.h
signal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
signal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -16320,7 +14529,6 @@ signal.$(OBJEXT): {$(VPATH)}ractor.h
signal.$(OBJEXT): {$(VPATH)}ractor_core.h
signal.$(OBJEXT): {$(VPATH)}ruby_assert.h
signal.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-signal.$(OBJEXT): {$(VPATH)}rubyparser.h
signal.$(OBJEXT): {$(VPATH)}shape.h
signal.$(OBJEXT): {$(VPATH)}signal.c
signal.$(OBJEXT): {$(VPATH)}st.h
@@ -16405,7 +14613,6 @@ sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16475,6 +14682,7 @@ sprintf.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/error.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/io.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16505,6 +14713,7 @@ sprintf.$(OBJEXT): {$(VPATH)}internal/memory.h
sprintf.$(OBJEXT): {$(VPATH)}internal/method.h
sprintf.$(OBJEXT): {$(VPATH)}internal/module.h
sprintf.$(OBJEXT): {$(VPATH)}internal/newobj.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/rgengc.h
sprintf.$(OBJEXT): {$(VPATH)}internal/scan_args.h
sprintf.$(OBJEXT): {$(VPATH)}internal/special_consts.h
sprintf.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -16586,7 +14795,6 @@ st.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
st.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
st.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
st.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
st.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
st.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
st.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16646,6 +14854,7 @@ st.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
st.$(OBJEXT): {$(VPATH)}internal/intern/error.h
st.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
st.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
st.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
st.$(OBJEXT): {$(VPATH)}internal/intern/io.h
st.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16676,6 +14885,7 @@ st.$(OBJEXT): {$(VPATH)}internal/memory.h
st.$(OBJEXT): {$(VPATH)}internal/method.h
st.$(OBJEXT): {$(VPATH)}internal/module.h
st.$(OBJEXT): {$(VPATH)}internal/newobj.h
+st.$(OBJEXT): {$(VPATH)}internal/rgengc.h
st.$(OBJEXT): {$(VPATH)}internal/scan_args.h
st.$(OBJEXT): {$(VPATH)}internal/special_consts.h
st.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -16688,6 +14898,7 @@ st.$(OBJEXT): {$(VPATH)}internal/variable.h
st.$(OBJEXT): {$(VPATH)}internal/warning_push.h
st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
st.$(OBJEXT): {$(VPATH)}missing.h
+st.$(OBJEXT): {$(VPATH)}ruby_assert.h
st.$(OBJEXT): {$(VPATH)}st.c
st.$(OBJEXT): {$(VPATH)}st.h
st.$(OBJEXT): {$(VPATH)}subst.h
@@ -16751,7 +14962,6 @@ strftime.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16820,6 +15030,7 @@ strftime.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/error.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/io.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16850,6 +15061,7 @@ strftime.$(OBJEXT): {$(VPATH)}internal/memory.h
strftime.$(OBJEXT): {$(VPATH)}internal/method.h
strftime.$(OBJEXT): {$(VPATH)}internal/module.h
strftime.$(OBJEXT): {$(VPATH)}internal/newobj.h
+strftime.$(OBJEXT): {$(VPATH)}internal/rgengc.h
strftime.$(OBJEXT): {$(VPATH)}internal/scan_args.h
strftime.$(OBJEXT): {$(VPATH)}internal/special_consts.h
strftime.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -16869,10 +15081,6 @@ strftime.$(OBJEXT): {$(VPATH)}strftime.c
strftime.$(OBJEXT): {$(VPATH)}subst.h
strftime.$(OBJEXT): {$(VPATH)}timev.h
strftime.$(OBJEXT): {$(VPATH)}util.h
-string.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-string.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-string.$(OBJEXT): $(CCAN_DIR)/list/list.h
-string.$(OBJEXT): $(CCAN_DIR)/str/str.h
string.$(OBJEXT): $(hdrdir)/ruby/ruby.h
string.$(OBJEXT): $(top_srcdir)/internal/array.h
string.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
@@ -16885,7 +15093,6 @@ string.$(OBJEXT): $(top_srcdir)/internal/encoding.h
string.$(OBJEXT): $(top_srcdir)/internal/error.h
string.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
string.$(OBJEXT): $(top_srcdir)/internal/gc.h
-string.$(OBJEXT): $(top_srcdir)/internal/imemo.h
string.$(OBJEXT): $(top_srcdir)/internal/numeric.h
string.$(OBJEXT): $(top_srcdir)/internal/object.h
string.$(OBJEXT): $(top_srcdir)/internal/proc.h
@@ -16915,6 +15122,7 @@ string.$(OBJEXT): {$(VPATH)}debug_counter.h
string.$(OBJEXT): {$(VPATH)}defines.h
string.$(OBJEXT): {$(VPATH)}encindex.h
string.$(OBJEXT): {$(VPATH)}encoding.h
+string.$(OBJEXT): {$(VPATH)}gc.h
string.$(OBJEXT): {$(VPATH)}id.h
string.$(OBJEXT): {$(VPATH)}id_table.h
string.$(OBJEXT): {$(VPATH)}intern.h
@@ -16956,8 +15164,8 @@ string.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
string.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
string.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
string.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
string.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
string.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
string.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
string.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17027,6 +15235,7 @@ string.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
string.$(OBJEXT): {$(VPATH)}internal/intern/error.h
string.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
string.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
string.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
string.$(OBJEXT): {$(VPATH)}internal/intern/io.h
string.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17057,6 +15266,7 @@ string.$(OBJEXT): {$(VPATH)}internal/memory.h
string.$(OBJEXT): {$(VPATH)}internal/method.h
string.$(OBJEXT): {$(VPATH)}internal/module.h
string.$(OBJEXT): {$(VPATH)}internal/newobj.h
+string.$(OBJEXT): {$(VPATH)}internal/rgengc.h
string.$(OBJEXT): {$(VPATH)}internal/scan_args.h
string.$(OBJEXT): {$(VPATH)}internal/special_consts.h
string.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -17068,9 +15278,7 @@ string.$(OBJEXT): {$(VPATH)}internal/value_type.h
string.$(OBJEXT): {$(VPATH)}internal/variable.h
string.$(OBJEXT): {$(VPATH)}internal/warning_push.h
string.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-string.$(OBJEXT): {$(VPATH)}method.h
string.$(OBJEXT): {$(VPATH)}missing.h
-string.$(OBJEXT): {$(VPATH)}node.h
string.$(OBJEXT): {$(VPATH)}onigmo.h
string.$(OBJEXT): {$(VPATH)}oniguruma.h
string.$(OBJEXT): {$(VPATH)}probes.dmyh
@@ -17078,18 +15286,13 @@ string.$(OBJEXT): {$(VPATH)}probes.h
string.$(OBJEXT): {$(VPATH)}re.h
string.$(OBJEXT): {$(VPATH)}regex.h
string.$(OBJEXT): {$(VPATH)}ruby_assert.h
-string.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-string.$(OBJEXT): {$(VPATH)}rubyparser.h
string.$(OBJEXT): {$(VPATH)}shape.h
string.$(OBJEXT): {$(VPATH)}st.h
string.$(OBJEXT): {$(VPATH)}string.c
string.$(OBJEXT): {$(VPATH)}subst.h
-string.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
string.$(OBJEXT): {$(VPATH)}thread_native.h
string.$(OBJEXT): {$(VPATH)}util.h
-string.$(OBJEXT): {$(VPATH)}vm_core.h
string.$(OBJEXT): {$(VPATH)}vm_debug.h
-string.$(OBJEXT): {$(VPATH)}vm_opts.h
string.$(OBJEXT): {$(VPATH)}vm_sync.h
strlcat.$(OBJEXT): {$(VPATH)}config.h
strlcat.$(OBJEXT): {$(VPATH)}internal/attr/format.h
@@ -17202,7 +15405,6 @@ struct.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17271,6 +15473,7 @@ struct.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/error.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/io.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17301,6 +15504,7 @@ struct.$(OBJEXT): {$(VPATH)}internal/memory.h
struct.$(OBJEXT): {$(VPATH)}internal/method.h
struct.$(OBJEXT): {$(VPATH)}internal/module.h
struct.$(OBJEXT): {$(VPATH)}internal/newobj.h
+struct.$(OBJEXT): {$(VPATH)}internal/rgengc.h
struct.$(OBJEXT): {$(VPATH)}internal/scan_args.h
struct.$(OBJEXT): {$(VPATH)}internal/special_consts.h
struct.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -17319,28 +15523,21 @@ struct.$(OBJEXT): {$(VPATH)}onigmo.h
struct.$(OBJEXT): {$(VPATH)}oniguruma.h
struct.$(OBJEXT): {$(VPATH)}ruby_assert.h
struct.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-struct.$(OBJEXT): {$(VPATH)}rubyparser.h
struct.$(OBJEXT): {$(VPATH)}shape.h
struct.$(OBJEXT): {$(VPATH)}st.h
struct.$(OBJEXT): {$(VPATH)}struct.c
struct.$(OBJEXT): {$(VPATH)}subst.h
struct.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
struct.$(OBJEXT): {$(VPATH)}thread_native.h
+struct.$(OBJEXT): {$(VPATH)}transient_heap.h
struct.$(OBJEXT): {$(VPATH)}vm_core.h
struct.$(OBJEXT): {$(VPATH)}vm_opts.h
-symbol.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-symbol.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-symbol.$(OBJEXT): $(CCAN_DIR)/list/list.h
-symbol.$(OBJEXT): $(CCAN_DIR)/str/str.h
symbol.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/array.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
symbol.$(OBJEXT): $(top_srcdir)/internal/class.h
symbol.$(OBJEXT): $(top_srcdir)/internal/compilers.h
symbol.$(OBJEXT): $(top_srcdir)/internal/error.h
symbol.$(OBJEXT): $(top_srcdir)/internal/gc.h
symbol.$(OBJEXT): $(top_srcdir)/internal/hash.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/imemo.h
symbol.$(OBJEXT): $(top_srcdir)/internal/object.h
symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h
symbol.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -17350,7 +15547,6 @@ symbol.$(OBJEXT): $(top_srcdir)/internal/variable.h
symbol.$(OBJEXT): $(top_srcdir)/internal/vm.h
symbol.$(OBJEXT): $(top_srcdir)/internal/warnings.h
symbol.$(OBJEXT): {$(VPATH)}assert.h
-symbol.$(OBJEXT): {$(VPATH)}atomic.h
symbol.$(OBJEXT): {$(VPATH)}backward/2/assume.h
symbol.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
symbol.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -17366,6 +15562,7 @@ symbol.$(OBJEXT): {$(VPATH)}constant.h
symbol.$(OBJEXT): {$(VPATH)}debug_counter.h
symbol.$(OBJEXT): {$(VPATH)}defines.h
symbol.$(OBJEXT): {$(VPATH)}encoding.h
+symbol.$(OBJEXT): {$(VPATH)}gc.h
symbol.$(OBJEXT): {$(VPATH)}id.c
symbol.$(OBJEXT): {$(VPATH)}id.h
symbol.$(OBJEXT): {$(VPATH)}id_table.c
@@ -17409,8 +15606,8 @@ symbol.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17479,6 +15676,7 @@ symbol.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/error.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/io.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17509,6 +15707,7 @@ symbol.$(OBJEXT): {$(VPATH)}internal/memory.h
symbol.$(OBJEXT): {$(VPATH)}internal/method.h
symbol.$(OBJEXT): {$(VPATH)}internal/module.h
symbol.$(OBJEXT): {$(VPATH)}internal/newobj.h
+symbol.$(OBJEXT): {$(VPATH)}internal/rgengc.h
symbol.$(OBJEXT): {$(VPATH)}internal/scan_args.h
symbol.$(OBJEXT): {$(VPATH)}internal/special_consts.h
symbol.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -17520,16 +15719,12 @@ symbol.$(OBJEXT): {$(VPATH)}internal/value_type.h
symbol.$(OBJEXT): {$(VPATH)}internal/variable.h
symbol.$(OBJEXT): {$(VPATH)}internal/warning_push.h
symbol.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-symbol.$(OBJEXT): {$(VPATH)}method.h
symbol.$(OBJEXT): {$(VPATH)}missing.h
-symbol.$(OBJEXT): {$(VPATH)}node.h
symbol.$(OBJEXT): {$(VPATH)}onigmo.h
symbol.$(OBJEXT): {$(VPATH)}oniguruma.h
symbol.$(OBJEXT): {$(VPATH)}probes.dmyh
symbol.$(OBJEXT): {$(VPATH)}probes.h
symbol.$(OBJEXT): {$(VPATH)}ruby_assert.h
-symbol.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-symbol.$(OBJEXT): {$(VPATH)}rubyparser.h
symbol.$(OBJEXT): {$(VPATH)}shape.h
symbol.$(OBJEXT): {$(VPATH)}st.h
symbol.$(OBJEXT): {$(VPATH)}subst.h
@@ -17537,11 +15732,7 @@ symbol.$(OBJEXT): {$(VPATH)}symbol.c
symbol.$(OBJEXT): {$(VPATH)}symbol.h
symbol.$(OBJEXT): {$(VPATH)}symbol.rb
symbol.$(OBJEXT): {$(VPATH)}symbol.rbinc
-symbol.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-symbol.$(OBJEXT): {$(VPATH)}thread_native.h
-symbol.$(OBJEXT): {$(VPATH)}vm_core.h
symbol.$(OBJEXT): {$(VPATH)}vm_debug.h
-symbol.$(OBJEXT): {$(VPATH)}vm_opts.h
symbol.$(OBJEXT): {$(VPATH)}vm_sync.h
thread.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
thread.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
@@ -17571,7 +15762,6 @@ thread.$(OBJEXT): $(top_srcdir)/internal/time.h
thread.$(OBJEXT): $(top_srcdir)/internal/variable.h
thread.$(OBJEXT): $(top_srcdir)/internal/vm.h
thread.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-thread.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
thread.$(OBJEXT): {$(VPATH)}assert.h
thread.$(OBJEXT): {$(VPATH)}atomic.h
thread.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -17592,6 +15782,7 @@ thread.$(OBJEXT): {$(VPATH)}defines.h
thread.$(OBJEXT): {$(VPATH)}encoding.h
thread.$(OBJEXT): {$(VPATH)}eval_intern.h
thread.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+thread.$(OBJEXT): {$(VPATH)}gc.h
thread.$(OBJEXT): {$(VPATH)}hrtime.h
thread.$(OBJEXT): {$(VPATH)}id.h
thread.$(OBJEXT): {$(VPATH)}id_table.h
@@ -17635,7 +15826,6 @@ thread.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17704,6 +15894,7 @@ thread.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/error.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/io.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17734,6 +15925,7 @@ thread.$(OBJEXT): {$(VPATH)}internal/memory.h
thread.$(OBJEXT): {$(VPATH)}internal/method.h
thread.$(OBJEXT): {$(VPATH)}internal/module.h
thread.$(OBJEXT): {$(VPATH)}internal/newobj.h
+thread.$(OBJEXT): {$(VPATH)}internal/rgengc.h
thread.$(OBJEXT): {$(VPATH)}internal/scan_args.h
thread.$(OBJEXT): {$(VPATH)}internal/special_consts.h
thread.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -17749,15 +15941,14 @@ thread.$(OBJEXT): {$(VPATH)}io.h
thread.$(OBJEXT): {$(VPATH)}iseq.h
thread.$(OBJEXT): {$(VPATH)}method.h
thread.$(OBJEXT): {$(VPATH)}missing.h
+thread.$(OBJEXT): {$(VPATH)}mjit.h
thread.$(OBJEXT): {$(VPATH)}node.h
thread.$(OBJEXT): {$(VPATH)}onigmo.h
thread.$(OBJEXT): {$(VPATH)}oniguruma.h
thread.$(OBJEXT): {$(VPATH)}ractor.h
thread.$(OBJEXT): {$(VPATH)}ractor_core.h
-thread.$(OBJEXT): {$(VPATH)}rjit.h
thread.$(OBJEXT): {$(VPATH)}ruby_assert.h
thread.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-thread.$(OBJEXT): {$(VPATH)}rubyparser.h
thread.$(OBJEXT): {$(VPATH)}shape.h
thread.$(OBJEXT): {$(VPATH)}st.h
thread.$(OBJEXT): {$(VPATH)}subst.h
@@ -17766,7 +15957,6 @@ thread.$(OBJEXT): {$(VPATH)}thread.h
thread.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).c
thread.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
thread.$(OBJEXT): {$(VPATH)}thread_native.h
-thread.$(OBJEXT): {$(VPATH)}thread_pthread_mn.c
thread.$(OBJEXT): {$(VPATH)}thread_sync.c
thread.$(OBJEXT): {$(VPATH)}thread_sync.rbinc
thread.$(OBJEXT): {$(VPATH)}timev.h
@@ -17774,10 +15964,6 @@ thread.$(OBJEXT): {$(VPATH)}vm_core.h
thread.$(OBJEXT): {$(VPATH)}vm_debug.h
thread.$(OBJEXT): {$(VPATH)}vm_opts.h
thread.$(OBJEXT): {$(VPATH)}vm_sync.h
-time.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-time.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-time.$(OBJEXT): $(CCAN_DIR)/list/list.h
-time.$(OBJEXT): $(CCAN_DIR)/str/str.h
time.$(OBJEXT): $(hdrdir)/ruby/ruby.h
time.$(OBJEXT): $(top_srcdir)/internal/array.h
time.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
@@ -17788,7 +15974,6 @@ time.$(OBJEXT): $(top_srcdir)/internal/compilers.h
time.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
time.$(OBJEXT): $(top_srcdir)/internal/gc.h
time.$(OBJEXT): $(top_srcdir)/internal/hash.h
-time.$(OBJEXT): $(top_srcdir)/internal/imemo.h
time.$(OBJEXT): $(top_srcdir)/internal/numeric.h
time.$(OBJEXT): $(top_srcdir)/internal/rational.h
time.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -17799,7 +15984,6 @@ time.$(OBJEXT): $(top_srcdir)/internal/variable.h
time.$(OBJEXT): $(top_srcdir)/internal/vm.h
time.$(OBJEXT): $(top_srcdir)/internal/warnings.h
time.$(OBJEXT): {$(VPATH)}assert.h
-time.$(OBJEXT): {$(VPATH)}atomic.h
time.$(OBJEXT): {$(VPATH)}backward/2/assume.h
time.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
time.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -17856,7 +16040,6 @@ time.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
time.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
time.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
time.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
time.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
time.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
time.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17925,6 +16108,7 @@ time.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
time.$(OBJEXT): {$(VPATH)}internal/intern/error.h
time.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
time.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
time.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
time.$(OBJEXT): {$(VPATH)}internal/intern/io.h
time.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17955,6 +16139,7 @@ time.$(OBJEXT): {$(VPATH)}internal/memory.h
time.$(OBJEXT): {$(VPATH)}internal/method.h
time.$(OBJEXT): {$(VPATH)}internal/module.h
time.$(OBJEXT): {$(VPATH)}internal/newobj.h
+time.$(OBJEXT): {$(VPATH)}internal/rgengc.h
time.$(OBJEXT): {$(VPATH)}internal/scan_args.h
time.$(OBJEXT): {$(VPATH)}internal/special_consts.h
time.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -17966,24 +16151,16 @@ time.$(OBJEXT): {$(VPATH)}internal/value_type.h
time.$(OBJEXT): {$(VPATH)}internal/variable.h
time.$(OBJEXT): {$(VPATH)}internal/warning_push.h
time.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-time.$(OBJEXT): {$(VPATH)}method.h
time.$(OBJEXT): {$(VPATH)}missing.h
-time.$(OBJEXT): {$(VPATH)}node.h
time.$(OBJEXT): {$(VPATH)}onigmo.h
time.$(OBJEXT): {$(VPATH)}oniguruma.h
time.$(OBJEXT): {$(VPATH)}ruby_assert.h
-time.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-time.$(OBJEXT): {$(VPATH)}rubyparser.h
time.$(OBJEXT): {$(VPATH)}shape.h
time.$(OBJEXT): {$(VPATH)}st.h
time.$(OBJEXT): {$(VPATH)}subst.h
-time.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-time.$(OBJEXT): {$(VPATH)}thread_native.h
time.$(OBJEXT): {$(VPATH)}time.c
time.$(OBJEXT): {$(VPATH)}timev.h
time.$(OBJEXT): {$(VPATH)}timev.rbinc
-time.$(OBJEXT): {$(VPATH)}vm_core.h
-time.$(OBJEXT): {$(VPATH)}vm_opts.h
transcode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
transcode.$(OBJEXT): $(top_srcdir)/internal/array.h
transcode.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -18053,7 +16230,6 @@ transcode.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18122,6 +16298,7 @@ transcode.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/error.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18152,6 +16329,7 @@ transcode.$(OBJEXT): {$(VPATH)}internal/memory.h
transcode.$(OBJEXT): {$(VPATH)}internal/method.h
transcode.$(OBJEXT): {$(VPATH)}internal/module.h
transcode.$(OBJEXT): {$(VPATH)}internal/newobj.h
+transcode.$(OBJEXT): {$(VPATH)}internal/rgengc.h
transcode.$(OBJEXT): {$(VPATH)}internal/scan_args.h
transcode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
transcode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -18171,6 +16349,184 @@ transcode.$(OBJEXT): {$(VPATH)}st.h
transcode.$(OBJEXT): {$(VPATH)}subst.h
transcode.$(OBJEXT): {$(VPATH)}transcode.c
transcode.$(OBJEXT): {$(VPATH)}transcode_data.h
+transient_heap.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/array.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/gc.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/hash.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/struct.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/variable.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+transient_heap.$(OBJEXT): {$(VPATH)}assert.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+transient_heap.$(OBJEXT): {$(VPATH)}config.h
+transient_heap.$(OBJEXT): {$(VPATH)}constant.h
+transient_heap.$(OBJEXT): {$(VPATH)}debug.h
+transient_heap.$(OBJEXT): {$(VPATH)}debug_counter.h
+transient_heap.$(OBJEXT): {$(VPATH)}defines.h
+transient_heap.$(OBJEXT): {$(VPATH)}gc.h
+transient_heap.$(OBJEXT): {$(VPATH)}id_table.h
+transient_heap.$(OBJEXT): {$(VPATH)}intern.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/abi.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/assume.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/cast.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/config.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/ctype.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/dosish.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/error.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/eval.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/event.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/gc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/glob.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/globals.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/iterator.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/memory.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/method.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/module.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/newobj.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/rgengc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/symbol.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/value.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/value_type.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/variable.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+transient_heap.$(OBJEXT): {$(VPATH)}missing.h
+transient_heap.$(OBJEXT): {$(VPATH)}ruby_assert.h
+transient_heap.$(OBJEXT): {$(VPATH)}shape.h
+transient_heap.$(OBJEXT): {$(VPATH)}st.h
+transient_heap.$(OBJEXT): {$(VPATH)}subst.h
+transient_heap.$(OBJEXT): {$(VPATH)}transient_heap.c
+transient_heap.$(OBJEXT): {$(VPATH)}transient_heap.h
+transient_heap.$(OBJEXT): {$(VPATH)}vm_debug.h
+transient_heap.$(OBJEXT): {$(VPATH)}vm_sync.h
util.$(OBJEXT): $(hdrdir)/ruby/ruby.h
util.$(OBJEXT): $(top_srcdir)/internal/compilers.h
util.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -18230,7 +16586,6 @@ util.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
util.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
util.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
util.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
util.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
util.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
util.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18290,6 +16645,7 @@ util.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
util.$(OBJEXT): {$(VPATH)}internal/intern/error.h
util.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
util.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
util.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
util.$(OBJEXT): {$(VPATH)}internal/intern/io.h
util.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18320,6 +16676,7 @@ util.$(OBJEXT): {$(VPATH)}internal/memory.h
util.$(OBJEXT): {$(VPATH)}internal/method.h
util.$(OBJEXT): {$(VPATH)}internal/module.h
util.$(OBJEXT): {$(VPATH)}internal/newobj.h
+util.$(OBJEXT): {$(VPATH)}internal/rgengc.h
util.$(OBJEXT): {$(VPATH)}internal/scan_args.h
util.$(OBJEXT): {$(VPATH)}internal/special_consts.h
util.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -18419,7 +16776,6 @@ variable.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18488,6 +16844,7 @@ variable.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/error.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/io.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18518,6 +16875,7 @@ variable.$(OBJEXT): {$(VPATH)}internal/memory.h
variable.$(OBJEXT): {$(VPATH)}internal/method.h
variable.$(OBJEXT): {$(VPATH)}internal/module.h
variable.$(OBJEXT): {$(VPATH)}internal/newobj.h
+variable.$(OBJEXT): {$(VPATH)}internal/rgengc.h
variable.$(OBJEXT): {$(VPATH)}internal/scan_args.h
variable.$(OBJEXT): {$(VPATH)}internal/special_consts.h
variable.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -18538,13 +16896,12 @@ variable.$(OBJEXT): {$(VPATH)}ractor.h
variable.$(OBJEXT): {$(VPATH)}ractor_core.h
variable.$(OBJEXT): {$(VPATH)}ruby_assert.h
variable.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-variable.$(OBJEXT): {$(VPATH)}rubyparser.h
variable.$(OBJEXT): {$(VPATH)}shape.h
variable.$(OBJEXT): {$(VPATH)}st.h
variable.$(OBJEXT): {$(VPATH)}subst.h
-variable.$(OBJEXT): {$(VPATH)}symbol.h
variable.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
variable.$(OBJEXT): {$(VPATH)}thread_native.h
+variable.$(OBJEXT): {$(VPATH)}transient_heap.h
variable.$(OBJEXT): {$(VPATH)}util.h
variable.$(OBJEXT): {$(VPATH)}variable.c
variable.$(OBJEXT): {$(VPATH)}variable.h
@@ -18586,7 +16943,6 @@ version.$(OBJEXT): {$(VPATH)}config.h
version.$(OBJEXT): {$(VPATH)}constant.h
version.$(OBJEXT): {$(VPATH)}debug_counter.h
version.$(OBJEXT): {$(VPATH)}defines.h
-version.$(OBJEXT): {$(VPATH)}encoding.h
version.$(OBJEXT): {$(VPATH)}id.h
version.$(OBJEXT): {$(VPATH)}id_table.h
version.$(OBJEXT): {$(VPATH)}intern.h
@@ -18629,7 +16985,6 @@ version.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
version.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
version.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
version.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
version.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
version.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
version.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18662,15 +17017,6 @@ version.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
version.$(OBJEXT): {$(VPATH)}internal/ctype.h
version.$(OBJEXT): {$(VPATH)}internal/dllexport.h
version.$(OBJEXT): {$(VPATH)}internal/dosish.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
version.$(OBJEXT): {$(VPATH)}internal/error.h
version.$(OBJEXT): {$(VPATH)}internal/eval.h
version.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -18698,6 +17044,7 @@ version.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
version.$(OBJEXT): {$(VPATH)}internal/intern/error.h
version.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
version.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
version.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
version.$(OBJEXT): {$(VPATH)}internal/intern/io.h
version.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18728,6 +17075,7 @@ version.$(OBJEXT): {$(VPATH)}internal/memory.h
version.$(OBJEXT): {$(VPATH)}internal/method.h
version.$(OBJEXT): {$(VPATH)}internal/module.h
version.$(OBJEXT): {$(VPATH)}internal/newobj.h
+version.$(OBJEXT): {$(VPATH)}internal/rgengc.h
version.$(OBJEXT): {$(VPATH)}internal/scan_args.h
version.$(OBJEXT): {$(VPATH)}internal/special_consts.h
version.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -18741,14 +17089,11 @@ version.$(OBJEXT): {$(VPATH)}internal/warning_push.h
version.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
version.$(OBJEXT): {$(VPATH)}method.h
version.$(OBJEXT): {$(VPATH)}missing.h
+version.$(OBJEXT): {$(VPATH)}mjit.h
version.$(OBJEXT): {$(VPATH)}node.h
-version.$(OBJEXT): {$(VPATH)}onigmo.h
-version.$(OBJEXT): {$(VPATH)}oniguruma.h
version.$(OBJEXT): {$(VPATH)}revision.h
-version.$(OBJEXT): {$(VPATH)}rjit.h
version.$(OBJEXT): {$(VPATH)}ruby_assert.h
version.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-version.$(OBJEXT): {$(VPATH)}rubyparser.h
version.$(OBJEXT): {$(VPATH)}shape.h
version.$(OBJEXT): {$(VPATH)}st.h
version.$(OBJEXT): {$(VPATH)}subst.h
@@ -18786,7 +17131,6 @@ vm.$(OBJEXT): $(top_srcdir)/internal/parse.h
vm.$(OBJEXT): $(top_srcdir)/internal/proc.h
vm.$(OBJEXT): $(top_srcdir)/internal/random.h
vm.$(OBJEXT): $(top_srcdir)/internal/re.h
-vm.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
vm.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -18816,6 +17160,7 @@ vm.$(OBJEXT): {$(VPATH)}defines.h
vm.$(OBJEXT): {$(VPATH)}defs/opt_operand.def
vm.$(OBJEXT): {$(VPATH)}encoding.h
vm.$(OBJEXT): {$(VPATH)}eval_intern.h
+vm.$(OBJEXT): {$(VPATH)}gc.h
vm.$(OBJEXT): {$(VPATH)}id.h
vm.$(OBJEXT): {$(VPATH)}id_table.h
vm.$(OBJEXT): {$(VPATH)}insns.def
@@ -18861,7 +17206,6 @@ vm.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18930,6 +17274,7 @@ vm.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18960,6 +17305,7 @@ vm.$(OBJEXT): {$(VPATH)}internal/memory.h
vm.$(OBJEXT): {$(VPATH)}internal/method.h
vm.$(OBJEXT): {$(VPATH)}internal/module.h
vm.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -18974,6 +17320,7 @@ vm.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
vm.$(OBJEXT): {$(VPATH)}iseq.h
vm.$(OBJEXT): {$(VPATH)}method.h
vm.$(OBJEXT): {$(VPATH)}missing.h
+vm.$(OBJEXT): {$(VPATH)}mjit.h
vm.$(OBJEXT): {$(VPATH)}node.h
vm.$(OBJEXT): {$(VPATH)}onigmo.h
vm.$(OBJEXT): {$(VPATH)}oniguruma.h
@@ -18982,10 +17329,8 @@ vm.$(OBJEXT): {$(VPATH)}probes.h
vm.$(OBJEXT): {$(VPATH)}probes_helper.h
vm.$(OBJEXT): {$(VPATH)}ractor.h
vm.$(OBJEXT): {$(VPATH)}ractor_core.h
-vm.$(OBJEXT): {$(VPATH)}rjit.h
vm.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm.$(OBJEXT): {$(VPATH)}rubyparser.h
vm.$(OBJEXT): {$(VPATH)}shape.h
vm.$(OBJEXT): {$(VPATH)}st.h
vm.$(OBJEXT): {$(VPATH)}subst.h
@@ -19017,7 +17362,6 @@ vm_backtrace.$(OBJEXT): $(CCAN_DIR)/str/str.h
vm_backtrace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/array.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/class.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/error.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/gc.h
@@ -19087,7 +17431,6 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19156,6 +17499,7 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19186,6 +17530,7 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/method.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/module.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -19205,7 +17550,6 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}onigmo.h
vm_backtrace.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_backtrace.$(OBJEXT): {$(VPATH)}shape.h
vm_backtrace.$(OBJEXT): {$(VPATH)}st.h
vm_backtrace.$(OBJEXT): {$(VPATH)}subst.h
@@ -19244,7 +17588,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
vm_dump.$(OBJEXT): {$(VPATH)}config.h
vm_dump.$(OBJEXT): {$(VPATH)}constant.h
vm_dump.$(OBJEXT): {$(VPATH)}defines.h
-vm_dump.$(OBJEXT): {$(VPATH)}encoding.h
+vm_dump.$(OBJEXT): {$(VPATH)}gc.h
vm_dump.$(OBJEXT): {$(VPATH)}id.h
vm_dump.$(OBJEXT): {$(VPATH)}id_table.h
vm_dump.$(OBJEXT): {$(VPATH)}intern.h
@@ -19287,7 +17631,6 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19320,15 +17663,6 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/ctype.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/dllexport.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/dosish.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/error.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/eval.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -19356,6 +17690,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19386,6 +17721,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/method.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/module.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -19401,14 +17737,11 @@ vm_dump.$(OBJEXT): {$(VPATH)}iseq.h
vm_dump.$(OBJEXT): {$(VPATH)}method.h
vm_dump.$(OBJEXT): {$(VPATH)}missing.h
vm_dump.$(OBJEXT): {$(VPATH)}node.h
-vm_dump.$(OBJEXT): {$(VPATH)}onigmo.h
-vm_dump.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_dump.$(OBJEXT): {$(VPATH)}procstat_vm.c
vm_dump.$(OBJEXT): {$(VPATH)}ractor.h
vm_dump.$(OBJEXT): {$(VPATH)}ractor_core.h
vm_dump.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_dump.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_dump.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_dump.$(OBJEXT): {$(VPATH)}shape.h
vm_dump.$(OBJEXT): {$(VPATH)}st.h
vm_dump.$(OBJEXT): {$(VPATH)}subst.h
@@ -19430,7 +17763,6 @@ vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/thread.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -19449,7 +17781,7 @@ vm_sync.$(OBJEXT): {$(VPATH)}config.h
vm_sync.$(OBJEXT): {$(VPATH)}constant.h
vm_sync.$(OBJEXT): {$(VPATH)}debug_counter.h
vm_sync.$(OBJEXT): {$(VPATH)}defines.h
-vm_sync.$(OBJEXT): {$(VPATH)}encoding.h
+vm_sync.$(OBJEXT): {$(VPATH)}gc.h
vm_sync.$(OBJEXT): {$(VPATH)}id.h
vm_sync.$(OBJEXT): {$(VPATH)}id_table.h
vm_sync.$(OBJEXT): {$(VPATH)}intern.h
@@ -19492,7 +17824,6 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19525,15 +17856,6 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/ctype.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/dllexport.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/dosish.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/error.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/eval.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -19561,6 +17883,7 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19591,6 +17914,7 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/method.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/module.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -19605,13 +17929,10 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
vm_sync.$(OBJEXT): {$(VPATH)}method.h
vm_sync.$(OBJEXT): {$(VPATH)}missing.h
vm_sync.$(OBJEXT): {$(VPATH)}node.h
-vm_sync.$(OBJEXT): {$(VPATH)}onigmo.h
-vm_sync.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_sync.$(OBJEXT): {$(VPATH)}ractor.h
vm_sync.$(OBJEXT): {$(VPATH)}ractor_core.h
vm_sync.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_sync.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_sync.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_sync.$(OBJEXT): {$(VPATH)}shape.h
vm_sync.$(OBJEXT): {$(VPATH)}st.h
vm_sync.$(OBJEXT): {$(VPATH)}subst.h
@@ -19630,7 +17951,6 @@ vm_trace.$(OBJEXT): $(hdrdir)/ruby.h
vm_trace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/array.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/class.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/hash.h
@@ -19702,7 +18022,6 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19771,6 +18090,7 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19801,6 +18121,7 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/method.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/module.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -19815,14 +18136,13 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
vm_trace.$(OBJEXT): {$(VPATH)}iseq.h
vm_trace.$(OBJEXT): {$(VPATH)}method.h
vm_trace.$(OBJEXT): {$(VPATH)}missing.h
+vm_trace.$(OBJEXT): {$(VPATH)}mjit.h
vm_trace.$(OBJEXT): {$(VPATH)}node.h
vm_trace.$(OBJEXT): {$(VPATH)}onigmo.h
vm_trace.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_trace.$(OBJEXT): {$(VPATH)}ractor.h
-vm_trace.$(OBJEXT): {$(VPATH)}rjit.h
vm_trace.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_trace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_trace.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_trace.$(OBJEXT): {$(VPATH)}shape.h
vm_trace.$(OBJEXT): {$(VPATH)}st.h
vm_trace.$(OBJEXT): {$(VPATH)}subst.h
@@ -19833,203 +18153,6 @@ vm_trace.$(OBJEXT): {$(VPATH)}vm_core.h
vm_trace.$(OBJEXT): {$(VPATH)}vm_opts.h
vm_trace.$(OBJEXT): {$(VPATH)}vm_trace.c
vm_trace.$(OBJEXT): {$(VPATH)}yjit.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/list/list.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/str/str.h
-weakmap.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/array.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/gc.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/hash.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/proc.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/serial.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/vm.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-weakmap.$(OBJEXT): {$(VPATH)}assert.h
-weakmap.$(OBJEXT): {$(VPATH)}atomic.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-weakmap.$(OBJEXT): {$(VPATH)}config.h
-weakmap.$(OBJEXT): {$(VPATH)}defines.h
-weakmap.$(OBJEXT): {$(VPATH)}encoding.h
-weakmap.$(OBJEXT): {$(VPATH)}id.h
-weakmap.$(OBJEXT): {$(VPATH)}intern.h
-weakmap.$(OBJEXT): {$(VPATH)}internal.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/abi.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/assume.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/cast.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/config.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/ctype.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/dosish.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/error.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/eval.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/event.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/gc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/glob.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/globals.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/iterator.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/memory.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/method.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/module.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/newobj.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/symbol.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/value.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/value_type.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/variable.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-weakmap.$(OBJEXT): {$(VPATH)}method.h
-weakmap.$(OBJEXT): {$(VPATH)}missing.h
-weakmap.$(OBJEXT): {$(VPATH)}node.h
-weakmap.$(OBJEXT): {$(VPATH)}onigmo.h
-weakmap.$(OBJEXT): {$(VPATH)}oniguruma.h
-weakmap.$(OBJEXT): {$(VPATH)}ruby_assert.h
-weakmap.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-weakmap.$(OBJEXT): {$(VPATH)}rubyparser.h
-weakmap.$(OBJEXT): {$(VPATH)}st.h
-weakmap.$(OBJEXT): {$(VPATH)}subst.h
-weakmap.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-weakmap.$(OBJEXT): {$(VPATH)}thread_native.h
-weakmap.$(OBJEXT): {$(VPATH)}vm_core.h
-weakmap.$(OBJEXT): {$(VPATH)}vm_opts.h
-weakmap.$(OBJEXT): {$(VPATH)}weakmap.c
yjit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
yjit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
yjit.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -20037,8 +18160,6 @@ yjit.$(OBJEXT): $(CCAN_DIR)/str/str.h
yjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
yjit.$(OBJEXT): $(top_srcdir)/internal/array.h
yjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-yjit.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-yjit.$(OBJEXT): $(top_srcdir)/internal/bits.h
yjit.$(OBJEXT): $(top_srcdir)/internal/class.h
yjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
yjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -20047,7 +18168,6 @@ yjit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
yjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
yjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
yjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-yjit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
yjit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
yjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
yjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -20073,6 +18193,7 @@ yjit.$(OBJEXT): {$(VPATH)}debug.h
yjit.$(OBJEXT): {$(VPATH)}debug_counter.h
yjit.$(OBJEXT): {$(VPATH)}defines.h
yjit.$(OBJEXT): {$(VPATH)}encoding.h
+yjit.$(OBJEXT): {$(VPATH)}gc.h
yjit.$(OBJEXT): {$(VPATH)}id.h
yjit.$(OBJEXT): {$(VPATH)}id_table.h
yjit.$(OBJEXT): {$(VPATH)}insns.def
@@ -20118,7 +18239,6 @@ yjit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -20187,6 +18307,7 @@ yjit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -20217,7 +18338,7 @@ yjit.$(OBJEXT): {$(VPATH)}internal/memory.h
yjit.$(OBJEXT): {$(VPATH)}internal/method.h
yjit.$(OBJEXT): {$(VPATH)}internal/module.h
yjit.$(OBJEXT): {$(VPATH)}internal/newobj.h
-yjit.$(OBJEXT): {$(VPATH)}internal/numeric.h
+yjit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
yjit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
yjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
yjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -20240,7 +18361,6 @@ yjit.$(OBJEXT): {$(VPATH)}probes.h
yjit.$(OBJEXT): {$(VPATH)}probes_helper.h
yjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
yjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-yjit.$(OBJEXT): {$(VPATH)}rubyparser.h
yjit.$(OBJEXT): {$(VPATH)}shape.h
yjit.$(OBJEXT): {$(VPATH)}st.h
yjit.$(OBJEXT): {$(VPATH)}subst.h
diff --git a/compar.c b/compar.c
index 2f62455a0e..040f77975e 100644
--- a/compar.c
+++ b/compar.c
@@ -187,12 +187,6 @@ cmp_between(VALUE x, VALUE min, VALUE max)
* 'd'.clamp('a', 'f') #=> 'd'
* 'z'.clamp('a', 'f') #=> 'f'
*
- * If _min_ is +nil+, it is considered smaller than _obj_,
- * and if _max_ is +nil+, it is considered greater than _obj_.
- *
- * -20.clamp(0, nil) #=> 0
- * 523.clamp(nil, 100) #=> 100
- *
* In <code>(range)</code> form, returns _range.begin_ if _obj_
* <code><=></code> _range.begin_ is less than zero, _range.end_
* if _obj_ <code><=></code> _range.end_ is greater than zero, and
@@ -235,7 +229,7 @@ cmp_clamp(int argc, VALUE *argv, VALUE x)
}
}
if (!NIL_P(min) && !NIL_P(max) && cmpint(min, max) > 0) {
- rb_raise(rb_eArgError, "min argument must be less than or equal to max argument");
+ rb_raise(rb_eArgError, "min argument must be smaller than max argument");
}
if (!NIL_P(min)) {
@@ -295,8 +289,8 @@ cmp_clamp(int argc, VALUE *argv, VALUE x)
* - #<: Returns whether +self+ is less than the given object.
* - #<=: Returns whether +self+ is less than or equal to the given object.
* - #==: Returns whether +self+ is equal to the given object.
- * - #>: Returns whether +self+ is greater than the given object.
- * - #>=: Returns whether +self+ is greater than or equal to the given object.
+ * - #>: Returns whether +self+ is greater than or equal to the given object.
+ * - #>=: Returns whether +self+ is greater than the given object.
* - #between?: Returns +true+ if +self+ is between two given objects.
* - #clamp: For given objects +min+ and +max+, or range <tt>(min..max)</tt>, returns:
*
diff --git a/compile.c b/compile.c
index e2ab0075d6..0452305923 100644
--- a/compile.c
+++ b/compile.c
@@ -17,6 +17,7 @@
#endif
#include "encindex.h"
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/array.h"
@@ -24,7 +25,6 @@
#include "internal/complex.h"
#include "internal/encoding.h"
#include "internal/error.h"
-#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/numeric.h"
#include "internal/object.h"
@@ -39,12 +39,10 @@
#include "vm_core.h"
#include "vm_callinfo.h"
#include "vm_debug.h"
-#include "yjit.h"
#include "builtin.h"
#include "insns.inc"
#include "insns_info.inc"
-#include "prism_compile.h"
#undef RUBY_UNTYPED_DATA_WARNING
#define RUBY_UNTYPED_DATA_WARNING 0
@@ -120,7 +118,7 @@ struct ensure_range {
};
struct iseq_compile_data_ensure_node_stack {
- const void *ensure_node;
+ const NODE *ensure_node;
struct iseq_compile_data_ensure_node_stack *prev;
struct ensure_range *erange;
};
@@ -334,10 +332,10 @@ static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NOD
(debug_compile("== " desc "\n", \
iseq_compile_each(iseq, (anchor), (node), (popped))))
-#define COMPILE_RECV(anchor, desc, node, recv) \
+#define COMPILE_RECV(anchor, desc, node) \
(private_recv_p(node) ? \
(ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
- COMPILE(anchor, desc, recv) ? 0 : -1)
+ COMPILE(anchor, desc, node->nd_recv) ? 0 : -1)
#define OPERAND_AT(insn, idx) \
(((INSN*)(insn))->operands[(idx)])
@@ -488,6 +486,7 @@ static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl);
static int iseq_set_exception_local_table(rb_iseq_t *iseq);
static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
+static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_set_exception_table(rb_iseq_t *iseq);
static int iseq_set_optargs_table(rb_iseq_t *iseq);
@@ -722,117 +721,6 @@ validate_labels(rb_iseq_t *iseq, st_table *labels_table)
st_free_table(labels_table);
}
-static NODE *
-get_nd_recv(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_recv;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_recv;
- case NODE_FCALL:
- return 0;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_recv;
- case NODE_VCALL:
- return 0;
- case NODE_ATTRASGN:
- return RNODE_ATTRASGN(node)->nd_recv;
- case NODE_OP_ASGN1:
- return RNODE_OP_ASGN1(node)->nd_recv;
- case NODE_OP_ASGN2:
- return RNODE_OP_ASGN2(node)->nd_recv;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static ID
-get_node_call_nd_mid(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_mid;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_mid;
- case NODE_FCALL:
- return RNODE_FCALL(node)->nd_mid;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_mid;
- case NODE_VCALL:
- return RNODE_VCALL(node)->nd_mid;
- case NODE_ATTRASGN:
- return RNODE_ATTRASGN(node)->nd_mid;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static NODE *
-get_nd_args(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_args;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_args;
- case NODE_FCALL:
- return RNODE_FCALL(node)->nd_args;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_args;
- case NODE_VCALL:
- return 0;
- case NODE_ATTRASGN:
- return RNODE_ATTRASGN(node)->nd_args;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static ID
-get_node_colon_nd_mid(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_COLON2:
- return RNODE_COLON2(node)->nd_mid;
- case NODE_COLON3:
- return RNODE_COLON3(node)->nd_mid;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static ID
-get_nd_vid(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_vid;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_vid;
- case NODE_IASGN:
- return RNODE_IASGN(node)->nd_vid;
- case NODE_CVASGN:
- return RNODE_CVASGN(node)->nd_vid;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-
-static NODE *
-get_nd_value(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_value;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_value;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
VALUE
rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
{
@@ -865,8 +753,8 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
/* assume node is T_NODE */
else if (nd_type_p(node, NODE_SCOPE)) {
/* iseq type of top, method, class, block */
- iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl);
- iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
+ iseq_set_local_table(iseq, node->nd_tbl);
+ iseq_set_arguments(iseq, ret, node->nd_args);
switch (ISEQ_BODY(iseq)->type) {
case ISEQ_TYPE_BLOCK:
@@ -881,7 +769,7 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
ADD_INSN (ret, &dummy_line_node, nop);
ADD_LABEL(ret, start);
- CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
+ CHECK(COMPILE(ret, "block body", node->nd_body));
ADD_LABEL(ret, end);
ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
@@ -894,23 +782,23 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
case ISEQ_TYPE_CLASS:
{
ADD_TRACE(ret, RUBY_EVENT_CLASS);
- CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
+ CHECK(COMPILE(ret, "scoped node", node->nd_body));
ADD_TRACE(ret, RUBY_EVENT_END);
ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
break;
}
case ISEQ_TYPE_METHOD:
{
- ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
+ ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
ADD_TRACE(ret, RUBY_EVENT_CALL);
- CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
- ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
+ CHECK(COMPILE(ret, "scoped node", node->nd_body));
+ ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
ADD_TRACE(ret, RUBY_EVENT_RETURN);
ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
break;
}
default: {
- CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
+ CHECK(COMPILE(ret, "scoped node", node->nd_body));
break;
}
}
@@ -968,20 +856,6 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
return iseq_setup(iseq, ret);
}
-static VALUE rb_translate_prism(pm_parser_t *parser, rb_iseq_t *iseq, pm_scope_node_t *scope_node, LINK_ANCHOR *const ret);
-
-VALUE
-rb_iseq_compile_prism_node(rb_iseq_t * iseq, pm_scope_node_t *scope_node, pm_parser_t *parser)
-{
- DECL_ANCHOR(ret);
- INIT_ANCHOR(ret);
-
- CHECK(rb_translate_prism(parser, iseq, scope_node, ret));
-
- CHECK(iseq_setup_insn(iseq, ret));
- return iseq_setup(iseq, ret);
-}
-
static int
rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
{
@@ -998,11 +872,6 @@ rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
}
FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
#endif
-
-#if USE_YJIT
- rb_yjit_live_iseq_count++;
-#endif
-
return COMPILE_OK;
}
@@ -1486,8 +1355,7 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
rb_ast_body_t ast;
ast.root = node;
- ast.frozen_string_literal = -1;
- ast.coverage_enabled = -1;
+ ast.compile_option = 0;
ast.script_lines = ISEQ_BODY(iseq)->variable.script_lines;
debugs("[new_child_iseq]> ---------------------------------------\n");
@@ -1516,14 +1384,11 @@ new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_call
}
static void
-set_catch_except_p(rb_iseq_t *iseq)
+set_catch_except_p(struct rb_iseq_constant_body *body)
{
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
- if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
- if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
- set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
- }
+ body->catch_except_p = true;
+ if (body->parent_iseq != NULL) {
+ set_catch_except_p(ISEQ_BODY(body->parent_iseq));
}
}
@@ -1535,7 +1400,7 @@ set_catch_except_p(rb_iseq_t *iseq)
So this function sets true for limited ISeqs with break/next/redo catch table entries
whose child ISeq would really raise an exception. */
static void
-update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
+update_catch_except_flags(struct rb_iseq_constant_body *body)
{
unsigned int pos;
size_t i;
@@ -1548,7 +1413,7 @@ update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
while (pos < body->iseq_size) {
insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
if (insn == BIN(throw)) {
- set_catch_except_p(iseq);
+ set_catch_except_p(body);
break;
}
pos += insn_len(insn);
@@ -1563,8 +1428,7 @@ update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
if (entry->type != CATCH_TYPE_BREAK
&& entry->type != CATCH_TYPE_NEXT
&& entry->type != CATCH_TYPE_REDO) {
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
+ body->catch_except_p = true;
break;
}
}
@@ -1576,9 +1440,9 @@ iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
if (NIL_P(catch_table_ary)) return;
unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
- const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
+ const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
for (i = 0; i < tlen; i++) {
- const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
LINK_ELEMENT *e;
@@ -1625,6 +1489,13 @@ iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
dump_disasm_list(FIRST_ELEMENT(anchor));
}
+ if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
+ debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
+ iseq_set_sequence_stackcaching(iseq, anchor);
+ if (compile_debug > 5)
+ dump_disasm_list(FIRST_ELEMENT(anchor));
+ }
+
debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
iseq_insert_nop_between_end_and_cont(iseq);
if (compile_debug > 5)
@@ -1654,12 +1525,10 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
debugs("[compile step 6 (update_catch_except_flags)] \n");
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- update_catch_except_flags(iseq, ISEQ_BODY(iseq));
+ update_catch_except_flags(ISEQ_BODY(iseq));
debugs("[compile step 6.1 (remove unused catch tables)] \n");
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
+ if (!ISEQ_BODY(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
xfree(ISEQ_BODY(iseq)->catch_table);
ISEQ_BODY(iseq)->catch_table = NULL;
}
@@ -1900,7 +1769,7 @@ static int
iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
const struct rb_args_info *args, int arg_size)
{
- const rb_node_kw_arg_t *node = args->kw_args;
+ const NODE *node = args->kw_args;
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
struct rb_iseq_param_keyword *keyword;
const VALUE default_values = rb_ary_hidden_new(1);
@@ -1919,7 +1788,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
node = args->kw_args;
while (node) {
- const NODE *val_node = get_nd_value(node->nd_body);
+ const NODE *val_node = node->nd_body->nd_value;
VALUE dv;
if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
@@ -1928,7 +1797,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
else {
switch (nd_type(val_node)) {
case NODE_LIT:
- dv = RNODE_LIT(val_node)->nd_lit;
+ dv = val_node->nd_lit;
break;
case NODE_NIL:
dv = Qnil;
@@ -1940,7 +1809,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
dv = Qfalse;
break;
default:
- NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
+ NO_CHECK(COMPILE_POPPED(optargs, "kwarg", node)); /* nd_type_p(node, NODE_KW_ARG) */
dv = complex_mark;
}
@@ -1953,7 +1822,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
keyword->num = kw;
- if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
+ if (args->kw_rest_arg->nd_vid != 0) {
keyword->rest_start = arg_size++;
body->param.flags.has_kwrest = TRUE;
}
@@ -1984,7 +1853,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
if (node_args) {
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
+ struct rb_args_info *args = node_args->nd_ainfo;
ID rest_id = 0;
int last_comma = 0;
ID block_id = 0;
@@ -2005,14 +1874,14 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
block_id = args->block_arg;
if (args->opt_args) {
- const rb_node_opt_arg_t *node = args->opt_args;
+ const NODE *node = args->opt_args;
LABEL *label;
VALUE labels = rb_ary_hidden_new(1);
VALUE *opt_table;
int i = 0, j;
while (node) {
- label = NEW_LABEL(nd_line(RNODE(node)));
+ label = NEW_LABEL(nd_line(node));
rb_ary_push(labels, (VALUE)label | 1);
ADD_LABEL(optargs, label);
NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
@@ -2027,7 +1896,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
opt_table = ALLOC_N(VALUE, i+1);
- MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
+ MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1);
for (j = 0; j < i+1; j++) {
opt_table[j] &= ~1;
}
@@ -2513,12 +2382,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
generated_iseq = ALLOC_N(VALUE, code_index);
insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
positions = ALLOC_N(unsigned int, insn_num);
- if (ISEQ_IS_SIZE(body)) {
- body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
- }
- else {
- body->is_entries = NULL;
- }
+ body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
@@ -2657,8 +2521,8 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
case TS_CALLDATA:
{
const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
- assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
+ assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
cd->ci = source_ci;
cd->cc = vm_cc_empty();
generated_iseq[code_index + 1 + j] = (VALUE)cd;
@@ -2796,16 +2660,18 @@ iseq_set_exception_table(rb_iseq_t *iseq)
struct iseq_catch_table_entry *entry;
ISEQ_BODY(iseq)->catch_table = NULL;
- if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) return COMPILE_OK;
- tlen = (int)RARRAY_LEN(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
- tptr = RARRAY_CONST_PTR(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
+
+ VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+ if (NIL_P(catch_table_ary)) return COMPILE_OK;
+ tlen = (int)RARRAY_LEN(catch_table_ary);
+ tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
if (tlen > 0) {
struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
table->size = tlen;
for (i = 0; i < table->size; i++) {
- ptr = RARRAY_CONST_PTR(tptr[i]);
+ ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
@@ -2834,6 +2700,8 @@ iseq_set_exception_table(rb_iseq_t *iseq)
RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
}
+ RB_GC_GUARD(catch_table_ary);
+
return COMPILE_OK;
}
@@ -2972,7 +2840,6 @@ remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
break;
}
else if ((lab = find_destination((INSN *)i)) != 0) {
- if (lab->unremovable) break;
unref_counts[lab->label_no]++;
}
}
@@ -2989,8 +2856,7 @@ remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
/* do nothing */
}
else if (IS_ADJUST(i)) {
- LABEL *dest = ((ADJUST *)i)->label;
- if (dest && dest->unremovable) return 0;
+ return 0;
}
end = i;
} while ((i = i->next) != 0);
@@ -3484,7 +3350,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
previ == BIN(getlocal) ||
previ == BIN(getblockparam) ||
previ == BIN(getblockparamproxy) ||
- previ == BIN(getinstancevariable) ||
+ /* getinstancevariable may issue a warning */
previ == BIN(duparray)) {
/* just push operand or static value and pop soon, no
* side effects */
@@ -3811,10 +3677,6 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_TRACE(iobj->link.next)) {
if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
- const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
- if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
- iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_INLINE;
- }
}
}
}
@@ -3867,18 +3729,13 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
switch (vm_ci_mid(ci)) {
case idMax:
+ iobj->insn_id = BIN(opt_newarray_max);
+ ELEM_REMOVE(&niobj->link);
+ return COMPILE_OK;
case idMin:
- case idHash:
- {
- VALUE num = iobj->operands[0];
- iobj->insn_id = BIN(opt_newarray_send);
- iobj->operands = compile_data_calloc2(iseq, insn_len(iobj->insn_id) - 1, sizeof(VALUE));
- iobj->operands[0] = num;
- iobj->operands[1] = rb_id2sym(vm_ci_mid(ci));
- iobj->operand_size = insn_len(iobj->insn_id) - 1;
- ELEM_REMOVE(&niobj->link);
- return COMPILE_OK;
- }
+ iobj->insn_id = BIN(opt_newarray_min);
+ ELEM_REMOVE(&niobj->link);
+ return COMPILE_OK;
}
}
}
@@ -3972,7 +3829,7 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
int do_block_optimization = 0;
- if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
+ if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_BODY(iseq)->catch_except_p) {
do_block_optimization = 1;
}
@@ -4110,6 +3967,167 @@ iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
return COMPILE_OK;
}
+#if OPT_STACK_CACHING
+
+#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
+#define SC_NEXT(insn) sc_insn_next[(insn)]
+
+#include "opt_sc.inc"
+
+static int
+insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
+{
+ int nstate;
+ int insn_id;
+
+ insn_id = iobj->insn_id;
+ iobj->insn_id = SC_INSN(insn_id, state);
+ nstate = SC_NEXT(iobj->insn_id);
+
+ if (insn_id == BIN(jump) ||
+ insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
+ LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
+
+ if (lobj->sc_state != 0) {
+ if (lobj->sc_state != nstate) {
+ BADINSN_DUMP(anchor, iobj, lobj);
+ COMPILE_ERROR(iseq, iobj->insn_info.line_no,
+ "insn_set_sc_state error: %d at "LABEL_FORMAT
+ ", %d expected\n",
+ lobj->sc_state, lobj->label_no, nstate);
+ return COMPILE_NG;
+ }
+ }
+ else {
+ lobj->sc_state = nstate;
+ }
+ if (insn_id == BIN(jump)) {
+ nstate = SCS_XX;
+ }
+ }
+ else if (insn_id == BIN(leave)) {
+ nstate = SCS_XX;
+ }
+
+ return nstate;
+}
+
+static int
+label_set_sc_state(LABEL *lobj, int state)
+{
+ if (lobj->sc_state != 0) {
+ if (lobj->sc_state != state) {
+ state = lobj->sc_state;
+ }
+ }
+ else {
+ lobj->sc_state = state;
+ }
+
+ return state;
+}
+
+
+#endif
+
+static int
+iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
+{
+#if OPT_STACK_CACHING
+ LINK_ELEMENT *list;
+ int state, insn_id;
+
+ /* initialize */
+ state = SCS_XX;
+ list = FIRST_ELEMENT(anchor);
+ /* dump_disasm_list(list); */
+
+ /* for each list element */
+ while (list) {
+ redo_point:
+ switch (list->type) {
+ case ISEQ_ELEMENT_INSN:
+ {
+ INSN *iobj = (INSN *)list;
+ insn_id = iobj->insn_id;
+
+ /* dump_disasm_list(list); */
+
+ switch (insn_id) {
+ case BIN(nop):
+ {
+ /* exception merge point */
+ if (state != SCS_AX) {
+ NODE dummy_line_node = generate_dummy_line_node(0, -1);
+ INSN *rpobj =
+ new_insn_body(iseq, &dummy_line_node, BIN(reput), 0);
+
+ /* replace this insn */
+ ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
+ list = (LINK_ELEMENT *)rpobj;
+ goto redo_point;
+ }
+ break;
+ }
+ case BIN(swap):
+ {
+ if (state == SCS_AB || state == SCS_BA) {
+ state = (state == SCS_AB ? SCS_BA : SCS_AB);
+
+ ELEM_REMOVE(list);
+ list = list->next;
+ goto redo_point;
+ }
+ break;
+ }
+ case BIN(pop):
+ {
+ switch (state) {
+ case SCS_AX:
+ case SCS_BX:
+ state = SCS_XX;
+ break;
+ case SCS_AB:
+ state = SCS_AX;
+ break;
+ case SCS_BA:
+ state = SCS_BX;
+ break;
+ case SCS_XX:
+ goto normal_insn;
+ default:
+ COMPILE_ERROR(iseq, iobj->insn_info.line_no,
+ "unreachable");
+ return COMPILE_NG;
+ }
+ /* remove useless pop */
+ ELEM_REMOVE(list);
+ list = list->next;
+ goto redo_point;
+ }
+ default:;
+ /* none */
+ } /* end of switch */
+ normal_insn:
+ state = insn_set_sc_state(iseq, anchor, iobj, state);
+ break;
+ }
+ case ISEQ_ELEMENT_LABEL:
+ {
+ LABEL *lobj;
+ lobj = (LABEL *)list;
+
+ state = label_set_sc_state(lobj, state);
+ }
+ default:
+ break;
+ }
+ list = list->next;
+ }
+#endif
+ return COMPILE_OK;
+}
+
static int
all_string_result_p(const NODE *node)
{
@@ -4118,16 +4136,16 @@ all_string_result_p(const NODE *node)
case NODE_STR: case NODE_DSTR:
return TRUE;
case NODE_IF: case NODE_UNLESS:
- if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
- if (all_string_result_p(RNODE_IF(node)->nd_body))
- return all_string_result_p(RNODE_IF(node)->nd_else);
+ if (!node->nd_body || !node->nd_else) return FALSE;
+ if (all_string_result_p(node->nd_body))
+ return all_string_result_p(node->nd_else);
return FALSE;
case NODE_AND: case NODE_OR:
- if (!RNODE_AND(node)->nd_2nd)
- return all_string_result_p(RNODE_AND(node)->nd_1st);
- if (!all_string_result_p(RNODE_AND(node)->nd_1st))
+ if (!node->nd_2nd)
+ return all_string_result_p(node->nd_1st);
+ if (!all_string_result_p(node->nd_1st))
return FALSE;
- return all_string_result_p(RNODE_AND(node)->nd_2nd);
+ return all_string_result_p(node->nd_2nd);
default:
return FALSE;
}
@@ -4136,8 +4154,8 @@ all_string_result_p(const NODE *node)
static int
compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
{
- const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
- VALUE lit = RNODE_DSTR(node)->nd_lit;
+ const NODE *list = node->nd_next;
+ VALUE lit = node->nd_lit;
LINK_ELEMENT *first_lit = 0;
int cnt = 0;
@@ -4158,7 +4176,7 @@ compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cons
while (list) {
const NODE *const head = list->nd_head;
if (nd_type_p(head, NODE_STR)) {
- lit = rb_fstring(RNODE_STR(head)->nd_lit);
+ lit = rb_fstring(head->nd_lit);
ADD_INSN1(ret, head, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
lit = Qnil;
@@ -4167,7 +4185,7 @@ compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cons
CHECK(COMPILE(ret, "each string", head));
}
cnt++;
- list = (struct RNode_LIST *)list->nd_next;
+ list = list->nd_next;
}
if (NIL_P(lit) && first_lit) {
ELEM_REMOVE(first_lit);
@@ -4182,12 +4200,12 @@ static int
compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
{
while (node && nd_type_p(node, NODE_BLOCK)) {
- CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
- (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
- node = RNODE_BLOCK(node)->nd_next;
+ CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
+ (node->nd_next ? 1 : popped)));
+ node = node->nd_next;
}
if (node) {
- CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
+ CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
}
return COMPILE_OK;
}
@@ -4196,8 +4214,8 @@ static int
compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
{
int cnt;
- if (!RNODE_DSTR(node)->nd_next) {
- VALUE lit = rb_fstring(RNODE_DSTR(node)->nd_lit);
+ if (!node->nd_next) {
+ VALUE lit = rb_fstring(node->nd_lit);
ADD_INSN1(ret, node, putstring, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@@ -4213,7 +4231,7 @@ compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
{
int cnt;
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
- ADD_INSN2(ret, node, toregexp, INT2FIX(RNODE_DREGX(node)->nd_cflag), INT2FIX(cnt));
+ ADD_INSN2(ret, node, toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
return COMPILE_OK;
}
@@ -4231,7 +4249,7 @@ compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
ADD_INSNL(ret, node, branchif, lend);
/* *flip == 0 */
- CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
+ CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
ADD_INSNL(ret, node, branchunless, else_label);
ADD_INSN1(ret, node, putobject, Qtrue);
ADD_INSN1(ret, node, setspecial, key);
@@ -4241,7 +4259,7 @@ compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
/* *flip == 1 */
ADD_LABEL(ret, lend);
- CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
+ CHECK(COMPILE(ret, "flip2 end", node->nd_end));
ADD_INSNL(ret, node, branchunless, then_label);
ADD_INSN1(ret, node, putobject, Qfalse);
ADD_INSN1(ret, node, setspecial, key);
@@ -4251,62 +4269,37 @@ compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
}
static int
-compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
- LABEL *then_label, LABEL *else_label);
-
-#define COMPILE_SINGLE 2
-static int
-compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
- LABEL *then_label, LABEL *else_label)
-{
- DECL_ANCHOR(seq);
- INIT_ANCHOR(seq);
- LABEL *label = NEW_LABEL(nd_line(cond));
- if (!then_label) then_label = label;
- else if (!else_label) else_label = label;
-
- CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
-
- if (LIST_INSN_SIZE_ONE(seq)) {
- INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
- if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
- return COMPILE_OK;
- }
- if (!label->refcnt) {
- return COMPILE_SINGLE;
- }
- ADD_LABEL(seq, label);
- ADD_SEQ(ret, seq);
- return COMPILE_OK;
-}
-
-static int
-compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
+compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
LABEL *then_label, LABEL *else_label)
{
- int ok;
- DECL_ANCHOR(ignore);
-
again:
switch (nd_type(cond)) {
case NODE_AND:
- CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
- cond = RNODE_AND(cond)->nd_2nd;
- if (ok == COMPILE_SINGLE) {
- INIT_ANCHOR(ignore);
- ret = ignore;
- then_label = NEW_LABEL(nd_line(cond));
- }
- goto again;
+ {
+ LABEL *label = NEW_LABEL(nd_line(cond));
+ CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
+ else_label));
+ if (!label->refcnt) {
+ ADD_INSN(ret, cond, putnil);
+ break;
+ }
+ ADD_LABEL(ret, label);
+ cond = cond->nd_2nd;
+ goto again;
+ }
case NODE_OR:
- CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
- cond = RNODE_OR(cond)->nd_2nd;
- if (ok == COMPILE_SINGLE) {
- INIT_ANCHOR(ignore);
- ret = ignore;
- else_label = NEW_LABEL(nd_line(cond));
- }
- goto again;
+ {
+ LABEL *label = NEW_LABEL(nd_line(cond));
+ CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
+ label));
+ if (!label->refcnt) {
+ ADD_INSN(ret, cond, putnil);
+ break;
+ }
+ ADD_LABEL(ret, label);
+ cond = cond->nd_2nd;
+ goto again;
+ }
case NODE_LIT: /* NODE_LIT is always true */
case NODE_TRUE:
case NODE_STR:
@@ -4337,28 +4330,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
break;
default:
- {
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
-
- CHECK(COMPILE(cond_seq, "branch condition", cond));
-
- if (LIST_INSN_SIZE_ONE(cond_seq)) {
- INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
- if (insn->insn_id == BIN(putobject)) {
- if (RTEST(insn->operands[0])) {
- ADD_INSNL(ret, cond, jump, then_label);
- // maybe unreachable
- return COMPILE_OK;
- }
- else {
- ADD_INSNL(ret, cond, jump, else_label);
- return COMPILE_OK;
- }
- }
- }
- ADD_SEQ(ret, cond_seq);
- }
+ CHECK(COMPILE(ret, "branch condition", cond));
break;
}
@@ -4372,35 +4344,33 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
static int
keyword_node_p(const NODE *const node)
{
- return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
+ return nd_type_p(node, NODE_HASH) && (node->nd_brace & HASH_BRACE) != HASH_BRACE;
}
static int
compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
- const NODE *const root_node,
- struct rb_callinfo_kwarg **const kw_arg_ptr,
- unsigned int *flag)
+ const NODE *const root_node,
+ struct rb_callinfo_kwarg **const kw_arg_ptr,
+ unsigned int *flag)
{
- RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
- RUBY_ASSERT(kw_arg_ptr != NULL);
- RUBY_ASSERT(flag != NULL);
+ if (kw_arg_ptr == NULL) return FALSE;
- if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
- const NODE *node = RNODE_HASH(root_node)->nd_head;
+ if (root_node->nd_head && nd_type_p(root_node->nd_head, NODE_LIST)) {
+ const NODE *node = root_node->nd_head;
int seen_nodes = 0;
while (node) {
- const NODE *key_node = RNODE_LIST(node)->nd_head;
+ const NODE *key_node = node->nd_head;
seen_nodes++;
assert(nd_type_p(node, NODE_LIST));
- if (key_node && nd_type_p(key_node, NODE_LIT) && SYMBOL_P(RNODE_LIT(key_node)->nd_lit)) {
+ if (key_node && nd_type_p(key_node, NODE_LIT) && SYMBOL_P(key_node->nd_lit)) {
/* can be keywords */
}
else {
if (flag) {
*flag |= VM_CALL_KW_SPLAT;
- if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
+ if (seen_nodes > 1 || node->nd_next->nd_next) {
/* A new hash will be created for the keyword arguments
* in this case, so mark the method as passing mutable
* keyword splat.
@@ -4410,27 +4380,26 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
}
return FALSE;
}
- node = RNODE_LIST(node)->nd_next; /* skip value node */
- node = RNODE_LIST(node)->nd_next;
+ node = node->nd_next; /* skip value node */
+ node = node->nd_next;
}
/* may be keywords */
- node = RNODE_HASH(root_node)->nd_head;
+ node = root_node->nd_head;
{
- int len = (int)RNODE_LIST(node)->as.nd_alen / 2;
+ int len = (int)node->nd_alen / 2;
struct rb_callinfo_kwarg *kw_arg =
rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
VALUE *keywords = kw_arg->keywords;
int i = 0;
- kw_arg->references = 0;
kw_arg->keyword_len = len;
*kw_arg_ptr = kw_arg;
- for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
- const NODE *key_node = RNODE_LIST(node)->nd_head;
- const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
- keywords[i] = RNODE_LIT(key_node)->nd_lit;
+ for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
+ const NODE *key_node = node->nd_head;
+ const NODE *val_node = node->nd_next->nd_head;
+ keywords[i] = key_node->nd_lit;
NO_CHECK(COMPILE(ret, "keyword values", val_node));
}
assert(i == len);
@@ -4441,21 +4410,26 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
}
static int
-compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
+compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
+ struct rb_callinfo_kwarg **keywords_ptr, unsigned int *flag)
{
int len = 0;
- for (; node; len++, node = RNODE_LIST(node)->nd_next) {
+ for (; node; len++, node = node->nd_next) {
if (CPDEBUG > 0) {
EXPECT_NODE("compile_args", node, NODE_LIST, -1);
}
- if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
- *kwnode_ptr = RNODE_LIST(node)->nd_head;
+ if (node->nd_next == NULL && keyword_node_p(node->nd_head)) { /* last node */
+ if (compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
+ len--;
+ }
+ else {
+ compile_hash(iseq, ret, node->nd_head, TRUE, FALSE);
+ }
}
else {
- RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
- NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
+ NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
}
}
@@ -4492,15 +4466,15 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq)
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
VALUE lit;
VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
- lit = rb_str_dup(RNODE_STR(node)->nd_lit);
+ lit = rb_str_dup(node->nd_lit);
rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
return rb_str_freeze(lit);
}
else {
- return rb_fstring(RNODE_STR(node)->nd_lit);
+ return rb_fstring(node->nd_lit);
}
default:
- return RNODE_LIT(node)->nd_lit;
+ return node->nd_lit;
}
}
@@ -4519,8 +4493,8 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
EXPECT_NODE("compile_array", node, NODE_LIST, -1);
if (popped) {
- for (; node; node = RNODE_LIST(node)->nd_next) {
- NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
+ for (; node; node = node->nd_next) {
+ NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
}
return 1;
}
@@ -4579,10 +4553,10 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
int count = 1;
/* pre-allocation check (this branch can be omittable) */
- if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq)) {
+ if (static_literal_node_p(node->nd_head, iseq)) {
/* count the elements that are optimizable */
- const NODE *node_tmp = RNODE_LIST(node)->nd_next;
- for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq); node_tmp = RNODE_LIST(node_tmp)->nd_next)
+ const NODE *node_tmp = node->nd_next;
+ for (; node_tmp && static_literal_node_p(node_tmp->nd_head, iseq); node_tmp = node_tmp->nd_next)
count++;
if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
@@ -4590,8 +4564,8 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
VALUE ary = rb_ary_hidden_new(count);
/* Create a hidden array */
- for (; count; count--, node = RNODE_LIST(node)->nd_next)
- rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
+ for (; count; count--, node = node->nd_next)
+ rb_ary_push(ary, static_literal_value(node->nd_head, iseq));
OBJ_FREEZE(ary);
/* Emit optimized code */
@@ -4609,15 +4583,15 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
}
/* Base case: Compile "count" elements */
- for (; count; count--, node = RNODE_LIST(node)->nd_next) {
+ for (; count; count--, node = node->nd_next) {
if (CPDEBUG > 0) {
EXPECT_NODE("compile_array", node, NODE_LIST, -1);
}
- NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
+ NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
stack_len++;
- if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
+ if (!node->nd_next && keyword_node_p(node->nd_head)) {
/* Reached the end, and the last element is a keyword */
FLUSH_CHUNK(newarraykwsplat);
return 1;
@@ -4646,7 +4620,12 @@ compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
}
else {
CHECK(COMPILE_(ret, "array element", node, FALSE));
- ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ if (keyword_node_p(node)) {
+ ADD_INSN1(ret, node, newarraykwsplat, INT2FIX(1));
+ }
+ else {
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ }
}
return 1;
@@ -4655,7 +4634,7 @@ compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
static inline int
static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
{
- return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
+ return node->nd_head && static_literal_node_p(node->nd_head, iseq) && static_literal_node_p(node->nd_next->nd_head, iseq);
}
static int
@@ -4663,7 +4642,7 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
{
const NODE *line_node = node;
- node = RNODE_HASH(node)->nd_head;
+ node = node->nd_head;
if (!node || nd_type_p(node, NODE_ZLIST)) {
if (!popped) {
@@ -4675,8 +4654,8 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
if (popped) {
- for (; node; node = RNODE_LIST(node)->nd_next) {
- NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
+ for (; node; node = node->nd_next) {
+ NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
}
return 1;
}
@@ -4729,8 +4708,8 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
/* pre-allocation check (this branch can be omittable) */
if (static_literal_node_pair_p(node, iseq)) {
/* count the elements that are optimizable */
- const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
- for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
+ const NODE *node_tmp = node->nd_next->nd_next;
+ for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
count++;
if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
@@ -4738,14 +4717,14 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
VALUE ary = rb_ary_hidden_new(count);
/* Create a hidden hash */
- for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
+ for (; count; count--, node = node->nd_next->nd_next) {
VALUE elem[2];
- elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
- elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
+ elem[0] = static_literal_value(node->nd_head, iseq);
+ elem[1] = static_literal_value(node->nd_next->nd_head, iseq);
rb_ary_cat(ary, elem, 2);
}
VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
- rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
+ rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
hash = rb_obj_hide(hash);
OBJ_FREEZE(hash);
@@ -4768,16 +4747,16 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
}
/* Base case: Compile "count" elements */
- for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
+ for (; count; count--, node = node->nd_next->nd_next) {
if (CPDEBUG > 0) {
EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
}
- if (RNODE_LIST(node)->nd_head) {
+ if (node->nd_head) {
/* Normal key-value pair */
- NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
- NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
+ NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
+ NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
stack_len += 2;
/* If there are many pushed elements, flush them to avoid stack overflow */
@@ -4787,10 +4766,10 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
/* kwsplat case: foo(..., **kw, ...) */
FLUSH_CHUNK();
- const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
- int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(RNODE_LIT(kw)->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
+ const NODE *kw = node->nd_next->nd_head;
+ int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
- int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
+ int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
if (empty_kw) {
@@ -4853,7 +4832,7 @@ rb_node_case_when_optimizable_literal(const NODE *const node)
{
switch (nd_type(node)) {
case NODE_LIT: {
- VALUE v = RNODE_LIT(node)->nd_lit;
+ VALUE v = node->nd_lit;
double ival;
if (RB_FLOAT_TYPE_P(v) &&
modf(RFLOAT_VALUE(v), &ival) == 0.0) {
@@ -4874,7 +4853,7 @@ rb_node_case_when_optimizable_literal(const NODE *const node)
case NODE_FALSE:
return Qfalse;
case NODE_STR:
- return rb_fstring(RNODE_STR(node)->nd_lit);
+ return rb_fstring(node->nd_lit);
}
return Qundef;
}
@@ -4884,7 +4863,7 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
LABEL *l1, int only_special_literals, VALUE literals)
{
while (vals) {
- const NODE *val = RNODE_LIST(vals)->nd_head;
+ const NODE *val = vals->nd_head;
VALUE lit = rb_node_case_when_optimizable_literal(val);
if (UNDEF_P(lit)) {
@@ -4895,8 +4874,8 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
}
if (nd_type_p(val, NODE_STR)) {
- debugp_param("nd_lit", RNODE_STR(val)->nd_lit);
- lit = rb_fstring(RNODE_STR(val)->nd_lit);
+ debugp_param("nd_lit", val->nd_lit);
+ lit = rb_fstring(val->nd_lit);
ADD_INSN1(cond_seq, val, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@@ -4904,11 +4883,11 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
if (!COMPILE(cond_seq, "when cond", val)) return -1;
}
- // Emit pattern === target
+ // Emit patern === target
ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
ADD_INSNL(cond_seq, val, branchif, l1);
- vals = RNODE_LIST(vals)->nd_next;
+ vals = vals->nd_next;
}
return only_special_literals;
}
@@ -4926,19 +4905,19 @@ when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
break;
case NODE_SPLAT:
ADD_INSN (cond_seq, line_node, dup);
- CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
+ CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
ADD_INSNL(cond_seq, line_node, branchif, l1);
break;
case NODE_ARGSCAT:
- CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
- CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
+ CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
+ CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
break;
case NODE_ARGSPUSH:
- CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
+ CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
ADD_INSN (cond_seq, line_node, dup);
- CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
+ CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
ADD_INSNL(cond_seq, line_node, branchif, l1);
break;
@@ -5097,12 +5076,17 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
+ bool safenav_call = false;
LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
ASSUME(iobj);
- ELEM_REMOVE(LAST_ELEMENT(pre));
- ELEM_REMOVE((LINK_ELEMENT *)iobj);
- pre->last = iobj->link.prev;
+ ELEM_REMOVE(insn_element);
+ if (!IS_INSN_ID(iobj, send)) {
+ safenav_call = true;
+ iobj = (INSN *)get_prev_insn(iobj);
+ ELEM_INSERT_NEXT(&iobj->link, insn_element);
+ }
+ (pre->last = iobj->link.prev)->next = 0;
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
int argc = vm_ci_argc(ci) + 1;
@@ -5121,7 +5105,9 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
return COMPILE_NG;
}
- ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
+ iobj->link.prev = lhs->last;
+ lhs->last->next = &iobj->link;
+ for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
int argc = vm_ci_argc(ci);
ci = ci_argc_set(iseq, ci, argc - 1);
@@ -5130,9 +5116,11 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
INSERT_BEFORE_INSN(iobj, line_node, concatarray);
}
- ADD_INSN(lhs, line_node, pop);
- if (argc != 1) {
+ if (!safenav_call) {
ADD_INSN(lhs, line_node, pop);
+ if (argc != 1) {
+ ADD_INSN(lhs, line_node, pop);
+ }
}
for (int i=0; i < argc; i++) {
ADD_INSN(post, line_node, pop);
@@ -5158,7 +5146,7 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
break;
}
case NODE_CDECL:
- if (!RNODE_CDECL(node)->nd_vid) {
+ if (!node->nd_vid) {
/* Special handling only needed for expr::C, not for C */
INSN *iobj;
@@ -5196,8 +5184,8 @@ static int
compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
{
if (lhsn) {
- CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
- CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
+ CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
+ CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, lhsn->nd_head, NULL, 0));
}
return COMPILE_OK;
}
@@ -5227,29 +5215,31 @@ compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
}
while (lhsn) {
- const NODE *ln = RNODE_LIST(lhsn)->nd_head;
+ const NODE *ln = lhsn->nd_head;
switch (nd_type(ln)) {
case NODE_LASGN:
+ MEMORY(ln->nd_vid);
+ break;
case NODE_DASGN:
case NODE_IASGN:
case NODE_CVASGN:
- MEMORY(get_nd_vid(ln));
+ MEMORY(ln->nd_vid);
break;
default:
return 0;
}
- lhsn = RNODE_LIST(lhsn)->nd_next;
+ lhsn = lhsn->nd_next;
llen++;
}
while (rhsn) {
if (llen <= rlen) {
- NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
+ NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
}
else {
- NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
+ NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
}
- rhsn = RNODE_LIST(rhsn)->nd_next;
+ rhsn = rhsn->nd_next;
rlen++;
}
@@ -5266,31 +5256,32 @@ compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
static int
compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped)
{
- const NODE *rhsn = RNODE_MASGN(node)->nd_value;
- const NODE *splatn = RNODE_MASGN(node)->nd_args;
- const NODE *lhsn = RNODE_MASGN(node)->nd_head;
+ const NODE *rhsn = node->nd_value;
+ const NODE *splatn = node->nd_args;
+ const NODE *lhsn = node->nd_head;
const NODE *lhsn_count = lhsn;
int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
int llen = 0;
int lpos = 0;
+ int expand = 1;
while (lhsn_count) {
llen++;
- lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
+ lhsn_count = lhsn_count->nd_next;
}
while (lhsn) {
- CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
+ CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, lhsn->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
lpos++;
- lhsn = RNODE_LIST(lhsn)->nd_next;
+ lhsn = lhsn->nd_next;
}
if (lhs_splat) {
if (nd_type_p(splatn, NODE_POSTARG)) {
/*a, b, *r, p1, p2 */
- const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
- const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
- int plen = (int)RNODE_LIST(postn)->as.nd_alen;
+ const NODE *postn = splatn->nd_2nd;
+ const NODE *restn = splatn->nd_1st;
+ int plen = (int)postn->nd_alen;
int ppos = 0;
int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
@@ -5300,9 +5291,9 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
}
while (postn) {
- CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
+ CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, postn->nd_head, state, (plen - ppos) + state->lhs_level));
ppos++;
- postn = RNODE_LIST(postn)->nd_next;
+ postn = postn->nd_next;
}
}
else {
@@ -5311,6 +5302,7 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
}
}
+
if (!state->nested) {
NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
}
@@ -5318,14 +5310,16 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
if (!popped) {
ADD_INSN(rhs, node, dup);
}
- ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
+ if (expand) {
+ ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
+ }
return COMPILE_OK;
}
static int
compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
- if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
+ if (!popped || node->nd_args || !compile_massign_opt(iseq, ret, node->nd_value, node->nd_head)) {
struct masgn_state state;
state.lhs_level = popped ? 0 : 1;
state.nested = 0;
@@ -5374,15 +5368,15 @@ collect_const_segments(rb_iseq_t *iseq, const NODE *node)
for (;;) {
switch (nd_type(node)) {
case NODE_CONST:
- rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
+ rb_ary_unshift(arr, ID2SYM(node->nd_vid));
return arr;
case NODE_COLON3:
- rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ rb_ary_unshift(arr, ID2SYM(node->nd_mid));
rb_ary_unshift(arr, ID2SYM(idNULL));
return arr;
case NODE_COLON2:
- rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
- node = RNODE_COLON2(node)->nd_head;
+ rb_ary_unshift(arr, ID2SYM(node->nd_mid));
+ node = node->nd_head;
break;
default:
return Qfalse;
@@ -5396,22 +5390,22 @@ compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
{
switch (nd_type(node)) {
case NODE_CONST:
- debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
+ debugi("compile_const_prefix - colon", node->nd_vid);
ADD_INSN1(body, node, putobject, Qtrue);
- ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
+ ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_vid));
break;
case NODE_COLON3:
- debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
+ debugi("compile_const_prefix - colon3", node->nd_mid);
ADD_INSN(body, node, pop);
ADD_INSN1(body, node, putobject, rb_cObject);
ADD_INSN1(body, node, putobject, Qtrue);
- ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
break;
case NODE_COLON2:
- CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
- debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
+ CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
+ debugi("compile_const_prefix - colon2", node->nd_mid);
ADD_INSN1(body, node, putobject, Qfalse);
- ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
+ ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
break;
default:
CHECK(COMPILE(pref, "const colon2 prefix", node));
@@ -5428,9 +5422,9 @@ compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
ADD_INSN1(ret, cpath, putobject, rb_cObject);
return VM_DEFINECLASS_FLAG_SCOPED;
}
- else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
+ else if (cpath->nd_head) {
/* Bar::Foo */
- NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
+ NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
return VM_DEFINECLASS_FLAG_SCOPED;
}
else {
@@ -5444,9 +5438,9 @@ compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
static inline int
private_recv_p(const NODE *node)
{
- NODE *recv = get_nd_recv(node);
- if (recv && nd_type_p(recv, NODE_SELF)) {
- return RNODE_SELF(recv)->nd_state != 0;
+ if (nd_type_p(node->nd_recv, NODE_SELF)) {
+ NODE *self = node->nd_recv;
+ return self->nd_state != 0;
}
return 0;
}
@@ -5488,13 +5482,13 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
const NODE *vals = node;
do {
- defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
+ defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse, false);
if (!lfinish[1]) {
lfinish[1] = NEW_LABEL(line);
}
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
- } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
+ } while ((vals = vals->nd_next) != NULL);
}
/* fall through */
case NODE_STR:
@@ -5514,48 +5508,49 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
case NODE_IVAR:
- ADD_INSN3(ret, line_node, definedivar,
- ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
+ ADD_INSN(ret, line_node, putnil);
+ ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_IVAR),
+ ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_IVAR));
return;
case NODE_GVAR:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
- ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
+ ID2SYM(node->nd_entry), PUSH_VAL(DEFINED_GVAR));
return;
case NODE_CVAR:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
- ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
+ ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CVAR));
return;
case NODE_CONST:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
- ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
+ ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CONST));
return;
case NODE_COLON2:
if (!lfinish[1]) {
lfinish[1] = NEW_LABEL(line);
}
- defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
+ defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse, false);
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
- NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
+ NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
- if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
+ if (rb_is_const_id(node->nd_mid)) {
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
- ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
}
else {
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
- ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
}
return;
case NODE_COLON3:
ADD_INSN1(ret, line_node, putobject, rb_cObject);
ADD_INSN3(ret, line_node, defined,
- INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
+ INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
return;
/* method dispatch */
@@ -5568,7 +5563,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
(type == NODE_CALL || type == NODE_OPCALL ||
(type == NODE_ATTRASGN && !private_recv_p(node)));
- if (get_nd_args(node) || explicit_receiver) {
+ if (node->nd_args || explicit_receiver) {
if (!lfinish[1]) {
lfinish[1] = NEW_LABEL(line);
}
@@ -5576,31 +5571,31 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
lfinish[2] = NEW_LABEL(line);
}
}
- if (get_nd_args(node)) {
- defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
+ if (node->nd_args) {
+ defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse, false);
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
}
if (explicit_receiver) {
- defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
- switch (nd_type(get_nd_recv(node))) {
+ defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse, true);
+ switch (nd_type(node->nd_recv)) {
case NODE_CALL:
case NODE_OPCALL:
case NODE_VCALL:
case NODE_FCALL:
case NODE_ATTRASGN:
ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
- compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
+ compile_call(iseq, ret, node->nd_recv, nd_type(node->nd_recv), line_node, 0, true);
break;
default:
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
- NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
+ NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
break;
}
if (keep_result) {
ADD_INSN(ret, line_node, dup);
}
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
- ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
}
else {
ADD_INSN(ret, line_node, putself);
@@ -5608,7 +5603,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
ADD_INSN(ret, line_node, dup);
}
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
- ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
}
return;
}
@@ -5623,7 +5618,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
case NODE_NTH_REF:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
- INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
+ INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
PUSH_VAL(DEFINED_GVAR));
return;
@@ -5699,7 +5694,7 @@ compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const
{
const int line = nd_line(node);
const NODE *line_node = node;
- if (!RNODE_DEFINED(node)->nd_head) {
+ if (!node->nd_head) {
VALUE str = rb_iseq_defined_string(DEFINED_NIL);
ADD_INSN1(ret, line_node, putobject, str);
}
@@ -5709,7 +5704,7 @@ compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const
lfinish[0] = NEW_LABEL(line);
lfinish[1] = 0;
lfinish[2] = 0;
- defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr);
+ defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
if (lfinish[1]) {
ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
ADD_INSN(ret, line_node, swap);
@@ -5750,7 +5745,7 @@ make_name_for_block(const rb_iseq_t *orig_iseq)
static void
push_ensure_entry(rb_iseq_t *iseq,
struct iseq_compile_data_ensure_node_stack *enl,
- struct ensure_range *er, const void *const node)
+ struct ensure_range *er, const NODE *const node)
{
enl->ensure_node = node;
enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
@@ -5826,138 +5821,79 @@ add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
ADD_SEQ(ret, ensure);
}
-#if RUBY_DEBUG
static int
check_keyword(const NODE *node)
{
/* This check is essentially a code clone of compile_keyword_arg. */
if (nd_type_p(node, NODE_LIST)) {
- while (RNODE_LIST(node)->nd_next) {
- node = RNODE_LIST(node)->nd_next;
+ while (node->nd_next) {
+ node = node->nd_next;
}
- node = RNODE_LIST(node)->nd_head;
+ node = node->nd_head;
}
return keyword_node_p(node);
}
-#endif
-
-static bool
-keyword_node_single_splat_p(NODE *kwnode)
-{
- RUBY_ASSERT(keyword_node_p(kwnode));
-
- NODE *node = RNODE_HASH(kwnode)->nd_head;
- return RNODE_LIST(node)->nd_head == NULL &&
- RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
-}
-static int
+static VALUE
setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
- int dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
-{
- if (!argn) return 0;
-
- NODE *kwnode = NULL;
-
- switch (nd_type(argn)) {
- case NODE_LIST: {
- // f(x, y, z)
- int len = compile_args(iseq, args, argn, &kwnode);
- RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
-
- if (kwnode) {
- if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
- len -= 1;
+ int dup_rest, unsigned int *flag, struct rb_callinfo_kwarg **keywords)
+{
+ if (argn) {
+ switch (nd_type(argn)) {
+ case NODE_SPLAT: {
+ NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
+ ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
+ if (flag) *flag |= VM_CALL_ARGS_SPLAT;
+ return INT2FIX(1);
+ }
+ case NODE_ARGSCAT:
+ case NODE_ARGSPUSH: {
+ int next_is_list = (nd_type_p(argn->nd_head, NODE_LIST));
+ VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
+ if (nd_type_p(argn->nd_body, NODE_LIST)) {
+ /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
+ int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
+ ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
}
else {
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
+ NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
}
- }
-
- return len;
- }
- case NODE_SPLAT: {
- // f(*a)
- NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
- ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
- if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
- RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
- return 1;
- }
- case NODE_ARGSCAT: {
- if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
- int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, 1, NULL, NULL);
-
- if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
- int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
- if (kwnode) rest_len--;
- ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
- }
- else {
- RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
- NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
- }
-
- if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
- ADD_INSN1(args, argn, splatarray, Qtrue);
- argc += 1;
- }
- else {
- ADD_INSN1(args, argn, splatarray, Qfalse);
- ADD_INSN(args, argn, concatarray);
- }
-
- // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
- if (kwnode) {
- // kwsplat
- *flag_ptr |= VM_CALL_KW_SPLAT;
- *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
- argc += 1;
- }
-
- return argc;
- }
- case NODE_ARGSPUSH: {
- if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
- int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, 1, NULL, NULL);
-
- if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
- int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
- if (kwnode) rest_len--;
- ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
- ADD_INSN1(args, argn, newarray, INT2FIX(1));
- ADD_INSN(args, argn, concatarray);
- }
- else {
- if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
- kwnode = RNODE_ARGSPUSH(argn)->nd_body;
+ if (flag) {
+ *flag |= VM_CALL_ARGS_SPLAT;
+ /* This is a dirty hack. It traverses the AST twice.
+ * In a long term, it should be fixed by a redesign of keyword arguments */
+ if (check_keyword(argn->nd_body))
+ *flag |= VM_CALL_KW_SPLAT;
+ }
+ if (nd_type_p(argn, NODE_ARGSCAT)) {
+ if (next_is_list) {
+ ADD_INSN1(args, argn, splatarray, Qtrue);
+ return INT2FIX(FIX2INT(argc) + 1);
+ }
+ else {
+ ADD_INSN1(args, argn, splatarray, Qfalse);
+ ADD_INSN(args, argn, concatarray);
+ return argc;
+ }
}
else {
- NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
ADD_INSN1(args, argn, newarray, INT2FIX(1));
ADD_INSN(args, argn, concatarray);
+ return argc;
}
+ }
+ case NODE_LIST: {
+ int len = compile_args(iseq, args, argn, keywords, flag);
+ return INT2FIX(len);
+ }
+ default: {
+ UNKNOWN_NODE("setup_arg", argn, Qnil);
+ }
}
-
- if (kwnode) {
- // f(*a, k:1)
- *flag_ptr |= VM_CALL_KW_SPLAT;
- if (!keyword_node_single_splat_p(kwnode)) {
- *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
- }
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
- argc += 1;
- }
-
- return argc;
- }
- default: {
- UNKNOWN_NODE("setup_arg", argn, Qnil);
- }
}
+ return INT2FIX(0);
}
static VALUE
@@ -5969,7 +5905,7 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
unsigned int dup_rest = 1;
DECL_ANCHOR(arg_block);
INIT_ANCHOR(arg_block);
- NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
+ NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
*flag |= VM_CALL_ARGS_BLOCKARG;
@@ -5983,11 +5919,11 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
dup_rest = 0;
}
}
- ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, dup_rest, flag, keywords));
+ ret = setup_args_core(iseq, args, argn->nd_head, dup_rest, flag, keywords);
ADD_SEQ(args, arg_block);
}
else {
- ret = INT2FIX(setup_args_core(iseq, args, argn, 0, flag, keywords));
+ ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
}
return ret;
}
@@ -6023,19 +5959,19 @@ compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
ADD_INSN(ret, line_node, dup);
ADD_INSNL(ret, line_node, branchunless, fail_label);
- for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
+ for (vars = node; vars; vars = vars->nd_next) {
INSN *cap;
- if (RNODE_BLOCK(vars)->nd_next) {
+ if (vars->nd_next) {
ADD_INSN(ret, line_node, dup);
}
last = ret->last;
- NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
+ NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
last = last->next; /* putobject :var */
cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
NULL, INT2FIX(0), NULL);
ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
- if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
+ if (!vars->nd_next && vars == node) {
/* only one name */
DECL_ANCHOR(nom);
@@ -6056,9 +5992,9 @@ compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
ADD_INSNL(ret, line_node, jump, end_label);
ADD_LABEL(ret, fail_label);
ADD_INSN(ret, line_node, pop);
- for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
+ for (vars = node; vars; vars = vars->nd_next) {
last = ret->last;
- NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
+ NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
last = last->next; /* putobject :var */
((INSN*)last)->insn_id = BIN(putnil);
((INSN*)last)->operand_size = 0;
@@ -6072,7 +6008,7 @@ optimizable_range_item_p(const NODE *n)
if (!n) return FALSE;
switch (nd_type(n)) {
case NODE_LIT:
- return RB_INTEGER_TYPE_P(RNODE_LIT(n)->nd_lit);
+ return RB_INTEGER_TYPE_P(n->nd_lit);
case NODE_NIL:
return TRUE;
default:
@@ -6083,21 +6019,53 @@ optimizable_range_item_p(const NODE *n)
static int
compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
{
- const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
- const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
+ struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
+ const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
+ const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
const int line = nd_line(node);
const NODE *line_node = node;
DECL_ANCHOR(cond_seq);
+ DECL_ANCHOR(then_seq);
+ DECL_ANCHOR(else_seq);
LABEL *then_label, *else_label, *end_label;
VALUE branches = Qfalse;
+ int ci_size;
+ VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+ long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
INIT_ANCHOR(cond_seq);
+ INIT_ANCHOR(then_seq);
+ INIT_ANCHOR(else_seq);
then_label = NEW_LABEL(line);
else_label = NEW_LABEL(line);
end_label = 0;
- compile_branch_condition(iseq, cond_seq, RNODE_IF(node)->nd_cond, then_label, else_label);
+ compile_branch_condition(iseq, cond_seq, node->nd_cond,
+ then_label, else_label);
+
+ ci_size = body->ci_size;
+ CHECK(COMPILE_(then_seq, "then", node_body, popped));
+ catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+ if (!then_label->refcnt) {
+ body->ci_size = ci_size;
+ if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
+ }
+ else {
+ if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
+ }
+
+ ci_size = body->ci_size;
+ CHECK(COMPILE_(else_seq, "else", node_else, popped));
+ catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+ if (!else_label->refcnt) {
+ body->ci_size = ci_size;
+ if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
+ }
+ else {
+ if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
+ }
+
ADD_SEQ(ret, cond_seq);
if (then_label->refcnt && else_label->refcnt) {
@@ -6106,11 +6074,6 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int
if (then_label->refcnt) {
ADD_LABEL(ret, then_label);
-
- DECL_ANCHOR(then_seq);
- INIT_ANCHOR(then_seq);
- CHECK(COMPILE_(then_seq, "then", node_body, popped));
-
if (else_label->refcnt) {
add_trace_branch_coverage(
iseq,
@@ -6130,11 +6093,6 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int
if (else_label->refcnt) {
ADD_LABEL(ret, else_label);
-
- DECL_ANCHOR(else_seq);
- INIT_ANCHOR(else_seq);
- CHECK(COMPILE_(else_seq, "else", node_else, popped));
-
if (then_label->refcnt) {
add_trace_branch_coverage(
iseq,
@@ -6177,11 +6135,11 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
RHASH_TBL_RAW(literals)->type = &cdhash_type;
- CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
+ CHECK(COMPILE(head, "case base", node->nd_head));
branches = decl_branch_base(iseq, node, "case");
- node = RNODE_CASE(node)->nd_body;
+ node = node->nd_body;
EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
type = nd_type(node);
line = nd_line(node);
@@ -6201,14 +6159,14 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
add_trace_branch_coverage(
iseq,
body_seq,
- RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
+ node->nd_body ? node->nd_body : node,
branch_id++,
"when",
branches);
- CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
+ CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
ADD_INSNL(body_seq, line_node, jump, endlabel);
- vals = RNODE_WHEN(node)->nd_head;
+ vals = node->nd_head;
if (vals) {
switch (nd_type(vals)) {
case NODE_LIST:
@@ -6229,7 +6187,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
}
- node = RNODE_WHEN(node)->nd_next;
+ node = node->nd_next;
if (!node) {
break;
}
@@ -6274,7 +6232,7 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
{
const NODE *vals;
const NODE *val;
- const NODE *node = RNODE_CASE2(orig_node)->nd_body;
+ const NODE *node = orig_node->nd_body;
LABEL *endlabel;
DECL_ANCHOR(body_seq);
VALUE branches = Qfalse;
@@ -6292,14 +6250,14 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
add_trace_branch_coverage(
iseq,
body_seq,
- RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
+ node->nd_body ? node->nd_body : node,
branch_id++,
"when",
branches);
- CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
+ CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
ADD_INSNL(body_seq, node, jump, endlabel);
- vals = RNODE_WHEN(node)->nd_head;
+ vals = node->nd_head;
if (!vals) {
EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
}
@@ -6307,12 +6265,12 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
case NODE_LIST:
while (vals) {
LABEL *lnext;
- val = RNODE_LIST(vals)->nd_head;
+ val = vals->nd_head;
lnext = NEW_LABEL(nd_line(val));
debug_compile("== when2\n", (void)0);
CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
ADD_LABEL(ret, lnext);
- vals = RNODE_LIST(vals)->nd_next;
+ vals = vals->nd_next;
}
break;
case NODE_SPLAT:
@@ -6326,7 +6284,7 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
default:
UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
}
- node = RNODE_WHEN(node)->nd_next;
+ node = node->nd_next;
}
/* else */
add_trace_branch_coverage(
@@ -6418,13 +6376,14 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
* match_failed:
* goto unmatched
*/
- const NODE *args = RNODE_ARYPTN(node)->pre_args;
- const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
- const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
+ struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
+ const NODE *args = apinfo->pre_args;
+ const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
+ const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
const int min_argc = pre_args_num + post_args_num;
- const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
- (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
+ const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
+ (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
int i;
@@ -6448,10 +6407,10 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, dup);
ADD_SEND(ret, line_node, idLength, INT2FIX(0));
ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
- ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
+ ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
if (in_single_pattern) {
CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
- RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
+ apinfo->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
INT2FIX(min_argc), base_index + 1 /* (1) */));
}
@@ -6461,12 +6420,12 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
- args = RNODE_LIST(args)->nd_next;
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
+ args = args->nd_next;
}
- if (RNODE_ARYPTN(node)->rest_arg) {
- if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
+ if (apinfo->rest_arg) {
+ if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
ADD_INSN1(ret, line_node, topn, INT2FIX(1));
@@ -6476,7 +6435,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, setn, INT2FIX(4));
ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_ARYPTN(node)->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
}
else {
if (post_args_num > 0) {
@@ -6490,7 +6449,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
}
- args = RNODE_ARYPTN(node)->post_args;
+ args = apinfo->post_args;
for (i = 0; i < post_args_num; i++) {
ADD_INSN(ret, line_node, dup);
@@ -6499,8 +6458,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
- args = RNODE_LIST(args)->nd_next;
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
+ args = args->nd_next;
}
ADD_INSN(ret, line_node, pop);
@@ -6578,8 +6537,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
* match_failed:
* goto unmatched
*/
- const NODE *args = RNODE_FNDPTN(node)->args;
- const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
+ struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
+ const NODE *args = fpinfo->args;
+ const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
match_failed = NEW_LABEL(line);
@@ -6632,25 +6592,25 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
- args = RNODE_LIST(args)->nd_next;
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
+ args = args->nd_next;
}
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
+ if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
ADD_INSN1(ret, line_node, topn, INT2FIX(2));
ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
}
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
+ if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_INSN1(ret, line_node, topn, INT2FIX(1));
ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
}
ADD_INSNL(ret, line_node, jump, find_succeeded);
@@ -6764,12 +6724,12 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
match_failed = NEW_LABEL(line);
type_error = NEW_LABEL(line);
- if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
- const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
- keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
+ if (node->nd_pkwargs && !node->nd_pkwrestarg) {
+ const NODE *kw_args = node->nd_pkwargs->nd_head;
+ keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
while (kw_args) {
- rb_ary_push(keys, RNODE_LIT(RNODE_LIST(kw_args)->nd_head)->nd_lit);
- kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
+ rb_ary_push(keys, kw_args->nd_head->nd_lit);
+ kw_args = kw_args->nd_next->nd_next;
}
}
@@ -6796,28 +6756,28 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
ADD_INSNL(ret, line_node, branchunless, type_error);
- if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
+ if (node->nd_pkwrestarg) {
ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
}
- if (RNODE_HSHPTN(node)->nd_pkwargs) {
+ if (node->nd_pkwargs) {
int i;
int keys_num;
const NODE *args;
- args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
+ args = node->nd_pkwargs->nd_head;
if (args) {
DECL_ANCHOR(match_values);
INIT_ANCHOR(match_values);
- keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
+ keys_num = rb_long2int(args->nd_alen) / 2;
for (i = 0; i < keys_num; i++) {
- NODE *key_node = RNODE_LIST(args)->nd_head;
- NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
+ NODE *key_node = args->nd_head;
+ NODE *value_node = args->nd_next->nd_head;
VALUE key;
if (!nd_type_p(key_node, NODE_LIT)) {
UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
}
- key = RNODE_LIT(key_node)->nd_lit;
+ key = key_node->nd_lit;
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, key);
@@ -6846,9 +6806,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(match_values, line_node, dup);
ADD_INSN1(match_values, line_node, putobject, key);
- ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
+ ADD_SEND(match_values, line_node, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
- args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
+ args = args->nd_next->nd_next;
}
ADD_SEQ(ret, match_values);
}
@@ -6862,8 +6822,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSNL(ret, line_node, branchunless, match_failed);
}
- if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
- if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
+ if (node->nd_pkwrestarg) {
+ if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
ADD_INSN(ret, line_node, dup);
ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
if (in_single_pattern) {
@@ -6873,7 +6833,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
else {
ADD_INSN(ret, line_node, dup); // (11)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_HSHPTN(node)->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
}
}
@@ -6930,7 +6890,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
break;
case NODE_LASGN: {
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- ID id = RNODE_LASGN(node)->nd_vid;
+ ID id = node->nd_vid;
int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
if (in_alt_pattern) {
@@ -6948,7 +6908,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
case NODE_DASGN: {
int idx, lv, ls;
- ID id = RNODE_DASGN(node)->nd_vid;
+ ID id = node->nd_vid;
idx = get_dyna_var_idx(iseq, id, &lv, &ls);
@@ -6974,8 +6934,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
case NODE_UNLESS: {
LABEL *match_failed;
match_failed = unmatched;
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
- CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
+ CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
+ CHECK(COMPILE(ret, "case in if", node->nd_cond));
if (in_single_pattern) {
LABEL *match_succeeded;
match_succeeded = NEW_LABEL(line);
@@ -7012,15 +6972,15 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
LABEL *match_failed;
match_failed = NEW_LABEL(line);
- n = RNODE_HASH(node)->nd_head;
- if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
+ n = node->nd_head;
+ if (! (nd_type_p(n, NODE_LIST) && n->nd_alen == 2)) {
COMPILE_ERROR(ERROR_ARGS "unexpected node");
return COMPILE_NG;
}
ADD_INSN(ret, line_node, dup); // (1)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(n)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
- CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, n->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
+ CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
ADD_INSN(ret, line_node, putnil);
ADD_LABEL(ret, match_failed);
@@ -7034,13 +6994,13 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
fin = NEW_LABEL(line);
ADD_INSN(ret, line_node, dup); // (1)
- CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
+ CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
ADD_LABEL(ret, match_succeeded);
ADD_INSN(ret, line_node, pop);
ADD_INSNL(ret, line_node, jump, matched);
ADD_INSN(ret, line_node, putnil);
ADD_LABEL(ret, fin);
- CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
+ CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
break;
}
default:
@@ -7063,9 +7023,9 @@ iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NOD
{
const NODE *line_node = node;
- if (RNODE_ARYPTN(node)->nd_pconst) {
+ if (node->nd_pconst) {
ADD_INSN(ret, line_node, dup); // (1)
- CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
+ CHECK(COMPILE(ret, "constant", node->nd_pconst)); // (2)
if (in_single_pattern) {
ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
}
@@ -7268,12 +7228,12 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
branches = decl_branch_base(iseq, node, "case");
- node = RNODE_CASE3(node)->nd_body;
+ node = node->nd_body;
EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
type = nd_type(node);
line = nd_line(node);
line_node = node;
- single_pattern = !RNODE_IN(node)->nd_next;
+ single_pattern = !node->nd_next;
endlabel = NEW_LABEL(line);
elselabel = NEW_LABEL(line);
@@ -7287,7 +7247,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
}
ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
- CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
+ CHECK(COMPILE(head, "case base", orig_node->nd_head));
ADD_SEQ(ret, head); /* case VAL */
@@ -7303,14 +7263,14 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
add_trace_branch_coverage(
iseq,
body_seq,
- RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node,
+ node->nd_body ? node->nd_body : node,
branch_id++,
"in",
branches);
- CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
+ CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
ADD_INSNL(body_seq, line_node, jump, endlabel);
- pattern = RNODE_IN(node)->nd_head;
+ pattern = node->nd_head;
if (pattern) {
int pat_line = nd_line(pattern);
LABEL *next_pat = NEW_LABEL(pat_line);
@@ -7325,7 +7285,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
return COMPILE_NG;
}
- node = RNODE_IN(node)->nd_next;
+ node = node->nd_next;
if (!node) {
break;
}
@@ -7367,7 +7327,6 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
fin = NEW_LABEL(line);
kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- kw_arg->references = 0;
kw_arg->keyword_len = 2;
kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
@@ -7451,7 +7410,7 @@ compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
push_ensure_entry(iseq, &enl, NULL, NULL);
- if (RNODE_WHILE(node)->nd_state == 1) {
+ if (node->nd_state == 1) {
ADD_INSNL(ret, line_node, jump, next_label);
}
else {
@@ -7470,27 +7429,27 @@ compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
add_trace_branch_coverage(
iseq,
ret,
- RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node,
+ node->nd_body ? node->nd_body : node,
0,
"body",
branches);
- CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
+ CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
ADD_LABEL(ret, next_label); /* next */
if (type == NODE_WHILE) {
- compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
+ compile_branch_condition(iseq, ret, node->nd_cond,
redo_label, end_label);
}
else {
/* until */
- compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
+ compile_branch_condition(iseq, ret, node->nd_cond,
end_label, redo_label);
}
ADD_LABEL(ret, end_label);
ADD_ADJUST_RESTORE(ret, adjust_label);
- if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
+ if (UNDEF_P(node->nd_state)) {
/* ADD_INSN(ret, line_node, putundef); */
COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
return COMPILE_NG;
@@ -7532,18 +7491,18 @@ compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
ADD_LABEL(ret, retry_label);
if (nd_type_p(node, NODE_FOR)) {
- CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
+ CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
- NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
+ NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
ISEQ_TYPE_BLOCK, line);
ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
}
else {
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
- NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
+ NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
ISEQ_TYPE_BLOCK, line);
- CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
+ CHECK(COMPILE(ret, "iter caller", node->nd_iter));
}
{
@@ -7587,7 +7546,7 @@ compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
* (args.length == 1 && Array.try_convert(args[0])) || args
*/
const NODE *line_node = node;
- const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
+ const NODE *var = node->nd_var;
LABEL *not_single = NEW_LABEL(nd_line(var));
LABEL *not_ary = NEW_LABEL(nd_line(var));
CHECK(COMPILE(ret, "for var", var));
@@ -7622,7 +7581,7 @@ compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
LABEL *splabel = NEW_LABEL(0);
ADD_LABEL(ret, splabel);
ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
- CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
+ CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
ISEQ_COMPILE_DATA(iseq)->loopval_popped));
add_ensure_iseq(ret, iseq, 0);
ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
@@ -7657,7 +7616,7 @@ compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
}
/* escape from block */
- CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
+ CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
if (popped) {
ADD_INSN(ret, line_node, pop);
@@ -7680,7 +7639,7 @@ compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
LABEL *splabel = NEW_LABEL(0);
debugs("next in while loop\n");
ADD_LABEL(ret, splabel);
- CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
+ CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
add_ensure_iseq(ret, iseq, 0);
ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
@@ -7694,11 +7653,10 @@ compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
debugs("next in block\n");
ADD_LABEL(ret, splabel);
ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
- CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
+ CHECK(COMPILE(ret, "next val", node->nd_stts));
add_ensure_iseq(ret, iseq, 0);
ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
ADD_ADJUST_RESTORE(ret, splabel);
- splabel->unremovable = FALSE;
if (!popped) {
ADD_INSN(ret, line_node, putnil);
@@ -7729,7 +7687,7 @@ compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
ip = ISEQ_BODY(ip)->parent_iseq;
}
if (ip != 0) {
- CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
+ CHECK(COMPILE(ret, "next val", node->nd_stts));
ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
if (popped) {
@@ -7841,7 +7799,7 @@ compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
LABEL *lstart = NEW_LABEL(line);
LABEL *lend = NEW_LABEL(line);
LABEL *lcont = NEW_LABEL(line);
- const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
+ const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
rb_str_concat(rb_str_new2("rescue in "),
ISEQ_BODY(iseq)->location.label),
ISEQ_TYPE_RESCUE, line);
@@ -7853,14 +7811,14 @@ compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
{
- CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
+ CHECK(COMPILE(ret, "rescue head", node->nd_head));
}
ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
ADD_LABEL(ret, lend);
- if (RNODE_RESCUE(node)->nd_else) {
+ if (node->nd_else) {
ADD_INSN(ret, line_node, pop);
- CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
+ CHECK(COMPILE(ret, "rescue else", node->nd_else));
}
ADD_INSN(ret, line_node, nop);
ADD_LABEL(ret, lcont);
@@ -7888,16 +7846,16 @@ compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
label_miss = NEW_LABEL(line);
label_hit = NEW_LABEL(line);
- narg = RNODE_RESBODY(resq)->nd_args;
+ narg = resq->nd_args;
if (narg) {
switch (nd_type(narg)) {
case NODE_LIST:
while (narg) {
ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
- CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
+ CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
ADD_INSNL(ret, line_node, branchif, label_hit);
- narg = RNODE_LIST(narg)->nd_next;
+ narg = narg->nd_next;
}
break;
case NODE_SPLAT:
@@ -7920,24 +7878,13 @@ compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
}
ADD_INSNL(ret, line_node, jump, label_miss);
ADD_LABEL(ret, label_hit);
- ADD_TRACE(ret, RUBY_EVENT_RESCUE);
-
- if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL) {
- // empty body
- int lineno = nd_line(RNODE_RESBODY(resq)->nd_body);
- NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
- ADD_INSN(ret, &dummy_line_node, putnil);
- }
- else {
- CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
- }
-
+ CHECK(COMPILE(ret, "resbody body", resq->nd_body));
if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
ADD_INSN(ret, line_node, nop);
}
ADD_INSN(ret, line_node, leave);
ADD_LABEL(ret, label_miss);
- resq = RNODE_RESBODY(resq)->nd_head;
+ resq = resq->nd_head;
}
return COMPILE_OK;
}
@@ -7948,7 +7895,7 @@ compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
const int line = nd_line(node);
const NODE *line_node = node;
DECL_ANCHOR(ensr);
- const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
+ const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
ISEQ_TYPE_ENSURE, line);
LABEL *lstart = NEW_LABEL(line);
@@ -7961,17 +7908,17 @@ compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
struct ensure_range *erange;
INIT_ANCHOR(ensr);
- CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
+ CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
last = ensr->last;
last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
er.begin = lstart;
er.end = lend;
er.next = 0;
- push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
+ push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
ADD_LABEL(ret, lstart);
- CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
+ CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
ADD_LABEL(ret, lend);
ADD_SEQ(ret, ensr);
if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
@@ -8000,7 +7947,7 @@ compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
const rb_iseq_t *is = iseq;
enum rb_iseq_type t = type;
- const NODE *retval = RNODE_RETURN(node)->nd_stts;
+ const NODE *retval = node->nd_stts;
LABEL *splabel = 0;
while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
@@ -8109,13 +8056,13 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
/* optimization shortcut
* "literal".freeze -> opt_str_freeze("literal")
*/
- if (get_nd_recv(node) && nd_type_p(get_nd_recv(node), NODE_STR) &&
- (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
- get_nd_args(node) == NULL &&
+ if (node->nd_recv && nd_type_p(node->nd_recv, NODE_STR) &&
+ (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
+ node->nd_args == NULL &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
- VALUE str = rb_fstring(RNODE_STR(get_nd_recv(node))->nd_lit);
- if (get_node_call_nd_mid(node) == idUMinus) {
+ VALUE str = rb_fstring(node->nd_recv->nd_lit);
+ if (node->nd_mid == idUMinus) {
ADD_INSN2(ret, line_node, opt_str_uminus, str,
new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
}
@@ -8132,14 +8079,14 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
/* optimization shortcut
* obj["literal"] -> opt_aref_with(obj, "literal")
*/
- if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
- nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
- nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) &&
+ if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
+ nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 1 &&
+ nd_type_p(node->nd_args->nd_head, NODE_STR) &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
- VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(get_nd_args(node))->nd_head)->nd_lit);
- CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
+ VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
+ CHECK(COMPILE(ret, "recv", node->nd_recv));
ADD_INSN2(ret, line_node, opt_aref_with, str,
new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
RB_OBJ_WRITTEN(iseq, Qundef, str);
@@ -8182,12 +8129,12 @@ iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
if (recv) {
switch (nd_type(recv)) {
case NODE_VCALL:
- if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
+ if (recv->nd_mid == rb_intern("__builtin")) {
return name;
}
break;
case NODE_CONST:
- if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
+ if (recv->nd_vid == rb_intern("Primitive")) {
return name;
}
break;
@@ -8268,60 +8215,16 @@ delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *arg
}
}
-// Compile Primitive.attr! :leaf, ...
-static int
-compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
-{
- VALUE symbol;
- VALUE string;
- if (!node) goto no_arg;
- while (node) {
- if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
- const NODE *next = RNODE_LIST(node)->nd_next;
-
- node = RNODE_LIST(node)->nd_head;
- if (!node) goto no_arg;
- if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
-
- symbol = RNODE_LIT(node)->nd_lit;
- if (!SYMBOL_P(symbol)) goto non_symbol_arg;
-
- string = rb_sym_to_s(symbol);
- if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
- ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
- }
- else if (strcmp(RSTRING_PTR(string), "no_gc") == 0) {
- ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_NO_GC;
- }
- else {
- goto unknown_arg;
- }
- node = next;
- }
- return COMPILE_OK;
- no_arg:
- COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
- return COMPILE_NG;
- non_symbol_arg:
- COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
- return COMPILE_NG;
- unknown_arg:
- COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
- return COMPILE_NG;
- bad_arg:
- UNKNOWN_NODE("attr!", node, COMPILE_NG);
-}
-
static int
compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
{
if (!node) goto no_arg;
if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
- if (RNODE_LIST(node)->nd_next) goto too_many_arg;
- node = RNODE_LIST(node)->nd_head;
+ if (node->nd_next) goto too_many_arg;
+ node = node->nd_head;
if (!node) goto no_arg;
if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
- VALUE name = RNODE_LIT(node)->nd_lit;
+ VALUE name = node->nd_lit;
if (!SYMBOL_P(name)) goto non_symbol_arg;
if (!popped) {
compile_lvar(iseq, ret, line_node, SYM2ID(name));
@@ -8345,8 +8248,8 @@ static NODE *
mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
{
const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
- if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
- return RNODE_IF(node)->nd_body;
+ if (nd_type(node) == NODE_IF && node->nd_cond == cond_node) {
+ return node->nd_body;
}
else {
rb_bug("mandatory_node: can't find mandatory node");
@@ -8360,9 +8263,8 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
struct rb_args_info args = {
.pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
};
- rb_node_args_t args_node;
- rb_node_init(RNODE(&args_node), NODE_ARGS);
- args_node.nd_ainfo = args;
+ NODE args_node;
+ rb_node_init(&args_node, NODE_ARGS, 0, 0, (VALUE)&args);
// local table without non-mandatory parameters
const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
@@ -8383,25 +8285,24 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
}
- rb_node_scope_t scope_node;
- rb_node_init(RNODE(&scope_node), NODE_SCOPE);
- scope_node.nd_tbl = tbl;
- scope_node.nd_body = mandatory_node(iseq, node);
- scope_node.nd_args = &args_node;
+ NODE scope_node;
+ rb_node_init(&scope_node, NODE_SCOPE, (VALUE)tbl, (VALUE)mandatory_node(iseq, node), (VALUE)&args_node);
rb_ast_body_t ast = {
- .root = RNODE(&scope_node),
- .frozen_string_literal = -1,
- .coverage_enabled = -1,
+ .root = &scope_node,
+ .compile_option = 0,
.script_lines = ISEQ_BODY(iseq)->variable.script_lines,
};
+ int prev_inline_index = GET_VM()->builtin_inline_index;
+
ISEQ_BODY(iseq)->mandatory_only_iseq =
rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
nd_line(line_node), NULL, 0,
ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
+ GET_VM()->builtin_inline_index = prev_inline_index;
ALLOCV_END(idtmp);
return COMPILE_OK;
}
@@ -8410,15 +8311,15 @@ static int
compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
{
- NODE *args_node = get_nd_args(node);
+ NODE *args_node = node->nd_args;
if (parent_block != NULL) {
- COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
+ COMPILE_ERROR(iseq, nd_line(line_node), "should not call builtins here.");
return COMPILE_NG;
}
else {
# define BUILTIN_INLINE_PREFIX "_bi"
- char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
+ char inline_func[DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT) + sizeof(BUILTIN_INLINE_PREFIX)];
bool cconst = false;
retry:;
const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
@@ -8437,7 +8338,9 @@ compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NOD
return COMPILE_OK;
}
else if (strcmp("attr!", builtin_func) == 0) {
- return compile_builtin_attr(iseq, args_node);
+ // There's only "inline" attribute for now
+ ISEQ_BODY(iseq)->builtin_inline_p = true;
+ return COMPILE_OK;
}
else if (strcmp("arg!", builtin_func) == 0) {
return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
@@ -8513,7 +8416,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
*/
DECL_ANCHOR(recv);
DECL_ANCHOR(args);
- ID mid = get_node_call_nd_mid(node);
+ ID mid = node->nd_mid;
VALUE argc;
unsigned int flag = 0;
struct rb_callinfo_kwarg *keywords = NULL;
@@ -8592,7 +8495,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
const char *builtin_func;
if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
- (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
+ (builtin_func = iseq_builtin_function_name(type, node->nd_recv, mid)) != NULL) {
return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
}
@@ -8602,16 +8505,16 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
int idx, level;
if (mid == idCall &&
- nd_type_p(get_nd_recv(node), NODE_LVAR) &&
- iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
- ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
+ nd_type_p(node->nd_recv, NODE_LVAR) &&
+ iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
+ ADD_INSN2(recv, node->nd_recv, getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
else if (private_recv_p(node)) {
ADD_INSN(recv, node, putself);
flag |= VM_CALL_FCALL;
}
else {
- CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
+ CHECK(COMPILE(recv, "recv", node->nd_recv));
}
if (type == NODE_QCALL) {
@@ -8625,7 +8528,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
/* args */
if (type != NODE_VCALL) {
- argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
+ argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
CHECK(!NIL_P(argc));
}
else {
@@ -8662,7 +8565,7 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
VALUE argc;
unsigned int flag = 0;
int asgnflag = 0;
- ID id = RNODE_OP_ASGN1(node)->nd_mid;
+ ID id = node->nd_mid;
int boff = 0;
/*
@@ -8691,9 +8594,9 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
if (!popped) {
ADD_INSN(ret, node, putnil);
}
- asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
+ asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
CHECK(asgnflag != -1);
- switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
+ switch (nd_type(node->nd_args->nd_head)) {
case NODE_ZLIST:
argc = INT2FIX(0);
break;
@@ -8701,7 +8604,7 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
boff = 1;
/* fall through */
default:
- argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
+ argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
CHECK(!NIL_P(argc));
}
ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
@@ -8729,7 +8632,7 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
}
ADD_INSN(ret, node, pop);
- CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
if (!popped) {
ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
}
@@ -8763,7 +8666,7 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_LABEL(ret, lfin);
}
else {
- CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
ADD_SEND(ret, node, id, INT2FIX(1));
if (!popped) {
ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
@@ -8797,8 +8700,8 @@ static int
compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
const int line = nd_line(node);
- ID atype = RNODE_OP_ASGN2(node)->nd_mid;
- ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
+ ID atype = node->nd_next->nd_mid;
+ ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
int asgnflag;
LABEL *lfin = NEW_LABEL(line);
LABEL *lcfin = NEW_LABEL(line);
@@ -8856,9 +8759,9 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
*/
- asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
+ asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
CHECK(asgnflag != -1);
- if (RNODE_OP_ASGN2(node)->nd_aid) {
+ if (node->nd_next->nd_aid) {
lskip = NEW_LABEL(line);
ADD_INSN(ret, node, dup);
ADD_INSNL(ret, node, branchnil, lskip);
@@ -8879,7 +8782,7 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
if (!popped) {
ADD_INSN(ret, node, pop);
}
- CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, swap);
ADD_INSN1(ret, node, topn, INT2FIX(1));
@@ -8895,7 +8798,7 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_LABEL(ret, lfin);
}
else {
- CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
ADD_SEND(ret, node, atype, INT2FIX(1));
if (!popped) {
ADD_INSN(ret, node, swap);
@@ -8921,21 +8824,21 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
LABEL *lassign = 0;
ID mid;
- switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
+ switch (nd_type(node->nd_head)) {
case NODE_COLON3:
ADD_INSN1(ret, node, putobject, rb_cObject);
break;
case NODE_COLON2:
- CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
+ CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
break;
default:
COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
- ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
+ ruby_node_name(nd_type(node->nd_head)));
return COMPILE_NG;
}
- mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
+ mid = node->nd_head->nd_mid;
/* cref */
- if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
+ if (node->nd_aid == idOROP) {
lassign = NEW_LABEL(line);
ADD_INSN(ret, node, dup); /* cref cref */
ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
@@ -8946,17 +8849,17 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_INSN1(ret, node, putobject, Qtrue);
ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
- if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
+ if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
lfin = NEW_LABEL(line);
if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
- if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
+ if (node->nd_aid == idOROP)
ADD_INSNL(ret, node, branchif, lfin);
else /* idANDOP */
ADD_INSNL(ret, node, branchunless, lfin);
/* cref [obj] */
if (!popped) ADD_INSN(ret, node, pop); /* cref */
if (lassign) ADD_LABEL(ret, lassign);
- CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
/* cref value */
if (popped)
ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
@@ -8970,9 +8873,9 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_INSN(ret, node, pop); /* [value] */
}
else {
- CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
/* cref obj value */
- ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
+ ADD_CALL(ret, node, node->nd_aid, INT2FIX(1));
/* cref value */
ADD_INSN(ret, node, swap); /* value cref */
if (!popped) {
@@ -8991,11 +8894,11 @@ compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
LABEL *lfin = NEW_LABEL(line);
LABEL *lassign;
- if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
+ if (type == NODE_OP_ASGN_OR && !nd_type_p(node->nd_head, NODE_IVAR)) {
LABEL *lfinish[2];
lfinish[0] = lfin;
lfinish[1] = 0;
- defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse);
+ defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
lassign = lfinish[1];
if (!lassign) {
lassign = NEW_LABEL(line);
@@ -9006,7 +8909,7 @@ compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
lassign = NEW_LABEL(line);
}
- CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
if (!popped) {
ADD_INSN(ret, node, dup);
@@ -9024,7 +8927,7 @@ compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
}
ADD_LABEL(ret, lassign);
- CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
+ CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value, popped));
ADD_LABEL(ret, lfin);
return COMPILE_OK;
}
@@ -9042,7 +8945,7 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
INIT_ANCHOR(args);
ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
if (type == NODE_SUPER) {
- VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
+ VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
CHECK(!NIL_P(vargc));
argc = FIX2INT(vargc);
}
@@ -9131,13 +9034,25 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
ADD_GETLOCAL(args, node, idx, lvar_level);
}
ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
+ if (local_body->param.flags.has_rest) {
+ ADD_INSN1(args, node, newarray, INT2FIX(1));
+ ADD_INSN (args, node, concatarray);
+ --argc;
+ }
flag |= VM_CALL_KW_SPLAT;
}
else if (local_body->param.flags.has_kwrest) {
int idx = local_body->local_table_size - local_kwd->rest_start;
ADD_GETLOCAL(args, node, idx, lvar_level);
- argc++;
- flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
+
+ if (local_body->param.flags.has_rest) {
+ ADD_INSN1(args, node, newarray, INT2FIX(1));
+ ADD_INSN (args, node, concatarray);
+ }
+ else {
+ argc++;
+ }
+ flag |= VM_CALL_KW_SPLAT;
}
}
@@ -9174,8 +9089,8 @@ compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
default: /* valid */;
}
- if (RNODE_YIELD(node)->nd_head) {
- argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
+ if (node->nd_head) {
+ argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
CHECK(!NIL_P(argc));
}
else {
@@ -9209,17 +9124,17 @@ compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
INIT_ANCHOR(val);
switch ((int)type) {
case NODE_MATCH:
- ADD_INSN1(recv, node, putobject, RNODE_MATCH(node)->nd_lit);
+ ADD_INSN1(recv, node, putobject, node->nd_lit);
ADD_INSN2(val, node, getspecial, INT2FIX(0),
INT2FIX(0));
break;
case NODE_MATCH2:
- CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
- CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
+ CHECK(COMPILE(recv, "receiver", node->nd_recv));
+ CHECK(COMPILE(val, "value", node->nd_value));
break;
case NODE_MATCH3:
- CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
- CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
+ CHECK(COMPILE(recv, "receiver", node->nd_value));
+ CHECK(COMPILE(val, "value", node->nd_recv));
break;
}
@@ -9227,8 +9142,8 @@ compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
ADD_SEQ(ret, val);
ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
- if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
- compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
+ if (node->nd_args) {
+ compile_named_capture_assign(iseq, ret, node->nd_args);
}
if (popped) {
@@ -9240,7 +9155,7 @@ compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
static int
compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
- if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
+ if (rb_is_const_id(node->nd_mid)) {
/* constant */
VALUE segments;
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
@@ -9270,8 +9185,8 @@ compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
else {
/* function call */
ADD_CALL_RECEIVER(ret, node);
- CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
- ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
+ CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
+ ADD_CALL(ret, node, node->nd_mid, INT2FIX(1));
}
if (popped) {
ADD_INSN(ret, node, pop);
@@ -9282,19 +9197,19 @@ compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
static int
compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
- debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
+ debugi("colon3#nd_mid", node->nd_mid);
/* add cache insn */
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
ISEQ_BODY(iseq)->ic_size++;
- VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
+ VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(node->nd_mid));
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
else {
ADD_INSN1(ret, node, putobject, rb_cObject);
ADD_INSN1(ret, node, putobject, Qtrue);
- ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_mid));
}
if (popped) {
@@ -9307,13 +9222,13 @@ static int
compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
{
VALUE flag = INT2FIX(excl);
- const NODE *b = RNODE_DOT2(node)->nd_beg;
- const NODE *e = RNODE_DOT2(node)->nd_end;
+ const NODE *b = node->nd_beg;
+ const NODE *e = node->nd_end;
if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
if (!popped) {
- VALUE bv = nd_type_p(b, NODE_LIT) ? RNODE_LIT(b)->nd_lit : Qnil;
- VALUE ev = nd_type_p(e, NODE_LIT) ? RNODE_LIT(e)->nd_lit : Qnil;
+ VALUE bv = nd_type_p(b, NODE_LIT) ? b->nd_lit : Qnil;
+ VALUE ev = nd_type_p(e, NODE_LIT) ? e->nd_lit : Qnil;
VALUE val = rb_range_new(bv, ev, excl);
ADD_INSN1(ret, node, putobject, val);
RB_OBJ_WRITTEN(iseq, Qundef, val);
@@ -9362,7 +9277,7 @@ compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
{
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
LABEL *end_label = NEW_LABEL(nd_line(node));
- const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
+ const NODE *default_value = node->nd_body->nd_value;
if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
/* required argument. do nothing */
@@ -9386,7 +9301,7 @@ compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
ADD_INSNL(ret, node, branchif, end_label);
- CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
+ CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
ADD_LABEL(ret, end_label);
}
return COMPILE_OK;
@@ -9398,7 +9313,7 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
DECL_ANCHOR(recv);
DECL_ANCHOR(args);
unsigned int flag = 0;
- ID mid = RNODE_ATTRASGN(node)->nd_mid;
+ ID mid = node->nd_mid;
VALUE argc;
LABEL *else_label = NULL;
VALUE branches = Qfalse;
@@ -9406,16 +9321,17 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
/* optimization shortcut
* obj["literal"] = value -> opt_aset_with(obj, "literal", value)
*/
- if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
- nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
- nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) &&
+ if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
+ mid == idASET && !private_recv_p(node) && node->nd_args &&
+ nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 2 &&
+ nd_type_p(node->nd_args->nd_head, NODE_STR) &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
{
- VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head)->nd_lit);
- CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
- CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
+ VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
+ CHECK(COMPILE(ret, "recv", node->nd_recv));
+ CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
if (!popped) {
ADD_INSN(ret, node, swap);
ADD_INSN1(ret, node, topn, INT2FIX(1));
@@ -9429,10 +9345,10 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
INIT_ANCHOR(recv);
INIT_ANCHOR(args);
- argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
+ argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
CHECK(!NIL_P(argc));
- int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
+ int asgnflag = COMPILE_RECV(recv, "recv", node);
CHECK(asgnflag != -1);
flag |= (unsigned int)asgnflag;
@@ -9514,7 +9430,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
/* ignore */
}
else {
- if (nd_fl_newline(node)) {
+ if (node->flags & NODE_FL_NEWLINE) {
int event = RUBY_EVENT_LINE;
ISEQ_COMPILE_DATA(iseq)->last_line = line;
if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
@@ -9569,7 +9485,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
CHECK(compile_retry(iseq, ret, node, popped));
break;
case NODE_BEGIN:{
- CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
+ CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
break;
}
case NODE_RESCUE:
@@ -9585,7 +9501,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_AND:
case NODE_OR:{
LABEL *end_label = NEW_LABEL(line);
- CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
+ CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
if (!popped) {
ADD_INSN(ret, node, dup);
}
@@ -9598,22 +9514,25 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
if (!popped) {
ADD_INSN(ret, node, pop);
}
- CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
+ CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
ADD_LABEL(ret, end_label);
break;
}
case NODE_MASGN:{
+ bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
+ ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
compile_massign(iseq, ret, node, popped);
+ ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
break;
}
case NODE_LASGN:{
- ID id = RNODE_LASGN(node)->nd_vid;
+ ID id = node->nd_vid;
int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
- CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "rvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
@@ -9623,8 +9542,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_DASGN: {
int idx, lv, ls;
- ID id = RNODE_DASGN(node)->nd_vid;
- CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
+ ID id = node->nd_vid;
+ CHECK(COMPILE(ret, "dvalue", node->nd_value));
debugi("dassn id", rb_id2str(id) ? id : '*');
if (!popped) {
@@ -9642,27 +9561,27 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_GASGN:{
- CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
}
- ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
+ ADD_INSN1(ret, node, setglobal, ID2SYM(node->nd_entry));
break;
}
case NODE_IASGN:{
- CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
}
ADD_INSN2(ret, node, setinstancevariable,
- ID2SYM(RNODE_IASGN(node)->nd_vid),
- get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_ivar_ic_value(iseq,node->nd_vid));
break;
}
case NODE_CDECL:{
- if (RNODE_CDECL(node)->nd_vid) {
- CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
+ if (node->nd_vid) {
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
@@ -9670,11 +9589,11 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
+ ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_vid));
}
else {
- compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
- CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
+ compile_cpath(ret, iseq, node->nd_else);
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
ADD_INSN(ret, node, swap);
if (!popped) {
@@ -9682,18 +9601,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
ADD_INSN(ret, node, swap);
}
- ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
+ ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_else->nd_mid));
}
break;
}
case NODE_CVASGN:{
- CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
}
ADD_INSN2(ret, node, setclassvariable,
- ID2SYM(RNODE_CVASGN(node)->nd_vid),
- get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_cvar_ic_value(iseq,node->nd_vid));
break;
}
case NODE_OP_ASGN1:
@@ -9735,6 +9654,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
break;
}
+ case NODE_VALUES:{
+ const NODE *n = node;
+ if (popped) {
+ COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
+ }
+ while (n) {
+ CHECK(COMPILE(ret, "values item", n->nd_head));
+ n = n->nd_next;
+ }
+ ADD_INSN1(ret, node, newarray, INT2FIX(node->nd_alen));
+ break;
+ }
case NODE_HASH:
CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
break;
@@ -9746,18 +9677,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
case NODE_LVAR:{
if (!popped) {
- compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
+ compile_lvar(iseq, ret, node, node->nd_vid);
}
break;
}
case NODE_DVAR:{
int lv, idx, ls;
- debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
+ debugi("nd_vid", node->nd_vid);
if (!popped) {
- idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
+ idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
if (idx < 0) {
COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
- rb_id2str(RNODE_DVAR(node)->nd_vid));
+ rb_id2str(node->nd_vid));
goto ng;
}
ADD_GETLOCAL(ret, node, ls - idx, lv);
@@ -9765,34 +9696,34 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_GVAR:{
- ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
+ ADD_INSN1(ret, node, getglobal, ID2SYM(node->nd_entry));
if (popped) {
ADD_INSN(ret, node, pop);
}
break;
}
case NODE_IVAR:{
- debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
+ debugi("nd_vid", node->nd_vid);
if (!popped) {
ADD_INSN2(ret, node, getinstancevariable,
- ID2SYM(RNODE_IVAR(node)->nd_vid),
- get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_ivar_ic_value(iseq,node->nd_vid));
}
break;
}
case NODE_CONST:{
- debugi("nd_vid", RNODE_CONST(node)->nd_vid);
+ debugi("nd_vid", node->nd_vid);
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
body->ic_size++;
- VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
+ VALUE segments = rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
else {
ADD_INSN(ret, node, putnil);
ADD_INSN1(ret, node, putobject, Qtrue);
- ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
+ ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_vid));
}
if (popped) {
@@ -9803,26 +9734,26 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_CVAR:{
if (!popped) {
ADD_INSN2(ret, node, getclassvariable,
- ID2SYM(RNODE_CVAR(node)->nd_vid),
- get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_cvar_ic_value(iseq,node->nd_vid));
}
break;
}
case NODE_NTH_REF:{
if (!popped) {
- if (!RNODE_NTH_REF(node)->nd_nth) {
+ if (!node->nd_nth) {
ADD_INSN(ret, node, putnil);
break;
}
ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
- INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
+ INT2FIX(node->nd_nth << 1));
}
break;
}
case NODE_BACK_REF:{
if (!popped) {
ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
- INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
+ INT2FIX(0x01 | (node->nd_nth << 1)));
}
break;
}
@@ -9832,17 +9763,22 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
CHECK(compile_match(iseq, ret, node, popped, type));
break;
case NODE_LIT:{
- debugp_param("lit", RNODE_LIT(node)->nd_lit);
+ debugp_param("lit", node->nd_lit);
if (!popped) {
- ADD_INSN1(ret, node, putobject, RNODE_LIT(node)->nd_lit);
- RB_OBJ_WRITTEN(iseq, Qundef, RNODE_LIT(node)->nd_lit);
+ if (UNLIKELY(node->nd_lit == rb_mRubyVMFrozenCore)) {
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); // [Bug #20569]
+ }
+ else {
+ ADD_INSN1(ret, node, putobject, node->nd_lit);
+ }
+ RB_OBJ_WRITTEN(iseq, Qundef, node->nd_lit);
}
break;
}
case NODE_STR:{
- debugp_param("nd_lit", RNODE_STR(node)->nd_lit);
+ debugp_param("nd_lit", node->nd_lit);
if (!popped) {
- VALUE lit = RNODE_STR(node)->nd_lit;
+ VALUE lit = node->nd_lit;
if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
lit = rb_fstring(lit);
ADD_INSN1(ret, node, putstring, lit);
@@ -9874,7 +9810,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_XSTR:{
ADD_CALL_RECEIVER(ret, node);
- VALUE str = rb_fstring(RNODE_XSTR(node)->nd_lit);
+ VALUE str = rb_fstring(node->nd_lit);
ADD_INSN1(ret, node, putobject, str);
RB_OBJ_WRITTEN(iseq, Qundef, str);
ADD_CALL(ret, node, idBackquote, INT2FIX(1));
@@ -9895,7 +9831,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_EVSTR:
- CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
+ CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
break;
case NODE_DREGX:{
compile_dregx(iseq, ret, node);
@@ -9908,7 +9844,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_ONCE:{
int ic_index = body->ise_size++;
const rb_iseq_t *block_iseq;
- block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
+ block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
@@ -9920,36 +9856,36 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_ARGSCAT:{
if (popped) {
- CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
+ CHECK(COMPILE(ret, "argscat head", node->nd_head));
ADD_INSN1(ret, node, splatarray, Qfalse);
ADD_INSN(ret, node, pop);
- CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
+ CHECK(COMPILE(ret, "argscat body", node->nd_body));
ADD_INSN1(ret, node, splatarray, Qfalse);
ADD_INSN(ret, node, pop);
}
else {
- CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
- CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
+ CHECK(COMPILE(ret, "argscat head", node->nd_head));
+ CHECK(COMPILE(ret, "argscat body", node->nd_body));
ADD_INSN(ret, node, concatarray);
}
break;
}
case NODE_ARGSPUSH:{
if (popped) {
- CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
+ CHECK(COMPILE(ret, "argspush head", node->nd_head));
ADD_INSN1(ret, node, splatarray, Qfalse);
ADD_INSN(ret, node, pop);
- CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
+ CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
}
else {
- CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
- CHECK(compile_array_1(iseq, ret, RNODE_ARGSPUSH(node)->nd_body));
+ CHECK(COMPILE(ret, "argspush head", node->nd_head));
+ CHECK(compile_array_1(iseq, ret, node->nd_body));
ADD_INSN(ret, node, concatarray);
}
break;
}
case NODE_SPLAT:{
- CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
+ CHECK(COMPILE(ret, "splat", node->nd_head));
ADD_INSN1(ret, node, splatarray, Qtrue);
if (popped) {
@@ -9958,8 +9894,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_DEFN:{
- ID mid = RNODE_DEFN(node)->nd_mid;
- const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
+ ID mid = node->nd_mid;
+ const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
rb_id2str(mid),
ISEQ_TYPE_METHOD, line);
@@ -9974,13 +9910,13 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_DEFS:{
- ID mid = RNODE_DEFS(node)->nd_mid;
- const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
+ ID mid = node->nd_mid;
+ const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
rb_id2str(mid),
ISEQ_TYPE_METHOD, line);
debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
- CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
+ CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
@@ -9992,8 +9928,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_ALIAS:{
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
- CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
- CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
+ CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
+ CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
if (popped) {
@@ -10003,8 +9939,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_VALIAS:{
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
- ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
+ ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_alias));
+ ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_orig));
ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
if (popped) {
@@ -10015,7 +9951,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_UNDEF:{
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
- CHECK(COMPILE(ret, "undef arg", RNODE_UNDEF(node)->nd_undef));
+ CHECK(COMPILE(ret, "undef arg", node->nd_undef));
ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
if (popped) {
@@ -10024,15 +9960,15 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_CLASS:{
- const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
- rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
+ const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
+ rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
ISEQ_TYPE_CLASS, line);
const int flags = VM_DEFINECLASS_TYPE_CLASS |
- (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
- compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
+ (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
+ compile_cpath(ret, iseq, node->nd_cpath);
- CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
- ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
+ CHECK(COMPILE(ret, "super", node->nd_super));
+ ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
if (popped) {
@@ -10041,14 +9977,14 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_MODULE:{
- const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
- rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
+ const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
+ rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
ISEQ_TYPE_CLASS, line);
const int flags = VM_DEFINECLASS_TYPE_MODULE |
- compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
+ compile_cpath(ret, iseq, node->nd_cpath);
ADD_INSN (ret, node, putnil); /* dummy */
- ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
+ ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
if (popped) {
@@ -10058,10 +9994,10 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_SCLASS:{
ID singletonclass;
- const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
+ const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
ISEQ_TYPE_CLASS, line);
- CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
+ CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
ADD_INSN (ret, node, putnil);
CONST_ID(singletonclass, "singletonclass");
ADD_INSN3(ret, node, defineclass,
@@ -10139,7 +10075,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
*/
int is_index = body->ise_size++;
struct rb_iseq_new_with_callback_callback_func *ifunc =
- rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
+ rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
const rb_iseq_t *once_iseq =
new_child_iseq_with_callback(iseq, ifunc,
rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
@@ -10170,7 +10106,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
case NODE_LAMBDA:{
/* compile same as lambda{...} */
- const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
+ const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
VALUE argc = INT2FIX(0);
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
@@ -10381,12 +10317,6 @@ dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr,
fflush(stdout);
}
-int
-rb_insn_len(VALUE insn)
-{
- return insn_len(insn);
-}
-
const char *
rb_insns_name(int i)
{
@@ -10550,7 +10480,6 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
size_t n = rb_callinfo_kwarg_bytes(len);
kw_arg = xmalloc(n);
- kw_arg->references = 0;
kw_arg->keyword_len = len;
for (i = 0; i < len; i++) {
VALUE kw = RARRAY_AREF(vkw_arg, i);
@@ -10576,7 +10505,6 @@ event_name_to_flag(VALUE sym)
CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN);
- CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT
return RUBY_EVENT_NONE;
}
@@ -10861,13 +10789,13 @@ iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
}
static void
-iseq_insn_each_object_mark_and_move(VALUE *obj_ptr, VALUE _)
+iseq_insn_each_object_mark(VALUE *obj_ptr, VALUE _)
{
- rb_gc_mark_and_move(obj_ptr);
+ rb_gc_mark(*obj_ptr);
}
void
-rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
+rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
{
INSN *iobj = 0;
size_t size = sizeof(INSN);
@@ -10892,7 +10820,7 @@ rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
iobj = (INSN *)&storage->buff[pos];
if (iobj->operands) {
- iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
+ iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark, (VALUE)0);
}
pos += (int)size;
}
@@ -11065,7 +10993,7 @@ rb_local_defined(ID id, const rb_iseq_t *iseq)
#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
#endif
-typedef uint32_t ibf_offset_t;
+typedef unsigned int ibf_offset_t;
#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
@@ -11076,27 +11004,17 @@ typedef uint32_t ibf_offset_t;
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
#endif
-static const char IBF_ENDIAN_MARK =
-#ifdef WORDS_BIGENDIAN
- 'b'
-#else
- 'l'
-#endif
- ;
-
struct ibf_header {
char magic[4]; /* YARB */
- uint32_t major_version;
- uint32_t minor_version;
- uint32_t size;
- uint32_t extra_size;
+ unsigned int major_version;
+ unsigned int minor_version;
+ unsigned int size;
+ unsigned int extra_size;
- uint32_t iseq_list_size;
- uint32_t global_object_list_size;
+ unsigned int iseq_list_size;
+ unsigned int global_object_list_size;
ibf_offset_t iseq_list_offset;
ibf_offset_t global_object_list_offset;
- uint8_t endian;
- uint8_t wordsize; /* assume no 2048-bit CPU */
};
struct ibf_dump_buffer {
@@ -12049,7 +11967,6 @@ ibf_load_ci_entries(const struct ibf_load *load,
int kwlen = (int)ibf_load_small_value(load, &reading_pos);
if (kwlen > 0) {
kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- kwarg->references = 0;
kwarg->keyword_len = kwlen;
for (int j=0; j<kwlen; j++) {
VALUE keyword = ibf_load_small_value(load, &reading_pos);
@@ -12204,7 +12121,8 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_dump_write_small_value(dump, body->ic_size);
ibf_dump_write_small_value(dump, body->ci_size);
ibf_dump_write_small_value(dump, body->stack_max);
- ibf_dump_write_small_value(dump, body->builtin_attrs);
+ ibf_dump_write_small_value(dump, body->catch_except_p);
+ ibf_dump_write_small_value(dump, body->builtin_inline_p);
#undef IBF_BODY_OFFSET
@@ -12316,7 +12234,8 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
- const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
+ const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
+ const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
// setup fname and dummy frame
VALUE path = ibf_load_object(load, location_pathobj_index);
@@ -12388,19 +12307,14 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
- load_body->builtin_attrs = builtin_attrs;
+ load_body->catch_except_p = catch_except_p;
+ load_body->builtin_inline_p = builtin_inline_p;
load_body->ivc_size = ivc_size;
load_body->icvarc_size = icvarc_size;
load_body->ise_size = ise_size;
load_body->ic_size = ic_size;
-
- if (ISEQ_IS_SIZE(load_body)) {
- load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
- }
- else {
- load_body->is_entries = NULL;
- }
+ load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
@@ -12933,7 +12847,7 @@ ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_head
}
typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
-static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
+static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
ibf_dump_object_unsupported, /* T_NONE */
ibf_dump_object_unsupported, /* T_OBJECT */
ibf_dump_object_class, /* T_CLASS */
@@ -13026,7 +12940,7 @@ ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
}
typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
-static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
+static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
ibf_load_object_unsupported, /* T_NONE */
ibf_load_object_unsupported, /* T_OBJECT */
ibf_load_object_class, /* T_CLASS */
@@ -13221,6 +13135,7 @@ rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
ibf_dump_setup(dump, dump_obj);
ibf_dump_write(dump, &header, sizeof(header));
+ ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
ibf_dump_iseq(dump, iseq);
header.magic[0] = 'Y'; /* YARB */
@@ -13229,8 +13144,6 @@ rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
header.magic[3] = 'B';
header.major_version = IBF_MAJOR_VERSION;
header.minor_version = IBF_MINOR_VERSION;
- header.endian = IBF_ENDIAN_MARK;
- header.wordsize = (uint8_t)SIZEOF_VALUE;
ibf_dump_iseq_list(dump, &header);
ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
header.size = ibf_dump_pos(dump);
@@ -13280,7 +13193,7 @@ rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
}
#if USE_LAZY_LOAD
-const rb_iseq_t *
+MJIT_FUNC_EXPORTED const rb_iseq_t *
rb_iseq_complete(const rb_iseq_t *iseq)
{
rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
@@ -13323,12 +13236,16 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
#endif
pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
- if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
+#if !USE_LAZY_LOAD
#if IBF_ISEQ_DEBUG
- fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
+ fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
#endif
+ rb_ibf_load_iseq_complete(iseq);
+#else
+ if (GET_VM()->builtin_function_table) {
rb_ibf_load_iseq_complete(iseq);
}
+#endif /* !USE_LAZY_LOAD */
#if IBF_ISEQ_DEBUG
fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
@@ -13342,39 +13259,35 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
static void
ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
{
- struct ibf_header *header = (struct ibf_header *)bytes;
load->loader_obj = loader_obj;
load->global_buffer.buff = bytes;
- load->header = header;
- load->global_buffer.size = header->size;
- load->global_buffer.obj_list_offset = header->global_object_list_offset;
- load->global_buffer.obj_list_size = header->global_object_list_size;
- RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
+ load->header = (struct ibf_header *)load->global_buffer.buff;
+ load->global_buffer.size = load->header->size;
+ load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
+ load->global_buffer.obj_list_size = load->header->global_object_list_size;
+ RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size));
RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
load->iseq = NULL;
load->current_buffer = &load->global_buffer;
- if (size < header->size) {
+ if (size < load->header->size) {
rb_raise(rb_eRuntimeError, "broken binary format");
}
- if (strncmp(header->magic, "YARB", 4) != 0) {
+ if (strncmp(load->header->magic, "YARB", 4) != 0) {
rb_raise(rb_eRuntimeError, "unknown binary format");
}
- if (header->major_version != IBF_MAJOR_VERSION ||
- header->minor_version != IBF_MINOR_VERSION) {
+ if (load->header->major_version != IBF_MAJOR_VERSION ||
+ load->header->minor_version != IBF_MINOR_VERSION) {
rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
- header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
+ load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
}
- if (header->endian != IBF_ENDIAN_MARK) {
- rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
+ if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
+ rb_raise(rb_eRuntimeError, "unmatched platform");
}
- if (header->wordsize != SIZEOF_VALUE) {
- rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
- }
- if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
+ if (load->header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
- header->iseq_list_offset);
+ load->header->iseq_list_offset);
}
if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
rb_raise(rb_eArgError, "unaligned object list offset: %u",
@@ -13389,9 +13302,9 @@ ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
rb_raise(rb_eRuntimeError, "broken binary format");
}
- if (USE_LAZY_LOAD) {
- str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
- }
+#if USE_LAZY_LOAD
+ str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
+#endif
ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
RB_OBJ_WRITE(loader_obj, &load->str, str);
@@ -13465,5 +13378,3 @@ rb_iseq_ibf_load_extra_data(VALUE str)
RB_GC_GUARD(loader_obj);
return extra_str;
}
-
-#include "prism_compile.c"
diff --git a/complex.c b/complex.c
index c9272778bb..a227cb0a58 100644
--- a/complex.c
+++ b/complex.c
@@ -391,8 +391,7 @@ k_numeric_p(VALUE x)
inline static VALUE
nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
{
- NEWOBJ_OF(obj, struct RComplex, klass,
- T_COMPLEX | (RGENGC_WB_PROTECTED_COMPLEX ? FL_WB_PROTECTED : 0), sizeof(struct RComplex), 0);
+ NEWOBJ_OF(obj, struct RComplex, klass, T_COMPLEX | (RGENGC_WB_PROTECTED_COMPLEX ? FL_WB_PROTECTED : 0));
RCOMPLEX_SET_REAL(obj, real);
RCOMPLEX_SET_IMAG(obj, imag);
@@ -1693,12 +1692,9 @@ nucomp_to_c(VALUE self)
/*
* call-seq:
- * to_c -> (0+0i)
- *
- * Returns zero as a Complex:
- *
- * nil.to_c # => (0+0i)
+ * nil.to_c -> (0+0i)
*
+ * Returns zero as a complex.
*/
static VALUE
nilclass_to_c(VALUE self)
@@ -2120,8 +2116,11 @@ nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
return a1;
/* should raise exception for consistency */
if (!k_numeric_p(a1)) {
- if (!raise)
- return rb_protect(to_complex, a1, NULL);
+ if (!raise) {
+ a1 = rb_protect(to_complex, a1, NULL);
+ rb_set_errinfo(Qnil);
+ return a1;
+ }
return to_complex(a1);
}
}
diff --git a/configure.ac b/configure.ac
index e0057d974f..220392d120 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,22 +47,11 @@ m4_include([tool/m4/ruby_universal_arch.m4])dnl
m4_include([tool/m4/ruby_wasm_tools.m4])dnl
m4_include([tool/m4/ruby_werror_flag.m4])dnl
-AS_IF([test "x${GITHUB_ACTIONS}" = xtrue],
-[AC_REQUIRE([_COLORIZE_RESULT_PREPARE])dnl
-dnl 93(bright yellow) is copied from .github/workflows/mingw.yml
- begin_group() { AS_ECHO(["::group::@<:@93m$[]1@<:@m"]);}
- end_group() { AS_ECHO(["::endgroup::"]);}
-],
-[dnl
- begin_group() { :;}
- end_group() { :;}
-])
-
AC_ARG_VAR([cflags], [additional CFLAGS (ignored when CFLAGS is given)])dnl
AC_ARG_VAR([cppflags], [additional CPPFLAGS (ignored when CPPFLAGS is given)])dnl
AC_ARG_VAR([cxxflags], [additional CXXFLAGS (ignored when CXXFLAGS is given)])dnl
-[begin]_group "environment section" && {
+: "environment section" && {
HAVE_BASERUBY=yes
BASERUBY_VERSION=
AC_ARG_WITH(baseruby,
@@ -75,13 +64,13 @@ AC_ARG_WITH(baseruby,
[
AC_PATH_PROG([BASERUBY], [ruby], [false])
])
-# BASERUBY must be >= 2.5.0. Note that `"2.5.0" > "2.5"` is true.
-AS_IF([test "$HAVE_BASERUBY" != no -a "`RUBYOPT=- $BASERUBY --disable=gems -e 'print 42 if RUBY_VERSION > "2.5"' 2>/dev/null`" = 42], [
+# BASERUBY must be >= 2.2.0. Note that `"2.2.0" > "2.2"` is true.
+AS_IF([test "$HAVE_BASERUBY" != no -a "`RUBYOPT=- $BASERUBY --disable=gems -e 'print 42 if RUBY_VERSION > "2.2"' 2>/dev/null`" = 42], [
AS_CASE(["$build_os"], [mingw*], [
# Can MSys shell run a command with a drive letter?
RUBYOPT=- `cygpath -ma "$BASERUBY"` --disable=gems -e exit 2>/dev/null || HAVE_BASERUBY=no
])
- RUBY_APPEND_OPTION(BASERUBY, "--disable=gems")
+ BASERUBY="$BASERUBY --disable=gems"
BASERUBY_VERSION=`$BASERUBY -v`
$BASERUBY -C "$srcdir" tool/downloader.rb -d tool -e gnu config.guess config.sub >&AS_MESSAGE_FD
], [
@@ -225,15 +214,23 @@ AS_CASE(["/${rb_CC} "],
[*clang*], [
# Ditto for LLVM. Note however that llvm-as is a LLVM-IR to LLVM bitcode
# assembler that does not target your machine native binary.
+
+ # Xcode has its own version tools that may be incompatible with
+ # genuine LLVM tools, use the tools in the same directory.
+
+ AS_IF([$rb_CC -E -dM -xc - < /dev/null | grep -F __apple_build_version__ > /dev/null],
+ [llvm_prefix=], [llvm_prefix=llvm-])
+ # AC_PREPROC_IFELSE cannot be used before AC_USE_SYSTEM_EXTENSIONS
+
RUBY_CHECK_PROG_FOR_CC([LD], [s/clang/ld/]) # ... maybe try lld ?
- RUBY_CHECK_PROG_FOR_CC([AR], [s/clang/llvm-ar/])
-# RUBY_CHECK_PROG_FOR_CC([AS], [s/clang/llvm-as/])
+ RUBY_CHECK_PROG_FOR_CC([AR], [s/clang/${llvm_prefix}ar/])
+# RUBY_CHECK_PROG_FOR_CC([AS], [s/clang/${llvm_prefix}as/])
RUBY_CHECK_PROG_FOR_CC([CXX], [s/clang/clang++/])
- RUBY_CHECK_PROG_FOR_CC([NM], [s/clang/llvm-nm/])
- RUBY_CHECK_PROG_FOR_CC([OBJCOPY], [s/clang/llvm-objcopy/])
- RUBY_CHECK_PROG_FOR_CC([OBJDUMP], [s/clang/llvm-objdump/])
- RUBY_CHECK_PROG_FOR_CC([RANLIB], [s/clang/llvm-ranlib/])
- RUBY_CHECK_PROG_FOR_CC([STRIP], [s/clang/llvm-strip/])
+ RUBY_CHECK_PROG_FOR_CC([NM], [s/clang/${llvm_prefix}nm/])
+ RUBY_CHECK_PROG_FOR_CC([OBJCOPY], [s/clang/${llvm_prefix}objcopy/])
+ RUBY_CHECK_PROG_FOR_CC([OBJDUMP], [s/clang/${llvm_prefix}objdump/])
+ RUBY_CHECK_PROG_FOR_CC([RANLIB], [s/clang/${llvm_prefix}ranlib/])
+ RUBY_CHECK_PROG_FOR_CC([STRIP], [s/clang/${llvm_prefix}strip/])
])
AS_UNSET(rb_CC)
AS_UNSET(rb_dummy)
@@ -244,15 +241,9 @@ AS_CASE(["${build_os}"],
],
[aix*], [
AC_PATH_TOOL([NM], [nm], [/usr/ccs/bin/nm], [/usr/ccs/bin:$PATH])
-],
-[darwin*], [
- # For Apple clang version 14.0.3 (clang-1403.0.22.14.1)
- ac_cv_prog_ac_ct_AR=`$CC -print-prog-name=ar`
- ac_cv_prog_ac_ct_LD=`$CC -print-prog-name=ld`
- ac_cv_prog_ac_ct_NM=`$CC -print-prog-name=nm`
])
AS_CASE(["${target_os}"],
-[cygwin*|msys*|mingw*|darwin*], [
+[cygwin*|msys*|mingw*], [
ac_cv_prog_ac_ct_OBJCOPY=":"
])
@@ -271,14 +262,10 @@ AC_CHECK_TOOLS([AR], [gar ar])
AC_CHECK_TOOLS([AS], [gas as])
AC_CHECK_TOOLS([LD], [gld ld]) # ... try gold ?
AC_CHECK_TOOLS([NM], [gnm nm])
-AC_CHECK_TOOLS([OBJCOPY], [gobjcopy objcopy], [:])
+AC_CHECK_TOOLS([OBJCOPY], [gobjcopy objcopy])
AC_CHECK_TOOLS([OBJDUMP], [gobjdump objdump])
AC_CHECK_TOOLS([STRIP], [gstrip strip], [:])
-# nm errors with Rust's LLVM bitcode when Rust uses a newer LLVM version than nm.
-# In case we're working with llvm-nm, tell it to not worry about the bitcode.
-AS_IF([${NM} --help | grep -q 'llvm-bc'], [NM="$NM --no-llvm-bc"])
-
AS_IF([test ! $rb_test_CFLAGS], [AS_UNSET(CFLAGS)]); AS_UNSET(rb_test_CFLAGS)
AS_IF([test ! $rb_test_CXXFLAGS], [AS_UNSET(CXXFLAGS)]); AS_UNSET(rb_save_CXXFLAGS)
@@ -406,6 +393,13 @@ AS_IF([test "$GCC" = yes], [
AS_IF([test "$gcc_major" -lt 4], [
AC_MSG_ERROR([too old GCC: $gcc_major.$gcc_minor])
])
+
+ AC_CACHE_CHECK([if thread-local storage is supported], [rb_cv_tls_supported],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[int __thread conftest;]])],
+ [rb_cv_tls_supported=yes],
+ [rb_cv_tls_supported=no])])
+ AS_IF([test x"$rb_cv_tls_supported" != xyes],
+ [AC_DEFINE(RB_THREAD_LOCAL_SPECIFIER_IS_UNSUPPORTED)])
], [
linker_flag=
])
@@ -420,17 +414,29 @@ AC_SUBST(OUTFLAG)
AC_SUBST(COUTFLAG)
AC_SUBST(CSRCFLAG)
+: ${MJIT_CC=$CC}
+AS_IF([test "x$cross_compiling" = xno], [
+ AC_PATH_PROG([MJIT_CC], ${MJIT_CC})
+
+ # if $CC is in /usr/lib/ccache/$CC, search original $CC (disable ccache)
+ AS_IF([echo $RUBY_DEBUG | grep ci > /dev/null &&
+ echo $MJIT_CC | grep ^/usr/lib/ccache > /dev/null], [
+ PATH=`echo $PATH | sed "s/\/usr\/lib\/ccache://"` MJIT_CC=`which $CC`])
+
+ AS_CASE([$target_os],
+ [*mingw*], [command -v cygpath > /dev/null && MJIT_CC=`cygpath -ma $MJIT_CC`])
+ shift 2
+ MJIT_CC="$MJIT_CC${1+ }$*"
+])
+
AS_CASE(["$build_os"],
- [darwin*], [
- # gcc 13 warns duplicate -l options, which are added by the
- # default spec.
+ [darwin1*.*], [
# Xcode linker warns for deprecated architecture and wrongly
# installed TBD files.
- CC_WRAPPER="" CC_NO_WRAPPER="$CC"
+ CC_WRAPPER=""
echo 'int main(void) {return 0;}' > conftest.c
AS_IF([$CC -framework Foundation -o conftest conftest.c 2>&1 |
- grep -e '^ld: warning: ignoring duplicate libraries:' \
- -e '^ld: warning: text-based stub file' >/dev/null], [
+ grep '^ld: warning: text-based stub file' >/dev/null], [
CC_WRAPPER=`cd -P "${tooldir}" && pwd`/darwin-cc
CC="$CC_WRAPPER $CC"
])
@@ -506,13 +512,9 @@ AS_CASE(["$target_os"],
])
rb_cv_binary_elf=no
: ${enable_shared=yes}
-],
-[darwin*], [
- : ${enable_shared=yes}
-],
+ ],
[hiuxmpp*], [AC_DEFINE(__HIUX_MPP__)]) # by TOYODA Eizi <toyoda@npd.kishou.go.jp>
-
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_INSTALL
@@ -593,7 +595,7 @@ AC_MSG_RESULT([$CHDIR])
AC_SUBST(CHDIR)
}
-[begin]_group "compiler section" && {
+: "compiler section" && {
RUBY_WERROR_FLAG([
AC_MSG_CHECKING([whether CFLAGS is valid])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
@@ -688,10 +690,6 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
AS_IF([test $gcc_major -le 6], [
extra_warnflags="$extra_warnflags -Wno-maybe-uninitialized"
])
- AS_CASE([ $CFLAGS ], [*" -save-temps="*|*" -save-temps "*], [], [
- extra_warnflags="$extra_warnflags -Werror=misleading-indentation"
- ])
-
# ICC doesn't support -Werror=
AS_IF([test $icc_version -gt 0], [
particular_werror_flags=no
@@ -703,6 +701,7 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
-Werror=duplicated-cond \
-Werror=implicit-function-declaration \
-Werror=implicit-int \
+ -Werror=misleading-indentation \
-Werror=pointer-arith \
-Werror=shorten-64-to-32 \
-Werror=write-strings \
@@ -806,6 +805,8 @@ AS_IF([test "$GCC" = yes], [
[@%:@include <stdio.h>])
])
+ : ${MJIT_HEADER_FLAGS='-P -dD'}
+
# -fstack-protector
AS_CASE(["$target_os"],
[emscripten*|wasi*], [
@@ -909,6 +910,7 @@ AS_IF([test "$GCC" = yes], [
], [
RUBY_TRY_LDFLAGS([-Wl,-unexported_symbol,_Init_*], [visibility_option=ld], [visibility_option=no])
])
+ test "$visibility_option" = no || OBJCOPY=:
])
AS_IF([test "$GCC" = yes], [
@@ -991,7 +993,7 @@ AS_IF([test "$rb_cv_have_stmt_and_decl_in_expr" = yes], [
AC_DEFINE(HAVE_STMT_AND_DECL_IN_EXPR)
])
-[begin]_group "header and library section" && {
+: "header and library section" && {
AC_ARG_WITH(winnt-ver,
AS_HELP_STRING([--with-winnt-ver=0xXXXX], [target Windows NT version (default to 0x0600)]),
[with_winnt_ver="$withval"], [with_winnt_ver="0x0600"])
@@ -1094,18 +1096,12 @@ main()
])
POSTLINK=""
AC_CHECK_PROGS(codesign, codesign)
- dsymutils=
- AS_CASE("$CC_NO_WRAPPER", [gcc*-1[[3-9]]], [
- dsymutils=${CC_NO_WRAPPER@%:@gcc}
- dsymutils=dsymutil${dsymutils%-1*}
- dsymutils="$dsymutils-19 $dsymutils-18 $dsymutils-17"
- ])
- AC_CHECK_PROGS(dsymutil, $dsymutils dsymutil)
+ AC_CHECK_PROGS(dsymutil, dsymutil)
AS_IF([test -n "$codesign"], [
POSTLINK="{ test -z '\$(RUBY_CODESIGN)' || $codesign -s '\$(RUBY_CODESIGN)' -f \$@; }${POSTLINK:+; $POSTLINK}"
])
AS_IF([test -n "$dsymutil"], [
- POSTLINK="$dsymutil \$@ 2>/dev/null${POSTLINK:+; $POSTLINK}"
+ POSTLINK="$dsymutil \$@${POSTLINK:+; $POSTLINK}"
])
AS_IF([test -n "${POSTLINK}"], [
LINK_SO="$LINK_SO
@@ -1207,8 +1203,6 @@ main()
ac_cv_func_gmtime_r=yes
rb_cv_large_fd_select=yes
ac_cv_type_struct_timeval=yes
- ac_cv_func_clock_gettime=yes
- ac_cv_func_clock_getres=yes
ac_cv_func_malloc_usable_size=no
ac_cv_type_off_t=yes
ac_cv_sizeof_off_t=8
@@ -1252,7 +1246,7 @@ main()
AS_CASE(["$target_cpu"], [powerpc64*], [
ac_cv_func___builtin_setjmp=no
])
- # With gcc-8's -fcf-protection, RJIT's __builtin_longjmp fails.
+ # With gcc-8's -fcf-protection, MJIT's __builtin_longjmp fails.
AS_CASE(["$CC $CFLAGS "], [*" -fcf-protection "*], [cf_protection=yes], [cf_protection=no])
AS_IF([test "$cf_protection" = yes], [
ac_cv_func___builtin_setjmp=no
@@ -1354,7 +1348,7 @@ AC_CHECK_HEADERS(syscall.h)
AC_CHECK_HEADERS(time.h)
AC_CHECK_HEADERS(ucontext.h)
AC_CHECK_HEADERS(utime.h)
-AC_CHECK_HEADERS(sys/epoll.h)
+AC_CHECK_HEADERS(stdatomic.h)
AS_CASE("$target_cpu", [x64|x86_64|i[3-6]86*], [
AC_CHECK_HEADERS(x86intrin.h)
@@ -1372,6 +1366,8 @@ AC_ARG_WITH([jemalloc],
[with_jemalloc=$withval], [with_jemalloc=no])
AS_IF([test "x$with_jemalloc" != xno],[
# find jemalloc header first
+ save_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${INCFLAGS} ${CPPFLAGS}"
malloc_header=
AC_CHECK_HEADER(jemalloc/jemalloc.h, [malloc_header=jemalloc/jemalloc.h], [
AC_CHECK_HEADER(jemalloc.h, [malloc_header=jemalloc.h])
@@ -1403,6 +1399,8 @@ AS_IF([test "x$with_jemalloc" != xno],[
done
done
])
+ CPPFLAGS="${save_CPPFLAGS}"
+ unset save_CPPFLAGS
with_jemalloc=${rb_cv_jemalloc_library}
AS_CASE(["$with_jemalloc"],
[no],
@@ -1489,25 +1487,6 @@ RUBY_CHECK_SIZEOF(float)
RUBY_CHECK_SIZEOF(double)
RUBY_CHECK_SIZEOF(time_t, [long "long long"], [], [@%:@include <time.h>])
RUBY_CHECK_SIZEOF(clock_t, [], [], [@%:@include <time.h>])
-AC_SUBST(X_BUILTIN_BINARY, yes)
-AS_IF([test "$cross_compiling" = yes],
-[dnl miniruby cannot run if cross compiling
- X_BUILTIN_BINARY=no
-],
-[
- AS_CASE([ac_cv_sizeof_voidp],
- [[1-9]*], [dnl fixed value
- ],
- [
- AC_CACHE_CHECK([word size], [rb_cv_word_size],
- [for w in 4 8; do
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@if SIZEOF_VOIDP != ${w}
- @%:@error SIZEOF_VOIDP
- @%:@endif]])], [rb_cv_word_size=${w}; break])
- done])
- AS_IF([test -z $rb_cv_word_size], [X_BUILTIN_BINARY=no])
- ])
-])
AC_CACHE_CHECK(packed struct attribute, rb_cv_packed_struct,
[rb_cv_packed_struct=no
@@ -1520,9 +1499,10 @@ AC_CACHE_CHECK(packed struct attribute, rb_cv_packed_struct,
[rb_cv_packed_struct=$mac; break])
done])
AS_IF([test "$rb_cv_packed_struct" != no], [
- AC_DEFINE_UNQUOTED([RBIMPL_ATTR_PACKED_STRUCT_BEGIN()], [`echo " $rb_cv_packed_struct " | sed 's/ x .*//;s/^ *//'`])
- AC_DEFINE_UNQUOTED([RBIMPL_ATTR_PACKED_STRUCT_END()], [`echo " $rb_cv_packed_struct " | sed 's/.* x //;s/ *$//'`])
+ AC_DEFINE_UNQUOTED([PACKED_STRUCT(x)], [$rb_cv_packed_struct])
RUBY_TRY_CFLAGS(-Wno-address-of-packed-member, [AC_DEFINE(USE_UNALIGNED_MEMBER_ACCESS)])
+], [
+ AC_DEFINE_UNQUOTED([PACKED_STRUCT(x)], x)
])
AS_IF([test "x$ac_cv_type_long_long" = xyes], [
@@ -2031,6 +2011,7 @@ AC_CHECK_FUNCS(_longjmp) # used for AC_ARG_WITH(setjmp-type)
test x$ac_cv_func__longjmp = xno && ac_cv_func__setjmp=no
AC_CHECK_FUNCS(arc4random_buf)
AC_CHECK_FUNCS(atan2l atan2f)
+AC_CHECK_DECLS(atomic_signal_fence, [], [], [#include <stdatomic.h>])
AC_CHECK_FUNCS(chmod)
AC_CHECK_FUNCS(chown)
AC_CHECK_FUNCS(chroot)
@@ -2054,7 +2035,6 @@ AC_CHECK_FUNCS(execv)
AC_CHECK_FUNCS(execve)
AC_CHECK_FUNCS(explicit_memset)
AC_CHECK_FUNCS(fcopyfile)
-AC_CHECK_FUNCS(fchdir)
AC_CHECK_FUNCS(fchmod)
AC_CHECK_FUNCS(fchown)
AC_CHECK_FUNCS(fcntl)
@@ -2112,7 +2092,6 @@ AC_CHECK_FUNCS(lstat)
AC_CHECK_FUNCS(lutimes)
AC_CHECK_FUNCS(malloc_usable_size)
AC_CHECK_FUNCS(malloc_size)
-AC_CHECK_FUNCS(malloc_trim)
AC_CHECK_FUNCS(mblen)
AC_CHECK_FUNCS(memalign)
AC_CHECK_FUNCS(memset_s)
@@ -2166,7 +2145,6 @@ AC_CHECK_FUNCS(sigaction)
AC_CHECK_FUNCS(sigaltstack)
AC_CHECK_FUNCS(sigprocmask)
AC_CHECK_FUNCS(sinh)
-AC_CHECK_FUNCS(snprintf)
AC_CHECK_FUNCS(spawnv)
AC_CHECK_FUNCS(symlink)
AC_CHECK_FUNCS(syscall)
@@ -2191,6 +2169,9 @@ AC_CHECK_FUNCS(__sinpi)
AS_IF([test "x$ac_cv_member_struct_statx_stx_btime" = xyes],
[AC_CHECK_FUNCS(statx)])
+AS_CASE(["$ac_cv_func_memset_s:$ac_cv_func_qsort_s"], [*yes*],
+ [RUBY_DEFINE_IF([!defined __STDC_WANT_LIB_EXT1__], [__STDC_WANT_LIB_EXT1__], 1)])
+
AS_IF([test "$ac_cv_func_getcwd" = yes], [
AC_CACHE_CHECK(if getcwd allocates buffer if NULL is given, [rb_cv_getcwd_malloc],
[AC_RUN_IFELSE([AC_LANG_SOURCE([[
@@ -2259,27 +2240,6 @@ RUBY_CHECK_BUILTIN_FUNC(__builtin_types_compatible_p, [__builtin_types_compatibl
RUBY_CHECK_BUILTIN_FUNC(__builtin_trap, [__builtin_trap()])
RUBY_CHECK_BUILTIN_FUNC(__builtin_expect, [__builtin_expect(0, 0)])
-AS_IF([test "$rb_cv_builtin___builtin_mul_overflow" != no], [
- AC_CACHE_CHECK(for __builtin_mul_overflow with long long arguments, rb_cv_use___builtin_mul_overflow_long_long, [
- AC_LINK_IFELSE([AC_LANG_SOURCE([[
-#pragma clang optimize off
-
-int
-main(void)
-{
- long long x = 0, y;
- __builtin_mul_overflow(x, x, &y);
-
- return 0;
-}
-]])],
- rb_cv_use___builtin_mul_overflow_long_long=yes,
- rb_cv_use___builtin_mul_overflow_long_long=no)])
-])
-AS_IF([test "$rb_cv_use___builtin_mul_overflow_long_long" = yes], [
- AC_DEFINE(USE___BUILTIN_MUL_OVERFLOW_LONG_LONG, 1)
-])
-
AS_IF([test "$ac_cv_func_qsort_r" != no], [
AC_CACHE_CHECK(whether qsort_r is GNU version, rb_cv_gnu_qsort_r,
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@@ -2679,9 +2639,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[riscv64-linux*], [
coroutine_type=riscv64
],
- [loongarch64-linux*], [
- coroutine_type=loongarch64
- ],
[x86_64-freebsd*], [
coroutine_type=amd64
],
@@ -2706,9 +2663,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[i386-openbsd*], [
coroutine_type=x86
],
- [aarch64-openbsd*], [
- coroutine_type=arm64
- ],
[*-openbsd*], [
coroutine_type=pthread
],
@@ -2806,22 +2760,6 @@ AS_IF([test "$THREAD_MODEL" = pthread], [
AC_DEFINE_UNQUOTED(SET_ANOTHER_THREAD_NAME(thid,name), $set_another_thread_name)
])
])
-
- AC_CACHE_CHECK([for thread-local storage sepcifier], [rb_cv_tls_specifier],
- rb_cv_tls_specifier=none
- RUBY_WERROR_FLAG([
- for attr in \
- _Thread_local \
- __thread \
- ; do
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[$attr int conftest;]])],
- [rb_cv_tls_specifier=$attr; break])
- done
- ])
- )
- AS_IF([test x"${rb_cv_tls_specifier}" != xnone],
- [AC_DEFINE_UNQUOTED(RB_THREAD_LOCAL_SPECIFIER, ${rb_cv_tls_specifier})]
- )
])
AS_IF([test x"$ac_cv_header_ucontext_h" = xno], [
@@ -2965,7 +2903,7 @@ AS_IF([test "x$ac_cv_func_ioctl" = xyes], [
}
-[begin]_group "runtime section" && {
+: "runtime section" && {
dnl wheather use dln_a_out or not
AC_ARG_WITH(dln-a-out,
AS_HELP_STRING([--with-dln-a-out], [dln_a_out is deprecated]),
@@ -2999,8 +2937,22 @@ AS_CASE(["$target_os"],
])])
LIBEXT=a
+AC_ARG_WITH(mjit-tabs,
+ AS_HELP_STRING([--without-mjit-tabs], [expand tabs in mjit header]),
+ [AS_IF([test $withval = no], [MJIT_TABS=false])])
+AC_SUBST(MJIT_TABS)dnl
AC_SUBST(DLDFLAGS)dnl
AC_SUBST(ARCH_FLAG)dnl
+AC_SUBST(MJIT_HEADER_FLAGS)dnl
+AC_SUBST(MJIT_HEADER_INSTALL_DIR)dnl
+AC_SUBST(MJIT_CC)dnl
+AS_CASE(["$GCC:$target_os"],
+ [yes:aix*], [mjit_std_cflag="-std=gnu99"],
+ [mjit_std_cflag=])
+AC_SUBST(MJIT_CFLAGS, [${MJIT_CFLAGS-"-w ${mjit_std_cflag} ${orig_cflags}"}])dnl
+AC_SUBST(MJIT_OPTFLAGS, [${MJIT_OPTFLAGS-'$(optflags)'}])dnl
+AC_SUBST(MJIT_DEBUGFLAGS, [${MJIT_DEBUGFLAGS-'$(debugflags)'}])dnl
+AC_SUBST(MJIT_LDSHARED)dnl
AC_SUBST(STATIC)dnl
AC_SUBST(CCDLFLAGS)dnl
@@ -3117,7 +3069,8 @@ AC_SUBST(EXTOBJS)
: ${LIBPATHENV=DYLD_LIBRARY_PATH}
: ${PRELOADENV=DYLD_INSERT_LIBRARIES}
AS_IF([test x"$enable_shared" = xyes], [
- # Resolve symbols from libruby.dylib in $(LIBS) when --enable-shared
+ # Resolve symbols from libruby.dylib when --enable-shared
+ EXTDLDFLAGS='$(LIBRUBYARG_SHARED)'
], [test "x$EXTSTATIC" = x], [
# When building exts as bundles, a mach-o bundle needs to know its loader
# program to bind symbols from the ruby executable
@@ -3466,6 +3419,9 @@ AC_ARG_ENABLE(multiarch,
[multiarch=], [unset multiarch])
AS_IF([test ${multiarch+set}], [
AC_DEFINE(ENABLE_MULTIARCH)
+ MJIT_HEADER_INSTALL_DIR=include/'${arch}/${RUBY_VERSION_NAME}'
+], [
+ MJIT_HEADER_INSTALL_DIR=include/'${RUBY_VERSION_NAME}/${arch}'
])
archlibdir='${libdir}/${arch}'
@@ -3745,7 +3701,7 @@ AS_IF([test x"$gcov" = xyes], [
RUBY_SETJMP_TYPE
}
-[begin]_group "installation section" && {
+: "build section" && {
dnl build rdoc index if requested
RDOCTARGET=""
CAPITARGET=""
@@ -3793,19 +3749,20 @@ AC_SUBST(CAPITARGET)
AS_CASE(["$RDOCTARGET:$CAPITARGET"],[nodoc:nodoc],[INSTALLDOC=nodoc],[INSTALLDOC=all])
AC_SUBST(INSTALLDOC)
-AC_ARG_ENABLE(install-static-library,
- AS_HELP_STRING([--disable-install-static-library], [do not install static ruby library]),
- [INSTALL_STATIC_LIBRARY=$enableval
- AS_IF([test x"$enable_shared" = xno -a x"$INSTALL_STATIC_LIBRARY" = xno],
- [AC_MSG_ERROR([must install either static or shared library])],
- [])],
- AS_IF([test x"$enable_shared" = xyes],
- [INSTALL_STATIC_LIBRARY=no],
- [INSTALL_STATIC_LIBRARY=yes]))
-AC_SUBST(INSTALL_STATIC_LIBRARY)
-}
+AC_ARG_ENABLE(jit-support,
+ AS_HELP_STRING([--disable-jit-support], [disable JIT features]),
+ [MJIT_SUPPORT=$enableval],
+ [AS_CASE(["$target_os"],
+ [wasi | mingw* | solaris*], [MJIT_SUPPORT=no],
+ [MJIT_SUPPORT=yes]
+ )])
+
+AS_IF([test x"$MJIT_SUPPORT" = "xyes"],
+ [AC_DEFINE(USE_MJIT, 1)],
+ [AC_DEFINE(USE_MJIT, 0)])
+
+AC_SUBST(MJIT_SUPPORT)
-[begin]_group "JIT section" && {
AC_CHECK_PROG(RUSTC, [rustc], [rustc], [no]) dnl no ac_tool_prefix
dnl check if rustc is recent enough to build YJIT (rustc >= 1.58.0)
@@ -3851,8 +3808,8 @@ AC_ARG_ENABLE(yjit,
AS_HELP_STRING([--enable-yjit],
[enable in-process JIT compiler that requires Rust build tools. enabled by default on supported platforms if rustc 1.58.0+ is available]),
[YJIT_SUPPORT=$enableval],
- [AS_CASE(["$YJIT_TARGET_OK:$YJIT_RUSTC_OK"],
- [yes:yes], [
+ [AS_CASE(["$enable_jit_support:$YJIT_TARGET_OK:$YJIT_RUSTC_OK"],
+ [yes:yes:yes|:yes:yes], [
YJIT_SUPPORT=yes
],
[YJIT_SUPPORT=no]
@@ -3864,6 +3821,9 @@ CARGO_BUILD_ARGS=
YJIT_LIBS=
AS_CASE(["${YJIT_SUPPORT}"],
[yes|dev|stats|dev_nodebug], [
+ AS_IF([test x"$enable_jit_support" = "xno"],
+ AC_MSG_ERROR([--disable-jit-support but --enable-yjit. YJIT requires JIT support])
+ )
AS_IF([test x"$RUSTC" = "xno"],
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
)
@@ -3880,7 +3840,6 @@ AS_CASE(["${YJIT_SUPPORT}"],
[dev_nodebug], [
rb_rust_target_subdir=dev_nodebug
CARGO_BUILD_ARGS='--profile dev_nodebug --features stats,disasm'
- AC_DEFINE(YJIT_STATS, 1)
],
[stats], [
rb_rust_target_subdir=stats
@@ -3904,9 +3863,7 @@ AS_CASE(["${YJIT_SUPPORT}"],
AC_DEFINE_UNQUOTED(YJIT_SUPPORT, [$YJIT_SUPPORT])
])
AC_DEFINE(USE_YJIT, 1)
-], [
- AC_DEFINE(USE_YJIT, 0)
-])
+], [AC_DEFINE(USE_YJIT, 0)])
dnl These variables end up in ::RbConfig::CONFIG
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
@@ -3916,60 +3873,17 @@ AC_SUBST(CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
AC_SUBST(YJIT_LIBS)dnl for optionally building the Rust parts of YJIT
AC_SUBST(YJIT_OBJ)dnl for optionally building the C parts of YJIT
-dnl Currently, RJIT only supports Unix x86_64 platforms.
-RJIT_TARGET_OK=no
-AS_IF([test "$cross_compiling" = no],
- AS_CASE(["$target_cpu-$target_os"],
- [*android*], [
- RJIT_TARGET_OK=no
- ],
- [x86_64-darwin*], [
- RJIT_TARGET_OK=yes
- ],
- [x86_64-*linux*], [
- RJIT_TARGET_OK=yes
- ],
- [x86_64-*bsd*], [
- RJIT_TARGET_OK=yes
- ]
- )
-)
-
-dnl Build RJIT on Unix x86_64 platforms or if --enable-rjit is specified.
-AC_ARG_ENABLE(rjit,
- AS_HELP_STRING([--enable-rjit],
- [enable pure-Ruby JIT compiler. enabled by default on Unix x86_64 platforms]),
- [RJIT_SUPPORT=$enableval],
- [AS_CASE(["$YJIT_TARGET_OK"],
- [yes], [RJIT_SUPPORT=yes],
- [RJIT_SUPPORT=no]
- )]
-)
-
-AS_CASE(["$RJIT_SUPPORT"],
-[yes|dev|disasm], [
- AS_CASE(["$RJIT_SUPPORT"],
- [dev], [
- # Link libcapstone for --rjit-dump-disasm
- AC_CHECK_LIB([capstone], [cs_disasm])
-
- # Enable extra stats (vm_insns_count, ratio_in_rjit)
- AC_DEFINE(RJIT_STATS, 1)
- ],
- [disasm], [
- # Link libcapstone for --rjit-dump-disasm
- AC_CHECK_LIB([capstone], [cs_disasm])
- ])
-
- AC_DEFINE(USE_RJIT, 1)
-], [
- AC_DEFINE(USE_RJIT, 0)
-])
-
-AC_SUBST(RJIT_SUPPORT)
-}
+AC_ARG_ENABLE(install-static-library,
+ AS_HELP_STRING([--disable-install-static-library], [do not install static ruby library]),
+ [INSTALL_STATIC_LIBRARY=$enableval
+ AS_IF([test x"$enable_shared" = xno -a x"$INSTALL_STATIC_LIBRARY" = xno],
+ [AC_MSG_ERROR([must install either static or shared library])],
+ [])],
+ AS_IF([test x"$enable_shared" = xyes],
+ [INSTALL_STATIC_LIBRARY=no],
+ [INSTALL_STATIC_LIBRARY=yes]))
+AC_SUBST(INSTALL_STATIC_LIBRARY)
-[begin]_group "build section" && {
AC_CACHE_CHECK([for prefix of external symbols], rb_cv_symbol_prefix, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[extern void conftest_external(void) {}]], [[]])],[
rb_cv_symbol_prefix=`$NM conftest.$ac_objext |
@@ -3980,23 +3894,6 @@ AC_CACHE_CHECK([for prefix of external symbols], rb_cv_symbol_prefix, [
])
SYMBOL_PREFIX="$rb_cv_symbol_prefix"
test "x$SYMBOL_PREFIX" = xNONE && SYMBOL_PREFIX=''
-
-AS_IF([test x"$enable_shared" = xyes], [
- AC_CACHE_CHECK([for default symbols in empty shared library], rb_cv_symbols_in_emptylib, [
- save_CC="$CC"
- eval CC=\"`printf "%s" "${DLDSHARED}" | sed ['s/\$(CC)/${CC}/']`\"
- AC_LINK_IFELSE([AC_LANG_PROGRAM()],[
- rb_cv_symbols_in_emptylib=`$NM -Pgp conftest$ac_exeext |
- sed ["/ [A-TV-Z] .*/!d;s///;s/^${SYMBOL_PREFIX}//;/^main$/d"]`
- ])
- set dummy ${rb_cv_symbols_in_emptylib}
- shift
- rb_cv_symbols_in_emptylib="$*"
- CC="$save_CC"
- ])
-])
-AC_SUBST(XSYMBOLS_IN_EMPTYLIB, "${rb_cv_symbols_in_emptylib}")
-
DLNOBJ=dln.o
AC_ARG_ENABLE(dln,
AS_HELP_STRING([--disable-dln], [disable dynamic link feature]),
@@ -4174,9 +4071,8 @@ AS_IF([test "${universal_binary-no}" = yes ], [
const char arch[[]] = __ARCHITECTURE__;]], [[puts(arch);]])],
[rb_cv_architecture_available=yes], [rb_cv_architecture_available=no]))
])
-}
-[end]_group
+: ${MJIT_LDSHARED=`echo "$LDSHARED" | sed ['s|\$(LD)|'"${LD}"'|g;s|\$(CC)|$(MJIT_CC)|g']`}
MAINLIBS="$LIBS"
LIBS=$ORIG_LIBS
@@ -4393,10 +4289,6 @@ AS_IF([test "${universal_binary-no}" = yes ], [
arch="${target_cpu}-${target_os}"
])
AC_DEFINE_UNQUOTED(RUBY_PLATFORM, "$arch")
-
- AS_IF([test "$arch" = "s390x-linux"], [
- AC_DEFINE_UNQUOTED(USE_MN_THREADS, 0)
- ])
])
unset sitearch
@@ -4501,7 +4393,7 @@ guard=INCLUDE_RUBY_CONFIG_H
{
echo "#ifndef $guard"
echo "#define $guard 1"
- sed "/^@%:@define PACKAGE_/d;s/ *$//" confdefs.h
+ grep -v "^#define PACKAGE_" confdefs.h
echo "#endif /* $guard */"
} | tr -d '\015' |
(
@@ -4619,6 +4511,7 @@ AC_SUBST(DESTDIR)
AC_OUTPUT
}
+}
AS_IF([test "$silent" = yes], [], [
AS_IF([${FOLD+:} false], [], [
@@ -4666,8 +4559,8 @@ config_summary "debugflags" "$debugflags"
config_summary "warnflags" "$warnflags"
config_summary "strip command" "$STRIP"
config_summary "install doc" "$DOCTARGETS"
+config_summary "MJIT support" "$MJIT_SUPPORT"
config_summary "YJIT support" "$YJIT_SUPPORT"
-config_summary "RJIT support" "$RJIT_SUPPORT"
config_summary "man page type" "$MANTYPE"
config_summary "search path" "$search_path"
config_summary "static-linked-ext" ${EXTSTATIC:+"yes"}
diff --git a/constant.h b/constant.h
index 90a68d447a..e0d36909e1 100644
--- a/constant.h
+++ b/constant.h
@@ -43,11 +43,13 @@ VALUE rb_mod_deprecate_constant(int argc, const VALUE *argv, VALUE obj);
void rb_free_const_table(struct rb_id_table *tbl);
VALUE rb_const_source_location(VALUE, ID);
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_autoloading_value(VALUE mod, ID id, VALUE *value, rb_const_flag_t *flag);
rb_const_entry_t *rb_const_lookup(VALUE klass, ID id);
VALUE rb_public_const_get_at(VALUE klass, ID id);
VALUE rb_public_const_get_from(VALUE klass, ID id);
int rb_public_const_defined_from(VALUE klass, ID id);
VALUE rb_const_source_location_at(VALUE, ID);
+MJIT_SYMBOL_EXPORT_END
#endif /* CONSTANT_H */
diff --git a/cont.c b/cont.c
index 621de351cb..5375d1945b 100644
--- a/cont.c
+++ b/cont.c
@@ -26,16 +26,15 @@ extern int madvise(caddr_t, size_t, int);
#include COROUTINE_H
#include "eval_intern.h"
+#include "gc.h"
#include "internal.h"
#include "internal/cont.h"
-#include "internal/thread.h"
#include "internal/error.h"
-#include "internal/gc.h"
#include "internal/proc.h"
#include "internal/sanitizers.h"
#include "internal/warnings.h"
#include "ruby/fiber/scheduler.h"
-#include "rjit.h"
+#include "mjit.h"
#include "yjit.h"
#include "vm_core.h"
#include "vm_sync.h"
@@ -71,6 +70,8 @@ static VALUE rb_cFiberPool;
#define FIBER_POOL_ALLOCATION_FREE
#endif
+#define jit_cont_enabled (mjit_enabled || rb_yjit_enabled_p())
+
enum context_type {
CONTINUATION_CONTEXT = 0,
FIBER_CONTEXT = 1
@@ -177,7 +178,7 @@ struct fiber_pool {
// A singly-linked list of allocations which contain 1 or more stacks each.
struct fiber_pool_allocation * allocations;
- // Free list that provides O(1) stack "allocation".
+ // Provides O(1) stack "allocation":
struct fiber_pool_vacancy * vacancies;
// The size of the stack allocations (excluding any guard page).
@@ -189,15 +190,13 @@ struct fiber_pool {
// The initial number of stacks to allocate.
size_t initial_count;
- // Whether to madvise(free) the stack or not.
- // If this value is set to 1, the stack will be madvise(free)ed
- // (or equivalent), where possible, when it is returned to the pool.
+ // Whether to madvise(free) the stack or not:
int free_stacks;
// The number of stacks that have been used in this pool.
size_t used;
- // The amount to allocate for the vm_stack.
+ // The amount to allocate for the vm_stack:
size_t vm_stack_size;
};
@@ -230,18 +229,18 @@ typedef struct rb_context_struct {
struct rb_jit_cont *jit_cont; // Continuation contexts for JITs
} rb_context_t;
+
/*
* Fiber status:
- * [Fiber.new] ------> FIBER_CREATED ----> [Fiber#kill] --> |
- * | [Fiber#resume] |
- * v |
- * +--> FIBER_RESUMED ----> [return] ------> |
- * [Fiber#resume] | | [Fiber.yield/transfer] |
- * [Fiber#transfer] | v |
- * +--- FIBER_SUSPENDED --> [Fiber#kill] --> |
- * |
- * |
- * FIBER_TERMINATED <-------------------+
+ * [Fiber.new] ------> FIBER_CREATED
+ * | [Fiber#resume]
+ * v
+ * +--> FIBER_RESUMED ----+
+ * [Fiber#resume] | | [Fiber.yield] |
+ * | v |
+ * +-- FIBER_SUSPENDED | [Terminate]
+ * |
+ * FIBER_TERMINATED <-+
*/
enum fiber_status {
FIBER_CREATED,
@@ -267,8 +266,6 @@ struct rb_fiber_struct {
unsigned int yielding : 1;
unsigned int blocking : 1;
- unsigned int killed : 1;
-
struct coroutine_context context;
struct fiber_pool_stack stack;
};
@@ -695,9 +692,7 @@ fiber_pool_stack_free(struct fiber_pool_stack * stack)
// If this is not true, the vacancy information will almost certainly be destroyed:
VM_ASSERT(size <= (stack->size - RB_PAGE_SIZE));
- int advice = stack->pool->free_stacks >> 1;
-
- if (DEBUG) fprintf(stderr, "fiber_pool_stack_free: %p+%"PRIuSIZE" [base=%p, size=%"PRIuSIZE"] advice=%d\n", base, size, stack->base, stack->size, advice);
+ if (DEBUG) fprintf(stderr, "fiber_pool_stack_free: %p+%"PRIuSIZE" [base=%p, size=%"PRIuSIZE"]\n", base, size, stack->base, stack->size);
// The pages being used by the stack can be returned back to the system.
// That doesn't change the page mapping, but it does allow the system to
@@ -711,29 +706,24 @@ fiber_pool_stack_free(struct fiber_pool_stack * stack)
#ifdef __wasi__
// WebAssembly doesn't support madvise, so we just don't do anything.
#elif VM_CHECK_MODE > 0 && defined(MADV_DONTNEED)
- if (!advice) advice = MADV_DONTNEED;
// This immediately discards the pages and the memory is reset to zero.
- madvise(base, size, advice);
+ madvise(base, size, MADV_DONTNEED);
#elif defined(MADV_FREE_REUSABLE)
- if (!advice) advice = MADV_FREE_REUSABLE;
// Darwin / macOS / iOS.
// Acknowledge the kernel down to the task info api we make this
// page reusable for future use.
- // As for MADV_FREE_REUSABLE below we ensure in the rare occasions the task was not
+ // As for MADV_FREE_REUSE below we ensure in the rare occasions the task was not
// completed at the time of the call to re-iterate.
- while (madvise(base, size, advice) == -1 && errno == EAGAIN);
+ while (madvise(base, size, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN);
#elif defined(MADV_FREE)
- if (!advice) advice = MADV_FREE;
// Recent Linux.
- madvise(base, size, advice);
+ madvise(base, size, MADV_FREE);
#elif defined(MADV_DONTNEED)
- if (!advice) advice = MADV_DONTNEED;
// Old Linux.
- madvise(base, size, advice);
+ madvise(base, size, MADV_DONTNEED);
#elif defined(POSIX_MADV_DONTNEED)
- if (!advice) advice = POSIX_MADV_DONTNEED;
// Solaris?
- posix_madvise(base, size, advice);
+ posix_madvise(base, size, POSIX_MADV_DONTNEED);
#elif defined(_WIN32)
VirtualAlloc(base, size, MEM_RESET, PAGE_READWRITE);
// Not available in all versions of Windows.
@@ -1060,8 +1050,10 @@ cont_free(void *ptr)
RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr);
- VM_ASSERT(cont->jit_cont != NULL);
- jit_cont_free(cont->jit_cont);
+ if (jit_cont_enabled) {
+ VM_ASSERT(cont->jit_cont != NULL);
+ jit_cont_free(cont->jit_cont);
+ }
/* free rb_cont_t or rb_fiber_t */
ruby_xfree(ptr);
RUBY_FREE_LEAVE("cont");
@@ -1307,6 +1299,9 @@ rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data)
void
rb_jit_cont_finish(void)
{
+ if (!jit_cont_enabled)
+ return;
+
struct rb_jit_cont *cont, *next;
for (cont = first_jit_cont; cont != NULL; cont = next) {
next = cont->next;
@@ -1319,8 +1314,9 @@ static void
cont_init_jit_cont(rb_context_t *cont)
{
VM_ASSERT(cont->jit_cont == NULL);
- // We always allocate this since YJIT may be enabled later
- cont->jit_cont = jit_cont_new(&(cont->saved_ec));
+ if (jit_cont_enabled) {
+ cont->jit_cont = jit_cont_new(&(cont->saved_ec));
+ }
}
struct rb_execution_context_struct *
@@ -1367,11 +1363,15 @@ rb_fiberptr_blocking(struct rb_fiber_struct *fiber)
return fiber->blocking;
}
-// Initialize the jit_cont_lock
+// Start working with jit_cont.
void
rb_jit_cont_init(void)
{
+ if (!jit_cont_enabled)
+ return;
+
rb_native_mutex_initialize(&jit_cont_lock);
+ cont_init_jit_cont(&GET_EC()->fiber_ptr->cont);
}
#if 0
@@ -1996,7 +1996,6 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
fiber->cont.self = fiber_value;
fiber->cont.type = FIBER_CONTEXT;
fiber->blocking = blocking;
- fiber->killed = 0;
cont_init(&fiber->cont, th);
fiber->cont.saved_ec.fiber_ptr = fiber;
@@ -2062,10 +2061,10 @@ fiber_storage_set(struct rb_fiber_struct *fiber, VALUE storage)
}
static inline VALUE
-fiber_storage_get(rb_fiber_t *fiber, int allocate)
+fiber_storage_get(rb_fiber_t *fiber)
{
VALUE storage = fiber->cont.saved_ec.storage;
- if (storage == Qnil && allocate) {
+ if (storage == Qnil) {
storage = rb_hash_new();
fiber_storage_set(fiber, storage);
}
@@ -2092,15 +2091,7 @@ static VALUE
rb_fiber_storage_get(VALUE self)
{
storage_access_must_be_from_same_fiber(self);
-
- VALUE storage = fiber_storage_get(fiber_ptr(self), FALSE);
-
- if (storage == Qnil) {
- return Qnil;
- }
- else {
- return rb_obj_dup(storage);
- }
+ return rb_obj_dup(fiber_storage_get(fiber_ptr(self)));
}
static int
@@ -2180,7 +2171,8 @@ rb_fiber_storage_aref(VALUE class, VALUE key)
{
Check_Type(key, T_SYMBOL);
- VALUE storage = fiber_storage_get(fiber_current(), FALSE);
+ VALUE storage = fiber_storage_get(fiber_current());
+
if (storage == Qnil) return Qnil;
return rb_hash_aref(storage, key);
@@ -2201,15 +2193,9 @@ rb_fiber_storage_aset(VALUE class, VALUE key, VALUE value)
{
Check_Type(key, T_SYMBOL);
- VALUE storage = fiber_storage_get(fiber_current(), value != Qnil);
- if (storage == Qnil) return Qnil;
+ VALUE storage = fiber_storage_get(fiber_current());
- if (value == Qnil) {
- return rb_hash_delete(storage, key);
- }
- else {
- return rb_hash_aset(storage, key, value);
- }
+ return rb_hash_aset(storage, key, value);
}
static VALUE
@@ -2353,7 +2339,7 @@ rb_fiber_initialize(int argc, VALUE* argv, VALUE self)
VALUE
rb_fiber_new_storage(rb_block_call_func_t func, VALUE obj, VALUE storage)
{
- return fiber_initialize(fiber_alloc(rb_cFiber), rb_proc_new(func, obj), rb_fiber_pool_default(Qnil), 1, storage);
+ return fiber_initialize(fiber_alloc(rb_cFiber), rb_proc_new(func, obj), rb_fiber_pool_default(Qnil), 0, storage);
}
VALUE
@@ -2487,6 +2473,7 @@ rb_fiber_start(rb_fiber_t *fiber)
rb_proc_t *proc;
enum ruby_tag_type state;
+ int need_interrupt = TRUE;
VM_ASSERT(th->ec == GET_EC());
VM_ASSERT(FIBER_RESUMED_P(fiber));
@@ -2512,7 +2499,6 @@ rb_fiber_start(rb_fiber_t *fiber)
}
EC_POP_TAG();
- int need_interrupt = TRUE;
VALUE err = Qfalse;
if (state) {
err = th->ec->errinfo;
@@ -2521,16 +2507,13 @@ rb_fiber_start(rb_fiber_t *fiber)
if (state == TAG_RAISE) {
// noop...
}
- else if (state == TAG_FATAL && err == RUBY_FATAL_FIBER_KILLED) {
- need_interrupt = FALSE;
- err = Qfalse;
- }
else if (state == TAG_FATAL) {
rb_threadptr_pending_interrupt_enque(th, err);
}
else {
err = rb_vm_make_jump_tag_but_local_jump(state, err);
}
+ need_interrupt = TRUE;
}
rb_fiber_terminate(fiber, need_interrupt, err);
@@ -2549,9 +2532,12 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th)
fiber->cont.saved_ec.fiber_ptr = fiber;
fiber->cont.saved_ec.thread_ptr = th;
fiber->blocking = 1;
- fiber->killed = 0;
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
th->ec = &fiber->cont.saved_ec;
+ // When rb_threadptr_root_fiber_setup is called for the first time, mjit_enabled and
+ // rb_yjit_enabled_p() are still false. So this does nothing and rb_jit_cont_init() that is
+ // called later will take care of it. However, you still have to call cont_init_jit_cont()
+ // here for other Ractors, which are not initialized by rb_jit_cont_init().
cont_init_jit_cont(&fiber->cont);
}
@@ -2648,19 +2634,6 @@ fiber_store(rb_fiber_t *next_fiber, rb_thread_t *th)
fiber_setcontext(next_fiber, fiber);
}
-static void
-fiber_check_killed(rb_fiber_t *fiber)
-{
- VM_ASSERT(fiber == fiber_current());
-
- if (fiber->killed) {
- rb_thread_t *thread = fiber->cont.saved_ec.thread_ptr;
-
- thread->ec->errinfo = RUBY_FATAL_FIBER_KILLED;
- EC_JUMP_TAG(thread->ec, RUBY_TAG_FATAL);
- }
-}
-
static inline VALUE
fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fiber_t *resuming_fiber, bool yielding)
{
@@ -2749,14 +2722,7 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
current_fiber = th->ec->fiber_ptr;
value = current_fiber->cont.value;
-
- fiber_check_killed(current_fiber);
-
- if (current_fiber->cont.argc == -1) {
- // Fiber#raise will trigger this path.
- rb_exc_raise(value);
- }
-
+ if (current_fiber->cont.argc == -1) rb_exc_raise(value);
return value;
}
@@ -2792,8 +2758,6 @@ fiber_blocking_yield(VALUE fiber_value)
rb_fiber_t *fiber = fiber_ptr(fiber_value);
rb_thread_t * volatile th = fiber->cont.saved_ec.thread_ptr;
- VM_ASSERT(fiber->blocking == 0);
-
// fiber->blocking is `unsigned int : 1`, so we use it as a boolean:
fiber->blocking = 1;
@@ -3196,9 +3160,14 @@ rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
}
static VALUE
-fiber_raise(rb_fiber_t *fiber, VALUE exception)
+fiber_raise(rb_fiber_t *fiber, int argc, const VALUE *argv)
{
- if (FIBER_SUSPENDED_P(fiber) && !fiber->yielding) {
+ VALUE exception = rb_make_exception(argc, argv);
+
+ if (fiber->resuming_fiber) {
+ rb_raise(rb_eFiberError, "attempt to raise a resuming fiber");
+ }
+ else if (FIBER_SUSPENDED_P(fiber) && !fiber->yielding) {
return fiber_transfer_kw(fiber, -1, &exception, RB_NO_KEYWORDS);
}
else {
@@ -3209,9 +3178,7 @@ fiber_raise(rb_fiber_t *fiber, VALUE exception)
VALUE
rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv)
{
- VALUE exception = rb_make_exception(argc, argv);
-
- return fiber_raise(fiber_ptr(fiber), exception);
+ return fiber_raise(fiber_ptr(fiber), argc, argv);
}
/*
@@ -3243,39 +3210,6 @@ rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * fiber.kill -> nil
- *
- * Terminates +fiber+ by raising an uncatchable exception, returning
- * the terminated Fiber.
- *
- * If the fiber has not been started, transition directly to the terminated state.
- *
- * If the fiber is already terminated, does nothing.
- */
-static VALUE
-rb_fiber_m_kill(VALUE self)
-{
- rb_fiber_t *fiber = fiber_ptr(self);
-
- if (fiber->killed) return Qfalse;
- fiber->killed = 1;
-
- if (fiber->status == FIBER_CREATED) {
- fiber->status = FIBER_TERMINATED;
- }
- else if (fiber->status != FIBER_TERMINATED) {
- if (fiber_current() == fiber) {
- fiber_check_killed(fiber);
- } else {
- fiber_raise(fiber_ptr(self), Qnil);
- }
- }
-
- return self;
-}
-
-/*
- * call-seq:
* Fiber.current -> fiber
*
* Returns the current fiber. If you are not running in the context of
@@ -3432,15 +3366,6 @@ Init_Cont(void)
const char *fiber_shared_fiber_pool_free_stacks = getenv("RUBY_SHARED_FIBER_POOL_FREE_STACKS");
if (fiber_shared_fiber_pool_free_stacks) {
shared_fiber_pool.free_stacks = atoi(fiber_shared_fiber_pool_free_stacks);
-
- if (shared_fiber_pool.free_stacks < 0) {
- rb_warn("Setting RUBY_SHARED_FIBER_POOL_FREE_STACKS to a negative value is not allowed.");
- shared_fiber_pool.free_stacks = 0;
- }
-
- if (shared_fiber_pool.free_stacks > 1) {
- rb_warn("Setting RUBY_SHARED_FIBER_POOL_FREE_STACKS to a value greater than 1 is operating system specific, and may cause crashes.");
- }
}
rb_cFiber = rb_define_class("Fiber", rb_cObject);
@@ -3458,7 +3383,6 @@ Init_Cont(void)
rb_define_method(rb_cFiber, "storage=", rb_fiber_storage_set, 1);
rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
rb_define_method(rb_cFiber, "raise", rb_fiber_m_raise, -1);
- rb_define_method(rb_cFiber, "kill", rb_fiber_m_kill, 0);
rb_define_method(rb_cFiber, "backtrace", rb_fiber_backtrace, -1);
rb_define_method(rb_cFiber, "backtrace_locations", rb_fiber_backtrace_locations, -1);
rb_define_method(rb_cFiber, "to_s", fiber_to_s, 0);
diff --git a/coroutine/amd64/Context.S b/coroutine/amd64/Context.S
index 056c276a31..d50732adbc 100644
--- a/coroutine/amd64/Context.S
+++ b/coroutine/amd64/Context.S
@@ -13,35 +13,29 @@
.globl PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer)
PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
- # Make space on the stack for 6 registers:
- subq $48, %rsp
-
- # Save caller state:
- movq %rbp, 40(%rsp)
- movq %rbx, 32(%rsp)
- movq %r12, 24(%rsp)
- movq %r13, 16(%rsp)
- movq %r14, 8(%rsp)
- movq %r15, (%rsp)
-
- # Save caller stack pointer:
+ # Save caller state
+ pushq %rbp
+ pushq %rbx
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+
+ # Save caller stack pointer
movq %rsp, (%rdi)
- # Restore callee stack pointer:
+ # Restore callee stack pointer
movq (%rsi), %rsp
# Restore callee state
- movq 40(%rsp), %rbp
- movq 32(%rsp), %rbx
- movq 24(%rsp), %r12
- movq 16(%rsp), %r13
- movq 8(%rsp), %r14
- movq (%rsp), %r15
-
- # Adjust stack pointer back:
- addq $48, %rsp
-
- # Put the first argument into the return value:
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbx
+ popq %rbp
+
+ # Put the first argument into the return value
movq %rdi, %rax
# We pop the return address and jump to it
diff --git a/coroutine/asyncify/Context.h b/coroutine/asyncify/Context.h
index 7dba829a1d..71791a4004 100644
--- a/coroutine/asyncify/Context.h
+++ b/coroutine/asyncify/Context.h
@@ -13,6 +13,7 @@
#include <stddef.h>
#include <stdio.h>
+#include <stdint.h>
#include "wasm/asyncify.h"
#include "wasm/machine.h"
#include "wasm/fiber.h"
@@ -47,10 +48,13 @@ static inline void coroutine_initialize_main(struct coroutine_context * context)
static inline void coroutine_initialize(struct coroutine_context *context, coroutine_start start, void *stack, size_t size)
{
- if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] entry (context = %p, stack = %p ... %p)\n", __func__, context, stack, (char *)stack + size);
+ // Linear stack pointer must be always aligned down to 16 bytes.
+ // https://github.com/WebAssembly/tool-conventions/blob/c74267a5897c1bdc9aa60adeaf41816387d3cd12/BasicCABI.md#the-linear-stack
+ uintptr_t sp = ((uintptr_t)stack + size) & ~0xF;
+ if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] entry (context = %p, stack = %p ... %p)\n", __func__, context, stack, (char *)sp);
rb_wasm_init_context(&context->fc, coroutine_trampoline, start, context);
// record the initial stack pointer position to restore it after resumption
- context->current_sp = (char *)stack + size;
+ context->current_sp = (char *)sp;
context->stack_base = stack;
context->size = size;
}
diff --git a/coroutine/loongarch64/Context.S b/coroutine/loongarch64/Context.S
deleted file mode 100644
index 662f5dfb6c..0000000000
--- a/coroutine/loongarch64/Context.S
+++ /dev/null
@@ -1,73 +0,0 @@
-#define TOKEN_PASTE(x,y) x##y
-#define PREFIXED_SYMBOL(prefix,name) TOKEN_PASTE(prefix,name)
-
-.text
-.align 2
-
-.global PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer)
-PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
-
- # Make space on the stack for caller registers
- addi.d $sp, $sp, -0xa0
-
- # Save caller registers
- st.d $s0, $sp, 0x00
- st.d $s1, $sp, 0x08
- st.d $s2, $sp, 0x10
- st.d $s3, $sp, 0x18
- st.d $s4, $sp, 0x20
- st.d $s5, $sp, 0x28
- st.d $s6, $sp, 0x30
- st.d $s7, $sp, 0x38
- st.d $s8, $sp, 0x40
- st.d $fp, $sp, 0x48
- fst.d $fs0, $sp, 0x50
- fst.d $fs1, $sp, 0x58
- fst.d $fs2, $sp, 0x60
- fst.d $fs3, $sp, 0x68
- fst.d $fs4, $sp, 0x70
- fst.d $fs5, $sp, 0x78
- fst.d $fs6, $sp, 0x80
- fst.d $fs7, $sp, 0x88
-
- # Save return address
- st.d $ra, $sp, 0x90
-
- # Save stack pointer to a0 (first argument)
- st.d $sp, $a0, 0x00
-
- # Load stack pointer from a1 (second argument)
- ld.d $sp, $a1, 0x00
-
- # Restore caller registers
- ld.d $s0, $sp, 0x00
- ld.d $s1, $sp, 0x08
- ld.d $s2, $sp, 0x10
- ld.d $s3, $sp, 0x18
- ld.d $s4, $sp, 0x20
- ld.d $s5, $sp, 0x28
- ld.d $s6, $sp, 0x30
- ld.d $s7, $sp, 0x38
- ld.d $s8, $sp, 0x40
- ld.d $fp, $sp, 0x48
- fld.d $fs0, $sp, 0x50
- fld.d $fs1, $sp, 0x58
- fld.d $fs2, $sp, 0x60
- fld.d $fs3, $sp, 0x68
- fld.d $fs4, $sp, 0x70
- fld.d $fs5, $sp, 0x78
- fld.d $fs6, $sp, 0x80
- fld.d $fs7, $sp, 0x88
-
- # Load return address
- ld.d $ra, $sp, 0x90
-
- # Pop stack frame
- addi.d $sp, $sp, 0xa0
-
- # Jump to return address
- jr $ra
-
-#if defined(__linux__) && defined(__ELF__)
-.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/coroutine/loongarch64/Context.h b/coroutine/loongarch64/Context.h
deleted file mode 100644
index 668c9a965e..0000000000
--- a/coroutine/loongarch64/Context.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#pragma once
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#define COROUTINE __attribute__((noreturn)) void
-
-enum {COROUTINE_REGISTERS = 0xa0 / 8};
-
-struct coroutine_context
-{
- void **stack_pointer;
- void *argument;
-};
-
-typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
-
-static inline void coroutine_initialize_main(struct coroutine_context * context) {
- context->stack_pointer = NULL;
-}
-
-static inline void coroutine_initialize(
- struct coroutine_context *context,
- coroutine_start start,
- void *stack,
- size_t size
-) {
- assert(start && stack && size >= 1024);
-
- // Stack grows down. Force 16-byte alignment.
- char * top = (char*)stack + size;
- context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
-
- context->stack_pointer -= COROUTINE_REGISTERS;
- memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
-
- context->stack_pointer[0x90 / 8] = (void*)start;
-}
-
-struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
-
-static inline void coroutine_destroy(struct coroutine_context * context)
-{
-}
diff --git a/coroutine/ppc/Context.S b/coroutine/ppc/Context.S
index e2431a9250..cdda93e179 100644
--- a/coroutine/ppc/Context.S
+++ b/coroutine/ppc/Context.S
@@ -3,7 +3,7 @@
; Some relevant examples: https://github.com/gcc-mirror/gcc/blob/master/libphobos/libdruntime/config/powerpc/switchcontext.S
; https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/rs6000/darwin-gpsave.S
; https://www.ibm.com/docs/en/aix/7.2?topic=epilogs-saving-gprs-only
-; ppc32 version may be re-written compactly with stmw/lwm, but the code won't be faster, see: https://github.com/ruby/ruby/pull/5927#issuecomment-1139730541
+; ppc32 version may be re-written compactly with stmw/lwm, but the code wonʼt be faster, see: https://github.com/ruby/ruby/pull/5927#issuecomment-1139730541
; Notice that this code is only for Darwin (macOS). Darwin ABI differs from AIX and ELF.
; To add support for AIX, *BSD or *Linux, please make separate implementations.
diff --git a/coroutine/ppc/Context.h b/coroutine/ppc/Context.h
index 8035d08556..1fce112579 100644
--- a/coroutine/ppc/Context.h
+++ b/coroutine/ppc/Context.h
@@ -13,7 +13,7 @@
enum {
COROUTINE_REGISTERS =
- 20 /* 19 general purpose registers (r13-r31) and 1 return address */
+ 20 /* 19 general purpose registers (r13–r31) and 1 return address */
+ 4 /* space for fiber_entry() to store the link register */
};
diff --git a/coroutine/ppc64/Context.h b/coroutine/ppc64/Context.h
index 085b475ed5..3e6f77f55a 100644
--- a/coroutine/ppc64/Context.h
+++ b/coroutine/ppc64/Context.h
@@ -12,7 +12,7 @@
enum {
COROUTINE_REGISTERS =
- 20 /* 19 general purpose registers (r13-r31) and 1 return address */
+ 20 /* 19 general purpose registers (r13–r31) and 1 return address */
+ 4 /* space for fiber_entry() to store the link register */
};
diff --git a/cygwin/GNUmakefile.in b/cygwin/GNUmakefile.in
index 0929859030..f342d2fcf7 100644
--- a/cygwin/GNUmakefile.in
+++ b/cygwin/GNUmakefile.in
@@ -2,6 +2,9 @@ gnumake = yes
include Makefile
+MUNICODE_FLAG := $(if $(filter mingw%,$(target_os)),-municode)
+override EXE_LDFLAGS += $(MUNICODE_FLAG)
+
DLLWRAP = @DLLWRAP@ --target=$(target_os) --driver-name="$(CC)"
windres-cpp := $(CPP) -xc
windres-cpp := --preprocessor=$(firstword $(windres-cpp)) \
@@ -41,7 +44,6 @@ SOLIBS := $(DLL_BASE_NAME).res.$(OBJEXT) $(SOLIBS)
override EXTOBJS += $(if $(filter-out $(RUBYW_INSTALL_NAME),$(@:$(EXEEXT)=)),$(RUBY_INSTALL_NAME),$(@:$(EXEEXT)=)).res.$(OBJEXT)
RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(DLL_BASE_NAME).rc
RUBYDEF = $(DLL_BASE_NAME).def
-override LIBRUBY_FOR_LEAKED_GLOBALS := # DLL shows symbols from import library
ruby: $(PROGRAM)
rubyw: $(WPROGRAM)
@@ -64,7 +66,7 @@ $(PROGRAM): $(RUBY_INSTALL_NAME).res.$(OBJEXT)
$(WPROGRAM): $(RUBYW_INSTALL_NAME).res.$(OBJEXT)
@rm -f $@
$(ECHO) linking $@
- $(Q) $(PURIFY) $(CC) -mwindows -e $(SYMBOL_PREFIX)mainCRTStartup $(LDFLAGS) $(XLDFLAGS) \
+ $(Q) $(PURIFY) $(CC) $(MUNICODE_FLAG) -mwindows -e $(SYMBOL_PREFIX)mainCRTStartup $(LDFLAGS) $(XLDFLAGS) \
$(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@
$(STUBPROGRAM): $(RUBY_INSTALL_NAME).res.$(OBJEXT)
diff --git a/darray.h b/darray.h
index 8e1e576355..c9a53f1e01 100644
--- a/darray.h
+++ b/darray.h
@@ -5,9 +5,6 @@
#include <stddef.h>
#include <stdlib.h>
-#include "internal/bits.h"
-#include "internal/gc.h"
-
// Type for a dynamic array. Use to declare a dynamic array.
// It is a pointer so it fits in st_table nicely. Designed
// to be fairly type-safe.
@@ -40,79 +37,66 @@
//
#define rb_darray_ref(ary, idx) (&((ary)->data[(idx)]))
-/* Copy a new element into the array. ptr_to_ary is evaluated multiple times.
- *
- * void rb_darray_append(rb_darray(T) *ptr_to_ary, T element);
- */
-#define rb_darray_append(ptr_to_ary, element) \
- rb_darray_append_impl(ptr_to_ary, element, rb_xrealloc_mul_add)
-
-#define rb_darray_append_without_gc(ptr_to_ary, element) \
- rb_darray_append_impl(ptr_to_ary, element, rb_darray_realloc_mul_add_without_gc)
-
-#define rb_darray_append_impl(ptr_to_ary, element, realloc_func) do { \
- rb_darray_ensure_space((ptr_to_ary), \
- sizeof(**(ptr_to_ary)), \
- sizeof((*(ptr_to_ary))->data[0]), \
- realloc_func); \
+// Copy a new element into the array. ptr_to_ary is evaluated multiple times.
+//
+// void rb_darray_append(rb_darray(T) *ptr_to_ary, T element);
+//
+#define rb_darray_append(ptr_to_ary, element) do { \
+ rb_darray_ensure_space((ptr_to_ary), sizeof(**(ptr_to_ary)), \
+ sizeof((*(ptr_to_ary))->data[0])); \
rb_darray_set(*(ptr_to_ary), \
(*(ptr_to_ary))->meta.size, \
(element)); \
(*(ptr_to_ary))->meta.size++; \
} while (0)
+
+// Last element of the array
+//
+#define rb_darray_back(ary) ((ary)->data[(ary)->meta.size - 1])
+
+// Remove the last element of the array.
+//
+#define rb_darray_pop_back(ary) ((ary)->meta.size--)
+
+// Remove element at idx and replace it by the last element
+#define rb_darray_remove_unordered(ary, idx) do { \
+ rb_darray_set(ary, idx, rb_darray_back(ary)); \
+ rb_darray_pop_back(ary); \
+} while (0);
+
// Iterate over items of the array in a for loop
//
#define rb_darray_foreach(ary, idx_name, elem_ptr_var) \
for (size_t idx_name = 0; idx_name < rb_darray_size(ary) && ((elem_ptr_var) = rb_darray_ref(ary, idx_name)); ++idx_name)
-// Iterate over valid indices in the array in a for loop
+// Iterate over valid indicies in the array in a for loop
//
#define rb_darray_for(ary, idx_name) \
for (size_t idx_name = 0; idx_name < rb_darray_size(ary); ++idx_name)
-/* Make a dynamic array of a certain size. All bytes backing the elements are set to zero.
- * Return 1 on success and 0 on failure.
- *
- * Note that NULL is a valid empty dynamic array.
- *
- * void rb_darray_make(rb_darray(T) *ptr_to_ary, size_t size);
- */
+// Make a dynamic array of a certain size. All bytes backing the elements are set to zero.
+//
+// Note that NULL is a valid empty dynamic array.
+//
+// void rb_darray_make(rb_darray(T) *ptr_to_ary, size_t size);
+//
#define rb_darray_make(ptr_to_ary, size) \
rb_darray_make_impl((ptr_to_ary), size, sizeof(**(ptr_to_ary)), \
- sizeof((*(ptr_to_ary))->data[0]), rb_xcalloc_mul_add)
-
-#define rb_darray_make_without_gc(ptr_to_ary, size) \
- rb_darray_make_impl((ptr_to_ary), size, sizeof(**(ptr_to_ary)), \
- sizeof((*(ptr_to_ary))->data[0]), rb_darray_calloc_mul_add_without_gc)
-
-/* Resize the darray to a new capacity. The new capacity must be greater than
- * or equal to the size of the darray.
- *
- * void rb_darray_resize_capa(rb_darray(T) *ptr_to_ary, size_t capa);
- */
-#define rb_darray_resize_capa_without_gc(ptr_to_ary, capa) \
- rb_darray_resize_capa_impl((ptr_to_ary), rb_darray_next_power_of_two(capa), sizeof(**(ptr_to_ary)), \
- sizeof((*(ptr_to_ary))->data[0]), rb_darray_realloc_mul_add_without_gc)
+ sizeof((*(ptr_to_ary))->data[0]))
#define rb_darray_data_ptr(ary) ((ary)->data)
+// Set the size of the array to zero without freeing the backing memory.
+// Allows reusing the same array.
+//
+#define rb_darray_clear(ary) (ary->meta.size = 0)
+
typedef struct rb_darray_meta {
size_t size;
size_t capa;
} rb_darray_meta_t;
-/* Set the size of the array to zero without freeing the backing memory.
- * Allows reusing the same array. */
-static inline void
-rb_darray_clear(void *ary)
-{
- rb_darray_meta_t *meta = ary;
- if (meta) {
- meta->size = 0;
- }
-}
-
// Get the size of the dynamic array.
//
static inline size_t
@@ -131,86 +115,20 @@ rb_darray_capa(const void *ary)
return meta ? meta->capa : 0;
}
-/* Free the dynamic array. */
+// Free the dynamic array.
+//
static inline void
rb_darray_free(void *ary)
{
rb_darray_meta_t *meta = ary;
- if (meta) ruby_sized_xfree(ary, meta->capa);
-}
-
-static inline void
-rb_darray_free_without_gc(void *ary)
-{
- free(ary);
-}
-
-/* Internal function. Like rb_xcalloc_mul_add but does not trigger GC and does
- * not check for overflow in arithmetic. */
-static inline void *
-rb_darray_calloc_mul_add_without_gc(size_t x, size_t y, size_t z)
-{
- size_t size = (x * y) + z;
-
- void *ptr = calloc(1, size);
- if (ptr == NULL) rb_bug("rb_darray_calloc_mul_add_without_gc: failed");
-
- return ptr;
-}
-
-/* Internal function. Like rb_xrealloc_mul_add but does not trigger GC and does
- * not check for overflow in arithmetic. */
-static inline void *
-rb_darray_realloc_mul_add_without_gc(const void *orig_ptr, size_t x, size_t y, size_t z)
-{
- size_t size = (x * y) + z;
-
- void *ptr = realloc((void *)orig_ptr, size);
- if (ptr == NULL) rb_bug("rb_darray_realloc_mul_add_without_gc: failed");
-
- return ptr;
-}
-
-/* Internal function. Returns the next power of two that is greater than or
- * equal to n. */
-static inline size_t
-rb_darray_next_power_of_two(size_t n)
-{
- return (size_t)(1 << (64 - nlz_int64(n)));
-}
-
-/* Internal function. Resizes the capacity of a darray. The new capacity must
- * be greater than or equal to the size of the darray. */
-static inline void
-rb_darray_resize_capa_impl(void *ptr_to_ary, size_t new_capa, size_t header_size, size_t element_size,
- void *(*realloc_mul_add_impl)(const void *, size_t, size_t, size_t))
-{
- rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary;
- rb_darray_meta_t *meta = *ptr_to_ptr_to_meta;
-
- rb_darray_meta_t *new_ary = realloc_mul_add_impl(meta, new_capa, element_size, header_size);
-
- if (meta == NULL) {
- /* First allocation. Initialize size. On subsequence allocations
- * realloc takes care of carrying over the size. */
- new_ary->size = 0;
- }
-
- assert(new_ary->size <= new_capa);
-
- new_ary->capa = new_capa;
-
- // We don't have access to the type of the dynamic array in function context.
- // Write out result with memcpy to avoid strict aliasing issue.
- memcpy(ptr_to_ary, &new_ary, sizeof(new_ary));
+ ruby_sized_xfree(ary, meta->capa);
}
// Internal function
// Ensure there is space for one more element.
// Note: header_size can be bigger than sizeof(rb_darray_meta_t) when T is __int128_t, for example.
static inline void
-rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size,
- void *(*realloc_mul_add_impl)(const void *, size_t, size_t, size_t))
+rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size)
{
rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary;
rb_darray_meta_t *meta = *ptr_to_ptr_to_meta;
@@ -220,12 +138,25 @@ rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size
// Double the capacity
size_t new_capa = current_capa == 0 ? 1 : current_capa * 2;
- rb_darray_resize_capa_impl(ptr_to_ary, new_capa, header_size, element_size, realloc_mul_add_impl);
+ rb_darray_meta_t *doubled_ary = rb_xrealloc_mul_add(meta, new_capa, element_size, header_size);
+ // rb_xrealloc functions guarantee that NULL is not returned
+ assert(doubled_ary != NULL);
+
+ if (meta == NULL) {
+ // First allocation. Initialize size. On subsequence allocations
+ // realloc takes care of carrying over the size.
+ doubled_ary->size = 0;
+ }
+
+ doubled_ary->capa = new_capa;
+
+ // We don't have access to the type of the dynamic array in function context.
+ // Write out result with memcpy to avoid strict aliasing issue.
+ memcpy(ptr_to_ary, &doubled_ary, sizeof(doubled_ary));
}
static inline void
-rb_darray_make_impl(void *ptr_to_ary, size_t array_size, size_t header_size, size_t element_size,
- void *(*calloc_mul_add_impl)(size_t, size_t, size_t))
+rb_darray_make_impl(void *ptr_to_ary, size_t array_size, size_t header_size, size_t element_size)
{
rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary;
if (array_size == 0) {
@@ -233,7 +164,9 @@ rb_darray_make_impl(void *ptr_to_ary, size_t array_size, size_t header_size, siz
return;
}
- rb_darray_meta_t *meta = calloc_mul_add_impl(array_size, element_size, header_size);
+ rb_darray_meta_t *meta = rb_xcalloc_mul_add(array_size, element_size, header_size);
+ // rb_xcalloc functions guarantee that NULL is not returned
+ assert(meta != NULL);
meta->size = array_size;
meta->capa = array_size;
diff --git a/debug.c b/debug.c
index e84e3d602a..3dd0f71906 100644
--- a/debug.c
+++ b/debug.c
@@ -53,8 +53,14 @@ const union {
rb_econv_result_t econv_result;
enum ruby_preserved_encindex encoding_index;
enum ruby_robject_flags robject_flags;
+#if !USE_RVARGC
+ enum ruby_robject_consts robject_consts;
+#endif
enum ruby_rmodule_flags rmodule_flags;
enum ruby_rstring_flags rstring_flags;
+#if !USE_RVARGC
+ enum ruby_rstring_consts rstring_consts;
+#endif
enum ruby_rarray_flags rarray_flags;
enum ruby_rarray_consts rarray_consts;
enum {
@@ -70,7 +76,7 @@ const union {
RUBY_FMODE_NOREVLOOKUP = 0x00000100,
RUBY_FMODE_TRUNC = FMODE_TRUNC,
RUBY_FMODE_TEXTMODE = FMODE_TEXTMODE,
- RUBY_FMODE_EXTERNAL = 0x00010000,
+ RUBY_FMODE_PREP = 0x00010000,
RUBY_FMODE_SETENC_BY_BOM = FMODE_SETENC_BY_BOM,
RUBY_FMODE_UNIX = 0x00200000,
RUBY_FMODE_INET = 0x00400000,
@@ -112,7 +118,7 @@ ruby_debug_printf(const char *format, ...)
va_end(ap);
}
-#include "internal/gc.h"
+#include "gc.h"
VALUE
ruby_debug_print_value(int level, int debug_level, const char *header, VALUE obj)
@@ -285,20 +291,12 @@ static const char *dlf_type_names[] = {
"func",
};
-#ifdef MAX_PATH
-#define DEBUG_LOG_MAX_PATH (MAX_PATH-1)
-#else
-#define DEBUG_LOG_MAX_PATH 255
-#endif
-
static struct {
char *mem;
unsigned int cnt;
struct debug_log_filter filters[MAX_DEBUG_LOG_FILTER_NUM];
unsigned int filters_num;
- bool show_pid;
rb_nativethread_lock_t lock;
- char output_file[DEBUG_LOG_MAX_PATH+1];
FILE *output;
} debug_log;
@@ -400,39 +398,7 @@ setup_debug_log(void)
}
else {
ruby_debug_log_mode |= ruby_debug_log_file;
-
- // pid extension with %p
- unsigned long len = strlen(log_config);
-
- for (unsigned long i=0, j=0; i<len; i++) {
- const char c = log_config[i];
-
- if (c == '%') {
- i++;
- switch (log_config[i]) {
- case '%':
- debug_log.output_file[j++] = '%';
- break;
- case 'p':
- snprintf(debug_log.output_file + j, DEBUG_LOG_MAX_PATH - j, "%d", getpid());
- j = strlen(debug_log.output_file);
- break;
- default:
- fprintf(stderr, "can not parse RUBY_DEBUG_LOG filename: %s\n", log_config);
- exit(1);
- }
- }
- else {
- debug_log.output_file[j++] = c;
- }
-
- if (j >= DEBUG_LOG_MAX_PATH) {
- fprintf(stderr, "RUBY_DEBUG_LOG=%s is too long\n", log_config);
- exit(1);
- }
- }
-
- if ((debug_log.output = fopen(debug_log.output_file, "w")) == NULL) {
+ if ((debug_log.output = fopen(log_config, "w")) == NULL) {
fprintf(stderr, "can not open %s for RUBY_DEBUG_LOG\n", log_config);
exit(1);
}
@@ -443,17 +409,9 @@ setup_debug_log(void)
(ruby_debug_log_mode & ruby_debug_log_memory) ? "[mem]" : "",
(ruby_debug_log_mode & ruby_debug_log_stderr) ? "[stderr]" : "",
(ruby_debug_log_mode & ruby_debug_log_file) ? "[file]" : "");
- if (debug_log.output_file[0]) {
- fprintf(stderr, "RUBY_DEBUG_LOG filename=%s\n", debug_log.output_file);
- }
-
rb_nativethread_lock_initialize(&debug_log.lock);
setup_debug_log_filter();
-
- if (getenv("RUBY_DEBUG_LOG_PID")) {
- debug_log.show_pid = true;
- }
}
}
@@ -492,7 +450,7 @@ check_filter(const char *str, const struct debug_log_filter *filter, bool *state
// (func_name or file_name) contains baz or boo
//
// RUBY_DEBUG_LOG_FILTER=foo,bar,-baz,-boo
-// returns true if
+// retunrs true if
// (func_name or file_name) contains foo or bar
// or
// (func_name or file_name) doesn't contain baz and
@@ -549,16 +507,10 @@ ruby_debug_log(const char *file, int line, const char *func_name, const char *fm
int len = 0;
int r = 0;
- if (debug_log.show_pid) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN, "pid:%d\t", getpid());
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
- len += r;
- }
-
// message title
if (func_name && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN, "%s\t", func_name);
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
@@ -577,67 +529,41 @@ ruby_debug_log(const char *file, int line, const char *func_name, const char *fm
// C location
if (file && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN, "\t%s:%d", pretty_filename(file), line);
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
- rb_execution_context_t *ec = rb_current_execution_context(false);
-
- // Ruby location
- int ruby_line;
- const char *ruby_file = ec ? rb_source_location_cstr(&ruby_line) : NULL;
-
- if (len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- if (ruby_file) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t%s:%d", pretty_filename(ruby_file), ruby_line);
- }
- else {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t");
+ if (rb_current_execution_context(false)) {
+ // Ruby location
+ int ruby_line;
+ const char *ruby_file = rb_source_location_cstr(&ruby_line);
+ if (len < MAX_DEBUG_LOG_MESSAGE_LEN) {
+ if (ruby_file) {
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t%s:%d", pretty_filename(ruby_file), ruby_line);
+ }
+ else {
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t");
+ }
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
+ len += r;
}
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
- len += r;
- }
-
-#ifdef RUBY_NT_SERIAL
- // native thread information
- if (len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tnt:%d", ruby_nt_serial);
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
- len += r;
- }
-#endif
-
- if (ec) {
- rb_thread_t *th = ec ? rb_ec_thread_ptr(ec) : NULL;
// ractor information
if (ruby_single_main_ractor == NULL) {
- rb_ractor_t *cr = th ? th->ractor : NULL;
- rb_vm_t *vm = GET_VM();
-
+ rb_ractor_t *cr = GET_RACTOR();
if (r && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tr:#%d/%u (%u)",
- cr ? (int)rb_ractor_id(cr) : -1, vm->ractor.cnt, vm->ractor.sched.running_cnt);
-
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tr:#%u/%u",
+ (unsigned int)rb_ractor_id(cr), GET_VM()->ractor.cnt);
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
}
// thread information
- if (th && r && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- rb_execution_context_t *rec = th->ractor ? th->ractor->threads.running_ec : NULL;
- const rb_thread_t *rth = rec ? rec->thread_ptr : NULL;
- const rb_thread_t *sth = th->ractor ? th->ractor->threads.sched.running : NULL;
-
- if (rth != th || sth != th) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tth:%u (rth:%d,sth:%d)",
- rb_th_serial(th), rth ? (int)rb_th_serial(rth) : -1, sth ? (int)rb_th_serial(sth) : -1);
- }
- else {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tth:%u", rb_th_serial(th));
- }
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ const rb_thread_t *th = GET_THREAD();
+ if (r && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tth:%u", rb_th_serial(th));
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
}
diff --git a/debug_counter.c b/debug_counter.c
index 3dcc4c6a3a..463bebf849 100644
--- a/debug_counter.c
+++ b/debug_counter.c
@@ -25,8 +25,10 @@ const char *const rb_debug_counter_names[] = {
#undef RB_DEBUG_COUNTER
};
+MJIT_SYMBOL_EXPORT_BEGIN
size_t rb_debug_counter[numberof(rb_debug_counter_names)];
void rb_debug_counter_add_atomic(enum rb_debug_counter_type type, int add);
+MJIT_SYMBOL_EXPORT_END
static rb_nativethread_lock_t debug_counter_lock;
diff --git a/debug_counter.h b/debug_counter.h
index a8b95edded..6e0b8dee60 100644
--- a/debug_counter.h
+++ b/debug_counter.h
@@ -100,13 +100,6 @@ RB_DEBUG_COUNTER(ccf_opt_block_call)
RB_DEBUG_COUNTER(ccf_opt_struct_aref)
RB_DEBUG_COUNTER(ccf_opt_struct_aset)
RB_DEBUG_COUNTER(ccf_super_method)
-RB_DEBUG_COUNTER(ccf_cfunc_other)
-RB_DEBUG_COUNTER(ccf_cfunc_only_splat)
-RB_DEBUG_COUNTER(ccf_cfunc_only_splat_kw)
-RB_DEBUG_COUNTER(ccf_iseq_bmethod)
-RB_DEBUG_COUNTER(ccf_noniseq_bmethod)
-RB_DEBUG_COUNTER(ccf_opt_send_complex)
-RB_DEBUG_COUNTER(ccf_opt_send_simple)
/*
* control frame push counts.
@@ -134,22 +127,29 @@ RB_DEBUG_COUNTER(frame_R2C)
RB_DEBUG_COUNTER(frame_C2C)
RB_DEBUG_COUNTER(frame_C2R)
-/* instance variable counts */
-RB_DEBUG_COUNTER(ivar_get_obj_hit) // Only T_OBJECT hits
-RB_DEBUG_COUNTER(ivar_get_obj_miss) // Only T_OBJECT misses
-RB_DEBUG_COUNTER(ivar_get_ic_hit) // All hits
-RB_DEBUG_COUNTER(ivar_get_ic_miss) // All misses
-RB_DEBUG_COUNTER(ivar_set_ic_hit) // All hits
-RB_DEBUG_COUNTER(ivar_set_obj_hit) // Only T_OBJECT hits
-RB_DEBUG_COUNTER(ivar_set_obj_miss) // Only T_OBJECT misses
-RB_DEBUG_COUNTER(ivar_set_ic_miss) // All misses
-RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject) // Miss because non T_OBJECT
-RB_DEBUG_COUNTER(ivar_get_base) // Calls to `rb_ivar_get` (very slow path)
-RB_DEBUG_COUNTER(ivar_set_base) // Calls to `ivar_set` (very slow path)
-RB_DEBUG_COUNTER(ivar_get_ic_miss_set) // Misses on IV reads where the cache was wrong
-RB_DEBUG_COUNTER(ivar_get_cc_miss_set) // Misses on attr_reader where the cache was wrong
-RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) // Misses on IV read where the cache wasn't set
-RB_DEBUG_COUNTER(ivar_get_cc_miss_unset) // Misses on attr_reader where the cache wasn't set
+/* instance variable counts
+ *
+ * * ivar_get_ic_hit/miss: ivar_get inline cache (ic) hit/miss counts (VM insn)
+ * * ivar_get_ic_miss_unset: ... by unset (VM insn)
+ * * ivar_get_ic_miss_noobject: ... by "not T_OBJECT" (VM insn)
+ * * ivar_set_...: same counts with ivar_set (VM insn)
+ * * ivar_get/set_base: call counts of "rb_ivar_get/set()".
+ * because of (1) ic miss.
+ * (2) direct call by C extensions.
+ */
+RB_DEBUG_COUNTER(ivar_get_ic_hit)
+RB_DEBUG_COUNTER(ivar_get_ic_miss)
+RB_DEBUG_COUNTER(ivar_get_ic_miss_noobject)
+RB_DEBUG_COUNTER(ivar_set_ic_hit)
+RB_DEBUG_COUNTER(ivar_set_ic_miss)
+RB_DEBUG_COUNTER(ivar_set_ic_miss_iv_hit)
+RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject)
+RB_DEBUG_COUNTER(ivar_get_base)
+RB_DEBUG_COUNTER(ivar_set_base)
+RB_DEBUG_COUNTER(ivar_get_ic_miss_set)
+RB_DEBUG_COUNTER(ivar_get_cc_miss_set)
+RB_DEBUG_COUNTER(ivar_get_ic_miss_unset)
+RB_DEBUG_COUNTER(ivar_get_cc_miss_unset)
/* local variable counts
*
@@ -185,7 +185,8 @@ RB_DEBUG_COUNTER(gc_major_force)
RB_DEBUG_COUNTER(gc_major_oldmalloc)
RB_DEBUG_COUNTER(gc_enter_start)
-RB_DEBUG_COUNTER(gc_enter_continue)
+RB_DEBUG_COUNTER(gc_enter_mark_continue)
+RB_DEBUG_COUNTER(gc_enter_sweep_continue)
RB_DEBUG_COUNTER(gc_enter_rest)
RB_DEBUG_COUNTER(gc_enter_finalizer)
@@ -214,6 +215,7 @@ RB_DEBUG_COUNTER(gc_isptr_maybe)
* * [attr]
* * _ptr: R?? is not embed.
* * _embed: R?? is embed.
+ * * _transient: R?? uses transient heap.
* * type specific attr.
* * str_shared: str is shared.
* * str_nofree: nofree
@@ -239,6 +241,7 @@ RB_DEBUG_COUNTER(obj_promote)
RB_DEBUG_COUNTER(obj_wb_unprotect)
RB_DEBUG_COUNTER(obj_obj_embed)
+RB_DEBUG_COUNTER(obj_obj_transient)
RB_DEBUG_COUNTER(obj_obj_ptr)
RB_DEBUG_COUNTER(obj_obj_too_complex)
@@ -249,6 +252,7 @@ RB_DEBUG_COUNTER(obj_str_nofree)
RB_DEBUG_COUNTER(obj_str_fstr)
RB_DEBUG_COUNTER(obj_ary_embed)
+RB_DEBUG_COUNTER(obj_ary_transient)
RB_DEBUG_COUNTER(obj_ary_ptr)
RB_DEBUG_COUNTER(obj_ary_extracapa)
/*
@@ -272,9 +276,11 @@ RB_DEBUG_COUNTER(obj_hash_g8)
RB_DEBUG_COUNTER(obj_hash_null)
RB_DEBUG_COUNTER(obj_hash_ar)
RB_DEBUG_COUNTER(obj_hash_st)
+RB_DEBUG_COUNTER(obj_hash_transient)
RB_DEBUG_COUNTER(obj_hash_force_convert)
RB_DEBUG_COUNTER(obj_struct_embed)
+RB_DEBUG_COUNTER(obj_struct_transient)
RB_DEBUG_COUNTER(obj_struct_ptr)
RB_DEBUG_COUNTER(obj_data_empty)
@@ -329,6 +335,11 @@ RB_DEBUG_COUNTER(heap_xmalloc)
RB_DEBUG_COUNTER(heap_xrealloc)
RB_DEBUG_COUNTER(heap_xfree)
+/* transient_heap */
+RB_DEBUG_COUNTER(theap_alloc)
+RB_DEBUG_COUNTER(theap_alloc_fail)
+RB_DEBUG_COUNTER(theap_evacuate)
+
// VM sync
RB_DEBUG_COUNTER(vm_sync_lock)
RB_DEBUG_COUNTER(vm_sync_lock_enter)
diff --git a/defs/gmake.mk b/defs/gmake.mk
index 5489b017b3..54fef6685f 100644
--- a/defs/gmake.mk
+++ b/defs/gmake.mk
@@ -1,19 +1,20 @@
# -*- mode: makefile-gmake; indent-tabs-mode: t -*-
reconfig config.status: export MAKE:=$(MAKE)
-export BASERUBY:=$(BASERUBY)
override gnumake_recursive := $(if $(findstring n,$(firstword $(MFLAGS))),,+)
override mflags := $(filter-out -j%,$(MFLAGS))
MSPECOPT += $(if $(filter -j%,$(MFLAGS)),-j)
nproc = $(subst -j,,$(filter -j%,$(MFLAGS)))
ifeq ($(GITHUB_ACTIONS),true)
-# 93(bright yellow) is copied from .github/workflows/mingw.yml
-override ACTIONS_GROUP = @echo "::group::$(@:yes-%=%)"
-override ACTIONS_ENDGROUP = @echo "::endgroup::"
+override ACTIONS_GROUP = @echo "\#\#[group]$(patsubst yes-%,%,$@)"
+override ACTIONS_ENDGROUP = @echo "\#\#[endgroup]"
endif
ifneq ($(filter darwin%,$(target_os)),)
+# Remove debug option not to generate thousands of .dSYM
+MJIT_DEBUGFLAGS := $(filter-out -g%,$(MJIT_DEBUGFLAGS))
+
INSTRUBY_ENV += SDKROOT=
endif
INSTRUBY_ARGS += --gnumake
@@ -25,7 +26,7 @@ TEST_TARGETS := $(filter $(CHECK_TARGETS),$(MAKECMDGOALS))
TEST_DEPENDS := $(filter-out commit $(TEST_TARGETS),$(MAKECMDGOALS))
TEST_TARGETS := $(patsubst great,exam,$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out great $(TEST_TARGETS),$(TEST_DEPENDS))
-TEST_TARGETS := $(patsubst exam,test-bundled-gems test-bundler-parallel check,$(TEST_TARGETS))
+TEST_TARGETS := $(patsubst exam,check,$(TEST_TARGETS))
TEST_TARGETS := $(patsubst check,test-syntax-suggest test-spec test-all test-tool test-short,$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-rubyspec,test-spec,$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out exam check test-spec $(TEST_TARGETS),$(TEST_DEPENDS))
@@ -36,15 +37,12 @@ TEST_DEPENDS := $(filter-out test-all $(TEST_TARGETS),$(TEST_DEPENDS))
TEST_TARGETS := $(patsubst test,test-short,$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out test $(TEST_TARGETS),$(TEST_DEPENDS))
TEST_TARGETS := $(patsubst test-short,btest-ruby test-knownbug test-basic,$(TEST_TARGETS))
-TEST_TARGETS := $(patsubst test-basic,test-basic test-leaked-globals,$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-bundled-gems,test-bundled-gems-run,$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-bundled-gems-run,test-bundled-gems-run $(PREPARE_BUNDLED_GEMS),$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-bundled-gems-prepare,test-bundled-gems-prepare $(PRECHECK_BUNDLED_GEMS) test-bundled-gems-fetch,$(TEST_TARGETS))
-TEST_TARGETS := $(patsubst test-bundler-parallel,test-bundler-parallel $(PREPARE_BUNDLER),$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-syntax-suggest,test-syntax-suggest $(PREPARE_SYNTAX_SUGGEST),$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out test-short $(TEST_TARGETS),$(TEST_DEPENDS))
TEST_DEPENDS += $(if $(filter great exam love check,$(MAKECMDGOALS)),all exts)
-TEST_TARGETS := $(patsubst yes-%,%,$(filter-out no-%,$(TEST_TARGETS)))
endif
in-srcdir := $(if $(filter-out .,$(srcdir)),$(CHDIR) $(srcdir) &&)
@@ -57,13 +55,6 @@ ifeq ($(if $(filter all main exts enc trans libencs libenc libtrans \
-include $(SHOWFLAGS)
endif
-ifeq ($(HAVE_BASERUBY):$(HAVE_GIT),yes:yes)
-override modified := $(shell $(BASERUBY) -C $(srcdir) tool/file2lastrev.rb --modified='%Y %m %d')
-override RUBY_RELEASE_YEAR := $(word 1,$(modified))
-override RUBY_RELEASE_MONTH := $(word 2,$(modified))
-override RUBY_RELEASE_DAY := $(word 3,$(modified))
-endif
-
ifneq ($(filter universal-%,$(arch)),)
define archcmd
%.$(1).S: %.c
@@ -79,7 +70,7 @@ define archcmd
%.i: %.$(1).i
endef
-$(foreach arch,$(filter -arch=%,$(subst -arch ,-arch=,$(ARCH_FLAG))),\
+$(foreach arch,$(arch_flags),\
$(eval $(call archcmd,$(patsubst -arch=%,%,$(value arch)),$(patsubst -arch=%,-arch %,$(value arch)))))
endif
@@ -91,31 +82,16 @@ $(addprefix yes-,$(TEST_TARGETS)): $(TEST_DEPENDS)
endif
ORDERED_TEST_TARGETS := $(filter $(TEST_TARGETS), \
- btest-ruby test-knownbug test-leaked-globals test-basic \
+ btest-ruby test-knownbug test-basic \
test-testframework test-tool test-ruby test-all \
test-spec test-syntax-suggest-prepare test-syntax-suggest \
test-bundler-prepare test-bundler test-bundler-parallel \
test-bundled-gems-precheck test-bundled-gems-fetch \
test-bundled-gems-prepare test-bundled-gems-run \
)
-
-# grep ^yes-test-.*-precheck: template/Makefile.in defs/gmake.mk common.mk
-test_prechecks := $(filter $(ORDERED_TEST_TARGETS),\
- test-leaked-globals \
- test-all \
- test-spec \
- test-syntax-suggest \
- test-bundler \
- test-bundler-parallel \
- test-bundled-gems\
- )
-prev_test := $(subst test-bundler-parallel,test-bundler,$(test_prechecks))
-prev_test := $(addsuffix -precheck,$(prev_test))
-first_test_prechecks := $(prev_test)
-
+prev_test := $(if $(filter test-spec,$(ORDERED_TEST_TARGETS)),test-spec-precheck)
$(foreach test,$(ORDERED_TEST_TARGETS), \
- $(eval yes-$(value test): $(addprefix yes-,$(value prev_test))); \
- $(eval no-$(value test): $(addprefix no-,$(value prev_test))); \
+ $(eval yes-$(value test) no-$(value test): $(value prev_test)); \
$(eval prev_test := $(value test)))
endif
@@ -193,22 +169,15 @@ $(SCRIPTBINDIR):
$(Q) mkdir $@
.PHONY: commit
-COMMIT_PREPARE := $(filter-out commit do-commit,$(MAKECMDGOALS)) up
-
-commit: pre-commit $(DOT_WAIT) do-commit $(DOT_WAIT) post_commit
-pre-commit: $(COMMIT_PREPARE)
-do-commit: $(if $(DOT_WAIT),,pre-commit)
+commit: $(if $(filter commit,$(MAKECMDGOALS)),$(filter-out commit,$(MAKECMDGOALS))) up
@$(BASERUBY) -C "$(srcdir)" -I./tool/lib -rvcs -e 'VCS.detect(".").commit'
-post-commit: $(if $(DOT_WAIT),,do-commit)
+$(Q) \
{ \
$(in-srcdir) \
exec sed -f tool/prereq.status defs/gmake.mk template/Makefile.in common.mk; \
} | \
- $(MAKE) $(mflags) Q=$(Q) ECHO=$(ECHO) \
- top_srcdir="$(top_srcdir)" srcdir="$(srcdir)" srcs_vpath="" CHDIR="$(CHDIR)" \
- BOOTSTRAPRUBY="$(BOOTSTRAPRUBY)" BOOTSTRAPRUBY_OPT="$(BOOTSTRAPRUBY_OPT)" \
- MINIRUBY="$(BASERUBY)" BASERUBY="$(BASERUBY)" HAVE_BASERUBY="$(HAVE_BASERUBY)" \
+ $(MAKE) $(mflags) Q=$(Q) ECHO=$(ECHO) srcdir="$(srcdir)" srcs_vpath="" CHDIR="$(CHDIR)" \
+ BOOTSTRAPRUBY="$(BOOTSTRAPRUBY)" MINIRUBY="$(BASERUBY)" BASERUBY="$(BASERUBY)" \
VCSUP="" ENC_MK=.top-enc.mk REVISION_FORCE=PHONY CONFIGURE="$(CONFIGURE)" -f - \
update-src srcs all-incs
@@ -299,7 +268,6 @@ HELP_EXTRA_TASKS = \
" checkout-github: checkout GitHub Pull Request [PR=1234]" \
" pull-github: rebase GitHub Pull Request to new worktree [PR=1234]" \
" update-github: merge master branch and push it to Pull Request [PR=1234]" \
- " tags: generate TAGS file" \
""
# 1. squeeze spaces
@@ -324,13 +292,12 @@ foreach-bundled-gems-rev = \
foreach-bundled-gems-rev-0 = \
$(call $(1),$(word 1,$(2)),$(word 2,$(2)),$(word 3,$(2)),$(word 4,$(2)))
bundled-gem-gemfile = $(srcdir)/gems/$(1)-$(2).gem
-bundled-gem-gemspec = $(srcdir)/gems/src/$(1)/$(1).gemspec
+bundled-gem-srcdir = $(srcdir)/gems/src/$(1)
bundled-gem-extracted = $(srcdir)/.bundle/gems/$(1)-$(2)
-bundled-gem-revision = $(srcdir)/.bundle/.timestamp/$(1).revision
update-gems: | $(patsubst %,$(srcdir)/gems/%.gem,$(bundled-gems))
update-gems: | $(call foreach-bundled-gems-rev,bundled-gem-gemfile)
-update-gems: | $(call foreach-bundled-gems-rev,bundled-gem-gemspec)
+update-gems: | $(call foreach-bundled-gems-rev,bundled-gem-srcdir)
test-bundler-precheck: | $(srcdir)/.bundle/cache
@@ -358,44 +325,27 @@ $(srcdir)/.bundle/gems/%: $(srcdir)/gems/%.gem | .bundle/gems
-Itool/lib -rbundled_gem \
-e 'BundledGem.unpack("gems/$(@F).gem", ".bundle")'
-$(srcdir)/.bundle/.timestamp:
- $(MAKEDIRS) $@
-
-define build-gem
-$(srcdir)/gems/src/$(1)/.git: | $(srcdir)/gems/src
+define copy-gem
+$(srcdir)/gems/src/$(1): | $(srcdir)/gems/src
$(ECHO) Cloning $(4)
- $(Q) $(GIT) clone $(4) $$(@D)
+ $(Q) $(GIT) clone $(4) $$(@)
-$(bundled-gem-revision): \
- $(if $(if $(wildcard $$(@)),$(filter $(3),$(shell cat $$(@)))),,PHONY) \
- | $(srcdir)/.bundle/.timestamp $(srcdir)/gems/src/$(1)/.git
- $(ECHO) Update $(1) to $(3)
+$(srcdir)/.bundle/gems/$(1)-$(2): | $(srcdir)/gems/src/$(1) .bundle/gems
+ $(ECHO) Copying $(1)@$(3) to $$(@F)
$(Q) $(CHDIR) "$(srcdir)/gems/src/$(1)" && \
- if [ `$(GIT) rev-parse HEAD` != $(3) ]; then \
- $(GIT) fetch origin $(3) && \
- $(GIT) checkout --detach $(3) && \
- :; \
- fi
- echo $(3) | $(IFCHANGE) $$(@) -
-
-# The repository of minitest does not include minitest.gemspec because it uses hoe.
-# This creates a dummy gemspec.
-$(bundled-gem-gemspec): $(bundled-gem-revision) \
- | $(srcdir)/gems/src/$(1)/.git
- $(Q) $(BASERUBY) -I$(tooldir)/lib -rbundled_gem -e 'BundledGem.dummy_gemspec(*ARGV)' $$(@)
-
-$(bundled-gem-gemfile): $(bundled-gem-gemspec) $(bundled-gem-revision)
- $(ECHO) Building $(1)@$(3) to $$(@)
+ $(GIT) fetch origin $(3) && \
+ $(GIT) checkout --detach $(3) && \
+ :
$(Q) $(BASERUBY) -C "$(srcdir)" \
-Itool/lib -rbundled_gem \
- -e 'BundledGem.build("gems/src/$(1)/$(1).gemspec", "$(2)", "gems", validation: false)'
+ -e 'BundledGem.copy("gems/src/$(1)/$(1).gemspec", ".bundle")'
endef
-define build-gem-0
-$(eval $(call build-gem,$(1),$(2),$(3),$(4)))
+define copy-gem-0
+$(eval $(call copy-gem,$(1),$(2),$(3),$(4)))
endef
-$(call foreach-bundled-gems-rev,build-gem-0)
+$(call foreach-bundled-gems-rev,copy-gem-0)
$(srcdir)/gems/src:
$(MAKEDIRS) $@
@@ -403,36 +353,49 @@ $(srcdir)/gems/src:
$(srcdir)/.bundle/gems:
$(MAKEDIRS) $@
-ifneq ($(DOT_WAIT),)
-up:: $(DOT_WAIT) after-update
-endif
-
ifneq ($(filter update-bundled_gems refresh-gems,$(MAKECMDGOALS)),)
update-gems: update-bundled_gems
endif
+ifeq ($(filter 0 1,$(words $(arch_flags))),)
+$(foreach x,$(patsubst -arch=%,%,$(arch_flags)), \
+ $(eval $$(MJIT_HEADER:.h=)-$(value x).h \
+ $$(MJIT_MIN_HEADER:.h=)-$(value x).h \
+ $$(TIMESTAMPDIR)/$$(MJIT_HEADER:.h=)-$(value x).time \
+ : ARCH_FLAG := -arch $(value x)))
+
+$(foreach x,$(patsubst -arch=%,%,$(arch_flags)), \
+ $(eval $$(MJIT_HEADER:.h=)-$(value x).h: \
+ $$(TIMESTAMPDIR)/$$(MJIT_HEADER:.h=)-$(value x).time))
+
+mjit_min_headers := $(patsubst -arch=%,$(MJIT_MIN_HEADER:.h=-%.h),$(arch_flags))
+$(MJIT_MIN_HEADER): $(mjit_min_headers) $(PREP)
+ @ set -e; set $(patsubst -arch=%,%,$(arch_flags)); \
+ cd $(@D); h=$(@F:.h=); \
+ exec > $(@F).new; \
+ echo '#if 0'; \
+ for arch; do\
+ echo "#elif defined __$${arch}__"; \
+ echo "# include \"$$h-$$arch.h\""; \
+ done; \
+ echo "#else"; echo "# error unsupported platform"; echo "#endif"
+ $(IFCHANGE) $@ $@.new
+ $(Q) $(MAKEDIRS) $(MJIT_HEADER_INSTALL_DIR)
+ $(Q) $(MAKE_LINK) $@ $(MJIT_HEADER_INSTALL_DIR)/$(@F)
+
+endif
+
.SECONDARY: update-unicode-files
.SECONDARY: update-unicode-auxiliary-files
.SECONDARY: update-unicode-ucd-emoji-files
.SECONDARY: update-unicode-emoji-files
-ifneq ($(DOT_WAIT),)
-.NOTPARALLEL: update-unicode
-.NOTPARALLEL: update-unicode-files
-.NOTPARALLEL: update-unicode-auxiliary-files
-.NOTPARALLEL: update-unicode-ucd-emoji-files
-.NOTPARALLEL: update-unicode-emoji-files
-.NOTPARALLEL: $(UNICODE_FILES) $(UNICODE_PROPERTY_FILES)
-.NOTPARALLEL: $(UNICODE_AUXILIARY_FILES)
-.NOTPARALLEL: $(UNICODE_UCD_EMOJI_FILES) $(UNICODE_EMOJI_FILES)
-endif
-
ifeq ($(HAVE_GIT),yes)
REVISION_LATEST := $(shell $(CHDIR) $(srcdir) && $(GIT) log -1 --format=%H 2>/dev/null)
else
REVISION_LATEST := update
endif
-REVISION_IN_HEADER := $(shell sed '/^\#define RUBY_FULL_REVISION "\(.*\)"/!d;s//\1/;q' $(wildcard $(srcdir)/revision.h revision.h) /dev/null 2>/dev/null)
+REVISION_IN_HEADER := $(shell sed -n 's/^\#define RUBY_FULL_REVISION "\(.*\)"/\1/p' $(wildcard $(srcdir)/revision.h revision.h) /dev/null 2>/dev/null)
ifeq ($(REVISION_IN_HEADER),)
REVISION_IN_HEADER := none
endif
@@ -503,7 +466,7 @@ update-deps:
$(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(srcdir)/$(RUBYSPEC_CAPIEXT)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY)
$(ECHO) building $@
$(Q) $(MAKEDIRS) $(@D)
- $(Q) $(DLDSHARED) -L. $(XDLDFLAGS) $(XLDFLAGS) $(LDFLAGS) $(INCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ $< $(LIBRUBYARG)
+ $(Q) $(DLDSHARED) $(XDLDFLAGS) $(XLDFLAGS) $(LDFLAGS) $(INCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ $< $(LIBRUBYARG)
$(Q) $(RMALL) $@.*
rubyspec-capiext: $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
@@ -517,29 +480,3 @@ spec/%/ spec/%_spec.rb: programs exts PHONY
+$(RUNRUBY) -r./$(arch)-fake $(srcdir)/spec/mspec/bin/mspec-run -B $(srcdir)/spec/default.mspec $(SPECOPTS) $(patsubst %,$(srcdir)/%,$@)
ruby.pc: $(filter-out ruby.pc,$(ruby_pc))
-
-matz: up
- $(eval MINOR := $(shell expr $(MINOR) + 1))
- $(eval message := Development of $(MAJOR).$(MINOR).0 started.)
- $(eval files := include/ruby/version.h include/ruby/internal/abi.h)
- sed -i~ \
- -e "s/^\(#define RUBY_API_VERSION_MINOR\) .*/\1 $(MINOR)/" \
- -e "s/^\(#define RUBY_ABI_VERSION\) .*/\1 0/" \
- $(files:%=$(srcdir)/%)
- $(GIT) -C $(srcdir) commit -m "$(message)" $(files)
-
-tags:
- $(MAKE) GIT="$(GIT)" -C "$(srcdir)" -f defs/tags.mk
-
-
-# ripper_srcs makes all sources at once. invoking this target multiple
-# times in parallel means all sources will be built for the number of
-# sources times respectively.
-ifneq ($(DOT_WAIT),)
-.NOTPARALLEL: ripper_srcs
-else
-ripper_src =
-$(foreach r,$(RIPPER_SRCS),$(eval $(value r): | $(value ripper_src))\
- $(eval ripper_src := $(value r)))
-ripper_srcs: $(ripper_src)
-endif
diff --git a/defs/id.def b/defs/id.def
index 2ddde7be70..ebf00506ea 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -2,7 +2,6 @@
firstline, predefined = __LINE__+1, %[\
max
min
- hash
freeze
nil?
inspect
@@ -26,6 +25,7 @@ firstline, predefined = __LINE__+1, %[\
lambda
send
__send__
+ __attached__
__recursive_key__
initialize
initialize_copy
diff --git a/defs/tags.mk b/defs/tags.mk
deleted file mode 100644
index d29260c294..0000000000
--- a/defs/tags.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- mode: makefile-gmake; indent-tabs-mode: t -*-
-
-SRCS := $(shell $(GIT) ls-files \
- *.[chy] *.def *.inc *.rb \
- ccan/ coroutine/ include/ internal/ missing/ \
- 'enc/**/*.[ch]' 'win32/**/*.[ch]' \
- )
-
-TAGS: $(SRCS)
- @echo updating $@
- @tmp=$$(mktemp); \
- trap 'rm -f "$$tmp"' 0; \
- { \
- $(GIT) grep -h --no-line-number -o '^ *# *define *RBIMPL_ATTR_[A-Z_]*(*' -- include | \
- sed 's/^ *# *define *//;/_H$$/d;y/(/+/' | sort -u && \
- echo 'NORETURN+'; \
- } > "$$tmp" && \
- ctags -e -I@"$$tmp" -h .def.inc --langmap=c:+.y.def.inc $(^)
diff --git a/defs/universal.mk b/defs/universal.mk
new file mode 100644
index 0000000000..c34a31b356
--- /dev/null
+++ b/defs/universal.mk
@@ -0,0 +1,5 @@
+arch_flags := $(filter -arch=%,$(subst -arch ,-arch=,$(ARCH_FLAG)))
+ifeq ($(filter 0 1,$(words $(arch_flags))),)
+override MJIT_HEADER_SUFFIX = -%
+override MJIT_HEADER_ARCH = -$(word 2,$(ARCH_FLAG))
+endif
diff --git a/dir.c b/dir.c
index 21b1acada3..3f73f83fc5 100644
--- a/dir.c
+++ b/dir.c
@@ -466,6 +466,13 @@ struct dir_data {
};
static void
+dir_mark(void *ptr)
+{
+ struct dir_data *dir = ptr;
+ rb_gc_mark(dir->path);
+}
+
+static void
dir_free(void *ptr)
{
struct dir_data *dir = ptr;
@@ -480,14 +487,10 @@ dir_memsize(const void *ptr)
return sizeof(struct dir_data);
}
-RUBY_REFERENCES_START(dir_refs)
- REF_EDGE(dir_data, path),
-RUBY_REFERENCES_END
-
static const rb_data_type_t dir_data_type = {
"dir",
- {REFS_LIST_PTR(dir_refs), dir_free, dir_memsize,},
- 0, NULL, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING
+ {dir_mark, dir_free, dir_memsize,},
+ 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE dir_close(VALUE);
@@ -588,45 +591,6 @@ dir_s_close(rb_execution_context_t *ec, VALUE klass, VALUE dir)
return dir_close(dir);
}
-# if defined(HAVE_FDOPENDIR) && defined(HAVE_DIRFD)
-/*
- * call-seq:
- * Dir.for_fd(fd) -> dir
- *
- * Returns a new \Dir object representing the directory specified by the given
- * integer directory file descriptor +fd+:
- *
- * d0 = Dir.new('..')
- * d1 = Dir.for_fd(d0.fileno)
- *
- * Note that the returned +d1+ does not have an associated path:
- *
- * d0.path # => '..'
- * d1.path # => nil
- *
- * This method uses the
- * {fdopendir()}[https://www.man7.org/linux/man-pages/man3/fdopendir.3p.html]
- * function defined by POSIX 2008;
- * the method is not implemented on non-POSIX platforms (raises NotImplementedError).
- */
-static VALUE
-dir_s_for_fd(VALUE klass, VALUE fd)
-{
- struct dir_data *dp;
- VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);
-
- if (!(dp->dir = fdopendir(NUM2INT(fd)))) {
- rb_sys_fail("fdopendir");
- UNREACHABLE_RETURN(Qnil);
- }
-
- RB_OBJ_WRITE(dir, &dp->path, Qnil);
- return dir;
-}
-#else
-#define dir_s_for_fd rb_f_notimplement
-#endif
-
NORETURN(static void dir_closed(void));
static void
@@ -654,13 +618,10 @@ dir_check(VALUE dir)
/*
- * call-seq:
- * inspect -> string
- *
- * Returns a string description of +self+:
- *
- * Dir.new('example').inspect # => "#<Dir:example>"
+ * call-seq:
+ * dir.inspect -> string
*
+ * Return a string describing this Dir object.
*/
static VALUE
dir_inspect(VALUE dir)
@@ -694,18 +655,18 @@ dir_inspect(VALUE dir)
#ifdef HAVE_DIRFD
/*
- * call-seq:
- * fileno -> integer
+ * call-seq:
+ * dir.fileno -> integer
+ *
+ * Returns the file descriptor used in <em>dir</em>.
*
- * Returns the file descriptor used in <em>dir</em>.
+ * d = Dir.new("..")
+ * d.fileno #=> 8
*
- * d = Dir.new('..')
- * d.fileno # => 8
+ * This method uses dirfd() function defined by POSIX 2008.
+ * NotImplementedError is raised on other platforms, such as Windows,
+ * which doesn't provide the function.
*
- * This method uses the
- * {dirfd()}[https://www.man7.org/linux/man-pages/man3/dirfd.3.html]
- * function defined by POSIX 2008;
- * the method is not implemented on non-POSIX platforms (raises NotImplementedError).
*/
static VALUE
dir_fileno(VALUE dir)
@@ -724,14 +685,14 @@ dir_fileno(VALUE dir)
#endif
/*
- * call-seq:
- * path -> string or nil
- *
- * Returns the +dirpath+ string that was used to create +self+
- * (or +nil+ if created by method Dir.for_fd):
+ * call-seq:
+ * dir.path -> string or nil
+ * dir.to_path -> string or nil
*
- * Dir.new('example').path # => "example"
+ * Returns the path parameter passed to <em>dir</em>'s constructor.
*
+ * d = Dir.new("..")
+ * d.path #=> ".."
*/
static VALUE
dir_path(VALUE dir)
@@ -785,18 +746,16 @@ to_be_skipped(const struct dirent *dp)
}
/*
- * call-seq:
- * read -> string or nil
- *
- * Reads and returns the next entry name from +self+;
- * returns +nil+ if at end-of-stream;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
+ * call-seq:
+ * dir.read -> string or nil
*
- * dir = Dir.new('example')
- * dir.read # => "."
- * dir.read # => ".."
- * dir.read # => "config.h"
+ * Reads the next entry from <em>dir</em> and returns it as a string.
+ * Returns <code>nil</code> at the end of the stream.
*
+ * d = Dir.new("testdir")
+ * d.read #=> "."
+ * d.read #=> ".."
+ * d.read #=> "config.h"
*/
static VALUE
dir_read(VALUE dir)
@@ -805,7 +764,7 @@ dir_read(VALUE dir)
struct dirent *dp;
GetDIR(dir, dirp);
- rb_errno_set(0);
+ errno = 0;
if ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
}
@@ -825,23 +784,24 @@ dir_yield(VALUE arg, VALUE path)
}
/*
- * call-seq:
- * each {|entry_name| ... } -> self
+ * call-seq:
+ * dir.each { |filename| block } -> dir
+ * dir.each -> an_enumerator
*
- * Calls the block with each entry name in +self+:
+ * Calls the block once for each entry in this directory, passing the
+ * filename of each entry as a parameter to the block.
*
- * Dir.new('example').each {|entry_name| p entry_name }
+ * If no block is given, an enumerator is returned instead.
*
- * Output:
-
- * "."
- * ".."
- * "config.h"
- * "lib"
- * "main.rb"
+ * d = Dir.new("testdir")
+ * d.each {|x| puts "Got #{x}" }
*
- * With no block given, returns an Enumerator.
+ * <em>produces:</em>
*
+ * Got .
+ * Got ..
+ * Got config.h
+ * Got main.rb
*/
static VALUE
dir_each(VALUE dir)
@@ -884,17 +844,16 @@ dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_o
#ifdef HAVE_TELLDIR
/*
- * call-seq:
- * tell -> integer
- *
- * Returns the current position of +self+;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
+ * call-seq:
+ * dir.pos -> integer
+ * dir.tell -> integer
*
- * dir = Dir.new('example')
- * dir.tell # => 0
- * dir.read # => "."
- * dir.tell # => 1
+ * Returns the current position in <em>dir</em>. See also Dir#seek.
*
+ * d = Dir.new("testdir")
+ * d.tell #=> 0
+ * d.read #=> "."
+ * d.tell #=> 12
*/
static VALUE
dir_tell(VALUE dir)
@@ -912,24 +871,18 @@ dir_tell(VALUE dir)
#ifdef HAVE_SEEKDIR
/*
- * call-seq:
- * seek(position) -> self
- *
- * Sets the position in +self+ and returns +self+.
- * The value of +position+ should have been returned from an earlier call to #tell;
- * if not, the return values from subsequent calls to #read are unspecified.
- *
- * See {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like].
- *
- * Examples:
- *
- * dir = Dir.new('example')
- * dir.pos # => 0
- * dir.seek(3) # => #<Dir:example>
- * dir.pos # => 3
- * dir.seek(30) # => #<Dir:example>
- * dir.pos # => 5
- *
+ * call-seq:
+ * dir.seek( integer ) -> dir
+ *
+ * Seeks to a particular location in <em>dir</em>. <i>integer</i>
+ * must be a value returned by Dir#tell.
+ *
+ * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
+ * d.read #=> "."
+ * i = d.tell #=> 12
+ * d.read #=> ".."
+ * d.seek(i) #=> #<Dir:0x401b3c40>
+ * d.read #=> ".."
*/
static VALUE
dir_seek(VALUE dir, VALUE pos)
@@ -947,24 +900,17 @@ dir_seek(VALUE dir, VALUE pos)
#ifdef HAVE_SEEKDIR
/*
- * call-seq:
- * pos = position -> integer
- *
- * Sets the position in +self+ and returns +position+.
- * The value of +position+ should have been returned from an earlier call to #tell;
- * if not, the return values from subsequent calls to #read are unspecified.
+ * call-seq:
+ * dir.pos = integer -> integer
*
- * See {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like].
- *
- * Examples:
- *
- * dir = Dir.new('example')
- * dir.pos # => 0
- * dir.pos = 3 # => 3
- * dir.pos # => 3
- * dir.pos = 30 # => 30
- * dir.pos # => 5
+ * Synonym for Dir#seek, but returns the position parameter.
*
+ * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
+ * d.read #=> "."
+ * i = d.pos #=> 12
+ * d.read #=> ".."
+ * d.pos = i #=> 12
+ * d.read #=> ".."
*/
static VALUE
dir_set_pos(VALUE dir, VALUE pos)
@@ -977,19 +923,15 @@ dir_set_pos(VALUE dir, VALUE pos)
#endif
/*
- * call-seq:
- * rewind -> self
+ * call-seq:
+ * dir.rewind -> dir
*
- * Sets the position in +self+ to zero;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
- *
- * dir = Dir.new('example')
- * dir.read # => "."
- * dir.read # => ".."
- * dir.pos # => 2
- * dir.rewind # => #<Dir:example>
- * dir.pos # => 0
+ * Repositions <em>dir</em> to the first entry.
*
+ * d = Dir.new("testdir")
+ * d.read #=> "."
+ * d.rewind #=> #<Dir:0x401b3fb0>
+ * d.read #=> "."
*/
static VALUE
dir_rewind(VALUE dir)
@@ -1002,18 +944,14 @@ dir_rewind(VALUE dir)
}
/*
- * call-seq:
- * close -> nil
- *
- * Closes the stream in +self+, if it is open, and returns +nil+;
- * ignored if +self+ is already closed:
+ * call-seq:
+ * dir.close -> nil
*
- * dir = Dir.new('example')
- * dir.read # => "."
- * dir.close # => nil
- * dir.close # => nil
- * dir.read # Raises IOError.
+ * Closes the directory stream.
+ * Calling this method on closed Dir object is ignored since Ruby 2.3.
*
+ * d = Dir.new("testdir")
+ * d.close #=> nil
*/
static VALUE
dir_close(VALUE dir)
@@ -1037,7 +975,7 @@ nogvl_chdir(void *ptr)
}
static void
-dir_chdir0(VALUE path)
+dir_chdir(VALUE path)
{
if (chdir(RSTRING_PTR(path)) < 0)
rb_sys_fail_path(path);
@@ -1055,7 +993,7 @@ static VALUE
chdir_yield(VALUE v)
{
struct chdir_data *args = (void *)v;
- dir_chdir0(args->new_path);
+ dir_chdir(args->new_path);
args->done = TRUE;
chdir_blocking++;
if (NIL_P(chdir_thread))
@@ -1071,73 +1009,50 @@ chdir_restore(VALUE v)
chdir_blocking--;
if (chdir_blocking == 0)
chdir_thread = Qnil;
- dir_chdir0(args->old_path);
+ dir_chdir(args->old_path);
}
return Qnil;
}
/*
- * call-seq:
- * Dir.chdir(new_dirpath) -> 0
- * Dir.chdir -> 0
- * Dir.chdir(new_dirpath) {|new_dirpath| ... } -> object
- * Dir.chdir {|cur_dirpath| ... } -> object
- *
- * Changes the current working directory.
- *
- * With argument +new_dirpath+ and no block,
- * changes to the given +dirpath+:
- *
- * Dir.pwd # => "/example"
- * Dir.chdir('..') # => 0
- * Dir.pwd # => "/"
- *
- * With no argument and no block:
- *
- * - Changes to the value of environment variable +HOME+ if defined.
- * - Otherwise changes to the value of environment variable +LOGDIR+ if defined.
- * - Otherwise makes no change.
- *
- * With argument +new_dirpath+ and a block, temporarily changes the working directory:
- *
- * - Calls the block with the argument.
- * - Changes to the given directory.
- * - Executes the block
- * - Restores the previous working directory.
- * - Returns the block's return value.
- *
- * Example:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * Dir.chdir('/tmp') do
- * Dir.pwd # => "/tmp"
- * end
- * Dir.pwd # => "/var/spool/mail"
- *
- * With no argument and a block,
- * calls the block with the current working directory (string)
- * and returns the block's return value.
- *
- * Calls to \Dir.chdir with blocks may be nested:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * Dir.chdir('/tmp') do
- * Dir.pwd # => "/tmp"
- * Dir.chdir('/usr') do
- * Dir.pwd # => "/usr"
+ * call-seq:
+ * Dir.chdir( [ string] ) -> 0
+ * Dir.chdir( [ string] ) {| path | block } -> anObject
+ *
+ * Changes the current working directory of the process to the given
+ * string. When called without an argument, changes the directory to
+ * the value of the environment variable <code>HOME</code>, or
+ * <code>LOGDIR</code>. SystemCallError (probably Errno::ENOENT) if
+ * the target directory does not exist.
+ *
+ * If a block is given, it is passed the name of the new current
+ * directory, and the block is executed with that as the current
+ * directory. The original working directory is restored when the block
+ * exits. The return value of <code>chdir</code> is the value of the
+ * block. <code>chdir</code> blocks can be nested, but in a
+ * multi-threaded program an error will be raised if a thread attempts
+ * to open a <code>chdir</code> block while another thread has one
+ * open or a call to <code>chdir</code> without a block occurs inside
+ * a block passed to <code>chdir</code> (even in the same thread).
+ *
+ * Dir.chdir("/var/spool/mail")
+ * puts Dir.pwd
+ * Dir.chdir("/tmp") do
+ * puts Dir.pwd
+ * Dir.chdir("/usr") do
+ * puts Dir.pwd
+ * end
+ * puts Dir.pwd
* end
- * Dir.pwd # => "/tmp"
- * end
- * Dir.pwd # => "/var/spool/mail"
+ * puts Dir.pwd
*
- * In a multi-threaded program an error is raised if a thread attempts
- * to open a +chdir+ block while another thread has one open,
- * or a call to +chdir+ without a block occurs inside
- * a block passed to +chdir+ (even in the same thread).
+ * <em>produces:</em>
*
- * Raises an exception if the target directory does not exist.
+ * /var/spool/mail
+ * /tmp
+ * /usr
+ * /tmp
+ * /var/spool/mail
*/
static VALUE
dir_s_chdir(int argc, VALUE *argv, VALUE obj)
@@ -1182,164 +1097,6 @@ dir_s_chdir(int argc, VALUE *argv, VALUE obj)
return INT2FIX(0);
}
-#if defined(HAVE_FCHDIR) && defined(HAVE_DIRFD) && HAVE_FCHDIR && HAVE_DIRFD
-static void *
-nogvl_fchdir(void *ptr)
-{
- const int *fd = ptr;
-
- return (void *)(VALUE)fchdir(*fd);
-}
-
-static void
-dir_fchdir(int fd)
-{
- if (fchdir(fd) < 0)
- rb_sys_fail("fchdir");
-}
-
-struct fchdir_data {
- VALUE old_dir;
- int fd;
- int done;
-};
-
-static VALUE
-fchdir_yield(VALUE v)
-{
- struct fchdir_data *args = (void *)v;
- dir_fchdir(args->fd);
- args->done = TRUE;
- chdir_blocking++;
- if (NIL_P(chdir_thread))
- chdir_thread = rb_thread_current();
- return rb_yield_values(0);
-}
-
-static VALUE
-fchdir_restore(VALUE v)
-{
- struct fchdir_data *args = (void *)v;
- if (args->done) {
- chdir_blocking--;
- if (chdir_blocking == 0)
- chdir_thread = Qnil;
- dir_fchdir(RB_NUM2INT(dir_fileno(args->old_dir)));
- }
- dir_close(args->old_dir);
- return Qnil;
-}
-
-/*
- * call-seq:
- * Dir.fchdir(fd) -> 0
- * Dir.fchdir(fd) { ... } -> object
- *
- * Changes the current working directory to the directory
- * specified by the integer file descriptor +fd+.
- *
- * When passing a file descriptor over a UNIX socket or to a child process,
- * using +fchdir+ instead of +chdir+ avoids the
- * {time-of-check to time-of-use vulnerability}[https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use]
- *
- * With no block, changes to the directory given by +fd+:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * dir = Dir.new('/usr')
- * fd = dir.fileno
- * Dir.fchdir(fd) do
- * Dir.pwd # => "/usr"
- * end
- * Dir.pwd # => "/var/spool/mail"
- *
- * With a block, temporarily changes the working directory:
- *
- * - Calls the block with the argument.
- * - Changes to the given directory.
- * - Executes the block
- * - Restores the previous working directory.
- * - Returns the block's return value.
- *
- * Example:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * Dir.chdir('/tmp') do
- * Dir.pwd # => "/tmp"
- * end
- * Dir.pwd # => "/var/spool/mail"
- *
- * This method uses the
- * {fchdir()}[https://www.man7.org/linux/man-pages/man3/fchdir.3p.html]
- * function defined by POSIX 2008;
- * the method is not implemented on non-POSIX platforms (raises NotImplementedError).
- *
- * Raises an exception if the file descriptor is not valid.
- *
- * In a multi-threaded program an error is raised if a thread attempts
- * to open a +chdir+ block while another thread has one open,
- * or a call to +chdir+ without a block occurs inside
- * a block passed to +chdir+ (even in the same thread).
- */
-static VALUE
-dir_s_fchdir(VALUE klass, VALUE fd_value)
-{
- int fd = RB_NUM2INT(fd_value);
-
- if (chdir_blocking > 0) {
- if (rb_thread_current() != chdir_thread)
- rb_raise(rb_eRuntimeError, "conflicting chdir during another chdir block");
- if (!rb_block_given_p())
- rb_warn("conflicting chdir during another chdir block");
- }
-
- if (rb_block_given_p()) {
- struct fchdir_data args;
- args.old_dir = dir_s_alloc(klass);
- dir_initialize(NULL, args.old_dir, rb_fstring_cstr("."), Qnil);
- args.fd = fd;
- args.done = FALSE;
- return rb_ensure(fchdir_yield, (VALUE)&args, fchdir_restore, (VALUE)&args);
- }
- else {
- int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_fchdir, &fd,
- RUBY_UBF_IO, 0);
- if (r < 0)
- rb_sys_fail("fchdir");
- }
-
- return INT2FIX(0);
-}
-#else
-#define dir_s_fchdir rb_f_notimplement
-#endif
-
-/*
- * call-seq:
- * chdir -> nil
- *
- * Changes the current working directory to the path of +self+:
- *
- * Dir.pwd # => "/"
- * dir = Dir.new('example')
- * dir.chdir
- * dir.pwd # => "/example"
- *
- */
-static VALUE
-dir_chdir(VALUE dir)
-{
-#if defined(HAVE_FCHDIR) && defined(HAVE_DIRFD) && HAVE_FCHDIR && HAVE_DIRFD
- dir_s_fchdir(rb_cDir, dir_fileno(dir));
-#else
- VALUE path = dir_get(dir)->path;
- dir_s_chdir(1, &path, rb_cDir);
-#endif
-
- return Qnil;
-}
-
#ifndef _WIN32
VALUE
rb_dir_getwd_ospath(void)
@@ -1386,14 +1143,16 @@ rb_dir_getwd(void)
}
/*
- * call-seq:
- * Dir.pwd -> string
+ * call-seq:
+ * Dir.getwd -> string
+ * Dir.pwd -> string
*
- * Returns the path to the current working directory:
- *
- * Dir.chdir("/tmp") # => 0
- * Dir.pwd # => "/tmp"
+ * Returns the path to the current working directory of this process as
+ * a string.
*
+ * Dir.chdir("/tmp") #=> 0
+ * Dir.getwd #=> "/tmp"
+ * Dir.pwd #=> "/tmp"
*/
static VALUE
dir_s_getwd(VALUE dir)
@@ -1423,16 +1182,13 @@ check_dirname(VALUE dir)
#if defined(HAVE_CHROOT)
/*
- * call-seq:
- * Dir.chroot(dirpath) -> 0
- *
- * Changes the root directory of the calling process to that specified in +dirpath+.
- * The new root directory is used for pathnames beginning with <tt>'/'</tt>.
- * The root directory is inherited by all children of the calling process.
+ * call-seq:
+ * Dir.chroot( string ) -> 0
*
- * Only a privileged process may call +chroot+.
- *
- * See {Linux chroot}[https://man7.org/linux/man-pages/man2/chroot.2.html].
+ * Changes this process's idea of the file system root. Only a
+ * privileged process may make this call. Not available on all
+ * platforms. On Unix systems, see <code>chroot(2)</code> for more
+ * information.
*/
static VALUE
dir_s_chroot(VALUE dir, VALUE path)
@@ -1461,20 +1217,18 @@ nogvl_mkdir(void *ptr)
}
/*
- * call-seq:
- * Dir.mkdir(dirpath, permissions = 0775) -> 0
+ * call-seq:
+ * Dir.mkdir( string [, integer] ) -> 0
*
- * Creates a directory in the underlying file system
- * at +dirpath+ with the given +permissions+;
- * returns zero:
+ * Makes a new directory named by <i>string</i>, with permissions
+ * specified by the optional parameter <i>anInteger</i>. The
+ * permissions may be modified by the value of File::umask, and are
+ * ignored on NT. Raises a SystemCallError if the directory cannot be
+ * created. See also the discussion of permissions in the class
+ * documentation for File.
*
- * Dir.mkdir('foo')
- * File.stat(Dir.new('foo')).mode.to_s(8)[1..4] # => "0755"
- * Dir.mkdir('bar', 0644)
- * File.stat(Dir.new('bar')).mode.to_s(8)[1..4] # => "0644"
+ * Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
*
- * See {File Permissions}[rdoc-ref:File@File+Permissions].
- * Note that argument +permissions+ is ignored on Windows.
*/
static VALUE
dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
@@ -1508,14 +1262,13 @@ nogvl_rmdir(void *ptr)
}
/*
- * call-seq:
- * Dir.rmdir(dirpath) -> 0
- *
- * Removes the directory at +dirpath+ from the underlying file system:
- *
- * Dir.rmdir('foo') # => 0
+ * call-seq:
+ * Dir.delete( string ) -> 0
+ * Dir.rmdir( string ) -> 0
+ * Dir.unlink( string ) -> 0
*
- * Raises an exception if the directory is not empty.
+ * Deletes the named directory. Raises a subclass of SystemCallError
+ * if the directory isn't empty.
*/
static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
@@ -1723,7 +1476,7 @@ nogvl_opendir_at(void *ptr)
/* fallthrough*/
case 0:
if (fd >= 0) close(fd);
- rb_errno_set(e);
+ errno = e;
}
}
#else /* !USE_OPENDIR_AT */
@@ -3240,35 +2993,26 @@ dir_open_dir(int argc, VALUE *argv)
/*
- * call-seq:
- * Dir.foreach(dirpath, encoding: 'UTF-8') {|entry_name| ... } -> nil
- *
- * Calls the block with each entry name in the directory at +dirpath+;
- * sets the given encoding onto each passed +entry_name+:
+ * call-seq:
+ * Dir.foreach( dirname ) {| filename | block } -> nil
+ * Dir.foreach( dirname, encoding: enc ) {| filename | block } -> nil
+ * Dir.foreach( dirname ) -> an_enumerator
+ * Dir.foreach( dirname, encoding: enc ) -> an_enumerator
*
- * Dir.foreach('/example') {|entry_name| p entry_name }
+ * Calls the block once for each entry in the named directory, passing
+ * the filename of each entry as a parameter to the block.
*
- * Output:
+ * If no block is given, an enumerator is returned instead.
*
- * "config.h"
- * "lib"
- * "main.rb"
- * ".."
- * "."
+ * Dir.foreach("testdir") {|x| puts "Got #{x}" }
*
- * Encoding:
+ * <em>produces:</em>
*
- * Dir.foreach('/example') {|entry_name| p entry_name.encoding; break }
- * Dir.foreach('/example', encoding: 'US-ASCII') {|entry_name| p entry_name.encoding; break }
+ * Got .
+ * Got ..
+ * Got config.h
+ * Got main.rb
*
- * Output:
- *
- * #<Encoding:UTF-8>
- * #<Encoding:US-ASCII>
- *
- * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
- *
- * Returns an enumerator if no block is given.
*/
static VALUE
dir_foreach(int argc, VALUE *argv, VALUE io)
@@ -3290,21 +3034,19 @@ dir_collect(VALUE dir)
}
/*
- * call-seq:
- * Dir.entries(dirname, encoding: 'UTF-8') -> array
+ * call-seq:
+ * Dir.entries( dirname ) -> array
+ * Dir.entries( dirname, encoding: enc ) -> array
*
- * Returns an array of the entry names in the directory at +dirpath+;
- * sets the given encoding onto each returned entry name:
+ * Returns an array containing all of the filenames in the given
+ * directory. Will raise a SystemCallError if the named directory
+ * doesn't exist.
*
- * Dir.entries('/example') # => ["config.h", "lib", "main.rb", "..", "."]
- * Dir.entries('/example').first.encoding
- * # => #<Encoding:UTF-8>
- * Dir.entries('/example', encoding: 'US-ASCII').first.encoding
- * # => #<Encoding:US-ASCII>
+ * The optional <i>encoding</i> keyword argument specifies the encoding of the
+ * directory. If not specified, the filesystem encoding is used.
*
- * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
+ * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"]
*
- * Raises an exception if the directory does not exist.
*/
static VALUE
dir_entries(int argc, VALUE *argv, VALUE io)
@@ -3322,12 +3064,25 @@ dir_each_child(VALUE dir)
}
/*
- * call-seq:
- * Dir.each_child(dirpath) {|entry_name| ... } -> nil
- * Dir.each_child(dirpath, encoding: 'UTF-8') {|entry_name| ... } -> nil
+ * call-seq:
+ * Dir.each_child( dirname ) {| filename | block } -> nil
+ * Dir.each_child( dirname, encoding: enc ) {| filename | block } -> nil
+ * Dir.each_child( dirname ) -> an_enumerator
+ * Dir.each_child( dirname, encoding: enc ) -> an_enumerator
+ *
+ * Calls the block once for each entry except for "." and ".." in the
+ * named directory, passing the filename of each entry as a parameter
+ * to the block.
+ *
+ * If no block is given, an enumerator is returned instead.
+ *
+ * Dir.each_child("testdir") {|x| puts "Got #{x}" }
+ *
+ * <em>produces:</em>
+ *
+ * Got config.h
+ * Got main.rb
*
- * Like Dir.foreach, except that entries <tt>'.'</tt> and <tt>'..'</tt>
- * are not included.
*/
static VALUE
dir_s_each_child(int argc, VALUE *argv, VALUE io)
@@ -3341,22 +3096,24 @@ dir_s_each_child(int argc, VALUE *argv, VALUE io)
}
/*
- * call-seq:
- * each_child {|entry_name| ... } -> self
+ * call-seq:
+ * dir.each_child {| filename | block } -> dir
+ * dir.each_child -> an_enumerator
*
- * Calls the block with each entry name in +self+
- * except <tt>'.'</tt> and <tt>'..'</tt>:
+ * Calls the block once for each entry except for "." and ".." in
+ * this directory, passing the filename of each entry as a parameter
+ * to the block.
*
- * dir = Dir.new('/example')
- * dir.each_child {|entry_name| p entry_name }
+ * If no block is given, an enumerator is returned instead.
*
- * Output:
+ * d = Dir.new("testdir")
+ * d.each_child {|x| puts "Got #{x}" }
*
- * "config.h"
- * "lib"
- * "main.rb"
+ * <em>produces:</em>
+ *
+ * Got config.h
+ * Got main.rb
*
- * If no block is given, returns an enumerator.
*/
static VALUE
dir_each_child_m(VALUE dir)
@@ -3366,14 +3123,14 @@ dir_each_child_m(VALUE dir)
}
/*
- * call-seq:
- * children -> array
+ * call-seq:
+ * dir.children -> array
*
- * Returns an array of the entry names in +self+
- * except for <tt>'.'</tt> and <tt>'..'</tt>:
+ * Returns an array containing all of the filenames except for "."
+ * and ".." in this directory.
*
- * dir = Dir.new('/example')
- * dir.children # => ["config.h", "lib", "main.rb"]
+ * d = Dir.new("testdir")
+ * d.children #=> ["config.h", "main.rb"]
*
*/
static VALUE
@@ -3385,23 +3142,19 @@ dir_collect_children(VALUE dir)
}
/*
- * call-seq:
- * Dir.children(dirpath) -> array
- * Dir.children(dirpath, encoding: 'UTF-8') -> array
+ * call-seq:
+ * Dir.children( dirname ) -> array
+ * Dir.children( dirname, encoding: enc ) -> array
*
- * Returns an array of the entry names in the directory at +dirpath+
- * except for <tt>'.'</tt> and <tt>'..'</tt>;
- * sets the given encoding onto each returned entry name:
+ * Returns an array containing all of the filenames except for "."
+ * and ".." in the given directory. Will raise a SystemCallError if
+ * the named directory doesn't exist.
*
- * Dir.children('/example') # => ["config.h", "lib", "main.rb"]
- * Dir.children('/example').first.encoding
- * # => #<Encoding:UTF-8>
- * Dir.children('/example', encoding: 'US-ASCII').first.encoding
- * # => #<Encoding:US-ASCII>
+ * The optional <i>encoding</i> keyword argument specifies the encoding of the
+ * directory. If not specified, the filesystem encoding is used.
*
- * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
+ * Dir.children("testdir") #=> ["config.h", "main.rb"]
*
- * Raises an exception if the directory does not exist.
*/
static VALUE
dir_s_children(int argc, VALUE *argv, VALUE io)
@@ -3475,13 +3228,12 @@ file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
}
/*
- * call-seq:
- * Dir.home(user_name = nil) -> dirpath
- *
- * Dir.home # => "/home/me"
- * Dir.home('root') # => "/root"
+ * call-seq:
+ * Dir.home() -> "/home/me"
+ * Dir.home("root") -> "/root"
*
- * Raises ArgumentError if +user_name+ is not a user name.
+ * Returns the home directory of the current user or the named user
+ * if given.
*/
static VALUE
dir_s_home(int argc, VALUE *argv, VALUE obj)
@@ -3506,14 +3258,10 @@ dir_s_home(int argc, VALUE *argv, VALUE obj)
#if 0
/*
* call-seq:
- * Dir.exist?(dirpath) -> true or false
- *
- * Returns whether +dirpath+ is a directory in the underlying file system:
- *
- * Dir.exist?('/example') # => true
- * Dir.exist?('/nosuch') # => false
- * Dir.exist?('/example/main.rb') # => false
+ * Dir.exist?(file_name) -> true or false
*
+ * Returns <code>true</code> if the named file is a directory,
+ * <code>false</code> otherwise.
*
*/
VALUE
@@ -3540,7 +3288,8 @@ nogvl_dir_empty_p(void *ptr)
/* fall through */
case 0:
if (e == ENOTDIR) return (void *)Qfalse;
- return (void *)INT2FIX(e);
+ errno = e; /* for rb_sys_fail_path */
+ return (void *)Qundef;
}
}
while ((dp = READDIR(dir, NULL)) != NULL) {
@@ -3555,18 +3304,10 @@ nogvl_dir_empty_p(void *ptr)
/*
* call-seq:
- * Dir.empty?(dirpath) -> true or false
- *
- * Returns whether +dirpath+ specifies an empty directory:
+ * Dir.empty?(path_name) -> true or false
*
- * dirpath = '/tmp/foo'
- * Dir.mkdir(dirpath)
- * Dir.empty?(dirpath) # => true
- * Dir.empty?('/example') # => false
- * Dir.empty?('/example/main.rb') # => false
- *
- * Raises an exception if +dirpath+ does not specify a directory or file
- * in the underlying file system.
+ * Returns <code>true</code> if the named file is an empty directory,
+ * <code>false</code> if it is not a directory or non-empty.
*/
static VALUE
rb_dir_s_empty_p(VALUE obj, VALUE dirname)
@@ -3602,8 +3343,8 @@ rb_dir_s_empty_p(VALUE obj, VALUE dirname)
result = (VALUE)rb_thread_call_without_gvl(nogvl_dir_empty_p, (void *)path,
RUBY_UBF_IO, 0);
- if (FIXNUM_P(result)) {
- rb_syserr_fail_path((int)FIX2LONG(result), orig);
+ if (UNDEF_P(result)) {
+ rb_sys_fail_path(orig);
}
return result;
}
@@ -3616,7 +3357,6 @@ Init_Dir(void)
rb_include_module(rb_cDir, rb_mEnumerable);
rb_define_alloc_func(rb_cDir, dir_s_alloc);
- rb_define_singleton_method(rb_cDir,"for_fd", dir_s_for_fd, 1);
rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
rb_define_singleton_method(rb_cDir, "each_child", dir_s_each_child, -1);
@@ -3636,9 +3376,7 @@ Init_Dir(void)
rb_define_method(rb_cDir,"pos", dir_tell, 0);
rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
rb_define_method(rb_cDir,"close", dir_close, 0);
- rb_define_method(rb_cDir,"chdir", dir_chdir, 0);
- rb_define_singleton_method(rb_cDir,"fchdir", dir_s_fchdir, 1);
rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
@@ -3654,12 +3392,52 @@ Init_Dir(void)
rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
+
+ /* Document-const: File::Constants::FNM_NOESCAPE
+ *
+ * Disables escapes in File.fnmatch and Dir.glob patterns
+ */
rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
+
+ /* Document-const: File::Constants::FNM_PATHNAME
+ *
+ * Wildcards in File.fnmatch and Dir.glob patterns do not match directory
+ * separators
+ */
rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
+
+ /* Document-const: File::Constants::FNM_DOTMATCH
+ *
+ * The '*' wildcard matches filenames starting with "." in File.fnmatch
+ * and Dir.glob patterns
+ */
rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
+
+ /* Document-const: File::Constants::FNM_CASEFOLD
+ *
+ * Makes File.fnmatch patterns case insensitive (but not Dir.glob
+ * patterns).
+ */
rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
+
+ /* Document-const: File::Constants::FNM_EXTGLOB
+ *
+ * Allows file globbing through "{a,b}" in File.fnmatch patterns.
+ */
rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB));
+
+ /* Document-const: File::Constants::FNM_SYSCASE
+ *
+ * System default case insensitiveness, equals to FNM_CASEFOLD or
+ * 0.
+ */
rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
+
+ /* Document-const: File::Constants::FNM_SHORTNAME
+ *
+ * Makes patterns to match short names if existing. Valid only
+ * on Microsoft Windows.
+ */
rb_file_const("FNM_SHORTNAME", INT2FIX(FNM_SHORTNAME));
}
diff --git a/dir.rb b/dir.rb
index 7de62da921..2e426b0881 100644
--- a/dir.rb
+++ b/dir.rb
@@ -1,85 +1,11 @@
-# An object of class \Dir represents a directory in the underlying file system.
+# Objects of class Dir are directory streams representing
+# directories in the underlying file system. They provide a variety
+# of ways to list directories and their contents. See also File.
#
-# It consists mainly of:
-#
-# - A string _path_, given when the object is created,
-# that specifies a directory in the underlying file system;
-# method #path returns the path.
-# - A collection of string <i>entry names</i>,
-# each of which is the name of a directory or file in the underlying file system;
-# the entry names may be retrieved
-# in an {array-like fashion}[rdoc-ref:Dir@Dir+As+Array-Like]
-# or in a {stream-like fashion}[rdoc-ref:Dir@Dir+As+Stream-Like].
-#
-# == About the Examples
-#
-# Some examples on this page use this simple file tree:
-#
-# example/
-# ├── config.h
-# ├── lib/
-# │ ├── song/
-# │ │ └── karaoke.rb
-# │ └── song.rb
-# └── main.rb
-#
-# Others use the file tree for the
-# {Ruby project itself}[https://github.com/ruby/ruby].
-#
-# == \Dir As \Array-Like
-#
-# A \Dir object is in some ways array-like:
-#
-# - It has instance methods #children, #each, and #each_child.
-# - It includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here].
-#
-# == \Dir As Stream-Like
-#
-# A \Dir object is in some ways stream-like.
-#
-# The stream is initially open for reading,
-# but may be closed manually (using method #close),
-# and will be closed on block exit if created by Dir.open called with a block.
-# The closed stream may not be further manipulated,
-# and may not be reopened.
-#
-# The stream has a _position_, which is the index of an entry in the directory:
-#
-# - The initial position is zero (before the first entry).
-# - \Method #tell (aliased as #pos) returns the position.
-# - \Method #pos= sets the position (but ignores a value outside the stream),
-# and returns the position.
-# - \Method #seek is like #pos=, but returns +self+ (convenient for chaining).
-# - \Method #read, if not at end-of-stream, reads the next entry and increments
-# the position;
-# if at end-of-stream, does not increment the position.
-# - \Method #rewind sets the position to zero.
-#
-# Examples (using the {simple file tree}[rdoc-ref:Dir@About+the+Examples]):
-#
-# dir = Dir.new('example') # => #<Dir:example>
-# dir.pos # => 0
-#
-# dir.read # => "."
-# dir.read # => ".."
-# dir.read # => "config.h"
-# dir.read # => "lib"
-# dir.read # => "main.rb"
-# dir.pos # => 5
-# dir.read # => nil
-# dir.pos # => 5
-#
-# dir.rewind # => #<Dir:example>
-# dir.pos # => 0
-#
-# dir.pos = 3 # => 3
-# dir.pos # => 3
-#
-# dir.seek(4) # => #<Dir:example>
-# dir.pos # => 4
-#
-# dir.close # => nil
-# dir.read # Raises IOError.
+# The directory used in these examples contains the two regular files
+# (<code>config.h</code> and <code>main.rb</code>), the parent
+# directory (<code>..</code>), and the directory itself
+# (<code>.</code>).
#
# == What's Here
#
@@ -154,32 +80,20 @@
# closing it upon block exit.
# - ::unlink (aliased as ::delete and ::rmdir): Removes the given directory.
# - #inspect: Returns a string description of +self+.
-#
class Dir
# call-seq:
- # Dir.open(dirpath) -> dir
- # Dir.open(dirpath, encoding: nil) -> dir
- # Dir.open(dirpath) {|dir| ... } -> object
- # Dir.open(dirpath, encoding: nil) {|dir| ... } -> object
- #
- # Creates a new \Dir object _dir_ for the directory at +dirpath+.
- #
- # With no block, the method equivalent to Dir.new(dirpath, encoding):
- #
- # Dir.open('.') # => #<Dir:.>
- #
- # With a block given, the block is called with the created _dir_;
- # on block exit _dir_ is closed and the block's value is returned:
- #
- # Dir.open('.') {|dir| dir.inspect } # => "#<Dir:.>"
- #
- # The value given with optional keyword argument +encoding+
- # specifies the encoding for the directory entry names;
- # if +nil+ (the default), the file system's encoding is used:
- #
- # Dir.open('.').read.encoding # => #<Encoding:UTF-8>
- # Dir.open('.', encoding: 'US-ASCII').read.encoding # => #<Encoding:US-ASCII>
- #
+ # Dir.open( string ) -> aDir
+ # Dir.open( string, encoding: enc ) -> aDir
+ # Dir.open( string ) {| aDir | block } -> anObject
+ # Dir.open( string, encoding: enc ) {| aDir | block } -> anObject
+ #
+ # The optional <i>encoding</i> keyword argument specifies the encoding of the directory.
+ # If not specified, the filesystem encoding is used.
+ #
+ # With no block, <code>open</code> is a synonym for Dir::new. If a
+ # block is present, it is passed <i>aDir</i> as a parameter. The
+ # directory is closed at the end of the block, and Dir::open returns
+ # the value of the block.
def self.open(name, encoding: nil, &block)
dir = Primitive.dir_s_open(name, encoding)
if block
@@ -194,219 +108,114 @@ class Dir
end
# call-seq:
- # Dir.new(dirpath) -> dir
- # Dir.new(dirpath, encoding: nil) -> dir
- #
- # Returns a new \Dir object for the directory at +dirpath+:
- #
- # Dir.new('.') # => #<Dir:.>
+ # Dir.new( string ) -> aDir
+ # Dir.new( string, encoding: enc ) -> aDir
#
- # The value given with optional keyword argument +encoding+
- # specifies the encoding for the directory entry names;
- # if +nil+ (the default), the file system's encoding is used:
- #
- # Dir.new('.').read.encoding # => #<Encoding:UTF-8>
- # Dir.new('.', encoding: 'US-ASCII').read.encoding # => #<Encoding:US-ASCII>
+ # Returns a new directory object for the named directory.
#
+ # The optional <i>encoding</i> keyword argument specifies the encoding of the directory.
+ # If not specified, the filesystem encoding is used.
def initialize(name, encoding: nil)
Primitive.dir_initialize(name, encoding)
end
# call-seq:
- # Dir[*patterns, base: nil, sort: true] -> array
- #
- # Calls Dir.glob with argument +patterns+
- # and the values of keyword arguments +base+ and +sort+;
- # returns the array of selected entry names.
+ # Dir[ string [, string ...] [, base: path] [, sort: true] ] -> array
#
+ # Equivalent to calling
+ # <code>Dir.glob([</code><i>string,...</i><code>], 0)</code>.
def self.[](*args, base: nil, sort: true)
Primitive.dir_s_aref(args, base, sort)
end
# call-seq:
- # Dir.glob(*patterns, flags: 0, base: nil, sort: true) -> array
- # Dir.glob(*patterns, flags: 0, base: nil, sort: true) {|entry_name| ... } -> nil
- #
- # Forms an array _entry_names_ of the entry names selected by the arguments.
- #
- # Argument +patterns+ is a string pattern or an array of string patterns;
- # note that these are not regexps; see below.
- #
- # Notes for the following examples:
- #
- # - <tt>'*'</tt> is the pattern that matches any entry name
- # except those that begin with <tt>'.'</tt>.
- # - We use method Array#take to shorten returned arrays
- # that otherwise would be very large.
- #
- # With no block, returns array _entry_names_;
- # example (using the {simple file tree}[rdoc-ref:Dir@About+the+Examples]):
- #
- # Dir.glob('*') # => ["config.h", "lib", "main.rb"]
- #
- # With a block, calls the block with each of the _entry_names_
- # and returns +nil+:
- #
- # Dir.glob('*') {|entry_name| puts entry_name } # => nil
+ # Dir.glob( pattern, [flags], [base: path] [, sort: true] ) -> array
+ # Dir.glob( pattern, [flags], [base: path] [, sort: true] ) { |filename| block } -> nil
#
- # Output:
+ # Expands +pattern+, which is a pattern string or an Array of pattern
+ # strings, and returns an array containing the matching filenames.
+ # If a block is given, calls the block once for each matching filename,
+ # passing the filename as a parameter to the block.
#
- # config.h
- # lib
- # main.rb
+ # The optional +base+ keyword argument specifies the base directory for
+ # interpreting relative pathnames instead of the current working directory.
+ # As the results are not prefixed with the base directory name in this
+ # case, you will need to prepend the base directory name if you want real
+ # paths.
#
- # If optional keyword argument +flags+ is given,
- # the value modifies the matching; see below.
+ # The results which matched single wildcard or character set are sorted in
+ # binary ascending order, unless +false+ is given as the optional +sort+
+ # keyword argument. The order of an Array of pattern strings and braces
+ # are preserved.
#
- # If optional keyword argument +base+ is given,
- # its value specifies the base directory.
- # Each pattern string specifies entries relative to the base directory;
- # the default is <tt>'.'</tt>.
- # The base directory is not prepended to the entry names in the result:
+ # Note that the pattern is not a regexp, it's closer to a shell glob.
+ # See File::fnmatch for the meaning of the +flags+ parameter.
+ # Case sensitivity depends on your system (+File::FNM_CASEFOLD+ is ignored).
#
- # Dir.glob(pattern, base: 'lib').take(5)
- # # => ["abbrev.gemspec", "abbrev.rb", "base64.gemspec", "base64.rb", "benchmark.gemspec"]
- # Dir.glob(pattern, base: 'lib/irb').take(5)
- # # => ["cmd", "color.rb", "color_printer.rb", "completion.rb", "context.rb"]
- #
- # If optional keyword +sort+ is given, its value specifies whether
- # the array is to be sorted; the default is +true+.
- # Passing value +false+ with that keyword disables sorting
- # (though the underlying file system may already have sorted the array).
- #
- # <b>Patterns</b>
- #
- # Each pattern string is expanded
- # according to certain metacharacters;
- # examples below use the {Ruby file tree}[rdoc-ref:Dir@About+the+Examples]:
- #
- # - <tt>'*'</tt>: Matches any substring in an entry name,
- # similar in meaning to regexp <tt>/.*/mx</tt>;
- # may be restricted by other values in the pattern strings:
- #
- # - <tt>'*'</tt> matches all entry names:
- #
- # Dir.glob('*').take(3) # => ["BSDL", "CONTRIBUTING.md", "COPYING"]
- #
- # - <tt>'c*'</tt> matches entry names beginning with <tt>'c'</tt>:
- #
- # Dir.glob('c*').take(3) # => ["CONTRIBUTING.md", "COPYING", "COPYING.ja"]
- #
- # - <tt>'*c'</tt> matches entry names ending with <tt>'c'</tt>:
- #
- # Dir.glob('*c').take(3) # => ["addr2line.c", "array.c", "ast.c"]
- #
- # - <tt>'\*c\*'</tt> matches entry names that contain <tt>'c'</tt>,
- # even at the beginning or end:
- #
- # Dir.glob('*c*').take(3) # => ["CONTRIBUTING.md", "COPYING", "COPYING.ja"]
- #
- # Does not match Unix-like hidden entry names ("dot files").
- # To include those in the matched entry names,
- # use flag IO::FNM_DOTMATCH or something like <tt>'{*,.*}'</tt>.
- #
- # - <tt>'**'</tt>: Matches entry names recursively
- # if followed by the slash character <tt>'/'</tt>:
- #
- # Dir.glob('**/').take(3) # => ["basictest/", "benchmark/", "benchmark/gc/"]
- #
- # If the string pattern contains other characters
- # or is not followed by a slash character,
- # it is equivalent to <tt>'*'</tt>.
- #
- # - <tt>'?'</tt> Matches any single character;
- # similar in meaning to regexp <tt>/./</tt>:
- #
- # Dir.glob('io.?') # => ["io.c"]
- #
- # - <tt>'[_set_]'</tt>: Matches any one character in the string _set_;
- # behaves like a {Regexp character class}[rdoc-ref:regexp.rdoc@Character+Classes],
- # including set negation (<tt>'[^a-z]'</tt>):
- #
- # Dir.glob('*.[a-z][a-z]').take(3)
- # # => ["CONTRIBUTING.md", "COPYING.ja", "KNOWNBUGS.rb"]
- #
- # - <tt>'{_abc_,_xyz_}'</tt>:
- # Matches either string _abc_ or string _xyz_;
- # behaves like {Regexp alternation}[rdoc-ref:regexp.rdoc@Alternation]:
- #
- # Dir.glob('{LEGAL,BSDL}') # => ["LEGAL", "BSDL"]
- #
- # More than two alternatives may be given.
- #
- # - <tt>\\</tt>: Escapes the following metacharacter.
- #
- # Note that on Windows, the backslash character may not be used
- # in a string pattern:
- # <tt>Dir['c:\\foo*']</tt> will not work, use <tt>Dir['c:/foo*']</tt> instead.
- #
- # More examples (using the {simple file tree}[rdoc-ref:Dir@About+the+Examples]):
- #
- # # We're in the example directory.
- # File.basename(Dir.pwd) # => "example"
- # Dir.glob('config.?') # => ["config.h"]
- # Dir.glob('*.[a-z][a-z]') # => ["main.rb"]
- # Dir.glob('*.[^r]*') # => ["config.h"]
- # Dir.glob('*.{rb,h}') # => ["main.rb", "config.h"]
- # Dir.glob('*') # => ["config.h", "lib", "main.rb"]
- # Dir.glob('*', File::FNM_DOTMATCH) # => [".", "config.h", "lib", "main.rb"]
- # Dir.glob(["*.rb", "*.h"]) # => ["main.rb", "config.h"]
- #
- # Dir.glob('**/*.rb')
- # => ["lib/song/karaoke.rb", "lib/song.rb", "main.rb"]
- #
- # Dir.glob('**/*.rb', base: 'lib') # => ["song/karaoke.rb", "song.rb"]
- #
- # Dir.glob('**/lib') # => ["lib"]
+ # <code>*</code>::
+ # Matches any file. Can be restricted by other values in the glob.
+ # Equivalent to <code>/.*/mx</code> in regexp.
#
- # Dir.glob('**/lib/**/*.rb') # => ["lib/song/karaoke.rb", "lib/song.rb"]
+ # <code>*</code>:: Matches all files
+ # <code>c*</code>:: Matches all files beginning with <code>c</code>
+ # <code>*c</code>:: Matches all files ending with <code>c</code>
+ # <code>\*c\*</code>:: Match all files that have <code>c</code> in them
+ # (including at the beginning or end).
#
- # Dir.glob('**/lib/*.rb') # => ["lib/song.rb"]
+ # Note, this will not match Unix-like hidden files (dotfiles). In order
+ # to include those in the match results, you must use the
+ # File::FNM_DOTMATCH flag or something like <code>"{*,.*}"</code>.
#
- # <b>Flags</b>
+ # <code>**</code>::
+ # Matches directories recursively if followed by <code>/</code>. If
+ # this path segment contains any other characters, it is the same as the
+ # usual <code>*</code>.
#
- # If optional keyword argument +flags+ is given (the default is zero -- no flags),
- # its value should be the bitwise OR of one or more of the constants
- # defined in module File::Constants.
+ # <code>?</code>::
+ # Matches any one character. Equivalent to <code>/.{1}/</code> in regexp.
#
- # Example:
+ # <code>[set]</code>::
+ # Matches any one character in +set+. Behaves exactly like character sets
+ # in Regexp, including set negation (<code>[^a-z]</code>).
#
- # flags = File::FNM_EXTGLOB | File::FNM_DOTMATCH
+ # <code>{p,q}</code>::
+ # Matches either literal <code>p</code> or literal <code>q</code>.
+ # Equivalent to pattern alternation in regexp.
#
- # Specifying flags can extend, restrict, or otherwise modify the matching.
+ # Matching literals may be more than one character in length. More than
+ # two literals may be specified.
#
- # The flags for this method (other constants in File::Constants do not apply):
+ # <code>\\</code>::
+ # Escapes the next metacharacter.
#
- # - File::FNM_DOTMATCH:
- # specifies that entry names beginning with <tt>'.'</tt>
- # should be considered for matching:
+ # Note that this means you cannot use backslash on windows as part of a
+ # glob, i.e. <code>Dir["c:\\foo*"]</code> will not work, use
+ # <code>Dir["c:/foo*"]</code> instead.
#
- # Dir.glob('*').take(5)
- # # => ["BSDL", "CONTRIBUTING.md", "COPYING", "COPYING.ja", "GPL"]
- # Dir.glob('*', flags: File::FNM_DOTMATCH).take(5)
- # # => [".", ".appveyor.yml", ".cirrus.yml", ".dir-locals.el", ".document"]
+ # Examples:
#
- # - File::FNM_EXTGLOB:
- # enables the pattern extension
- # <tt>'{_a_,_b_}'</tt>, which matches pattern _a_ and pattern _b_;
- # behaves like a
- # {regexp union}[rdoc-ref:Regexp.union]
- # (e.g., <tt>'(?:_a_|_b_)'</tt>):
+ # Dir["config.?"] #=> ["config.h"]
+ # Dir.glob("config.?") #=> ["config.h"]
+ # Dir.glob("*.[a-z][a-z]") #=> ["main.rb"]
+ # Dir.glob("*.[^r]*") #=> ["config.h"]
+ # Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"]
+ # Dir.glob("*") #=> ["config.h", "main.rb"]
+ # Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "config.h", "main.rb"]
+ # Dir.glob(["*.rb", "*.h"]) #=> ["main.rb", "config.h"]
#
- # pattern = '{LEGAL,BSDL}'
- # Dir.glob(pattern) # => ["LEGAL", "BSDL"]
+ # Dir.glob("**/*.rb") #=> ["main.rb",
+ # # "lib/song.rb",
+ # # "lib/song/karaoke.rb"]
#
- # - File::FNM_NOESCAPE:
- # specifies that escaping with the backslash character <tt>'\'</tt>
- # is disabled; the character is not an escape character.
+ # Dir.glob("**/*.rb", base: "lib") #=> ["song.rb",
+ # # "song/karaoke.rb"]
#
- # - File::FNM_PATHNAME:
- # specifies that metacharacters <tt>'*'</tt> and <tt>'?'</tt>
- # do not match directory separators.
+ # Dir.glob("**/lib") #=> ["lib"]
#
- # - File::FNM_SHORTNAME:
- # specifies that patterns may match short names if they exist; Windows only.
+ # Dir.glob("**/lib/**/*.rb") #=> ["lib/song.rb",
+ # # "lib/song/karaoke.rb"]
#
+ # Dir.glob("**/lib/*.rb") #=> ["lib/song.rb"]
def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true)
Primitive.dir_s_glob(pattern, flags, base, sort)
end
diff --git a/dln.c b/dln.c
index 77bfe91b28..0edd709bbe 100644
--- a/dln.c
+++ b/dln.c
@@ -392,12 +392,6 @@ dln_open(const char *file)
dln_fatalerror("%s - %s", incompatible, file);
}
else {
- if (libruby_name) {
- const size_t len = strlen(libruby_name);
- char *const tmp = ALLOCA_N(char, len + 1);
- if (tmp) memcpy(tmp, libruby_name, len + 1);
- libruby_name = tmp;
- }
dlclose(handle);
if (libruby_name) {
dln_loaderror("linked to incompatible %s - %s", libruby_name, file);
diff --git a/dln_find.c b/dln_find.c
index 91c51394a9..5d380f5d39 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -75,7 +75,7 @@ dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size
".";
}
buf = dln_find_1(fname, path, buf, size, 1 DLN_FIND_EXTRA_ARG);
- free(envpath);
+ if (envpath) free(envpath);
return buf;
}
diff --git a/doc/.document b/doc/.document
index 4b90648377..f589dda07c 100644
--- a/doc/.document
+++ b/doc/.document
@@ -6,5 +6,4 @@ NEWS
syntax
optparse
rdoc
-regexp
yjit
diff --git a/doc/ChangeLog/ChangeLog-0.06_to_0.52 b/doc/ChangeLog-0.06_to_0.52
index 63826081b3..63826081b3 100644
--- a/doc/ChangeLog/ChangeLog-0.06_to_0.52
+++ b/doc/ChangeLog-0.06_to_0.52
diff --git a/doc/ChangeLog/ChangeLog-0.50_to_0.60 b/doc/ChangeLog-0.50_to_0.60
index 5f5b03ff40..5f5b03ff40 100644
--- a/doc/ChangeLog/ChangeLog-0.50_to_0.60
+++ b/doc/ChangeLog-0.50_to_0.60
diff --git a/doc/ChangeLog/ChangeLog-0.60_to_1.1 b/doc/ChangeLog-0.60_to_1.1
index 59d195e780..59d195e780 100644
--- a/doc/ChangeLog/ChangeLog-0.60_to_1.1
+++ b/doc/ChangeLog-0.60_to_1.1
diff --git a/doc/ChangeLog/ChangeLog-1.8.0 b/doc/ChangeLog-1.8.0
index 6d9453d011..6d9453d011 100644
--- a/doc/ChangeLog/ChangeLog-1.8.0
+++ b/doc/ChangeLog-1.8.0
diff --git a/doc/ChangeLog/ChangeLog-1.9.3 b/doc/ChangeLog-1.9.3
index 0f80eed2d5..0f80eed2d5 100644
--- a/doc/ChangeLog/ChangeLog-1.9.3
+++ b/doc/ChangeLog-1.9.3
diff --git a/doc/ChangeLog/ChangeLog-2.0.0 b/doc/ChangeLog-2.0.0
index 9e654db189..9e654db189 100644
--- a/doc/ChangeLog/ChangeLog-2.0.0
+++ b/doc/ChangeLog-2.0.0
diff --git a/doc/ChangeLog/ChangeLog-2.1.0 b/doc/ChangeLog-2.1.0
index 5b670b31c9..5b670b31c9 100644
--- a/doc/ChangeLog/ChangeLog-2.1.0
+++ b/doc/ChangeLog-2.1.0
diff --git a/doc/ChangeLog/ChangeLog-2.2.0 b/doc/ChangeLog-2.2.0
index 5a7dbf826d..5a7dbf826d 100644
--- a/doc/ChangeLog/ChangeLog-2.2.0
+++ b/doc/ChangeLog-2.2.0
diff --git a/doc/ChangeLog/ChangeLog-2.3.0 b/doc/ChangeLog-2.3.0
index 94996cffd0..94996cffd0 100644
--- a/doc/ChangeLog/ChangeLog-2.3.0
+++ b/doc/ChangeLog-2.3.0
diff --git a/doc/ChangeLog/ChangeLog-2.4.0 b/doc/ChangeLog-2.4.0
index a297a579d1..a297a579d1 100644
--- a/doc/ChangeLog/ChangeLog-2.4.0
+++ b/doc/ChangeLog-2.4.0
diff --git a/doc/ChangeLog/ChangeLog-YARV b/doc/ChangeLog-YARV
index 83df05c52c..83df05c52c 100644
--- a/doc/ChangeLog/ChangeLog-YARV
+++ b/doc/ChangeLog-YARV
diff --git a/doc/NEWS/NEWS-3.2.0.md b/doc/NEWS/NEWS-3.2.0.md
deleted file mode 100644
index 33a7b85c47..0000000000
--- a/doc/NEWS/NEWS-3.2.0.md
+++ /dev/null
@@ -1,820 +0,0 @@
-# NEWS for Ruby 3.2.0
-
-This document is a list of user-visible feature changes
-since the **3.1.0** release, except for bug fixes.
-
-Note that each entry is kept to a minimum, see links for details.
-
-## Language changes
-
-* Anonymous rest and keyword rest arguments can now be passed as
- arguments, instead of just used in method parameters.
- [[Feature #18351]]
-
- ```ruby
- def foo(*)
- bar(*)
- end
- def baz(**)
- quux(**)
- end
- ```
-
-* A proc that accepts a single positional argument and keywords will
- no longer autosplat. [[Bug #18633]]
-
- ```ruby
- proc{|a, **k| a}.call([1, 2])
- # Ruby 3.1 and before
- # => 1
- # Ruby 3.2 and after
- # => [1, 2]
- ```
-
-* Constant assignment evaluation order for constants set on explicit
- objects has been made consistent with single attribute assignment
- evaluation order. With this code:
-
- ```ruby
- foo::BAR = baz
- ```
-
- `foo` is now called before `baz`. Similarly, for multiple assignments
- to constants, left-to-right evaluation order is used. With this
- code:
-
- ```ruby
- foo1::BAR1, foo2::BAR2 = baz1, baz2
- ```
-
- The following evaluation order is now used:
-
- 1. `foo1`
- 2. `foo2`
- 3. `baz1`
- 4. `baz2`
-
- [[Bug #15928]]
-
-* "Find pattern" is no longer experimental.
- [[Feature #18585]]
-
-* Methods taking a rest parameter (like `*args`) and wishing to delegate keyword
- arguments through `foo(*args)` must now be marked with `ruby2_keywords`
- (if not already the case). In other words, all methods wishing to delegate
- keyword arguments through `*args` must now be marked with `ruby2_keywords`,
- with no exception. This will make it easier to transition to other ways of
- delegation once a library can require Ruby 3+. Previously, the `ruby2_keywords`
- flag was kept if the receiving method took `*args`, but this was a bug and an
- inconsistency. A good technique to find the potentially-missing `ruby2_keywords`
- is to run the test suite, for where it fails find the last method which must
- receive keyword arguments, use `puts nil, caller, nil` there, and check each
- method/block on the call chain which must delegate keywords is correctly marked
- as `ruby2_keywords`. [[Bug #18625]] [[Bug #16466]]
-
- ```ruby
- def target(**kw)
- end
-
- # Accidentally worked without ruby2_keywords in Ruby 2.7-3.1, ruby2_keywords
- # needed in 3.2+. Just like (*args, **kwargs) or (...) would be needed on
- # both #foo and #bar when migrating away from ruby2_keywords.
- ruby2_keywords def bar(*args)
- target(*args)
- end
-
- ruby2_keywords def foo(*args)
- bar(*args)
- end
-
- foo(k: 1)
- ```
-
-## Core classes updates
-
-Note: We're only listing outstanding class updates.
-
-* Fiber
-
- * Introduce Fiber.[] and Fiber.[]= for inheritable fiber storage.
- Introduce Fiber#storage and Fiber#storage= (experimental) for
- getting and resetting the current storage. Introduce
- `Fiber.new(storage:)` for setting the storage when creating a
- fiber. [[Feature #19078]]
-
- Existing Thread and Fiber local variables can be tricky to use.
- Thread-local variables are shared between all fibers, making it
- hard to isolate, while Fiber-local variables can be hard to
- share. It is often desirable to define unit of execution
- ("execution context") such that some state is shared between all
- fibers and threads created in that context. This is what Fiber
- storage provides.
-
- ```ruby
- def log(message)
- puts "#{Fiber[:request_id]}: #{message}"
- end
-
- def handle_requests
- while request = read_request
- Fiber.schedule do
- Fiber[:request_id] = SecureRandom.uuid
-
- request.messages.each do |message|
- Fiber.schedule do
- log("Handling #{message}") # Log includes inherited request_id.
- end
- end
- end
- end
- end
- ```
-
- You should generally consider Fiber storage for any state which
- you want to be shared implicitly between all fibers and threads
- created in a given context, e.g. a connection pool, a request
- id, a logger level, environment variables, configuration, etc.
-
-* Fiber::Scheduler
-
- * Introduce `Fiber::Scheduler#io_select` for non-blocking IO.select.
- [[Feature #19060]]
-
-* IO
-
- * Introduce IO#timeout= and IO#timeout which can cause
- IO::TimeoutError to be raised if a blocking operation exceeds the
- specified timeout. [[Feature #18630]]
-
- ```ruby
- STDIN.timeout = 1
- STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
- ```
-
- * Introduce `IO.new(..., path:)` and promote `File#path` to `IO#path`.
- [[Feature #19036]]
-
-* Class
-
- * Class#attached_object, which returns the object for which
- the receiver is the singleton class. Raises TypeError if the
- receiver is not a singleton class.
- [[Feature #12084]]
-
- ```ruby
- class Foo; end
-
- Foo.singleton_class.attached_object #=> Foo
- Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370>
- Foo.attached_object #=> TypeError: `Foo' is not a singleton class
- nil.singleton_class.attached_object #=> TypeError: `NilClass' is not a singleton class
- ```
-
-* Data
-
- * New core class to represent simple immutable value object. The class is
- similar to Struct and partially shares an implementation, but has more
- lean and strict API. [[Feature #16122]]
-
- ```ruby
- Measure = Data.define(:amount, :unit)
- distance = Measure.new(100, 'km') #=> #<data Measure amount=100, unit="km">
- weight = Measure.new(amount: 50, unit: 'kg') #=> #<data Measure amount=50, unit="kg">
- weight.with(amount: 40) #=> #<data Measure amount=40, unit="kg">
- weight.amount #=> 50
- weight.amount = 40 #=> NoMethodError: undefined method `amount='
- ```
-
-* Encoding
-
- * Encoding#replicate has been deprecated and will be removed in 3.3. [[Feature #18949]]
- * The dummy `Encoding::UTF_16` and `Encoding::UTF_32` encodings no longer
- try to dynamically guess the endian based on a byte order mark.
- Use `Encoding::UTF_16BE`/`UTF_16LE` and `Encoding::UTF_32BE`/`UTF_32LE` instead.
- This change speeds up getting the encoding of a String. [[Feature #18949]]
- * Limit maximum encoding set size by 256.
- If exceeding maximum size, `EncodingError` will be raised. [[Feature #18949]]
-
-* Enumerator
-
- * Enumerator.product has been added. Enumerator::Product is the implementation. [[Feature #18685]]
-
-* Exception
-
- * Exception#detailed_message has been added.
- The default error printer calls this method on the Exception object
- instead of #message. [[Feature #18564]]
-
-* Hash
-
- * Hash#shift now always returns nil if the hash is
- empty, instead of returning the default value or
- calling the default proc. [[Bug #16908]]
-
-* Integer
-
- * Integer#ceildiv has been added. [[Feature #18809]]
-
-* Kernel
-
- * Kernel#binding raises RuntimeError if called from a non-Ruby frame
- (such as a method defined in C). [[Bug #18487]]
-
-* MatchData
-
- * MatchData#byteoffset has been added. [[Feature #13110]]
- * MatchData#deconstruct has been added. [[Feature #18821]]
- * MatchData#deconstruct_keys has been added. [[Feature #18821]]
-
-* Module
-
- * Module.used_refinements has been added. [[Feature #14332]]
- * Module#refinements has been added. [[Feature #12737]]
- * Module#const_added has been added. [[Feature #17881]]
- * Module#undefined_instance_methods has been added. [[Feature #12655]]
-
-* Proc
-
- * Proc#dup returns an instance of subclass. [[Bug #17545]]
- * Proc#parameters now accepts lambda keyword. [[Feature #15357]]
-
-* Process
- * Added `RLIMIT_NPTS` constant to FreeBSD platform
-
-* Regexp
-
- * The cache-based optimization is introduced.
- Many (but not all) Regexp matching is now in linear time, which
- will prevent regular expression denial of service (ReDoS)
- vulnerability. [[Feature #19104]]
-
- * Regexp.linear_time? is introduced. [[Feature #19194]]
-
- * Regexp.new now supports passing the regexp flags not only as an Integer,
- but also as a String. Unknown flags raise ArgumentError.
- Otherwise, anything other than `true`, `false`, `nil` or Integer will be warned.
- [[Feature #18788]]
-
- * Regexp.timeout= has been added. Also, Regexp.new new supports timeout keyword.
- See [[Feature #17837]]
-
-* Refinement
-
- * Refinement#refined_class has been added. [[Feature #12737]]
-
-* RubyVM::AbstractSyntaxTree
-
- * Add `error_tolerant` option for `parse`, `parse_file` and `of`. [[Feature #19013]]
- With this option
-
- 1. SyntaxError is suppressed
- 2. AST is returned for invalid input
- 3. `end` is complemented when a parser reaches to the end of input but `end` is insufficient
- 4. `end` is treated as keyword based on indent
-
- ```ruby
- # Without error_tolerant option
- root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY)
- def m
- a = 10
- if
- end
- RUBY
- # => <internal:ast>:33:in `parse': syntax error, unexpected `end' (SyntaxError)
-
- # With error_tolerant option
- root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
- def m
- a = 10
- if
- end
- RUBY
- p root # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-4:3>
-
- # `end` is treated as keyword based on indent
- root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
- module Z
- class Foo
- foo.
- end
-
- def bar
- end
- end
- RUBY
- p root.children[-1].children[-1].children[-1].children[-2..-1]
- # => [#<RubyVM::AbstractSyntaxTree::Node:CLASS@2:2-4:5>, #<RubyVM::AbstractSyntaxTree::Node:DEFN@6:2-7:5>]
- ```
-
- * Add `keep_tokens` option for `parse`, `parse_file` and `of`. Add `#tokens` and `#all_tokens`
- for RubyVM::AbstractSyntaxTree::Node [[Feature #19070]]
-
- ```ruby
- root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2", keep_tokens: true)
- root.tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...]
- root.tokens.map{_1[2]}.join # => "x = 1 + 2"
- ```
-
-* Set
-
- * Set is now available as a built-in class without the need for `require "set"`. [[Feature #16989]]
- It is currently autoloaded via the Set constant or a call to Enumerable#to_set.
-
-* String
-
- * String#byteindex and String#byterindex have been added. [[Feature #13110]]
- * Update Unicode to Version 15.0.0 and Emoji Version 15.0. [[Feature #18639]]
- (also applies to Regexp)
- * String#bytesplice has been added. [[Feature #18598]]
- * String#dedup has been added as an alias to String#-@. [[Feature #18595]]
-
-* Struct
-
- * A Struct class can also be initialized with keyword arguments
- without `keyword_init: true` on Struct.new [[Feature #16806]]
-
- ```ruby
- Post = Struct.new(:id, :name)
- Post.new(1, "hello") #=> #<struct Post id=1, name="hello">
- # From Ruby 3.2, the following code also works without keyword_init: true.
- Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">
- ```
-
-* Thread
-
- * Thread.each_caller_location is added. [[Feature #16663]]
-
-* Thread::Queue
-
- * Thread::Queue#pop(timeout: sec) is added. [[Feature #18774]]
-
-* Thread::SizedQueue
-
- * Thread::SizedQueue#pop(timeout: sec) is added. [[Feature #18774]]
- * Thread::SizedQueue#push(timeout: sec) is added. [[Feature #18944]]
-
-* Time
-
- * Time#deconstruct_keys is added, allowing to use Time instances
- in pattern-matching expressions [[Feature #19071]]
-
- * Time.new now can parse a string like generated by Time#inspect
- and return a Time instance based on the given argument.
- [[Feature #18033]]
-
-* SyntaxError
- * SyntaxError#path has been added. [[Feature #19138]]
-
-* TracePoint
-
- * TracePoint#binding now returns `nil` for `c_call`/`c_return` TracePoints.
- [[Bug #18487]]
- * TracePoint#enable `target_thread` keyword argument now defaults to the
- current thread if a block is given and `target` and `target_line` keyword
- arguments are not passed. [[Bug #16889]]
-
-* UnboundMethod
-
- * `UnboundMethod#==` returns `true` if the actual method is same. For example,
- `String.instance_method(:object_id) == Array.instance_method(:object_id)`
- returns `true`. [[Feature #18798]]
-
- * `UnboundMethod#inspect` does not show the receiver of `instance_method`.
- For example `String.instance_method(:object_id).inspect` returns
- `"#<UnboundMethod: Kernel#object_id()>"`
- (was `"#<UnboundMethod: String(Kernel)#object_id()>"`).
-
-* GC
-
- * Expose `need_major_gc` via `GC.latest_gc_info`. [GH-6791]
-
-* ObjectSpace
-
- * `ObjectSpace.dump_all` dump shapes as well. [GH-6868]
-
-## Stdlib updates
-
-* Bundler
-
- * Bundler now uses [PubGrub] resolver instead of [Molinillo] for performance improvement.
- * Add --ext=rust support to bundle gem for creating simple gems with Rust extensions.
- [[GH-rubygems-6149]]
- * Make cloning git repos faster [[GH-rubygems-4475]]
-
-* RubyGems
-
- * Add mswin support for cargo builder. [[GH-rubygems-6167]]
-
-* CGI
-
- * `CGI.escapeURIComponent` and `CGI.unescapeURIComponent` are added.
- [[Feature #18822]]
-
-* Coverage
-
- * `Coverage.setup` now accepts `eval: true`. By this, `eval` and related methods are
- able to generate code coverage. [[Feature #19008]]
-
- * `Coverage.supported?(mode)` enables detection of what coverage modes are
- supported. [[Feature #19026]]
-
-* Date
-
- * Added `Date#deconstruct_keys` and `DateTime#deconstruct_keys` same as [[Feature #19071]]
-
-* ERB
-
- * `ERB::Util.html_escape` is made faster than `CGI.escapeHTML`.
- * It no longer allocates a String object when no character needs to be escaped.
- * It skips calling `#to_s` method when an argument is already a String.
- * `ERB::Escape.html_escape` is added as an alias to `ERB::Util.html_escape`,
- which has not been monkey-patched by Rails.
- * `ERB::Util.url_encode` is made faster using `CGI.escapeURIComponent`.
- * `-S` option is removed from `erb` command.
-
-* FileUtils
-
- * Add FileUtils.ln_sr method and `relative:` option to FileUtils.ln_s.
- [[Feature #18925]]
-
-* IRB
-
- * debug.gem integration commands have been added: `debug`, `break`, `catch`,
- `next`, `delete`, `step`, `continue`, `finish`, `backtrace`, `info`
- * They work even if you don't have `gem "debug"` in your Gemfile.
- * See also: [What's new in Ruby 3.2's IRB?](https://st0012.dev/whats-new-in-ruby-3-2-irb)
- * More Pry-like commands and features have been added.
- * `edit` and `show_cmds` (like Pry's `help`) are added.
- * `ls` takes `-g` or `-G` option to filter out outputs.
- * `show_source` is aliased from `$` and accepts unquoted inputs.
- * `whereami` is aliased from `@`.
-
-* Net::Protocol
-
- * Improve `Net::BufferedIO` performance. [[GH-net-protocol-14]]
-
-* Pathname
-
- * Added `Pathname#lutime`. [[GH-pathname-20]]
-
-* Socket
-
- * Added the following constants for supported platforms.
- * `SO_INCOMING_CPU`
- * `SO_INCOMING_NAPI_ID`
- * `SO_RTABLE`
- * `SO_SETFIB`
- * `SO_USER_COOKIE`
- * `TCP_KEEPALIVE`
- * `TCP_CONNECTION_INFO`
-
-* SyntaxSuggest
-
- * The feature of `syntax_suggest` formerly `dead_end` is integrated in Ruby.
- [[Feature #18159]]
-
-* UNIXSocket
-
- * Add support for UNIXSocket on Windows. Emulate anonymous sockets. Add
- support for File.socket? and File::Stat#socket? where possible.
- [[Feature #19135]]
-
-* The following default gems are updated.
-
- * RubyGems 3.4.1
- * abbrev 0.1.1
- * benchmark 0.2.1
- * bigdecimal 3.1.3
- * bundler 2.4.1
- * cgi 0.3.6
- * csv 3.2.6
- * date 3.3.3
- * delegate 0.3.0
- * did_you_mean 1.6.3
- * digest 3.1.1
- * drb 2.1.1
- * english 0.7.2
- * erb 4.0.2
- * error_highlight 0.5.1
- * etc 1.4.2
- * fcntl 1.0.2
- * fiddle 1.1.1
- * fileutils 1.7.0
- * forwardable 1.3.3
- * getoptlong 0.2.0
- * io-console 0.6.0
- * io-nonblock 0.2.0
- * io-wait 0.3.0
- * ipaddr 1.2.5
- * irb 1.6.2
- * json 2.6.3
- * logger 1.5.3
- * mutex_m 0.1.2
- * net-http 0.3.2
- * net-protocol 0.2.1
- * nkf 0.1.2
- * open-uri 0.3.0
- * open3 0.1.2
- * openssl 3.1.0
- * optparse 0.3.1
- * ostruct 0.5.5
- * pathname 0.2.1
- * pp 0.4.0
- * pstore 0.1.2
- * psych 5.0.1
- * racc 1.6.2
- * rdoc 6.5.0
- * readline-ext 0.1.5
- * reline 0.3.2
- * resolv 0.2.2
- * resolv-replace 0.1.1
- * securerandom 0.2.2
- * set 1.0.3
- * stringio 3.0.4
- * strscan 3.0.5
- * syntax_suggest 1.0.2
- * syslog 0.1.1
- * tempfile 0.1.3
- * time 0.2.1
- * timeout 0.3.1
- * tmpdir 0.1.3
- * tsort 0.1.1
- * un 0.2.1
- * uri 0.12.0
- * weakref 0.1.2
- * win32ole 1.8.9
- * yaml 0.2.1
- * zlib 3.0.0
-
-* The following bundled gems are updated.
-
- * minitest 5.16.3
- * power_assert 2.0.3
- * test-unit 3.5.7
- * net-ftp 0.2.0
- * net-imap 0.3.4
- * net-pop 0.1.2
- * net-smtp 0.3.3
- * rbs 2.8.2
- * typeprof 0.21.3
- * debug 1.7.1
-
-See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/logger/releases) or changelog for details of the default gems or bundled gems.
-
-## Supported platforms
-
-* WebAssembly/WASI is added. See [wasm/README.md] and [ruby.wasm] for more details. [[Feature #18462]]
-
-## Compatibility issues
-
-* `String#to_c` currently treat a sequence of underscores as an end of Complex
- string. [[Bug #19087]]
-
-* Now `ENV.clone` raises `TypeError` as well as `ENV.dup` [[Bug #17767]]
-
-### Removed constants
-
-The following deprecated constants are removed.
-
-* `Fixnum` and `Bignum` [[Feature #12005]]
-* `Random::DEFAULT` [[Feature #17351]]
-* `Struct::Group`
-* `Struct::Passwd`
-
-### Removed methods
-
-The following deprecated methods are removed.
-
-* `Dir.exists?` [[Feature #17391]]
-* `File.exists?` [[Feature #17391]]
-* `Kernel#=~` [[Feature #15231]]
-* `Kernel#taint`, `Kernel#untaint`, `Kernel#tainted?`
- [[Feature #16131]]
-* `Kernel#trust`, `Kernel#untrust`, `Kernel#untrusted?`
- [[Feature #16131]]
-* `Method#public?`, `Method#private?`, `Method#protected?`,
- `UnboundMethod#public?`, `UnboundMethod#private?`, `UnboundMethod#protected?`
- [[Bug #18729]] [[Bug #18751]] [[Bug #18435]]
-
-### Source code incompatibility of extension libraries
-
-* Extension libraries provide PRNG, subclasses of Random, need updates.
- See [PRNG update] below for more information. [[Bug #19100]]
-
-### Error printer
-
-* Ruby no longer escapes control characters and backslashes in an
- error message. [[Feature #18367]]
-
-### Constant lookup when defining a class/module
-
-* When defining a class/module directly under the Object class by class/module
- statement, if there is already a class/module defined by `Module#include`
- with the same name, the statement was handled as "open class" in Ruby 3.1 or before.
- Since Ruby 3.2, a new class is defined instead. [[Feature #18832]]
-
-## Stdlib compatibility issues
-
-* Psych no longer bundles libyaml sources.
- And also Fiddle no longer bundles libffi sources.
- Users need to install the libyaml/libffi library themselves via the package
- manager like apt, yum, brew, etc.
-
- Psych and fiddle supported the static build with specific version of libyaml
- and libffi sources. You can build psych with libyaml-0.2.5 like this.
-
- ```bash
- $ ./configure --with-libyaml-source-dir=/path/to/libyaml-0.2.5
- ```
-
- And you can build fiddle with libffi-3.4.4 like this.
-
- ```bash
- $ ./configure --with-libffi-source-dir=/path/to/libffi-3.4.4
- ```
-
- [[Feature #18571]]
-
-* Check cookie name/path/domain characters in `CGI::Cookie`. [[CVE-2021-33621]]
-
-* `URI.parse` return empty string in host instead of nil. [[sec-156615]]
-
-## C API updates
-
-### Updated C APIs
-
-The following APIs are updated.
-
-* PRNG update
-
- `rb_random_interface_t` in ruby/random.h updated and versioned.
- Extension libraries which use this interface and built for older
- versions need to rebuild with adding `init_int32` function.
-
-### Added C APIs
-
-* `VALUE rb_hash_new_capa(long capa)` was added to created hashes with the desired capacity.
-* `rb_internal_thread_add_event_hook` and `rb_internal_thread_add_event_hook` were added to instrument threads scheduling.
- The following events are available:
- * `RUBY_INTERNAL_THREAD_EVENT_STARTED`
- * `RUBY_INTERNAL_THREAD_EVENT_READY`
- * `RUBY_INTERNAL_THREAD_EVENT_RESUMED`
- * `RUBY_INTERNAL_THREAD_EVENT_SUSPENDED`
- * `RUBY_INTERNAL_THREAD_EVENT_EXITED`
-* `rb_debug_inspector_current_depth` and `rb_debug_inspector_frame_depth` are added for debuggers.
-
-### Removed C APIs
-
-The following deprecated APIs are removed.
-
-* `rb_cData` variable.
-* "taintedness" and "trustedness" functions. [[Feature #16131]]
-
-## Implementation improvements
-
-* Fixed several race conditions in Kernel#autoload. [[Bug #18782]]
-* Cache invalidation for expressions referencing constants is now
- more fine-grained. `RubyVM.stat(:global_constant_state)` was
- removed because it was closely tied to the previous caching scheme
- where setting any constant invalidates all caches in the system.
- New keys, `:constant_cache_invalidations` and `:constant_cache_misses`,
- were introduced to help with use cases for `:global_constant_state`.
- [[Feature #18589]]
-* The cache-based optimization for Regexp matching is introduced.
- [[Feature #19104]]
-* [Variable Width Allocation](https://shopify.engineering/ruby-variable-width-allocation)
- is now enabled by default. [[Feature #18239]]
-* Added a new instance variable caching mechanism, called object shapes, which
- improves inline cache hits for most objects and allows us to generate very
- efficient JIT code. Objects whose instance variables are defined in a
- consistent order will see the most performance benefits.
- [[Feature #18776]]
-* Speed up marking instruction sequences by using a bitmap to find "markable"
- objects. This change results in faster major collections.
- [[Feature #18875]]
-
-## JIT
-
-### YJIT
-
-* YJIT is no longer experimental
- * Has been tested on production workloads for over a year and proven to be quite stable.
-* YJIT now supports both x86-64 and arm64/aarch64 CPUs on Linux, MacOS, BSD and other UNIX platforms.
- * This release brings support for Mac M1/M2, AWS Graviton and Raspberry Pi 4.
-* Building YJIT now requires Rust 1.58.0+. [[Feature #18481]]
- * In order to ensure that CRuby is built with YJIT, please install `rustc` >= 1.58.0
- before running `./configure`
- * Please reach out to the YJIT team should you run into any issues.
-* Physical memory for JIT code is lazily allocated. Unlike Ruby 3.1,
- the RSS of a Ruby process is minimized because virtual memory pages
- allocated by `--yjit-exec-mem-size` will not be mapped to physical
- memory pages until actually utilized by JIT code.
-* Introduce Code GC that frees all code pages when the memory consumption
- by JIT code reaches `--yjit-exec-mem-size`.
- * `RubyVM::YJIT.runtime_stats` returns Code GC metrics in addition to
- existing `inline_code_size` and `outlined_code_size` keys:
- `code_gc_count`, `live_page_count`, `freed_page_count`, and `freed_code_size`.
-* Most of the statistics produced by `RubyVM::YJIT.runtime_stats` are now available in release builds.
- * Simply run ruby with `--yjit-stats` to compute and dump stats (incurs some run-time overhead).
-* YJIT is now optimized to take advantage of object shapes. [[Feature #18776]]
-* Take advantage of finer-grained constant invalidation to invalidate less code when defining new constants. [[Feature #18589]]
-* The default `--yjit-exec-mem-size` is changed to 64 (MiB).
-* The default `--yjit-call-threshold` is changed to 30.
-
-### MJIT
-
-* The MJIT compiler is re-implemented in Ruby as `ruby_vm/mjit/compiler`.
-* MJIT compiler is executed under a forked Ruby process instead of
- doing it in a native thread called MJIT worker. [[Feature #18968]]
- * As a result, Microsoft Visual Studio (MSWIN) is no longer supported.
-* MinGW is no longer supported. [[Feature #18824]]
-* Rename `--mjit-min-calls` to `--mjit-call-threshold`.
-* Change default `--mjit-max-cache` back from 10000 to 100.
-
-[Feature #12005]: https://bugs.ruby-lang.org/issues/12005
-[Feature #12084]: https://bugs.ruby-lang.org/issues/12084
-[Feature #12655]: https://bugs.ruby-lang.org/issues/12655
-[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
-[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
-[Feature #14332]: https://bugs.ruby-lang.org/issues/14332
-[Feature #15231]: https://bugs.ruby-lang.org/issues/15231
-[Feature #15357]: https://bugs.ruby-lang.org/issues/15357
-[Bug #15928]: https://bugs.ruby-lang.org/issues/15928
-[Feature #16122]: https://bugs.ruby-lang.org/issues/16122
-[Feature #16131]: https://bugs.ruby-lang.org/issues/16131
-[Bug #16466]: https://bugs.ruby-lang.org/issues/16466
-[Feature #16663]: https://bugs.ruby-lang.org/issues/16663
-[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
-[Bug #16889]: https://bugs.ruby-lang.org/issues/16889
-[Bug #16908]: https://bugs.ruby-lang.org/issues/16908
-[Feature #16989]: https://bugs.ruby-lang.org/issues/16989
-[Feature #17351]: https://bugs.ruby-lang.org/issues/17351
-[Feature #17391]: https://bugs.ruby-lang.org/issues/17391
-[Bug #17545]: https://bugs.ruby-lang.org/issues/17545
-[Bug #17767]: https://bugs.ruby-lang.org/issues/17767
-[Feature #17837]: https://bugs.ruby-lang.org/issues/17837
-[Feature #17881]: https://bugs.ruby-lang.org/issues/17881
-[Feature #18033]: https://bugs.ruby-lang.org/issues/18033
-[Feature #18159]: https://bugs.ruby-lang.org/issues/18159
-[Feature #18239]: https://bugs.ruby-lang.org/issues/18239#note-17
-[Feature #18351]: https://bugs.ruby-lang.org/issues/18351
-[Feature #18367]: https://bugs.ruby-lang.org/issues/18367
-[Bug #18435]: https://bugs.ruby-lang.org/issues/18435
-[Feature #18462]: https://bugs.ruby-lang.org/issues/18462
-[Feature #18481]: https://bugs.ruby-lang.org/issues/18481
-[Bug #18487]: https://bugs.ruby-lang.org/issues/18487
-[Feature #18564]: https://bugs.ruby-lang.org/issues/18564
-[Feature #18571]: https://bugs.ruby-lang.org/issues/18571
-[Feature #18585]: https://bugs.ruby-lang.org/issues/18585
-[Feature #18589]: https://bugs.ruby-lang.org/issues/18589
-[Feature #18595]: https://bugs.ruby-lang.org/issues/18595
-[Feature #18598]: https://bugs.ruby-lang.org/issues/18598
-[Bug #18625]: https://bugs.ruby-lang.org/issues/18625
-[Feature #18630]: https://bugs.ruby-lang.org/issues/18630
-[Bug #18633]: https://bugs.ruby-lang.org/issues/18633
-[Feature #18639]: https://bugs.ruby-lang.org/issues/18639
-[Feature #18685]: https://bugs.ruby-lang.org/issues/18685
-[Bug #18729]: https://bugs.ruby-lang.org/issues/18729
-[Bug #18751]: https://bugs.ruby-lang.org/issues/18751
-[Feature #18774]: https://bugs.ruby-lang.org/issues/18774
-[Feature #18776]: https://bugs.ruby-lang.org/issues/18776
-[Bug #18782]: https://bugs.ruby-lang.org/issues/18782
-[Feature #18788]: https://bugs.ruby-lang.org/issues/18788
-[Feature #18798]: https://bugs.ruby-lang.org/issues/18798
-[Feature #18809]: https://bugs.ruby-lang.org/issues/18809
-[Feature #18821]: https://bugs.ruby-lang.org/issues/18821
-[Feature #18822]: https://bugs.ruby-lang.org/issues/18822
-[Feature #18824]: https://bugs.ruby-lang.org/issues/18824
-[Feature #18832]: https://bugs.ruby-lang.org/issues/18832
-[Feature #18875]: https://bugs.ruby-lang.org/issues/18875
-[Feature #18925]: https://bugs.ruby-lang.org/issues/18925
-[Feature #18944]: https://bugs.ruby-lang.org/issues/18944
-[Feature #18949]: https://bugs.ruby-lang.org/issues/18949
-[Feature #18968]: https://bugs.ruby-lang.org/issues/18968
-[Feature #19008]: https://bugs.ruby-lang.org/issues/19008
-[Feature #19013]: https://bugs.ruby-lang.org/issues/19013
-[Feature #19026]: https://bugs.ruby-lang.org/issues/19026
-[Feature #19036]: https://bugs.ruby-lang.org/issues/19036
-[Feature #19060]: https://bugs.ruby-lang.org/issues/19060
-[Feature #19070]: https://bugs.ruby-lang.org/issues/19070
-[Feature #19071]: https://bugs.ruby-lang.org/issues/19071
-[Feature #19078]: https://bugs.ruby-lang.org/issues/19078
-[Bug #19087]: https://bugs.ruby-lang.org/issues/19087
-[Bug #19100]: https://bugs.ruby-lang.org/issues/19100
-[Feature #19104]: https://bugs.ruby-lang.org/issues/19104
-[Feature #19135]: https://bugs.ruby-lang.org/issues/19135
-[Feature #19138]: https://bugs.ruby-lang.org/issues/19138
-[Feature #19194]: https://bugs.ruby-lang.org/issues/19194
-[Molinillo]: https://github.com/CocoaPods/Molinillo
-[PubGrub]: https://github.com/jhawthorn/pub_grub
-[GH-net-protocol-14]: https://github.com/ruby/net-protocol/pull/14
-[GH-pathname-20]: https://github.com/ruby/pathname/pull/20
-[GH-6791]: https://github.com/ruby/ruby/pull/6791
-[GH-6868]: https://github.com/ruby/ruby/pull/6868
-[GH-rubygems-4475]: https://github.com/rubygems/rubygems/pull/4475
-[GH-rubygems-6149]: https://github.com/rubygems/rubygems/pull/6149
-[GH-rubygems-6167]: https://github.com/rubygems/rubygems/pull/6167
-[sec-156615]: https://hackerone.com/reports/156615
-[CVE-2021-33621]: https://www.ruby-lang.org/en/news/2022/11/22/http-response-splitting-in-cgi-cve-2021-33621/
-[wasm/README.md]: https://github.com/ruby/ruby/blob/master/wasm/README.md
-[ruby.wasm]: https://github.com/ruby/ruby.wasm
diff --git a/doc/command_injection.rdoc b/doc/command_injection.rdoc
index 4408b1839d..af09be23f0 100644
--- a/doc/command_injection.rdoc
+++ b/doc/command_injection.rdoc
@@ -8,7 +8,6 @@ They should not be called with unknown or unsanitized commands.
These methods include:
- Kernel.system
-- Kernel.open
- {\`command` (backtick method)}[rdoc-ref:Kernel#`]
(also called by the expression <tt>%x[command]</tt>).
- IO.popen(command).
@@ -18,7 +17,6 @@ These methods include:
- IO.binwrite(command).
- IO.readlines(command).
- IO.foreach(command).
-- URI.open(command).
Note that some of these methods do not execute commands when called
from subclass \File:
diff --git a/doc/contributing/building_ruby.md b/doc/contributing/building_ruby.md
index b2a7b007eb..469c9d8361 100644
--- a/doc/contributing/building_ruby.md
+++ b/doc/contributing/building_ruby.md
@@ -1,113 +1,83 @@
# Building Ruby
-## Dependencies
+## Quick start guide
1. Install the prerequisite dependencies for building the CRuby interpreter:
* C compiler
-
- For RubyGems, you will also need:
-
- * OpenSSL 1.1.x or 3.0.x / LibreSSL
- * libyaml 0.1.7 or later
- * zlib
-
- If you want to build from the git repository, you will also need:
-
* autoconf - 2.67 or later
- * gperf - 3.1 or later
- * Usually unneeded; only if you edit some source files using gperf
- * ruby - 2.5 or later
- * We can upgrade this version to system ruby version of the latest Ubuntu LTS.
+ * bison - 3.0 or later
+ * gperf - 3.0.3 or later
+ * ruby - 2.7 or later
2. Install optional, recommended dependencies:
- * libffi (to build fiddle)
- * gmp (if you with to accelerate Bignum operations)
+ * OpenSSL/LibreSSL
+ * readline/editline (libedit)
+ * zlib
+ * libffi
+ * libyaml
* libexecinfo (FreeBSD)
- * rustc - 1.58.0 or later, if you wish to build
- [YJIT](https://docs.ruby-lang.org/en/master/RubyVM/YJIT.html).
+ * rustc - 1.58.0 or later (if you wish to build [YJIT](/doc/yjit/yjit.md))
- If you installed the libraries needed for extensions (openssl, readline, libyaml, zlib) into other than the OS default place,
- typically using Homebrew on macOS, add `--with-EXTLIB-dir` options to `CONFIGURE_ARGS` environment variable.
+3. Checkout the CRuby source code:
- ``` shell
- export CONFIGURE_ARGS=""
- for ext in openssl readline libyaml zlib; do
- CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-$ext-dir=$(brew --prefix $ext)"
- done
+ ```
+ git clone https://github.com/ruby/ruby.git
```
-## Quick start guide
-
-1. Download ruby source code:
-
- Select one of the bellow.
-
- 1. Build from the tarball:
-
- Download the latest tarball from [ruby-lang.org](https://www.ruby-lang.org/en/downloads/) and
- extract it. Example for Ruby 3.0.2:
-
- ``` shell
- tar -xzf ruby-3.0.2.tar.gz
- cd ruby-3.0.2
- ```
-
- 2. Build from the git repository:
-
- Checkout the CRuby source code:
-
- ``` shell
- git clone https://github.com/ruby/ruby.git
- cd ruby
- ```
-
- Generate the configure file:
+4. Generate the configure file:
- ``` shell
- ./autogen.sh
- ```
+ ```
+ ./autogen.sh
+ ```
-2. Create a `build` directory separate from the source directory:
+5. Create a `build` directory outside of the source directory:
- ``` shell
+ ```
mkdir build && cd build
```
While it's not necessary to build in a separate directory, it's good practice to do so.
-3. We'll install Ruby in `~/.rubies/ruby-master`, so create the directory:
+6. We'll install Ruby in `~/.rubies/ruby-master`, so create the directory:
- ``` shell
+ ```
mkdir ~/.rubies
```
-4. Run configure:
+7. Run configure:
- ``` shell
+ ```
../configure --prefix="${HOME}/.rubies/ruby-master"
```
- If you are frequently building Ruby, add the `--disable-install-doc` flag to not build documentation which will speed up the build process.
- - Also `-C` (or `--config-cache`) would reduce time to configure from the next time.
-
-5. Build Ruby:
+8. Build Ruby:
- ``` shell
+ ```
make install
```
-6. [Run tests](testing_ruby.md) to confirm your build succeeded.
+ - If you're on macOS and installed \OpenSSL through Homebrew, you may encounter failure to build \OpenSSL that look like this:
-### Unexplainable Build Errors
+ ```
+ openssl:
+ Could not be configured. It will not be installed.
+ ruby/ext/openssl/extconf.rb: OpenSSL library could not be found. You might want to use --with-openssl-dir=<dir> option to specify the prefix where OpenSSL is installed.
+ Check ext/openssl/mkmf.log for more details.
+ ```
-If you are having unexplainable build errors, after saving all your work, try running `git clean -xfd` in the source root to remove all git ignored local files. If you are working from a source directory that's been updated several times, you may have temporary build artifacts from previous releases which can cause build failures.
+ Adding `--with-openssl-dir=$(brew --prefix openssl)` to the list of options passed to configure may solve the issue.
+
+ Remember to delete your `build` directory and start again from the configure step.
-## Building on Windows
+9. [Run tests](testing_ruby.md) to confirm your build succeeded.
-The documentation for building on Windows can be found [here](../windows.md).
+### Unexplainable Build Errors
+
+If you are having unexplainable build errors, after saving all your work, try running `git clean -xfd` in the source root to remove all git ignored local files. If you are working from a source directory that's been updated several times, you may have temporary build artifacts from previous releases which can cause build failures.
## More details
@@ -119,7 +89,7 @@ about Ruby's build to help out.
In GNU make and BSD make implementations, to run a specific make script in parallel, pass the flag `-j<number of processes>`. For instance,
to run tests on 8 processes, use:
-``` shell
+```
make test-all -j8
```
@@ -147,7 +117,7 @@ Miniruby is a version of Ruby which has no external dependencies and lacks certa
It can be useful in Ruby development because it allows for faster build times. Miniruby is
built before Ruby. A functional Miniruby is required to build Ruby. To build Miniruby:
-``` shell
+```
make miniruby
```
@@ -163,14 +133,6 @@ with the Ruby script you'd like to run. You can use the following make targets:
* `make lldb-ruby`: Runs `test.rb` using Ruby in lldb
* `make gdb-ruby`: Runs `test.rb` using Ruby in gdb
-### Compiling for Debugging
-
-You should configure Ruby without optimization and other flags that may interfere with debugging:
-
-``` shell
-./configure --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
-```
-
### Building with Address Sanitizer
Using the address sanitizer is a great way to detect memory issues.
@@ -189,7 +151,7 @@ On Linux it is important to specify `-O0` when debugging. This is especially tru
You need to be able to use gcc (gcov) and lcov visualizer.
-``` shell
+```
./autogen.sh
./configure --enable-gcov
make
diff --git a/doc/contributing/documentation_guide.md b/doc/contributing/documentation_guide.md
index af91817003..9cfd59d629 100644
--- a/doc/contributing/documentation_guide.md
+++ b/doc/contributing/documentation_guide.md
@@ -20,16 +20,14 @@ build directory:
make html
```
-If you don't have a build directory, follow the [quick start
-guide](building_ruby.md#label-Quick+start+guide) up to step 4.
-
Then you can preview your changes by opening
`{build folder}/.ext/html/index.html` file in your browser.
+
## Goal
The goal of Ruby documentation is to impart the most important
-and relevant information in the shortest time.
+and relevant in the shortest time.
The reader should be able to quickly understand the usefulness
of the subject code and how to use it.
@@ -43,17 +41,16 @@ Use your judgment about what the user needs to know.
- Write short declarative or imperative sentences.
- Group sentences into (ideally short) paragraphs,
each covering a single topic.
-- Organize material with
- [headings](rdoc-ref:RDoc::MarkupReference@Headings).
+- Organize material with [headers](rdoc-ref:RDoc::Markup@Headers).
- Refer to authoritative and relevant sources using
- [links](rdoc-ref:RDoc::MarkupReference@Links).
+ [links](rdoc-ref:RDoc::Markup@Links).
- Use simple verb tenses: simple present, simple past, simple future.
- Use simple sentence structure, not compound or complex structure.
- Avoid:
- Excessive comma-separated phrases;
- consider a [list](rdoc-ref:RDoc::MarkupReference@Lists).
+ consider a [list](rdoc-ref:RDoc::Markup@Simple+Lists).
- Idioms and culture-specific references.
- - Overuse of headings.
+ - Overuse of headers.
- Using US-ASCII-incompatible characters in C source files;
see [Characters](#label-Characters) below.
@@ -127,23 +124,16 @@ a.shuffle! #=> [2, 3, 1]
a #=> [2, 3, 1]
```
-### Headings
-
-Organize a long discussion for a class or module with [headings](rdoc-ref:RDoc::MarkupReference@Headings).
+### Headers
-Do not use formal headings in the documentation for a method or constant.
-
-In the rare case where heading-like structures are needed
-within the documentation for a method or constant, use
-[bold text](rdoc-ref:RDoc::MarkupReference@Bold)
-as pseudo-headings.
+Organize a long discussion with [headers](rdoc-ref:RDoc::Markup@Headers).
### Blank Lines
A blank line begins a new paragraph.
-A [code block](rdoc-ref:RDoc::MarkupReference@Code+Blocks)
-or [list](rdoc-ref:RDoc::MarkupReference@Lists)
+A [code block](rdoc-ref:RDoc::Markup@Paragraphs+and+Verbatim)
+or [list](rdoc-ref:RDoc::Markup@Simple+Lists)
should be preceded by and followed by a blank line.
This is unnecessary for the HTML output, but helps in the `ri` output.
@@ -160,14 +150,6 @@ For a method name in text:
or a hash mark for an instance method:
<tt>Foo.bar</tt>, <tt>Foo#baz</tt>.
-### Embedded Code and Commands
-
-Code or commands embedded in running text (i.e., not in a code block)
-should marked up as
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
-
-Code that is a simple string should include the quote marks.
-
### Auto-Linking
In general, \RDoc's auto-linking should not be suppressed.
@@ -181,31 +163,6 @@ We might consider whether to suppress when:
(e.g., _Array_ in the documentation for class `Array`).
- The same reference is repeated many times
(e.g., _RDoc_ on this page).
-- The reference is to a class or module that users
- usually don't deal with, including these:
-
- - \Class.
- - \Method.
- - \Module.
-
-Most often, the name of a class, module, or method
-will be autolinked:
-
-- Array.
-- Enumerable.
-- File.new
-- File#read.
-
-If not, or if you suppress autolinking, consider forcing
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
-
-### Variable Names
-
-The name of a variable (as specified in its call-seq) should be marked up as
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
-
-Also, use monofont text for the name of a transient variable
-(i.e., one defined and used only in the discussion, such as +n+).
### HTML Tags
@@ -218,21 +175,16 @@ may not render them properly.
In particular, avoid building tables with HTML tags
(<tt><table></tt>, etc.).
-Alternatives:
-
-- A {verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks],
- using spaces and punctuation to format the text;
- note that {text markup}[rdoc-ref:RDoc::MarkupReference@Text+Markup]
- will not be honored:
-
- - Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/file.c#L6570-L6596].
- - Corresponding {output}[rdoc-ref:File@Read-2FWrite+Mode].
+Alternatives are:
-- (Markdown format only): A {Github Flavored Markdown (GFM) table}[https://github.github.com/gfm/#tables-extension-],
- using special formatting for the text:
+- The GFM (GitHub Flavored Markdown) table extension,
+ which is enabled by default. See
+ {GFM tables extension}[https://github.github.com/gfm/#tables-extension-].
- - Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/doc/contributing/glossary.md?plain=1].
- - Corresponding {output}[https://docs.ruby-lang.org/en/master/contributing/glossary_md.html].
+- A {verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks],
+ using spaces and punctuation to format the text.
+ Note that {text markup}[rdoc-ref:RDoc::MarkupReference@Text+Markup]
+ will not be honored.
## Documenting Classes and Modules
@@ -262,7 +214,7 @@ Guidelines:
- The section title is `What's Here`.
- Consider listing the parent class and any included modules; consider
- [links](rdoc-ref:RDoc::MarkupReference@Links)
+ [links](rdoc-ref:RDoc::Markup@Links)
to their "What's Here" sections if those exist.
- List methods as a bullet list:
@@ -272,9 +224,9 @@ Guidelines:
(and do not list the aliases separately).
- Check the rendered documentation to determine whether \RDoc has recognized
the method and linked to it; if not, manually insert a
- [link](rdoc-ref:RDoc::MarkupReference@Links).
+ [link](rdoc-ref:RDoc::Markup@Links).
-- If there are numerous entries, consider grouping them into subsections with headings.
+- If there are numerous entries, consider grouping them into subsections with headers.
- If there are more than a few such subsections,
consider adding a table of contents just below the main section title.
@@ -289,6 +241,7 @@ The general structure of the method documentation should be:
- Details and examples.
- Argument description (if necessary).
- Corner cases and exceptions.
+- Aliases.
- Related methods (optional).
### Calling Sequence (for methods written in C)
@@ -297,7 +250,7 @@ For methods written in Ruby, \RDoc documents the calling sequence automatically.
For methods written in C, \RDoc cannot determine what arguments
the method accepts, so those need to be documented using \RDoc directive
-[`call-seq:`](rdoc-ref:RDoc::MarkupReference@Directives+for+Method+Documentation).
+[`call-seq:`](rdoc-ref:RDoc::Markup@Method+arguments).
For a singleton method, use the form:
@@ -375,11 +328,7 @@ Return types:
Aliases:
-- Omit aliases from the `call-seq`, unless the alias is an
- operator method. If listing both a regular method and an
- operator method in the `call-seq`, explain in the details and
- examples section when it is recommended to use the regular method
- and when it is recommended to use the operator method.
+- Omit aliases from the `call-seq`, but mention them near the end (see below).
### Synopsis
@@ -436,7 +385,7 @@ argument passed if it is not obvious, not explicitly mentioned in the
details, and not implicitly shown in the examples.
If there is more than one argument or block argument, use a
-[labeled list](rdoc-ref:RDoc::MarkupReference@Labeled+Lists).
+[labeled list](rdoc-ref:RDoc::Markup@Labeled+Lists).
### Corner Cases and Exceptions
@@ -449,6 +398,14 @@ you do not need to document that a `TypeError` is raised if a non-integer
is passed. Do not provide examples of exceptions being raised unless
that is a common case, such as `Hash#fetch` raising a `KeyError`.
+### Aliases
+
+Mention aliases in the form
+
+```
+// Array#find_index is an alias for Array#index.
+```
+
### Related Methods (optional)
In some cases, it is useful to document which methods are related to
diff --git a/doc/contributing/glossary.md b/doc/contributing/glossary.md
deleted file mode 100644
index 0d27d28c96..0000000000
--- a/doc/contributing/glossary.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Ruby Internals Glossary
-
-Just a list of acronyms I've run across in the Ruby source code and their meanings.
-
-| Term | Definition |
-| --- | -----------|
-| `BIN` | Basic Instruction Name. Used as a macro to reference the YARV instruction. Converts pop into YARVINSN_pop. |
-| `bop` | Basic Operator. Relates to methods like `Integer` plus and minus which can be optimized as long as they haven't been redefined. |
-| `cc` | Call Cache. An inline cache structure for the call site. Stored in the `cd` |
-| `cd` | Call Data. A data structure that points at the `ci` and the `cc`. `iseq` objects points at the `cd`, and access call information and call caches via this structure |
-| `cfp`| Control Frame Pointer. Represents a Ruby stack frame. Calling a method pushes a new frame (cfp), returning pops a frame. Points at the `pc`, `sp`, `ep`, and the corresponding `iseq`|
-| `ci` | Call Information. Refers to an `rb_callinfo` struct. Contains call information about the call site, including number of parameters to be passed, whether it they are keyword arguments or not, etc. Used in conjunction with the `cc` and `cd`. |
-| `cref` | Class reference. A structure pointing to the class reference where `klass_or_self`, visibility scope, and refinements are stored. It also stores a pointer to the next class in the hierachy referenced by `rb_cref_struct * next`. The Class reference is lexically scoped. |
-| CRuby | Implementation of Ruby written in C |
-| `cvar` | Class Variable. Refers to a Ruby class variable like `@@foo` |
-| `dvar` | Dynamic Variable. Used by the parser to refer to local variables that are defined outside of the current lexical scope. For example `def foo; bar = 1; -> { p bar }; end` the "bar" inside the block is a `dvar` |
-| `ec` | Execution Context. The top level VM context, points at the current `cfp` |
-| `ep` | Environment Pointer. Local variables, including method parameters are stored in the `ep` array. The `ep` is pointed to by the `cfp` |
-| GC | Garbage Collector |
-| `gvar` | Global Variable. Refers to a Ruby global variable like `$$`, etc |
-| `ICLASS` | Internal Class. When a module is included, the target class gets a new superclass which is an instance of an `ICLASS`. The `ICLASS` represents the module in the inheritance chain. |
-| `ifunc` | Internal FUNCtion. A block implemented in C. |
-| `iseq` | Instruction Sequence. Usually "iseq" in the C code will refer to an `rb_iseq_t` object that holds a reference to the actual instruction sequences which are executed by the VM. The object also holds information about the code, like the method name associated with the code. |
-| `insn` | Instruction. Refers to a YARV instruction. |
-| `insns` | Instructions. Usually an array of YARV instructions. |
-| `ivar` | Instance Variable. Refers to a Ruby instance variable like `@foo` |
-| `imemo` | Internal Memo. A tagged struct whose memory is managed by Ruby's GC, but contains internal information and isn't meant to be exposed to Ruby programs. Contains various information depending on the type. See the `imemo_type` enum for different types. |
-| JIT | Just In Time compiler |
-| `lep` | Local Environment Pointer. An `ep` which is tagged `VM_ENV_FLAG_LOCAL`. Usually this is the `ep` of a method (rather than a block, whose `ep` isn't "local") |
-| `local` | Local. Refers to a local variable. |
-| `me` | Method Entry. Refers to an `rb_method_entry_t` struct, the internal representation of a Ruby method.
-| MRI | Matz's Ruby Implementation |
-| `pc` | Program Counter. Usually the instruction that will be executed _next_ by the VM. Pointed to by the `cfp` and incremented by the VM |
-| `sp` | Stack Pointer. The top of the stack. The VM executes instructions in the `iseq` and instructions will push and pop values on the stack. The VM updates the `sp` on the `cfp` to point at the top of the stack|
-| `svar` | Special Variable. Refers to special local variables like `$~` and `$_`. See the `getspecial` instruction in `insns.def` |
-| `VALUE` | VALUE is a pointer to a ruby object from the Ruby C code. |
-| VM | Virtual Machine. In MRI's case YARV (Yet Another Ruby VM)
-| WB | Write Barrier. To do with GC write barriers |
-| WC | Wild Card. As seen in instructions like `getlocal_WC_0`. It means this instruction takes a "wild card" for the parameter (in this case an index for a local) |
-| YARV | Yet Another Ruby VM. The virtual machine that CRuby uses |
-| ZOMBIE | A zombie object. An object that has a finalizer which hasn't been executed yet. The object has been collected, so is "dead", but the finalizer hasn't run yet so it's still somewhat alive. |
diff --git a/doc/contributing/making_changes_to_stdlibs.md b/doc/contributing/making_changes_to_stdlibs.md
index 3b33092fea..ef3811ea12 100644
--- a/doc/contributing/making_changes_to_stdlibs.md
+++ b/doc/contributing/making_changes_to_stdlibs.md
@@ -8,7 +8,7 @@ For example, CSV lives in [a separate repository](https://github.com/ruby/csv) a
## Maintainers
-You can find the list of maintainers [here](https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Maintainers).
+You can find the list of maintainers [here](https://docs.ruby-lang.org/en/master/maintainers_rdoc.html#label-Maintainers).
## Build
diff --git a/doc/contributing/testing_ruby.md b/doc/contributing/testing_ruby.md
index dfb7fb3a65..6247686efc 100644
--- a/doc/contributing/testing_ruby.md
+++ b/doc/contributing/testing_ruby.md
@@ -70,7 +70,7 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
first the file name, and then the test name, prefixed with `--name`. For example:
```
- make test-all TESTS="../test/ruby/test_alias.rb --name=TestAlias#test_alias_with_zsuper_method"
+ make test-all TESTS="../test/ruby/test_alias.rb --name=/test_alias_with_zsuper_method/"
```
To run these specs with logs, we can use:
@@ -79,13 +79,7 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
make test-all TESTS=-v
```
- We can display the help of the `TESTS` option:
-
- ```
- make test-all TESTS=--help
- ```
-
- If we would like to run the `test/`, `bootstraptest/` and `spec/` test suites (the `spec/` is explained in a later section), we can run
+ If we would like to run both the `test/` and `bootstraptest/` test suites, we can run
```
make check
@@ -99,28 +93,28 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
make test-spec
```
- To run a specific directory, we can use `SPECOPTS` to specify the directory:
+ To run a specific directory, we can use `MSPECOPT` to specify the directory:
```
- make test-spec SPECOPTS=spec/ruby/core/array
+ make test-spec MSPECOPT=spec/ruby/core/array
```
- To run a specific file, we can also use `SPECOPTS` to specify the file:
+ To run a specific file, we can also use `MSPECOPT` to specify the file:
```
- make test-spec SPECOPTS=spec/ruby/core/array/any_spec.rb
+ make test-spec MSPECOPT=spec/ruby/core/array/any_spec.rb
```
To run a specific test, we can use the `--example` flag to match against the test name:
```
- make test-spec SPECOPTS="../spec/ruby/core/array/any_spec.rb --example='is false if the array is empty'"
+ make test-spec MSPECOPT="../spec/ruby/core/array/any_spec.rb --example='is false if the array is empty'"
```
To run these specs with logs, we can use:
```
- make test-spec SPECOPTS=-Vfs
+ make test-spec MSPECOPT=-Vfs
```
To run a ruby-spec file or directory with GNU make, we can use
@@ -140,17 +134,5 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
To run a specific bundler spec file, we can use `BUNDLER_SPECS` as follows:
```
- make test-bundler BUNDLER_SPECS=commands/exec_spec.rb
+ $ make test-bundler BUNDLER_SPECS=commands/exec_spec.rb
```
-
-## Troubleshooting
-
-### Running test suites on s390x CPU Architecture
-
-If we see failing tests related to the zlib library on s390x CPU architecture, we can run the test suites with `DFLTCC=0` to pass:
-
-```
-DFLTCC=0 make check
-```
-
-The failures can happen with the zlib library applying the patch [madler/zlib#410](https://github.com/madler/zlib/pull/410) to enable the deflate algorithm producing a different compressed byte stream. We manage this issue at [[ruby-core:114942][Bug #19909]](https://bugs.ruby-lang.org/issues/19909).
diff --git a/doc/csv/options/common/col_sep.rdoc b/doc/csv/options/common/col_sep.rdoc
index 3f23c6d2d3..05769b5773 100644
--- a/doc/csv/options/common/col_sep.rdoc
+++ b/doc/csv/options/common/col_sep.rdoc
@@ -55,3 +55,9 @@ Raises an exception if parsing with the empty \String:
# Raises ArgumentError (:col_sep must be 1 or more characters: "")
CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
+Raises an exception if the given value is not String-convertible:
+ col_sep = BasicObject.new
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.generate(line, col_sep: col_sep)
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.parse(str, col_sep: col_sep)
diff --git a/doc/csv/options/common/row_sep.rdoc b/doc/csv/options/common/row_sep.rdoc
index eae15b4a84..872d9d1f3f 100644
--- a/doc/csv/options/common/row_sep.rdoc
+++ b/doc/csv/options/common/row_sep.rdoc
@@ -89,3 +89,12 @@ if any of the following is true:
* The stream is only available for output.
Obviously, discovery takes a little time. Set manually if speed is important. Also note that IO objects should be opened in binary mode on Windows if this feature will be used as the line-ending translation can cause problems with resetting the document position to where it was before the read ahead.
+
+---
+
+Raises an exception if the given value is not String-convertible:
+ row_sep = BasicObject.new
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.generate(ary, row_sep: row_sep)
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.parse(str, row_sep: row_sep)
diff --git a/doc/csv/options/generating/write_converters.rdoc b/doc/csv/options/generating/write_converters.rdoc
index d1a9cc748f..6e5fae5fda 100644
--- a/doc/csv/options/generating/write_converters.rdoc
+++ b/doc/csv/options/generating/write_converters.rdoc
@@ -23,3 +23,11 @@ With two write converters (called in order):
str # => "a,b,c\n"
See also {Write Converters}[#class-CSV-label-Write+Converters]
+
+---
+
+Raises an exception if the converter returns a value that is neither +nil+
+nor \String-convertible:
+ bad_converter = proc {|field| BasicObject.new }
+ # Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
+ CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter) \ No newline at end of file
diff --git a/doc/csv/options/generating/write_headers.rdoc b/doc/csv/options/generating/write_headers.rdoc
index c56aa48adb..f9faa9d438 100644
--- a/doc/csv/options/generating/write_headers.rdoc
+++ b/doc/csv/options/generating/write_headers.rdoc
@@ -19,7 +19,7 @@ Without +write_headers+:
With +write_headers+":
CSV.open(file_path,'w',
- :write_headers => true,
+ :write_headers=> true,
:headers => ['Name','Value']
) do |csv|
csv << ['foo', '0']
diff --git a/doc/csv/options/parsing/liberal_parsing.rdoc b/doc/csv/options/parsing/liberal_parsing.rdoc
index 603de28613..b8b9b00c98 100644
--- a/doc/csv/options/parsing/liberal_parsing.rdoc
+++ b/doc/csv/options/parsing/liberal_parsing.rdoc
@@ -1,13 +1,13 @@
====== Option +liberal_parsing+
-Specifies the boolean or hash value that determines whether
+Specifies the boolean value that determines whether
CSV will attempt to parse input not conformant with RFC 4180,
such as double quotes in unquoted fields.
Default value:
CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
-For the next two examples:
+For examples in this section:
str = 'is,this "three, or four",fields'
Without +liberal_parsing+:
@@ -17,22 +17,3 @@ Without +liberal_parsing+:
With +liberal_parsing+:
ary = CSV.parse_line(str, liberal_parsing: true)
ary # => ["is", "this \"three", " or four\"", "fields"]
-
-Use the +backslash_quote+ sub-option to parse values that use
-a backslash to escape a double-quote character. This
-causes the parser to treat <code>\"</code> as if it were
-<code>""</code>.
-
-For the next two examples:
- str = 'Show,"Harry \"Handcuff\" Houdini, the one and only","Tampa Theater"'
-
-With +liberal_parsing+, but without the +backslash_quote+ sub-option:
- # Incorrect interpretation of backslash; incorrectly interprets the quoted comma as a field separator.
- ary = CSV.parse_line(str, liberal_parsing: true)
- ary # => ["Show", "\"Harry \\\"Handcuff\\\" Houdini", " the one and only\"", "Tampa Theater"]
- puts ary[1] # => "Harry \"Handcuff\" Houdini
-
-With +liberal_parsing+ and its +backslash_quote+ sub-option:
- ary = CSV.parse_line(str, liberal_parsing: { backslash_quote: true })
- ary # => ["Show", "Harry \"Handcuff\" Houdini, the one and only", "Tampa Theater"]
- puts ary[1] # => Harry "Handcuff" Houdini, the one and only
diff --git a/doc/csv/recipes/filtering.rdoc b/doc/csv/recipes/filtering.rdoc
index 1552bf0fb8..470649d09a 100644
--- a/doc/csv/recipes/filtering.rdoc
+++ b/doc/csv/recipes/filtering.rdoc
@@ -1,7 +1,5 @@
== Recipes for Filtering \CSV
-These recipes are specific code examples for specific \CSV filtering tasks.
-
For other recipes, see {Recipes for CSV}[./recipes_rdoc.html].
All code snippets on this page assume that the following has been executed:
diff --git a/doc/csv/recipes/generating.rdoc b/doc/csv/recipes/generating.rdoc
index a6bd88a714..3ef6df99b4 100644
--- a/doc/csv/recipes/generating.rdoc
+++ b/doc/csv/recipes/generating.rdoc
@@ -1,7 +1,5 @@
== Recipes for Generating \CSV
-These recipes are specific code examples for specific \CSV generating tasks.
-
For other recipes, see {Recipes for CSV}[./recipes_rdoc.html].
All code snippets on this page assume that the following has been executed:
@@ -146,7 +144,7 @@ This example defines and uses a custom write converter to strip whitespace from
==== Recipe: Specify Multiple Write Converters
-Use option <tt>:write_converters</tt> and multiple custom converters
+Use option <tt>:write_converters</tt> and multiple custom coverters
to convert field values when generating \CSV.
This example defines and uses two custom write converters to strip and upcase generated fields:
diff --git a/doc/csv/recipes/parsing.rdoc b/doc/csv/recipes/parsing.rdoc
index f3528fbdf1..7ac96a934b 100644
--- a/doc/csv/recipes/parsing.rdoc
+++ b/doc/csv/recipes/parsing.rdoc
@@ -1,7 +1,5 @@
== Recipes for Parsing \CSV
-These recipes are specific code examples for specific \CSV parsing tasks.
-
For other recipes, see {Recipes for CSV}[./recipes_rdoc.html].
All code snippets on this page assume that the following has been executed:
@@ -520,7 +518,7 @@ Apply multiple header converters by defining and registering a custom header con
To capture unconverted field values, use option +:unconverted_fields+:
source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
parsed = CSV.parse(source, converters: :integer, unconverted_fields: true)
- parsed # => [["Name", "Value"], ["foo", 0], ["bar", 1], ["baz", 2]]
+ parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
parsed.each {|row| p row.unconverted_fields }
Output:
["Name", "Value"]
diff --git a/doc/csv/recipes/recipes.rdoc b/doc/csv/recipes/recipes.rdoc
index 9bf7885b1e..9e4eaa1da4 100644
--- a/doc/csv/recipes/recipes.rdoc
+++ b/doc/csv/recipes/recipes.rdoc
@@ -1,6 +1,6 @@
== Recipes for \CSV
-The recipes are specific code examples for specific tasks. See:
+See:
- {Recipes for Parsing CSV}[./parsing_rdoc.html]
- {Recipes for Generating CSV}[./generating_rdoc.html]
- {Recipes for Filtering CSV}[./filtering_rdoc.html]
diff --git a/doc/distribution.md b/doc/distribution.md
deleted file mode 100644
index bc89a7500a..0000000000
--- a/doc/distribution.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Distribution
-
-This document outlines the expected way to distribute Ruby, with a specific focus on building Ruby packages.
-
-## Getting the Ruby Tarball
-
-### Official Releases
-
-The tarball for official releases is created by the release manager. The release manager uploads the tarball to the [Ruby website](https://www.ruby-lang.org/en/downloads/).
-
-Downstream distributors should use the official release tarballs as part of their build process. This ensures that the tarball is created in a consistent way, and that the tarball is crytographically verified.
-
-### Using the nightly tarball for testing
-
-See the Snapshots section of the [Ruby website](https://www.ruby-lang.org/en/downloads/).
-
-### Building a manual snapshot tarball for testing
-
-This can be useful if the nightly tarball does not have all changes yet.
-
-At Ruby source tree cloned using git:
-```sh-session
-$ ./autogen.sh
-$ ./configure -C
-$ make
-$ make dist
-```
-
-This will create several tarball in the `tmp` directory. The tarball will be named e.g. `ruby-<version>.tar.gz` (several different compression formats will be generated).
-
-## Building the Tarball
-
-See [Building Ruby](contributing/building_ruby.md).
-
-## Updating the Ruby Standard Library
-
-The Ruby standard library is a collection of Ruby files that are included with Ruby. These files are used to provide the basic functionality of Ruby. The standard library is located in the `lib` directory and is distributed as part of the Ruby tarball.
-
-Occasionally, the standard library needs to be updated, for example a security issue might be found in a default gem or standard gem. There are two main ways that Ruby would update this code.
-
-### Releasing an Updated Ruby Gem
-
-Normally, the Ruby gem maintainer will release an updated gem. This gem can be installed alongside the default gem. This allows the user to update the gem without having to update Ruby.
-
-### Releasing a New Ruby Version
-
-If the update is critical, then the Ruby maintainers may decide to release a new version of Ruby. This new version will include the updated standard library.
diff --git a/doc/encodings.rdoc b/doc/encodings.rdoc
index 914f5d3afa..1f3c54d740 100644
--- a/doc/encodings.rdoc
+++ b/doc/encodings.rdoc
@@ -137,16 +137,15 @@ returns the \Encoding of the concatenated string, or +nil+ if incompatible:
A Ruby String object has an encoding that is an instance of class \Encoding.
The encoding may be retrieved by method String#encoding.
-The default encoding for a string literal is the script encoding;
-see {Script Encoding}[rdoc-ref:encodings.rdoc@Script+Encoding].
+The default encoding for a string literal is the script encoding
+(see Encoding@Script+encoding):
's'.encoding # => #<Encoding:UTF-8>
The default encoding for a string created with method String.new is:
- For a \String object argument, the encoding of that string.
-- For a string literal, the script encoding;
- see {Script Encoding}[rdoc-ref:encodings.rdoc@Script+Encoding].
+- For a string literal, the script encoding (see Encoding@Script+encoding).
In either case, any encoding may be specified:
@@ -191,8 +190,7 @@ the encoding may be retrieved by method Symbol#encoding or Regexp#encoding.
The default encoding for these, however, is:
- US-ASCII, if all characters are US-ASCII.
-- The script encoding, otherwise;
- see (Script Encoding)[rdoc-ref:encodings.rdoc@Script+Encoding].
+- The script encoding, otherwise (see Encoding@Script+encoding).
=== Filesystem \Encoding
diff --git a/doc/extension.ja.rdoc b/doc/extension.ja.rdoc
index bde907c916..93f5753cd1 100644
--- a/doc/extension.ja.rdoc
+++ b/doc/extension.ja.rdoc
@@ -888,12 +888,12 @@ dbm.cではTypedData_Make_Structを以下のように使っています.
obj = TypedData_Make_Struct(klass, struct dbmdata, &dbm_type, dbmp);
-ここではdbmdata構造体へのポインタをRubyオブジェクトにカプセ
-ル化しています.DBM*を直接カプセル化しないのはclose()した時
-の処理を考えてのことです.
+ここではdbmdata構造体へのポインタをDataにカプセル化してい
+ます.DBM*を直接カプセル化しないのはclose()した時の処理を考
+えてのことです.
-Rubyオブジェクトからdbmdata構造体のポインタを取り出すために
-以下のマクロを使っています.
+Dataオブジェクトからdbmstruct構造体のポインタを取り出すため
+に以下のマクロを使っています.
#define GetDBM(obj, dbmp) do {\
TypedData_Get_Struct((obj), struct dbmdata, &dbm_type, (dbmp));\
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index 5089272599..ad9ae641d2 100644
--- a/doc/extension.rdoc
+++ b/doc/extension.rdoc
@@ -1,6 +1,6 @@
# extension.rdoc - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995
-= Creating extension libraries for Ruby
+= Creating Extension Libraries for Ruby
This document explains how to make extension libraries for Ruby.
@@ -10,8 +10,8 @@ In C, variables have types and data do not have types. In contrast,
Ruby variables do not have a static type, and data themselves have
types, so data will need to be converted between the languages.
-Objects in Ruby are represented by the C type `VALUE'. Each VALUE
-data has its data type.
+Data in Ruby are represented by the C type `VALUE'. Each VALUE data
+has its data type.
To retrieve C data from a VALUE, you need to:
@@ -20,7 +20,7 @@ To retrieve C data from a VALUE, you need to:
Converting to the wrong data type may cause serious problems.
-=== Ruby data types
+=== Data Types
The Ruby interpreter has the following data types:
@@ -54,7 +54,7 @@ T_ZOMBIE :: object awaiting finalization
Most of the types are represented by C structures.
-=== Check type of the VALUE data
+=== Check Data Type of the VALUE
The macro TYPE() defined in ruby.h shows the data type of the VALUE.
TYPE() returns the constant number T_XXXX described above. To handle
@@ -88,7 +88,7 @@ There are also faster check macros for fixnums and nil.
FIXNUM_P(obj)
NIL_P(obj)
-=== Convert VALUE into C data
+=== Convert VALUE into C Data
The data for type T_NIL, T_FALSE, T_TRUE are nil, false, true
respectively. They are singletons for the data type.
@@ -143,7 +143,7 @@ Notice: Do not change the value of the structure directly, unless you
are responsible for the result. This ends up being the cause of
interesting bugs.
-=== Convert C data into VALUE
+=== Convert C Data into VALUE
To convert C data to Ruby values:
@@ -169,14 +169,14 @@ INT2NUM() :: for arbitrary sized integers.
INT2NUM() converts an integer into a Bignum if it is out of the FIXNUM
range, but is a bit slower.
-=== Manipulating Ruby object
+=== Manipulating Ruby Data
As I already mentioned, it is not recommended to modify an object's
internal structure. To manipulate objects, use the functions supplied
by the Ruby interpreter. Some (not all) of the useful functions are
listed below:
-==== String functions
+==== String Functions
rb_str_new(const char *ptr, long len) ::
@@ -279,7 +279,7 @@ rb_str_modify(VALUE str) ::
you MUST call this function before modifying the contents using
RSTRING_PTR and/or rb_str_set_len.
-==== Array functions
+==== Array Functions
rb_ary_new() ::
@@ -338,13 +338,13 @@ rb_ary_cat(VALUE ary, const VALUE *ptr, long len) ::
== Extending Ruby with C
-=== Adding new features to Ruby
+=== Adding New Features to Ruby
You can add new features (classes, methods, etc.) to the Ruby
interpreter. Ruby provides APIs for defining the following things:
- Classes, Modules
-- Methods, singleton methods
+- Methods, Singleton Methods
- Constants
==== Class and Module Definition
@@ -362,7 +362,7 @@ To define nested classes or modules, use the functions below:
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
VALUE rb_define_module_under(VALUE outer, const char *name)
-==== Method and singleton method definition
+==== Method and Singleton Method Definition
To define methods or singleton methods, use these functions:
@@ -467,7 +467,7 @@ available), you can use:
VALUE rb_current_receiver(void)
-==== Constant definition
+==== Constant Definition
We have 2 functions to define constants:
@@ -477,11 +477,11 @@ We have 2 functions to define constants:
The former is to define a constant under specified class/module. The
latter is to define a global constant.
-=== Use Ruby features from C
+=== Use Ruby Features from C
There are several ways to invoke Ruby's features from C code.
-==== Evaluate Ruby programs in a string
+==== Evaluate Ruby Programs in a String
The easiest way to use Ruby's functionality from a C program is to
evaluate the string as Ruby program. This function will do the job:
@@ -550,7 +550,7 @@ and to convert Ruby Symbol object to ID, use
ID SYM2ID(VALUE symbol)
-==== Invoke Ruby method from C
+==== Invoke Ruby Method from C
To invoke methods directly, you can use the function below
@@ -559,7 +559,7 @@ To invoke methods directly, you can use the function below
This function invokes a method on the recv, with the method name
specified by the symbol mid.
-==== Accessing the variables and constants
+==== Accessing the Variables and Constants
You can access class variables and instance variables using access
functions. Also, global variables can be shared between both
@@ -578,9 +578,9 @@ To access the constants of the class/module:
See also Constant Definition above.
-== Information sharing between Ruby and C
+== Information Sharing Between Ruby and C
-=== Ruby constants that can be accessed from C
+=== Ruby Constants That Can Be Accessed From C
As stated in section 1.3,
the following Ruby constants can be referred from C.
@@ -594,7 +594,7 @@ Qnil ::
Ruby nil in C scope.
-=== Global variables shared between C and Ruby
+=== Global Variables Shared Between C and Ruby
Information can be shared between the two environments using shared global
variables. To define them, you can use functions listed below:
@@ -636,7 +636,7 @@ The prototypes of the getter and setter functions are as follows:
VALUE (*getter)(ID id);
void (*setter)(VALUE val, ID id);
-=== Encapsulate C data into a Ruby object
+=== Encapsulate C Data into a Ruby Object
Sometimes you need to expose your struct in the C world as a Ruby
object.
@@ -762,7 +762,7 @@ You can allocate and wrap the structure in one step.
TypedData_Make_Struct(klass, type, data_type, sval)
-This macro returns an allocated T_DATA object, wrapping the pointer to
+This macro returns an allocated Data object, wrapping the pointer to
the structure, which is also allocated. This macro works like:
(sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval))
@@ -771,65 +771,9 @@ Arguments klass and data_type work like their counterparts in
TypedData_Wrap_Struct(). A pointer to the allocated structure will
be assigned to sval, which should be a pointer of the type specified.
-==== Declaratively marking/compacting struct references
-
-In the case where your struct refers to Ruby objects that are simple values,
-not wrapped in conditional logic or complex data structures an alternative
-approach to marking and reference updating is provided, by declaring offset
-references to the VALUES in your struct.
-
-Doing this allows the Ruby GC to support marking these references and GC
-compaction without the need to define the `dmark` and `dcompact` callbacks.
-
-You must define a static list of VALUE pointers to the offsets within your
-struct where the references are located, and set the "data" member to point to
-this reference list. The reference list must end with `END_REFS`
-
-Some Macros have been provided to make edge referencing easier:
-
-* <code>RUBY_TYPED_DECL_MARKING</code> =A flag that can be set on the `ruby_data_type_t` to indicate that references are being declared as edges.
-
-* <code>RUBY_REFERENCES_START(ref_list_name)</code> - Define `ref_list_name` as a list of references
-
-* <code>RUBY_REFERENCES_END</code> - Mark the end of the references list. This will take care of terminating the list correctly
-
-* <code>RUBY_REF_EDGE\(struct, member\)</code> - Declare `member` as a VALUE edge from `struct`. Use this after `RUBY_REFERENCES_START`
-
-* +REFS_LIST_PTR+ - Coerce the reference list into a format that can be
- accepted by the existing `dmark` interface.
-
-The example below is from `Dir` (defined in `dir.c`)
-
- // The struct being wrapped. Notice this contains 3 members of which the second
- // is a VALUE reference to another ruby object.
- struct dir_data {
- DIR *dir;
- const VALUE path;
- rb_encoding *enc;
- }
-
- // Define a reference list `dir_refs` containing a single entry to `path`, and
- // terminating with RUBY_REF_END
- RUBY_REFERENCES_START(dir_refs)
- REF_EDGE(dir_data, path),
- RUBY_REFERENCES_END
-
- // Override the "dmark" field with the defined reference list now that we
- // no longer need a marking callback and add RUBY_TYPED_DECL_MARKING to the
- // flags field
- static const rb_data_type_t dir_data_type = {
- "dir",
- {REFS_LIST_PTR(dir_refs), dir_free, dir_memsize,},
- 0, NULL, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING
- };
-
-Declaring simple references declaratively in this manner allows the GC to both
-mark, and move the underlying object, and automatically update the reference to
-it during compaction.
-
==== Ruby object to C struct
-To retrieve the C pointer from the T_DATA object, use the macro
+To retrieve the C pointer from the Data object, use the macro
TypedData_Get_Struct().
TypedData_Get_Struct(obj, type, &data_type, sval)
@@ -844,7 +788,7 @@ OK, here's the example of making an extension library. This is the
extension to access DBMs. The full source is included in the ext/
directory in the Ruby's source tree.
-=== Make the directory
+=== Make the Directory
% mkdir ext/dbm
@@ -1055,7 +999,7 @@ If a compilation condition is not fulfilled, you should not call
``create_makefile''. The Makefile will not be generated, compilation will
not be done.
-=== Prepare depend (Optional)
+=== Prepare Depend (Optional)
If the file named depend exists, Makefile will include that file to
check dependencies. You can make this file by invoking
@@ -1094,15 +1038,15 @@ You may need to rb_debug the extension. Extensions can be linked
statically by adding the directory name in the ext/Setup file so that
you can inspect the extension with the debugger.
-=== Done! Now you have the extension library
+=== Done! Now You Have the Extension Library
You can do anything you want with your library. The author of Ruby
will not claim any restrictions on your code depending on the Ruby API.
Feel free to use, modify, distribute or sell your program.
-== Appendix A. Ruby header and source files overview
+== Appendix A. Ruby Header and Source Files Overview
-=== Ruby header files
+=== Ruby Header Files
Everything under <tt>$repo_root/include/ruby</tt> is installed with
<tt>make install</tt>.
@@ -1119,7 +1063,7 @@ Header files under <tt>$repo_root/internal/</tt> or directly under the
root <tt>$repo_root/*.h</tt> are not make-installed.
They are internal headers with only internal APIs.
-=== Ruby language core
+=== Ruby Language Core
class.c :: classes and modules
error.c :: exception classes and exception mechanism
@@ -1128,14 +1072,14 @@ load.c :: library loading
object.c :: objects
variable.c :: variables and constants
-=== Ruby syntax parser
+=== Ruby Syntax Parser
parse.y :: grammar definition
parse.c :: automatically generated from parse.y
defs/keywords :: reserved keywords
lex.c :: automatically generated from keywords
-=== Ruby evaluator (a.k.a. YARV)
+=== Ruby Evaluator (a.k.a. YARV)
compile.c
eval.c
@@ -1161,7 +1105,7 @@ lex.c :: automatically generated from keywords
-> opt*.inc : automatically generated
-> vm.inc : automatically generated
-=== Regular expression engine (Onigumo)
+=== Regular Expression Engine (Onigumo)
regcomp.c
regenc.c
@@ -1170,7 +1114,7 @@ lex.c :: automatically generated from keywords
regparse.c
regsyntax.c
-=== Utility functions
+=== Utility Functions
debug.c :: debug symbols for C debugger
dln.c :: dynamic loading
@@ -1178,7 +1122,7 @@ st.c :: general purpose hash table
strftime.c :: formatting times
util.c :: misc utilities
-=== Ruby interpreter implementation
+=== Ruby Interpreter Implementation
dmyext.c
dmydln.c
@@ -1192,7 +1136,7 @@ util.c :: misc utilities
gem_prelude.rb
prelude.rb
-=== Class library
+=== Class Library
array.c :: Array
bignum.c :: Bignum
@@ -1231,13 +1175,13 @@ transcode.c :: Encoding::Converter
enc/*.c :: encoding classes
enc/trans/* :: codepoint mapping tables
-=== goruby interpreter implementation
+=== goruby Interpreter Implementation
goruby.c
golf_prelude.rb : goruby specific libraries.
-> golf_prelude.c : automatically generated
-== Appendix B. Ruby extension API reference
+== Appendix B. Ruby Extension API Reference
=== Types
@@ -1247,7 +1191,7 @@ VALUE ::
such as struct RString, etc. To refer the values in structures, use
casting macros like RSTRING(obj).
-=== Variables and constants
+=== Variables and Constants
Qnil ::
@@ -1261,7 +1205,7 @@ Qfalse ::
false object
-=== C pointer wrapping
+=== C Pointer Wrapping
Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) ::
@@ -1281,7 +1225,7 @@ Data_Get_Struct(data, type, sval) ::
This macro retrieves the pointer value from DATA, and assigns it to
the variable sval.
-=== Checking VALUE types
+=== Checking Data Types
RB_TYPE_P(value, type) ::
@@ -1311,7 +1255,7 @@ void Check_Type(VALUE value, int type) ::
Ensures +value+ is of the given internal +type+ or raises a TypeError
-=== VALUE type conversion
+=== Data Type Conversion
FIX2INT(value), INT2FIX(i) ::
@@ -1395,7 +1339,7 @@ rb_str_new2(s) ::
char * -> String
-=== Defining classes and modules
+=== Defining Classes and Modules
VALUE rb_define_class(const char *name, VALUE super) ::
@@ -1422,7 +1366,7 @@ void rb_extend_object(VALUE object, VALUE module) ::
Extend the object with the module's attributes.
-=== Defining global variables
+=== Defining Global Variables
void rb_define_variable(const char *name, VALUE *var) ::
@@ -1466,7 +1410,7 @@ void rb_gc_register_mark_object(VALUE object) ::
Tells GC to protect the +object+, which may not be referenced anywhere.
-=== Constant definition
+=== Constant Definition
void rb_define_const(VALUE klass, const char *name, VALUE val) ::
@@ -1478,7 +1422,7 @@ void rb_define_global_const(const char *name, VALUE val) ::
rb_define_const(rb_cObject, name, val)
-=== Method definition
+=== Method Definition
rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc) ::
@@ -1654,7 +1598,7 @@ int rb_respond_to(VALUE obj, ID id) ::
Returns true if the object responds to the message specified by id.
-=== Instance variables
+=== Instance Variables
VALUE rb_iv_get(VALUE obj, const char *name) ::
@@ -1665,7 +1609,7 @@ VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) ::
Sets the value of the instance variable.
-=== Control structure
+=== Control Structure
VALUE rb_block_call(VALUE recv, ID mid, int argc, VALUE * argv, VALUE (*func) (ANYARGS), VALUE data2) ::
@@ -1761,7 +1705,7 @@ void rb_iter_break_value(VALUE value) ::
return the given argument value. This function never return to the
caller.
-=== Exceptions and errors
+=== Exceptions and Errors
void rb_warn(const char *fmt, ...) ::
@@ -1834,7 +1778,7 @@ int rb_wait_for_single_fd(int fd, int events, struct timeval *timeout) ::
Use a NULL +timeout+ to wait indefinitely.
-=== I/O multiplexing
+=== I/O Multiplexing
Ruby supports I/O multiplexing based on the select(2) system call.
The Linux select_tut(2) manpage
@@ -1886,7 +1830,7 @@ int rb_thread_fd_select(int nfds, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_
rb_io_wait_writable, or rb_wait_for_single_fd functions since
they can be optimized for specific platforms (currently, only Linux).
-=== Initialize and start the interpreter
+=== Initialize and Start the Interpreter
The embedding API functions are below (not needed for extension libraries):
@@ -1911,7 +1855,7 @@ void ruby_script(char *name) ::
Specifies the name of the script ($0).
-=== Hooks for the interpreter events
+=== Hooks for the Interpreter Events
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data) ::
@@ -1953,7 +1897,7 @@ void rb_gc_adjust_memory_usage(ssize_t diff) ::
is decreased; a memory block is freed or a block is reallocated as
smaller size. This function may trigger the GC.
-=== Macros for compatibility
+=== Macros for Compatibility
Some macros to check API compatibilities are available by default.
diff --git a/doc/globals.rdoc b/doc/globals.rdoc
index 2b4f6bd7cf..1d7cda69f9 100644
--- a/doc/globals.rdoc
+++ b/doc/globals.rdoc
@@ -1,422 +1,69 @@
-== Pre-Defined Global Variables
-
-Some of the pre-defined global variables have synonyms
-that are available via module Engish.
-For each of those, the \English synonym is given.
-
-To use the module:
-
- require 'English'
-
-=== Exceptions
-
-==== <tt>$!</tt> (\Exception)
-
-Contains the Exception object set by Kernel#raise:
-
- begin
- raise RuntimeError.new('Boo!')
- rescue RuntimeError
- p $!
- end
-
-Output:
-
- #<RuntimeError: Boo!>
-
-English - <tt>$ERROR_INFO</tt>
-
-==== <tt>$@</tt> (Backtrace)
-
-Same as <tt>$!.backtrace</tt>;
-returns an array of backtrace positions:
-
- begin
- raise RuntimeError.new('Boo!')
- rescue RuntimeError
- pp $@.take(4)
- end
-
-Output:
-
- ["(irb):338:in `<top (required)>'",
- "/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `eval'",
- "/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `evaluate'",
- "/snap/ruby/317/lib/ruby/3.2.0/irb/context.rb:502:in `evaluate'"]
-
-English - <tt>$ERROR_POSITION</tt>.
-
-=== Pattern Matching
-
-These global variables store information about the most recent
-successful match in the current scope.
-
-For details and examples,
-see {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
-
-==== <tt>$~</tt> (\MatchData)
-
-MatchData object created from the match;
-thread-local and frame-local.
-
-English - <tt>$LAST_MATCH_INFO</tt>.
-
-==== <tt>$&</tt> (Matched Substring)
-
-The matched string.
-
-English - <tt>$MATCH</tt>.
-
-==== <tt>$`</tt> (Pre-Match Substring)
-
-The string to the left of the match.
-
-English - <tt>$PREMATCH</tt>.
-
-==== <tt>$'</tt> (Post-Match Substring)
-
-The string to the right of the match.
-
-English - <tt>$POSTMATCH</tt>.
-
-==== <tt>$+</tt> (Last Matched Group)
-
-The last group matched.
-
-English - <tt>$LAST_PAREN_MATCH</tt>.
-
-==== <tt>$1</tt>, <tt>$2</tt>, \Etc. (Matched Group)
-
-For <tt>$_n_</tt> the _nth_ group of the match.
-
-No \English.
-
-=== Separators
-
-==== <tt>$/</tt> (Input Record Separator)
-
-An input record separator, initially newline.
-
-English - <tt>$INPUT_RECORD_SEPARATOR</tt>, <tt>$RS</tt>.
-
-Aliased as <tt>$-0</tt>.
-
-==== <tt>$;</tt> (Input Field Separator)
-
-An input field separator, initially +nil+.
-
-English - <tt>$FIELD_SEPARATOR</tt>, <tt>$FS</tt>.
-
-Aliased as <tt>$-F</tt>.
-
-==== <tt>$\\</tt> (Output Record Separator)
-
-An output record separator, initially +nil+.
-
-English - <tt>$OUTPUT_RECORD_SEPARATOR</tt>, <tt>$ORS</tt>.
-
-=== Streams
-
-==== <tt>$stdin</tt> (Standard Input)
-
-The current standard input stream; initially:
-
- $stdin # => #<IO:<STDIN>>
-
-==== <tt>$stdout</tt> (Standard Output)
-
-The current standard output stream; initially:
-
- $stdout # => #<IO:<STDOUT>>
-
-==== <tt>$stderr</tt> (Standard Error)
-
-The current standard error stream; initially:
-
- $stderr # => #<IO:<STDERR>>
-
-==== <tt>$<</tt> (\ARGF or $stdin)
-
-Points to stream ARGF if not empty, else to stream $stdin; read-only.
-
-English - <tt>$DEFAULT_INPUT</tt>.
-
-==== <tt>$></tt> (Default Standard Output)
-
-An output stream, initially <tt>$stdout</tt>.
-
-English - <tt>$DEFAULT_OUTPUT
-
-==== <tt>$.</tt> (Input Position)
-
-The input position (line number) in the most recently read stream.
-
-English - <tt>$INPUT_LINE_NUMBER</tt>, <tt>$NR</tt>
-
-==== <tt>$_</tt> (Last Read Line)
-
-The line (string) from the most recently read stream.
-
-English - <tt>$LAST_READ_LINE</tt>.
-
-=== Processes
-
-==== <tt>$0</tt>
-
-Initially, contains the name of the script being executed;
-may be reassigned.
-
-==== <tt>$*</tt> (\ARGV)
-
-Points to ARGV.
-
-English - <tt>$ARGV</tt>.
-
-==== <tt>$$</tt> (Process ID)
-
-The process ID of the current process. Same as Process.pid.
-
-English - <tt>$PROCESS_ID</tt>, <tt>$PID</tt>.
-
-==== <tt>$?</tt> (Child Status)
-
-Initially +nil+, otherwise the Process::Status object
-created for the most-recently exited child process;
-thread-local.
-
-English - <tt>$CHILD_STATUS</tt>.
-
-==== <tt>$LOAD_PATH</tt> (Load Path)
-
-Contains the array of paths to be searched
-by Kernel#load and Kernel#require.
-
-Singleton method <tt>$LOAD_PATH.resolve_feature_path(feature)</tt>
-returns:
-
-- <tt>[:rb, _path_]</tt>, where +path+ is the path to the Ruby file
- to be loaded for the given +feature+.
-- <tt>[:so+ _path_]</tt>, where +path+ is the path to the shared object file
- to be loaded for the given +feature+.
-- +nil+ if there is no such +feature+ and +path+.
-
-Examples:
-
- $LOAD_PATH.resolve_feature_path('timeout')
- # => [:rb, "/snap/ruby/317/lib/ruby/3.2.0/timeout.rb"]
- $LOAD_PATH.resolve_feature_path('date_core')
- # => [:so, "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/date_core.so"]
- $LOAD_PATH.resolve_feature_path('foo')
- # => nil
-
-Aliased as <tt>$:</tt> and <tt>$-I</tt>.
-
-==== <tt>$LOADED_FEATURES</tt>
-
-Contains an array of the paths to the loaded files:
-
- $LOADED_FEATURES.take(10)
- # =>
- ["enumerator.so",
- "thread.rb",
- "fiber.so",
- "rational.so",
- "complex.so",
- "ruby2_keywords.rb",
- "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/encdb.so",
- "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/trans/transdb.so",
- "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/rbconfig.rb",
- "/snap/ruby/317/lib/ruby/3.2.0/rubygems/compatibility.rb"]
-
-Aliased as <tt>$"</tt>.
-
-=== Debugging
-
-==== <tt>$FILENAME</tt>
-
-The value returned by method ARGF.filename.
-
-==== <tt>$DEBUG</tt>
-
-Initially +true+ if command-line option <tt>-d</tt> or <tt>--debug</tt> is given,
-otherwise initially +false+;
-may be set to either value in the running program.
-
-When +true+, prints each raised exception to <tt>$stderr</tt>.
-
-Aliased as <tt>$-d</tt>.
-
-==== <tt>$VERBOSE</tt>
-
-Initially +true+ if command-line option <tt>-v</tt> or <tt>-w</tt> is given,
-otherwise initially +false+;
-may be set to either value, or to +nil+, in the running program.
-
-When +true+, enables Ruby warnings.
-
-When +nil+, disables warnings, including those from Kernel#warn.
-
-Aliased as <tt>$-v</tt> and <tt>$-w</tt>.
-
-=== Other Variables
-
-==== <tt>$-a</tt>
-
-Whether command-line option <tt>-a</tt> was given; read-only.
-
-==== <tt>$-i</tt>
-
-Contains the extension given with command-line option <tt>-i</tt>,
-or +nil+ if none.
-
-An alias of ARGF.inplace_mode.
-
-==== <tt>$-l</tt>
-
-Whether command-line option <tt>-l</tt> was set; read-only.
-
-==== <tt>$-p</tt>
-
-Whether command-line option <tt>-p</tt> was given; read-only.
-
-=== Deprecated
-
-==== <tt>$=</tt>
-
-==== <tt>$,</tt>
-
-== Pre-Defined Global Constants
-
-== Streams
-
-==== <tt>STDIN</tt>
-
-The standard input stream (the default value for <tt>$stdin</tt>):
-
- STDIN # => #<IO:<STDIN>>
-
-==== <tt>STDOUT</tt>
-
-The standard output stream (the default value for <tt>$stdout</tt>):
-
- STDOUT # => #<IO:<STDOUT>>
-
-==== <tt>STDERR</tt>
-
-The standard error stream (the default value for <tt>$stderr</tt>):
-
- STDERR # => #<IO:<STDERR>>
-
-=== Enviroment
-
-==== ENV
-
-A hash of the contains current environment variables names and values:
-
- ENV.take(5)
- # =>
- [["COLORTERM", "truecolor"],
- ["DBUS_SESSION_BUS_ADDRESS", "unix:path=/run/user/1000/bus"],
- ["DESKTOP_SESSION", "ubuntu"],
- ["DISPLAY", ":0"],
- ["GDMSESSION", "ubuntu"]]
-
-==== ARGF
-
-The virtual concatenation of the files given on the command line, or from
-<tt>$stdin</tt> if no files were given, <tt>"-"</tt> is given, or after
-all files have been read.
-
-==== <tt>ARGV</tt>
-
-An array of the given command-line arguments.
-
-==== <tt>TOPLEVEL_BINDING</tt>
-
-The Binding of the top level scope:
-
- TOPLEVEL_BINDING # => #<Binding:0x00007f58da0da7c0>
-
-==== <tt>RUBY_VERSION</tt>
-
-The Ruby version:
-
- RUBY_VERSION # => "3.2.2"
-
-==== <tt>RUBY_RELEASE_DATE</tt>
-
-The release date string:
-
- RUBY_RELEASE_DATE # => "2023-03-30"
-
-==== <tt>RUBY_PLATFORM</tt>
-
-The platform identifier:
-
- RUBY_PLATFORM # => "x86_64-linux"
-
-==== <tt>RUBY_PATCHLEVEL</tt>
-
-The integer patch level for this Ruby:
-
- RUBY_PATCHLEVEL # => 53
-
-For a development build the patch level will be -1.
-
-==== <tt>RUBY_REVISION</tt>
-
-The git commit hash for this Ruby:
-
- RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015"
-
-==== <tt>RUBY_COPYRIGHT</tt>
-
-The copyright string:
-
- RUBY_COPYRIGHT
- # => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
-
-==== <tt>RUBY_ENGINE</tt>
-
-The name of the Ruby implementation:
-
- RUBY_ENGINE # => "ruby"
-
-==== <tt>RUBY_ENGINE_VERSION</tt>
-
-The version of the Ruby implementation:
-
- RUBY_ENGINE_VERSION # => "3.2.2"
-
-==== <tt>RUBY_DESCRIPTION</tt>
-
-The description of the Ruby implementation:
-
- RUBY_DESCRIPTION
- # => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
-
-=== Embedded \Data
-
-==== <tt>DATA</tt>
-
-Defined if and only if the program has this line:
-
- __END__
-
-When defined, <tt>DATA</tt> is a File object
-containing the lines following the <tt>__END__</tt>,
-positioned at the first of those lines:
-
- p DATA
- DATA.each_line { |line| p line }
- __END__
- Foo
- Bar
- Baz
-
-Output:
-
- #<File:t.rb>
- "Foo\n"
- "Bar\n"
- "Baz\n"
+# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*-
+
+== Pre-defined global variables
+
+$!:: The Exception object set by Kernel#raise.
+$@:: The same as <code>$!.backtrace</code>.
+$~:: The information about the last match in the current scope (thread-local and frame-local).
+$&:: The string matched by the last successful match.
+$`:: The string to the left of the last successful match.
+$':: The string to the right of the last successful match.
+$+:: The highest group matched by the last successful match.
+$1:: The Nth group of the last successful match. May be > 1.
+$=:: This variable is no longer effective. Deprecated.
+$/:: The input record separator, newline by default. Aliased to $-0.
+$\:: The output record separator for Kernel#print and IO#write. Default is +nil+.
+$,:: The output field separator for Kernel#print and Array#join. Non-nil $, will be deprecated.
+$;:: The default separator for String#split. Non-nil $; will be deprecated. Aliased to $-F.
+$.:: The current input line number of the last file that was read.
+$<:: The same as ARGF.
+$>:: The default output stream for Kernel#print and Kernel#printf. $stdout by default.
+$_:: The last input line of string by gets or readline.
+$0:: Contains the name of the script being executed. May be assignable.
+$*:: The same as ARGV.
+$$:: The process number of the Ruby running this script. Same as Process.pid.
+$?:: The status of the last executed child process (thread-local).
+$LOAD_PATH:: Load path for searching Ruby scripts and extension libraries used
+ by Kernel#load and Kernel#require. Aliased to $: and $-I.
+ Has a singleton method <code>$LOAD_PATH.resolve_feature_path(feature)</code>
+ that returns [+:rb+ or +:so+, path], which resolves the feature to
+ the path the original Kernel#require method would load.
+$LOADED_FEATURES:: The array contains the module names loaded by require.
+ Aliased to $".
+$DEBUG:: The debug flag, which is set by the <tt>-d</tt> switch. Enabling debug
+ output prints each exception raised to $stderr (but not its
+ backtrace). Setting this to a true value enables debug output as
+ if <tt>-d</tt> were given on the command line. Setting this to a false
+ value disables debug output. Aliased to $-d.
+$FILENAME:: Current input filename from ARGF. Same as ARGF.filename.
+$stderr:: The current standard error output.
+$stdin:: The current standard input.
+$stdout:: The current standard output.
+$VERBOSE:: The verbose flag, which is set by the <tt>-w</tt> or <tt>-v</tt> switch.
+ Setting this to a true value enables warnings as if <tt>-w</tt> or <tt>-v</tt> were given
+ on the command line. Setting this to +nil+ disables warnings,
+ including from Kernel#warn. Aliased to $-v and $-w.
+$-a:: True if option <tt>-a</tt> is set. Read-only variable.
+$-i:: In in-place-edit mode, this variable holds the extension, otherwise +nil+.
+$-l:: True if option <tt>-l</tt> is set. Read-only variable.
+$-p:: True if option <tt>-p</tt> is set. Read-only variable.
+
+== Pre-defined global constants
+
+STDIN:: The standard input. The default value for $stdin.
+STDOUT:: The standard output. The default value for $stdout.
+STDERR:: The standard error output. The default value for $stderr.
+ENV:: The hash contains current environment variables.
+ARGF:: The virtual concatenation of the files given on command line (or from $stdin if no files were given).
+ARGV:: An Array of command line arguments given for the script.
+DATA:: The file object of the script, pointing just after <code>__END__</code>.
+TOPLEVEL_BINDING:: The Binding of the top level scope.
+RUBY_VERSION:: The Ruby language version.
+RUBY_RELEASE_DATE:: The release date string.
+RUBY_PLATFORM:: The platform identifier.
+RUBY_PATCHLEVEL:: The patchlevel for this Ruby. If this is a development build of Ruby the patchlevel will be -1.
+RUBY_REVISION:: The GIT commit hash for this Ruby.
+RUBY_COPYRIGHT:: The copyright string for Ruby.
+RUBY_ENGINE:: The name of the Ruby implementation.
+RUBY_ENGINE_VERSION:: The version of the Ruby implementation.
+RUBY_DESCRIPTION:: The same as <tt>ruby --version</tt>, a String describing various aspects of the Ruby implementation.
diff --git a/doc/irb/irb.rd.ja b/doc/irb/irb.rd.ja
index c51e0bd60d..633c08cbd4 100644
--- a/doc/irb/irb.rd.ja
+++ b/doc/irb/irb.rd.ja
@@ -125,6 +125,7 @@ irb起動時に``~/.irbrc''を読み込みます. もし存在しない場合は
IRB.conf[:PROMPT][:MY_PROMPT] = { # プロンプトモードの名前
:PROMPT_I => nil, # 通常のプロンプト
+ :PROMPT_N => nil, # 継続行のプロンプト
:PROMPT_S => nil, # 文字列などの継続行のプロンプト
:PROMPT_C => nil, # 式が継続している時のプロンプト
:RETURN => " ==>%s\n" # リターン時のプロンプト
@@ -139,7 +140,7 @@ OKです.
IRB.conf[:PROMPT_MODE] = :MY_PROMPT
-PROMPT_I, PROMPT_S, PROMPT_Cは, フォーマットを指定します.
+PROMPT_I, PROMPT_N, PROMPT_S, PROMPT_Cは, フォーマットを指定します.
%N 起動しているコマンド名が出力される.
%m mainオブジェクト(self)がto_sで出力される.
@@ -154,6 +155,7 @@ PROMPT_I, PROMPT_S, PROMPT_Cは, フォーマットを指定します.
IRB.conf[:PROMPT][:DEFAULT] = {
:PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "=> %s\n"
diff --git a/doc/maintainers.md b/doc/maintainers.md
deleted file mode 100644
index 631371e178..0000000000
--- a/doc/maintainers.md
+++ /dev/null
@@ -1,520 +0,0 @@
-# Maintainers
-This page describes the current module, library, and extension maintainers of Ruby.
-
-## Module Maintainers
-A module maintainer is responsible for a certain part of Ruby.
-
-* The maintainer fixes bugs of the part. Particularly, they should fix
- security vulnerabilities as soon as possible.
-* They handle issues related the module on the Redmine or ML.
-* They may be discharged by the 3 months rule [[ruby-core:25764]](https://blade.ruby-lang.org/ruby-core/25764).
-* They have commit right to Ruby's repository to modify their part in the
- repository.
-* They have "developer" role on the Redmine to modify issues.
-* They have authority to decide the feature of their part. But they should
- always respect discussions on ruby-core/ruby-dev.
-
-A submaintainer of a module is like a maintainer. But the submaintainer does
-not have authority to change/add a feature on his/her part. They need
-consensus on ruby-core/ruby-dev before changing/adding. Some of submaintainers
-have commit right, others don't.
-
-### Language core features including security
-* Yukihiro Matsumoto (matz)
-
-### Evaluator
-* Koichi Sasada (ko1)
-
-### Core classes
-* Yukihiro Matsumoto (matz)
-
-## Standard Library Maintainers
-### Libraries
-#### lib/mkmf.rb
-* *unmaintained*
-
-#### lib/rubygems.rb, lib/rubygems/*
-* Eric Hodel (drbrain)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/rubygems/rubygems
-
-#### lib/unicode_normalize.rb, lib/unicode_normalize/*
-* Martin J. Dürst
-
-### Extensions
-#### ext/continuation
-* Koichi Sasada (ko1)
-
-#### ext/coverage
-* Yusuke Endoh (mame)
-
-#### ext/fiber
-* Koichi Sasada (ko1)
-
-#### ext/monitor
-* Koichi Sasada (ko1)
-
-#### ext/objspace
-* *unmaintained*
-
-#### ext/pty
-* *unmaintained*
-
-#### ext/ripper
-* *unmaintained*
-
-#### ext/socket
-* Tanaka Akira (akr)
-* API change needs matz's approval
-
-#### ext/win32
-* NAKAMURA Usaku (usa)
-
-## Default gems Maintainers
-### Libraries
-#### lib/abbrev.rb
-* Akinori MUSHA (knu)
-* https://github.com/ruby/abbrev
-* https://rubygems.org/gems/abbrev
-
-#### lib/base64.rb
-* Yusuke Endoh (mame)
-* https://github.com/ruby/base64
-* https://rubygems.org/gems/base64
-
-#### lib/benchmark.rb
-* *unmaintained*
-* https://github.com/ruby/benchmark
-* https://rubygems.org/gems/benchmark
-
-#### lib/bundler.rb, lib/bundler/*
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/rubygems/rubygems
-* https://rubygems.org/gems/bundler
-
-#### lib/cgi.rb, lib/cgi/*
-* *unmaintained*
-* https://github.com/ruby/cgi
-* https://rubygems.org/gems/cgi
-
-#### lib/csv.rb
-* Kenta Murata (mrkn)
-* Kouhei Sutou (kou)
-* https://github.com/ruby/csv
-* https://rubygems.org/gems/csv
-
-#### lib/English.rb
-* *unmaintained*
-* https://github.com/ruby/English
-* https://rubygems.org/gems/English
-
-#### lib/delegate.rb
-* *unmaintained*
-* https://github.com/ruby/delegate
-* https://rubygems.org/gems/delegate
-
-#### lib/did_you_mean.rb
-* Yuki Nishijima (yuki24)
-* https://github.com/ruby/did_you_mean
-* https://rubygems.org/gems/did_you_mean
-
-#### ext/digest, ext/digest/*
-* Akinori MUSHA (knu)
-* https://github.com/ruby/digest
-* https://rubygems.org/gems/digest
-
-#### lib/drb.rb, lib/drb/*
-* Masatoshi SEKI (seki)
-* https://github.com/ruby/drb
-* https://rubygems.org/gems/drb
-
-#### lib/erb.rb
-* Masatoshi SEKI (seki)
-* Takashi Kokubun (k0kubun)
-* https://github.com/ruby/erb
-* https://rubygems.org/gems/erb
-
-#### lib/error_highlight.rb, lib/error_highlight/*
-* Yusuke Endoh (mame)
-* https://github.com/ruby/error_highlight
-* https://rubygems.org/gems/error_highlight
-
-#### lib/fileutils.rb
-* *unmaintained*
-* https://github.com/ruby/fileutils
-* https://rubygems.org/gems/fileutils
-
-#### lib/find.rb
-* Kazuki Tsujimoto (ktsj)
-* https://github.com/ruby/find
-* https://rubygems.org/gems/find
-
-#### lib/forwardable.rb
-* Keiju ISHITSUKA (keiju)
-* https://github.com/ruby/forwardable
-* https://rubygems.org/gems/forwardable
-
-#### lib/getoptlong.rb
-* *unmaintained*
-* https://github.com/ruby/getoptlong
-* https://rubygems.org/gems/getoptlong
-
-#### lib/ipaddr.rb
-* Akinori MUSHA (knu)
-* https://github.com/ruby/ipaddr
-* https://rubygems.org/gems/ipaddr
-
-#### lib/irb.rb, lib/irb/*
-* Stan Lo (st0012)
-* Tomoya Ishida (tompng)
-* Mari Imaizumi (ima1zumi)
-* Hitoshi Hasumi (hasumikin)
-* https://github.com/ruby/irb
-* https://rubygems.org/gems/irb
-
-#### lib/optparse.rb, lib/optparse/*
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/optparse
-
-#### lib/logger.rb
-* Naotoshi Seo (sonots)
-* https://github.com/ruby/logger
-* https://rubygems.org/gems/logger
-
-#### lib/mutex_m.rb
-* Keiju ISHITSUKA (keiju)
-* https://github.com/ruby/mutex_m
-* https://rubygems.org/gems/mutex_m
-
-#### lib/net/http.rb, lib/net/https.rb
-* NARUSE, Yui (naruse)
-* https://github.com/ruby/net-http
-* https://rubygems.org/gems/net-http
-
-#### lib/net/protocol.rb
-* *unmaintained*
-* https://github.com/ruby/net-protocol
-* https://rubygems.org/gems/net-protocol
-
-#### lib/observer.rb
-* *unmaintained*
-* https://github.com/ruby/observer
-* https://rubygems.org/gems/observer
-
-#### lib/open3.rb
-* *unmaintained*
-* https://github.com/ruby/open3
-* https://rubygems.org/gems/open3
-
-#### lib/open-uri.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/open-uri
-
-#### lib/ostruct.rb
-* Marc-André Lafortune (marcandre)
-* https://github.com/ruby/ostruct
-* https://rubygems.org/gems/ostruct
-
-#### lib/pp.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/pp
-* https://rubygems.org/gems/pp
-
-#### lib/prettyprint.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/prettyprint
-* https://rubygems.org/gems/prettyprint
-
-#### lib/prism.rb
-* Kevin Newton (kddnewton)
-* Jemma Issroff (jemmaissroff)
-* https://github.com/ruby/prism
-* https://rubygems.org/gems/prism
-
-#### lib/pstore.rb
-* *unmaintained*
-* https://github.com/ruby/pstore
-* https://rubygems.org/gems/pstore
-
-#### lib/readline.rb
-* aycabta
-* https://github.com/ruby/readline
-* https://rubygems.org/gems/readline
-
-#### lib/resolv.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/resolv
-* https://rubygems.org/gems/resolv
-
-#### lib/resolv-replace.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/resolv-replace
-* https://rubygems.org/gems/resolv-replace
-
-#### lib/rdoc.rb, lib/rdoc/*
-* Eric Hodel (drbrain)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/ruby/rdoc
-* https://rubygems.org/gems/rdoc
-
-#### lib/reline.rb, lib/reline/*
-* Tomoya Ishida (tompng)
-* Mari Imaizumi (ima1zumi)
-* Stan Lo (st0012)
-* Hitoshi Hasumi (hasumikin)
-* https://github.com/ruby/reline
-* https://rubygems.org/gems/reline
-
-#### lib/rinda/*
-* Masatoshi SEKI (seki)
-* https://github.com/ruby/rinda
-* https://rubygems.org/gems/rinda
-
-#### lib/securerandom.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/securerandom
-* https://rubygems.org/gems/securerandom
-
-#### lib/set.rb
-* Akinori MUSHA (knu)
-* https://github.com/ruby/set
-* https://rubygems.org/gems/set
-
-#### lib/shellwords.rb
-* Akinori MUSHA (knu)
-* https://github.com/ruby/shellwords
-* https://rubygems.org/gems/shellwords
-
-#### lib/singleton.rb
-* Yukihiro Matsumoto (matz)
-* https://github.com/ruby/singleton
-* https://rubygems.org/gems/singleton
-
-#### lib/tempfile.rb
-* *unmaintained*
-* https://github.com/ruby/tempfile
-* https://rubygems.org/gems/tempfile
-
-#### lib/time.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/time
-* https://rubygems.org/gems/time
-
-#### lib/timeout.rb
-* Yukihiro Matsumoto (matz)
-* https://github.com/ruby/timeout
-* https://rubygems.org/gems/timeout
-
-#### lib/thwait.rb
-* Keiju ISHITSUKA (keiju)
-* https://github.com/ruby/thwait
-* https://rubygems.org/gems/thwait
-
-#### lib/tmpdir.rb
-* *unmaintained*
-* https://github.com/ruby/tmpdir
-* https://rubygems.org/gems/tmpdir
-
-#### lib/tsort.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/tsort
-* https://rubygems.org/gems/tsort
-
-#### lib/un.rb
-* WATANABE Hirofumi (eban)
-* https://github.com/ruby/un
-* https://rubygems.org/gems/un
-
-#### lib/uri.rb, lib/uri/*
-* NARUSE, Yui (naruse)
-* https://github.com/ruby/uri
-* https://rubygems.org/gems/uri
-
-#### lib/yaml.rb, lib/yaml/*
-* Aaron Patterson (tenderlove)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/ruby/yaml
-* https://rubygems.org/gems/yaml
-
-#### lib/weakref.rb
-* *unmaintained*
-* https://github.com/ruby/weakref
-* https://rubygems.org/gems/weakref
-
-### Extensions
-#### ext/bigdecimal
-* Kenta Murata (mrkn) https://github.com/ruby/bigdecimal
-* https://rubygems.org/gems/bigdecimal
-
-#### ext/cgi
-* Nobuyoshi Nakada (nobu)
-* https://github.com/ruby/cgi
-* https://rubygems.org/gems/cgi
-
-#### ext/date
-* *unmaintained*
-* https://github.com/ruby/date
-* https://rubygems.org/gems/date
-
-#### ext/etc
-* *unmaintained*
-* https://github.com/ruby/etc
-* https://rubygems.org/gems/etc
-
-#### ext/fcntl
-* *unmaintained*
-* https://github.com/ruby/fcntl
-* https://rubygems.org/gems/fcntl
-
-#### ext/fiddle
-* Aaron Patterson (tenderlove)
-* https://github.com/ruby/fiddle
-* https://rubygems.org/gems/fiddle
-
-#### ext/io/console
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/io-console
-* https://rubygems.org/gems/io-console
-
-#### ext/io/nonblock
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/io-nonblock
-* https://rubygems.org/gems/io-nonblock
-
-#### ext/io/wait
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/io-wait
-* https://rubygems.org/gems/io-wait
-
-#### ext/json
-* NARUSE, Yui (naruse)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/flori/json
-* https://rubygems.org/gems/json
-
-#### ext/nkf
-* NARUSE, Yui (naruse)
-* https://github.com/ruby/nkf
-* https://rubygems.org/gems/nkf
-
-#### ext/openssl
-* Kazuki Yamaguchi (rhe)
-* https://github.com/ruby/openssl
-* https://rubygems.org/gems/openssl
-
-#### ext/pathname
-* Tanaka Akira (akr)
-* https://github.com/ruby/pathname
-* https://rubygems.org/gems/pathname
-
-#### ext/psych
-* Aaron Patterson (tenderlove)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/ruby/psych
-* https://rubygems.org/gems/psych
-
-#### ext/stringio
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/stringio
-* https://rubygems.org/gems/stringio
-
-#### ext/strscan
-* Kouhei Sutou (kou)
-* https://github.com/ruby/strscan
-* https://rubygems.org/gems/strscan
-
-#### ext/syslog
-* Akinori MUSHA (knu)
-* https://github.com/ruby/syslog
-* https://rubygems.org/gems/syslog
-
-#### ext/win32ole
-* Masaki Suketa (suke)
-* https://github.com/ruby/win32ole
-* https://rubygems.org/gems/win32ole
-
-#### ext/zlib
-* NARUSE, Yui (naruse)
-* https://github.com/ruby/zlib
-* https://rubygems.org/gems/zlib
-
-## Bundled gems upstream repositories
-### minitest
-* https://github.com/seattlerb/minitest
-
-### power_assert
-* https://github.com/ruby/power_assert
-
-### rake
-* https://github.com/ruby/rake
-
-### test-unit
-* https://github.com/test-unit/test-unit
-
-### rexml
-* https://github.com/ruby/rexml
-
-### rss
-* https://github.com/ruby/rss
-
-### net-ftp
-* https://github.com/ruby/net-ftp
-
-### net-imap
-* https://github.com/ruby/net-imap
-
-### net-pop
-* https://github.com/ruby/net-pop
-
-### net-smtp
-* https://github.com/ruby/net-smtp
-
-### matrix
-* https://github.com/ruby/matrix
-
-### prime
-* https://github.com/ruby/prime
-
-### rbs
-* https://github.com/ruby/rbs
-
-### typeprof
-* https://github.com/ruby/typeprof
-
-### debug
-* https://github.com/ruby/debug
-
-### racc
-* https://github.com/ruby/racc
-
-
-## Platform Maintainers
-### mswin64 (Microsoft Windows)
-* NAKAMURA Usaku (usa)
-
-### mingw32 (Minimalist GNU for Windows)
-* Nobuyoshi Nakada (nobu)
-
-### AIX
-* Yutaka Kanemoto (kanemoto)
-
-### FreeBSD
-* Akinori MUSHA (knu)
-
-### Solaris
-* Naohisa Goto (ngoto)
-
-### RHEL, CentOS
-* KOSAKI Motohiro (kosaki)
-
-### macOS
-* Kenta Murata (mrkn)
-
-### OpenBSD
-* Jeremy Evans (jeremyevans0)
-
-### cygwin, ...
-* none. (Maintainer WANTED)
-
-### WebAssembly/WASI
-* Yuta Saito (katei)
diff --git a/doc/maintainers.rdoc b/doc/maintainers.rdoc
new file mode 100644
index 0000000000..7e0c35194f
--- /dev/null
+++ b/doc/maintainers.rdoc
@@ -0,0 +1,424 @@
+= Maintainers
+
+This page describes the current module, library, and extension maintainers of Ruby.
+
+== Module Maintainers
+
+A module maintainer is responsible for a certain part of Ruby.
+
+* The maintainer fixes bugs of the part. Particularly, they should fix security vulnerabilities as soon as possible.
+* They handle issues related the module on the Redmine or ML.
+* They may be discharged by the 3 months rule [ruby-core:25764].
+* They have commit right to Ruby's repository to modify their part in the repository.
+* They have "developer" role on the Redmine to modify issues.
+* They have authority to decide the feature of their part. But they should always respect discussions on ruby-core/ruby-dev.
+
+A submaintainer of a module is like a maintainer. But the submaintainer does
+not have authority to change/add a feature on his/her part. They need consensus
+on ruby-core/ruby-dev before changing/adding. Some of submaintainers have
+commit right, others don't.
+
+=== Language core features including security
+
+Yukihiro Matsumoto (matz)
+
+=== Evaluator
+
+Koichi Sasada (ko1)
+
+=== Core classes
+
+Yukihiro Matsumoto (matz)
+
+== Standard Library Maintainers
+
+=== Libraries
+
+[lib/mkmf.rb]
+ _unmaintained_
+[lib/rubygems.rb, lib/rubygems/*]
+ Eric Hodel (drbrain), Hiroshi SHIBATA (hsbt)
+ https://github.com/rubygems/rubygems
+[lib/unicode_normalize.rb, lib/unicode_normalize/*]
+ Martin J. Dürst
+
+=== Extensions
+
+[ext/continuation]
+ Koichi Sasada (ko1)
+[ext/coverage]
+ Yusuke Endoh (mame)
+[ext/fiber]
+ Koichi Sasada (ko1)
+[ext/monitor]
+ Koichi Sasada (ko1)
+[ext/objspace]
+ _unmaintained_
+[ext/pty]
+ _unmaintained_
+[ext/ripper]
+ _unmaintained_
+[ext/socket]
+ * Tanaka Akira (akr)
+ * API change needs matz's approval
+[ext/win32]
+ NAKAMURA Usaku (usa)
+
+== Default gems Maintainers
+
+=== Libraries
+
+[lib/abbrev.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/abbrev
+ https://rubygems.org/gems/abbrev
+[lib/base64.rb]
+ Yusuke Endoh (mame)
+ https://github.com/ruby/base64
+ https://rubygems.org/gems/base64
+[lib/benchmark.rb]
+ _unmaintained_
+ https://github.com/ruby/benchmark
+ https://rubygems.org/gems/benchmark
+[lib/bundler.rb, lib/bundler/*]
+ Hiroshi SHIBATA (hsbt)
+ https://github.com/rubygems/rubygems
+ https://rubygems.org/gems/bundler
+[lib/cgi.rb, lib/cgi/*]
+ _unmaintained_
+ https://github.com/ruby/cgi
+ https://rubygems.org/gems/cgi
+[lib/csv.rb]
+ Kenta Murata (mrkn), Kouhei Sutou (kou)
+ https://github.com/ruby/csv
+ https://rubygems.org/gems/csv
+[lib/English.rb]
+ _unmaintained_
+ https://github.com/ruby/English
+ https://rubygems.org/gems/English
+[lib/debug.rb]
+ _unmaintained_
+ https://github.com/ruby/debug
+[lib/delegate.rb]
+ _unmaintained_
+ https://github.com/ruby/delegate
+ https://rubygems.org/gems/delegate
+[lib/did_you_mean.rb]
+ Yuki Nishijima (yuki24)
+ https://github.com/ruby/did_you_mean
+ https://rubygems.org/gems/did_you_mean
+[ext/digest, ext/digest/*]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/digest
+ https://rubygems.org/gems/digest
+[lib/drb.rb, lib/drb/*]
+ Masatoshi SEKI (seki)
+ https://github.com/ruby/drb
+ https://rubygems.org/gems/drb
+[lib/erb.rb]
+ Masatoshi SEKI (seki), Takashi Kokubun (k0kubun)
+ https://github.com/ruby/erb
+ https://rubygems.org/gems/erb
+[lib/error_highlight.rb, lib/error_highlight/*]
+ Yusuke Endoh (mame)
+ https://github.com/ruby/error_highlight
+ https://rubygems.org/gems/error_highlight
+[lib/fileutils.rb]
+ _unmaintained_
+ https://github.com/ruby/fileutils
+ https://rubygems.org/gems/fileutils
+[lib/find.rb]
+ Kazuki Tsujimoto (ktsj)
+ https://github.com/ruby/find
+ https://rubygems.org/gems/find
+[lib/forwardable.rb]
+ Keiju ISHITSUKA (keiju)
+ https://github.com/ruby/forwardable
+ https://rubygems.org/gems/forwardable
+[lib/getoptlong.rb]
+ _unmaintained_
+ https://github.com/ruby/getoptlong
+ https://rubygems.org/gems/getoptlong
+[lib/ipaddr.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/ipaddr
+ https://rubygems.org/gems/ipaddr
+[lib/irb.rb, lib/irb/*]
+ aycabta
+ https://github.com/ruby/irb
+ https://rubygems.org/gems/irb
+[lib/optparse.rb, lib/optparse/*]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/optparse
+[lib/logger.rb]
+ Naotoshi Seo (sonots)
+ https://github.com/ruby/logger
+ https://rubygems.org/gems/logger
+[lib/mutex_m.rb]
+ Keiju ISHITSUKA (keiju)
+ https://github.com/ruby/mutex_m
+ https://rubygems.org/gems/mutex_m
+[lib/net/http.rb, lib/net/https.rb]
+ NARUSE, Yui (naruse)
+ https://github.com/ruby/net-http
+ https://rubygems.org/gems/net-http
+[lib/net/protocol.rb]
+ _unmaintained_
+ https://github.com/ruby/net-protocol
+ https://rubygems.org/gems/net-protocol
+[lib/observer.rb]
+ _unmaintained_
+ https://github.com/ruby/observer
+ https://rubygems.org/gems/observer
+[lib/open3.rb]
+ _unmaintained_
+ https://github.com/ruby/open3
+ https://rubygems.org/gems/open3
+[lib/open-uri.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/open-uri
+[lib/ostruct.rb]
+ Marc-André Lafortune (marcandre)
+ https://github.com/ruby/ostruct
+ https://rubygems.org/gems/ostruct
+[lib/pp.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/pp
+ https://rubygems.org/gems/pp
+[lib/prettyprint.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/prettyprint
+ https://rubygems.org/gems/prettyprint
+[lib/pstore.rb]
+ _unmaintained_
+ https://github.com/ruby/pstore
+ https://rubygems.org/gems/pstore
+[lib/racc.rb, lib/racc/*]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/racc
+ https://rubygems.org/gems/racc
+[lib/readline.rb]
+ aycabta
+ https://github.com/ruby/readline
+ https://rubygems.org/gems/readline
+[lib/resolv.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/resolv
+ https://rubygems.org/gems/resolv
+[lib/resolv-replace.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/resolv-replace
+ https://rubygems.org/gems/resolv-replace
+[lib/rdoc.rb, lib/rdoc/*]
+ Eric Hodel (drbrain), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/rdoc
+ https://rubygems.org/gems/rdoc
+[lib/readline.rb]
+ aycabta
+ https://github.com/ruby/readline
+ https://rubygems.org/gems/readline
+[lib/reline.rb, lib/reline/*]
+ aycabta
+ https://github.com/ruby/reline
+ https://rubygems.org/gems/reline
+[lib/rinda/*]
+ Masatoshi SEKI (seki)
+ https://github.com/ruby/rinda
+ https://rubygems.org/gems/rinda
+[lib/securerandom.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/securerandom
+ https://rubygems.org/gems/securerandom
+[lib/set.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/set
+ https://rubygems.org/gems/set
+[lib/shellwords.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/shellwords
+ https://rubygems.org/gems/shellwords
+[lib/singleton.rb]
+ Yukihiro Matsumoto (matz)
+ https://github.com/ruby/singleton
+ https://rubygems.org/gems/singleton
+[lib/tempfile.rb]
+ _unmaintained_
+ https://github.com/ruby/tempfile
+ https://rubygems.org/gems/tempfile
+[lib/time.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/time
+ https://rubygems.org/gems/time
+[lib/timeout.rb]
+ Yukihiro Matsumoto (matz)
+ https://github.com/ruby/timeout
+ https://rubygems.org/gems/timeout
+[lib/thwait.rb]
+ Keiju ISHITSUKA (keiju)
+ https://github.com/ruby/thwait
+ https://rubygems.org/gems/thwait
+[lib/tmpdir.rb]
+ _unmaintained_
+ https://github.com/ruby/tmpdir
+ https://rubygems.org/gems/tmpdir
+[lib/tsort.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/tsort
+ https://rubygems.org/gems/tsort
+[lib/un.rb]
+ WATANABE Hirofumi (eban)
+ https://github.com/ruby/un
+ https://rubygems.org/gems/un
+[lib/uri.rb, lib/uri/*]
+ YAMADA, Akira (akira)
+ https://github.com/ruby/uri
+ https://rubygems.org/gems/uri
+[lib/yaml.rb, lib/yaml/*]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/yaml
+ https://rubygems.org/gems/yaml
+[lib/weakref.rb]
+ _unmaintained_
+ https://github.com/ruby/weakref
+ https://rubygems.org/gems/weakref
+
+=== Extensions
+
+[ext/bigdecimal]
+ Kenta Murata (mrkn)
+ https://github.com/ruby/bigdecimal
+ https://rubygems.org/gems/bigdecimal
+[ext/cgi]
+ Nobuyoshi Nakada (nobu)
+ https://github.com/ruby/cgi
+ https://rubygems.org/gems/cgi
+[ext/date]
+ _unmaintained_
+ https://github.com/ruby/date
+ https://rubygems.org/gems/date
+[ext/etc]
+ Ruby core team
+ https://github.com/ruby/etc
+ https://rubygems.org/gems/etc
+[ext/fcntl]
+ Ruby core team
+ https://github.com/ruby/fcntl
+ https://rubygems.org/gems/fcntl
+[ext/fiddle]
+ Aaron Patterson (tenderlove)
+ https://github.com/ruby/fiddle
+ https://rubygems.org/gems/fiddle
+[ext/io/console]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/io-console
+ https://rubygems.org/gems/io-console
+[ext/io/nonblock]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/io-nonblock
+ https://rubygems.org/gems/io-nonblock
+[ext/io/wait]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/io-wait
+ https://rubygems.org/gems/io-wait
+[ext/json]
+ NARUSE, Yui (naruse), Hiroshi SHIBATA (hsbt)
+ https://github.com/flori/json
+ https://rubygems.org/gems/json
+[ext/nkf]
+ NARUSE, Yui (naruse)
+ https://github.com/ruby/nkf
+ https://rubygems.org/gems/nkf
+[ext/openssl]
+ Kazuki Yamaguchi (rhe)
+ https://github.com/ruby/openssl
+ https://rubygems.org/gems/openssl
+[ext/pathname]
+ Tanaka Akira (akr)
+ https://github.com/ruby/pathname
+ https://rubygems.org/gems/pathname
+[ext/psych]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/psych
+ https://rubygems.org/gems/psych
+[ext/racc]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/racc
+ https://rubygems.org/gems/racc
+[ext/readline]
+ TAKAO Kouji (kouji)
+ https://github.com/ruby/readline-ext
+ https://rubygems.org/gems/readline-ext
+[ext/stringio]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/stringio
+ https://rubygems.org/gems/stringio
+[ext/strscan]
+ Kouhei Sutou (kou)
+ https://github.com/ruby/strscan
+ https://rubygems.org/gems/strscan
+[ext/syslog]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/syslog
+ https://rubygems.org/gems/syslog
+[ext/win32ole]
+ Masaki Suketa (suke)
+ https://github.com/ruby/win32ole
+ https://rubygems.org/gems/win32ole
+[ext/zlib]
+ NARUSE, Yui (naruse)
+ https://github.com/ruby/zlib
+ https://rubygems.org/gems/zlib
+
+== Bundled gems upstream repositories
+
+[minitest]
+ https://github.com/seattlerb/minitest
+[power_assert]
+ https://github.com/ruby/power_assert
+[rake]
+ https://github.com/ruby/rake
+[test-unit]
+ https://github.com/test-unit/test-unit
+[rexml]
+ https://github.com/ruby/rexml
+[rss]
+ https://github.com/ruby/rss
+[net-ftp]
+ https://github.com/ruby/net-ftp
+[net-imap]
+ https://github.com/ruby/net-imap
+[net-pop]
+ https://github.com/ruby/net-pop
+[net-smtp]
+ https://github.com/ruby/net-smtp
+[matrix]
+ https://github.com/ruby/matrix
+[prime]
+ https://github.com/ruby/prime
+[rbs]
+ https://github.com/ruby/rbs
+[typeprof]
+ https://github.com/ruby/typeprof
+
+=== Platform Maintainers
+
+[mswin64 (Microsoft Windows)]
+ NAKAMURA Usaku (usa)
+[mingw32 (Minimalist GNU for Windows)]
+ Nobuyoshi Nakada (nobu)
+[AIX]
+ Yutaka Kanemoto (kanemoto)
+[FreeBSD]
+ Akinori MUSHA (knu)
+[Solaris]
+ Naohisa Goto (ngoto)
+[RHEL, CentOS]
+ KOSAKI Motohiro (kosaki)
+[macOS]
+ Kenta Murata (mrkn)
+[OpenBSD]
+ Jeremy Evans (jeremyevans0)
+[cygwin, ...]
+ none. (Maintainer WANTED)
+[WebAssembly/WASI]
+ Yuta Saito (katei)
diff --git a/doc/mjit/mjit.md b/doc/mjit/mjit.md
new file mode 100644
index 0000000000..6f19ab3ea7
--- /dev/null
+++ b/doc/mjit/mjit.md
@@ -0,0 +1,39 @@
+# MJIT
+
+This document has some tips that might be useful when you work on MJIT.
+
+## Supported platforms
+
+The following platforms are either tested on CI or assumed to work.
+
+* OS: Linux, macOS
+* Arch: x86\_64, aarch64, arm64, i686, i386
+
+### Not supported
+
+The MJIT support for the following platforms is no longer maintained.
+
+* OS: Windows (mswin, MinGW), Solaris
+* Arch: SPARC, s390x
+
+## Developing MJIT
+
+### Bindgen
+
+If you see an "MJIT bindgen" GitHub Actions failure, please commit the `git diff` shown on the failed job.
+
+For doing the same thing locally, run `make mjit-bindgen` after installing libclang.
+macOS seems to have libclang by default. On Ubuntu, you can install it with `apt install libclang1`.
+
+### Always run make install
+
+Always run `make install` before running MJIT. It could easily cause a SEGV if you don't.
+MJIT looks for the installed header for security reasons.
+
+### --mjit-debug vs --mjit-debug=-ggdb3
+
+`--mjit-debug=[flags]` allows you to specify arbitrary flags while keeping other compiler flags like `-O3`,
+which is useful for profiling benchmarks.
+
+`--mjit-debug` alone, on the other hand, disables `-O3` and adds debug flags.
+If you're debugging MJIT, what you need to use is not `--mjit-debug=-ggdb3` but `--mjit-debug`.
diff --git a/doc/optparse/argument_converters.rdoc b/doc/optparse/argument_converters.rdoc
index 4b4b30e8de..ac659da8c5 100644
--- a/doc/optparse/argument_converters.rdoc
+++ b/doc/optparse/argument_converters.rdoc
@@ -1,7 +1,7 @@
== Argument Converters
An option can specify that its argument is to be converted
-from the default +String+ to an instance of another class.
+from the default \String to an instance of another class.
=== Contents
@@ -27,13 +27,13 @@ from the default +String+ to an instance of another class.
=== Built-In Argument Converters
-+OptionParser+ has a number of built-in argument converters,
+\OptionParser has a number of built-in argument converters,
which are demonstrated below.
-==== +Date+
+==== \Date
File +date.rb+
-defines an option whose argument is to be converted to a +Date+ object.
+defines an option whose argument is to be converted to a \Date object.
The argument is converted by method Date#parse.
:include: ruby/date.rb
@@ -47,10 +47,10 @@ Executions:
$ ruby date.rb --date "3rd Feb 2001"
[#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, Date]
-==== +DateTime+
+==== \DateTime
File +datetime.rb+
-defines an option whose argument is to be converted to a +DateTime+ object.
+defines an option whose argument is to be converted to a \DateTime object.
The argument is converted by method DateTime#parse.
:include: ruby/datetime.rb
@@ -64,10 +64,10 @@ Executions:
$ ruby datetime.rb --datetime "3rd Feb 2001 04:05:06 PM"
[#<DateTime: 2001-02-03T16:05:06+00:00 ((2451944j,57906s,0n),+0s,2299161j)>, DateTime]
-==== +Time+
+==== \Time
File +time.rb+
-defines an option whose argument is to be converted to a +Time+ object.
+defines an option whose argument is to be converted to a \Time object.
The argument is converted by method Time#httpdate or Time#parse.
:include: ruby/time.rb
@@ -79,10 +79,10 @@ Executions:
$ ruby time.rb --time 2010-10-31
[2010-10-31 00:00:00 -0500, Time]
-==== +URI+
+==== \URI
File +uri.rb+
-defines an option whose argument is to be converted to a +URI+ object.
+defines an option whose argument is to be converted to a \URI object.
The argument is converted by method URI#parse.
:include: ruby/uri.rb
@@ -96,10 +96,10 @@ Executions:
$ ruby uri.rb --uri file://~/var
[#<URI::File file://~/var>, URI::File]
-==== +Shellwords+
+==== \Shellwords
File +shellwords.rb+
-defines an option whose argument is to be converted to an +Array+ object by method
+defines an option whose argument is to be converted to an \Array object by method
Shellwords#shellwords.
:include: ruby/shellwords.rb
@@ -111,10 +111,10 @@ Executions:
$ ruby shellwords.rb --shellwords "here are 'two words'"
[["here", "are", "two words"], Array]
-==== +Integer+
+==== \Integer
File +integer.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer.
:include: ruby/integer.rb
@@ -132,10 +132,10 @@ Executions:
$ ruby integer.rb --integer 0b100
[4, Integer]
-==== +Float+
+==== \Float
File +float.rb+
-defines an option whose argument is to be converted to a +Float+ object.
+defines an option whose argument is to be converted to a \Float object.
The argument is converted by method Kernel#Float.
:include: ruby/float.rb
@@ -151,11 +151,11 @@ Executions:
$ ruby float.rb --float 1.234E-2
[0.01234, Float]
-==== +Numeric+
+==== \Numeric
File +numeric.rb+
defines an option whose argument is to be converted to an instance
-of +Rational+, +Float+, or +Integer+.
+of \Rational, \Float, or \Integer.
The argument is converted by method Kernel#Rational,
Kernel#Float, or Kernel#Integer.
@@ -170,10 +170,10 @@ Executions:
$ ruby numeric.rb --numeric 3
[3, Integer]
-==== +DecimalInteger+
+==== \DecimalInteger
File +decimal_integer.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer.
:include: ruby/decimal_integer.rb
@@ -192,10 +192,10 @@ Executions:
$ ruby decimal_integer.rb --decimal_integer -0100
[-100, Integer]
-==== +OctalInteger+
+==== \OctalInteger
File +octal_integer.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer.
:include: ruby/octal_integer.rb
@@ -212,10 +212,10 @@ Executions:
$ ruby octal_integer.rb --octal_integer 0100
[64, Integer]
-==== +DecimalNumeric+
+==== \DecimalNumeric
File +decimal_numeric.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer
:include: ruby/decimal_numeric.rb
@@ -232,7 +232,7 @@ Executions:
$ ruby decimal_numeric.rb --decimal_numeric 0100
[64, Integer]
-==== +TrueClass+
+==== \TrueClass
File +true_class.rb+
defines an option whose argument is to be converted to +true+ or +false+.
@@ -259,7 +259,7 @@ Executions:
$ ruby true_class.rb --true_class nil
[false, FalseClass]
-==== +FalseClass+
+==== \FalseClass
File +false_class.rb+
defines an option whose argument is to be converted to +true+ or +false+.
@@ -286,10 +286,10 @@ Executions:
$ ruby false_class.rb --false_class +
[true, TrueClass]
-==== +Object+
+==== \Object
File +object.rb+
-defines an option whose argument is not to be converted from +String+.
+defines an option whose argument is not to be converted from \String.
:include: ruby/object.rb
@@ -300,10 +300,10 @@ Executions:
$ ruby object.rb --object nil
["nil", String]
-==== +String+
+==== \String
File +string.rb+
-defines an option whose argument is not to be converted from +String+.
+defines an option whose argument is not to be converted from \String.
:include: ruby/string.rb
@@ -314,10 +314,10 @@ Executions:
$ ruby string.rb --string nil
["nil", String]
-==== +Array+
+==== \Array
File +array.rb+
-defines an option whose argument is to be converted from +String+
+defines an option whose argument is to be converted from \String
to an array of strings, based on comma-separated substrings.
:include: ruby/array.rb
@@ -331,10 +331,10 @@ Executions:
$ ruby array.rb --array "foo, bar, baz"
[["foo", " bar", " baz"], Array]
-==== +Regexp+
+==== \Regexp
File +regexp.rb+
-defines an option whose argument is to be converted to a +Regexp+ object.
+defines an option whose argument is to be converted to a \Regexp object.
:include: ruby/regexp.rb
@@ -352,7 +352,7 @@ To create a custom converter, call OptionParser#accept with:
- A block that accepts the argument and returns the converted value.
This custom converter accepts any argument and converts it,
-if possible, to a +Complex+ object.
+if possible, to a \Complex object.
:include: ruby/custom_converter.rb
diff --git a/doc/optparse/option_params.rdoc b/doc/optparse/option_params.rdoc
index 55f9b53dff..ace2c4283f 100644
--- a/doc/optparse/option_params.rdoc
+++ b/doc/optparse/option_params.rdoc
@@ -1,6 +1,6 @@
== Parameters for New Options
-Option-creating methods in +OptionParser+
+Option-creating methods in \OptionParser
accept arguments that determine the behavior of a new option:
- OptionParser#on
@@ -405,7 +405,7 @@ Executions:
=== Argument Converters
An option can specify that its argument is to be converted
-from the default +String+ to an instance of another class.
+from the default \String to an instance of another class.
There are a number of built-in converters.
You can also define custom converters.
diff --git a/doc/optparse/tutorial.rdoc b/doc/optparse/tutorial.rdoc
index b104379cf7..b95089826d 100644
--- a/doc/optparse/tutorial.rdoc
+++ b/doc/optparse/tutorial.rdoc
@@ -1,10 +1,10 @@
== Tutorial
-=== Why +OptionParser+?
+=== Why \OptionParser?
When a Ruby program executes, it captures its command-line arguments
and options into variable ARGV.
-This simple program just prints its +ARGV+:
+This simple program just prints its \ARGV:
:include: ruby/argv.rb
@@ -18,7 +18,7 @@ the command-line options.
OptionParser offers methods for parsing and handling those options.
-With +OptionParser+, you can define options so that for each option:
+With \OptionParser, you can define options so that for each option:
- The code that defines the option and code that handles that option
are in the same place.
@@ -55,7 +55,7 @@ The class also has method #help, which displays automatically-generated help tex
- {Argument Converters}[#label-Argument+Converters]
- {Help}[#label-Help]
- {Top List and Base List}[#label-Top+List+and+Base+List]
-- {Methods for Defining Options}[#label-Methods+for+Defining+Options]
+- {Defining Options}[#label-Defining+Options]
- {Parsing}[#label-Parsing]
- {Method parse!}[#label-Method+parse-21]
- {Method parse}[#label-Method+parse]
@@ -66,10 +66,10 @@ The class also has method #help, which displays automatically-generated help tex
=== To Begin With
-To use +OptionParser+:
+To use \OptionParser:
-1. Require the +OptionParser+ code.
-2. Create an +OptionParser+ object.
+1. Require the \OptionParser code.
+2. Create an \OptionParser object.
3. Define one or more options.
4. Parse the command line.
@@ -92,9 +92,9 @@ the block defined for the option is called with the argument value.
An invalid option raises an exception.
Method #parse!, which is used most often in this tutorial,
-removes from +ARGV+ the options and arguments it finds,
+removes from \ARGV the options and arguments it finds,
leaving other non-option arguments for the program to handle on its own.
-The method returns the possibly-reduced +ARGV+ array.
+The method returns the possibly-reduced \ARGV array.
Executions:
@@ -115,7 +115,7 @@ Executions:
=== Defining Options
-A common way to define an option in +OptionParser+
+A common way to define an option in \OptionParser
is with instance method OptionParser#on.
The method may be called with any number of arguments
@@ -522,11 +522,11 @@ Executions:
=== Argument Converters
An option can specify that its argument is to be converted
-from the default +String+ to an instance of another class.
+from the default \String to an instance of another class.
There are a number of built-in converters.
Example: File +date.rb+
-defines an option whose argument is to be converted to a +Date+ object.
+defines an option whose argument is to be converted to a \Date object.
The argument is converted by method Date#parse.
:include: ruby/date.rb
@@ -546,7 +546,7 @@ for both built-in and custom converters.
=== Help
-+OptionParser+ makes automatically generated help text available.
+\OptionParser makes automatically generated help text available.
The help text consists of:
@@ -614,49 +614,49 @@ Execution:
=== Top List and Base List
-An +OptionParser+ object maintains a stack of OptionParser::List objects,
+An \OptionParser object maintains a stack of \OptionParser::List objects,
each of which has a collection of zero or more options.
It is unlikely that you'll need to add or take away from that stack.
The stack includes:
-- The <em>top list</em>, given by OptionParser#top.
-- The <em>base list</em>, given by OptionParser#base.
+- The <em>top list</em>, given by \OptionParser#top.
+- The <em>base list</em>, given by \OptionParser#base.
-When +OptionParser+ builds its help text, the options in the top list
+When \OptionParser builds its help text, the options in the top list
precede those in the base list.
-=== Methods for Defining Options
+=== Defining Options
Option-defining methods allow you to create an option, and also append/prepend it
to the top list or append it to the base list.
Each of these next three methods accepts a sequence of parameter arguments and a block,
-creates an option object using method OptionParser#make_switch (see below),
+creates an option object using method \Option#make_switch (see below),
and returns the created option:
-- \Method OptionParser#define appends the created option to the top list.
+- \Method \OptionParser#define appends the created option to the top list.
-- \Method OptionParser#define_head prepends the created option to the top list.
+- \Method \OptionParser#define_head prepends the created option to the top list.
-- \Method OptionParser#define_tail appends the created option to the base list.
+- \Method \OptionParser#define_tail appends the created option to the base list.
These next three methods are identical to the three above,
except for their return values:
-- \Method OptionParser#on is identical to method OptionParser#define,
+- \Method \OptionParser#on is identical to method \OptionParser#define,
except that it returns the parser object +self+.
-- \Method OptionParser#on_head is identical to method OptionParser#define_head,
+- \Method \OptionParser#on_head is identical to method \OptionParser#define_head,
except that it returns the parser object +self+.
-- \Method OptionParser#on_tail is identical to method OptionParser#define_tail,
+- \Method \OptionParser#on_tail is identical to method \OptionParser#define_tail,
except that it returns the parser object +self+.
Though you may never need to call it directly,
here's the core method for defining an option:
-- \Method OptionParser#make_switch accepts an array of parameters and a block.
+- \Method \OptionParser#make_switch accepts an array of parameters and a block.
See {Parameters for New Options}[optparse/option_params.rdoc].
This method is unlike others here in that it:
- Accepts an <em>array of parameters</em>;
@@ -668,7 +668,7 @@ here's the core method for defining an option:
=== Parsing
-+OptionParser+ has six instance methods for parsing.
+\OptionParser has six instance methods for parsing.
Three have names ending with a "bang" (<tt>!</tt>):
@@ -699,9 +699,9 @@ Each of these methods:
(see {Keyword Argument into}[#label-Keyword+Argument+into]).
- Returns +argv+, possibly with some elements removed.
-==== \Method +parse!+
+==== \Method parse!
-\Method +parse!+:
+\Method parse!:
- Accepts an optional array of string arguments +argv+;
if not given, +argv+ defaults to the value of OptionParser#default_argv,
@@ -756,9 +756,9 @@ Processing ended by non-option found when +POSIXLY_CORRECT+ is defined:
["--xxx", true]
Returned: ["input_file.txt", "output_file.txt", "-yyy", "FOO"] (Array)
-==== \Method +parse+
+==== \Method parse
-\Method +parse+:
+\Method parse:
- Accepts an array of string arguments
_or_ zero or more string arguments.
@@ -810,25 +810,25 @@ Processing ended by non-option found when +POSIXLY_CORRECT+ is defined:
["--xxx", true]
Returned: ["input_file.txt", "output_file.txt", "-yyy", "FOO"] (Array)
-==== \Method +order!+
+==== \Method order!
Calling method OptionParser#order! gives exactly the same result as
calling method OptionParser#parse! with environment variable
+POSIXLY_CORRECT+ defined.
-==== \Method +order+
+==== \Method order
Calling method OptionParser#order gives exactly the same result as
calling method OptionParser#parse with environment variable
+POSIXLY_CORRECT+ defined.
-==== \Method +permute!+
+==== \Method permute!
Calling method OptionParser#permute! gives exactly the same result as
calling method OptionParser#parse! with environment variable
+POSIXLY_CORRECT+ _not_ defined.
-==== \Method +permute+
+==== \Method permute
Calling method OptionParser#permute gives exactly the same result as
calling method OptionParser#parse with environment variable
diff --git a/doc/packed_data.rdoc b/doc/packed_data.rdoc
index bd71d13373..ec13b24c69 100644
--- a/doc/packed_data.rdoc
+++ b/doc/packed_data.rdoc
@@ -109,7 +109,7 @@ for one element in the input or output array.
s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF"
s.unpack('c*') # => [0, 1, -1]
-- <tt>'C'</tt> - 8-bit unsigned integer
+- <tt>'C'</tt> - 8-bit signed integer
(like C <tt>unsigned char</tt>):
[0, 1, 255].pack('C*') # => "\x00\x01\xFF"
@@ -214,16 +214,18 @@ for one element in the input or output array.
s.unpack('I*')
# => [67305985, 4244504319]
-- <tt>'j'</tt> - Pointer-width signed integer, native-endian
- (like C <tt>intptr_t</tt>):
+==== Pointer Directives
+
+- <tt>'j'</tt> - 64-bit pointer-width signed integer,
+ native-endian (like C <tt>intptr_t</tt>):
s = [67305985, -50462977].pack('j*')
# => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\xFF\xFF\xFF\xFF"
s.unpack('j*')
# => [67305985, -50462977]
-- <tt>'J'</tt> - Pointer-width unsigned integer, native-endian
- (like C <tt>uintptr_t</tt>):
+- <tt>'j'</tt> - 64-bit pointer-width unsigned integer,
+ native-endian (like C <tt>uintptr_t</tt>):
s = [67305985, 4244504319].pack('J*')
# => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\x00\x00\x00\x00"
@@ -231,7 +233,7 @@ for one element in the input or output array.
# => [67305985, 4244504319]
==== Other \Integer Directives
-
+:
- <tt>'U'</tt> - UTF-8 character:
s = [4194304].pack('U*')
@@ -249,19 +251,20 @@ for one element in the input or output array.
==== Modifiers for \Integer Directives
-For the following directives, <tt>'!'</tt> or <tt>'_'</tt> modifiers may be
-suffixed as underlying platform’s native size.
-
-- <tt>'i'</tt>, <tt>'I'</tt> - C <tt>int</tt>, always native size.
-- <tt>'s'</tt>, <tt>'S'</tt> - C <tt>short</tt>.
-- <tt>'l'</tt>, <tt>'L'</tt> - C <tt>long</tt>.
-- <tt>'q'</tt>, <tt>'Q'</tt> - C <tt>long long</tt>, if available.
-- <tt>'j'</tt>, <tt>'J'</tt> - C <tt>intptr_t</tt>, always native size.
-
-Native size modifiers are silently ignored for always native size directives.
-
-The endian modifiers also may be suffixed in the directives above:
-
+For directives in
+<tt>'i'</tt>,
+<tt>'I'</tt>,
+<tt>'s'</tt>,
+<tt>'S'</tt>,
+<tt>'l'</tt>,
+<tt>'L'</tt>,
+<tt>'q'</tt>,
+<tt>'Q'</tt>,
+<tt>'j'</tt>, and
+<tt>'J'</tt>,
+these modifiers may be suffixed:
+
+- <tt>'!'</tt> or <tt>'_'</tt> - Underlying platform’s native size.
- <tt>'>'</tt> - Big-endian.
- <tt>'<'</tt> - Little-endian.
diff --git a/doc/ractor.md b/doc/ractor.md
index 3ead510501..843754c263 100644
--- a/doc/ractor.md
+++ b/doc/ractor.md
@@ -393,7 +393,7 @@ TODO: `select` syntax of go-language uses round-robin technique to make fair sch
* `Ractor#close_incoming/outgoing` close incoming/outgoing ports (similar to `Queue#close`).
* `Ractor#close_incoming`
- * `r.send(obj)` where `r`'s incoming port is closed, will raise an exception.
+ * `r.send(obj) ` where `r`'s incoming port is closed, will raise an exception.
* When the incoming queue is empty and incoming port is closed, `Ractor.receive` raises an exception. If the incoming queue is not empty, it dequeues an object without exceptions.
* `Ractor#close_outgoing`
* `Ractor.yield` on a Ractor which closed the outgoing port, it will raise an exception.
@@ -536,7 +536,7 @@ The following objects are shareable.
Implementation: Now shareable objects (`RVALUE`) have `FL_SHAREABLE` flag. This flag can be added lazily.
-To make shareable objects, `Ractor.make_shareable(obj)` method is provided. In this case, try to make sharaeble by freezing `obj` and recursively traversable objects. This method accepts `copy:` keyword (default value is false).`Ractor.make_shareable(obj, copy: true)` tries to make a deep copy of `obj` and make the copied object shareable.
+To make shareable objects, `Ractor.make_shareable(obj)` method is provided. In this case, try to make sharaeble by freezing `obj` and recursively travasible objects. This method accepts `copy:` keyword (default value is false).`Ractor.make_shareable(obj, copy: true)` tries to make a deep copy of `obj` and make the copied object shareable.
## Language changes to isolate unshareable objects between Ractors
@@ -705,8 +705,8 @@ TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
* none: Do nothing. Same as: `CONST = expr`
* literal:
- * if `expr` consists of literals, replaced to `CONST = Ractor.make_shareable(expr)`.
- * otherwise: replaced to `CONST = expr.tap{|o| raise unless Ractor.shareable?(o)}`.
+ * if `expr` is consites of literals, replaced to `CONST = Ractor.make_shareable(expr)`.
+ * otherwise: replaced to `CONST = expr.tap{|o| raise unless Ractor.shareable?}`.
* experimental_everything: replaced to `CONST = Ractor.make_shareable(expr)`.
* experimental_copy: replaced to `CONST = Ractor.make_shareable(expr, copy: true)`.
diff --git a/doc/rdoc/markup_reference.rb b/doc/rdoc/markup_reference.rb
index dac5c84708..66ec6786c0 100644
--- a/doc/rdoc/markup_reference.rb
+++ b/doc/rdoc/markup_reference.rb
@@ -26,7 +26,7 @@ require 'rdoc'
# - Single-line or multi-line comments that precede certain definitions;
# see {Markup in Comments}[rdoc-ref:RDoc::MarkupReference@Markup+in+Comments].
# - \RDoc directives in trailing comments (on the same line as code);
-# see <tt>:nodoc:</tt>, <tt>:doc:</tt>, and <tt>:notnew:</tt>.
+# see <tt>:nodoc:</tt>, <tt>:doc:</tt>, and <tt>:notnew</tt>.
# - \RDoc directives in single-line comments;
# see other {Directives}[rdoc-ref:RDoc::MarkupReference@Directives].
# - The Ruby code itself (but not from C code);
@@ -66,7 +66,7 @@ require 'rdoc'
# In a multi-line comment,
# \RDoc looks for the comment's natural left margin,
# which becomes the <em>base margin</em> for the comment
-# and is the initial <em>current margin</em> for the comment.
+# and is the initial <em>current margin</em> for for the comment.
#
# The current margin can change, and does so, for example in a list.
#
@@ -346,7 +346,7 @@ require 'rdoc'
#
# ===== Lettered Lists
#
-# A lettered list item begins with letters and a period.
+# A numbered list item begins with a letters and a period.
#
# The items are automatically "re-lettered."
#
diff --git a/doc/regexp.rdoc b/doc/regexp.rdoc
index 309e109afd..92c7ecf66e 100644
--- a/doc/regexp.rdoc
+++ b/doc/regexp.rdoc
@@ -1,1269 +1,801 @@
-A {regular expression}[https://en.wikipedia.org/wiki/Regular_expression]
-(also called a _regexp_) is a <i>match pattern</i> (also simply called a _pattern_).
+# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*-
-A common notation for a regexp uses enclosing slash characters:
+Regular expressions (<i>regexp</i>s) are patterns which describe the
+contents of a string. They're used for testing whether a string contains a
+given pattern, or extracting the portions that match. They are created
+with the <tt>/</tt><i>pat</i><tt>/</tt> and
+<tt>%r{</tt><i>pat</i><tt>}</tt> literals or the <tt>Regexp.new</tt>
+constructor.
- /foo/
+A regexp is usually delimited with forward slashes (<tt>/</tt>). For
+example:
-A regexp may be applied to a <i>target string</i>;
-The part of the string (if any) that matches the pattern is called a _match_,
-and may be said <i>to match</i>:
+ /hay/ =~ 'haystack' #=> 0
+ /y/.match('haystack') #=> #<MatchData "y">
- re = /red/
- re.match?('redirect') # => true # Match at beginning of target.
- re.match?('bored') # => true # Match at end of target.
- re.match?('credit') # => true # Match within target.
- re.match?('foo') # => false # No match.
+If a string contains the pattern it is said to <i>match</i>. A literal
+string matches itself.
-== \Regexp Uses
+Here 'haystack' does not contain the pattern 'needle', so it doesn't match:
-A regexp may be used:
+ /needle/.match('haystack') #=> nil
-- To extract substrings based on a given pattern:
+Here 'haystack' contains the pattern 'hay', so it matches:
- re = /foo/ # => /foo/
- re.match('food') # => #<MatchData "foo">
- re.match('good') # => nil
+ /hay/.match('haystack') #=> #<MatchData "hay">
- See sections {Method match}[rdoc-ref:regexp.rdoc@Method+match]
- and {Operator =~}[rdoc-ref:regexp.rdoc@Operator+-3D~].
+Specifically, <tt>/st/</tt> requires that the string contains the letter
+_s_ followed by the letter _t_, so it matches _haystack_, also.
-- To determine whether a string matches a given pattern:
+Note that any Regexp matching will raise a RuntimeError if timeout is set and
+exceeded. See {"Timeout"}[#label-Timeout] section in detail.
- re.match?('food') # => true
- re.match?('good') # => false
+== \Regexp Interpolation
- See section {Method match?}[rdoc-ref:regexp.rdoc@Method+match-3F].
+A regexp may contain interpolated strings; trivially:
-- As an argument for calls to certain methods in other classes and modules;
- most such methods accept an argument that may be either a string
- or the (much more powerful) regexp.
+ foo = 'bar'
+ /#{foo}/ # => /bar/
- See {Regexp Methods}[./Regexp/methods_rdoc.html].
+== <tt>=~</tt> and Regexp#match
-== \Regexp Objects
+Pattern matching may be achieved by using <tt>=~</tt> operator or Regexp#match
+method.
-A regexp object has:
+=== <tt>=~</tt> Operator
-- A source; see {Sources}[rdoc-ref:regexp.rdoc@Sources].
+<tt>=~</tt> is Ruby's basic pattern-matching operator. When one operand is a
+regular expression and the other is a string then the regular expression is
+used as a pattern to match against the string. (This operator is equivalently
+defined by Regexp and String so the order of String and Regexp do not matter.
+Other classes may have different implementations of <tt>=~</tt>.) If a match
+is found, the operator returns index of first match in string, otherwise it
+returns +nil+.
-- Several modes; see {Modes}[rdoc-ref:regexp.rdoc@Modes].
+ /hay/ =~ 'haystack' #=> 0
+ 'haystack' =~ /hay/ #=> 0
+ /a/ =~ 'haystack' #=> 1
+ /u/ =~ 'haystack' #=> nil
-- A timeout; see {Timeouts}[rdoc-ref:regexp.rdoc@Timeouts].
+Using <tt>=~</tt> operator with a String and Regexp the <tt>$~</tt> global
+variable is set after a successful match. <tt>$~</tt> holds a MatchData
+object. Regexp.last_match is equivalent to <tt>$~</tt>.
-- An encoding; see {Encodings}[rdoc-ref:regexp.rdoc@Encodings].
+=== Regexp#match Method
-== Creating a \Regexp
+The #match method returns a MatchData object:
-A regular expression may be created with:
+ /st/.match('haystack') #=> #<MatchData "st">
-- A regexp literal using slash characters
- (see {Regexp Literals}[https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-Regexp+Literals]):
+== Metacharacters and Escapes
- # This is a very common usage.
- /foo/ # => /foo/
+The following are <i>metacharacters</i> <tt>(</tt>, <tt>)</tt>,
+<tt>[</tt>, <tt>]</tt>, <tt>{</tt>, <tt>}</tt>, <tt>.</tt>, <tt>?</tt>,
+<tt>+</tt>, <tt>*</tt>. They have a specific meaning when appearing in a
+pattern. To match them literally they must be backslash-escaped. To match
+a backslash literally, backslash-escape it: <tt>\\\\</tt>.
-- A <tt>%r</tt> regexp literal
- (see {%r: Regexp Literals}[https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-25r-3A+Regexp+Literals]):
+ /1 \+ 2 = 3\?/.match('Does 1 + 2 = 3?') #=> #<MatchData "1 + 2 = 3?">
+ /a\\\\b/.match('a\\\\b') #=> #<MatchData "a\\b">
- # Same delimiter character at beginning and end;
- # useful for avoiding escaping characters
- %r/name\/value pair/ # => /name\/value pair/
- %r:name/value pair: # => /name\/value pair/
- %r|name/value pair| # => /name\/value pair/
+Patterns behave like double-quoted strings and can contain the same
+backslash escapes (the meaning of <tt>\s</tt> is different, however,
+see below[#label-Character+Classes]).
- # Certain "paired" characters can be delimiters.
- %r[foo] # => /foo/
- %r{foo} # => /foo/
- %r(foo) # => /foo/
- %r<foo> # => /foo/
+ /\s\u{6771 4eac 90fd}/.match("Go to 東京都")
+ #=> #<MatchData " 東京都">
-- \Method Regexp.new.
+Arbitrary Ruby expressions can be embedded into patterns with the
+<tt>#{...}</tt> construct.
-== \Method <tt>match</tt>
+ place = "東京都"
+ /#{place}/.match("Go to 東京都")
+ #=> #<MatchData "東京都">
-Each of the methods Regexp#match, String#match, and Symbol#match
-returns a MatchData object if a match was found, +nil+ otherwise;
-each also sets {global variables}[rdoc-ref:regexp.rdoc@Global+Variables]:
+== Character Classes
- 'food'.match(/foo/) # => #<MatchData "foo">
- 'food'.match(/bar/) # => nil
+A <i>character class</i> is delimited with square brackets (<tt>[</tt>,
+<tt>]</tt>) and lists characters that may appear at that point in the
+match. <tt>/[ab]/</tt> means _a_ or _b_, as opposed to <tt>/ab/</tt> which
+means _a_ followed by _b_.
-== Operator <tt>=~</tt>
+ /W[aeiou]rd/.match("Word") #=> #<MatchData "Word">
-Each of the operators Regexp#=~, String#=~, and Symbol#=~
-returns an integer offset if a match was found, +nil+ otherwise;
-each also sets {global variables}[rdoc-ref:regexp.rdoc@Global+Variables]:
+Within a character class the hyphen (<tt>-</tt>) is a metacharacter
+denoting an inclusive range of characters. <tt>[abcd]</tt> is equivalent
+to <tt>[a-d]</tt>. A range can be followed by another range, so
+<tt>[abcdwxyz]</tt> is equivalent to <tt>[a-dw-z]</tt>. The order in which
+ranges or individual characters appear inside a character class is
+irrelevant.
- /bar/ =~ 'foo bar' # => 4
- 'foo bar' =~ /bar/ # => 4
- /baz/ =~ 'foo bar' # => nil
+ /[0-9a-f]/.match('9f') #=> #<MatchData "9">
+ /[9f]/.match('9f') #=> #<MatchData "9">
-== \Method <tt>match?</tt>
+If the first character of a character class is a caret (<tt>^</tt>) the
+class is inverted: it matches any character _except_ those named.
-Each of the methods Regexp#match?, String#match?, and Symbol#match?
-returns +true+ if a match was found, +false+ otherwise;
-none sets {global variables}[rdoc-ref:regexp.rdoc@Global+Variables]:
+ /[^a-eg-z]/.match('f') #=> #<MatchData "f">
- 'food'.match?(/foo/) # => true
- 'food'.match?(/bar/) # => false
+A character class may contain another character class. By itself this
+isn't useful because <tt>[a-z[0-9]]</tt> describes the same set as
+<tt>[a-z0-9]</tt>. However, character classes also support the <tt>&&</tt>
+operator which performs set intersection on its arguments. The two can be
+combined as follows:
-== Global Variables
-
-Certain regexp-oriented methods assign values to global variables:
-
-- <tt>#match</tt>: see {Method match}[rdoc-ref:regexp.rdoc@Method+match].
-- <tt>#=~</tt>: see {Operator =~}[rdoc-ref:regexp.rdoc@Operator+-3D~].
-
-The affected global variables are:
-
-- <tt>$~</tt>: Returns a MatchData object, or +nil+.
-- <tt>$&</tt>: Returns the matched part of the string, or +nil+.
-- <tt>$`</tt>: Returns the part of the string to the left of the match, or +nil+.
-- <tt>$'</tt>: Returns the part of the string to the right of the match, or +nil+.
-- <tt>$+</tt>: Returns the last group matched, or +nil+.
-- <tt>$1</tt>, <tt>$2</tt>, etc.: Returns the first, second, etc.,
- matched group, or +nil+.
- Note that <tt>$0</tt> is quite different;
- it returns the name of the currently executing program.
-
-Examples:
-
- # Matched string, but no matched groups.
- 'foo bar bar baz'.match('bar')
- $~ # => #<MatchData "bar">
- $& # => "bar"
- $` # => "foo "
- $' # => " bar baz"
- $+ # => nil
- $1 # => nil
-
- # Matched groups.
- /s(\w{2}).*(c)/.match('haystack')
- $~ # => #<MatchData "stac" 1:"ta" 2:"c">
- $& # => "stac"
- $` # => "hay"
- $' # => "k"
- $+ # => "c"
- $1 # => "ta"
- $2 # => "c"
- $3 # => nil
-
- # No match.
- 'foo'.match('bar')
- $~ # => nil
- $& # => nil
- $` # => nil
- $' # => nil
- $+ # => nil
- $1 # => nil
-
-Note that Regexp#match?, String#match?, and Symbol#match?
-do not set global variables.
-
-== Sources
-
-As seen above, the simplest regexp uses a literal expression as its source:
-
- re = /foo/ # => /foo/
- re.match('food') # => #<MatchData "foo">
- re.match('good') # => nil
-
-A rich collection of available _subexpressions_
-gives the regexp great power and flexibility:
-
-- {Special characters}[rdoc-ref:regexp.rdoc@Special+Characters]
-- {Source literals}[rdoc-ref:regexp.rdoc@Source+Literals]
-- {Character classes}[rdoc-ref:regexp.rdoc@Character+Classes]
-- {Shorthand character classes}[rdoc-ref:regexp.rdoc@Shorthand+Character+Classes]
-- {Anchors}[rdoc-ref:regexp.rdoc@Anchors]
-- {Alternation}[rdoc-ref:regexp.rdoc@Alternation]
-- {Quantifiers}[rdoc-ref:regexp.rdoc@Quantifiers]
-- {Groups and captures}[rdoc-ref:regexp.rdoc@Groups+and+Captures]
-- {Unicode}[rdoc-ref:regexp.rdoc@Unicode]
-- {POSIX Bracket Expressions}[rdoc-ref:regexp.rdoc@POSIX+Bracket+Expressions]
-- {Comments}[rdoc-ref:regexp.rdoc@Comments]
-
-=== Special Characters
-
-\Regexp special characters, called _metacharacters_,
-have special meanings in certain contexts;
-depending on the context, these are sometimes metacharacters:
-
- . ? - + * ^ \ | $ ( ) [ ] { }
-
-To match a metacharacter literally, backslash-escape it:
-
- # Matches one or more 'o' characters.
- /o+/.match('foo') # => #<MatchData "oo">
- # Would match 'o+'.
- /o\+/.match('foo') # => nil
-
-To match a backslash literally, backslash-escape it:
-
- /\./.match('\.') # => #<MatchData ".">
- /\\./.match('\.') # => #<MatchData "\\.">
-
-Method Regexp.escape returns an escaped string:
-
- Regexp.escape('.?-+*^\|$()[]{}')
- # => "\\.\\?\\-\\+\\*\\^\\\\\\|\\$\\(\\)\\[\\]\\{\\}"
-
-=== Source Literals
-
-The source literal largely behaves like a double-quoted string;
-see {String Literals}[rdoc-ref:syntax/literals.rdoc@String+Literals].
-
-In particular, a source literal may contain interpolated expressions:
-
- s = 'foo' # => "foo"
- /#{s}/ # => /foo/
- /#{s.capitalize}/ # => /Foo/
- /#{2 + 2}/ # => /4/
-
-There are differences between an ordinary string literal and a source literal;
-see {Shorthand Character Classes}[rdoc-ref:regexp.rdoc@Shorthand+Character+Classes].
-
-- <tt>\s</tt> in an ordinary string literal is equivalent to a space character;
- in a source literal, it's shorthand for matching a whitespace character.
-- In an ordinary string literal, these are (needlessly) escaped characters;
- in a source literal, they are shorthands for various matching characters:
-
- \w \W \d \D \h \H \S \R
-
-=== Character Classes
-
-A <i>character class</i> is delimited by square brackets;
-it specifies that certain characters match at a given point in the target string:
-
- # This character class will match any vowel.
- re = /B[aeiou]rd/
- re.match('Bird') # => #<MatchData "Bird">
- re.match('Bard') # => #<MatchData "Bard">
- re.match('Byrd') # => nil
-
-A character class may contain hyphen characters to specify ranges of characters:
-
- # These regexps have the same effect.
- /[abcdef]/.match('foo') # => #<MatchData "f">
- /[a-f]/.match('foo') # => #<MatchData "f">
- /[a-cd-f]/.match('foo') # => #<MatchData "f">
-
-When the first character of a character class is a caret (<tt>^</tt>),
-the sense of the class is inverted: it matches any character _except_ those specified.
-
- /[^a-eg-z]/.match('f') # => #<MatchData "f">
-
-A character class may contain another character class.
-By itself this isn't useful because <tt>[a-z[0-9]]</tt>
-describes the same set as <tt>[a-z0-9]</tt>.
-
-However, character classes also support the <tt>&&</tt> operator,
-which performs set intersection on its arguments.
-The two can be combined as follows:
-
- /[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))
+ /[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))
This is equivalent to:
/[abh-w]/
-=== Shorthand Character Classes
-
-Each of the following metacharacters serves as a shorthand
-for a character class:
-
-- <tt>/./</tt>: Matches any character except a newline:
-
- /./.match('foo') # => #<MatchData "f">
- /./.match("\n") # => nil
-
-- <tt>/./m</tt>: Matches any character, including a newline;
- see {Multiline Mode}[rdoc-ref:regexp.rdoc@Multiline+Mode}:
-
- /./m.match("\n") # => #<MatchData "\n">
-
-- <tt>/\w/</tt>: Matches a word character: equivalent to <tt>[a-zA-Z0-9_]</tt>:
-
- /\w/.match(' foo') # => #<MatchData "f">
- /\w/.match(' _') # => #<MatchData "_">
- /\w/.match(' ') # => nil
-
-- <tt>/\W/</tt>: Matches a non-word character: equivalent to <tt>[^a-zA-Z0-9_]</tt>:
-
- /\W/.match(' ') # => #<MatchData " ">
- /\W/.match('_') # => nil
-
-- <tt>/\d/</tt>: Matches a digit character: equivalent to <tt>[0-9]</tt>:
-
- /\d/.match('THX1138') # => #<MatchData "1">
- /\d/.match('foo') # => nil
-
-- <tt>/\D/</tt>: Matches a non-digit character: equivalent to <tt>[^0-9]</tt>:
-
- /\D/.match('123Jump!') # => #<MatchData "J">
- /\D/.match('123') # => nil
-
-- <tt>/\h/</tt>: Matches a hexdigit character: equivalent to <tt>[0-9a-fA-F]</tt>:
-
- /\h/.match('xyz fedcba9876543210') # => #<MatchData "f">
- /\h/.match('xyz') # => nil
-
-- <tt>/\H/</tt>: Matches a non-hexdigit character: equivalent to <tt>[^0-9a-fA-F]</tt>:
-
- /\H/.match('fedcba9876543210xyz') # => #<MatchData "x">
- /\H/.match('fedcba9876543210') # => nil
-
-- <tt>/\s/</tt>: Matches a whitespace character: equivalent to <tt>/[ \t\r\n\f\v]/</tt>:
-
- /\s/.match('foo bar') # => #<MatchData " ">
- /\s/.match('foo') # => nil
-
-- <tt>/\S/</tt>: Matches a non-whitespace character: equivalent to <tt>/[^ \t\r\n\f\v]/</tt>:
-
- /\S/.match(" \t\r\n\f\v foo") # => #<MatchData "f">
- /\S/.match(" \t\r\n\f\v") # => nil
-
-- <tt>/\R/</tt>: Matches a linebreak, platform-independently:
-
- /\R/.match("\r") # => #<MatchData "\r"> # Carriage return (CR)
- /\R/.match("\n") # => #<MatchData "\n"> # Newline (LF)
- /\R/.match("\f") # => #<MatchData "\f"> # Formfeed (FF)
- /\R/.match("\v") # => #<MatchData "\v"> # Vertical tab (VT)
- /\R/.match("\r\n") # => #<MatchData "\r\n"> # CRLF
- /\R/.match("\u0085") # => #<MatchData "\u0085"> # Next line (NEL)
- /\R/.match("\u2028") # => #<MatchData "\u2028"> # Line separator (LSEP)
- /\R/.match("\u2029") # => #<MatchData "\u2029"> # Paragraph separator (PSEP)
-
-=== Anchors
-
-An anchor is a metasequence that matches a zero-width position between
-characters in the target string.
-
-For a subexpression with no anchor,
-matching may begin anywhere in the target string:
-
- /real/.match('surrealist') # => #<MatchData "real">
-
-For a subexpression with an anchor,
-matching must begin at the matched anchor.
-
-==== Boundary Anchors
-
-Each of these anchors matches a boundary:
-
-- <tt>^</tt>: Matches the beginning of a line:
-
- /^bar/.match("foo\nbar") # => #<MatchData "bar">
- /^ar/.match("foo\nbar") # => nil
-
-- <tt>$</tt>: Matches the end of a line:
-
- /bar$/.match("foo\nbar") # => #<MatchData "bar">
- /ba$/.match("foo\nbar") # => nil
-
-- <tt>\A</tt>: Matches the beginning of the string:
-
- /\Afoo/.match('foo bar') # => #<MatchData "foo">
- /\Afoo/.match(' foo bar') # => nil
-
-- <tt>\Z</tt>: Matches the end of the string;
- if string ends with a single newline,
- it matches just before the ending newline:
-
- /foo\Z/.match('bar foo') # => #<MatchData "foo">
- /foo\Z/.match('foo bar') # => nil
- /foo\Z/.match("bar foo\n") # => #<MatchData "foo">
- /foo\Z/.match("bar foo\n\n") # => nil
-
-- <tt>\z</tt>: Matches the end of the string:
-
- /foo\z/.match('bar foo') # => #<MatchData "foo">
- /foo\z/.match('foo bar') # => nil
- /foo\z/.match("bar foo\n") # => nil
-
-- <tt>\b</tt>: Matches word boundary when not inside brackets;
- matches backspace (<tt>"0x08"</tt>) when inside brackets:
-
- /foo\b/.match('foo bar') # => #<MatchData "foo">
- /foo\b/.match('foobar') # => nil
-
-- <tt>\B</tt>: Matches non-word boundary:
-
- /foo\B/.match('foobar') # => #<MatchData "foo">
- /foo\B/.match('foo bar') # => nil
-
-- <tt>\G</tt>: Matches first matching position:
-
- In methods like String#gsub and String#scan, it changes on each iteration.
- It initially matches the beginning of subject, and in each following iteration it matches where the last match finished.
-
- " a b c".gsub(/ /, '_') # => "____a_b_c"
- " a b c".gsub(/\G /, '_') # => "____a b c"
-
- In methods like Regexp#match and String#match
- that take an optional offset, it matches where the search begins.
-
- "hello, world".match(/,/, 3) # => #<MatchData ",">
- "hello, world".match(/\G,/, 3) # => nil
-
-==== Lookaround Anchors
-
-Lookahead anchors:
-
-- <tt>(?=_pat_)</tt>: Positive lookahead assertion:
- ensures that the following characters match _pat_,
- but doesn't include those characters in the matched substring.
-
-- <tt>(?!_pat_)</tt>: Negative lookahead assertion:
- ensures that the following characters <i>do not</i> match _pat_,
- but doesn't include those characters in the matched substring.
-
-Lookbehind anchors:
-
-- <tt>(?<=_pat_)</tt>: Positive lookbehind assertion:
- ensures that the preceding characters match _pat_, but
- doesn't include those characters in the matched substring.
-
-- <tt>(?<!_pat_)</tt>: Negative lookbehind assertion:
- ensures that the preceding characters do not match
- _pat_, but doesn't include those characters in the matched substring.
-
-The pattern below uses positive lookahead and positive lookbehind to match
-text appearing in <tt><b></tt>...<tt></b></tt> tags
-without including the tags in the match:
-
- /(?<=<b>)\w+(?=<\/b>)/.match("Fortune favors the <b>bold</b>.")
- # => #<MatchData "bold">
-
-==== Match-Reset Anchor
-
-- <tt>\K</tt>: Match reset:
- the matched content preceding <tt>\K</tt> in the regexp is excluded from the result.
- For example, the following two regexps are almost equivalent:
-
- /ab\Kc/.match('abc') # => #<MatchData "c">
- /(?<=ab)c/.match('abc') # => #<MatchData "c">
-
- These match same string and <tt>$&</tt> equals <tt>'c'</tt>,
- while the matched position is different.
-
- As are the following two regexps:
-
- /(a)\K(b)\Kc/
- /(?<=(?<=(a))(b))c/
-
-=== Alternation
-
-The vertical bar metacharacter (<tt>|</tt>) may be used within parentheses
-to express alternation:
-two or more subexpressions any of which may match the target string.
-
-Two alternatives:
-
- re = /(a|b)/
- re.match('foo') # => nil
- re.match('bar') # => #<MatchData "b" 1:"b">
-
-Four alternatives:
-
- re = /(a|b|c|d)/
- re.match('shazam') # => #<MatchData "a" 1:"a">
- re.match('cold') # => #<MatchData "c" 1:"c">
-
-Each alternative is a subexpression, and may be composed of other subexpressions:
-
- re = /([a-c]|[x-z])/
- re.match('bar') # => #<MatchData "b" 1:"b">
- re.match('ooz') # => #<MatchData "z" 1:"z">
-
-\Method Regexp.union provides a convenient way to construct
-a regexp with alternatives.
-
-=== Quantifiers
-
-A simple regexp matches one character:
-
- /\w/.match('Hello') # => #<MatchData "H">
-
-An added _quantifier_ specifies how many matches are required or allowed:
-
-- <tt>*</tt> - Matches zero or more times:
-
- /\w*/.match('')
- # => #<MatchData "">
- /\w*/.match('x')
- # => #<MatchData "x">
- /\w*/.match('xyz')
- # => #<MatchData "yz">
-
-- <tt>+</tt> - Matches one or more times:
-
- /\w+/.match('') # => nil
- /\w+/.match('x') # => #<MatchData "x">
- /\w+/.match('xyz') # => #<MatchData "xyz">
-
-- <tt>?</tt> - Matches zero or one times:
-
- /\w?/.match('') # => #<MatchData "">
- /\w?/.match('x') # => #<MatchData "x">
- /\w?/.match('xyz') # => #<MatchData "x">
-
-- <tt>{</tt>_n_<tt>}</tt> - Matches exactly _n_ times:
-
- /\w{2}/.match('') # => nil
- /\w{2}/.match('x') # => nil
- /\w{2}/.match('xyz') # => #<MatchData "xy">
-
-- <tt>{</tt>_min_<tt>,}</tt> - Matches _min_ or more times:
-
- /\w{2,}/.match('') # => nil
- /\w{2,}/.match('x') # => nil
- /\w{2,}/.match('xy') # => #<MatchData "xy">
- /\w{2,}/.match('xyz') # => #<MatchData "xyz">
-
-- <tt>{,</tt>_max_<tt>}</tt> - Matches _max_ or fewer times:
-
- /\w{,2}/.match('') # => #<MatchData "">
- /\w{,2}/.match('x') # => #<MatchData "x">
- /\w{,2}/.match('xyz') # => #<MatchData "xy">
-
-- <tt>{</tt>_min_<tt>,</tt>_max_<tt>}</tt> -
- Matches at least _min_ times and at most _max_ times:
-
- /\w{1,2}/.match('') # => nil
- /\w{1,2}/.match('x') # => #<MatchData "x">
- /\w{1,2}/.match('xyz') # => #<MatchData "xy">
-
-==== Greedy, Lazy, or Possessive Matching
-
-Quantifier matching may be greedy, lazy, or possessive:
-
-- In _greedy_ matching, as many occurrences as possible are matched
- while still allowing the overall match to succeed.
- Greedy quantifiers: <tt>*</tt>, <tt>+</tt>, <tt>?</tt>,
- <tt>{min, max}</tt> and its variants.
-- In _lazy_ matching, the minimum number of occurrences are matched.
- Lazy quantifiers: <tt>*?</tt>, <tt>+?</tt>, <tt>??</tt>,
- <tt>{min, max}?</tt> and its variants.
-- In _possessive_ matching, once a match is found, there is no backtracking;
- that match is retained, even if it jeopardises the overall match.
- Possessive quantifiers: <tt>*+</tt>, <tt>++</tt>, <tt>?+</tt>.
- Note that <tt>{min, max}</tt> and its variants do _not_ support possessive matching.
-
-More:
-
-- About greedy and lazy matching, see
- {Choosing Minimal or Maximal Repetition}[https://doc.lagout.org/programmation/Regular%20Expressions/Regular%20Expressions%20Cookbook_%20Detailed%20Solutions%20in%20Eight%20Programming%20Languages%20%282nd%20ed.%29%20%5BGoyvaerts%20%26%20Levithan%202012-09-06%5D.pdf#tutorial-backtrack].
-- About possessive matching, see
- {Eliminate Needless Backtracking}[https://doc.lagout.org/programmation/Regular%20Expressions/Regular%20Expressions%20Cookbook_%20Detailed%20Solutions%20in%20Eight%20Programming%20Languages%20%282nd%20ed.%29%20%5BGoyvaerts%20%26%20Levithan%202012-09-06%5D.pdf#tutorial-backtrack].
-
-=== Groups and Captures
-
-A simple regexp has (at most) one match:
+The following metacharacters also behave like character classes:
+
+* <tt>/./</tt> - Any character except a newline.
+* <tt>/./m</tt> - Any character (the +m+ modifier enables multiline mode)
+* <tt>/\w/</tt> - A word character (<tt>[a-zA-Z0-9_]</tt>)
+* <tt>/\W/</tt> - A non-word character (<tt>[^a-zA-Z0-9_]</tt>).
+ Please take a look at {Bug #4044}[https://bugs.ruby-lang.org/issues/4044] if
+ using <tt>/\W/</tt> with the <tt>/i</tt> modifier.
+* <tt>/\d/</tt> - A digit character (<tt>[0-9]</tt>)
+* <tt>/\D/</tt> - A non-digit character (<tt>[^0-9]</tt>)
+* <tt>/\h/</tt> - A hexdigit character (<tt>[0-9a-fA-F]</tt>)
+* <tt>/\H/</tt> - A non-hexdigit character (<tt>[^0-9a-fA-F]</tt>)
+* <tt>/\s/</tt> - A whitespace character: <tt>/[ \t\r\n\f\v]/</tt>
+* <tt>/\S/</tt> - A non-whitespace character: <tt>/[^ \t\r\n\f\v]/</tt>
+* <tt>/\R/</tt> - A linebreak: <tt>\n</tt>, <tt>\v</tt>, <tt>\f</tt>, <tt>\r</tt>
+ <tt>\u0085</tt> (NEXT LINE), <tt>\u2028</tt> (LINE SEPARATOR), <tt>\u2029</tt> (PARAGRAPH SEPARATOR)
+ or <tt>\r\n</tt>.
+
+POSIX <i>bracket expressions</i> are also similar to character classes.
+They provide a portable alternative to the above, with the added benefit
+that they encompass non-ASCII characters. For instance, <tt>/\d/</tt>
+matches only the ASCII decimal digits (0-9); whereas <tt>/[[:digit:]]/</tt>
+matches any character in the Unicode _Nd_ category.
+
+* <tt>/[[:alnum:]]/</tt> - Alphabetic and numeric character
+* <tt>/[[:alpha:]]/</tt> - Alphabetic character
+* <tt>/[[:blank:]]/</tt> - Space or tab
+* <tt>/[[:cntrl:]]/</tt> - Control character
+* <tt>/[[:digit:]]/</tt> - Digit
+* <tt>/[[:graph:]]/</tt> - Non-blank character (excludes spaces, control
+ characters, and similar)
+* <tt>/[[:lower:]]/</tt> - Lowercase alphabetical character
+* <tt>/[[:print:]]/</tt> - Like [:graph:], but includes the space character
+* <tt>/[[:punct:]]/</tt> - Punctuation character
+* <tt>/[[:space:]]/</tt> - Whitespace character (<tt>[:blank:]</tt>, newline,
+ carriage return, etc.)
+* <tt>/[[:upper:]]/</tt> - Uppercase alphabetical
+* <tt>/[[:xdigit:]]/</tt> - Digit allowed in a hexadecimal number (i.e.,
+ 0-9a-fA-F)
- re = /\d\d\d\d-\d\d-\d\d/
- re.match('1943-02-04') # => #<MatchData "1943-02-04">
- re.match('1943-02-04').size # => 1
- re.match('foo') # => nil
+Ruby also supports the following non-POSIX character classes:
-Adding one or more pairs of parentheses, <tt>(_subexpression_)</tt>,
-defines _groups_, which may result in multiple matched substrings,
-called _captures_:
+* <tt>/[[:word:]]/</tt> - A character in one of the following Unicode
+ general categories _Letter_, _Mark_, _Number_,
+ <i>Connector_Punctuation</i>
+* <tt>/[[:ascii:]]/</tt> - A character in the ASCII character set
- re = /(\d\d\d\d)-(\d\d)-(\d\d)/
- re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04">
- re.match('1943-02-04').size # => 4
+ # U+06F2 is "EXTENDED ARABIC-INDIC DIGIT TWO"
+ /[[:digit:]]/.match("\u06F2") #=> #<MatchData "\u{06F2}">
+ /[[:upper:]][[:lower:]]/.match("Hello") #=> #<MatchData "He">
+ /[[:xdigit:]][[:xdigit:]]/.match("A6") #=> #<MatchData "A6">
-The first capture is the entire matched string;
-the other captures are the matched substrings from the groups.
+== Repetition
-A group may have a
-{quantifier}[rdoc-ref:regexp.rdoc@Quantifiers]:
+The constructs described so far match a single character. They can be
+followed by a repetition metacharacter to specify how many times they need
+to occur. Such metacharacters are called <i>quantifiers</i>.
- re = /July 4(th)?/
- re.match('July 4') # => #<MatchData "July 4" 1:nil>
- re.match('July 4th') # => #<MatchData "July 4th" 1:"th">
+* <tt>*</tt> - Zero or more times
+* <tt>+</tt> - One or more times
+* <tt>?</tt> - Zero or one times (optional)
+* <tt>{</tt><i>n</i><tt>}</tt> - Exactly <i>n</i> times
+* <tt>{</tt><i>n</i><tt>,}</tt> - <i>n</i> or more times
+* <tt>{,</tt><i>m</i><tt>}</tt> - <i>m</i> or less times
+* <tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}</tt> - At least <i>n</i> and
+ at most <i>m</i> times
- re = /(foo)*/
- re.match('') # => #<MatchData "" 1:nil>
- re.match('foo') # => #<MatchData "foo" 1:"foo">
- re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
+At least one uppercase character ('H'), at least one lowercase character
+('e'), two 'l' characters, then one 'o':
- re = /(foo)+/
- re.match('') # => nil
- re.match('foo') # => #<MatchData "foo" 1:"foo">
- re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
+ "Hello".match(/[[:upper:]]+[[:lower:]]+l{2}o/) #=> #<MatchData "Hello">
-The returned \MatchData object gives access to the matched substrings:
+=== Greedy Match
- re = /(\d\d\d\d)-(\d\d)-(\d\d)/
- md = re.match('1943-02-04')
- # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04">
- md[0] # => "1943-02-04"
- md[1] # => "1943"
- md[2] # => "02"
- md[3] # => "04"
+Repetition is <i>greedy</i> by default: as many occurrences as possible
+are matched while still allowing the overall match to succeed. By
+contrast, <i>lazy</i> matching makes the minimal amount of matches
+necessary for overall success. Most greedy metacharacters can be made lazy
+by following them with <tt>?</tt>. For the <tt>{n}</tt> pattern, because
+it specifies an exact number of characters to match and not a variable
+number of characters, the <tt>?</tt> metacharacter instead makes the
+repeated pattern optional.
-==== Non-Capturing Groups
+Both patterns below match the string. The first uses a greedy quantifier so
+'.+' matches '<a><b>'; the second uses a lazy quantifier so '.+?' matches
+'<a>':
-A group may be made non-capturing;
-it is still a group (and, for example, can have a quantifier),
-but its matching substring is not included among the captures.
+ /<.+>/.match("<a><b>") #=> #<MatchData "<a><b>">
+ /<.+?>/.match("<a><b>") #=> #<MatchData "<a>">
-A non-capturing group begins with <tt>?:</tt> (inside the parentheses):
+=== Possessive Match
- # Don't capture the year.
- re = /(?:\d\d\d\d)-(\d\d)-(\d\d)/
- md = re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"02" 2:"04">
+A quantifier followed by <tt>+</tt> matches <i>possessively</i>: once it
+has matched it does not backtrack. They behave like greedy quantifiers,
+but having matched they refuse to "give up" their match even if this
+jeopardises the overall match.
-==== Backreferences
+ /<.*><.+>/.match("<a><b>") #=> #<MatchData "<a><b>">
+ /<.*+><.+>/.match("<a><b>") #=> nil
+ /<.*><.++>/.match("<a><b>") #=> nil
-A group match may also be referenced within the regexp itself;
-such a reference is called a +backreference+:
+== Capturing
- /[csh](..) [csh]\1 in/.match('The cat sat in the hat')
- # => #<MatchData "cat sat in" 1:"at">
+Parentheses can be used for <i>capturing</i>. The text enclosed by the
+<i>n</i>th group of parentheses can be subsequently referred to
+with <i>n</i>. Within a pattern use the <i>backreference</i>
+<tt>\n</tt> (e.g. <tt>\1</tt>); outside of the pattern use
+<tt>MatchData[n]</tt> (e.g. <tt>MatchData[1]</tt>).
-This table shows how each subexpression in the regexp above
-matches a substring in the target string:
+In this example, <tt>'at'</tt> is captured by the first group of
+parentheses, then referred to later with <tt>\1</tt>:
- | Subexpression in Regexp | Matching Substring in Target String |
- |---------------------------|-------------------------------------|
- | First '[csh]' | Character 'c' |
- | '(..)' | First substring 'at' |
- | First space ' ' | First space character ' ' |
- | Second '[csh]' | Character 's' |
- | '\1' (backreference 'at') | Second substring 'at' |
- | ' in' | Substring ' in' |
+ /[csh](..) [csh]\1 in/.match("The cat sat in the hat")
+ #=> #<MatchData "cat sat in" 1:"at">
-A regexp may contain any number of groups:
+Regexp#match returns a MatchData object which makes the captured text
+available with its #[] method:
-- For a large number of groups:
+ /[csh](..) [csh]\1 in/.match("The cat sat in the hat")[1] #=> 'at'
- - The ordinary <tt>\\_n_</tt> notation applies only for _n_ in range (1..9).
- - The <tt>MatchData[_n_]</tt> notation applies for any non-negative _n_.
+While Ruby supports an arbitrary number of numbered captured groups,
+only groups 1-9 are supported using the <tt>\n</tt> backreference
+syntax.
-- <tt>\0</tt> is a special backreference, referring to the entire matched string;
- it may not be used within the regexp itself,
- but may be used outside it (for example, in a substitution method call):
+Ruby also supports <tt>\0</tt> as a special backreference, which
+references the entire matched string. This is also available at
+<tt>MatchData[0]</tt>. Note that the <tt>\0</tt> backreference cannot
+be used inside the regexp, as backreferences can only be used after the
+end of the capture group, and the <tt>\0</tt> backreference uses the
+implicit capture group of the entire match. However, you can use
+this backreference when doing substitution:
- 'The cat sat in the hat'.gsub(/[csh]at/, '\0s')
+ "The cat sat in the hat".gsub(/[csh]at/, '\0s')
# => "The cats sats in the hats"
-==== Named Captures
-
-As seen above, a capture can be referred to by its number.
-A capture can also have a name,
-prefixed as <tt>?<_name_></tt> or <tt>?'_name_'</tt>,
-and the name (symbolized) may be used as an index in <tt>MatchData[]</tt>:
-
- md = /\$(?<dollars>\d+)\.(?'cents'\d+)/.match("$3.67")
- # => #<MatchData "$3.67" dollars:"3" cents:"67">
- md[:dollars] # => "3"
- md[:cents] # => "67"
- # The capture numbers are still valid.
- md[2] # => "67"
-
-When a regexp contains a named capture, there are no unnamed captures:
-
- /\$(?<dollars>\d+)\.(\d+)/.match("$3.67")
- # => #<MatchData "$3.67" dollars:"3">
-
-A named group may be backreferenced as <tt>\k<_name_></tt>:
-
- /(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
- # => #<MatchData "ototo" vowel:"o">
-
-When (and only when) a regexp contains named capture groups
-and appears before the <tt>=~</tt> operator,
-the captured substrings are assigned to local variables with corresponding names:
-
- /\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ '$3.67'
- dollars # => "3"
- cents # => "67"
-
-\Method Regexp#named_captures returns a hash of the capture names and substrings;
-method Regexp#names returns an array of the capture names.
-
-==== Atomic Grouping
+=== Named Captures
-A group may be made _atomic_ with <tt>(?></tt>_subexpression_<tt>)</tt>.
+Capture groups can be referred to by name when defined with the
+<tt>(?<</tt><i>name</i><tt>>)</tt> or <tt>(?'</tt><i>name</i><tt>')</tt>
+constructs.
-This causes the subexpression to be matched
-independently of the rest of the expression,
-so that the matched substring becomes fixed for the remainder of the match,
-unless the entire subexpression must be abandoned and subsequently revisited.
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")
+ #=> #<MatchData "$3.67" dollars:"3" cents:"67">
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")[:dollars] #=> "3"
-In this way _subexpression_ is treated as a non-divisible whole.
-Atomic grouping is typically used to optimise patterns
-to prevent needless backtracking .
+Named groups can be backreferenced with <tt>\k<</tt><i>name</i><tt>></tt>,
+where _name_ is the group name.
-Example (without atomic grouping):
+ /(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
+ #=> #<MatchData "ototo" vowel:"o">
- /".*"/.match('"Quote"') # => #<MatchData "\"Quote\"">
+*Note*: A regexp can't use named backreferences and numbered
+backreferences simultaneously. Also, if a named capture is used in a
+regexp, then parentheses used for grouping which would otherwise result
+in a unnamed capture are treated as non-capturing.
-Analysis:
+ /(\w)(\w)/.match("ab").captures # => ["a", "b"]
+ /(\w)(\w)/.match("ab").named_captures # => {}
-1. The leading subexpression <tt>"</tt> in the pattern matches the first character
- <tt>"</tt> in the target string.
-2. The next subexpression <tt>.*</tt> matches the next substring <tt>Quote“</tt>
- (including the trailing double-quote).
-3. Now there is nothing left in the target string to match
- the trailing subexpression <tt>"</tt> in the pattern;
- this would cause the overall match to fail.
-4. The matched substring is backtracked by one position: <tt>Quote</tt>.
-5. The final subexpression <tt>"</tt> now matches the final substring <tt>"</tt>,
- and the overall match succeeds.
+ /(?<c>\w)(\w)/.match("ab").captures # => ["a"]
+ /(?<c>\w)(\w)/.match("ab").named_captures # => {"c"=>"a"}
-If subexpression <tt>.*</tt> is grouped atomically,
-the backtracking is disabled, and the overall match fails:
+When named capture groups are used with a literal regexp on the left-hand
+side of an expression and the <tt>=~</tt> operator, the captured text is
+also assigned to local variables with corresponding names.
- /"(?>.*)"/.match('"Quote"') # => nil
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
+ dollars #=> "3"
-Atomic grouping can affect performance;
-see {Atomic Group}[https://www.regular-expressions.info/atomic.html].
+== Grouping
-==== Subexpression Calls
+Parentheses also <i>group</i> the terms they enclose, allowing them to be
+quantified as one <i>atomic</i> whole.
-As seen above, a backreference number (<tt>\\_n_</tt>) or name (<tt>\k<_name_></tt>)
-gives access to a captured _substring_;
-the corresponding regexp _subexpression_ may also be accessed,
-via the number (<tt>\\g<i>n</i></tt>) or name (<tt>\g<_name_></tt>):
+The pattern below matches a vowel followed by 2 word characters:
- /\A(?<paren>\(\g<paren>*\))*\z/.match('(())')
- # ^1
- # ^2
- # ^3
- # ^4
- # ^5
- # ^6
- # ^7
- # ^8
- # ^9
- # ^10
+ /[aeiou]\w{2}/.match("Caenorhabditis elegans") #=> #<MatchData "aen">
-The pattern:
+Whereas the following pattern matches a vowel followed by a word character,
+twice, i.e. <tt>[aeiou]\w[aeiou]\w</tt>: 'enor'.
-1. Matches at the beginning of the string, i.e. before the first character.
-2. Enters a named group +paren+.
-3. Matches the first character in the string, <tt>'('</tt>.
-4. Calls the +paren+ group again, i.e. recurses back to the second step.
-5. Re-enters the +paren+ group.
-6. Matches the second character in the string, <tt>'('</tt>.
-7. Attempts to call +paren+ a third time,
- but fails because doing so would prevent an overall successful match.
-8. Matches the third character in the string, <tt>')'</tt>;
- marks the end of the second recursive call
-9. Matches the fourth character in the string, <tt>')'</tt>.
-10. Matches the end of the string.
+ /([aeiou]\w){2}/.match("Caenorhabditis elegans")
+ #=> #<MatchData "enor" 1:"or">
-See {Subexpression calls}[https://learnbyexample.github.io/Ruby_Regexp/groupings-and-backreferences.html?highlight=subexpression#subexpression-calls].
+The <tt>(?:</tt>...<tt>)</tt> construct provides grouping without
+capturing. That is, it combines the terms it contains into an atomic whole
+without creating a backreference. This benefits performance at the slight
+expense of readability.
-==== Conditionals
+The first group of parentheses captures 'n' and the second 'ti'. The second
+group is referred to later with the backreference <tt>\2</tt>:
-The conditional construct takes the form <tt>(?(_cond_)_yes_|_no_)</tt>, where:
+ /I(n)ves(ti)ga\2ons/.match("Investigations")
+ #=> #<MatchData "Investigations" 1:"n" 2:"ti">
-- _cond_ may be a capture number or name.
-- The match to be applied is _yes_ if _cond_ is captured;
- otherwise the match to be applied is _no_.
-- If not needed, <tt>|_no_</tt> may be omitted.
+The first group of parentheses is now made non-capturing with '?:', so it
+still matches 'n', but doesn't create the backreference. Thus, the
+backreference <tt>\1</tt> now refers to 'ti'.
-Examples:
+ /I(?:n)ves(ti)ga\1ons/.match("Investigations")
+ #=> #<MatchData "Investigations" 1:"ti">
- re = /\A(foo)?(?(1)(T)|(F))\z/
- re.match('fooT') # => #<MatchData "fooT" 1:"foo" 2:"T" 3:nil>
- re.match('F') # => #<MatchData "F" 1:nil 2:nil 3:"F">
- re.match('fooF') # => nil
- re.match('T') # => nil
+=== Atomic Grouping
- re = /\A(?<xyzzy>foo)?(?(<xyzzy>)(T)|(F))\z/
- re.match('fooT') # => #<MatchData "fooT" xyzzy:"foo">
- re.match('F') # => #<MatchData "F" xyzzy:nil>
- re.match('fooF') # => nil
- re.match('T') # => nil
+Grouping can be made <i>atomic</i> with
+<tt>(?></tt><i>pat</i><tt>)</tt>. This causes the subexpression <i>pat</i>
+to be matched independently of the rest of the expression such that what
+it matches becomes fixed for the remainder of the match, unless the entire
+subexpression must be abandoned and subsequently revisited. In this
+way <i>pat</i> is treated as a non-divisible whole. Atomic grouping is
+typically used to optimise patterns so as to prevent the regular
+expression engine from backtracking needlessly.
+The <tt>"</tt> in the pattern below matches the first character of the string,
+then <tt>.*</tt> matches <i>Quote"</i>. This causes the overall match to fail,
+so the text matched by <tt>.*</tt> is backtracked by one position, which
+leaves the final character of the string available to match <tt>"</tt>
-==== Absence Operator
+ /".*"/.match('"Quote"') #=> #<MatchData "\"Quote\"">
-The absence operator is a special group that matches anything which does _not_ match the contained subexpressions.
+If <tt>.*</tt> is grouped atomically, it refuses to backtrack <i>Quote"</i>,
+even though this means that the overall match fails
- /(?~real)/.match('surrealist') # => #<MatchData "surrea">
- /(?~real)ist/.match('surrealist') # => #<MatchData "ealist">
- /sur(?~real)ist/.match('surrealist') # => nil
+ /"(?>.*)"/.match('"Quote"') #=> nil
-=== Unicode
+== Subexpression Calls
-==== Unicode Properties
+The <tt>\g<</tt><i>name</i><tt>></tt> syntax matches the previous
+subexpression named _name_, which can be a group name or number, again.
+This differs from backreferences in that it re-executes the group rather
+than simply trying to re-match the same text.
-The <tt>/\p{_property_name_}/</tt> construct (with lowercase +p+)
-matches characters using a Unicode property name,
-much like a character class;
-property +Alpha+ specifies alphabetic characters:
+This pattern matches a <i>(</i> character and assigns it to the <tt>paren</tt>
+group, tries to call that the <tt>paren</tt> sub-expression again but fails,
+then matches a literal <i>)</i>:
- /\p{Alpha}/.match('a') # => #<MatchData "a">
- /\p{Alpha}/.match('1') # => nil
+ /\A(?<paren>\(\g<paren>*\))*\z/ =~ '()'
-A property can be inverted
-by prefixing the name with a caret character (<tt>^</tt>):
- /\p{^Alpha}/.match('1') # => #<MatchData "1">
- /\p{^Alpha}/.match('a') # => nil
+ /\A(?<paren>\(\g<paren>*\))*\z/ =~ '(())' #=> 0
+ # ^1
+ # ^2
+ # ^3
+ # ^4
+ # ^5
+ # ^6
+ # ^7
+ # ^8
+ # ^9
+ # ^10
-Or by using <tt>\P</tt> (uppercase +P+):
+1. Matches at the beginning of the string, i.e. before the first
+ character.
+2. Enters a named capture group called <tt>paren</tt>
+3. Matches a literal <i>(</i>, the first character in the string
+4. Calls the <tt>paren</tt> group again, i.e. recurses back to the
+ second step
+5. Re-enters the <tt>paren</tt> group
+6. Matches a literal <i>(</i>, the second character in the
+ string
+7. Try to call <tt>paren</tt> a third time, but fail because
+ doing so would prevent an overall successful match
+8. Match a literal <i>)</i>, the third character in the string.
+ Marks the end of the second recursive call
+9. Match a literal <i>)</i>, the fourth character in the string
+10. Match the end of the string
- /\P{Alpha}/.match('1') # => #<MatchData "1">
- /\P{Alpha}/.match('a') # => nil
+== Alternation
-See {Unicode Properties}[./Regexp/unicode_properties_rdoc.html]
-for regexps based on the numerous properties.
-
-Some commonly-used properties correspond to POSIX bracket expressions:
-
-- <tt>/\p{Alnum}/</tt>: Alphabetic and numeric character
-- <tt>/\p{Alpha}/</tt>: Alphabetic character
-- <tt>/\p{Blank}/</tt>: Space or tab
-- <tt>/\p{Cntrl}/</tt>: Control character
-- <tt>/\p{Digit}/</tt>: Digit
+The vertical bar metacharacter (<tt>|</tt>) combines several expressions into
+a single one that matches any of the expressions. Each expression is an
+<i>alternative</i>.
+
+ /\w(and|or)\w/.match("Feliformia") #=> #<MatchData "form" 1:"or">
+ /\w(and|or)\w/.match("furandi") #=> #<MatchData "randi" 1:"and">
+ /\w(and|or)\w/.match("dissemblance") #=> nil
+
+== Character Properties
+
+The <tt>\p{}</tt> construct matches characters with the named property,
+much like POSIX bracket classes.
+
+* <tt>/\p{Alnum}/</tt> - Alphabetic and numeric character
+* <tt>/\p{Alpha}/</tt> - Alphabetic character
+* <tt>/\p{Blank}/</tt> - Space or tab
+* <tt>/\p{Cntrl}/</tt> - Control character
+* <tt>/\p{Digit}/</tt> - Digit
+* <tt>/\p{Emoji}/</tt> - Unicode emoji
+* <tt>/\p{Graph}/</tt> - Non-blank character (excludes spaces, control
characters, and similar)
-- <tt>/\p{Lower}/</tt>: Lowercase alphabetical character
-- <tt>/\p{Print}/</tt>: Like <tt>\p{Graph}</tt>, but includes the space character
-- <tt>/\p{Punct}/</tt>: Punctuation character
-- <tt>/\p{Space}/</tt>: Whitespace character (<tt>[:blank:]</tt>, newline,
+* <tt>/\p{Lower}/</tt> - Lowercase alphabetical character
+* <tt>/\p{Print}/</tt> - Like <tt>\p{Graph}</tt>, but includes the space character
+* <tt>/\p{Punct}/</tt> - Punctuation character
+* <tt>/\p{Space}/</tt> - Whitespace character (<tt>[:blank:]</tt>, newline,
carriage return, etc.)
-- <tt>/\p{Upper}/</tt>: Uppercase alphabetical
-- <tt>/\p{XDigit}/</tt>: Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
-
-These are also commonly used:
-
-- <tt>/\p{Emoji}/</tt>: Unicode emoji.
-- <tt>/\p{Graph}/</tt>: Non-blank character
- (excludes spaces, control characters, and similar).
-- <tt>/\p{Word}/</tt>: A member of one of the following Unicode character
- categories (see below):
-
- - +Mark+ (+M+).
- - +Letter+ (+L+).
- - +Number+ (+N+)
- - <tt>Connector Punctuation</tt> (+Pc+).
-
-- <tt>/\p{ASCII}/</tt>: A character in the ASCII character set.
-- <tt>/\p{Any}/</tt>: Any Unicode character (including unassigned characters).
-- <tt>/\p{Assigned}/</tt>: An assigned character.
-
-==== Unicode Character Categories
-
-A Unicode character category name:
-
-- May be either its full name or its abbreviated name.
-- Is case-insensitive.
-- Treats a space, a hyphen, and an underscore as equivalent.
-
-Examples:
-
- /\p{lu}/ # => /\p{lu}/
- /\p{LU}/ # => /\p{LU}/
- /\p{Uppercase Letter}/ # => /\p{Uppercase Letter}/
- /\p{Uppercase_Letter}/ # => /\p{Uppercase_Letter}/
- /\p{UPPERCASE-LETTER}/ # => /\p{UPPERCASE-LETTER}/
-
-Below are the Unicode character category abbreviations and names.
-Enumerations of characters in each category are at the links.
-
-Letters:
-
-- +L+, +Letter+: +LC+, +Lm+, or +Lo+.
-- +LC+, +Cased_Letter+: +Ll+, +Lt+, or +Lu+.
-- {Lu, Lowercase_Letter}[https://www.compart.com/en/unicode/category/Ll].
-- {Lu, Modifier_Letter}[https://www.compart.com/en/unicode/category/Lm].
-- {Lu, Other_Letter}[https://www.compart.com/en/unicode/category/Lo].
-- {Lu, Titlecase_Letter}[https://www.compart.com/en/unicode/category/Lt].
-- {Lu, Uppercase_Letter}[https://www.compart.com/en/unicode/category/Lu].
-
-Marks:
-
-- +M+, +Mark+: +Mc+, +Me+, or +Mn+.
-- {Mc, Spacing_Mark}[https://www.compart.com/en/unicode/category/Mc].
-- {Me, Enclosing_Mark}[https://www.compart.com/en/unicode/category/Me].
-- {Mn, Nonapacing_Mark}[https://www.compart.com/en/unicode/category/Mn].
-
-Numbers:
-
-- +N+, +Number+: +Nd+, +Nl+, or +No+.
-- {Nd, Decimal_Number}[https://www.compart.com/en/unicode/category/Nd].
-- {Nl, Letter_Number}[https://www.compart.com/en/unicode/category/Nl].
-- {No, Other_Number}[https://www.compart.com/en/unicode/category/No].
-
-Punctation:
-
-- +P+, +Punctuation+: +Pc+, +Pd+, +Pe+, +Pf+, +Pi+, +Po+, or +Ps+.
-- {Pc, Connector_Punctuation}[https://www.compart.com/en/unicode/category/Pc].
-- {Pd, Dash_Punctuation}[https://www.compart.com/en/unicode/category/Pd].
-- {Pe, Close_Punctuation}[https://www.compart.com/en/unicode/category/Pe].
-- {Pf, Final_Punctuation}[https://www.compart.com/en/unicode/category/Pf].
-- {Pi, Initial_Punctuation}[https://www.compart.com/en/unicode/category/Pi].
-- {Po, Other_Punctuation}[https://www.compart.com/en/unicode/category/Po].
-- {Ps, Open_Punctuation}[https://www.compart.com/en/unicode/category/Ps].
-
-- +S+, +Symbol+: +Sc+, +Sk+, +Sm+, or +So+.
-- {Sc, Currency_Symbol}[https://www.compart.com/en/unicode/category/Sc].
-- {Sk, Modifier_Symbol}[https://www.compart.com/en/unicode/category/Sk].
-- {Sm, Math_Symbol}[https://www.compart.com/en/unicode/category/Sm].
-- {So, Other_Symbol}[https://www.compart.com/en/unicode/category/So].
-
-- +Z+, +Separator+: +Zl+, +Zp+, or +Zs+.
-- {Zl, Line_Separator}[https://www.compart.com/en/unicode/category/Zl].
-- {Zp, Paragraph_Separator}[https://www.compart.com/en/unicode/category/Zp].
-- {Zs, Space_Separator}[https://www.compart.com/en/unicode/category/Zs].
-
-- +C+, +Other+: +Cc+, +Cf+, +Cn+, +Co+, or +Cs+.
-- {Cc, Control}[https://www.compart.com/en/unicode/category/Cc].
-- {Cf, Format}[https://www.compart.com/en/unicode/category/Cf].
-- {Cn, Unassigned}[https://www.compart.com/en/unicode/category/Cn].
-- {Co, Private_Use}[https://www.compart.com/en/unicode/category/Co].
-- {Cs, Surrogate}[https://www.compart.com/en/unicode/category/Cs].
-
-==== Unicode Scripts and Blocks
-
-Among the Unicode properties are:
-
-- {Unicode scripts}[https://en.wikipedia.org/wiki/Script_(Unicode)];
- see {supported scripts}[https://www.unicode.org/standard/supported.html].
-- {Unicode blocks}[https://en.wikipedia.org/wiki/Unicode_block];
- see {supported blocks}[http://www.unicode.org/Public/UNIDATA/Blocks.txt].
-
-=== POSIX Bracket Expressions
-
-A POSIX <i>bracket expression</i> is also similar to a character class.
-These expressions provide a portable alternative to the above,
-with the added benefit of encompassing non-ASCII characters:
-
-- <tt>/\d/</tt> matches only ASCII decimal digits +0+ through +9+.
-- <tt>/[[:digit:]]/</tt> matches any character in the Unicode
- <tt>Decimal Number</tt> (+Nd+) category;
- see below.
-
-The POSIX bracket expressions:
-
-- <tt>/[[:digit:]]/</tt>: Matches a {Unicode digit}[https://www.compart.com/en/unicode/category/Nd]:
-
- /[[:digit:]]/.match('9') # => #<MatchData "9">
- /[[:digit:]]/.match("\u1fbf9") # => #<MatchData "9">
-
-- <tt>/[[:xdigit:]]/</tt>: Matches a digit allowed in a hexadecimal number;
- equivalent to <tt>[0-9a-fA-F]</tt>.
-
-- <tt>/[[:upper:]]/</tt>: Matches a {Unicode uppercase letter}[https://www.compart.com/en/unicode/category/Lu]:
-
- /[[:upper:]]/.match('A') # => #<MatchData "A">
- /[[:upper:]]/.match("\u00c6") # => #<MatchData "Æ">
-
-- <tt>/[[:lower:]]/</tt>: Matches a {Unicode lowercase letter}[https://www.compart.com/en/unicode/category/Ll]:
-
- /[[:lower:]]/.match('a') # => #<MatchData "a">
- /[[:lower:]]/.match("\u01fd") # => #<MatchData "ǽ">
-
-- <tt>/[[:alpha:]]/</tt>: Matches <tt>/[[:upper:]]/</tt> or <tt>/[[:lower:]]/</tt>.
-
-- <tt>/[[:alnum:]]/</tt>: Matches <tt>/[[:alpha:]]/</tt> or <tt>/[[:digit:]]/</tt>.
-
-- <tt>/[[:space:]]/</tt>: Matches {Unicode space character}[https://www.compart.com/en/unicode/category/Zs]:
-
- /[[:space:]]/.match(' ') # => #<MatchData " ">
- /[[:space:]]/.match("\u2005") # => #<MatchData " ">
-
-- <tt>/[[:blank:]]/</tt>: Matches <tt>/[[:space:]]/</tt> or tab character:
-
- /[[:blank:]]/.match(' ') # => #<MatchData " ">
- /[[:blank:]]/.match("\u2005") # => #<MatchData " ">
- /[[:blank:]]/.match("\t") # => #<MatchData "\t">
-
-- <tt>/[[:cntrl:]]/</tt>: Matches {Unicode control character}[https://www.compart.com/en/unicode/category/Cc]:
-
- /[[:cntrl:]]/.match("\u0000") # => #<MatchData "\u0000">
- /[[:cntrl:]]/.match("\u009f") # => #<MatchData "\u009F">
-
-- <tt>/[[:graph:]]/</tt>: Matches any character
- except <tt>/[[:space:]]/</tt> or <tt>/[[:cntrl:]]/</tt>.
-
-- <tt>/[[:print:]]/</tt>: Matches <tt>/[[:graph:]]/</tt> or space character.
-
-- <tt>/[[:punct:]]/</tt>: Matches any (Unicode punctuation character}[https://www.compart.com/en/unicode/category/Po]:
-
-Ruby also supports these (non-POSIX) bracket expressions:
-
-- <tt>/[[:ascii:]]/</tt>: Matches a character in the ASCII character set.
-- <tt>/[[:word:]]/</tt>: Matches a character in one of these Unicode character
- categories (see below):
-
- - +Mark+ (+M+).
- - +Letter+ (+L+).
- - +Number+ (+N+)
- - <tt>Connector Punctuation</tt> (+Pc+).
-
-=== Comments
-
-A comment may be included in a regexp pattern
-using the <tt>(?#</tt>_comment_<tt>)</tt> construct,
-where _comment_ is a substring that is to be ignored.
-arbitrary text ignored by the regexp engine:
-
- /foo(?#Ignore me)bar/.match('foobar') # => #<MatchData "foobar">
-
-The comment may not include an unescaped terminator character.
-
-See also {Extended Mode}[rdoc-ref:regexp.rdoc@Extended+Mode].
-
-== Modes
-
-Each of these modifiers sets a mode for the regexp:
-
-- +i+: <tt>/_pattern_/i</tt> sets
- {Case-Insensitive Mode}[rdoc-ref:regexp.rdoc@Case-Insensitive+Mode].
-- +m+: <tt>/_pattern_/m</tt> sets
- {Multiline Mode}[rdoc-ref:regexp.rdoc@Multiline+Mode].
-- +x+: <tt>/_pattern_/x</tt> sets
- {Extended Mode}[rdoc-ref:regexp.rdoc@Extended+Mode].
-- +o+: <tt>/_pattern_/o</tt> sets
- {Interpolation Mode}[rdoc-ref:regexp.rdoc@Interpolation+Mode].
-
-Any, all, or none of these may be applied.
-
-Modifiers +i+, +m+, and +x+ may be applied to subexpressions:
+* <tt>/\p{Upper}/</tt> - Uppercase alphabetical
+* <tt>/\p{XDigit}/</tt> - Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
+* <tt>/\p{Word}/</tt> - A member of one of the following Unicode general
+ category <i>Letter</i>, <i>Mark</i>, <i>Number</i>,
+ <i>Connector\_Punctuation</i>
+* <tt>/\p{ASCII}/</tt> - A character in the ASCII character set
+* <tt>/\p{Any}/</tt> - Any Unicode character (including unassigned
+ characters)
+* <tt>/\p{Assigned}/</tt> - An assigned character
+
+A Unicode character's <i>General Category</i> value can also be matched
+with <tt>\p{</tt><i>Ab</i><tt>}</tt> where <i>Ab</i> is the category's
+abbreviation as described below:
+
+* <tt>/\p{L}/</tt> - 'Letter'
+* <tt>/\p{Ll}/</tt> - 'Letter: Lowercase'
+* <tt>/\p{Lm}/</tt> - 'Letter: Mark'
+* <tt>/\p{Lo}/</tt> - 'Letter: Other'
+* <tt>/\p{Lt}/</tt> - 'Letter: Titlecase'
+* <tt>/\p{Lu}/</tt> - 'Letter: Uppercase
+* <tt>/\p{Lo}/</tt> - 'Letter: Other'
+* <tt>/\p{M}/</tt> - 'Mark'
+* <tt>/\p{Mn}/</tt> - 'Mark: Nonspacing'
+* <tt>/\p{Mc}/</tt> - 'Mark: Spacing Combining'
+* <tt>/\p{Me}/</tt> - 'Mark: Enclosing'
+* <tt>/\p{N}/</tt> - 'Number'
+* <tt>/\p{Nd}/</tt> - 'Number: Decimal Digit'
+* <tt>/\p{Nl}/</tt> - 'Number: Letter'
+* <tt>/\p{No}/</tt> - 'Number: Other'
+* <tt>/\p{P}/</tt> - 'Punctuation'
+* <tt>/\p{Pc}/</tt> - 'Punctuation: Connector'
+* <tt>/\p{Pd}/</tt> - 'Punctuation: Dash'
+* <tt>/\p{Ps}/</tt> - 'Punctuation: Open'
+* <tt>/\p{Pe}/</tt> - 'Punctuation: Close'
+* <tt>/\p{Pi}/</tt> - 'Punctuation: Initial Quote'
+* <tt>/\p{Pf}/</tt> - 'Punctuation: Final Quote'
+* <tt>/\p{Po}/</tt> - 'Punctuation: Other'
+* <tt>/\p{S}/</tt> - 'Symbol'
+* <tt>/\p{Sm}/</tt> - 'Symbol: Math'
+* <tt>/\p{Sc}/</tt> - 'Symbol: Currency'
+* <tt>/\p{Sc}/</tt> - 'Symbol: Currency'
+* <tt>/\p{Sk}/</tt> - 'Symbol: Modifier'
+* <tt>/\p{So}/</tt> - 'Symbol: Other'
+* <tt>/\p{Z}/</tt> - 'Separator'
+* <tt>/\p{Zs}/</tt> - 'Separator: Space'
+* <tt>/\p{Zl}/</tt> - 'Separator: Line'
+* <tt>/\p{Zp}/</tt> - 'Separator: Paragraph'
+* <tt>/\p{C}/</tt> - 'Other'
+* <tt>/\p{Cc}/</tt> - 'Other: Control'
+* <tt>/\p{Cf}/</tt> - 'Other: Format'
+* <tt>/\p{Cn}/</tt> - 'Other: Not Assigned'
+* <tt>/\p{Co}/</tt> - 'Other: Private Use'
+* <tt>/\p{Cs}/</tt> - 'Other: Surrogate'
+
+Lastly, <tt>\p{}</tt> matches a character's Unicode <i>script</i>. The
+following scripts are supported: <i>Arabic</i>, <i>Armenian</i>,
+<i>Balinese</i>, <i>Bengali</i>, <i>Bopomofo</i>, <i>Braille</i>,
+<i>Buginese</i>, <i>Buhid</i>, <i>Canadian_Aboriginal</i>, <i>Carian</i>,
+<i>Cham</i>, <i>Cherokee</i>, <i>Common</i>, <i>Coptic</i>,
+<i>Cuneiform</i>, <i>Cypriot</i>, <i>Cyrillic</i>, <i>Deseret</i>,
+<i>Devanagari</i>, <i>Ethiopic</i>, <i>Georgian</i>, <i>Glagolitic</i>,
+<i>Gothic</i>, <i>Greek</i>, <i>Gujarati</i>, <i>Gurmukhi</i>, <i>Han</i>,
+<i>Hangul</i>, <i>Hanunoo</i>, <i>Hebrew</i>, <i>Hiragana</i>,
+<i>Inherited</i>, <i>Kannada</i>, <i>Katakana</i>, <i>Kayah_Li</i>,
+<i>Kharoshthi</i>, <i>Khmer</i>, <i>Lao</i>, <i>Latin</i>, <i>Lepcha</i>,
+<i>Limbu</i>, <i>Linear_B</i>, <i>Lycian</i>, <i>Lydian</i>,
+<i>Malayalam</i>, <i>Mongolian</i>, <i>Myanmar</i>, <i>New_Tai_Lue</i>,
+<i>Nko</i>, <i>Ogham</i>, <i>Ol_Chiki</i>, <i>Old_Italic</i>,
+<i>Old_Persian</i>, <i>Oriya</i>, <i>Osmanya</i>, <i>Phags_Pa</i>,
+<i>Phoenician</i>, <i>Rejang</i>, <i>Runic</i>, <i>Saurashtra</i>,
+<i>Shavian</i>, <i>Sinhala</i>, <i>Sundanese</i>, <i>Syloti_Nagri</i>,
+<i>Syriac</i>, <i>Tagalog</i>, <i>Tagbanwa</i>, <i>Tai_Le</i>,
+<i>Tamil</i>, <i>Telugu</i>, <i>Thaana</i>, <i>Thai</i>, <i>Tibetan</i>,
+<i>Tifinagh</i>, <i>Ugaritic</i>, <i>Vai</i>, and <i>Yi</i>.
+
+Unicode codepoint U+06E9 is named "ARABIC PLACE OF SAJDAH" and belongs to the
+Arabic script:
+
+ /\p{Arabic}/.match("\u06E9") #=> #<MatchData "\u06E9">
+
+All character properties can be inverted by prefixing their name with a
+caret (<tt>^</tt>).
+
+Letter 'A' is not in the Unicode Ll (Letter; Lowercase) category, so this
+match succeeds:
+
+ /\p{^Ll}/.match("A") #=> #<MatchData "A">
+
+== Anchors
+
+Anchors are metacharacter that match the zero-width positions between
+characters, <i>anchoring</i> the match to a specific position.
+
+* <tt>^</tt> - Matches beginning of line
+* <tt>$</tt> - Matches end of line
+* <tt>\A</tt> - Matches beginning of string.
+* <tt>\Z</tt> - Matches end of string. If string ends with a newline,
+ it matches just before newline
+* <tt>\z</tt> - Matches end of string
+* <tt>\G</tt> - Matches first matching position:
+
+ In methods like <tt>String#gsub</tt> and <tt>String#scan</tt>, it changes on each iteration.
+ It initially matches the beginning of subject, and in each following iteration it matches where the last match finished.
-- <tt>(?_modifier_)</tt> turns the mode "on" for ensuing subexpressions
-- <tt>(?-_modifier_)</tt> turns the mode "off" for ensuing subexpressions
-- <tt>(?_modifier_:_subexp_)</tt> turns the mode "on" for _subexp_ within the group
-- <tt>(?-_modifier_:_subexp_)</tt> turns the mode "off" for _subexp_ within the group
+ " a b c".gsub(/ /, '_') #=> "____a_b_c"
+ " a b c".gsub(/\G /, '_') #=> "____a b c"
-Example:
+ In methods like <tt>Regexp#match</tt> and <tt>String#match</tt> that take an (optional) offset, it matches where the search begins.
- re = /(?i)te(?-i)st/
- re.match('test') # => #<MatchData "test">
- re.match('TEst') # => #<MatchData "TEst">
- re.match('TEST') # => nil
- re.match('teST') # => nil
-
- re = /t(?i:e)st/
- re.match('test') # => #<MatchData "test">
- re.match('tEst') # => #<MatchData "tEst">
- re.match('tEST') # => nil
+ "hello, world".match(/,/, 3) #=> #<MatchData ",">
+ "hello, world".match(/\G,/, 3) #=> nil
-\Method Regexp#options returns an integer whose value showing
-the settings for case-insensitivity mode, multiline mode, and extended mode.
+* <tt>\b</tt> - Matches word boundaries when outside brackets;
+ backspace (0x08) when inside brackets
+* <tt>\B</tt> - Matches non-word boundaries
+* <tt>(?=</tt><i>pat</i><tt>)</tt> - <i>Positive lookahead</i> assertion:
+ ensures that the following characters match <i>pat</i>, but doesn't
+ include those characters in the matched text
+* <tt>(?!</tt><i>pat</i><tt>)</tt> - <i>Negative lookahead</i> assertion:
+ ensures that the following characters do not match <i>pat</i>, but
+ doesn't include those characters in the matched text
+* <tt>(?<=</tt><i>pat</i><tt>)</tt> - <i>Positive lookbehind</i>
+ assertion: ensures that the preceding characters match <i>pat</i>, but
+ doesn't include those characters in the matched text
+* <tt>(?<!</tt><i>pat</i><tt>)</tt> - <i>Negative lookbehind</i>
+ assertion: ensures that the preceding characters do not match
+ <i>pat</i>, but doesn't include those characters in the matched text
-=== Case-Insensitive Mode
+* <tt>\K</tt> - <i>Match reset</i>: the matched content preceding
+ <tt>\K</tt> in the regexp is excluded from the result. For example,
+ the following two regexps are almost equivalent:
-By default, a regexp is case-sensitive:
+ /ab\Kc/ =~ "abc" #=> 0
+ /(?<=ab)c/ =~ "abc" #=> 2
- /foo/.match('FOO') # => nil
+ These match same string and <i>$&</i> equals <tt>"c"</tt>, while the
+ matched position is different.
-Modifier +i+ enables case-insensitive mode:
+ As are the following two regexps:
- /foo/i.match('FOO')
- # => #<MatchData "FOO">
+ /(a)\K(b)\Kc/
+ /(?<=(?<=(a))(b))c/
-\Method Regexp#casefold? returns whether the mode is case-insensitive.
+If a pattern isn't anchored it can begin at any point in the string:
-=== Multiline Mode
+ /real/.match("surrealist") #=> #<MatchData "real">
-The multiline-mode in Ruby is what is commonly called a "dot-all mode":
+Anchoring the pattern to the beginning of the string forces the match to start
+there. 'real' doesn't occur at the beginning of the string, so now the match
+fails:
-- Without the +m+ modifier, the subexpression <tt>.</tt> does not match newlines:
+ /\Areal/.match("surrealist") #=> nil
- /a.c/.match("a\nc") # => nil
+The match below fails because although 'Demand' contains 'and', the pattern
+does not occur at a word boundary.
-- With the modifier, it does match:
+ /\band/.match("Demand")
- /a.c/m.match("a\nc") # => #<MatchData "a\nc">
+Whereas in the following example 'and' has been anchored to a non-word
+boundary so instead of matching the first 'and' it matches from the fourth
+letter of 'demand' instead:
-Unlike other languages, the modifier +m+ does not affect the anchors <tt>^</tt> and <tt>$</tt>.
-These anchors always match at line-boundaries in Ruby.
+ /\Band.+/.match("Supply and demand curve") #=> #<MatchData "and curve">
-=== Extended Mode
+The pattern below uses positive lookahead and positive lookbehind to match
+text appearing in <b></b> tags without including the tags in the match:
-Modifier +x+ enables extended mode, which means that:
+ /(?<=<b>)\w+(?=<\/b>)/.match("Fortune favours the <b>bold</b>")
+ #=> #<MatchData "bold">
-- Literal white space in the pattern is to be ignored.
-- Character <tt>#</tt> marks the remainder of its containing line as a comment,
- which is also to be ignored for matching purposes.
+== Options
-In extended mode, whitespace and comments may be used
-to form a self-documented regexp.
+The end delimiter for a regexp can be followed by one or more single-letter
+options which control how the pattern can match.
-Regexp not in extended mode (matches some Roman numerals):
+* <tt>/pat/i</tt> - Ignore case
+* <tt>/pat/m</tt> - Treat a newline as a character matched by <tt>.</tt>
+* <tt>/pat/x</tt> - Ignore whitespace and comments in the pattern
+* <tt>/pat/o</tt> - Perform <tt>#{}</tt> interpolation only once
- pattern = '^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
- re = /#{pattern}/
- re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
+<tt>i</tt>, <tt>m</tt>, and <tt>x</tt> can also be applied on the
+subexpression level with the
+<tt>(?</tt><i>on</i><tt>-</tt><i>off</i><tt>)</tt> construct, which
+enables options <i>on</i>, and disables options <i>off</i> for the
+expression enclosed by the parentheses:
-Regexp in extended mode:
+ /a(?i:b)c/.match('aBc') #=> #<MatchData "aBc">
+ /a(?-i:b)c/i.match('ABC') #=> nil
- pattern = <<-EOT
- ^ # beginning of string
- M{0,3} # thousands - 0 to 3 Ms
- (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
- # or 500-800 (D, followed by 0 to 3 Cs)
- (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
- # or 50-80 (L, followed by 0 to 3 Xs)
- (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
- # or 5-8 (V, followed by 0 to 3 Is)
- $ # end of string
- EOT
- re = /#{pattern}/x
- re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
+Additionally, these options can also be toggled for the remainder of the
+pattern:
-=== Interpolation Mode
+ /a(?i)bc/.match('abC') #=> #<MatchData "abC">
-Modifier +o+ means that the first time a literal regexp with interpolations
-is encountered,
-the generated Regexp object is saved and used for all future evaluations
-of that literal regexp.
-Without modifier +o+, the generated Regexp is not saved,
-so each evaluation of the literal regexp generates a new Regexp object.
+Options may also be used with <tt>Regexp.new</tt>:
-Without modifier +o+:
+ Regexp.new("abc", Regexp::IGNORECASE) #=> /abc/i
+ Regexp.new("abc", Regexp::MULTILINE) #=> /abc/m
+ Regexp.new("abc # Comment", Regexp::EXTENDED) #=> /abc # Comment/x
+ Regexp.new("abc", Regexp::IGNORECASE | Regexp::MULTILINE) #=> /abc/mi
- def letters; sleep 5; /[A-Z][a-z]/; end
- words = %w[abc def xyz]
- start = Time.now
- words.each {|word| word.match(/\A[#{letters}]+\z/) }
- Time.now - start # => 15.0174892
+ Regexp.new("abc", "i") #=> /abc/i
+ Regexp.new("abc", "m") #=> /abc/m
+ Regexp.new("abc # Comment", "x") #=> /abc # Comment/x
+ Regexp.new("abc", "im") #=> /abc/mi
-With modifier +o+:
+== Free-Spacing Mode and Comments
- start = Time.now
- words.each {|word| word.match(/\A[#{letters}]+\z/o) }
- Time.now - start # => 5.0010866
+As mentioned above, the <tt>x</tt> option enables <i>free-spacing</i>
+mode. Literal white space inside the pattern is ignored, and the
+octothorpe (<tt>#</tt>) character introduces a comment until the end of
+the line. This allows the components of the pattern to be organized in a
+potentially more readable fashion.
-Note that if the literal regexp does not have interpolations,
-the +o+ behavior is the default.
+A contrived pattern to match a number with optional decimal places:
-== Encodings
+ float_pat = /\A
+ [[:digit:]]+ # 1 or more digits before the decimal point
+ (\. # Decimal point
+ [[:digit:]]+ # 1 or more digits after the decimal point
+ )? # The decimal point and following digits are optional
+ \Z/x
+ float_pat.match('3.14') #=> #<MatchData "3.14" 1:".14">
-By default, a regexp with only US-ASCII characters has US-ASCII encoding:
+There are a number of strategies for matching whitespace:
- re = /foo/
- re.source.encoding # => #<Encoding:US-ASCII>
- re.encoding # => #<Encoding:US-ASCII>
+* Use a pattern such as <tt>\s</tt> or <tt>\p{Space}</tt>.
+* Use escaped whitespace such as <tt>\ </tt>, i.e. a space preceded by a backslash.
+* Use a character class such as <tt>[ ]</tt>.
-A regular expression containing non-US-ASCII characters
-is assumed to use the source encoding.
-This can be overridden with one of the following modifiers.
+Comments can be included in a non-<tt>x</tt> pattern with the
+<tt>(?#</tt><i>comment</i><tt>)</tt> construct, where <i>comment</i> is
+arbitrary text ignored by the regexp engine.
-- <tt>/_pat_/n</tt>: US-ASCII if only containing US-ASCII characters,
- otherwise ASCII-8BIT:
+Comments in regexp literals cannot include unescaped terminator
+characters.
- /foo/n.encoding # => #<Encoding:US-ASCII>
- /foo\xff/n.encoding # => #<Encoding:ASCII-8BIT>
- /foo\x7f/n.encoding # => #<Encoding:US-ASCII>
+== Encoding
-- <tt>/_pat_/u</tt>: UTF-8
+Regular expressions are assumed to use the source encoding. This can be
+overridden with one of the following modifiers.
- /foo/u.encoding # => #<Encoding:UTF-8>
+* <tt>/</tt><i>pat</i><tt>/u</tt> - UTF-8
+* <tt>/</tt><i>pat</i><tt>/e</tt> - EUC-JP
+* <tt>/</tt><i>pat</i><tt>/s</tt> - Windows-31J
+* <tt>/</tt><i>pat</i><tt>/n</tt> - ASCII-8BIT
-- <tt>/_pat_/e</tt>: EUC-JP
+A regexp can be matched against a string when they either share an
+encoding, or the regexp's encoding is _US-ASCII_ and the string's encoding
+is ASCII-compatible.
- /foo/e.encoding # => #<Encoding:EUC-JP>
+If a match between incompatible encodings is attempted an
+<tt>Encoding::CompatibilityError</tt> exception is raised.
-- <tt>/_pat_/s</tt>: Windows-31J
+The <tt>Regexp#fixed_encoding?</tt> predicate indicates whether the regexp
+has a <i>fixed</i> encoding, that is one incompatible with ASCII. A
+regexp's encoding can be explicitly fixed by supplying
+<tt>Regexp::FIXEDENCODING</tt> as the second argument of
+<tt>Regexp.new</tt>:
- /foo/s.encoding # => #<Encoding:Windows-31J>
+ r = Regexp.new("a".force_encoding("iso-8859-1"),Regexp::FIXEDENCODING)
+ r =~ "a\u3042"
+ # raises Encoding::CompatibilityError: incompatible encoding regexp match
+ # (ISO-8859-1 regexp with UTF-8 string)
-A regexp can be matched against a target string when either:
+== \Regexp Global Variables
-- They have the same encoding.
-- The regexp's encoding is a fixed encoding and the string
- contains only ASCII characters.
- Method Regexp#fixed_encoding? returns whether the regexp
- has a <i>fixed</i> encoding.
+Pattern matching sets some global variables :
-If a match between incompatible encodings is attempted an
-<tt>Encoding::CompatibilityError</tt> exception is raised.
+* <tt>$~</tt> is equivalent to Regexp.last_match;
+* <tt>$&</tt> contains the complete matched text;
+* <tt>$`</tt> contains string before match;
+* <tt>$'</tt> contains string after match;
+* <tt>$1</tt>, <tt>$2</tt> and so on contain text matching first, second, etc
+ capture group;
+* <tt>$+</tt> contains last capture group.
Example:
- re = eval("# encoding: ISO-8859-1\n/foo\\xff?/")
- re.encoding # => #<Encoding:ISO-8859-1>
- re =~ "foo".encode("UTF-8") # => 0
- re =~ "foo\u0100" # Raises Encoding::CompatibilityError
+ m = /s(\w{2}).*(c)/.match('haystack') #=> #<MatchData "stac" 1:"ta" 2:"c">
+ $~ #=> #<MatchData "stac" 1:"ta" 2:"c">
+ Regexp.last_match #=> #<MatchData "stac" 1:"ta" 2:"c">
-The encoding may be explicitly fixed by including Regexp::FIXEDENCODING
-in the second argument for Regexp.new:
+ $& #=> "stac"
+ # same as m[0]
+ $` #=> "hay"
+ # same as m.pre_match
+ $' #=> "k"
+ # same as m.post_match
+ $1 #=> "ta"
+ # same as m[1]
+ $2 #=> "c"
+ # same as m[2]
+ $3 #=> nil
+ # no third group in pattern
+ $+ #=> "c"
+ # same as m[-1]
- # Regexp with encoding ISO-8859-1.
- re = Regexp.new("a".force_encoding('iso-8859-1'), Regexp::FIXEDENCODING)
- re.encoding # => #<Encoding:ISO-8859-1>
- # Target string with encoding UTF-8.
- s = "a\u3042"
- s.encoding # => #<Encoding:UTF-8>
- re.match(s) # Raises Encoding::CompatibilityError.
+These global variables are thread-local and method-local variables.
-== Timeouts
+== Performance
-When either a regexp source or a target string comes from untrusted input,
-malicious values could become a denial-of-service attack;
-to prevent such an attack, it is wise to set a timeout.
+Certain pathological combinations of constructs can lead to abysmally bad
+performance.
-\Regexp has two timeout values:
+Consider a string of 25 <i>a</i>s, a <i>d</i>, 4 <i>a</i>s, and a
+<i>c</i>.
-- A class default timeout, used for a regexp whose instance timeout is +nil+;
- this default is initially +nil+, and may be set by method Regexp.timeout=:
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ #=> "aaaaaaaaaaaaaaaaaaaaaaaaadaaaac"
- Regexp.timeout # => nil
- Regexp.timeout = 3.0
- Regexp.timeout # => 3.0
+The following patterns match instantly as you would expect:
-- An instance timeout, which defaults to +nil+ and may be set in Regexp.new:
+ /(b|a)/ =~ s #=> 0
+ /(b|a+)/ =~ s #=> 0
+ /(b|a+)*/ =~ s #=> 0
- re = Regexp.new('foo', timeout: 5.0)
- re.timeout # => 5.0
+However, the following pattern takes appreciably longer:
-When regexp.timeout is +nil+, the timeout "falls through" to Regexp.timeout;
-when regexp.timeout is non-+nil+, that value controls timing out:
+ /(b|a+)*c/ =~ s #=> 26
- | regexp.timeout Value | Regexp.timeout Value | Result |
- |----------------------|----------------------|-----------------------------|
- | nil | nil | Never times out. |
- | nil | Float | Times out in Float seconds. |
- | Float | Any | Times out in Float seconds. |
+This happens because an atom in the regexp is quantified by both an
+immediate <tt>+</tt> and an enclosing <tt>*</tt> with nothing to
+differentiate which is in control of any particular character. The
+nondeterminism that results produces super-linear performance. (Consult
+<i>Mastering Regular Expressions</i> (3rd ed.), pp 222, by
+<i>Jeffery Friedl</i>, for an in-depth analysis). This particular case
+can be fixed by use of atomic grouping, which prevents the unnecessary
+backtracking:
-== Optimization
+ (start = Time.now) && /(b|a+)*c/ =~ s && (Time.now - start)
+ #=> 24.702736882
+ (start = Time.now) && /(?>b|a+)*c/ =~ s && (Time.now - start)
+ #=> 0.000166571
-For certain values of the pattern and target string,
-matching time can grow polynomially or exponentially in relation to the input size;
-the potential vulnerability arising from this is the {regular expression denial-of-service}[https://en.wikipedia.org/wiki/ReDoS] (ReDoS) attack.
+A similar case is typified by the following example, which takes
+approximately 60 seconds to execute for me:
-\Regexp matching can apply an optimization to prevent ReDoS attacks.
-When the optimization is applied, matching time increases linearly (not polynomially or exponentially)
-in relation to the input size, and a ReDoS attach is not possible.
+Match a string of 29 <i>a</i>s against a pattern of 29 optional <i>a</i>s
+followed by 29 mandatory <i>a</i>s:
-This optimization is applied if the pattern meets these criteria:
+ Regexp.new('a?' * 29 + 'a' * 29) =~ 'a' * 29
-- No backreferences.
-- No subexpression calls.
-- No nested lookaround anchors or atomic groups.
-- No nested quantifiers with counting (i.e. no nested <tt>{n}</tt>,
- <tt>{min,}</tt>, <tt>{,max}</tt>, or <tt>{min,max}</tt> style quantifiers)
+The 29 optional <i>a</i>s match the string, but this prevents the 29
+mandatory <i>a</i>s that follow from matching. Ruby must then backtrack
+repeatedly so as to satisfy as many of the optional matches as it can
+while still matching the mandatory 29. It is plain to us that none of the
+optional matches can succeed, but this fact unfortunately eludes Ruby.
-You can use method Regexp.linear_time? to determine whether a pattern meets these criteria:
+The best way to improve performance is to significantly reduce the amount of
+backtracking needed. For this case, instead of individually matching 29
+optional <i>a</i>s, a range of optional <i>a</i>s can be matched all at once
+with <i>a{0,29}</i>:
- Regexp.linear_time?(/a*/) # => true
- Regexp.linear_time?('a*') # => true
- Regexp.linear_time?(/(a*)\1/) # => false
+ Regexp.new('a{0,29}' + 'a' * 29) =~ 'a' * 29
-However, an untrusted source may not be safe even if the method returns +true+,
-because the optimization uses memoization (which may invoke large memory consumption).
+== Timeout
-== References
+There are two APIs to set timeout. One is Regexp.timeout=, which is
+process-global configuration of timeout for Regexp matching.
-Read (online PDF books):
+ Regexp.timeout = 3
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ /(b|a+)*c/ =~ s #=> This raises an exception in three seconds
-- {Mastering Regular Expressions}[https://ia902508.us.archive.org/10/items/allitebooks-02/Mastering%20Regular%20Expressions%2C%203rd%20Edition.pdf]
- by Jeffrey E.F. Friedl.
-- {Regular Expressions Cookbook}[https://doc.lagout.org/programmation/Regular%20Expressions/Regular%20Expressions%20Cookbook_%20Detailed%20Solutions%20in%20Eight%20Programming%20Languages%20%282nd%20ed.%29%20%5BGoyvaerts%20%26%20Levithan%202012-09-06%5D.pdf]
- by Jan Goyvaerts & Steven Levithan.
+The other is timeout keyword of Regexp.new.
-Explore, test (interactive online editor):
+ re = Regexp.new("(b|a+)*c", timeout: 3)
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ /(b|a+)*c/ =~ s #=> This raises an exception in three seconds
-- {Rubular}[https://rubular.com/].
+When using Regexps to process untrusted input, you should use the timeout
+feature to avoid excessive backtracking. Otherwise, a malicious user can
+provide input to Regexp causing Denial-of-Service attack.
+Note that the timeout is not set by default because an appropriate limit
+highly depends on an application requirement and context.
diff --git a/doc/regexp/methods.rdoc b/doc/regexp/methods.rdoc
deleted file mode 100644
index 356156ac9a..0000000000
--- a/doc/regexp/methods.rdoc
+++ /dev/null
@@ -1,41 +0,0 @@
-== \Regexp Methods
-
-Each of these Ruby core methods can accept a regexp as an argument:
-
-- Enumerable#all?
-- Enumerable#any?
-- Enumerable#grep
-- Enumerable#grep_v
-- Enumerable#none?
-- Enumerable#one?
-- Enumerable#slice_after
-- Enumerable#slice_before
-- Regexp#=~
-- Regexp#match
-- Regexp#match?
-- Regexp.new
-- Regexp.union
-- String#=~
-- String#[]=
-- String#byteindex
-- String#byterindex
-- String#gsub
-- String#gsub!
-- String#index
-- String#match
-- String#match?
-- String#partition
-- String#rindex
-- String#rpartition
-- String#scan
-- String#slice
-- String#slice!
-- String#split
-- String#start_with?
-- String#sub
-- String#sub!
-- Symbol#=~
-- Symbol#match
-- Symbol#match?
-- Symbol#slice
-- Symbol#start_with?
diff --git a/doc/regexp/unicode_properties.rdoc b/doc/regexp/unicode_properties.rdoc
deleted file mode 100644
index a1d7ecc380..0000000000
--- a/doc/regexp/unicode_properties.rdoc
+++ /dev/null
@@ -1,678 +0,0 @@
-== \Regexps Based on Unicode Properties
-
-The properties shown here are those currently supported in Ruby.
-Older versions may not support all of these.
-
-=== POSIX brackets
-
-- <tt>\p{ASCII}</tt>
-- <tt>\p{Alnum}</tt>
-- <tt>\p{Alphabetic}</tt>, <tt>\p{Alpha}</tt>
-- <tt>\p{Blank}</tt>
-- <tt>\p{Cntrl}</tt>
-- <tt>\p{Digit}</tt>
-- <tt>\p{Graph}</tt>
-- <tt>\p{Lowercase}</tt>, <tt>\p{Lower}</tt>
-- <tt>\p{Print}</tt>
-- <tt>\p{Punct}</tt>
-- <tt>\p{Space}</tt>
-- <tt>\p{Uppercase}</tt>, <tt>\p{Upper}</tt>
-- <tt>\p{Word}</tt>
-- <tt>\p{XDigit}</tt>
-- <tt>\p{XPosixPunct}</tt>
-
-=== Special
-
-- <tt>\p{Any}</tt>
-- <tt>\p{Assigned}</tt>
-
-=== Major and General Categories
-
-- <tt>\p{Cased_Letter}</tt>, <tt>\p{LC}</tt>
-- <tt>\p{Close_Punctuation}</tt>, <tt>\p{Pe}</tt>
-- <tt>\p{Connector_Punctuation}</tt>, <tt>\p{Pc}</tt>
-- <tt>\p{Control}</tt>, <tt>\p{Cc}</tt>
-- <tt>\p{Currency_Symbol}</tt>, <tt>\p{Sc}</tt>
-- <tt>\p{Dash_Punctuation}</tt>, <tt>\p{Pd}</tt>
-- <tt>\p{Decimal_Number}</tt>, <tt>\p{Nd}</tt>
-- <tt>\p{Enclosing_Mark}</tt>, <tt>\p{Me}</tt>
-- <tt>\p{Final_Punctuation}</tt>, <tt>\p{Pf}</tt>
-- <tt>\p{Format}</tt>, <tt>\p{Cf}</tt>
-- <tt>\p{Initial_Punctuation}</tt>, <tt>\p{Pi}</tt>
-- <tt>\p{Letter}</tt>, <tt>\p{L}</tt>
-- <tt>\p{Letter_Number}</tt>, <tt>\p{Nl}</tt>
-- <tt>\p{Line_Separator}</tt>, <tt>\p{Zl}</tt>
-- <tt>\p{Lowercase_Letter}</tt>, <tt>\p{Ll}</tt>
-- <tt>\p{Mark}</tt>, <tt>\p{M}</tt>
-- <tt>\p{Math_Symbol}</tt>, <tt>\p{Sm}</tt>
-- <tt>\p{Modifier_Letter}</tt>, <tt>\p{Lm}</tt>
-- <tt>\p{Modifier_Symbol}</tt>, <tt>\p{Sk}</tt>
-- <tt>\p{Nonspacing_Mark}</tt>, <tt>\p{Mn}</tt>
-- <tt>\p{Number}</tt>, <tt>\p{N}</tt>
-- <tt>\p{Open_Punctuation}</tt>, <tt>\p{Ps}</tt>
-- <tt>\p{Other}</tt>, <tt>\p{C}</tt>
-- <tt>\p{Other_Letter}</tt>, <tt>\p{Lo}</tt>
-- <tt>\p{Other_Number}</tt>, <tt>\p{No}</tt>
-- <tt>\p{Other_Punctuation}</tt>, <tt>\p{Po}</tt>
-- <tt>\p{Other_Symbol}</tt>, <tt>\p{So}</tt>
-- <tt>\p{Paragraph_Separator}</tt>, <tt>\p{Zp}</tt>
-- <tt>\p{Private_Use}</tt>, <tt>\p{Co}</tt>
-- <tt>\p{Punctuation}</tt>, <tt>\p{P}</tt>
-- <tt>\p{Separator}</tt>, <tt>\p{Z}</tt>
-- <tt>\p{Space_Separator}</tt>, <tt>\p{Zs}</tt>
-- <tt>\p{Spacing_Mark}</tt>, <tt>\p{Mc}</tt>
-- <tt>\p{Surrogate}</tt>, <tt>\p{Cs}</tt>
-- <tt>\p{Symbol}</tt>, <tt>\p{S}</tt>
-- <tt>\p{Titlecase_Letter}</tt>, <tt>\p{Lt}</tt>
-- <tt>\p{Unassigned}</tt>, <tt>\p{Cn}</tt>
-- <tt>\p{Uppercase_Letter}</tt>, <tt>\p{Lu}</tt>
-
-=== Prop List
-
-- <tt>\p{ASCII_Hex_Digit}</tt>, <tt>\p{AHex}</tt>
-- <tt>\p{Bidi_Control}</tt>, <tt>\p{Bidi_C}</tt>
-- <tt>\p{Dash}</tt>
-- <tt>\p{Deprecated}</tt>, <tt>\p{Dep}</tt>
-- <tt>\p{Diacritic}</tt>, <tt>\p{Dia}</tt>
-- <tt>\p{Extender}</tt>, <tt>\p{Ext}</tt>
-- <tt>\p{Hex_Digit}</tt>, <tt>\p{Hex}</tt>
-- <tt>\p{Hyphen}</tt>
-- <tt>\p{IDS_Binary_Operator}</tt>, <tt>\p{IDSB}</tt>
-- <tt>\p{IDS_Trinary_Operator}</tt>, <tt>\p{IDST}</tt>
-- <tt>\p{Ideographic}</tt>, <tt>\p{Ideo}</tt>
-- <tt>\p{Join_Control}</tt>, <tt>\p{Join_C}</tt>
-- <tt>\p{Logical_Order_Exception}</tt>, <tt>\p{LOE}</tt>
-- <tt>\p{Noncharacter_Code_Point}</tt>, <tt>\p{NChar}</tt>
-- <tt>\p{Other_Alphabetic}</tt>, <tt>\p{OAlpha}</tt>
-- <tt>\p{Other_Default_Ignorable_Code_Point}</tt>, <tt>\p{ODI}</tt>
-- <tt>\p{Other_Grapheme_Extend}</tt>, <tt>\p{OGr_Ext}</tt>
-- <tt>\p{Other_ID_Continue}</tt>, <tt>\p{OIDC}</tt>
-- <tt>\p{Other_ID_Start}</tt>, <tt>\p{OIDS}</tt>
-- <tt>\p{Other_Lowercase}</tt>, <tt>\p{OLower}</tt>
-- <tt>\p{Other_Math}</tt>, <tt>\p{OMath}</tt>
-- <tt>\p{Other_Uppercase}</tt>, <tt>\p{OUpper}</tt>
-- <tt>\p{Pattern_Syntax}</tt>, <tt>\p{Pat_Syn}</tt>
-- <tt>\p{Pattern_White_Space}</tt>, <tt>\p{Pat_WS}</tt>
-- <tt>\p{Prepended_Concatenation_Mark}</tt>, <tt>\p{PCM}</tt>
-- <tt>\p{Quotation_Mark}</tt>, <tt>\p{QMark}</tt>
-- <tt>\p{Radical}</tt>
-- <tt>\p{Regional_Indicator}</tt>, <tt>\p{RI}</tt>
-- <tt>\p{Sentence_Terminal}</tt>, <tt>\p{STerm}</tt>
-- <tt>\p{Soft_Dotted}</tt>, <tt>\p{SD}</tt>
-- <tt>\p{Terminal_Punctuation}</tt>, <tt>\p{Term}</tt>
-- <tt>\p{Unified_Ideograph}</tt>, <tt>\p{UIdeo}</tt>
-- <tt>\p{Variation_Selector}</tt>, <tt>\p{VS}</tt>
-- <tt>\p{White_Space}</tt>, <tt>\p{WSpace}</tt>
-
-=== Derived Core Properties
-
-- <tt>\p{Alphabetic}</tt>, <tt>\p{Alpha}</tt>
-- <tt>\p{Case_Ignorable}</tt>, <tt>\p{CI}</tt>
-- <tt>\p{Cased}</tt>
-- <tt>\p{Changes_When_Casefolded}</tt>, <tt>\p{CWCF}</tt>
-- <tt>\p{Changes_When_Casemapped}</tt>, <tt>\p{CWCM}</tt>
-- <tt>\p{Changes_When_Lowercased}</tt>, <tt>\p{CWL}</tt>
-- <tt>\p{Changes_When_Titlecased}</tt>, <tt>\p{CWT}</tt>
-- <tt>\p{Changes_When_Uppercased}</tt>, <tt>\p{CWU}</tt>
-- <tt>\p{Default_Ignorable_Code_Point}</tt>, <tt>\p{DI}</tt>
-- <tt>\p{Grapheme_Base}</tt>, <tt>\p{Gr_Base}</tt>
-- <tt>\p{Grapheme_Extend}</tt>, <tt>\p{Gr_Ext}</tt>
-- <tt>\p{Grapheme_Link}</tt>, <tt>\p{Gr_Link}</tt>
-- <tt>\p{ID_Continue}</tt>, <tt>\p{IDC}</tt>
-- <tt>\p{ID_Start}</tt>, <tt>\p{IDS}</tt>
-- <tt>\p{Lowercase}</tt>, <tt>\p{Lower}</tt>
-- <tt>\p{Math}</tt>
-- <tt>\p{Uppercase}</tt>, <tt>\p{Upper}</tt>
-- <tt>\p{XID_Continue}</tt>, <tt>\p{XIDC}</tt>
-- <tt>\p{XID_Start}</tt>, <tt>\p{XIDS}</tt>
-
-=== Scripts
-
-- <tt>\p{Adlam}</tt>, <tt>\p{Adlm}</tt>
-- <tt>\p{Ahom}</tt>
-- <tt>\p{Anatolian_Hieroglyphs}</tt>, <tt>\p{Hluw}</tt>
-- <tt>\p{Arabic}</tt>, <tt>\p{Arab}</tt>
-- <tt>\p{Armenian}</tt>, <tt>\p{Armn}</tt>
-- <tt>\p{Avestan}</tt>, <tt>\p{Avst}</tt>
-- <tt>\p{Balinese}</tt>, <tt>\p{Bali}</tt>
-- <tt>\p{Bamum}</tt>, <tt>\p{Bamu}</tt>
-- <tt>\p{Bassa_Vah}</tt>, <tt>\p{Bass}</tt>
-- <tt>\p{Batak}</tt>, <tt>\p{Batk}</tt>
-- <tt>\p{Bengali}</tt>, <tt>\p{Beng}</tt>
-- <tt>\p{Bhaiksuki}</tt>, <tt>\p{Bhks}</tt>
-- <tt>\p{Bopomofo}</tt>, <tt>\p{Bopo}</tt>
-- <tt>\p{Brahmi}</tt>, <tt>\p{Brah}</tt>
-- <tt>\p{Braille}</tt>, <tt>\p{Brai}</tt>
-- <tt>\p{Buginese}</tt>, <tt>\p{Bugi}</tt>
-- <tt>\p{Buhid}</tt>, <tt>\p{Buhd}</tt>
-- <tt>\p{Canadian_Aboriginal}</tt>, <tt>\p{Cans}</tt>
-- <tt>\p{Carian}</tt>, <tt>\p{Cari}</tt>
-- <tt>\p{Caucasian_Albanian}</tt>, <tt>\p{Aghb}</tt>
-- <tt>\p{Chakma}</tt>, <tt>\p{Cakm}</tt>
-- <tt>\p{Cham}</tt>
-- <tt>\p{Cherokee}</tt>, <tt>\p{Cher}</tt>
-- <tt>\p{Chorasmian}</tt>, <tt>\p{Chrs}</tt>
-- <tt>\p{Common}</tt>, <tt>\p{Zyyy}</tt>
-- <tt>\p{Coptic}</tt>, <tt>\p{Copt}</tt>
-- <tt>\p{Cuneiform}</tt>, <tt>\p{Xsux}</tt>
-- <tt>\p{Cypriot}</tt>, <tt>\p{Cprt}</tt>
-- <tt>\p{Cypro_Minoan}</tt>, <tt>\p{Cpmn}</tt>
-- <tt>\p{Cyrillic}</tt>, <tt>\p{Cyrl}</tt>
-- <tt>\p{Deseret}</tt>, <tt>\p{Dsrt}</tt>
-- <tt>\p{Devanagari}</tt>, <tt>\p{Deva}</tt>
-- <tt>\p{Dives_Akuru}</tt>, <tt>\p{Diak}</tt>
-- <tt>\p{Dogra}</tt>, <tt>\p{Dogr}</tt>
-- <tt>\p{Duployan}</tt>, <tt>\p{Dupl}</tt>
-- <tt>\p{Egyptian_Hieroglyphs}</tt>, <tt>\p{Egyp}</tt>
-- <tt>\p{Elbasan}</tt>, <tt>\p{Elba}</tt>
-- <tt>\p{Elymaic}</tt>, <tt>\p{Elym}</tt>
-- <tt>\p{Ethiopic}</tt>, <tt>\p{Ethi}</tt>
-- <tt>\p{Georgian}</tt>, <tt>\p{Geor}</tt>
-- <tt>\p{Glagolitic}</tt>, <tt>\p{Glag}</tt>
-- <tt>\p{Gothic}</tt>, <tt>\p{Goth}</tt>
-- <tt>\p{Grantha}</tt>, <tt>\p{Gran}</tt>
-- <tt>\p{Greek}</tt>, <tt>\p{Grek}</tt>
-- <tt>\p{Gujarati}</tt>, <tt>\p{Gujr}</tt>
-- <tt>\p{Gunjala_Gondi}</tt>, <tt>\p{Gong}</tt>
-- <tt>\p{Gurmukhi}</tt>, <tt>\p{Guru}</tt>
-- <tt>\p{Han}</tt>, <tt>\p{Hani}</tt>
-- <tt>\p{Hangul}</tt>, <tt>\p{Hang}</tt>
-- <tt>\p{Hanifi_Rohingya}</tt>, <tt>\p{Rohg}</tt>
-- <tt>\p{Hanunoo}</tt>, <tt>\p{Hano}</tt>
-- <tt>\p{Hatran}</tt>, <tt>\p{Hatr}</tt>
-- <tt>\p{Hebrew}</tt>, <tt>\p{Hebr}</tt>
-- <tt>\p{Hiragana}</tt>, <tt>\p{Hira}</tt>
-- <tt>\p{Imperial_Aramaic}</tt>, <tt>\p{Armi}</tt>
-- <tt>\p{Inherited}</tt>, <tt>\p{Zinh}</tt>
-- <tt>\p{Inscriptional_Pahlavi}</tt>, <tt>\p{Phli}</tt>
-- <tt>\p{Inscriptional_Parthian}</tt>, <tt>\p{Prti}</tt>
-- <tt>\p{Javanese}</tt>, <tt>\p{Java}</tt>
-- <tt>\p{Kaithi}</tt>, <tt>\p{Kthi}</tt>
-- <tt>\p{Kannada}</tt>, <tt>\p{Knda}</tt>
-- <tt>\p{Katakana}</tt>, <tt>\p{Kana}</tt>
-- <tt>\p{Kawi}</tt>
-- <tt>\p{Kayah_Li}</tt>, <tt>\p{Kali}</tt>
-- <tt>\p{Kharoshthi}</tt>, <tt>\p{Khar}</tt>
-- <tt>\p{Khitan_Small_Script}</tt>, <tt>\p{Kits}</tt>
-- <tt>\p{Khmer}</tt>, <tt>\p{Khmr}</tt>
-- <tt>\p{Khojki}</tt>, <tt>\p{Khoj}</tt>
-- <tt>\p{Khudawadi}</tt>, <tt>\p{Sind}</tt>
-- <tt>\p{Lao}</tt>, <tt>\p{Laoo}</tt>
-- <tt>\p{Latin}</tt>, <tt>\p{Latn}</tt>
-- <tt>\p{Lepcha}</tt>, <tt>\p{Lepc}</tt>
-- <tt>\p{Limbu}</tt>, <tt>\p{Limb}</tt>
-- <tt>\p{Linear_A}</tt>, <tt>\p{Lina}</tt>
-- <tt>\p{Linear_B}</tt>, <tt>\p{Linb}</tt>
-- <tt>\p{Lisu}</tt>
-- <tt>\p{Lycian}</tt>, <tt>\p{Lyci}</tt>
-- <tt>\p{Lydian}</tt>, <tt>\p{Lydi}</tt>
-- <tt>\p{Mahajani}</tt>, <tt>\p{Mahj}</tt>
-- <tt>\p{Makasar}</tt>, <tt>\p{Maka}</tt>
-- <tt>\p{Malayalam}</tt>, <tt>\p{Mlym}</tt>
-- <tt>\p{Mandaic}</tt>, <tt>\p{Mand}</tt>
-- <tt>\p{Manichaean}</tt>, <tt>\p{Mani}</tt>
-- <tt>\p{Marchen}</tt>, <tt>\p{Marc}</tt>
-- <tt>\p{Masaram_Gondi}</tt>, <tt>\p{Gonm}</tt>
-- <tt>\p{Medefaidrin}</tt>, <tt>\p{Medf}</tt>
-- <tt>\p{Meetei_Mayek}</tt>, <tt>\p{Mtei}</tt>
-- <tt>\p{Mende_Kikakui}</tt>, <tt>\p{Mend}</tt>
-- <tt>\p{Meroitic_Cursive}</tt>, <tt>\p{Merc}</tt>
-- <tt>\p{Meroitic_Hieroglyphs}</tt>, <tt>\p{Mero}</tt>
-- <tt>\p{Miao}</tt>, <tt>\p{Plrd}</tt>
-- <tt>\p{Modi}</tt>
-- <tt>\p{Mongolian}</tt>, <tt>\p{Mong}</tt>
-- <tt>\p{Mro}</tt>, <tt>\p{Mroo}</tt>
-- <tt>\p{Multani}</tt>, <tt>\p{Mult}</tt>
-- <tt>\p{Myanmar}</tt>, <tt>\p{Mymr}</tt>
-- <tt>\p{Nabataean}</tt>, <tt>\p{Nbat}</tt>
-- <tt>\p{Nag_Mundari}</tt>, <tt>\p{Nagm}</tt>
-- <tt>\p{Nandinagari}</tt>, <tt>\p{Nand}</tt>
-- <tt>\p{New_Tai_Lue}</tt>, <tt>\p{Talu}</tt>
-- <tt>\p{Newa}</tt>
-- <tt>\p{Nko}</tt>, <tt>\p{Nkoo}</tt>
-- <tt>\p{Nushu}</tt>, <tt>\p{Nshu}</tt>
-- <tt>\p{Nyiakeng_Puachue_Hmong}</tt>, <tt>\p{Hmnp}</tt>
-- <tt>\p{Ogham}</tt>, <tt>\p{Ogam}</tt>
-- <tt>\p{Ol_Chiki}</tt>, <tt>\p{Olck}</tt>
-- <tt>\p{Old_Hungarian}</tt>, <tt>\p{Hung}</tt>
-- <tt>\p{Old_Italic}</tt>, <tt>\p{Ital}</tt>
-- <tt>\p{Old_North_Arabian}</tt>, <tt>\p{Narb}</tt>
-- <tt>\p{Old_Permic}</tt>, <tt>\p{Perm}</tt>
-- <tt>\p{Old_Persian}</tt>, <tt>\p{Xpeo}</tt>
-- <tt>\p{Old_Sogdian}</tt>, <tt>\p{Sogo}</tt>
-- <tt>\p{Old_South_Arabian}</tt>, <tt>\p{Sarb}</tt>
-- <tt>\p{Old_Turkic}</tt>, <tt>\p{Orkh}</tt>
-- <tt>\p{Old_Uyghur}</tt>, <tt>\p{Ougr}</tt>
-- <tt>\p{Oriya}</tt>, <tt>\p{Orya}</tt>
-- <tt>\p{Osage}</tt>, <tt>\p{Osge}</tt>
-- <tt>\p{Osmanya}</tt>, <tt>\p{Osma}</tt>
-- <tt>\p{Pahawh_Hmong}</tt>, <tt>\p{Hmng}</tt>
-- <tt>\p{Palmyrene}</tt>, <tt>\p{Palm}</tt>
-- <tt>\p{Pau_Cin_Hau}</tt>, <tt>\p{Pauc}</tt>
-- <tt>\p{Phags_Pa}</tt>, <tt>\p{Phag}</tt>
-- <tt>\p{Phoenician}</tt>, <tt>\p{Phnx}</tt>
-- <tt>\p{Psalter_Pahlavi}</tt>, <tt>\p{Phlp}</tt>
-- <tt>\p{Rejang}</tt>, <tt>\p{Rjng}</tt>
-- <tt>\p{Runic}</tt>, <tt>\p{Runr}</tt>
-- <tt>\p{Samaritan}</tt>, <tt>\p{Samr}</tt>
-- <tt>\p{Saurashtra}</tt>, <tt>\p{Saur}</tt>
-- <tt>\p{Sharada}</tt>, <tt>\p{Shrd}</tt>
-- <tt>\p{Shavian}</tt>, <tt>\p{Shaw}</tt>
-- <tt>\p{Siddham}</tt>, <tt>\p{Sidd}</tt>
-- <tt>\p{SignWriting}</tt>, <tt>\p{Sgnw}</tt>
-- <tt>\p{Sinhala}</tt>, <tt>\p{Sinh}</tt>
-- <tt>\p{Sogdian}</tt>, <tt>\p{Sogd}</tt>
-- <tt>\p{Sora_Sompeng}</tt>, <tt>\p{Sora}</tt>
-- <tt>\p{Soyombo}</tt>, <tt>\p{Soyo}</tt>
-- <tt>\p{Sundanese}</tt>, <tt>\p{Sund}</tt>
-- <tt>\p{Syloti_Nagri}</tt>, <tt>\p{Sylo}</tt>
-- <tt>\p{Syriac}</tt>, <tt>\p{Syrc}</tt>
-- <tt>\p{Tagalog}</tt>, <tt>\p{Tglg}</tt>
-- <tt>\p{Tagbanwa}</tt>, <tt>\p{Tagb}</tt>
-- <tt>\p{Tai_Le}</tt>, <tt>\p{Tale}</tt>
-- <tt>\p{Tai_Tham}</tt>, <tt>\p{Lana}</tt>
-- <tt>\p{Tai_Viet}</tt>, <tt>\p{Tavt}</tt>
-- <tt>\p{Takri}</tt>, <tt>\p{Takr}</tt>
-- <tt>\p{Tamil}</tt>, <tt>\p{Taml}</tt>
-- <tt>\p{Tangsa}</tt>, <tt>\p{Tnsa}</tt>
-- <tt>\p{Tangut}</tt>, <tt>\p{Tang}</tt>
-- <tt>\p{Telugu}</tt>, <tt>\p{Telu}</tt>
-- <tt>\p{Thaana}</tt>, <tt>\p{Thaa}</tt>
-- <tt>\p{Thai}</tt>
-- <tt>\p{Tibetan}</tt>, <tt>\p{Tibt}</tt>
-- <tt>\p{Tifinagh}</tt>, <tt>\p{Tfng}</tt>
-- <tt>\p{Tirhuta}</tt>, <tt>\p{Tirh}</tt>
-- <tt>\p{Toto}</tt>
-- <tt>\p{Ugaritic}</tt>, <tt>\p{Ugar}</tt>
-- <tt>\p{Unknown}</tt>, <tt>\p{Zzzz}</tt>
-- <tt>\p{Vai}</tt>, <tt>\p{Vaii}</tt>
-- <tt>\p{Vithkuqi}</tt>, <tt>\p{Vith}</tt>
-- <tt>\p{Wancho}</tt>, <tt>\p{Wcho}</tt>
-- <tt>\p{Warang_Citi}</tt>, <tt>\p{Wara}</tt>
-- <tt>\p{Yezidi}</tt>, <tt>\p{Yezi}</tt>
-- <tt>\p{Yi}</tt>, <tt>\p{Yiii}</tt>
-- <tt>\p{Zanabazar_Square}</tt>, <tt>\p{Zanb}</tt>
-
-=== Blocks
-
-- <tt>\p{In_Adlam}</tt>
-- <tt>\p{In_Aegean_Numbers}</tt>
-- <tt>\p{In_Ahom}</tt>
-- <tt>\p{In_Alchemical_Symbols}</tt>
-- <tt>\p{In_Alphabetic_Presentation_Forms}</tt>
-- <tt>\p{In_Anatolian_Hieroglyphs}</tt>
-- <tt>\p{In_Ancient_Greek_Musical_Notation}</tt>
-- <tt>\p{In_Ancient_Greek_Numbers}</tt>
-- <tt>\p{In_Ancient_Symbols}</tt>
-- <tt>\p{In_Arabic}</tt>
-- <tt>\p{In_Arabic_Extended_A}</tt>
-- <tt>\p{In_Arabic_Extended_B}</tt>
-- <tt>\p{In_Arabic_Extended_C}</tt>
-- <tt>\p{In_Arabic_Mathematical_Alphabetic_Symbols}</tt>
-- <tt>\p{In_Arabic_Presentation_Forms_A}</tt>
-- <tt>\p{In_Arabic_Presentation_Forms_B}</tt>
-- <tt>\p{In_Arabic_Supplement}</tt>
-- <tt>\p{In_Armenian}</tt>
-- <tt>\p{In_Arrows}</tt>
-- <tt>\p{In_Avestan}</tt>
-- <tt>\p{In_Balinese}</tt>
-- <tt>\p{In_Bamum}</tt>
-- <tt>\p{In_Bamum_Supplement}</tt>
-- <tt>\p{In_Basic_Latin}</tt>
-- <tt>\p{In_Bassa_Vah}</tt>
-- <tt>\p{In_Batak}</tt>
-- <tt>\p{In_Bengali}</tt>
-- <tt>\p{In_Bhaiksuki}</tt>
-- <tt>\p{In_Block_Elements}</tt>
-- <tt>\p{In_Bopomofo}</tt>
-- <tt>\p{In_Bopomofo_Extended}</tt>
-- <tt>\p{In_Box_Drawing}</tt>
-- <tt>\p{In_Brahmi}</tt>
-- <tt>\p{In_Braille_Patterns}</tt>
-- <tt>\p{In_Buginese}</tt>
-- <tt>\p{In_Buhid}</tt>
-- <tt>\p{In_Byzantine_Musical_Symbols}</tt>
-- <tt>\p{In_CJK_Compatibility}</tt>
-- <tt>\p{In_CJK_Compatibility_Forms}</tt>
-- <tt>\p{In_CJK_Compatibility_Ideographs}</tt>
-- <tt>\p{In_CJK_Compatibility_Ideographs_Supplement}</tt>
-- <tt>\p{In_CJK_Radicals_Supplement}</tt>
-- <tt>\p{In_CJK_Strokes}</tt>
-- <tt>\p{In_CJK_Symbols_and_Punctuation}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_A}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_B}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_C}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_D}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_E}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_F}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_G}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_H}</tt>
-- <tt>\p{In_Carian}</tt>
-- <tt>\p{In_Caucasian_Albanian}</tt>
-- <tt>\p{In_Chakma}</tt>
-- <tt>\p{In_Cham}</tt>
-- <tt>\p{In_Cherokee}</tt>
-- <tt>\p{In_Cherokee_Supplement}</tt>
-- <tt>\p{In_Chess_Symbols}</tt>
-- <tt>\p{In_Chorasmian}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks_Extended}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks_Supplement}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks_for_Symbols}</tt>
-- <tt>\p{In_Combining_Half_Marks}</tt>
-- <tt>\p{In_Common_Indic_Number_Forms}</tt>
-- <tt>\p{In_Control_Pictures}</tt>
-- <tt>\p{In_Coptic}</tt>
-- <tt>\p{In_Coptic_Epact_Numbers}</tt>
-- <tt>\p{In_Counting_Rod_Numerals}</tt>
-- <tt>\p{In_Cuneiform}</tt>
-- <tt>\p{In_Cuneiform_Numbers_and_Punctuation}</tt>
-- <tt>\p{In_Currency_Symbols}</tt>
-- <tt>\p{In_Cypriot_Syllabary}</tt>
-- <tt>\p{In_Cypro_Minoan}</tt>
-- <tt>\p{In_Cyrillic}</tt>
-- <tt>\p{In_Cyrillic_Extended_A}</tt>
-- <tt>\p{In_Cyrillic_Extended_B}</tt>
-- <tt>\p{In_Cyrillic_Extended_C}</tt>
-- <tt>\p{In_Cyrillic_Extended_D}</tt>
-- <tt>\p{In_Cyrillic_Supplement}</tt>
-- <tt>\p{In_Deseret}</tt>
-- <tt>\p{In_Devanagari}</tt>
-- <tt>\p{In_Devanagari_Extended}</tt>
-- <tt>\p{In_Devanagari_Extended_A}</tt>
-- <tt>\p{In_Dingbats}</tt>
-- <tt>\p{In_Dives_Akuru}</tt>
-- <tt>\p{In_Dogra}</tt>
-- <tt>\p{In_Domino_Tiles}</tt>
-- <tt>\p{In_Duployan}</tt>
-- <tt>\p{In_Early_Dynastic_Cuneiform}</tt>
-- <tt>\p{In_Egyptian_Hieroglyph_Format_Controls}</tt>
-- <tt>\p{In_Egyptian_Hieroglyphs}</tt>
-- <tt>\p{In_Elbasan}</tt>
-- <tt>\p{In_Elymaic}</tt>
-- <tt>\p{In_Emoticons}</tt>
-- <tt>\p{In_Enclosed_Alphanumeric_Supplement}</tt>
-- <tt>\p{In_Enclosed_Alphanumerics}</tt>
-- <tt>\p{In_Enclosed_CJK_Letters_and_Months}</tt>
-- <tt>\p{In_Enclosed_Ideographic_Supplement}</tt>
-- <tt>\p{In_Ethiopic}</tt>
-- <tt>\p{In_Ethiopic_Extended}</tt>
-- <tt>\p{In_Ethiopic_Extended_A}</tt>
-- <tt>\p{In_Ethiopic_Extended_B}</tt>
-- <tt>\p{In_Ethiopic_Supplement}</tt>
-- <tt>\p{In_General_Punctuation}</tt>
-- <tt>\p{In_Geometric_Shapes}</tt>
-- <tt>\p{In_Geometric_Shapes_Extended}</tt>
-- <tt>\p{In_Georgian}</tt>
-- <tt>\p{In_Georgian_Extended}</tt>
-- <tt>\p{In_Georgian_Supplement}</tt>
-- <tt>\p{In_Glagolitic}</tt>
-- <tt>\p{In_Glagolitic_Supplement}</tt>
-- <tt>\p{In_Gothic}</tt>
-- <tt>\p{In_Grantha}</tt>
-- <tt>\p{In_Greek_Extended}</tt>
-- <tt>\p{In_Greek_and_Coptic}</tt>
-- <tt>\p{In_Gujarati}</tt>
-- <tt>\p{In_Gunjala_Gondi}</tt>
-- <tt>\p{In_Gurmukhi}</tt>
-- <tt>\p{In_Halfwidth_and_Fullwidth_Forms}</tt>
-- <tt>\p{In_Hangul_Compatibility_Jamo}</tt>
-- <tt>\p{In_Hangul_Jamo}</tt>
-- <tt>\p{In_Hangul_Jamo_Extended_A}</tt>
-- <tt>\p{In_Hangul_Jamo_Extended_B}</tt>
-- <tt>\p{In_Hangul_Syllables}</tt>
-- <tt>\p{In_Hanifi_Rohingya}</tt>
-- <tt>\p{In_Hanunoo}</tt>
-- <tt>\p{In_Hatran}</tt>
-- <tt>\p{In_Hebrew}</tt>
-- <tt>\p{In_High_Private_Use_Surrogates}</tt>
-- <tt>\p{In_High_Surrogates}</tt>
-- <tt>\p{In_Hiragana}</tt>
-- <tt>\p{In_IPA_Extensions}</tt>
-- <tt>\p{In_Ideographic_Description_Characters}</tt>
-- <tt>\p{In_Ideographic_Symbols_and_Punctuation}</tt>
-- <tt>\p{In_Imperial_Aramaic}</tt>
-- <tt>\p{In_Indic_Siyaq_Numbers}</tt>
-- <tt>\p{In_Inscriptional_Pahlavi}</tt>
-- <tt>\p{In_Inscriptional_Parthian}</tt>
-- <tt>\p{In_Javanese}</tt>
-- <tt>\p{In_Kaithi}</tt>
-- <tt>\p{In_Kaktovik_Numerals}</tt>
-- <tt>\p{In_Kana_Extended_A}</tt>
-- <tt>\p{In_Kana_Extended_B}</tt>
-- <tt>\p{In_Kana_Supplement}</tt>
-- <tt>\p{In_Kanbun}</tt>
-- <tt>\p{In_Kangxi_Radicals}</tt>
-- <tt>\p{In_Kannada}</tt>
-- <tt>\p{In_Katakana}</tt>
-- <tt>\p{In_Katakana_Phonetic_Extensions}</tt>
-- <tt>\p{In_Kawi}</tt>
-- <tt>\p{In_Kayah_Li}</tt>
-- <tt>\p{In_Kharoshthi}</tt>
-- <tt>\p{In_Khitan_Small_Script}</tt>
-- <tt>\p{In_Khmer}</tt>
-- <tt>\p{In_Khmer_Symbols}</tt>
-- <tt>\p{In_Khojki}</tt>
-- <tt>\p{In_Khudawadi}</tt>
-- <tt>\p{In_Lao}</tt>
-- <tt>\p{In_Latin_1_Supplement}</tt>
-- <tt>\p{In_Latin_Extended_A}</tt>
-- <tt>\p{In_Latin_Extended_Additional}</tt>
-- <tt>\p{In_Latin_Extended_B}</tt>
-- <tt>\p{In_Latin_Extended_C}</tt>
-- <tt>\p{In_Latin_Extended_D}</tt>
-- <tt>\p{In_Latin_Extended_E}</tt>
-- <tt>\p{In_Latin_Extended_F}</tt>
-- <tt>\p{In_Latin_Extended_G}</tt>
-- <tt>\p{In_Lepcha}</tt>
-- <tt>\p{In_Letterlike_Symbols}</tt>
-- <tt>\p{In_Limbu}</tt>
-- <tt>\p{In_Linear_A}</tt>
-- <tt>\p{In_Linear_B_Ideograms}</tt>
-- <tt>\p{In_Linear_B_Syllabary}</tt>
-- <tt>\p{In_Lisu}</tt>
-- <tt>\p{In_Lisu_Supplement}</tt>
-- <tt>\p{In_Low_Surrogates}</tt>
-- <tt>\p{In_Lycian}</tt>
-- <tt>\p{In_Lydian}</tt>
-- <tt>\p{In_Mahajani}</tt>
-- <tt>\p{In_Mahjong_Tiles}</tt>
-- <tt>\p{In_Makasar}</tt>
-- <tt>\p{In_Malayalam}</tt>
-- <tt>\p{In_Mandaic}</tt>
-- <tt>\p{In_Manichaean}</tt>
-- <tt>\p{In_Marchen}</tt>
-- <tt>\p{In_Masaram_Gondi}</tt>
-- <tt>\p{In_Mathematical_Alphanumeric_Symbols}</tt>
-- <tt>\p{In_Mathematical_Operators}</tt>
-- <tt>\p{In_Mayan_Numerals}</tt>
-- <tt>\p{In_Medefaidrin}</tt>
-- <tt>\p{In_Meetei_Mayek}</tt>
-- <tt>\p{In_Meetei_Mayek_Extensions}</tt>
-- <tt>\p{In_Mende_Kikakui}</tt>
-- <tt>\p{In_Meroitic_Cursive}</tt>
-- <tt>\p{In_Meroitic_Hieroglyphs}</tt>
-- <tt>\p{In_Miao}</tt>
-- <tt>\p{In_Miscellaneous_Mathematical_Symbols_A}</tt>
-- <tt>\p{In_Miscellaneous_Mathematical_Symbols_B}</tt>
-- <tt>\p{In_Miscellaneous_Symbols}</tt>
-- <tt>\p{In_Miscellaneous_Symbols_and_Arrows}</tt>
-- <tt>\p{In_Miscellaneous_Symbols_and_Pictographs}</tt>
-- <tt>\p{In_Miscellaneous_Technical}</tt>
-- <tt>\p{In_Modi}</tt>
-- <tt>\p{In_Modifier_Tone_Letters}</tt>
-- <tt>\p{In_Mongolian}</tt>
-- <tt>\p{In_Mongolian_Supplement}</tt>
-- <tt>\p{In_Mro}</tt>
-- <tt>\p{In_Multani}</tt>
-- <tt>\p{In_Musical_Symbols}</tt>
-- <tt>\p{In_Myanmar}</tt>
-- <tt>\p{In_Myanmar_Extended_A}</tt>
-- <tt>\p{In_Myanmar_Extended_B}</tt>
-- <tt>\p{In_NKo}</tt>
-- <tt>\p{In_Nabataean}</tt>
-- <tt>\p{In_Nag_Mundari}</tt>
-- <tt>\p{In_Nandinagari}</tt>
-- <tt>\p{In_New_Tai_Lue}</tt>
-- <tt>\p{In_Newa}</tt>
-- <tt>\p{In_No_Block}</tt>
-- <tt>\p{In_Number_Forms}</tt>
-- <tt>\p{In_Nushu}</tt>
-- <tt>\p{In_Nyiakeng_Puachue_Hmong}</tt>
-- <tt>\p{In_Ogham}</tt>
-- <tt>\p{In_Ol_Chiki}</tt>
-- <tt>\p{In_Old_Hungarian}</tt>
-- <tt>\p{In_Old_Italic}</tt>
-- <tt>\p{In_Old_North_Arabian}</tt>
-- <tt>\p{In_Old_Permic}</tt>
-- <tt>\p{In_Old_Persian}</tt>
-- <tt>\p{In_Old_Sogdian}</tt>
-- <tt>\p{In_Old_South_Arabian}</tt>
-- <tt>\p{In_Old_Turkic}</tt>
-- <tt>\p{In_Old_Uyghur}</tt>
-- <tt>\p{In_Optical_Character_Recognition}</tt>
-- <tt>\p{In_Oriya}</tt>
-- <tt>\p{In_Ornamental_Dingbats}</tt>
-- <tt>\p{In_Osage}</tt>
-- <tt>\p{In_Osmanya}</tt>
-- <tt>\p{In_Ottoman_Siyaq_Numbers}</tt>
-- <tt>\p{In_Pahawh_Hmong}</tt>
-- <tt>\p{In_Palmyrene}</tt>
-- <tt>\p{In_Pau_Cin_Hau}</tt>
-- <tt>\p{In_Phags_pa}</tt>
-- <tt>\p{In_Phaistos_Disc}</tt>
-- <tt>\p{In_Phoenician}</tt>
-- <tt>\p{In_Phonetic_Extensions}</tt>
-- <tt>\p{In_Phonetic_Extensions_Supplement}</tt>
-- <tt>\p{In_Playing_Cards}</tt>
-- <tt>\p{In_Private_Use_Area}</tt>
-- <tt>\p{In_Psalter_Pahlavi}</tt>
-- <tt>\p{In_Rejang}</tt>
-- <tt>\p{In_Rumi_Numeral_Symbols}</tt>
-- <tt>\p{In_Runic}</tt>
-- <tt>\p{In_Samaritan}</tt>
-- <tt>\p{In_Saurashtra}</tt>
-- <tt>\p{In_Sharada}</tt>
-- <tt>\p{In_Shavian}</tt>
-- <tt>\p{In_Shorthand_Format_Controls}</tt>
-- <tt>\p{In_Siddham}</tt>
-- <tt>\p{In_Sinhala}</tt>
-- <tt>\p{In_Sinhala_Archaic_Numbers}</tt>
-- <tt>\p{In_Small_Form_Variants}</tt>
-- <tt>\p{In_Small_Kana_Extension}</tt>
-- <tt>\p{In_Sogdian}</tt>
-- <tt>\p{In_Sora_Sompeng}</tt>
-- <tt>\p{In_Soyombo}</tt>
-- <tt>\p{In_Spacing_Modifier_Letters}</tt>
-- <tt>\p{In_Specials}</tt>
-- <tt>\p{In_Sundanese}</tt>
-- <tt>\p{In_Sundanese_Supplement}</tt>
-- <tt>\p{In_Superscripts_and_Subscripts}</tt>
-- <tt>\p{In_Supplemental_Arrows_A}</tt>
-- <tt>\p{In_Supplemental_Arrows_B}</tt>
-- <tt>\p{In_Supplemental_Arrows_C}</tt>
-- <tt>\p{In_Supplemental_Mathematical_Operators}</tt>
-- <tt>\p{In_Supplemental_Punctuation}</tt>
-- <tt>\p{In_Supplemental_Symbols_and_Pictographs}</tt>
-- <tt>\p{In_Supplementary_Private_Use_Area_A}</tt>
-- <tt>\p{In_Supplementary_Private_Use_Area_B}</tt>
-- <tt>\p{In_Sutton_SignWriting}</tt>
-- <tt>\p{In_Syloti_Nagri}</tt>
-- <tt>\p{In_Symbols_and_Pictographs_Extended_A}</tt>
-- <tt>\p{In_Symbols_for_Legacy_Computing}</tt>
-- <tt>\p{In_Syriac}</tt>
-- <tt>\p{In_Syriac_Supplement}</tt>
-- <tt>\p{In_Tagalog}</tt>
-- <tt>\p{In_Tagbanwa}</tt>
-- <tt>\p{In_Tags}</tt>
-- <tt>\p{In_Tai_Le}</tt>
-- <tt>\p{In_Tai_Tham}</tt>
-- <tt>\p{In_Tai_Viet}</tt>
-- <tt>\p{In_Tai_Xuan_Jing_Symbols}</tt>
-- <tt>\p{In_Takri}</tt>
-- <tt>\p{In_Tamil}</tt>
-- <tt>\p{In_Tamil_Supplement}</tt>
-- <tt>\p{In_Tangsa}</tt>
-- <tt>\p{In_Tangut}</tt>
-- <tt>\p{In_Tangut_Components}</tt>
-- <tt>\p{In_Tangut_Supplement}</tt>
-- <tt>\p{In_Telugu}</tt>
-- <tt>\p{In_Thaana}</tt>
-- <tt>\p{In_Thai}</tt>
-- <tt>\p{In_Tibetan}</tt>
-- <tt>\p{In_Tifinagh}</tt>
-- <tt>\p{In_Tirhuta}</tt>
-- <tt>\p{In_Toto}</tt>
-- <tt>\p{In_Transport_and_Map_Symbols}</tt>
-- <tt>\p{In_Ugaritic}</tt>
-- <tt>\p{In_Unified_Canadian_Aboriginal_Syllabics}</tt>
-- <tt>\p{In_Unified_Canadian_Aboriginal_Syllabics_Extended}</tt>
-- <tt>\p{In_Unified_Canadian_Aboriginal_Syllabics_Extended_A}</tt>
-- <tt>\p{In_Vai}</tt>
-- <tt>\p{In_Variation_Selectors}</tt>
-- <tt>\p{In_Variation_Selectors_Supplement}</tt>
-- <tt>\p{In_Vedic_Extensions}</tt>
-- <tt>\p{In_Vertical_Forms}</tt>
-- <tt>\p{In_Vithkuqi}</tt>
-- <tt>\p{In_Wancho}</tt>
-- <tt>\p{In_Warang_Citi}</tt>
-- <tt>\p{In_Yezidi}</tt>
-- <tt>\p{In_Yi_Radicals}</tt>
-- <tt>\p{In_Yi_Syllables}</tt>
-- <tt>\p{In_Yijing_Hexagram_Symbols}</tt>
-- <tt>\p{In_Zanabazar_Square}</tt>
-- <tt>\p{In_Znamenny_Musical_Notation}</tt>
-
-=== Emoji
-
-- <tt>\p{Emoji}</tt>
-- <tt>\p{Emoji_Component}</tt>, <tt>\p{EComp}</tt>
-- <tt>\p{Emoji_Modifier}</tt>, <tt>\p{EMod}</tt>
-- <tt>\p{Emoji_Modifier_Base}</tt>, <tt>\p{EBase}</tt>
-- <tt>\p{Emoji_Presentation}</tt>, <tt>\p{EPres}</tt>
-- <tt>\p{Extended_Pictographic}</tt>, <tt>\p{ExtPict}</tt>
-
-=== Graphemes
-
-- <tt>\p{Grapheme_Cluster_Break_CR}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Control}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Extend}</tt>
-- <tt>\p{Grapheme_Cluster_Break_L}</tt>
-- <tt>\p{Grapheme_Cluster_Break_LF}</tt>
-- <tt>\p{Grapheme_Cluster_Break_LV}</tt>
-- <tt>\p{Grapheme_Cluster_Break_LVT}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Prepend}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Regional_Indicator}</tt>
-- <tt>\p{Grapheme_Cluster_Break_SpacingMark}</tt>
-- <tt>\p{Grapheme_Cluster_Break_T}</tt>
-- <tt>\p{Grapheme_Cluster_Break_V}</tt>
-- <tt>\p{Grapheme_Cluster_Break_ZWJ}</tt>
-
-=== Derived Ages
-
-- <tt>\p{Age_10_0}</tt>
-- <tt>\p{Age_11_0}</tt>
-- <tt>\p{Age_12_0}</tt>
-- <tt>\p{Age_12_1}</tt>
-- <tt>\p{Age_13_0}</tt>
-- <tt>\p{Age_14_0}</tt>
-- <tt>\p{Age_15_0}</tt>
-- <tt>\p{Age_1_1}</tt>
-- <tt>\p{Age_2_0}</tt>
-- <tt>\p{Age_2_1}</tt>
-- <tt>\p{Age_3_0}</tt>
-- <tt>\p{Age_3_1}</tt>
-- <tt>\p{Age_3_2}</tt>
-- <tt>\p{Age_4_0}</tt>
-- <tt>\p{Age_4_1}</tt>
-- <tt>\p{Age_5_0}</tt>
-- <tt>\p{Age_5_1}</tt>
-- <tt>\p{Age_5_2}</tt>
-- <tt>\p{Age_6_0}</tt>
-- <tt>\p{Age_6_1}</tt>
-- <tt>\p{Age_6_2}</tt>
-- <tt>\p{Age_6_3}</tt>
-- <tt>\p{Age_7_0}</tt>
-- <tt>\p{Age_8_0}</tt>
-- <tt>\p{Age_9_0}</tt>
diff --git a/doc/reline/face.md b/doc/reline/face.md
deleted file mode 100644
index cf3bb69440..0000000000
--- a/doc/reline/face.md
+++ /dev/null
@@ -1,108 +0,0 @@
-# Face
-
-With the `Reline::Face` class, you can modify the text color and text decorations in your terminal emulator.
-This is primarily used to customize the appearance of the method completion dialog in IRB.
-
-## Usage
-
-### ex: Change the background color of the completion dialog cyan to blue
-
-```ruby
-Reline::Face.config(:completion_dialog) do |conf|
- conf.define :default, foreground: :white, background: :blue
- # ^^^^^ `:cyan` by default
- conf.define :enhanced, foreground: :white, background: :magenta
- conf.define :scrollbar, foreground: :white, background: :blue
-end
-```
-
-If you provide the above code to an IRB session in some way, you can apply the configuration.
-It's generally done by writing it in `.irbrc`.
-
-Regarding `.irbrc`, please refer to the following link: [https://docs.ruby-lang.org/en/master/IRB.html](https://docs.ruby-lang.org/en/master/IRB.html)
-
-## Available parameters
-
-`Reline::Face` internally creates SGR (Select Graphic Rendition) code according to the block parameter of `Reline::Face.config` method.
-
-| Key | Value | SGR Code (numeric part following "\e[")|
-|:------------|:------------------|-----:|
-| :foreground | :black | 30 |
-| | :red | 31 |
-| | :green | 32 |
-| | :yellow | 33 |
-| | :blue | 34 |
-| | :magenta | 35 |
-| | :cyan | 36 |
-| | :white | 37 |
-| | :bright_black | 90 |
-| | :gray | 90 |
-| | :bright_red | 91 |
-| | :bright_green | 92 |
-| | :bright_yellow | 93 |
-| | :bright_blue | 94 |
-| | :bright_magenta | 95 |
-| | :bright_cyan | 96 |
-| | :bright_white | 97 |
-| :background | :black | 40 |
-| | :red | 41 |
-| | :green | 42 |
-| | :yellow | 43 |
-| | :blue | 44 |
-| | :magenta | 45 |
-| | :cyan | 46 |
-| | :white | 47 |
-| | :bright_black | 100 |
-| | :gray | 100 |
-| | :bright_red | 101 |
-| | :bright_green | 102 |
-| | :bright_yellow | 103 |
-| | :bright_blue | 104 |
-| | :bright_magenta | 105 |
-| | :bright_cyan | 106 |
-| | :bright_white | 107 |
-| :style | :reset | 0 |
-| | :bold | 1 |
-| | :faint | 2 |
-| | :italicized | 3 |
-| | :underlined | 4 |
-| | :slowly_blinking | 5 |
-| | :blinking | 5 |
-| | :rapidly_blinking | 6 |
-| | :negative | 7 |
-| | :concealed | 8 |
-| | :crossed_out | 9 |
-
-- The value for `:style` can be both a Symbol and an Array
- ```ruby
- # Single symbol
- conf.define :default, style: :bold
- # Array
- conf.define :default, style: [:bold, :negative]
- ```
-- The availability of specific SGR codes depends on your terminal emulator
-- You can specify a hex color code to `:foreground` and `:background` color like `foreground: "#FF1020"`. Its availability also depends on your terminal emulator
-
-## Debugging
-
-You can see the current Face configuration by `Reline::Face.configs` method
-
-Example:
-
-```ruby
-irb(main):001:0> Reline::Face.configs
-=>
-{:default=>
- {:default=>{:style=>:reset, :escape_sequence=>"\e[0m"},
- :enhanced=>{:style=>:reset, :escape_sequence=>"\e[0m"},
- :scrollbar=>{:style=>:reset, :escape_sequence=>"\e[0m"}},
- :completion_dialog=>
- {:default=>{:foreground=>:white, :background=>:cyan, :escape_sequence=>"\e[0m\e[37;46m"},
- :enhanced=>{:foreground=>:white, :background=>:magenta, :escape_sequence=>"\e[0m\e[37;45m"},
- :scrollbar=>{:foreground=>:white, :background=>:cyan, :escape_sequence=>"\e[0m\e[37;46m"}}}
-```
-
-## Backlog
-
-- Support for 256-color terminal emulator. Fallback hex color code such as "#FF1020" to 256 colors
-
diff --git a/doc/rjit/README.md b/doc/rjit/README.md
deleted file mode 100644
index e3795e35b8..0000000000
--- a/doc/rjit/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# RJIT: Ruby JIT
-
-This document has some tips that might be useful when you work on RJIT.
-
-## Project purpose
-
-This project is for experimental purposes.
-For production deployment, consider using YJIT instead.
-
-## Supported platforms
-
-The following platforms are assumed to work. `linux-x86_64` is tested on CI.
-
-* OS: Linux, macOS, BSD
-* Arch: x86\_64
-
-## configure
-### --enable-rjit
-
-On supported platforms, `--enable-rjit` is set by default. You usually don't need to specify this.
-You may still manually pass `--enable-rjit` to try RJIT on unsupported platforms.
-
-### --enable-rjit=dev
-
-It enables `--rjit-dump-disasm` if libcapstone is available.
-
-It also enables `vm_insns_count` and `ratio_in_rjit` in `--rjit-stats`.
-However, it makes the interpreter a little slower.
-
-### --enable-rjit=disasm
-
-It enables `--rjit-dump-disasm` if libcapstone is available.
-
-## make
-### rjit-bindgen
-
-If you see an "RJIT bindgen" GitHub Actions failure, please commit the `git diff` shown on the failed job.
-
-For doing the same thing locally, run `make rjit-bindgen` after installing libclang.
-macOS seems to have libclang by default. On Ubuntu, you can install it with `apt install libclang1`.
-
-## ruby
-### --rjit-stats
-
-This prints RJIT stats at exit. Some stats are available only with `--enable-rjit=dev` on configure.
-
-### --rjit-dump-disasm
-
-This dumps all JIT code. You need to install libcapstone before configure and use `--enable-rjit=dev`
-or `--enable-rjit=disasm` on configure.
-
-* Ubuntu: `sudo apt-get install -y libcapstone-dev`
-* macOS: `brew install capstone`
diff --git a/doc/standard_library.rdoc b/doc/standard_library.rdoc
index 2282d7226b..7c9938c5b0 100644
--- a/doc/standard_library.rdoc
+++ b/doc/standard_library.rdoc
@@ -23,14 +23,6 @@ Socket:: Access underlying OS socket implementations
= Default gems
-* default gems are shipped with Ruby releases and also available as rubygems.
-* default gems are not uninstallable from Ruby installation.
-* default gems can be updated used by rubygems.
- * e.g. `gem update json`
-* default gems can be used with bundler environment like `unbundled_env`.
-* default gems can be used any version on Gemfile.
- * e.g. `gem "json", ">= 2.6"`
-
== Libraries
Abbrev:: Calculates a set of unique abbreviations for a given set of strings
@@ -61,7 +53,6 @@ OpenStruct:: Class to build custom data structures, similar to a Hash
OpenURI:: An easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP
PP:: Provides a PrettyPrinter for Ruby objects
PrettyPrinter:: Implements a pretty printing algorithm for readable structure
-Prism:: A portable, error-tolerant Ruby parser
PStore:: Implements a file based persistence mechanism based on a Hash
Readline:: Wrapper for Readline extencion and Reline
Reline:: GNU Readline and Editline by pure Ruby implementation.
@@ -98,6 +89,8 @@ NKF:: Ruby extension for Network Kanji Filter
OpenSSL:: Provides SSL, TLS and general purpose cryptography for Ruby
Pathname:: Representation of the name of a file or directory on the filesystem
Psych:: A YAML parser and emitter for Ruby
+Racc:: A LALR(1) parser generator written in Ruby.
+Readline:: Provides an interface for GNU Readline and Edit Line (libedit)
StringIO:: Pseudo I/O on String objects
StringScanner:: Provides lexical scanning operations on a String
Syslog:: Ruby interface for the POSIX system logging facility
@@ -106,12 +99,6 @@ Zlib:: Ruby interface for the zlib compression/decompression library
= Bundled gems
-* bundled gems are shipped with Ruby releases and also available as rubygems.
-* bundled gems are same as normal gems like `rails`, `rack`.
- * They are only bundled with Ruby releases.
- * They can be uninstallable from Ruby installation.
- * They are needed to declare in Gemfile when use with bundler.
-
== Libraries
MiniTest:: A test suite with TDD, BDD, mocking and benchmarking
@@ -129,4 +116,3 @@ Prime:: Prime numbers and factorization library
RBS:: RBS is a language to describe the structure of Ruby programs
TypeProf:: A type analysis tool for Ruby code based on abstract interpretation
DEBUGGER__:: Debugging functionality for Ruby
-Racc:: A LALR(1) parser generator written in Ruby.
diff --git a/doc/string/encode.rdoc b/doc/string/encode.rdoc
deleted file mode 100644
index 65872fdfd4..0000000000
--- a/doc/string/encode.rdoc
+++ /dev/null
@@ -1,47 +0,0 @@
-Returns a copy of +self+ transcoded as determined by +dst_encoding+.
-By default, raises an exception if +self+
-contains an invalid byte or a character not defined in +dst_encoding+;
-that behavior may be modified by encoding options; see below.
-
-With no arguments:
-
-- Uses the same encoding if <tt>Encoding.default_internal</tt> is +nil+
- (the default):
-
- Encoding.default_internal # => nil
- s = "Ruby\x99".force_encoding('Windows-1252')
- s.encoding # => #<Encoding:Windows-1252>
- s.bytes # => [82, 117, 98, 121, 153]
- t = s.encode # => "Ruby\x99"
- t.encoding # => #<Encoding:Windows-1252>
- t.bytes # => [82, 117, 98, 121, 226, 132, 162]
-
-- Otherwise, uses the encoding <tt>Encoding.default_internal</tt>:
-
- Encoding.default_internal = 'UTF-8'
- t = s.encode # => "Ruby™"
- t.encoding # => #<Encoding:UTF-8>
-
-With only argument +dst_encoding+ given, uses that encoding:
-
- s = "Ruby\x99".force_encoding('Windows-1252')
- s.encoding # => #<Encoding:Windows-1252>
- t = s.encode('UTF-8') # => "Ruby™"
- t.encoding # => #<Encoding:UTF-8>
-
-With arguments +dst_encoding+ and +src_encoding+ given,
-interprets +self+ using +src_encoding+, encodes the new string using +dst_encoding+:
-
- s = "Ruby\x99"
- t = s.encode('UTF-8', 'Windows-1252') # => "Ruby™"
- t.encoding # => #<Encoding:UTF-8>
-
-Optional keyword arguments +enc_opts+ specify encoding options;
-see {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
-
-Please note that, unless <code>invalid: :replace</code> option is
-given, conversion from an encoding +enc+ to the same encoding +enc+
-(independent of whether +enc+ is given explicitly or implicitly) is a
-no-op, i.e. the string is simply copied without any changes, and no
-exceptions are raised, even if there are invalid bytes.
-
diff --git a/doc/string/length.rdoc b/doc/string/length.rdoc
index 544bca269f..0a7e17f7dc 100644
--- a/doc/string/length.rdoc
+++ b/doc/string/length.rdoc
@@ -10,3 +10,4 @@ Contrast with String#bytesize:
'тест'.bytesize # => 8
'こんにちは'.bytesize # => 15
+String#size is an alias for String#length.
diff --git a/doc/syntax.rdoc b/doc/syntax.rdoc
index 6ca5843512..5895673f36 100644
--- a/doc/syntax.rdoc
+++ b/doc/syntax.rdoc
@@ -37,6 +37,3 @@ Miscellaneous[rdoc-ref:syntax/miscellaneous.rdoc] ::
Comments[rdoc-ref:syntax/comments.rdoc] ::
Line and block code comments
-
-Operators[rdoc-ref:syntax/operators.rdoc] ::
- Operator method behaviors
diff --git a/doc/syntax/assignment.rdoc b/doc/syntax/assignment.rdoc
index e30cb35adf..1321bbf3ac 100644
--- a/doc/syntax/assignment.rdoc
+++ b/doc/syntax/assignment.rdoc
@@ -107,7 +107,7 @@ Rather than printing "true" you receive a NameError, "undefined local variable
or method `a'". Since ruby parses the bare +a+ left of the +if+ first and has
not yet seen an assignment to +a+ it assumes you wish to call a method. Ruby
then sees the assignment to +a+ and will assume you are referencing a local
-variable.
+method.
The confusion comes from the out-of-order execution of the expression. First
the local variable is assigned-to then you attempt to call a nonexistent
@@ -403,10 +403,6 @@ assigning. This is similar to multiple assignment:
p a # prints [1, 2, 3]
- b = *1
-
- p b # prints [1]
-
You can splat anywhere in the right-hand side of the assignment:
a = 1, *[2, 3]
diff --git a/doc/syntax/comments.rdoc b/doc/syntax/comments.rdoc
index 00d19d588a..dbc7816984 100644
--- a/doc/syntax/comments.rdoc
+++ b/doc/syntax/comments.rdoc
@@ -196,7 +196,7 @@ The method Module#const_set is not affected.
In this mode, all values assigned to constants are deeply copied and
made shareable. It is safer mode than +experimental_everything+.
- # shareable_constant_value: experimental_copy
+ # shareable_constant_value: experimental_everything
var = [{foo: []}]
var.frozen? # => false (assignment was made to local variable)
X = var # => calls `Ractor.make_shareable(var, copy: true)`
diff --git a/doc/syntax/control_expressions.rdoc b/doc/syntax/control_expressions.rdoc
index 5350585f15..df3b5ced38 100644
--- a/doc/syntax/control_expressions.rdoc
+++ b/doc/syntax/control_expressions.rdoc
@@ -569,71 +569,3 @@ evaluated on the following iteration:
Here, the flip-flop turns on when +value+ equals 2, but doesn't turn off on the
same iteration. The `off' condition isn't evaluated until the following
iteration and +value+ will never be two again.
-
-== throw/catch
-
-+throw+ and +catch+ are used to implement non-local control flow in Ruby. They
-operate similarly to exceptions, allowing control to pass directly from the
-place where +throw+ is called to the place where the matching +catch+ is
-called. The main difference between +throw+/+catch+ and the use of exceptions
-is that +throw+/+catch+ are designed for expected non-local control flow,
-while exceptions are designed for exceptional control flow situations, such
-as handling unexpected errors.
-
-When using +throw+, you provide 1-2 arguments. The first argument is the
-value for the matching +catch+. The second argument is optional (defaults to
-+nil+), and will be the value that +catch+ returns if there is a matching
-+throw+ inside the +catch+ block. If no matching +throw+ method is called
-inside a +catch+ block, the +catch+ method returns the return value of the
-block passed to it.
-
- def a(n)
- throw :d, :a if n == 0
- b(n)
- end
-
- def b(n)
- throw :d, :b if n == 1
- c(n)
- end
-
- def c(n)
- throw :d if n == 2
- end
-
- 4.times.map do |i|
- catch(:d) do
- a(i)
- :default
- end
- end
- # => [:a, :b, nil, :default]
-
-If the first argument you pass to +throw+ is not handled by a matching
-+catch+, an UncaughtThrowError exception will be raised. This is because
-+throw+/+catch+ should only be used for expected control flow changes, so
-using a value that is not already expected is an error.
-
-+throw+/+catch+ are implemented as Kernel methods (Kernel#throw and
-Kernel#catch), not as keywords. So they are not usable directly if you are
-in a BasicObject context. You can use Kernel.throw and Kernel.catch in
-this case:
-
- BasicObject.new.instance_exec do
- def a
- b
- end
-
- def b
- c
- end
-
- def c
- ::Kernel.throw :d, :e
- end
-
- result = ::Kernel.catch(:d) do
- a
- end
- result # => :e
- end
diff --git a/doc/syntax/literals.rdoc b/doc/syntax/literals.rdoc
index 0c1e4a434b..b641433249 100644
--- a/doc/syntax/literals.rdoc
+++ b/doc/syntax/literals.rdoc
@@ -414,9 +414,9 @@ slash (<tt>'/'</tt>) characters:
re = /foo/ # => /foo/
re.class # => Regexp
-The trailing slash may be followed by one or more modifiers characters
-that set modes for the regexp.
-See {Regexp modes}[rdoc-ref:Regexp@Modes] for details.
+The trailing slash may be followed by one or more _flag_ characters
+that modify the behavior.
+See {Regexp options}[rdoc-ref:Regexp@Options] for details.
Interpolation may be used inside regular expressions along with escaped
characters. Note that a regular expression may require additional escaped
@@ -523,9 +523,9 @@ A few "symmetrical" character pairs may be used as delimiters:
%r(foo) # => /foo/
%r<foo> # => /foo/
-The trailing delimiter may be followed by one or more modifier characters
-that set modes for the regexp.
-See {Regexp modes}[rdoc-ref:Regexp@Modes] for details.
+The trailing delimiter may be followed by one or more _flag_ characters
+that modify the behavior.
+See {Regexp options}[rdoc-ref:Regexp@Options] for details.
=== <tt>%x</tt>: Backtick Literals
diff --git a/doc/syntax/modules_and_classes.rdoc b/doc/syntax/modules_and_classes.rdoc
index 9e05c5c774..024815a5a6 100644
--- a/doc/syntax/modules_and_classes.rdoc
+++ b/doc/syntax/modules_and_classes.rdoc
@@ -40,9 +40,9 @@ functionality:
remove_method :my_method
end
-Reopening modules (or classes) is a very powerful feature of Ruby, but it is
-best to only reopen modules you own. Reopening modules you do not own may lead
-to naming conflicts or difficult to diagnose bugs.
+Reopening classes is a very powerful feature of Ruby, but it is best to only
+reopen classes you own. Reopening classes you do not own may lead to naming
+conflicts or difficult to diagnose bugs.
== Nesting
@@ -259,28 +259,6 @@ includes a minimum of built-in methods. You can use BasicObject to create an
independent inheritance structure. See the BasicObject documentation for
further details.
-Just like modules, classes can also be reopened. You can omit its superclass
-when you reopen a class. Specifying a different superclass than the previous
-definition will raise an error.
-
- class C
- end
-
- class D < C
- end
-
- # OK
- class D < C
- end
-
- # OK
- class D
- end
-
- # TypeError: superclass mismatch for class D
- class D < String
- end
-
== Inheritance
Any method defined on a class is callable from its subclass:
diff --git a/doc/syntax/operators.rdoc b/doc/syntax/operators.rdoc
deleted file mode 100644
index f972309412..0000000000
--- a/doc/syntax/operators.rdoc
+++ /dev/null
@@ -1,75 +0,0 @@
-= Operators
-
-In Ruby, operators such as <code>+</code>, are defined as methods on the class.
-Literals[rdoc-ref:syntax/literals.rdoc] define their methods within the lower
-level, C language. String class, for example.
-
-Ruby objects can define or overload their own implementation for most operators.
-
-Here is an example:
-
- class Foo < String
- def +(str)
- self.concat(str).concat("another string")
- end
- end
-
- foobar = Foo.new("test ")
- puts foobar + "baz "
-
-This prints:
-
- test baz another string
-
-What operators are available is dependent on the implementing class.
-
-== Operator Behavior
-
-How a class behaves to a given operator is specific to that class, since
-operators are method implementations.
-
-When using an operator, it's the expression on the left-hand side of the
-operation that specifies the behavior.
-
- 'a' * 3 #=> "aaa"
- 3 * 'a' # TypeError: String can't be coerced into Integer
-
-== Logical Operators
-
-Logical operators are not methods, and therefor cannot be
-redefined/overloaded. They are tokenized at a lower level.
-
-Short-circuit logical operators (<code>&&</code>, <code>||</code>,
-<code>and</code>, and <code>or</code>) do not always result in a boolean value.
-Similar to blocks, it's the last evaluated expression that defines the result
-of the operation.
-
-=== <code>&&</code>, <code>and</code>
-
-Both <code>&&</code>/<code>and</code> operators provide short-circuiting by executing each
-side of the operator, left to right, and stopping at the first occurence of a
-falsey expression. The expression that defines the result is the last one
-executed, whether it be the final expression, or the first occurence of a falsey
-expression.
-
-Some examples:
-
- true && 9 && "string" #=> "string"
- (1 + 2) && nil && "string" #=> nil
- (a = 1) && (b = false) && (c = "string") #=> false
-
- puts a #=> 1
- puts b #=> false
- puts c #=> nil
-
-In this last example, <code>c</code> was initialized, but not defined.
-
-=== <code>||</code>, <code>or</code>
-
-The means by which <code>||</code>/<code>or</code> short-circuits, is to return the result of
-the first expression that is truthy.
-
-Some examples:
-
- (1 + 2) || true || "string" #=> 3
- false || nil || "string" #=> "string"
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index e49c09a1f8..b7d614770c 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -415,11 +415,6 @@ Additionally, when matching custom classes, the expected class can be specified
end
#=> "matched: 1"
-These core and library classes implement deconstruction:
-
-* MatchData#deconstruct and MatchData#deconstruct_keys;
-* Time#deconstruct_keys, Date#deconstruct_keys, DateTime#deconstruct_keys.
-
== Guard clauses
+if+ can be used to attach an additional condition (guard clause) when the pattern matches. This condition may use bound variables:
@@ -450,6 +445,29 @@ These core and library classes implement deconstruction:
end
#=> "matched"
+== Current feature status
+
+As of Ruby 3.1, find patterns are considered _experimental_: its syntax can change in the future. Every time you use these features in code, a warning will be printed:
+
+ [0] => [*, 0, *]
+ # warning: Find pattern is experimental, and the behavior may change in future versions of Ruby!
+ # warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
+
+To suppress this warning, one may use the Warning::[]= method:
+
+ Warning[:experimental] = false
+ eval('[0] => [*, 0, *]')
+ # ...no warning printed...
+
+Note that pattern-matching warnings are raised at compile time, so this will not suppress the warning:
+
+ Warning[:experimental] = false # At the time this line is evaluated, the parsing happened and warning emitted
+ [0] => [*, 0, *]
+
+So, only subsequently loaded files or `eval`-ed code is affected by switching the flag.
+
+Alternatively, the command line option <code>-W:no-experimental</code> can be used to turn off "experimental" feature warnings.
+
== Appendix A. Pattern syntax
Approximate syntax is:
diff --git a/doc/syntax/refinements.rdoc b/doc/syntax/refinements.rdoc
index 17d5e67c21..c900ab1bdc 100644
--- a/doc/syntax/refinements.rdoc
+++ b/doc/syntax/refinements.rdoc
@@ -279,6 +279,6 @@ Refinements in descendants have higher precedence than those of ancestors.
== Further Reading
-See https://github.com/ruby/ruby/wiki/Refinements-Spec for the
+See https://bugs.ruby-lang.org/projects/ruby-master/wiki/RefinementsSpec for the
current specification for implementing refinements. The specification also
contains more details.
diff --git a/doc/transcode.rdoc b/doc/transcode.rdoc
new file mode 100644
index 0000000000..4f15dff94a
--- /dev/null
+++ b/doc/transcode.rdoc
@@ -0,0 +1,52 @@
+# :markup: ruby
+
+class String
+ # call-seq:
+ # encode(dst_encoding = Encoding.default_internal, **enc_opts) -> string
+ # encode(dst_encoding, src_encoding, **enc_opts) -> string
+ #
+ # Returns a copy of +self+ transcoded as determined by +dst_encoding+.
+ # By default, raises an exception if +self+
+ # contains an invalid byte or a character not defined in +dst_encoding+;
+ # that behavior may be modified by encoding options; see below.
+ #
+ # With no arguments:
+ #
+ # - Uses the same encoding if <tt>Encoding.default_internal</tt> is +nil+
+ # (the default):
+ #
+ # Encoding.default_internal # => nil
+ # s = "Ruby\x99".force_encoding('Windows-1252')
+ # s.encoding # => #<Encoding:Windows-1252>
+ # s.bytes # => [82, 117, 98, 121, 153]
+ # t = s.encode # => "Ruby\x99"
+ # t.encoding # => #<Encoding:Windows-1252>
+ # t.bytes # => [82, 117, 98, 121, 226, 132, 162]
+ #
+ # - Otherwise, uses the encoding <tt>Encoding.default_internal</tt>:
+ #
+ # Encoding.default_internal = 'UTF-8'
+ # t = s.encode # => "Ruby™"
+ # t.encoding # => #<Encoding:UTF-8>
+ #
+ # With only argument +dst_encoding+ given, uses that encoding:
+ #
+ # s = "Ruby\x99".force_encoding('Windows-1252')
+ # s.encoding # => #<Encoding:Windows-1252>
+ # t = s.encode('UTF-8') # => "Ruby™"
+ # t.encoding # => #<Encoding:UTF-8>
+ #
+ # With arguments +dst_encoding+ and +src_encoding+ given,
+ # interprets +self+ using +src_encoding+, encodes the new string using +dst_encoding+:
+ #
+ # s = "Ruby\x99"
+ # t = s.encode('UTF-8', 'Windows-1252') # => "Ruby™"
+ # t.encoding # => #<Encoding:UTF-8>
+ #
+ # Optional keyword arguments +enc_opts+ specify encoding options;
+ # see {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
+ def encode(dst_encoding = Encoding.default_internal, **enc_opts)
+ # Pseudo code
+ Primitive.str_encode(...)
+ end
+end
diff --git a/doc/windows.md b/doc/windows.md
deleted file mode 100644
index 65c6b15c45..0000000000
--- a/doc/windows.md
+++ /dev/null
@@ -1,233 +0,0 @@
-# Windows
-
-Ruby supports a few native build platforms for Windows.
-
-* mswin: Build using Microsoft Visual C++ compiler with vcruntimeXXX.dll
-* mingw-msvcrt: Build using compiler for Mingw with msvcrtXX.dll
-* mingw-ucrt: Build using compiler for Mingw with Windows Universal CRT
-
-## Building Ruby using Mingw with UCRT
-
-The easiest build environment is just a standard [RubyInstaller-Devkit]
-installation and [git-for-windows]. You might like to use [VSCode] as an
-editor.
-
-### Build examples
-
-Ruby core development can be done either in Windows `cmd` like:
-
-```
-ridk enable ucrt64
-
-pacman -S --needed %MINGW_PACKAGE_PREFIX%-openssl %MINGW_PACKAGE_PREFIX%-libyaml %MINGW_PACKAGE_PREFIX%-libffi
-
-cd c:\
-mkdir work
-cd work
-git clone https://github.com/ruby/ruby
-
-cd c:\work\ruby
-sh autogen.sh
-sh configure -C --disable-install-doc
-make
-```
-
-or in MSYS2 `bash` like:
-
-```
-ridk enable ucrt64
-bash
-
-pacman -S --needed $MINGW_PACKAGE_PREFIX-openssl $MINGW_PACKAGE_PREFIX-libyaml $MINGW_PACKAGE_PREFIX-libffi
-
-cd /c/
-mkdir work
-cd work
-git clone https://github.com/ruby/ruby
-cd ruby
-
-./autogen.sh
-./configure -C --disable-install-doc
-make
-```
-
-[RubyInstaller-Devkit]: https://rubyinstaller.org/
-[git-for-windows]: https://gitforwindows.org/
-[VSCode]: https://code.visualstudio.com/
-
-## Building Ruby using Visual C++
-
-### Requirement
-
-1. Windows 7 or later.
-
-2. Visual C++ 12.0 (2013) or later.
-
- **Note** if you want to build x64 version, use native compiler for
- x64.
-
-3. Please set environment variable `INCLUDE`, `LIB`, `PATH`
- to run required commands properly from the command line.
-
- **Note** building ruby requires following commands.
-
- * nmake
- * cl
- * ml
- * lib
- * dumpbin
-
-4. If you want to build from GIT source, following commands are required.
- * patch
- * sed
- * ruby 2.0 or later
-
- You can use [scoop](https://scoop.sh/) to install them like:
-
- ```
- scoop install git ruby sed patch
- ```
-
-5. You need to install required libraries using [vcpkg](https://vcpkg.io/) like:
-
- ```
- vcpkg --triplet x64-windows install openssl libffi libyaml zlib
- ```
-
-6. Enable Command Extension of your command line. It's the default behavior
- of `cmd.exe`. If you want to enable it explicitly, run `cmd.exe` with
- `/E:ON` option.
-
-### How to compile and install
-
-1. Execute `win32\configure.bat` on your build directory.
- You can specify the target platform as an argument.
- For example, run `configure --target=i686-mswin32`
- You can also specify the install directory.
- For example, run `configure --prefix=<install_directory>`
- Default of the install directory is `/usr` .
- The default _PLATFORM_ is `i386-mswin32_`_MSRTVERSION_ on 32-bit
- platforms, or `x64-mswin64_`_MSRTVERSION_ on x64 platforms.
- _MSRTVERSION_ is the 2- or 3-digits version of the Microsoft
- Runtime Library.
-
-2. Change _RUBY_INSTALL_NAME_ and _RUBY_SO_NAME_ in `Makefile`
- if you want to change the name of the executable files.
- And add _RUBYW_INSTALL_NAME_ to change the name of the
- executable without console window if also you want.
-
-3. You need specify vcpkg directory to use `--with-opt-dir`
- option like `configure --with-opt-dir=C:\vcpkg\installed\x64-windows`
-
-4. Run `nmake up` if you are building from GIT source.
-
-5. Run `nmake`
-
-6. Run `nmake check`
-
-7. Run `nmake install`
-
-### Build examples
-
-* Build on the ruby source directory.
-
- ```
- ruby source directory: C:\ruby
- build directory: C:\ruby
- install directory: C:\usr\local
- ```
-
- ```
- C:
- cd \ruby
- win32\configure --prefix=/usr/local
- nmake
- nmake check
- nmake install
- ```
-
-* Build on the relative directory from the ruby source directory.
-
- ```
- ruby source directory: C:\ruby
- build directory: C:\ruby\mswin32
- install directory: C:\usr\local
- ```
-
- ```
- C:
- cd \ruby
- mkdir mswin32
- cd mswin32
- ..\win32\configure --prefix=/usr/local
- nmake
- nmake check
- nmake install
- ```
-
-* Build on the different drive.
-
- ```
- ruby source directory: C:\src\ruby
- build directory: D:\build\ruby
- install directory: C:\usr\local
- ```
-
- ```
- D:
- cd D:\build\ruby
- C:\src\ruby\win32\configure --prefix=/usr/local
- nmake
- nmake check
- nmake install DESTDIR=C:
- ```
-
-* Build x64 version (requires native x64 VC++ compiler)
-
- ```
- ruby source directory: C:\ruby
- build directory: C:\ruby
- install directory: C:\usr\local
- ```
-
- ```
- C:
- cd \ruby
- win32\configure --prefix=/usr/local --target=x64-mswin64
- nmake
- nmake check
- nmake install
- ```
-
-### Bugs
-
-You can **NOT** use a path name that contains any white space characters
-as the ruby source directory, this restriction comes from the behavior
-of `!INCLUDE` directives of `NMAKE`.
-
-You can build ruby in any directory including the source directory,
-except `win32` directory in the source directory.
-This is restriction originating in the path search method of `NMAKE`.
-
-## Icons
-
-Any icon files(`*.ico`) in the build directory, directories specified with
-_icondirs_ make variable and `win32` directory under the ruby
-source directory will be included in DLL or executable files, according
-to their base names.
- $(RUBY_INSTALL_NAME).ico or ruby.ico --> $(RUBY_INSTALL_NAME).exe
- $(RUBYW_INSTALL_NAME).ico or rubyw.ico --> $(RUBYW_INSTALL_NAME).exe
- the others --> $(RUBY_SO_NAME).dll
-
-Although no icons are distributed with the ruby source, you can use
-anything you like. You will be able to find many images by search engines.
-For example, followings are made from [Ruby logo kit]:
-
-* Small [favicon] in the official site
-
-* [vit-ruby.ico] or [icon itself]
-
-[Ruby logo kit]: https://cache.ruby-lang.org/pub/misc/logo/ruby-logo-kit.zip
-[favicon]: https://www.ruby-lang.org/favicon.ico
-[vit-ruby.ico]: http://ruby.morphball.net/vit-ruby-ico_en.html
-[icon itself]: http://ruby.morphball.net/icon/vit-ruby.ico
diff --git a/doc/yjit/yjit.md b/doc/yjit/yjit.md
index 5e3e7e961b..67b2ffa5f0 100644
--- a/doc/yjit/yjit.md
+++ b/doc/yjit/yjit.md
@@ -24,7 +24,6 @@ If you wish to learn more about the approach taken, here are some conference tal
- RubyKaigi 2022 talk: [Building a Lightweight IR and Backend for YJIT](https://www.youtube.com/watch?v=BbLGqTxTRp0)
- RubyKaigi 2021 talk: [YJIT: Building a New JIT Compiler Inside CRuby](https://www.youtube.com/watch?v=PBVLf3yfMs8)
- Blog post: [YJIT: Building a New JIT Compiler Inside CRuby](https://pointersgonewild.com/2021/06/02/yjit-building-a-new-jit-compiler-inside-cruby/)
-- MPLR 2023 paper: [Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach](https://dl.acm.org/doi/10.1145/3617651.3622982)
- VMIL 2021 paper: [YJIT: A Basic Block Versioning JIT Compiler for CRuby](https://dl.acm.org/doi/10.1145/3486606.3486781)
- MoreVMs 2021 talk: [YJIT: Building a New JIT Compiler Inside CRuby](https://www.youtube.com/watch?v=vucLAqv7qpc)
- ECOOP 2016 talk: [Interprocedural Type Specialization of JavaScript Programs Without Type Analysis](https://www.youtube.com/watch?v=sRNBY7Ss97A)
@@ -32,24 +31,24 @@ If you wish to learn more about the approach taken, here are some conference tal
- ECOOP 2015 talk: [Simple and Effective Type Check Removal through Lazy Basic Block Versioning](https://www.youtube.com/watch?v=S-aHBuoiYE0)
- ECOOP 2015 paper: [Simple and Effective Type Check Removal through Lazy Basic Block Versioning](https://arxiv.org/pdf/1411.0352.pdf)
-To cite YJIT in your publications, please cite the MPLR 2023 paper:
+To cite YJIT in your publications, please cite the VMIL 2021 paper:
```
-@inproceedings{yjit_mplr_2023,
-author = {Chevalier-Boisvert, Maxime and Kokubun, Takashi and Gibbs, Noah and Wu, Si Xing (Alan) and Patterson, Aaron and Issroff, Jemma},
-title = {Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach},
-year = {2023},
-isbn = {9798400703805},
+@inproceedings{yjit_vmil2021,
+author = {Chevalier-Boisvert, Maxime and Gibbs, Noah and Boussier, Jean and Wu, Si Xing (Alan) and Patterson, Aaron and Newton, Kevin and Hawthorn, John},
+title = {YJIT: A Basic Block Versioning JIT Compiler for CRuby},
+year = {2021},
+isbn = {9781450391092},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
-url = {https://doi.org/10.1145/3617651.3622982},
-doi = {10.1145/3617651.3622982},
-booktitle = {Proceedings of the 20th ACM SIGPLAN International Conference on Managed Programming Languages and Runtimes},
-pages = {20–33},
-numpages = {14},
-keywords = {dynamically typed, optimization, just-in-time, virtual machine, ruby, compiler, bytecode},
-location = {Cascais, Portugal},
-series = {MPLR 2023}
+url = {https://doi.org/10.1145/3486606.3486781},
+doi = {10.1145/3486606.3486781},
+booktitle = {Proceedings of the 13th ACM SIGPLAN International Workshop on Virtual Machines and Intermediate Languages},
+pages = {25–32},
+numpages = {8},
+keywords = {ruby, dynamically typed, compiler, optimization, just-in-time, bytecode},
+location = {Chicago, IL, USA},
+series = {VMIL 2021}
}
```
@@ -113,7 +112,7 @@ On macOS, you may need to specify where to find some libraries:
```sh
# Install dependencies
-brew install openssl libyaml
+brew install openssl readline libyaml
# Configure in dev (debug) mode for development, build and install
./autogen.sh
@@ -166,25 +165,13 @@ YJIT supports all command-line options supported by upstream CRuby, but also add
- `--yjit`: enable YJIT (disabled by default)
- `--yjit-call-threshold=N`: number of calls after which YJIT begins to compile a function (default 30)
-- `--yjit-cold-threshold=N`: number of global calls after which an ISEQ is considered cold and not
-compiled, lower values mean less code is compiled (default 200000)
-- `--yjit-exec-mem-size=N`: size of the executable memory block to allocate, in MiB (default 64 MiB in Ruby 3.2, 128 MiB in Ruby 3.3+)
+- `--yjit-exec-mem-size=N`: size of the executable memory block to allocate, in MiB (default 64 MiB)
- `--yjit-stats`: print statistics after the execution of a program (incurs a run-time cost)
-- `--yjit-stats=quiet`: gather statistics while running a program but don't print them. Stats are accessible through `RubyVM::YJIT.runtime_stats`. (incurs a run-time cost)
- `--yjit-trace-exits`: produce a Marshal dump of backtraces from specific exits. Automatically enables `--yjit-stats`
-- `--yjit-max-versions=N`: maximum number of versions to generate per basic block (default 4)
-- `--yjit-perf`: Enable frame pointers and profiling with the `perf` tool
Note that there is also an environment variable `RUBY_YJIT_ENABLE` which can be used to enable YJIT.
This can be useful for some deployment scripts where specifying an extra command-line option to Ruby is not practical.
-You can verify that YJIT is enabled by checking that `ruby -v --yjit` includes the string `+YJIT`:
-
-```sh
-ruby -v --yjit
-ruby 3.3.0dev (2023-01-31T15:11:10Z master 2a0bf269c9) +YJIT dev [x86_64-darwin22]
-```
-
### Benchmarking
We have collected a set of benchmarks and implemented a simple benchmarking harness in the [yjit-bench](https://github.com/Shopify/yjit-bench) repository. This benchmarking harness is designed to disable CPU frequency scaling, set process affinity and disable address space randomization so that the variance between benchmarking runs will be as small as possible. Please kindly note that we are at an early stage in this project.
@@ -268,7 +255,7 @@ irb(main):001:0> RubyVM::YJIT.runtime_stats
{:inline_code_size=>340745,
:outlined_code_size=>297664,
:all_stats=>true,
- :yjit_insns_count=>1547816,
+ :exec_instruction=>1547816,
:send_callsite_not_simple=>7267,
:send_kw_splat=>7,
:send_ivar_set_method=>72,
@@ -277,7 +264,7 @@ irb(main):001:0> RubyVM::YJIT.runtime_stats
Some of the counters include:
-* :yjit_insns_count - how many Ruby bytecode instructions have been executed
+* :exec_instruction - how many Ruby bytecode instructions have been executed
* :binding_allocations - number of bindings allocated
* :binding_set - number of variables set via a binding
* :code_gc_count - number of garbage collections of compiled code since process start
@@ -344,12 +331,11 @@ add them to `yjit/cruby.rs` instead.
### Coding & Debugging Protips
-There are multiple test suites:
+There are 3 test suites:
- `make btest` (see `/bootstraptest`)
- `make test-all`
- `make test-spec`
- `make check` runs all of the above
-- `make yjit-smoke-test` runs quick checks to see that YJIT is working correctly
The tests can be run in parallel like this:
@@ -429,30 +415,3 @@ While in your i386 shell, install Cargo and Homebrew, then hack away!
2. Cargo will install in $HOME/.cargo by default, and I don't know a good way to change architectures after install
If you use Fish shell you can [read this link](https://tenderlovemaking.com/2022/01/07/homebrew-rosetta-and-ruby.html) for information on making the dev environment easier.
-
-## Profiling with Linux perf
-
-`--yjit-perf` allows you to profile JIT-ed methods along with other native functions using Linux perf.
-When you run Ruby with `perf record`, perf looks up `/tmp/perf-{pid}.map` to resolve symbols in JIT code,
-and this option lets YJIT write method symbols into that file as well as enabling frame pointers.
-
-Here's an example way to use this option with [Firefox Profiler](https://profiler.firefox.com)
-(See also: [Profiling with Linux perf](https://profiler.firefox.com/docs/#/./guide-perf-profiling)):
-
-```bash
-# Compile the interpreter with frame pointers enabled
-./configure --enable-yjit --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc cflags=-fno-omit-frame-pointer
-make -j && make install
-
-# [Optional] Allow running perf without sudo
-echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
-echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
-
-# Profile Ruby with --yjit-perf
-cd ../yjit-bench
-perf record --call-graph fp -- ruby --yjit-perf -Iharness-perf benchmarks/liquid-render/benchmark.rb
-
-# View results on Firefox Profiler https://profiler.firefox.com.
-# Create /tmp/test.perf as below and upload it using "Load a profile from file".
-perf script --fields +pid > /tmp/test.perf
-```
diff --git a/enc/Makefile.in b/enc/Makefile.in
index dd8ca1b528..9d0c367134 100644
--- a/enc/Makefile.in
+++ b/enc/Makefile.in
@@ -51,7 +51,7 @@ optflags = @optflags@
debugflags = @debugflags@
warnflags = @warnflags@
CCDLFLAGS = @CCDLFLAGS@
-INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(top_srcdir)
+INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(top_srcdir) @incflags@
DEFS = @DEFS@
CPPFLAGS = @CPPFLAGS@ -DONIG_ENC_REGISTER=rb_enc_register
LDFLAGS = @LDFLAGS@
diff --git a/enc/depend b/enc/depend
index 12ddbc223a..973ad93010 100644
--- a/enc/depend
+++ b/enc/depend
@@ -58,8 +58,12 @@ TRANSCLEANOBJS = <%=cleanobjs.map {|clean|
LIBTRANS=enc/libtrans.$(LIBEXT)
UNICODE_HDR_DIR = --missing-unicode-header-dir--
-encs all: <%= MODULE_TYPE == :static ? "lib" : "mod" %>encs
-modencs: enc trans
+encs: all
+% if MODULE_TYPE == :static
+all: libenc libtrans
+% else
+all: enc trans
+%end
libencs: libenc libtrans
enc: $(ENCSOS)
libenc: $(LIBENC)
@@ -230,7 +234,6 @@ enc/ascii.$(OBJEXT): internal/attr/noexcept.h
enc/ascii.$(OBJEXT): internal/attr/noinline.h
enc/ascii.$(OBJEXT): internal/attr/nonnull.h
enc/ascii.$(OBJEXT): internal/attr/noreturn.h
-enc/ascii.$(OBJEXT): internal/attr/packed_struct.h
enc/ascii.$(OBJEXT): internal/attr/pure.h
enc/ascii.$(OBJEXT): internal/attr/restrict.h
enc/ascii.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -299,6 +302,7 @@ enc/ascii.$(OBJEXT): internal/intern/enumerator.h
enc/ascii.$(OBJEXT): internal/intern/error.h
enc/ascii.$(OBJEXT): internal/intern/eval.h
enc/ascii.$(OBJEXT): internal/intern/file.h
+enc/ascii.$(OBJEXT): internal/intern/gc.h
enc/ascii.$(OBJEXT): internal/intern/hash.h
enc/ascii.$(OBJEXT): internal/intern/io.h
enc/ascii.$(OBJEXT): internal/intern/load.h
@@ -329,6 +333,7 @@ enc/ascii.$(OBJEXT): internal/memory.h
enc/ascii.$(OBJEXT): internal/method.h
enc/ascii.$(OBJEXT): internal/module.h
enc/ascii.$(OBJEXT): internal/newobj.h
+enc/ascii.$(OBJEXT): internal/rgengc.h
enc/ascii.$(OBJEXT): internal/scan_args.h
enc/ascii.$(OBJEXT): internal/special_consts.h
enc/ascii.$(OBJEXT): internal/static_assert.h
@@ -400,7 +405,6 @@ enc/big5.$(OBJEXT): internal/attr/noexcept.h
enc/big5.$(OBJEXT): internal/attr/noinline.h
enc/big5.$(OBJEXT): internal/attr/nonnull.h
enc/big5.$(OBJEXT): internal/attr/noreturn.h
-enc/big5.$(OBJEXT): internal/attr/packed_struct.h
enc/big5.$(OBJEXT): internal/attr/pure.h
enc/big5.$(OBJEXT): internal/attr/restrict.h
enc/big5.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -460,6 +464,7 @@ enc/big5.$(OBJEXT): internal/intern/enumerator.h
enc/big5.$(OBJEXT): internal/intern/error.h
enc/big5.$(OBJEXT): internal/intern/eval.h
enc/big5.$(OBJEXT): internal/intern/file.h
+enc/big5.$(OBJEXT): internal/intern/gc.h
enc/big5.$(OBJEXT): internal/intern/hash.h
enc/big5.$(OBJEXT): internal/intern/io.h
enc/big5.$(OBJEXT): internal/intern/load.h
@@ -490,6 +495,7 @@ enc/big5.$(OBJEXT): internal/memory.h
enc/big5.$(OBJEXT): internal/method.h
enc/big5.$(OBJEXT): internal/module.h
enc/big5.$(OBJEXT): internal/newobj.h
+enc/big5.$(OBJEXT): internal/rgengc.h
enc/big5.$(OBJEXT): internal/scan_args.h
enc/big5.$(OBJEXT): internal/special_consts.h
enc/big5.$(OBJEXT): internal/static_assert.h
@@ -562,7 +568,6 @@ enc/cesu_8.$(OBJEXT): internal/attr/noexcept.h
enc/cesu_8.$(OBJEXT): internal/attr/noinline.h
enc/cesu_8.$(OBJEXT): internal/attr/nonnull.h
enc/cesu_8.$(OBJEXT): internal/attr/noreturn.h
-enc/cesu_8.$(OBJEXT): internal/attr/packed_struct.h
enc/cesu_8.$(OBJEXT): internal/attr/pure.h
enc/cesu_8.$(OBJEXT): internal/attr/restrict.h
enc/cesu_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -631,6 +636,7 @@ enc/cesu_8.$(OBJEXT): internal/intern/enumerator.h
enc/cesu_8.$(OBJEXT): internal/intern/error.h
enc/cesu_8.$(OBJEXT): internal/intern/eval.h
enc/cesu_8.$(OBJEXT): internal/intern/file.h
+enc/cesu_8.$(OBJEXT): internal/intern/gc.h
enc/cesu_8.$(OBJEXT): internal/intern/hash.h
enc/cesu_8.$(OBJEXT): internal/intern/io.h
enc/cesu_8.$(OBJEXT): internal/intern/load.h
@@ -661,6 +667,7 @@ enc/cesu_8.$(OBJEXT): internal/memory.h
enc/cesu_8.$(OBJEXT): internal/method.h
enc/cesu_8.$(OBJEXT): internal/module.h
enc/cesu_8.$(OBJEXT): internal/newobj.h
+enc/cesu_8.$(OBJEXT): internal/rgengc.h
enc/cesu_8.$(OBJEXT): internal/scan_args.h
enc/cesu_8.$(OBJEXT): internal/special_consts.h
enc/cesu_8.$(OBJEXT): internal/static_assert.h
@@ -732,7 +739,6 @@ enc/cp949.$(OBJEXT): internal/attr/noexcept.h
enc/cp949.$(OBJEXT): internal/attr/noinline.h
enc/cp949.$(OBJEXT): internal/attr/nonnull.h
enc/cp949.$(OBJEXT): internal/attr/noreturn.h
-enc/cp949.$(OBJEXT): internal/attr/packed_struct.h
enc/cp949.$(OBJEXT): internal/attr/pure.h
enc/cp949.$(OBJEXT): internal/attr/restrict.h
enc/cp949.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -792,6 +798,7 @@ enc/cp949.$(OBJEXT): internal/intern/enumerator.h
enc/cp949.$(OBJEXT): internal/intern/error.h
enc/cp949.$(OBJEXT): internal/intern/eval.h
enc/cp949.$(OBJEXT): internal/intern/file.h
+enc/cp949.$(OBJEXT): internal/intern/gc.h
enc/cp949.$(OBJEXT): internal/intern/hash.h
enc/cp949.$(OBJEXT): internal/intern/io.h
enc/cp949.$(OBJEXT): internal/intern/load.h
@@ -822,6 +829,7 @@ enc/cp949.$(OBJEXT): internal/memory.h
enc/cp949.$(OBJEXT): internal/method.h
enc/cp949.$(OBJEXT): internal/module.h
enc/cp949.$(OBJEXT): internal/newobj.h
+enc/cp949.$(OBJEXT): internal/rgengc.h
enc/cp949.$(OBJEXT): internal/scan_args.h
enc/cp949.$(OBJEXT): internal/special_consts.h
enc/cp949.$(OBJEXT): internal/static_assert.h
@@ -892,7 +900,6 @@ enc/emacs_mule.$(OBJEXT): internal/attr/noexcept.h
enc/emacs_mule.$(OBJEXT): internal/attr/noinline.h
enc/emacs_mule.$(OBJEXT): internal/attr/nonnull.h
enc/emacs_mule.$(OBJEXT): internal/attr/noreturn.h
-enc/emacs_mule.$(OBJEXT): internal/attr/packed_struct.h
enc/emacs_mule.$(OBJEXT): internal/attr/pure.h
enc/emacs_mule.$(OBJEXT): internal/attr/restrict.h
enc/emacs_mule.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -952,6 +959,7 @@ enc/emacs_mule.$(OBJEXT): internal/intern/enumerator.h
enc/emacs_mule.$(OBJEXT): internal/intern/error.h
enc/emacs_mule.$(OBJEXT): internal/intern/eval.h
enc/emacs_mule.$(OBJEXT): internal/intern/file.h
+enc/emacs_mule.$(OBJEXT): internal/intern/gc.h
enc/emacs_mule.$(OBJEXT): internal/intern/hash.h
enc/emacs_mule.$(OBJEXT): internal/intern/io.h
enc/emacs_mule.$(OBJEXT): internal/intern/load.h
@@ -982,6 +990,7 @@ enc/emacs_mule.$(OBJEXT): internal/memory.h
enc/emacs_mule.$(OBJEXT): internal/method.h
enc/emacs_mule.$(OBJEXT): internal/module.h
enc/emacs_mule.$(OBJEXT): internal/newobj.h
+enc/emacs_mule.$(OBJEXT): internal/rgengc.h
enc/emacs_mule.$(OBJEXT): internal/scan_args.h
enc/emacs_mule.$(OBJEXT): internal/special_consts.h
enc/emacs_mule.$(OBJEXT): internal/static_assert.h
@@ -1053,7 +1062,6 @@ enc/encdb.$(OBJEXT): internal/attr/noexcept.h
enc/encdb.$(OBJEXT): internal/attr/noinline.h
enc/encdb.$(OBJEXT): internal/attr/nonnull.h
enc/encdb.$(OBJEXT): internal/attr/noreturn.h
-enc/encdb.$(OBJEXT): internal/attr/packed_struct.h
enc/encdb.$(OBJEXT): internal/attr/pure.h
enc/encdb.$(OBJEXT): internal/attr/restrict.h
enc/encdb.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1122,6 +1130,7 @@ enc/encdb.$(OBJEXT): internal/intern/enumerator.h
enc/encdb.$(OBJEXT): internal/intern/error.h
enc/encdb.$(OBJEXT): internal/intern/eval.h
enc/encdb.$(OBJEXT): internal/intern/file.h
+enc/encdb.$(OBJEXT): internal/intern/gc.h
enc/encdb.$(OBJEXT): internal/intern/hash.h
enc/encdb.$(OBJEXT): internal/intern/io.h
enc/encdb.$(OBJEXT): internal/intern/load.h
@@ -1152,6 +1161,7 @@ enc/encdb.$(OBJEXT): internal/memory.h
enc/encdb.$(OBJEXT): internal/method.h
enc/encdb.$(OBJEXT): internal/module.h
enc/encdb.$(OBJEXT): internal/newobj.h
+enc/encdb.$(OBJEXT): internal/rgengc.h
enc/encdb.$(OBJEXT): internal/scan_args.h
enc/encdb.$(OBJEXT): internal/special_consts.h
enc/encdb.$(OBJEXT): internal/static_assert.h
@@ -1225,7 +1235,6 @@ enc/euc_jp.$(OBJEXT): internal/attr/noexcept.h
enc/euc_jp.$(OBJEXT): internal/attr/noinline.h
enc/euc_jp.$(OBJEXT): internal/attr/nonnull.h
enc/euc_jp.$(OBJEXT): internal/attr/noreturn.h
-enc/euc_jp.$(OBJEXT): internal/attr/packed_struct.h
enc/euc_jp.$(OBJEXT): internal/attr/pure.h
enc/euc_jp.$(OBJEXT): internal/attr/restrict.h
enc/euc_jp.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1285,6 +1294,7 @@ enc/euc_jp.$(OBJEXT): internal/intern/enumerator.h
enc/euc_jp.$(OBJEXT): internal/intern/error.h
enc/euc_jp.$(OBJEXT): internal/intern/eval.h
enc/euc_jp.$(OBJEXT): internal/intern/file.h
+enc/euc_jp.$(OBJEXT): internal/intern/gc.h
enc/euc_jp.$(OBJEXT): internal/intern/hash.h
enc/euc_jp.$(OBJEXT): internal/intern/io.h
enc/euc_jp.$(OBJEXT): internal/intern/load.h
@@ -1315,6 +1325,7 @@ enc/euc_jp.$(OBJEXT): internal/memory.h
enc/euc_jp.$(OBJEXT): internal/method.h
enc/euc_jp.$(OBJEXT): internal/module.h
enc/euc_jp.$(OBJEXT): internal/newobj.h
+enc/euc_jp.$(OBJEXT): internal/rgengc.h
enc/euc_jp.$(OBJEXT): internal/scan_args.h
enc/euc_jp.$(OBJEXT): internal/special_consts.h
enc/euc_jp.$(OBJEXT): internal/static_assert.h
@@ -1385,7 +1396,6 @@ enc/euc_kr.$(OBJEXT): internal/attr/noexcept.h
enc/euc_kr.$(OBJEXT): internal/attr/noinline.h
enc/euc_kr.$(OBJEXT): internal/attr/nonnull.h
enc/euc_kr.$(OBJEXT): internal/attr/noreturn.h
-enc/euc_kr.$(OBJEXT): internal/attr/packed_struct.h
enc/euc_kr.$(OBJEXT): internal/attr/pure.h
enc/euc_kr.$(OBJEXT): internal/attr/restrict.h
enc/euc_kr.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1445,6 +1455,7 @@ enc/euc_kr.$(OBJEXT): internal/intern/enumerator.h
enc/euc_kr.$(OBJEXT): internal/intern/error.h
enc/euc_kr.$(OBJEXT): internal/intern/eval.h
enc/euc_kr.$(OBJEXT): internal/intern/file.h
+enc/euc_kr.$(OBJEXT): internal/intern/gc.h
enc/euc_kr.$(OBJEXT): internal/intern/hash.h
enc/euc_kr.$(OBJEXT): internal/intern/io.h
enc/euc_kr.$(OBJEXT): internal/intern/load.h
@@ -1475,6 +1486,7 @@ enc/euc_kr.$(OBJEXT): internal/memory.h
enc/euc_kr.$(OBJEXT): internal/method.h
enc/euc_kr.$(OBJEXT): internal/module.h
enc/euc_kr.$(OBJEXT): internal/newobj.h
+enc/euc_kr.$(OBJEXT): internal/rgengc.h
enc/euc_kr.$(OBJEXT): internal/scan_args.h
enc/euc_kr.$(OBJEXT): internal/special_consts.h
enc/euc_kr.$(OBJEXT): internal/static_assert.h
@@ -1545,7 +1557,6 @@ enc/euc_tw.$(OBJEXT): internal/attr/noexcept.h
enc/euc_tw.$(OBJEXT): internal/attr/noinline.h
enc/euc_tw.$(OBJEXT): internal/attr/nonnull.h
enc/euc_tw.$(OBJEXT): internal/attr/noreturn.h
-enc/euc_tw.$(OBJEXT): internal/attr/packed_struct.h
enc/euc_tw.$(OBJEXT): internal/attr/pure.h
enc/euc_tw.$(OBJEXT): internal/attr/restrict.h
enc/euc_tw.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1605,6 +1616,7 @@ enc/euc_tw.$(OBJEXT): internal/intern/enumerator.h
enc/euc_tw.$(OBJEXT): internal/intern/error.h
enc/euc_tw.$(OBJEXT): internal/intern/eval.h
enc/euc_tw.$(OBJEXT): internal/intern/file.h
+enc/euc_tw.$(OBJEXT): internal/intern/gc.h
enc/euc_tw.$(OBJEXT): internal/intern/hash.h
enc/euc_tw.$(OBJEXT): internal/intern/io.h
enc/euc_tw.$(OBJEXT): internal/intern/load.h
@@ -1635,6 +1647,7 @@ enc/euc_tw.$(OBJEXT): internal/memory.h
enc/euc_tw.$(OBJEXT): internal/method.h
enc/euc_tw.$(OBJEXT): internal/module.h
enc/euc_tw.$(OBJEXT): internal/newobj.h
+enc/euc_tw.$(OBJEXT): internal/rgengc.h
enc/euc_tw.$(OBJEXT): internal/scan_args.h
enc/euc_tw.$(OBJEXT): internal/special_consts.h
enc/euc_tw.$(OBJEXT): internal/static_assert.h
@@ -1705,7 +1718,6 @@ enc/gb18030.$(OBJEXT): internal/attr/noexcept.h
enc/gb18030.$(OBJEXT): internal/attr/noinline.h
enc/gb18030.$(OBJEXT): internal/attr/nonnull.h
enc/gb18030.$(OBJEXT): internal/attr/noreturn.h
-enc/gb18030.$(OBJEXT): internal/attr/packed_struct.h
enc/gb18030.$(OBJEXT): internal/attr/pure.h
enc/gb18030.$(OBJEXT): internal/attr/restrict.h
enc/gb18030.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1765,6 +1777,7 @@ enc/gb18030.$(OBJEXT): internal/intern/enumerator.h
enc/gb18030.$(OBJEXT): internal/intern/error.h
enc/gb18030.$(OBJEXT): internal/intern/eval.h
enc/gb18030.$(OBJEXT): internal/intern/file.h
+enc/gb18030.$(OBJEXT): internal/intern/gc.h
enc/gb18030.$(OBJEXT): internal/intern/hash.h
enc/gb18030.$(OBJEXT): internal/intern/io.h
enc/gb18030.$(OBJEXT): internal/intern/load.h
@@ -1795,6 +1808,7 @@ enc/gb18030.$(OBJEXT): internal/memory.h
enc/gb18030.$(OBJEXT): internal/method.h
enc/gb18030.$(OBJEXT): internal/module.h
enc/gb18030.$(OBJEXT): internal/newobj.h
+enc/gb18030.$(OBJEXT): internal/rgengc.h
enc/gb18030.$(OBJEXT): internal/scan_args.h
enc/gb18030.$(OBJEXT): internal/special_consts.h
enc/gb18030.$(OBJEXT): internal/static_assert.h
@@ -1865,7 +1879,6 @@ enc/gb2312.$(OBJEXT): internal/attr/noexcept.h
enc/gb2312.$(OBJEXT): internal/attr/noinline.h
enc/gb2312.$(OBJEXT): internal/attr/nonnull.h
enc/gb2312.$(OBJEXT): internal/attr/noreturn.h
-enc/gb2312.$(OBJEXT): internal/attr/packed_struct.h
enc/gb2312.$(OBJEXT): internal/attr/pure.h
enc/gb2312.$(OBJEXT): internal/attr/restrict.h
enc/gb2312.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1925,6 +1938,7 @@ enc/gb2312.$(OBJEXT): internal/intern/enumerator.h
enc/gb2312.$(OBJEXT): internal/intern/error.h
enc/gb2312.$(OBJEXT): internal/intern/eval.h
enc/gb2312.$(OBJEXT): internal/intern/file.h
+enc/gb2312.$(OBJEXT): internal/intern/gc.h
enc/gb2312.$(OBJEXT): internal/intern/hash.h
enc/gb2312.$(OBJEXT): internal/intern/io.h
enc/gb2312.$(OBJEXT): internal/intern/load.h
@@ -1955,6 +1969,7 @@ enc/gb2312.$(OBJEXT): internal/memory.h
enc/gb2312.$(OBJEXT): internal/method.h
enc/gb2312.$(OBJEXT): internal/module.h
enc/gb2312.$(OBJEXT): internal/newobj.h
+enc/gb2312.$(OBJEXT): internal/rgengc.h
enc/gb2312.$(OBJEXT): internal/scan_args.h
enc/gb2312.$(OBJEXT): internal/special_consts.h
enc/gb2312.$(OBJEXT): internal/static_assert.h
@@ -2025,7 +2040,6 @@ enc/gbk.$(OBJEXT): internal/attr/noexcept.h
enc/gbk.$(OBJEXT): internal/attr/noinline.h
enc/gbk.$(OBJEXT): internal/attr/nonnull.h
enc/gbk.$(OBJEXT): internal/attr/noreturn.h
-enc/gbk.$(OBJEXT): internal/attr/packed_struct.h
enc/gbk.$(OBJEXT): internal/attr/pure.h
enc/gbk.$(OBJEXT): internal/attr/restrict.h
enc/gbk.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2085,6 +2099,7 @@ enc/gbk.$(OBJEXT): internal/intern/enumerator.h
enc/gbk.$(OBJEXT): internal/intern/error.h
enc/gbk.$(OBJEXT): internal/intern/eval.h
enc/gbk.$(OBJEXT): internal/intern/file.h
+enc/gbk.$(OBJEXT): internal/intern/gc.h
enc/gbk.$(OBJEXT): internal/intern/hash.h
enc/gbk.$(OBJEXT): internal/intern/io.h
enc/gbk.$(OBJEXT): internal/intern/load.h
@@ -2115,6 +2130,7 @@ enc/gbk.$(OBJEXT): internal/memory.h
enc/gbk.$(OBJEXT): internal/method.h
enc/gbk.$(OBJEXT): internal/module.h
enc/gbk.$(OBJEXT): internal/newobj.h
+enc/gbk.$(OBJEXT): internal/rgengc.h
enc/gbk.$(OBJEXT): internal/scan_args.h
enc/gbk.$(OBJEXT): internal/special_consts.h
enc/gbk.$(OBJEXT): internal/static_assert.h
@@ -2186,7 +2202,6 @@ enc/iso_8859_1.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_1.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_1.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_1.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_1.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_1.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_1.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_1.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2246,6 +2261,7 @@ enc/iso_8859_1.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_1.$(OBJEXT): internal/intern/error.h
enc/iso_8859_1.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_1.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_1.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_1.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_1.$(OBJEXT): internal/intern/io.h
enc/iso_8859_1.$(OBJEXT): internal/intern/load.h
@@ -2276,6 +2292,7 @@ enc/iso_8859_1.$(OBJEXT): internal/memory.h
enc/iso_8859_1.$(OBJEXT): internal/method.h
enc/iso_8859_1.$(OBJEXT): internal/module.h
enc/iso_8859_1.$(OBJEXT): internal/newobj.h
+enc/iso_8859_1.$(OBJEXT): internal/rgengc.h
enc/iso_8859_1.$(OBJEXT): internal/scan_args.h
enc/iso_8859_1.$(OBJEXT): internal/special_consts.h
enc/iso_8859_1.$(OBJEXT): internal/static_assert.h
@@ -2347,7 +2364,6 @@ enc/iso_8859_10.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_10.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_10.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_10.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_10.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_10.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_10.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_10.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2407,6 +2423,7 @@ enc/iso_8859_10.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_10.$(OBJEXT): internal/intern/error.h
enc/iso_8859_10.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_10.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_10.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_10.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_10.$(OBJEXT): internal/intern/io.h
enc/iso_8859_10.$(OBJEXT): internal/intern/load.h
@@ -2437,6 +2454,7 @@ enc/iso_8859_10.$(OBJEXT): internal/memory.h
enc/iso_8859_10.$(OBJEXT): internal/method.h
enc/iso_8859_10.$(OBJEXT): internal/module.h
enc/iso_8859_10.$(OBJEXT): internal/newobj.h
+enc/iso_8859_10.$(OBJEXT): internal/rgengc.h
enc/iso_8859_10.$(OBJEXT): internal/scan_args.h
enc/iso_8859_10.$(OBJEXT): internal/special_consts.h
enc/iso_8859_10.$(OBJEXT): internal/static_assert.h
@@ -2507,7 +2525,6 @@ enc/iso_8859_11.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_11.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_11.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_11.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_11.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_11.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_11.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_11.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2567,6 +2584,7 @@ enc/iso_8859_11.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_11.$(OBJEXT): internal/intern/error.h
enc/iso_8859_11.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_11.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_11.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_11.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_11.$(OBJEXT): internal/intern/io.h
enc/iso_8859_11.$(OBJEXT): internal/intern/load.h
@@ -2597,6 +2615,7 @@ enc/iso_8859_11.$(OBJEXT): internal/memory.h
enc/iso_8859_11.$(OBJEXT): internal/method.h
enc/iso_8859_11.$(OBJEXT): internal/module.h
enc/iso_8859_11.$(OBJEXT): internal/newobj.h
+enc/iso_8859_11.$(OBJEXT): internal/rgengc.h
enc/iso_8859_11.$(OBJEXT): internal/scan_args.h
enc/iso_8859_11.$(OBJEXT): internal/special_consts.h
enc/iso_8859_11.$(OBJEXT): internal/static_assert.h
@@ -2668,7 +2687,6 @@ enc/iso_8859_13.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_13.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_13.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_13.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_13.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_13.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_13.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_13.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2728,6 +2746,7 @@ enc/iso_8859_13.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_13.$(OBJEXT): internal/intern/error.h
enc/iso_8859_13.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_13.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_13.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_13.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_13.$(OBJEXT): internal/intern/io.h
enc/iso_8859_13.$(OBJEXT): internal/intern/load.h
@@ -2758,6 +2777,7 @@ enc/iso_8859_13.$(OBJEXT): internal/memory.h
enc/iso_8859_13.$(OBJEXT): internal/method.h
enc/iso_8859_13.$(OBJEXT): internal/module.h
enc/iso_8859_13.$(OBJEXT): internal/newobj.h
+enc/iso_8859_13.$(OBJEXT): internal/rgengc.h
enc/iso_8859_13.$(OBJEXT): internal/scan_args.h
enc/iso_8859_13.$(OBJEXT): internal/special_consts.h
enc/iso_8859_13.$(OBJEXT): internal/static_assert.h
@@ -2829,7 +2849,6 @@ enc/iso_8859_14.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_14.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_14.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_14.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_14.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_14.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_14.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_14.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2889,6 +2908,7 @@ enc/iso_8859_14.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_14.$(OBJEXT): internal/intern/error.h
enc/iso_8859_14.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_14.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_14.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_14.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_14.$(OBJEXT): internal/intern/io.h
enc/iso_8859_14.$(OBJEXT): internal/intern/load.h
@@ -2919,6 +2939,7 @@ enc/iso_8859_14.$(OBJEXT): internal/memory.h
enc/iso_8859_14.$(OBJEXT): internal/method.h
enc/iso_8859_14.$(OBJEXT): internal/module.h
enc/iso_8859_14.$(OBJEXT): internal/newobj.h
+enc/iso_8859_14.$(OBJEXT): internal/rgengc.h
enc/iso_8859_14.$(OBJEXT): internal/scan_args.h
enc/iso_8859_14.$(OBJEXT): internal/special_consts.h
enc/iso_8859_14.$(OBJEXT): internal/static_assert.h
@@ -2990,7 +3011,6 @@ enc/iso_8859_15.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_15.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_15.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_15.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_15.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_15.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_15.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_15.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3050,6 +3070,7 @@ enc/iso_8859_15.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_15.$(OBJEXT): internal/intern/error.h
enc/iso_8859_15.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_15.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_15.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_15.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_15.$(OBJEXT): internal/intern/io.h
enc/iso_8859_15.$(OBJEXT): internal/intern/load.h
@@ -3080,6 +3101,7 @@ enc/iso_8859_15.$(OBJEXT): internal/memory.h
enc/iso_8859_15.$(OBJEXT): internal/method.h
enc/iso_8859_15.$(OBJEXT): internal/module.h
enc/iso_8859_15.$(OBJEXT): internal/newobj.h
+enc/iso_8859_15.$(OBJEXT): internal/rgengc.h
enc/iso_8859_15.$(OBJEXT): internal/scan_args.h
enc/iso_8859_15.$(OBJEXT): internal/special_consts.h
enc/iso_8859_15.$(OBJEXT): internal/static_assert.h
@@ -3151,7 +3173,6 @@ enc/iso_8859_16.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_16.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_16.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_16.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_16.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_16.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_16.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_16.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3211,6 +3232,7 @@ enc/iso_8859_16.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_16.$(OBJEXT): internal/intern/error.h
enc/iso_8859_16.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_16.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_16.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_16.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_16.$(OBJEXT): internal/intern/io.h
enc/iso_8859_16.$(OBJEXT): internal/intern/load.h
@@ -3241,6 +3263,7 @@ enc/iso_8859_16.$(OBJEXT): internal/memory.h
enc/iso_8859_16.$(OBJEXT): internal/method.h
enc/iso_8859_16.$(OBJEXT): internal/module.h
enc/iso_8859_16.$(OBJEXT): internal/newobj.h
+enc/iso_8859_16.$(OBJEXT): internal/rgengc.h
enc/iso_8859_16.$(OBJEXT): internal/scan_args.h
enc/iso_8859_16.$(OBJEXT): internal/special_consts.h
enc/iso_8859_16.$(OBJEXT): internal/static_assert.h
@@ -3312,7 +3335,6 @@ enc/iso_8859_2.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_2.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_2.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_2.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_2.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_2.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_2.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_2.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3372,6 +3394,7 @@ enc/iso_8859_2.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_2.$(OBJEXT): internal/intern/error.h
enc/iso_8859_2.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_2.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_2.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_2.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_2.$(OBJEXT): internal/intern/io.h
enc/iso_8859_2.$(OBJEXT): internal/intern/load.h
@@ -3402,6 +3425,7 @@ enc/iso_8859_2.$(OBJEXT): internal/memory.h
enc/iso_8859_2.$(OBJEXT): internal/method.h
enc/iso_8859_2.$(OBJEXT): internal/module.h
enc/iso_8859_2.$(OBJEXT): internal/newobj.h
+enc/iso_8859_2.$(OBJEXT): internal/rgengc.h
enc/iso_8859_2.$(OBJEXT): internal/scan_args.h
enc/iso_8859_2.$(OBJEXT): internal/special_consts.h
enc/iso_8859_2.$(OBJEXT): internal/static_assert.h
@@ -3473,7 +3497,6 @@ enc/iso_8859_3.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_3.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_3.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_3.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_3.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_3.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_3.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_3.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3533,6 +3556,7 @@ enc/iso_8859_3.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_3.$(OBJEXT): internal/intern/error.h
enc/iso_8859_3.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_3.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_3.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_3.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_3.$(OBJEXT): internal/intern/io.h
enc/iso_8859_3.$(OBJEXT): internal/intern/load.h
@@ -3563,6 +3587,7 @@ enc/iso_8859_3.$(OBJEXT): internal/memory.h
enc/iso_8859_3.$(OBJEXT): internal/method.h
enc/iso_8859_3.$(OBJEXT): internal/module.h
enc/iso_8859_3.$(OBJEXT): internal/newobj.h
+enc/iso_8859_3.$(OBJEXT): internal/rgengc.h
enc/iso_8859_3.$(OBJEXT): internal/scan_args.h
enc/iso_8859_3.$(OBJEXT): internal/special_consts.h
enc/iso_8859_3.$(OBJEXT): internal/static_assert.h
@@ -3634,7 +3659,6 @@ enc/iso_8859_4.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_4.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_4.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_4.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_4.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_4.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_4.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_4.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3694,6 +3718,7 @@ enc/iso_8859_4.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_4.$(OBJEXT): internal/intern/error.h
enc/iso_8859_4.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_4.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_4.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_4.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_4.$(OBJEXT): internal/intern/io.h
enc/iso_8859_4.$(OBJEXT): internal/intern/load.h
@@ -3724,6 +3749,7 @@ enc/iso_8859_4.$(OBJEXT): internal/memory.h
enc/iso_8859_4.$(OBJEXT): internal/method.h
enc/iso_8859_4.$(OBJEXT): internal/module.h
enc/iso_8859_4.$(OBJEXT): internal/newobj.h
+enc/iso_8859_4.$(OBJEXT): internal/rgengc.h
enc/iso_8859_4.$(OBJEXT): internal/scan_args.h
enc/iso_8859_4.$(OBJEXT): internal/special_consts.h
enc/iso_8859_4.$(OBJEXT): internal/static_assert.h
@@ -3794,7 +3820,6 @@ enc/iso_8859_5.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_5.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_5.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_5.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_5.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_5.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_5.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_5.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3854,6 +3879,7 @@ enc/iso_8859_5.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_5.$(OBJEXT): internal/intern/error.h
enc/iso_8859_5.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_5.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_5.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_5.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_5.$(OBJEXT): internal/intern/io.h
enc/iso_8859_5.$(OBJEXT): internal/intern/load.h
@@ -3884,6 +3910,7 @@ enc/iso_8859_5.$(OBJEXT): internal/memory.h
enc/iso_8859_5.$(OBJEXT): internal/method.h
enc/iso_8859_5.$(OBJEXT): internal/module.h
enc/iso_8859_5.$(OBJEXT): internal/newobj.h
+enc/iso_8859_5.$(OBJEXT): internal/rgengc.h
enc/iso_8859_5.$(OBJEXT): internal/scan_args.h
enc/iso_8859_5.$(OBJEXT): internal/special_consts.h
enc/iso_8859_5.$(OBJEXT): internal/static_assert.h
@@ -3954,7 +3981,6 @@ enc/iso_8859_6.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_6.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_6.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_6.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_6.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_6.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_6.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_6.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4014,6 +4040,7 @@ enc/iso_8859_6.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_6.$(OBJEXT): internal/intern/error.h
enc/iso_8859_6.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_6.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_6.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_6.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_6.$(OBJEXT): internal/intern/io.h
enc/iso_8859_6.$(OBJEXT): internal/intern/load.h
@@ -4044,6 +4071,7 @@ enc/iso_8859_6.$(OBJEXT): internal/memory.h
enc/iso_8859_6.$(OBJEXT): internal/method.h
enc/iso_8859_6.$(OBJEXT): internal/module.h
enc/iso_8859_6.$(OBJEXT): internal/newobj.h
+enc/iso_8859_6.$(OBJEXT): internal/rgengc.h
enc/iso_8859_6.$(OBJEXT): internal/scan_args.h
enc/iso_8859_6.$(OBJEXT): internal/special_consts.h
enc/iso_8859_6.$(OBJEXT): internal/static_assert.h
@@ -4114,7 +4142,6 @@ enc/iso_8859_7.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_7.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_7.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_7.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_7.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_7.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_7.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_7.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4174,6 +4201,7 @@ enc/iso_8859_7.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_7.$(OBJEXT): internal/intern/error.h
enc/iso_8859_7.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_7.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_7.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_7.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_7.$(OBJEXT): internal/intern/io.h
enc/iso_8859_7.$(OBJEXT): internal/intern/load.h
@@ -4204,6 +4232,7 @@ enc/iso_8859_7.$(OBJEXT): internal/memory.h
enc/iso_8859_7.$(OBJEXT): internal/method.h
enc/iso_8859_7.$(OBJEXT): internal/module.h
enc/iso_8859_7.$(OBJEXT): internal/newobj.h
+enc/iso_8859_7.$(OBJEXT): internal/rgengc.h
enc/iso_8859_7.$(OBJEXT): internal/scan_args.h
enc/iso_8859_7.$(OBJEXT): internal/special_consts.h
enc/iso_8859_7.$(OBJEXT): internal/static_assert.h
@@ -4274,7 +4303,6 @@ enc/iso_8859_8.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_8.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_8.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_8.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_8.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_8.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_8.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4334,6 +4362,7 @@ enc/iso_8859_8.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_8.$(OBJEXT): internal/intern/error.h
enc/iso_8859_8.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_8.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_8.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_8.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_8.$(OBJEXT): internal/intern/io.h
enc/iso_8859_8.$(OBJEXT): internal/intern/load.h
@@ -4364,6 +4393,7 @@ enc/iso_8859_8.$(OBJEXT): internal/memory.h
enc/iso_8859_8.$(OBJEXT): internal/method.h
enc/iso_8859_8.$(OBJEXT): internal/module.h
enc/iso_8859_8.$(OBJEXT): internal/newobj.h
+enc/iso_8859_8.$(OBJEXT): internal/rgengc.h
enc/iso_8859_8.$(OBJEXT): internal/scan_args.h
enc/iso_8859_8.$(OBJEXT): internal/special_consts.h
enc/iso_8859_8.$(OBJEXT): internal/static_assert.h
@@ -4435,7 +4465,6 @@ enc/iso_8859_9.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_9.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_9.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_9.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_9.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_9.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_9.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_9.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4495,6 +4524,7 @@ enc/iso_8859_9.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_9.$(OBJEXT): internal/intern/error.h
enc/iso_8859_9.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_9.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_9.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_9.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_9.$(OBJEXT): internal/intern/io.h
enc/iso_8859_9.$(OBJEXT): internal/intern/load.h
@@ -4525,6 +4555,7 @@ enc/iso_8859_9.$(OBJEXT): internal/memory.h
enc/iso_8859_9.$(OBJEXT): internal/method.h
enc/iso_8859_9.$(OBJEXT): internal/module.h
enc/iso_8859_9.$(OBJEXT): internal/newobj.h
+enc/iso_8859_9.$(OBJEXT): internal/rgengc.h
enc/iso_8859_9.$(OBJEXT): internal/scan_args.h
enc/iso_8859_9.$(OBJEXT): internal/special_consts.h
enc/iso_8859_9.$(OBJEXT): internal/static_assert.h
@@ -4595,7 +4626,6 @@ enc/koi8_r.$(OBJEXT): internal/attr/noexcept.h
enc/koi8_r.$(OBJEXT): internal/attr/noinline.h
enc/koi8_r.$(OBJEXT): internal/attr/nonnull.h
enc/koi8_r.$(OBJEXT): internal/attr/noreturn.h
-enc/koi8_r.$(OBJEXT): internal/attr/packed_struct.h
enc/koi8_r.$(OBJEXT): internal/attr/pure.h
enc/koi8_r.$(OBJEXT): internal/attr/restrict.h
enc/koi8_r.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4655,6 +4685,7 @@ enc/koi8_r.$(OBJEXT): internal/intern/enumerator.h
enc/koi8_r.$(OBJEXT): internal/intern/error.h
enc/koi8_r.$(OBJEXT): internal/intern/eval.h
enc/koi8_r.$(OBJEXT): internal/intern/file.h
+enc/koi8_r.$(OBJEXT): internal/intern/gc.h
enc/koi8_r.$(OBJEXT): internal/intern/hash.h
enc/koi8_r.$(OBJEXT): internal/intern/io.h
enc/koi8_r.$(OBJEXT): internal/intern/load.h
@@ -4685,6 +4716,7 @@ enc/koi8_r.$(OBJEXT): internal/memory.h
enc/koi8_r.$(OBJEXT): internal/method.h
enc/koi8_r.$(OBJEXT): internal/module.h
enc/koi8_r.$(OBJEXT): internal/newobj.h
+enc/koi8_r.$(OBJEXT): internal/rgengc.h
enc/koi8_r.$(OBJEXT): internal/scan_args.h
enc/koi8_r.$(OBJEXT): internal/special_consts.h
enc/koi8_r.$(OBJEXT): internal/static_assert.h
@@ -4755,7 +4787,6 @@ enc/koi8_u.$(OBJEXT): internal/attr/noexcept.h
enc/koi8_u.$(OBJEXT): internal/attr/noinline.h
enc/koi8_u.$(OBJEXT): internal/attr/nonnull.h
enc/koi8_u.$(OBJEXT): internal/attr/noreturn.h
-enc/koi8_u.$(OBJEXT): internal/attr/packed_struct.h
enc/koi8_u.$(OBJEXT): internal/attr/pure.h
enc/koi8_u.$(OBJEXT): internal/attr/restrict.h
enc/koi8_u.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4815,6 +4846,7 @@ enc/koi8_u.$(OBJEXT): internal/intern/enumerator.h
enc/koi8_u.$(OBJEXT): internal/intern/error.h
enc/koi8_u.$(OBJEXT): internal/intern/eval.h
enc/koi8_u.$(OBJEXT): internal/intern/file.h
+enc/koi8_u.$(OBJEXT): internal/intern/gc.h
enc/koi8_u.$(OBJEXT): internal/intern/hash.h
enc/koi8_u.$(OBJEXT): internal/intern/io.h
enc/koi8_u.$(OBJEXT): internal/intern/load.h
@@ -4845,6 +4877,7 @@ enc/koi8_u.$(OBJEXT): internal/memory.h
enc/koi8_u.$(OBJEXT): internal/method.h
enc/koi8_u.$(OBJEXT): internal/module.h
enc/koi8_u.$(OBJEXT): internal/newobj.h
+enc/koi8_u.$(OBJEXT): internal/rgengc.h
enc/koi8_u.$(OBJEXT): internal/scan_args.h
enc/koi8_u.$(OBJEXT): internal/special_consts.h
enc/koi8_u.$(OBJEXT): internal/static_assert.h
@@ -4918,7 +4951,6 @@ enc/shift_jis.$(OBJEXT): internal/attr/noexcept.h
enc/shift_jis.$(OBJEXT): internal/attr/noinline.h
enc/shift_jis.$(OBJEXT): internal/attr/nonnull.h
enc/shift_jis.$(OBJEXT): internal/attr/noreturn.h
-enc/shift_jis.$(OBJEXT): internal/attr/packed_struct.h
enc/shift_jis.$(OBJEXT): internal/attr/pure.h
enc/shift_jis.$(OBJEXT): internal/attr/restrict.h
enc/shift_jis.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4978,6 +5010,7 @@ enc/shift_jis.$(OBJEXT): internal/intern/enumerator.h
enc/shift_jis.$(OBJEXT): internal/intern/error.h
enc/shift_jis.$(OBJEXT): internal/intern/eval.h
enc/shift_jis.$(OBJEXT): internal/intern/file.h
+enc/shift_jis.$(OBJEXT): internal/intern/gc.h
enc/shift_jis.$(OBJEXT): internal/intern/hash.h
enc/shift_jis.$(OBJEXT): internal/intern/io.h
enc/shift_jis.$(OBJEXT): internal/intern/load.h
@@ -5008,6 +5041,7 @@ enc/shift_jis.$(OBJEXT): internal/memory.h
enc/shift_jis.$(OBJEXT): internal/method.h
enc/shift_jis.$(OBJEXT): internal/module.h
enc/shift_jis.$(OBJEXT): internal/newobj.h
+enc/shift_jis.$(OBJEXT): internal/rgengc.h
enc/shift_jis.$(OBJEXT): internal/scan_args.h
enc/shift_jis.$(OBJEXT): internal/special_consts.h
enc/shift_jis.$(OBJEXT): internal/static_assert.h
@@ -5077,7 +5111,6 @@ enc/trans/big5.$(OBJEXT): internal/attr/noexcept.h
enc/trans/big5.$(OBJEXT): internal/attr/noinline.h
enc/trans/big5.$(OBJEXT): internal/attr/nonnull.h
enc/trans/big5.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/big5.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/big5.$(OBJEXT): internal/attr/pure.h
enc/trans/big5.$(OBJEXT): internal/attr/restrict.h
enc/trans/big5.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5137,6 +5170,7 @@ enc/trans/big5.$(OBJEXT): internal/intern/enumerator.h
enc/trans/big5.$(OBJEXT): internal/intern/error.h
enc/trans/big5.$(OBJEXT): internal/intern/eval.h
enc/trans/big5.$(OBJEXT): internal/intern/file.h
+enc/trans/big5.$(OBJEXT): internal/intern/gc.h
enc/trans/big5.$(OBJEXT): internal/intern/hash.h
enc/trans/big5.$(OBJEXT): internal/intern/io.h
enc/trans/big5.$(OBJEXT): internal/intern/load.h
@@ -5167,6 +5201,7 @@ enc/trans/big5.$(OBJEXT): internal/memory.h
enc/trans/big5.$(OBJEXT): internal/method.h
enc/trans/big5.$(OBJEXT): internal/module.h
enc/trans/big5.$(OBJEXT): internal/newobj.h
+enc/trans/big5.$(OBJEXT): internal/rgengc.h
enc/trans/big5.$(OBJEXT): internal/scan_args.h
enc/trans/big5.$(OBJEXT): internal/special_consts.h
enc/trans/big5.$(OBJEXT): internal/static_assert.h
@@ -5235,7 +5270,6 @@ enc/trans/cesu_8.$(OBJEXT): internal/attr/noexcept.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/noinline.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/nonnull.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/cesu_8.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/pure.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/restrict.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5295,6 +5329,7 @@ enc/trans/cesu_8.$(OBJEXT): internal/intern/enumerator.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/error.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/eval.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/file.h
+enc/trans/cesu_8.$(OBJEXT): internal/intern/gc.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/hash.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/io.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/load.h
@@ -5325,6 +5360,7 @@ enc/trans/cesu_8.$(OBJEXT): internal/memory.h
enc/trans/cesu_8.$(OBJEXT): internal/method.h
enc/trans/cesu_8.$(OBJEXT): internal/module.h
enc/trans/cesu_8.$(OBJEXT): internal/newobj.h
+enc/trans/cesu_8.$(OBJEXT): internal/rgengc.h
enc/trans/cesu_8.$(OBJEXT): internal/scan_args.h
enc/trans/cesu_8.$(OBJEXT): internal/special_consts.h
enc/trans/cesu_8.$(OBJEXT): internal/static_assert.h
@@ -5393,7 +5429,6 @@ enc/trans/chinese.$(OBJEXT): internal/attr/noexcept.h
enc/trans/chinese.$(OBJEXT): internal/attr/noinline.h
enc/trans/chinese.$(OBJEXT): internal/attr/nonnull.h
enc/trans/chinese.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/chinese.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/chinese.$(OBJEXT): internal/attr/pure.h
enc/trans/chinese.$(OBJEXT): internal/attr/restrict.h
enc/trans/chinese.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5453,6 +5488,7 @@ enc/trans/chinese.$(OBJEXT): internal/intern/enumerator.h
enc/trans/chinese.$(OBJEXT): internal/intern/error.h
enc/trans/chinese.$(OBJEXT): internal/intern/eval.h
enc/trans/chinese.$(OBJEXT): internal/intern/file.h
+enc/trans/chinese.$(OBJEXT): internal/intern/gc.h
enc/trans/chinese.$(OBJEXT): internal/intern/hash.h
enc/trans/chinese.$(OBJEXT): internal/intern/io.h
enc/trans/chinese.$(OBJEXT): internal/intern/load.h
@@ -5483,6 +5519,7 @@ enc/trans/chinese.$(OBJEXT): internal/memory.h
enc/trans/chinese.$(OBJEXT): internal/method.h
enc/trans/chinese.$(OBJEXT): internal/module.h
enc/trans/chinese.$(OBJEXT): internal/newobj.h
+enc/trans/chinese.$(OBJEXT): internal/rgengc.h
enc/trans/chinese.$(OBJEXT): internal/scan_args.h
enc/trans/chinese.$(OBJEXT): internal/special_consts.h
enc/trans/chinese.$(OBJEXT): internal/static_assert.h
@@ -5551,7 +5588,6 @@ enc/trans/ebcdic.$(OBJEXT): internal/attr/noexcept.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/noinline.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/nonnull.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/ebcdic.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/pure.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/restrict.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5611,6 +5647,7 @@ enc/trans/ebcdic.$(OBJEXT): internal/intern/enumerator.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/error.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/eval.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/file.h
+enc/trans/ebcdic.$(OBJEXT): internal/intern/gc.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/hash.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/io.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/load.h
@@ -5641,6 +5678,7 @@ enc/trans/ebcdic.$(OBJEXT): internal/memory.h
enc/trans/ebcdic.$(OBJEXT): internal/method.h
enc/trans/ebcdic.$(OBJEXT): internal/module.h
enc/trans/ebcdic.$(OBJEXT): internal/newobj.h
+enc/trans/ebcdic.$(OBJEXT): internal/rgengc.h
enc/trans/ebcdic.$(OBJEXT): internal/scan_args.h
enc/trans/ebcdic.$(OBJEXT): internal/special_consts.h
enc/trans/ebcdic.$(OBJEXT): internal/static_assert.h
@@ -5709,7 +5747,6 @@ enc/trans/emoji.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5769,6 +5806,7 @@ enc/trans/emoji.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji.$(OBJEXT): internal/intern/error.h
enc/trans/emoji.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji.$(OBJEXT): internal/intern/io.h
enc/trans/emoji.$(OBJEXT): internal/intern/load.h
@@ -5799,6 +5837,7 @@ enc/trans/emoji.$(OBJEXT): internal/memory.h
enc/trans/emoji.$(OBJEXT): internal/method.h
enc/trans/emoji.$(OBJEXT): internal/module.h
enc/trans/emoji.$(OBJEXT): internal/newobj.h
+enc/trans/emoji.$(OBJEXT): internal/rgengc.h
enc/trans/emoji.$(OBJEXT): internal/scan_args.h
enc/trans/emoji.$(OBJEXT): internal/special_consts.h
enc/trans/emoji.$(OBJEXT): internal/static_assert.h
@@ -5867,7 +5906,6 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5927,6 +5965,7 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/load.h
@@ -5957,6 +5996,7 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/memory.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/method.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/module.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/static_assert.h
@@ -6025,7 +6065,6 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6085,6 +6124,7 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/load.h
@@ -6115,6 +6155,7 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/memory.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/method.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/module.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/static_assert.h
@@ -6183,7 +6224,6 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6243,6 +6283,7 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/load.h
@@ -6273,6 +6314,7 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/memory.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/method.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/module.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/static_assert.h
@@ -6341,7 +6383,6 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6401,6 +6442,7 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/load.h
@@ -6431,6 +6473,7 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/memory.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/method.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/module.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/static_assert.h
@@ -6499,7 +6542,6 @@ enc/trans/escape.$(OBJEXT): internal/attr/noexcept.h
enc/trans/escape.$(OBJEXT): internal/attr/noinline.h
enc/trans/escape.$(OBJEXT): internal/attr/nonnull.h
enc/trans/escape.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/escape.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/escape.$(OBJEXT): internal/attr/pure.h
enc/trans/escape.$(OBJEXT): internal/attr/restrict.h
enc/trans/escape.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6559,6 +6601,7 @@ enc/trans/escape.$(OBJEXT): internal/intern/enumerator.h
enc/trans/escape.$(OBJEXT): internal/intern/error.h
enc/trans/escape.$(OBJEXT): internal/intern/eval.h
enc/trans/escape.$(OBJEXT): internal/intern/file.h
+enc/trans/escape.$(OBJEXT): internal/intern/gc.h
enc/trans/escape.$(OBJEXT): internal/intern/hash.h
enc/trans/escape.$(OBJEXT): internal/intern/io.h
enc/trans/escape.$(OBJEXT): internal/intern/load.h
@@ -6589,6 +6632,7 @@ enc/trans/escape.$(OBJEXT): internal/memory.h
enc/trans/escape.$(OBJEXT): internal/method.h
enc/trans/escape.$(OBJEXT): internal/module.h
enc/trans/escape.$(OBJEXT): internal/newobj.h
+enc/trans/escape.$(OBJEXT): internal/rgengc.h
enc/trans/escape.$(OBJEXT): internal/scan_args.h
enc/trans/escape.$(OBJEXT): internal/special_consts.h
enc/trans/escape.$(OBJEXT): internal/static_assert.h
@@ -6657,7 +6701,6 @@ enc/trans/gb18030.$(OBJEXT): internal/attr/noexcept.h
enc/trans/gb18030.$(OBJEXT): internal/attr/noinline.h
enc/trans/gb18030.$(OBJEXT): internal/attr/nonnull.h
enc/trans/gb18030.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/gb18030.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/gb18030.$(OBJEXT): internal/attr/pure.h
enc/trans/gb18030.$(OBJEXT): internal/attr/restrict.h
enc/trans/gb18030.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6717,6 +6760,7 @@ enc/trans/gb18030.$(OBJEXT): internal/intern/enumerator.h
enc/trans/gb18030.$(OBJEXT): internal/intern/error.h
enc/trans/gb18030.$(OBJEXT): internal/intern/eval.h
enc/trans/gb18030.$(OBJEXT): internal/intern/file.h
+enc/trans/gb18030.$(OBJEXT): internal/intern/gc.h
enc/trans/gb18030.$(OBJEXT): internal/intern/hash.h
enc/trans/gb18030.$(OBJEXT): internal/intern/io.h
enc/trans/gb18030.$(OBJEXT): internal/intern/load.h
@@ -6747,6 +6791,7 @@ enc/trans/gb18030.$(OBJEXT): internal/memory.h
enc/trans/gb18030.$(OBJEXT): internal/method.h
enc/trans/gb18030.$(OBJEXT): internal/module.h
enc/trans/gb18030.$(OBJEXT): internal/newobj.h
+enc/trans/gb18030.$(OBJEXT): internal/rgengc.h
enc/trans/gb18030.$(OBJEXT): internal/scan_args.h
enc/trans/gb18030.$(OBJEXT): internal/special_consts.h
enc/trans/gb18030.$(OBJEXT): internal/static_assert.h
@@ -6815,7 +6860,6 @@ enc/trans/gbk.$(OBJEXT): internal/attr/noexcept.h
enc/trans/gbk.$(OBJEXT): internal/attr/noinline.h
enc/trans/gbk.$(OBJEXT): internal/attr/nonnull.h
enc/trans/gbk.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/gbk.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/gbk.$(OBJEXT): internal/attr/pure.h
enc/trans/gbk.$(OBJEXT): internal/attr/restrict.h
enc/trans/gbk.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6875,6 +6919,7 @@ enc/trans/gbk.$(OBJEXT): internal/intern/enumerator.h
enc/trans/gbk.$(OBJEXT): internal/intern/error.h
enc/trans/gbk.$(OBJEXT): internal/intern/eval.h
enc/trans/gbk.$(OBJEXT): internal/intern/file.h
+enc/trans/gbk.$(OBJEXT): internal/intern/gc.h
enc/trans/gbk.$(OBJEXT): internal/intern/hash.h
enc/trans/gbk.$(OBJEXT): internal/intern/io.h
enc/trans/gbk.$(OBJEXT): internal/intern/load.h
@@ -6905,6 +6950,7 @@ enc/trans/gbk.$(OBJEXT): internal/memory.h
enc/trans/gbk.$(OBJEXT): internal/method.h
enc/trans/gbk.$(OBJEXT): internal/module.h
enc/trans/gbk.$(OBJEXT): internal/newobj.h
+enc/trans/gbk.$(OBJEXT): internal/rgengc.h
enc/trans/gbk.$(OBJEXT): internal/scan_args.h
enc/trans/gbk.$(OBJEXT): internal/special_consts.h
enc/trans/gbk.$(OBJEXT): internal/static_assert.h
@@ -6972,8 +7018,8 @@ enc/trans/iso2022.$(OBJEXT): internal/attr/nodiscard.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noexcept.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noinline.h
enc/trans/iso2022.$(OBJEXT): internal/attr/nonnull.h
+enc/trans/iso2022.$(OBJEXT): internal/attr/nonstring.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/iso2022.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/iso2022.$(OBJEXT): internal/attr/pure.h
enc/trans/iso2022.$(OBJEXT): internal/attr/restrict.h
enc/trans/iso2022.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7033,6 +7079,7 @@ enc/trans/iso2022.$(OBJEXT): internal/intern/enumerator.h
enc/trans/iso2022.$(OBJEXT): internal/intern/error.h
enc/trans/iso2022.$(OBJEXT): internal/intern/eval.h
enc/trans/iso2022.$(OBJEXT): internal/intern/file.h
+enc/trans/iso2022.$(OBJEXT): internal/intern/gc.h
enc/trans/iso2022.$(OBJEXT): internal/intern/hash.h
enc/trans/iso2022.$(OBJEXT): internal/intern/io.h
enc/trans/iso2022.$(OBJEXT): internal/intern/load.h
@@ -7063,6 +7110,7 @@ enc/trans/iso2022.$(OBJEXT): internal/memory.h
enc/trans/iso2022.$(OBJEXT): internal/method.h
enc/trans/iso2022.$(OBJEXT): internal/module.h
enc/trans/iso2022.$(OBJEXT): internal/newobj.h
+enc/trans/iso2022.$(OBJEXT): internal/rgengc.h
enc/trans/iso2022.$(OBJEXT): internal/scan_args.h
enc/trans/iso2022.$(OBJEXT): internal/special_consts.h
enc/trans/iso2022.$(OBJEXT): internal/static_assert.h
@@ -7131,7 +7179,6 @@ enc/trans/japanese.$(OBJEXT): internal/attr/noexcept.h
enc/trans/japanese.$(OBJEXT): internal/attr/noinline.h
enc/trans/japanese.$(OBJEXT): internal/attr/nonnull.h
enc/trans/japanese.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/japanese.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/japanese.$(OBJEXT): internal/attr/pure.h
enc/trans/japanese.$(OBJEXT): internal/attr/restrict.h
enc/trans/japanese.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7191,6 +7238,7 @@ enc/trans/japanese.$(OBJEXT): internal/intern/enumerator.h
enc/trans/japanese.$(OBJEXT): internal/intern/error.h
enc/trans/japanese.$(OBJEXT): internal/intern/eval.h
enc/trans/japanese.$(OBJEXT): internal/intern/file.h
+enc/trans/japanese.$(OBJEXT): internal/intern/gc.h
enc/trans/japanese.$(OBJEXT): internal/intern/hash.h
enc/trans/japanese.$(OBJEXT): internal/intern/io.h
enc/trans/japanese.$(OBJEXT): internal/intern/load.h
@@ -7221,6 +7269,7 @@ enc/trans/japanese.$(OBJEXT): internal/memory.h
enc/trans/japanese.$(OBJEXT): internal/method.h
enc/trans/japanese.$(OBJEXT): internal/module.h
enc/trans/japanese.$(OBJEXT): internal/newobj.h
+enc/trans/japanese.$(OBJEXT): internal/rgengc.h
enc/trans/japanese.$(OBJEXT): internal/scan_args.h
enc/trans/japanese.$(OBJEXT): internal/special_consts.h
enc/trans/japanese.$(OBJEXT): internal/static_assert.h
@@ -7289,7 +7338,6 @@ enc/trans/japanese_euc.$(OBJEXT): internal/attr/noexcept.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/noinline.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/nonnull.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/japanese_euc.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/pure.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/restrict.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7349,6 +7397,7 @@ enc/trans/japanese_euc.$(OBJEXT): internal/intern/enumerator.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/error.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/eval.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/file.h
+enc/trans/japanese_euc.$(OBJEXT): internal/intern/gc.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/hash.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/io.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/load.h
@@ -7379,6 +7428,7 @@ enc/trans/japanese_euc.$(OBJEXT): internal/memory.h
enc/trans/japanese_euc.$(OBJEXT): internal/method.h
enc/trans/japanese_euc.$(OBJEXT): internal/module.h
enc/trans/japanese_euc.$(OBJEXT): internal/newobj.h
+enc/trans/japanese_euc.$(OBJEXT): internal/rgengc.h
enc/trans/japanese_euc.$(OBJEXT): internal/scan_args.h
enc/trans/japanese_euc.$(OBJEXT): internal/special_consts.h
enc/trans/japanese_euc.$(OBJEXT): internal/static_assert.h
@@ -7447,7 +7497,6 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/attr/noexcept.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/noinline.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/nonnull.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/japanese_sjis.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/pure.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/restrict.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7507,6 +7556,7 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/intern/enumerator.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/error.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/eval.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/file.h
+enc/trans/japanese_sjis.$(OBJEXT): internal/intern/gc.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/hash.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/io.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/load.h
@@ -7537,6 +7587,7 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/memory.h
enc/trans/japanese_sjis.$(OBJEXT): internal/method.h
enc/trans/japanese_sjis.$(OBJEXT): internal/module.h
enc/trans/japanese_sjis.$(OBJEXT): internal/newobj.h
+enc/trans/japanese_sjis.$(OBJEXT): internal/rgengc.h
enc/trans/japanese_sjis.$(OBJEXT): internal/scan_args.h
enc/trans/japanese_sjis.$(OBJEXT): internal/special_consts.h
enc/trans/japanese_sjis.$(OBJEXT): internal/static_assert.h
@@ -7605,7 +7656,6 @@ enc/trans/korean.$(OBJEXT): internal/attr/noexcept.h
enc/trans/korean.$(OBJEXT): internal/attr/noinline.h
enc/trans/korean.$(OBJEXT): internal/attr/nonnull.h
enc/trans/korean.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/korean.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/korean.$(OBJEXT): internal/attr/pure.h
enc/trans/korean.$(OBJEXT): internal/attr/restrict.h
enc/trans/korean.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7665,6 +7715,7 @@ enc/trans/korean.$(OBJEXT): internal/intern/enumerator.h
enc/trans/korean.$(OBJEXT): internal/intern/error.h
enc/trans/korean.$(OBJEXT): internal/intern/eval.h
enc/trans/korean.$(OBJEXT): internal/intern/file.h
+enc/trans/korean.$(OBJEXT): internal/intern/gc.h
enc/trans/korean.$(OBJEXT): internal/intern/hash.h
enc/trans/korean.$(OBJEXT): internal/intern/io.h
enc/trans/korean.$(OBJEXT): internal/intern/load.h
@@ -7695,6 +7746,7 @@ enc/trans/korean.$(OBJEXT): internal/memory.h
enc/trans/korean.$(OBJEXT): internal/method.h
enc/trans/korean.$(OBJEXT): internal/module.h
enc/trans/korean.$(OBJEXT): internal/newobj.h
+enc/trans/korean.$(OBJEXT): internal/rgengc.h
enc/trans/korean.$(OBJEXT): internal/scan_args.h
enc/trans/korean.$(OBJEXT): internal/special_consts.h
enc/trans/korean.$(OBJEXT): internal/static_assert.h
@@ -7762,7 +7814,6 @@ enc/trans/newline.$(OBJEXT): internal/attr/noexcept.h
enc/trans/newline.$(OBJEXT): internal/attr/noinline.h
enc/trans/newline.$(OBJEXT): internal/attr/nonnull.h
enc/trans/newline.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/newline.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/newline.$(OBJEXT): internal/attr/pure.h
enc/trans/newline.$(OBJEXT): internal/attr/restrict.h
enc/trans/newline.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7822,6 +7873,7 @@ enc/trans/newline.$(OBJEXT): internal/intern/enumerator.h
enc/trans/newline.$(OBJEXT): internal/intern/error.h
enc/trans/newline.$(OBJEXT): internal/intern/eval.h
enc/trans/newline.$(OBJEXT): internal/intern/file.h
+enc/trans/newline.$(OBJEXT): internal/intern/gc.h
enc/trans/newline.$(OBJEXT): internal/intern/hash.h
enc/trans/newline.$(OBJEXT): internal/intern/io.h
enc/trans/newline.$(OBJEXT): internal/intern/load.h
@@ -7852,6 +7904,7 @@ enc/trans/newline.$(OBJEXT): internal/memory.h
enc/trans/newline.$(OBJEXT): internal/method.h
enc/trans/newline.$(OBJEXT): internal/module.h
enc/trans/newline.$(OBJEXT): internal/newobj.h
+enc/trans/newline.$(OBJEXT): internal/rgengc.h
enc/trans/newline.$(OBJEXT): internal/scan_args.h
enc/trans/newline.$(OBJEXT): internal/special_consts.h
enc/trans/newline.$(OBJEXT): internal/static_assert.h
@@ -7920,7 +7973,6 @@ enc/trans/single_byte.$(OBJEXT): internal/attr/noexcept.h
enc/trans/single_byte.$(OBJEXT): internal/attr/noinline.h
enc/trans/single_byte.$(OBJEXT): internal/attr/nonnull.h
enc/trans/single_byte.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/single_byte.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/single_byte.$(OBJEXT): internal/attr/pure.h
enc/trans/single_byte.$(OBJEXT): internal/attr/restrict.h
enc/trans/single_byte.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7980,6 +8032,7 @@ enc/trans/single_byte.$(OBJEXT): internal/intern/enumerator.h
enc/trans/single_byte.$(OBJEXT): internal/intern/error.h
enc/trans/single_byte.$(OBJEXT): internal/intern/eval.h
enc/trans/single_byte.$(OBJEXT): internal/intern/file.h
+enc/trans/single_byte.$(OBJEXT): internal/intern/gc.h
enc/trans/single_byte.$(OBJEXT): internal/intern/hash.h
enc/trans/single_byte.$(OBJEXT): internal/intern/io.h
enc/trans/single_byte.$(OBJEXT): internal/intern/load.h
@@ -8010,6 +8063,7 @@ enc/trans/single_byte.$(OBJEXT): internal/memory.h
enc/trans/single_byte.$(OBJEXT): internal/method.h
enc/trans/single_byte.$(OBJEXT): internal/module.h
enc/trans/single_byte.$(OBJEXT): internal/newobj.h
+enc/trans/single_byte.$(OBJEXT): internal/rgengc.h
enc/trans/single_byte.$(OBJEXT): internal/scan_args.h
enc/trans/single_byte.$(OBJEXT): internal/special_consts.h
enc/trans/single_byte.$(OBJEXT): internal/static_assert.h
@@ -8078,7 +8132,6 @@ enc/trans/transdb.$(OBJEXT): internal/attr/noexcept.h
enc/trans/transdb.$(OBJEXT): internal/attr/noinline.h
enc/trans/transdb.$(OBJEXT): internal/attr/nonnull.h
enc/trans/transdb.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/transdb.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/transdb.$(OBJEXT): internal/attr/pure.h
enc/trans/transdb.$(OBJEXT): internal/attr/restrict.h
enc/trans/transdb.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8138,6 +8191,7 @@ enc/trans/transdb.$(OBJEXT): internal/intern/enumerator.h
enc/trans/transdb.$(OBJEXT): internal/intern/error.h
enc/trans/transdb.$(OBJEXT): internal/intern/eval.h
enc/trans/transdb.$(OBJEXT): internal/intern/file.h
+enc/trans/transdb.$(OBJEXT): internal/intern/gc.h
enc/trans/transdb.$(OBJEXT): internal/intern/hash.h
enc/trans/transdb.$(OBJEXT): internal/intern/io.h
enc/trans/transdb.$(OBJEXT): internal/intern/load.h
@@ -8168,6 +8222,7 @@ enc/trans/transdb.$(OBJEXT): internal/memory.h
enc/trans/transdb.$(OBJEXT): internal/method.h
enc/trans/transdb.$(OBJEXT): internal/module.h
enc/trans/transdb.$(OBJEXT): internal/newobj.h
+enc/trans/transdb.$(OBJEXT): internal/rgengc.h
enc/trans/transdb.$(OBJEXT): internal/scan_args.h
enc/trans/transdb.$(OBJEXT): internal/special_consts.h
enc/trans/transdb.$(OBJEXT): internal/static_assert.h
@@ -8237,7 +8292,6 @@ enc/trans/utf8_mac.$(OBJEXT): internal/attr/noexcept.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/noinline.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/nonnull.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/utf8_mac.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/pure.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/restrict.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8297,6 +8351,7 @@ enc/trans/utf8_mac.$(OBJEXT): internal/intern/enumerator.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/error.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/eval.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/file.h
+enc/trans/utf8_mac.$(OBJEXT): internal/intern/gc.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/hash.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/io.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/load.h
@@ -8327,6 +8382,7 @@ enc/trans/utf8_mac.$(OBJEXT): internal/memory.h
enc/trans/utf8_mac.$(OBJEXT): internal/method.h
enc/trans/utf8_mac.$(OBJEXT): internal/module.h
enc/trans/utf8_mac.$(OBJEXT): internal/newobj.h
+enc/trans/utf8_mac.$(OBJEXT): internal/rgengc.h
enc/trans/utf8_mac.$(OBJEXT): internal/scan_args.h
enc/trans/utf8_mac.$(OBJEXT): internal/special_consts.h
enc/trans/utf8_mac.$(OBJEXT): internal/static_assert.h
@@ -8395,7 +8451,6 @@ enc/trans/utf_16_32.$(OBJEXT): internal/attr/noexcept.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/noinline.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/nonnull.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/utf_16_32.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/pure.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/restrict.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8455,6 +8510,7 @@ enc/trans/utf_16_32.$(OBJEXT): internal/intern/enumerator.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/error.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/eval.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/file.h
+enc/trans/utf_16_32.$(OBJEXT): internal/intern/gc.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/hash.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/io.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/load.h
@@ -8485,6 +8541,7 @@ enc/trans/utf_16_32.$(OBJEXT): internal/memory.h
enc/trans/utf_16_32.$(OBJEXT): internal/method.h
enc/trans/utf_16_32.$(OBJEXT): internal/module.h
enc/trans/utf_16_32.$(OBJEXT): internal/newobj.h
+enc/trans/utf_16_32.$(OBJEXT): internal/rgengc.h
enc/trans/utf_16_32.$(OBJEXT): internal/scan_args.h
enc/trans/utf_16_32.$(OBJEXT): internal/special_consts.h
enc/trans/utf_16_32.$(OBJEXT): internal/static_assert.h
@@ -8556,7 +8613,6 @@ enc/unicode.$(OBJEXT): internal/attr/noexcept.h
enc/unicode.$(OBJEXT): internal/attr/noinline.h
enc/unicode.$(OBJEXT): internal/attr/nonnull.h
enc/unicode.$(OBJEXT): internal/attr/noreturn.h
-enc/unicode.$(OBJEXT): internal/attr/packed_struct.h
enc/unicode.$(OBJEXT): internal/attr/pure.h
enc/unicode.$(OBJEXT): internal/attr/restrict.h
enc/unicode.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8616,6 +8672,7 @@ enc/unicode.$(OBJEXT): internal/intern/enumerator.h
enc/unicode.$(OBJEXT): internal/intern/error.h
enc/unicode.$(OBJEXT): internal/intern/eval.h
enc/unicode.$(OBJEXT): internal/intern/file.h
+enc/unicode.$(OBJEXT): internal/intern/gc.h
enc/unicode.$(OBJEXT): internal/intern/hash.h
enc/unicode.$(OBJEXT): internal/intern/io.h
enc/unicode.$(OBJEXT): internal/intern/load.h
@@ -8646,6 +8703,7 @@ enc/unicode.$(OBJEXT): internal/memory.h
enc/unicode.$(OBJEXT): internal/method.h
enc/unicode.$(OBJEXT): internal/module.h
enc/unicode.$(OBJEXT): internal/newobj.h
+enc/unicode.$(OBJEXT): internal/rgengc.h
enc/unicode.$(OBJEXT): internal/scan_args.h
enc/unicode.$(OBJEXT): internal/special_consts.h
enc/unicode.$(OBJEXT): internal/static_assert.h
@@ -8717,7 +8775,6 @@ enc/us_ascii.$(OBJEXT): internal/attr/noexcept.h
enc/us_ascii.$(OBJEXT): internal/attr/noinline.h
enc/us_ascii.$(OBJEXT): internal/attr/nonnull.h
enc/us_ascii.$(OBJEXT): internal/attr/noreturn.h
-enc/us_ascii.$(OBJEXT): internal/attr/packed_struct.h
enc/us_ascii.$(OBJEXT): internal/attr/pure.h
enc/us_ascii.$(OBJEXT): internal/attr/restrict.h
enc/us_ascii.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8786,6 +8843,7 @@ enc/us_ascii.$(OBJEXT): internal/intern/enumerator.h
enc/us_ascii.$(OBJEXT): internal/intern/error.h
enc/us_ascii.$(OBJEXT): internal/intern/eval.h
enc/us_ascii.$(OBJEXT): internal/intern/file.h
+enc/us_ascii.$(OBJEXT): internal/intern/gc.h
enc/us_ascii.$(OBJEXT): internal/intern/hash.h
enc/us_ascii.$(OBJEXT): internal/intern/io.h
enc/us_ascii.$(OBJEXT): internal/intern/load.h
@@ -8816,6 +8874,7 @@ enc/us_ascii.$(OBJEXT): internal/memory.h
enc/us_ascii.$(OBJEXT): internal/method.h
enc/us_ascii.$(OBJEXT): internal/module.h
enc/us_ascii.$(OBJEXT): internal/newobj.h
+enc/us_ascii.$(OBJEXT): internal/rgengc.h
enc/us_ascii.$(OBJEXT): internal/scan_args.h
enc/us_ascii.$(OBJEXT): internal/special_consts.h
enc/us_ascii.$(OBJEXT): internal/static_assert.h
@@ -8888,7 +8947,6 @@ enc/utf_16be.$(OBJEXT): internal/attr/noexcept.h
enc/utf_16be.$(OBJEXT): internal/attr/noinline.h
enc/utf_16be.$(OBJEXT): internal/attr/nonnull.h
enc/utf_16be.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_16be.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_16be.$(OBJEXT): internal/attr/pure.h
enc/utf_16be.$(OBJEXT): internal/attr/restrict.h
enc/utf_16be.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8948,6 +9006,7 @@ enc/utf_16be.$(OBJEXT): internal/intern/enumerator.h
enc/utf_16be.$(OBJEXT): internal/intern/error.h
enc/utf_16be.$(OBJEXT): internal/intern/eval.h
enc/utf_16be.$(OBJEXT): internal/intern/file.h
+enc/utf_16be.$(OBJEXT): internal/intern/gc.h
enc/utf_16be.$(OBJEXT): internal/intern/hash.h
enc/utf_16be.$(OBJEXT): internal/intern/io.h
enc/utf_16be.$(OBJEXT): internal/intern/load.h
@@ -8978,6 +9037,7 @@ enc/utf_16be.$(OBJEXT): internal/memory.h
enc/utf_16be.$(OBJEXT): internal/method.h
enc/utf_16be.$(OBJEXT): internal/module.h
enc/utf_16be.$(OBJEXT): internal/newobj.h
+enc/utf_16be.$(OBJEXT): internal/rgengc.h
enc/utf_16be.$(OBJEXT): internal/scan_args.h
enc/utf_16be.$(OBJEXT): internal/special_consts.h
enc/utf_16be.$(OBJEXT): internal/static_assert.h
@@ -9049,7 +9109,6 @@ enc/utf_16le.$(OBJEXT): internal/attr/noexcept.h
enc/utf_16le.$(OBJEXT): internal/attr/noinline.h
enc/utf_16le.$(OBJEXT): internal/attr/nonnull.h
enc/utf_16le.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_16le.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_16le.$(OBJEXT): internal/attr/pure.h
enc/utf_16le.$(OBJEXT): internal/attr/restrict.h
enc/utf_16le.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9109,6 +9168,7 @@ enc/utf_16le.$(OBJEXT): internal/intern/enumerator.h
enc/utf_16le.$(OBJEXT): internal/intern/error.h
enc/utf_16le.$(OBJEXT): internal/intern/eval.h
enc/utf_16le.$(OBJEXT): internal/intern/file.h
+enc/utf_16le.$(OBJEXT): internal/intern/gc.h
enc/utf_16le.$(OBJEXT): internal/intern/hash.h
enc/utf_16le.$(OBJEXT): internal/intern/io.h
enc/utf_16le.$(OBJEXT): internal/intern/load.h
@@ -9139,6 +9199,7 @@ enc/utf_16le.$(OBJEXT): internal/memory.h
enc/utf_16le.$(OBJEXT): internal/method.h
enc/utf_16le.$(OBJEXT): internal/module.h
enc/utf_16le.$(OBJEXT): internal/newobj.h
+enc/utf_16le.$(OBJEXT): internal/rgengc.h
enc/utf_16le.$(OBJEXT): internal/scan_args.h
enc/utf_16le.$(OBJEXT): internal/special_consts.h
enc/utf_16le.$(OBJEXT): internal/static_assert.h
@@ -9210,7 +9271,6 @@ enc/utf_32be.$(OBJEXT): internal/attr/noexcept.h
enc/utf_32be.$(OBJEXT): internal/attr/noinline.h
enc/utf_32be.$(OBJEXT): internal/attr/nonnull.h
enc/utf_32be.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_32be.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_32be.$(OBJEXT): internal/attr/pure.h
enc/utf_32be.$(OBJEXT): internal/attr/restrict.h
enc/utf_32be.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9270,6 +9330,7 @@ enc/utf_32be.$(OBJEXT): internal/intern/enumerator.h
enc/utf_32be.$(OBJEXT): internal/intern/error.h
enc/utf_32be.$(OBJEXT): internal/intern/eval.h
enc/utf_32be.$(OBJEXT): internal/intern/file.h
+enc/utf_32be.$(OBJEXT): internal/intern/gc.h
enc/utf_32be.$(OBJEXT): internal/intern/hash.h
enc/utf_32be.$(OBJEXT): internal/intern/io.h
enc/utf_32be.$(OBJEXT): internal/intern/load.h
@@ -9300,6 +9361,7 @@ enc/utf_32be.$(OBJEXT): internal/memory.h
enc/utf_32be.$(OBJEXT): internal/method.h
enc/utf_32be.$(OBJEXT): internal/module.h
enc/utf_32be.$(OBJEXT): internal/newobj.h
+enc/utf_32be.$(OBJEXT): internal/rgengc.h
enc/utf_32be.$(OBJEXT): internal/scan_args.h
enc/utf_32be.$(OBJEXT): internal/special_consts.h
enc/utf_32be.$(OBJEXT): internal/static_assert.h
@@ -9371,7 +9433,6 @@ enc/utf_32le.$(OBJEXT): internal/attr/noexcept.h
enc/utf_32le.$(OBJEXT): internal/attr/noinline.h
enc/utf_32le.$(OBJEXT): internal/attr/nonnull.h
enc/utf_32le.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_32le.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_32le.$(OBJEXT): internal/attr/pure.h
enc/utf_32le.$(OBJEXT): internal/attr/restrict.h
enc/utf_32le.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9431,6 +9492,7 @@ enc/utf_32le.$(OBJEXT): internal/intern/enumerator.h
enc/utf_32le.$(OBJEXT): internal/intern/error.h
enc/utf_32le.$(OBJEXT): internal/intern/eval.h
enc/utf_32le.$(OBJEXT): internal/intern/file.h
+enc/utf_32le.$(OBJEXT): internal/intern/gc.h
enc/utf_32le.$(OBJEXT): internal/intern/hash.h
enc/utf_32le.$(OBJEXT): internal/intern/io.h
enc/utf_32le.$(OBJEXT): internal/intern/load.h
@@ -9461,6 +9523,7 @@ enc/utf_32le.$(OBJEXT): internal/memory.h
enc/utf_32le.$(OBJEXT): internal/method.h
enc/utf_32le.$(OBJEXT): internal/module.h
enc/utf_32le.$(OBJEXT): internal/newobj.h
+enc/utf_32le.$(OBJEXT): internal/rgengc.h
enc/utf_32le.$(OBJEXT): internal/scan_args.h
enc/utf_32le.$(OBJEXT): internal/special_consts.h
enc/utf_32le.$(OBJEXT): internal/static_assert.h
@@ -9532,7 +9595,6 @@ enc/utf_8.$(OBJEXT): internal/attr/noexcept.h
enc/utf_8.$(OBJEXT): internal/attr/noinline.h
enc/utf_8.$(OBJEXT): internal/attr/nonnull.h
enc/utf_8.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_8.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_8.$(OBJEXT): internal/attr/pure.h
enc/utf_8.$(OBJEXT): internal/attr/restrict.h
enc/utf_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9601,6 +9663,7 @@ enc/utf_8.$(OBJEXT): internal/intern/enumerator.h
enc/utf_8.$(OBJEXT): internal/intern/error.h
enc/utf_8.$(OBJEXT): internal/intern/eval.h
enc/utf_8.$(OBJEXT): internal/intern/file.h
+enc/utf_8.$(OBJEXT): internal/intern/gc.h
enc/utf_8.$(OBJEXT): internal/intern/hash.h
enc/utf_8.$(OBJEXT): internal/intern/io.h
enc/utf_8.$(OBJEXT): internal/intern/load.h
@@ -9631,6 +9694,7 @@ enc/utf_8.$(OBJEXT): internal/memory.h
enc/utf_8.$(OBJEXT): internal/method.h
enc/utf_8.$(OBJEXT): internal/module.h
enc/utf_8.$(OBJEXT): internal/newobj.h
+enc/utf_8.$(OBJEXT): internal/rgengc.h
enc/utf_8.$(OBJEXT): internal/scan_args.h
enc/utf_8.$(OBJEXT): internal/special_consts.h
enc/utf_8.$(OBJEXT): internal/static_assert.h
@@ -9703,7 +9767,6 @@ enc/windows_1250.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1250.$(OBJEXT): internal/attr/noinline.h
enc/windows_1250.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1250.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1250.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1250.$(OBJEXT): internal/attr/pure.h
enc/windows_1250.$(OBJEXT): internal/attr/restrict.h
enc/windows_1250.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9763,6 +9826,7 @@ enc/windows_1250.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1250.$(OBJEXT): internal/intern/error.h
enc/windows_1250.$(OBJEXT): internal/intern/eval.h
enc/windows_1250.$(OBJEXT): internal/intern/file.h
+enc/windows_1250.$(OBJEXT): internal/intern/gc.h
enc/windows_1250.$(OBJEXT): internal/intern/hash.h
enc/windows_1250.$(OBJEXT): internal/intern/io.h
enc/windows_1250.$(OBJEXT): internal/intern/load.h
@@ -9793,6 +9857,7 @@ enc/windows_1250.$(OBJEXT): internal/memory.h
enc/windows_1250.$(OBJEXT): internal/method.h
enc/windows_1250.$(OBJEXT): internal/module.h
enc/windows_1250.$(OBJEXT): internal/newobj.h
+enc/windows_1250.$(OBJEXT): internal/rgengc.h
enc/windows_1250.$(OBJEXT): internal/scan_args.h
enc/windows_1250.$(OBJEXT): internal/special_consts.h
enc/windows_1250.$(OBJEXT): internal/static_assert.h
@@ -9863,7 +9928,6 @@ enc/windows_1251.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1251.$(OBJEXT): internal/attr/noinline.h
enc/windows_1251.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1251.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1251.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1251.$(OBJEXT): internal/attr/pure.h
enc/windows_1251.$(OBJEXT): internal/attr/restrict.h
enc/windows_1251.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9923,6 +9987,7 @@ enc/windows_1251.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1251.$(OBJEXT): internal/intern/error.h
enc/windows_1251.$(OBJEXT): internal/intern/eval.h
enc/windows_1251.$(OBJEXT): internal/intern/file.h
+enc/windows_1251.$(OBJEXT): internal/intern/gc.h
enc/windows_1251.$(OBJEXT): internal/intern/hash.h
enc/windows_1251.$(OBJEXT): internal/intern/io.h
enc/windows_1251.$(OBJEXT): internal/intern/load.h
@@ -9953,6 +10018,7 @@ enc/windows_1251.$(OBJEXT): internal/memory.h
enc/windows_1251.$(OBJEXT): internal/method.h
enc/windows_1251.$(OBJEXT): internal/module.h
enc/windows_1251.$(OBJEXT): internal/newobj.h
+enc/windows_1251.$(OBJEXT): internal/rgengc.h
enc/windows_1251.$(OBJEXT): internal/scan_args.h
enc/windows_1251.$(OBJEXT): internal/special_consts.h
enc/windows_1251.$(OBJEXT): internal/static_assert.h
@@ -10024,7 +10090,6 @@ enc/windows_1252.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1252.$(OBJEXT): internal/attr/noinline.h
enc/windows_1252.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1252.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1252.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1252.$(OBJEXT): internal/attr/pure.h
enc/windows_1252.$(OBJEXT): internal/attr/restrict.h
enc/windows_1252.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10084,6 +10149,7 @@ enc/windows_1252.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1252.$(OBJEXT): internal/intern/error.h
enc/windows_1252.$(OBJEXT): internal/intern/eval.h
enc/windows_1252.$(OBJEXT): internal/intern/file.h
+enc/windows_1252.$(OBJEXT): internal/intern/gc.h
enc/windows_1252.$(OBJEXT): internal/intern/hash.h
enc/windows_1252.$(OBJEXT): internal/intern/io.h
enc/windows_1252.$(OBJEXT): internal/intern/load.h
@@ -10114,6 +10180,7 @@ enc/windows_1252.$(OBJEXT): internal/memory.h
enc/windows_1252.$(OBJEXT): internal/method.h
enc/windows_1252.$(OBJEXT): internal/module.h
enc/windows_1252.$(OBJEXT): internal/newobj.h
+enc/windows_1252.$(OBJEXT): internal/rgengc.h
enc/windows_1252.$(OBJEXT): internal/scan_args.h
enc/windows_1252.$(OBJEXT): internal/special_consts.h
enc/windows_1252.$(OBJEXT): internal/static_assert.h
@@ -10184,7 +10251,6 @@ enc/windows_1253.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1253.$(OBJEXT): internal/attr/noinline.h
enc/windows_1253.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1253.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1253.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1253.$(OBJEXT): internal/attr/pure.h
enc/windows_1253.$(OBJEXT): internal/attr/restrict.h
enc/windows_1253.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10244,6 +10310,7 @@ enc/windows_1253.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1253.$(OBJEXT): internal/intern/error.h
enc/windows_1253.$(OBJEXT): internal/intern/eval.h
enc/windows_1253.$(OBJEXT): internal/intern/file.h
+enc/windows_1253.$(OBJEXT): internal/intern/gc.h
enc/windows_1253.$(OBJEXT): internal/intern/hash.h
enc/windows_1253.$(OBJEXT): internal/intern/io.h
enc/windows_1253.$(OBJEXT): internal/intern/load.h
@@ -10274,6 +10341,7 @@ enc/windows_1253.$(OBJEXT): internal/memory.h
enc/windows_1253.$(OBJEXT): internal/method.h
enc/windows_1253.$(OBJEXT): internal/module.h
enc/windows_1253.$(OBJEXT): internal/newobj.h
+enc/windows_1253.$(OBJEXT): internal/rgengc.h
enc/windows_1253.$(OBJEXT): internal/scan_args.h
enc/windows_1253.$(OBJEXT): internal/special_consts.h
enc/windows_1253.$(OBJEXT): internal/static_assert.h
@@ -10345,7 +10413,6 @@ enc/windows_1254.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1254.$(OBJEXT): internal/attr/noinline.h
enc/windows_1254.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1254.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1254.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1254.$(OBJEXT): internal/attr/pure.h
enc/windows_1254.$(OBJEXT): internal/attr/restrict.h
enc/windows_1254.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10405,6 +10472,7 @@ enc/windows_1254.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1254.$(OBJEXT): internal/intern/error.h
enc/windows_1254.$(OBJEXT): internal/intern/eval.h
enc/windows_1254.$(OBJEXT): internal/intern/file.h
+enc/windows_1254.$(OBJEXT): internal/intern/gc.h
enc/windows_1254.$(OBJEXT): internal/intern/hash.h
enc/windows_1254.$(OBJEXT): internal/intern/io.h
enc/windows_1254.$(OBJEXT): internal/intern/load.h
@@ -10435,6 +10503,7 @@ enc/windows_1254.$(OBJEXT): internal/memory.h
enc/windows_1254.$(OBJEXT): internal/method.h
enc/windows_1254.$(OBJEXT): internal/module.h
enc/windows_1254.$(OBJEXT): internal/newobj.h
+enc/windows_1254.$(OBJEXT): internal/rgengc.h
enc/windows_1254.$(OBJEXT): internal/scan_args.h
enc/windows_1254.$(OBJEXT): internal/special_consts.h
enc/windows_1254.$(OBJEXT): internal/static_assert.h
@@ -10506,7 +10575,6 @@ enc/windows_1257.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1257.$(OBJEXT): internal/attr/noinline.h
enc/windows_1257.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1257.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1257.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1257.$(OBJEXT): internal/attr/pure.h
enc/windows_1257.$(OBJEXT): internal/attr/restrict.h
enc/windows_1257.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10566,6 +10634,7 @@ enc/windows_1257.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1257.$(OBJEXT): internal/intern/error.h
enc/windows_1257.$(OBJEXT): internal/intern/eval.h
enc/windows_1257.$(OBJEXT): internal/intern/file.h
+enc/windows_1257.$(OBJEXT): internal/intern/gc.h
enc/windows_1257.$(OBJEXT): internal/intern/hash.h
enc/windows_1257.$(OBJEXT): internal/intern/io.h
enc/windows_1257.$(OBJEXT): internal/intern/load.h
@@ -10596,6 +10665,7 @@ enc/windows_1257.$(OBJEXT): internal/memory.h
enc/windows_1257.$(OBJEXT): internal/method.h
enc/windows_1257.$(OBJEXT): internal/module.h
enc/windows_1257.$(OBJEXT): internal/newobj.h
+enc/windows_1257.$(OBJEXT): internal/rgengc.h
enc/windows_1257.$(OBJEXT): internal/scan_args.h
enc/windows_1257.$(OBJEXT): internal/special_consts.h
enc/windows_1257.$(OBJEXT): internal/static_assert.h
@@ -10669,7 +10739,6 @@ enc/windows_31j.$(OBJEXT): internal/attr/noexcept.h
enc/windows_31j.$(OBJEXT): internal/attr/noinline.h
enc/windows_31j.$(OBJEXT): internal/attr/nonnull.h
enc/windows_31j.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_31j.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_31j.$(OBJEXT): internal/attr/pure.h
enc/windows_31j.$(OBJEXT): internal/attr/restrict.h
enc/windows_31j.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10729,6 +10798,7 @@ enc/windows_31j.$(OBJEXT): internal/intern/enumerator.h
enc/windows_31j.$(OBJEXT): internal/intern/error.h
enc/windows_31j.$(OBJEXT): internal/intern/eval.h
enc/windows_31j.$(OBJEXT): internal/intern/file.h
+enc/windows_31j.$(OBJEXT): internal/intern/gc.h
enc/windows_31j.$(OBJEXT): internal/intern/hash.h
enc/windows_31j.$(OBJEXT): internal/intern/io.h
enc/windows_31j.$(OBJEXT): internal/intern/load.h
@@ -10759,6 +10829,7 @@ enc/windows_31j.$(OBJEXT): internal/memory.h
enc/windows_31j.$(OBJEXT): internal/method.h
enc/windows_31j.$(OBJEXT): internal/module.h
enc/windows_31j.$(OBJEXT): internal/newobj.h
+enc/windows_31j.$(OBJEXT): internal/rgengc.h
enc/windows_31j.$(OBJEXT): internal/scan_args.h
enc/windows_31j.$(OBJEXT): internal/special_consts.h
enc/windows_31j.$(OBJEXT): internal/static_assert.h
diff --git a/enc/trans/big5-uao-tbl.rb b/enc/trans/big5-uao-tbl.rb
index a6f37cc7bd..295fbfdda5 100644
--- a/enc/trans/big5-uao-tbl.rb
+++ b/enc/trans/big5-uao-tbl.rb
@@ -19781,4 +19781,4 @@ BIG5_UAO_TO_UCS_TBL = [
["FEFC",0x8262],
["FEFD",0x826A],
["FEFE",0x8288],
-]
+] \ No newline at end of file
diff --git a/enc/trans/cp850-tbl.rb b/enc/trans/cp850-tbl.rb
index e0d120c803..615d3b2599 100644
--- a/enc/trans/cp850-tbl.rb
+++ b/enc/trans/cp850-tbl.rb
@@ -127,4 +127,4 @@ CP850_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/cp852-tbl.rb b/enc/trans/cp852-tbl.rb
index ad32cdc59d..6763bfa6e9 100644
--- a/enc/trans/cp852-tbl.rb
+++ b/enc/trans/cp852-tbl.rb
@@ -127,4 +127,4 @@ CP852_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/cp855-tbl.rb b/enc/trans/cp855-tbl.rb
index a2ca9daf97..72e548b9cb 100644
--- a/enc/trans/cp855-tbl.rb
+++ b/enc/trans/cp855-tbl.rb
@@ -127,4 +127,4 @@ CP855_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/gbk-tbl.rb b/enc/trans/gbk-tbl.rb
index 40929f992e..26f5078c45 100644
--- a/enc/trans/gbk-tbl.rb
+++ b/enc/trans/gbk-tbl.rb
@@ -21791,4 +21791,4 @@ GBK_TO_UCS_TBL= [
["A3FE",0xFFE3],
["A957",0xFFE4],
["A3A4",0xFFE5],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm437-tbl.rb b/enc/trans/ibm437-tbl.rb
index 6a823c293d..5ae64d621e 100644
--- a/enc/trans/ibm437-tbl.rb
+++ b/enc/trans/ibm437-tbl.rb
@@ -127,4 +127,4 @@ IBM437_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm775-tbl.rb b/enc/trans/ibm775-tbl.rb
index 2b79780813..f55679f409 100644
--- a/enc/trans/ibm775-tbl.rb
+++ b/enc/trans/ibm775-tbl.rb
@@ -127,4 +127,4 @@ IBM775_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm852-tbl.rb b/enc/trans/ibm852-tbl.rb
index 3e70daef2e..6cec51cf80 100644
--- a/enc/trans/ibm852-tbl.rb
+++ b/enc/trans/ibm852-tbl.rb
@@ -127,4 +127,4 @@ IBM852_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm855-tbl.rb b/enc/trans/ibm855-tbl.rb
index b4c0244728..7e0cc5014f 100644
--- a/enc/trans/ibm855-tbl.rb
+++ b/enc/trans/ibm855-tbl.rb
@@ -127,4 +127,4 @@ IBM855_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm857-tbl.rb b/enc/trans/ibm857-tbl.rb
index c1c76545ed..5b20d389d3 100644
--- a/enc/trans/ibm857-tbl.rb
+++ b/enc/trans/ibm857-tbl.rb
@@ -124,4 +124,4 @@ IBM857_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm860-tbl.rb b/enc/trans/ibm860-tbl.rb
index 77734cd194..ae218a129f 100644
--- a/enc/trans/ibm860-tbl.rb
+++ b/enc/trans/ibm860-tbl.rb
@@ -127,4 +127,4 @@ IBM860_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm861-tbl.rb b/enc/trans/ibm861-tbl.rb
index 69e0a45019..c24042a76c 100644
--- a/enc/trans/ibm861-tbl.rb
+++ b/enc/trans/ibm861-tbl.rb
@@ -127,4 +127,4 @@ IBM861_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm862-tbl.rb b/enc/trans/ibm862-tbl.rb
index f564051fd6..31d6fb0243 100644
--- a/enc/trans/ibm862-tbl.rb
+++ b/enc/trans/ibm862-tbl.rb
@@ -127,4 +127,4 @@ IBM862_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm863-tbl.rb b/enc/trans/ibm863-tbl.rb
index af1eb97566..db110cf38c 100644
--- a/enc/trans/ibm863-tbl.rb
+++ b/enc/trans/ibm863-tbl.rb
@@ -127,4 +127,4 @@ IBM863_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm865-tbl.rb b/enc/trans/ibm865-tbl.rb
index 4747509d66..22e322fb31 100644
--- a/enc/trans/ibm865-tbl.rb
+++ b/enc/trans/ibm865-tbl.rb
@@ -127,4 +127,4 @@ IBM865_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm866-tbl.rb b/enc/trans/ibm866-tbl.rb
index ed4b0d683e..95b9ee7534 100644
--- a/enc/trans/ibm866-tbl.rb
+++ b/enc/trans/ibm866-tbl.rb
@@ -127,4 +127,4 @@ IBM866_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm869-tbl.rb b/enc/trans/ibm869-tbl.rb
index bee85b84ea..437e41ad98 100644
--- a/enc/trans/ibm869-tbl.rb
+++ b/enc/trans/ibm869-tbl.rb
@@ -118,4 +118,4 @@ IBM869_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/koi8-r-tbl.rb b/enc/trans/koi8-r-tbl.rb
index 4cfe523334..a1f55ff2e3 100644
--- a/enc/trans/koi8-r-tbl.rb
+++ b/enc/trans/koi8-r-tbl.rb
@@ -127,4 +127,4 @@ KOI8_R_TO_UCS_TBL = [
["91",0x2592],
["92",0x2593],
["94",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/koi8-u-tbl.rb b/enc/trans/koi8-u-tbl.rb
index 225931ba5e..e87aa1aa3f 100644
--- a/enc/trans/koi8-u-tbl.rb
+++ b/enc/trans/koi8-u-tbl.rb
@@ -127,4 +127,4 @@ KOI8_U_TO_UCS_TBL = [
["91",0x2592],
["92",0x2593],
["94",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/maccroatian-tbl.rb b/enc/trans/maccroatian-tbl.rb
index e78f2f373f..359878ec1f 100644
--- a/enc/trans/maccroatian-tbl.rb
+++ b/enc/trans/maccroatian-tbl.rb
@@ -126,4 +126,4 @@ MACCROATIAN_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/maccyrillic-tbl.rb b/enc/trans/maccyrillic-tbl.rb
index 2d5af7b466..378aa8c3bc 100644
--- a/enc/trans/maccyrillic-tbl.rb
+++ b/enc/trans/maccyrillic-tbl.rb
@@ -127,4 +127,4 @@ MACCYRILLIC_TO_UCS_TBL = [
["AD",0x2260],
["B2",0x2264],
["B3",0x2265],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macgreek-tbl.rb b/enc/trans/macgreek-tbl.rb
index 645aefe5ff..7f75fde6d2 100644
--- a/enc/trans/macgreek-tbl.rb
+++ b/enc/trans/macgreek-tbl.rb
@@ -126,4 +126,4 @@ MACGREEK_TO_UCS_TBL = [
["AD",0x2260],
["B2",0x2264],
["B3",0x2265],
-]
+] \ No newline at end of file
diff --git a/enc/trans/maciceland-tbl.rb b/enc/trans/maciceland-tbl.rb
index ee9b5000d9..818d992274 100644
--- a/enc/trans/maciceland-tbl.rb
+++ b/enc/trans/maciceland-tbl.rb
@@ -126,4 +126,4 @@ MACICELAND_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macroman-tbl.rb b/enc/trans/macroman-tbl.rb
index 9a8172554a..8f74eea27f 100644
--- a/enc/trans/macroman-tbl.rb
+++ b/enc/trans/macroman-tbl.rb
@@ -126,4 +126,4 @@ MACROMAN_TO_UCS_TBL = [
["D7",0x25CA],
["DE",0xFB01],
["DF",0xFB02],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macromania-tbl.rb b/enc/trans/macromania-tbl.rb
index 29a7942d9b..ff95c5e957 100644
--- a/enc/trans/macromania-tbl.rb
+++ b/enc/trans/macromania-tbl.rb
@@ -126,4 +126,4 @@ MACROMANIA_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macturkish-tbl.rb b/enc/trans/macturkish-tbl.rb
index 883f693e23..2358672ed6 100644
--- a/enc/trans/macturkish-tbl.rb
+++ b/enc/trans/macturkish-tbl.rb
@@ -125,4 +125,4 @@ MACTURKISH_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macukraine-tbl.rb b/enc/trans/macukraine-tbl.rb
index 09acf7c45a..6941af654d 100644
--- a/enc/trans/macukraine-tbl.rb
+++ b/enc/trans/macukraine-tbl.rb
@@ -127,4 +127,4 @@ MACUKRAINE_TO_UCS_TBL = [
["AD",0x2260],
["B2",0x2264],
["B3",0x2265],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1250-tbl.rb b/enc/trans/windows-1250-tbl.rb
index 9cdb432a03..52063e17b1 100644
--- a/enc/trans/windows-1250-tbl.rb
+++ b/enc/trans/windows-1250-tbl.rb
@@ -122,4 +122,4 @@ WINDOWS_1250_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1251-tbl.rb b/enc/trans/windows-1251-tbl.rb
index 3c6c4ca0bb..870c718b72 100644
--- a/enc/trans/windows-1251-tbl.rb
+++ b/enc/trans/windows-1251-tbl.rb
@@ -126,4 +126,4 @@ WINDOWS_1251_TO_UCS_TBL = [
["88",0x20AC],
["B9",0x2116],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1252-tbl.rb b/enc/trans/windows-1252-tbl.rb
index 86a7be41e7..cefc72dff2 100644
--- a/enc/trans/windows-1252-tbl.rb
+++ b/enc/trans/windows-1252-tbl.rb
@@ -122,4 +122,4 @@ WINDOWS_1252_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1253-tbl.rb b/enc/trans/windows-1253-tbl.rb
index b9d47be2e0..132edb60ba 100644
--- a/enc/trans/windows-1253-tbl.rb
+++ b/enc/trans/windows-1253-tbl.rb
@@ -110,4 +110,4 @@ WINDOWS_1253_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1254-tbl.rb b/enc/trans/windows-1254-tbl.rb
index 84063abf05..81a747afaa 100644
--- a/enc/trans/windows-1254-tbl.rb
+++ b/enc/trans/windows-1254-tbl.rb
@@ -120,4 +120,4 @@ WINDOWS_1254_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1256-tbl.rb b/enc/trans/windows-1256-tbl.rb
index 0b76c824d1..25c5874fb0 100644
--- a/enc/trans/windows-1256-tbl.rb
+++ b/enc/trans/windows-1256-tbl.rb
@@ -127,4 +127,4 @@ WINDOWS_1256_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1257-tbl.rb b/enc/trans/windows-1257-tbl.rb
index 7f15cbbd50..9e89b2b0b5 100644
--- a/enc/trans/windows-1257-tbl.rb
+++ b/enc/trans/windows-1257-tbl.rb
@@ -115,4 +115,4 @@ WINDOWS_1257_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-874-tbl.rb b/enc/trans/windows-874-tbl.rb
index a569765bf0..0552df3d28 100644
--- a/enc/trans/windows-874-tbl.rb
+++ b/enc/trans/windows-874-tbl.rb
@@ -96,4 +96,4 @@ WINDOWS_874_TO_UCS_TBL = [
["95",0x2022],
["85",0x2026],
["80",0x20AC],
-]
+] \ No newline at end of file
diff --git a/enc/unicode/15.0.0/name2ctype.h b/enc/unicode/15.0.0/name2ctype.h
index 6bbbb3512f..a2c996423d 100644
--- a/enc/unicode/15.0.0/name2ctype.h
+++ b/enc/unicode/15.0.0/name2ctype.h
@@ -5402,7 +5402,7 @@ static const OnigCodePoint CR_ASCII[] = {
0x0000, 0x007f,
}; /* CR_ASCII */
-/* 'Punct': [[:Punct:]] */
+/* 'Punct' */
static const OnigCodePoint CR_Punct[] = {
191,
0x0021, 0x0023,
diff --git a/encoding.c b/encoding.c
index 8bfab73177..2f4b47bdfa 100644
--- a/encoding.c
+++ b/encoding.c
@@ -102,7 +102,7 @@ static rb_encoding *global_enc_ascii,
static const rb_data_type_t encoding_data_type = {
"encoding",
{0, 0, 0,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#define is_data_encoding(obj) (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj) == &encoding_data_type)
@@ -505,6 +505,37 @@ enc_replicate(struct enc_table *enc_table, const char *name, rb_encoding *encodi
return idx;
}
+int
+rb_enc_replicate(const char *name, rb_encoding *encoding)
+{
+ int r;
+
+ GLOBAL_ENC_TABLE_EVAL(enc_table,
+ r = enc_replicate(enc_table, name, encoding));
+
+ return r;
+}
+
+/*
+ * call-seq:
+ * enc.replicate(name) -> encoding
+ *
+ * Returns a replicated encoding of _enc_ whose name is _name_.
+ * The new encoding should have the same byte structure of _enc_.
+ * If _name_ is used by another encoding, raise ArgumentError.
+ *
+ */
+static VALUE
+enc_replicate_m(VALUE encoding, VALUE name)
+{
+ int idx;
+ rb_warn_deprecated_to_remove("3.3", "Encoding#replicate", "the original encoding");
+
+ idx = rb_enc_replicate(name_for_encoding(&name), rb_to_encoding(encoding));
+ RB_GC_GUARD(name);
+ return rb_enc_from_encoding_index(idx);
+}
+
static int
enc_replicate_with_index(struct enc_table *enc_table, const char *name, rb_encoding *origenc, int idx)
{
@@ -1525,7 +1556,14 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
if (NIL_P(encoding)) {
def->index = -1;
def->enc = 0;
- st_insert(enc_table->names, (st_data_t)strdup(name),
+ char *name_dup = strdup(name);
+
+ st_data_t existing_name = (st_data_t)name_dup;
+ if (st_delete(enc_table->names, &existing_name, NULL)) {
+ xfree((void *)existing_name);
+ }
+
+ st_insert(enc_table->names, (st_data_t)name_dup,
(st_data_t)UNSPECIFIED_ENCODING);
}
else {
@@ -1883,6 +1921,7 @@ Init_Encoding(void)
rb_define_method(rb_cEncoding, "names", enc_names, 0);
rb_define_method(rb_cEncoding, "dummy?", enc_dummy_p, 0);
rb_define_method(rb_cEncoding, "ascii_compatible?", enc_ascii_compatible_p, 0);
+ rb_define_method(rb_cEncoding, "replicate", enc_replicate_m, 1);
rb_define_singleton_method(rb_cEncoding, "list", enc_list, 0);
rb_define_singleton_method(rb_cEncoding, "name_list", rb_enc_name_list, 0);
rb_define_singleton_method(rb_cEncoding, "aliases", rb_enc_aliases, 0);
diff --git a/enum.c b/enum.c
index 7f15836ba8..b3c715e0a1 100644
--- a/enum.c
+++ b/enum.c
@@ -354,7 +354,7 @@ find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
* {foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') } # => [:bar, 1]
* {foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') } # => []
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
*/
static VALUE
@@ -424,7 +424,7 @@ find_index_iter_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
* ['a', 'b', 'c', 'b'].find_index {|element| element.start_with?('b') } # => 1
* {foo: 0, bar: 1, baz: 2}.find_index {|key, value| value > 1 } # => 2
*
- * With no argument and no block given, returns an Enumerator.
+ * With no argument and no block given, returns an \Enumerator.
*
*/
@@ -501,7 +501,7 @@ enum_size_over_p(VALUE obj, long n)
* a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
* a # => {:bar=>1, :baz=>2}
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
* Related: #reject.
*/
@@ -543,7 +543,7 @@ filter_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* (0..9).filter_map {|i| i * 2 if i.even? } # => [0, 4, 8, 12, 16]
* {foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? } # => [:foo, :baz]
*
- * When no block given, returns an Enumerator.
+ * When no block given, returns an \Enumerator.
*
*/
static VALUE
@@ -584,7 +584,7 @@ reject_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* (0..9).reject {|i| i * 2 if i.even? } # => [1, 3, 5, 7, 9]
* {foo: 0, bar: 1, baz: 2}.reject {|key, value| key if value.odd? } # => {:foo=>0, :baz=>2}
*
- * When no block given, returns an Enumerator.
+ * When no block given, returns an \Enumerator.
*
* Related: #select.
*/
@@ -631,7 +631,7 @@ collect_all(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* (0..4).map {|i| i*i } # => [0, 1, 4, 9, 16]
* {foo: 0, bar: 1, baz: 2}.map {|key, value| value*2} # => [0, 2, 4]
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
*/
static VALUE
@@ -681,7 +681,7 @@ flat_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* [[0, 1], [2, 3]].flat_map {|e| e + [100] } # => [0, 1, 100, 2, 3, 100]
* {foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] } # => [:foo, 0, :bar, 1, :baz, 2]
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
* Alias: #collect_concat.
*/
@@ -700,12 +700,13 @@ enum_flat_map(VALUE obj)
/*
* call-seq:
- * to_a(*args) -> array
+ * to_a -> array
*
* Returns an array containing the items in +self+:
*
* (0..4).to_a # => [0, 1, 2, 3, 4]
*
+ * Enumerable#entries is an alias for Enumerable#to_a.
*/
static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
@@ -745,8 +746,8 @@ enum_to_h_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
/*
* call-seq:
- * to_h(*args) -> hash
- * to_h(*args) {|element| ... } -> hash
+ * to_h -> hash
+ * to_h {|element| ... } -> hash
*
* When +self+ consists of 2-element arrays,
* returns a hash each of whose entries is the key-value pair
@@ -999,6 +1000,7 @@ ary_inject_op(VALUE ary, VALUE init, VALUE op)
* "Memo: 3; element: 3"
* "Memo: 6; element: 4"
*
+ * Enumerable#reduce is an alias for Enumerable#inject.
*
*/
static VALUE
@@ -1334,12 +1336,10 @@ enum_sort(VALUE obj)
}
#define SORT_BY_BUFSIZE 16
-#define SORT_BY_UNIFORMED(num, flo, fix) (((num&1)<<2)|((flo&1)<<1)|fix)
struct sort_by_data {
const VALUE ary;
const VALUE buf;
- uint8_t n;
- uint8_t primitive_uniformed;
+ long n;
};
static VALUE
@@ -1360,11 +1360,6 @@ sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, _data))
rb_raise(rb_eRuntimeError, "sort_by reentered");
}
- if (data->primitive_uniformed) {
- data->primitive_uniformed &= SORT_BY_UNIFORMED((FIXNUM_P(v)) || (RB_FLOAT_TYPE_P(v)),
- RB_FLOAT_TYPE_P(v),
- FIXNUM_P(v));
- }
RARRAY_ASET(data->buf, data->n*2, v);
RARRAY_ASET(data->buf, data->n*2+1, i);
data->n++;
@@ -1392,179 +1387,6 @@ sort_by_cmp(const void *ap, const void *bp, void *data)
return OPTIMIZED_CMP(a, b);
}
-
-/*
- This is parts of uniform sort
-*/
-
-#define uless rb_uniform_is_less
-#define UNIFORM_SWAP(a,b)\
- do{struct rb_uniform_sort_data tmp = a; a = b; b = tmp;} while(0)
-
-struct rb_uniform_sort_data {
- VALUE v;
- VALUE i;
-};
-
-static inline bool
-rb_uniform_is_less(VALUE a, VALUE b)
-{
-
- if (FIXNUM_P(a) && FIXNUM_P(b)) {
- return (SIGNED_VALUE)a < (SIGNED_VALUE)b;
- }
- else if (FIXNUM_P(a)) {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(b));
- return rb_float_cmp(b, a) > 0;
- }
- else {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(a));
- return rb_float_cmp(a, b) < 0;
- }
-}
-
-static inline bool
-rb_uniform_is_larger(VALUE a, VALUE b)
-{
-
- if (FIXNUM_P(a) && FIXNUM_P(b)) {
- return (SIGNED_VALUE)a > (SIGNED_VALUE)b;
- }
- else if (FIXNUM_P(a)) {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(b));
- return rb_float_cmp(b, a) < 0;
- }
- else {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(a));
- return rb_float_cmp(a, b) > 0;
- }
-}
-
-#define med3_val(a,b,c) (uless(a,b)?(uless(b,c)?b:uless(c,a)?a:c):(uless(c,b)?b:uless(a,c)?a:c))
-
-static void
-rb_uniform_insertionsort_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end)
-{
- if ((ptr_end - ptr_begin) < 2) return;
- struct rb_uniform_sort_data tmp, *j, *k,
- *index = ptr_begin+1;
- for (; index < ptr_end; index++) {
- tmp = *index;
- j = k = index;
- if (uless(tmp.v, ptr_begin->v)) {
- while (ptr_begin < j) {
- *j = *(--k);
- j = k;
- }
- }
- else {
- while (uless(tmp.v, (--k)->v)) {
- *j = *k;
- j = k;
- }
- }
- *j = tmp;
- }
-}
-
-static inline void
-rb_uniform_heap_down_2(struct rb_uniform_sort_data* ptr_begin,
- size_t offset, size_t len)
-{
- size_t c;
- struct rb_uniform_sort_data tmp = ptr_begin[offset];
- while ((c = (offset<<1)+1) <= len) {
- if (c < len && uless(ptr_begin[c].v, ptr_begin[c+1].v)) {
- c++;
- }
- if (!uless(tmp.v, ptr_begin[c].v)) break;
- ptr_begin[offset] = ptr_begin[c];
- offset = c;
- }
- ptr_begin[offset] = tmp;
-}
-
-static void
-rb_uniform_heapsort_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end)
-{
- size_t n = ptr_end - ptr_begin;
- if (n < 2) return;
-
- for (size_t offset = n>>1; offset > 0;) {
- rb_uniform_heap_down_2(ptr_begin, --offset, n-1);
- }
- for (size_t offset = n-1; offset > 0;) {
- UNIFORM_SWAP(*ptr_begin, ptr_begin[offset]);
- rb_uniform_heap_down_2(ptr_begin, 0, --offset);
- }
-}
-
-
-static void
-rb_uniform_quicksort_intro_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end, size_t d)
-{
-
- if (ptr_end - ptr_begin <= 16) {
- rb_uniform_insertionsort_2(ptr_begin, ptr_end);
- return;
- }
- if (d == 0) {
- rb_uniform_heapsort_2(ptr_begin, ptr_end);
- return;
- }
-
- VALUE x = med3_val(ptr_begin->v,
- ptr_begin[(ptr_end - ptr_begin)>>1].v,
- ptr_end[-1].v);
- struct rb_uniform_sort_data *i = ptr_begin;
- struct rb_uniform_sort_data *j = ptr_end-1;
-
- do {
- while (uless(i->v, x)) i++;
- while (uless(x, j->v)) j--;
- if (i <= j) {
- UNIFORM_SWAP(*i, *j);
- i++;
- j--;
- }
- } while (i <= j);
- j++;
- if (ptr_end - j > 1) rb_uniform_quicksort_intro_2(j, ptr_end, d-1);
- if (i - ptr_begin > 1) rb_uniform_quicksort_intro_2(ptr_begin, i, d-1);
-}
-
-/**
- * Direct primitive data compare sort. Implement with intro sort.
- * @param[in] ptr_begin The begin address of target rb_ary's raw pointer.
- * @param[in] ptr_end The end address of target rb_ary's raw pointer.
-**/
-static void
-rb_uniform_intro_sort_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end)
-{
- size_t n = ptr_end - ptr_begin;
- size_t d = CHAR_BIT * sizeof(n) - nlz_intptr(n) - 1;
- bool sorted_flag = true;
-
- for (struct rb_uniform_sort_data* ptr = ptr_begin+1; ptr < ptr_end; ptr++) {
- if (rb_uniform_is_larger((ptr-1)->v, (ptr)->v)) {
- sorted_flag = false;
- break;
- }
- }
-
- if (sorted_flag) {
- return;
- }
- rb_uniform_quicksort_intro_2(ptr_begin, ptr_end, d<<1);
-}
-
-#undef uless
-
-
/*
* call-seq:
* sort_by {|element| ... } -> array
@@ -1671,9 +1493,6 @@ enum_sort_by(VALUE obj)
RB_OBJ_WRITE(memo, &data->ary, ary);
RB_OBJ_WRITE(memo, &data->buf, buf);
data->n = 0;
- data->primitive_uniformed = SORT_BY_UNIFORMED((CMP_OPTIMIZABLE(FLOAT) && CMP_OPTIMIZABLE(INTEGER)),
- CMP_OPTIMIZABLE(FLOAT),
- CMP_OPTIMIZABLE(INTEGER));
rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo);
ary = data->ary;
buf = data->buf;
@@ -1682,16 +1501,9 @@ enum_sort_by(VALUE obj)
rb_ary_concat(ary, buf);
}
if (RARRAY_LEN(ary) > 2) {
- if (data->primitive_uniformed) {
- RARRAY_PTR_USE(ary, ptr,
- rb_uniform_intro_sort_2((struct rb_uniform_sort_data*)ptr,
- (struct rb_uniform_sort_data*)(ptr + RARRAY_LEN(ary))));
- }
- else {
- RARRAY_PTR_USE(ary, ptr,
- ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
- sort_by_cmp, (void *)ary));
- }
+ RARRAY_PTR_USE(ary, ptr,
+ ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
+ sort_by_cmp, (void *)ary));
}
if (RBASIC(ary)->klass) {
rb_raise(rb_eRuntimeError, "sort_by reentered");
@@ -1757,9 +1569,6 @@ DEFINE_ENUMFUNCS(all)
*
* Returns whether every element meets a given criterion.
*
- * If +self+ has no element, returns +true+ and argument or block
- * are not used.
- *
* With no argument and no block,
* returns whether every element is truthy:
*
@@ -1821,9 +1630,6 @@ DEFINE_ENUMFUNCS(any)
*
* Returns whether any element meets a given criterion.
*
- * If +self+ has no element, returns +false+ and argument or block
- * are not used.
- *
* With no argument and no block,
* returns whether any element is truthy:
*
@@ -1854,6 +1660,7 @@ DEFINE_ENUMFUNCS(any)
* {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 1 } # => true
* {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 0 } # => false
*
+ *
* Related: #all?, #none?, #one?.
*/
@@ -2915,6 +2722,8 @@ member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args))
* {foo: 0, bar: 1, baz: 2}.include?('foo') # => false
* {foo: 0, bar: 1, baz: 2}.include?(0) # => false
*
+ * Enumerable#member? is an alias for Enumerable#include?.
+ *
*/
static VALUE
@@ -4650,7 +4459,7 @@ sum_iter(VALUE i, struct enum_sum_memo *memo)
}
else switch (TYPE(memo->v)) {
default: sum_iter_some_value(i, memo); return;
- case T_FLOAT: sum_iter_Kahan_Babuska(i, memo); return;
+ case T_FLOAT:
case T_FIXNUM:
case T_BIGNUM:
case T_RATIONAL:
@@ -4824,13 +4633,13 @@ uniq_iter(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
* %w[a b c c b a a b c].uniq # => ["a", "b", "c"]
* [0, 1, 2, 2, 1, 0, 0, 1, 2].uniq # => [0, 1, 2]
*
- * With a block, returns a new array containing elements only for which the block
+ * With a block, returns a new array containing only for which the block
* returns a unique value:
*
* a = [0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1]
* a.uniq {|i| i.even? ? i : 0 } # => [0, 2, 4]
* a = %w[a b c d e e d c b a a b c d e]
- * a.uniq {|c| c < 'c' } # => ["a", "c"]
+ a.uniq {|c| c < 'c' } # => ["a", "c"]
*
*/
@@ -4889,7 +4698,7 @@ enum_compact(VALUE obj)
*
* - {Querying}[rdoc-ref:Enumerable@Methods+for+Querying]
* - {Fetching}[rdoc-ref:Enumerable@Methods+for+Fetching]
- * - {Searching and Filtering}[rdoc-ref:Enumerable@Methods+for+Searching+and+Filtering]
+ * - {Searching}[rdoc-ref:Enumerable@Methods+for+Searching]
* - {Sorting}[rdoc-ref:Enumerable@Methods+for+Sorting]
* - {Iterating}[rdoc-ref:Enumerable@Methods+for+Iterating]
* - {And more....}[rdoc-ref:Enumerable@Other+Methods]
@@ -4905,7 +4714,7 @@ enum_compact(VALUE obj)
* - #one?: Returns +true+ if exactly one element meets a specified criterion; +false+ otherwise.
* - #count: Returns the count of elements,
* based on an argument or block criterion, if given.
- * - #tally: Returns a new Hash containing the counts of occurrences of each element.
+ * - #tally: Returns a new \Hash containing the counts of occurrences of each element.
*
* === Methods for Fetching
*
@@ -4926,21 +4735,21 @@ enum_compact(VALUE obj)
* as determined by <tt><=></tt> or a given block.
* - #max: Returns the elements whose values are largest among the elements,
* as determined by <tt><=></tt> or a given block.
- * - #minmax: Returns a 2-element Array containing the smallest and largest elements.
+ * - #minmax: Returns a 2-element \Array containing the smallest and largest elements.
* - #min_by: Returns the smallest element, as determined by the given block.
* - #max_by: Returns the largest element, as determined by the given block.
* - #minmax_by: Returns the smallest and largest elements, as determined by the given block.
*
* <i>Groups, slices, and partitions</i>:
*
- * - #group_by: Returns a Hash that partitions the elements into groups.
+ * - #group_by: Returns a \Hash that partitions the elements into groups.
* - #partition: Returns elements partitioned into two new Arrays, as determined by the given block.
- * - #slice_after: Returns a new Enumerator whose entries are a partition of +self+,
- * based either on a given +object+ or a given block.
- * - #slice_before: Returns a new Enumerator whose entries are a partition of +self+,
- * based either on a given +object+ or a given block.
- * - #slice_when: Returns a new Enumerator whose entries are a partition of +self+
- * based on the given block.
+ * - #slice_after: Returns a new \Enumerator whose entries are a partition of +self+,
+ based either on a given +object+ or a given block.
+ * - #slice_before: Returns a new \Enumerator whose entries are a partition of +self+,
+ based either on a given +object+ or a given block.
+ * - #slice_when: Returns a new \Enumerator whose entries are a partition of +self+
+ based on the given block.
* - #chunk: Returns elements organized into chunks as specified by the given block.
* - #chunk_while: Returns elements organized into chunks as specified by the given block.
*
@@ -5040,18 +4849,18 @@ enum_compact(VALUE obj)
*
* Virtually all methods in \Enumerable call method +#each+ in the including class:
*
- * - <tt>Hash#each</tt> yields the next key-value pair as a 2-element Array.
- * - <tt>Struct#each</tt> yields the next name-value pair as a 2-element Array.
+ * - <tt>Hash#each</tt> yields the next key-value pair as a 2-element \Array.
+ * - <tt>Struct#each</tt> yields the next name-value pair as a 2-element \Array.
* - For the other classes above, +#each+ yields the next object from the collection.
*
* == About the Examples
*
* The example code snippets for the \Enumerable methods:
*
- * - Always show the use of one or more Array-like classes (often Array itself).
- * - Sometimes show the use of a Hash-like class.
+ * - Always show the use of one or more \Array-like classes (often \Array itself).
+ * - Sometimes show the use of a \Hash-like class.
* For some methods, though, the usage would not make sense,
- * and so it is not shown. Example: #tally would find exactly one of each Hash entry.
+ * and so it is not shown. Example: #tally would find exactly one of each \Hash entry.
*
*/
diff --git a/enumerator.c b/enumerator.c
index 0e010c14c2..d587b63d32 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -73,7 +73,7 @@
* puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
* # => ["0:foo", "1:bar", "2:baz"]
*
- * == External Iteration
+ * == External Iteration
*
* An Enumerator can also be used as an external iterator.
* For example, Enumerator#next returns the next value of the iterator
@@ -85,31 +85,26 @@
* puts e.next # => 3
* puts e.next # raises StopIteration
*
- * +next+, +next_values+, +peek+, and +peek_values+ are the only methods
- * which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+ internally).
+ * +next+, +next_values+, +peek+ and +peek_values+ are the only methods
+ * which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+).
*
* These methods do not affect other internal enumeration methods,
* unless the underlying iteration method itself has side-effect, e.g. IO#each_line.
*
- * FrozenError will be raised if these methods are called against a frozen enumerator.
- * Since +rewind+ and +feed+ also change state for external iteration,
- * these methods may raise FrozenError too.
- *
* External iteration differs *significantly* from internal iteration
* due to using a Fiber:
- * - The Fiber adds some overhead compared to internal enumeration.
- * - The stacktrace will only include the stack from the Enumerator, not above.
- * - Fiber-local variables are *not* inherited inside the Enumerator Fiber,
- * which instead starts with no Fiber-local variables.
- * - Fiber storage variables *are* inherited and are designed
- * to handle Enumerator Fibers. Assigning to a Fiber storage variable
- * only affects the current Fiber, so if you want to change state
- * in the caller Fiber of the Enumerator Fiber, you need to use an
- * extra indirection (e.g., use some object in the Fiber storage
- * variable and mutate some ivar of it).
+ * - The Fiber adds some overhead compared to internal enumeration.
+ * - The stacktrace will only include the stack from the Enumerator, not above.
+ * - Fiber-local variables are *not* inherited inside the Enumerator Fiber,
+ * which instead starts with no Fiber-local variables.
+ * - Fiber storage variables *are* inherited and are designed
+ * to handle Enumerator Fibers. Assigning to a Fiber storage variable
+ * only affects the current Fiber, so if you want to change state
+ * in the caller Fiber of the Enumerator Fiber, you need to use an
+ * extra indirection (e.g., use some object in the Fiber storage
+ * variable and mutate some ivar of it).
*
* Concretely:
- *
* Thread.current[:fiber_local] = 1
* Fiber[:storage_var] = 1
* e = Enumerator.new do |y|
@@ -125,7 +120,7 @@
* e.each { p _1 }
* p Fiber[:storage_var] # => 2 (it ran in the same Fiber/"stack" as the current Fiber)
*
- * == Convert External Iteration to Internal Iteration
+ * == Convert External Iteration to Internal Iteration
*
* You can use an external iterator to implement an internal iterator as follows:
*
@@ -195,18 +190,6 @@ struct enumerator {
int kw_splat;
};
-RUBY_REFERENCES_START(enumerator_refs)
- REF_EDGE(enumerator, obj),
- REF_EDGE(enumerator, args),
- REF_EDGE(enumerator, fib),
- REF_EDGE(enumerator, dst),
- REF_EDGE(enumerator, lookahead),
- REF_EDGE(enumerator, feedvalue),
- REF_EDGE(enumerator, stop_exc),
- REF_EDGE(enumerator, size),
- REF_EDGE(enumerator, procs),
-RUBY_REFERENCES_END
-
static VALUE rb_cGenerator, rb_cYielder, rb_cEnumProducer;
struct generator {
@@ -256,6 +239,39 @@ struct enum_product {
VALUE rb_cArithSeq;
+/*
+ * Enumerator
+ */
+static void
+enumerator_mark(void *p)
+{
+ struct enumerator *ptr = p;
+ rb_gc_mark_movable(ptr->obj);
+ rb_gc_mark_movable(ptr->args);
+ rb_gc_mark_movable(ptr->fib);
+ rb_gc_mark_movable(ptr->dst);
+ rb_gc_mark_movable(ptr->lookahead);
+ rb_gc_mark_movable(ptr->feedvalue);
+ rb_gc_mark_movable(ptr->stop_exc);
+ rb_gc_mark_movable(ptr->size);
+ rb_gc_mark_movable(ptr->procs);
+}
+
+static void
+enumerator_compact(void *p)
+{
+ struct enumerator *ptr = p;
+ ptr->obj = rb_gc_location(ptr->obj);
+ ptr->args = rb_gc_location(ptr->args);
+ ptr->fib = rb_gc_location(ptr->fib);
+ ptr->dst = rb_gc_location(ptr->dst);
+ ptr->lookahead = rb_gc_location(ptr->lookahead);
+ ptr->feedvalue = rb_gc_location(ptr->feedvalue);
+ ptr->stop_exc = rb_gc_location(ptr->stop_exc);
+ ptr->size = rb_gc_location(ptr->size);
+ ptr->procs = rb_gc_location(ptr->procs);
+}
+
#define enumerator_free RUBY_TYPED_DEFAULT_FREE
static size_t
@@ -267,12 +283,12 @@ enumerator_memsize(const void *p)
static const rb_data_type_t enumerator_data_type = {
"enumerator",
{
- REFS_LIST_PTR(enumerator_refs),
+ enumerator_mark,
enumerator_free,
enumerator_memsize,
- NULL,
+ enumerator_compact,
},
- 0, NULL, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct enumerator *
@@ -873,8 +889,6 @@ enumerator_next_values(VALUE obj)
struct enumerator *e = enumerator_ptr(obj);
VALUE vs;
- rb_check_frozen(obj);
-
if (!UNDEF_P(e->lookahead)) {
vs = e->lookahead;
e->lookahead = Qundef;
@@ -936,8 +950,6 @@ enumerator_peek_values(VALUE obj)
{
struct enumerator *e = enumerator_ptr(obj);
- rb_check_frozen(obj);
-
if (UNDEF_P(e->lookahead)) {
e->lookahead = get_next_values(obj, e);
}
@@ -1062,8 +1074,6 @@ enumerator_feed(VALUE obj, VALUE v)
{
struct enumerator *e = enumerator_ptr(obj);
- rb_check_frozen(obj);
-
if (!UNDEF_P(e->feedvalue)) {
rb_raise(rb_eTypeError, "feed value already set");
}
@@ -1086,8 +1096,6 @@ enumerator_rewind(VALUE obj)
{
struct enumerator *e = enumerator_ptr(obj);
- rb_check_frozen(obj);
-
rb_check_funcall(e->obj, id_rewind, 0, 0);
e->fib = 0;
@@ -2392,6 +2400,7 @@ lazy_zip_arrays_func(VALUE proc_entry, struct MEMO *result, VALUE memos, long me
rb_ary_push(ary, rb_ary_entry(RARRAY_AREF(arrays, i), count));
}
LAZY_MEMO_SET_VALUE(result, ary);
+ LAZY_MEMO_SET_PACKED(result);
rb_ary_store(memos, memo_index, LONG2NUM(++count));
return result;
}
diff --git a/error.c b/error.c
index 041ab834f3..726f57a4c0 100644
--- a/error.c
+++ b/error.c
@@ -23,10 +23,6 @@
# include <unistd.h>
#endif
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
#if defined __APPLE__
# include <AvailabilityMacros.h>
#endif
@@ -38,14 +34,12 @@
#include "internal/io.h"
#include "internal/load.h"
#include "internal/object.h"
-#include "internal/process.h"
#include "internal/string.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "ruby/encoding.h"
#include "ruby/st.h"
-#include "ruby/util.h"
#include "ruby_assert.h"
#include "vm_core.h"
@@ -83,7 +77,6 @@ static ID id_warn;
static ID id_category;
static ID id_deprecated;
static ID id_experimental;
-static ID id_performance;
static VALUE sym_category;
static VALUE sym_highlight;
static struct {
@@ -155,8 +148,8 @@ rb_syntax_error_append(VALUE exc, VALUE file, int line, int column,
}
static unsigned int warning_disabled_categories = (
- (1U << RB_WARN_CATEGORY_DEPRECATED) |
- ~RB_WARN_CATEGORY_DEFAULT_BITS);
+ 1U << RB_WARN_CATEGORY_DEPRECATED |
+ 0);
static unsigned int
rb_warning_category_mask(VALUE category)
@@ -194,7 +187,7 @@ rb_warning_category_update(unsigned int mask, unsigned int bits)
warning_disabled_categories |= mask & ~bits;
}
-bool
+MJIT_FUNC_EXPORTED bool
rb_warning_category_enabled_p(rb_warning_category_t category)
{
return !(warning_disabled_categories & (1U << category));
@@ -207,19 +200,14 @@ rb_warning_category_enabled_p(rb_warning_category_t category)
* Returns the flag to show the warning messages for +category+.
* Supported categories are:
*
- * +:deprecated+ ::
- * deprecation warnings
- * * assignment of non-nil value to <code>$,</code> and <code>$;</code>
- * * keyword arguments
- * etc.
- *
- * +:experimental+ ::
- * experimental features
- * * Pattern matching
+ * +:deprecated+ :: deprecation warnings
+ * * assignment of non-nil value to <code>$,</code> and <code>$;</code>
+ * * keyword arguments
+ * * proc/lambda without block
+ * etc.
*
- * +:performance+ ::
- * performance hints
- * * Shape variation limit
+ * +:experimental+ :: experimental features
+ * * Pattern matching
*/
static VALUE
@@ -432,7 +420,7 @@ rb_warn(const char *fmt, ...)
void
rb_category_warn(rb_warning_category_t category, const char *fmt, ...)
{
- if (!NIL_P(ruby_verbose)) {
+ if (!NIL_P(ruby_verbose) && rb_warning_category_enabled_p(category)) {
with_warning_string(mesg, 0, fmt) {
rb_warn_category(mesg, rb_warning_category_to_name(category));
}
@@ -464,7 +452,7 @@ rb_warning(const char *fmt, ...)
void
rb_category_warning(rb_warning_category_t category, const char *fmt, ...)
{
- if (RTEST(ruby_verbose)) {
+ if (RTEST(ruby_verbose) && rb_warning_category_enabled_p(category)) {
with_warning_string(mesg, 0, fmt) {
rb_warn_category(mesg, rb_warning_category_to_name(category));
}
@@ -628,239 +616,18 @@ rb_bug_reporter_add(void (*func)(FILE *, void *), void *data)
return 1;
}
-/* returns true if x can not be used as file name */
-static bool
-path_sep_p(char x)
-{
-#if defined __CYGWIN__ || defined DOSISH
-# define PATH_SEP_ENCODING 1
- // Assume that "/" is only the first byte in any encoding.
- if (x == ':') return true; // drive letter or ADS
- if (x == '\\') return true;
-#endif
- return x == '/';
-}
-
-struct path_string {
- const char *ptr;
- size_t len;
-};
-
-static const char PATHSEP_REPLACE = '!';
-
-static char *
-append_pathname(char *p, const char *pe, VALUE str)
-{
-#ifdef PATH_SEP_ENCODING
- rb_encoding *enc = rb_enc_get(str);
-#endif
- const char *s = RSTRING_PTR(str);
- const char *const se = s + RSTRING_LEN(str);
- char c;
-
- --pe; // for terminator
-
- while (p < pe && s < se && (c = *s) != '\0') {
- if (c == '.') {
- if (s == se || !*s) break; // chomp "." basename
- if (path_sep_p(s[1])) goto skipsep; // skip "./"
- }
- else if (path_sep_p(c)) {
- // squeeze successive separators
- *p++ = PATHSEP_REPLACE;
- skipsep:
- while (++s < se && path_sep_p(*s));
- continue;
- }
- const char *const ss = s;
- while (p < pe && s < se && *s && !path_sep_p(*s)) {
-#ifdef PATH_SEP_ENCODING
- int n = rb_enc_mbclen(s, se, enc);
-#else
- const int n = 1;
-#endif
- p += n;
- s += n;
- }
- if (s > ss) memcpy(p - (s - ss), ss, s - ss);
- }
-
- return p;
-}
-
-static char *
-append_basename(char *p, const char *pe, struct path_string *path, VALUE str)
-{
- if (!path->ptr) {
-#ifdef PATH_SEP_ENCODING
- rb_encoding *enc = rb_enc_get(str);
-#endif
- const char *const b = RSTRING_PTR(str), *const e = RSTRING_END(str), *p = e;
-
- while (p > b) {
- if (path_sep_p(p[-1])) {
-#ifdef PATH_SEP_ENCODING
- const char *t = rb_enc_prev_char(b, p, e, enc);
- if (t == p-1) break;
- p = t;
-#else
- break;
-#endif
- }
- else {
- --p;
- }
- }
-
- path->ptr = p;
- path->len = e - p;
- }
- size_t n = path->len;
- if (p + n > pe) n = pe - p;
- memcpy(p, path->ptr, n);
- return p + n;
-}
-
-static void
-finish_report(FILE *out, rb_pid_t pid)
-{
- if (out != stdout && out != stderr) fclose(out);
-#ifdef HAVE_WORKING_FORK
- if (pid > 0) waitpid(pid, NULL, 0);
-#endif
-}
-
-struct report_expansion {
- struct path_string exe, script;
- rb_pid_t pid;
- time_t time;
-};
-
-/*
- * Open a bug report file to write. The `RUBY_CRASH_REPORT`
- * environment variable can be set to define a template that is used
- * to name bug report files. The template can contain % specifiers
- * which are substituted by the following values when a bug report
- * file is created:
- *
- * %% A single % character.
- * %e The base name of the executable filename.
- * %E Pathname of executable, with slashes ('/') replaced by
- * exclamation marks ('!').
- * %f Similar to %e with the main script filename.
- * %F Similar to %E with the main script filename.
- * %p PID of dumped process in decimal.
- * %t Time of dump, expressed as seconds since the Epoch,
- * 1970-01-01 00:00:00 +0000 (UTC).
- * %NNN Octal char code, upto 3 digits.
- */
-static char *
-expand_report_argument(const char **input_template, struct report_expansion *values,
- char *buf, size_t size, bool word)
-{
- char *p = buf;
- char *end = buf + size;
- const char *template = *input_template;
- bool store = true;
-
- if (p >= end-1 || !*template) return NULL;
- do {
- char c = *template++;
- if (word && ISSPACE(c)) break;
- if (!store) continue;
- if (c == '%') {
- size_t n;
- switch (c = *template++) {
- case 'e':
- p = append_basename(p, end, &values->exe, rb_argv0);
- continue;
- case 'E':
- p = append_pathname(p, end, rb_argv0);
- continue;
- case 'f':
- p = append_basename(p, end, &values->script, GET_VM()->orig_progname);
- continue;
- case 'F':
- p = append_pathname(p, end, GET_VM()->orig_progname);
- continue;
- case 'p':
- if (!values->pid) values->pid = getpid();
- snprintf(p, end-p, "%" PRI_PIDT_PREFIX "d", values->pid);
- p += strlen(p);
- continue;
- case 't':
- if (!values->time) values->time = time(NULL);
- snprintf(p, end-p, "%" PRI_TIMET_PREFIX "d", values->time);
- p += strlen(p);
- continue;
- default:
- if (c >= '0' && c <= '7') {
- c = (unsigned char)ruby_scan_oct(template-1, 3, &n);
- template += n - 1;
- if (!c) store = false;
- }
- break;
- }
- }
- if (p < end-1) *p++ = c;
- } while (*template);
- *input_template = template;
- *p = '\0';
- return ++p;
-}
-
-FILE *ruby_popen_writer(char *const *argv, rb_pid_t *pid);
-
-static FILE *
-open_report_path(const char *template, char *buf, size_t size, rb_pid_t *pid)
-{
- struct report_expansion values = {{0}};
-
- if (!template) return NULL;
- if (0) fprintf(stderr, "RUBY_CRASH_REPORT=%s\n", buf);
- if (*template == '|') {
- char *argv[16], *bufend = buf + size, *p;
- int argc;
- template++;
- for (argc = 0; argc < numberof(argv) - 1; ++argc) {
- while (*template && ISSPACE(*template)) template++;
- p = expand_report_argument(&template, &values, buf, bufend-buf, true);
- if (!p) break;
- argv[argc] = buf;
- buf = p;
- }
- argv[argc] = NULL;
- if (!p) return ruby_popen_writer(argv, pid);
- }
- else if (*template) {
- expand_report_argument(&template, &values, buf, size, false);
- return fopen(buf, "w");
- }
- return NULL;
-}
-
-static const char *crash_report;
-
/* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */
#define REPORT_BUG_BUFSIZ 256
static FILE *
-bug_report_file(const char *file, int line, rb_pid_t *pid)
+bug_report_file(const char *file, int line)
{
char buf[REPORT_BUG_BUFSIZ];
- const char *report = crash_report;
- if (!report) report = getenv("RUBY_CRASH_REPORT");
- FILE *out = open_report_path(report, buf, sizeof(buf), pid);
+ FILE *out = stderr;
int len = err_position_0(buf, sizeof(buf), file, line);
- if (out) {
- if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len) return out;
- fclose(out);
- }
- if ((ssize_t)fwrite(buf, 1, len, stderr) == (ssize_t)len) {
- return stderr;
- }
- if ((ssize_t)fwrite(buf, 1, len, stdout) == (ssize_t)len) {
- return stdout;
+ if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len ||
+ (ssize_t)fwrite(buf, 1, len, (out = stdout)) == (ssize_t)len) {
+ return out;
}
return NULL;
@@ -967,7 +734,7 @@ bug_report_begin_valist(FILE *out, const char *fmt, va_list args)
} while (0)
static void
-bug_report_end(FILE *out, rb_pid_t pid)
+bug_report_end(FILE *out)
{
/* call additional bug reporters */
{
@@ -978,45 +745,26 @@ bug_report_end(FILE *out, rb_pid_t pid)
}
}
postscript_dump(out);
- finish_report(out, pid);
}
#define report_bug(file, line, fmt, ctx) do { \
- rb_pid_t pid = -1; \
- FILE *out = bug_report_file(file, line, &pid); \
+ FILE *out = bug_report_file(file, line); \
if (out) { \
bug_report_begin(out, fmt); \
- rb_vm_bugreport(ctx, out); \
- bug_report_end(out, pid); \
+ rb_vm_bugreport(ctx); \
+ bug_report_end(out); \
} \
} while (0) \
#define report_bug_valist(file, line, fmt, ctx, args) do { \
- rb_pid_t pid = -1; \
- FILE *out = bug_report_file(file, line, &pid); \
+ FILE *out = bug_report_file(file, line); \
if (out) { \
bug_report_begin_valist(out, fmt, args); \
- rb_vm_bugreport(ctx, out); \
- bug_report_end(out, pid); \
+ rb_vm_bugreport(ctx); \
+ bug_report_end(out); \
} \
} while (0) \
-void
-ruby_set_crash_report(const char *template)
-{
- crash_report = template;
-#if RUBY_DEBUG
- rb_pid_t pid = -1;
- char buf[REPORT_BUG_BUFSIZ];
- FILE *out = open_report_path(template, buf, sizeof(buf), &pid);
- if (out) {
- time_t t = time(NULL);
- fprintf(out, "ruby_test_bug_report: %s", ctime(&t));
- finish_report(out, pid);
- }
-#endif
-}
-
NORETURN(static void die(void));
static void
die(void)
@@ -1119,7 +867,7 @@ rb_report_bug_valist(VALUE file, int line, const char *fmt, va_list args)
report_bug_valist(RSTRING_PTR(file), line, fmt, NULL, args);
}
-void
+MJIT_FUNC_EXPORTED void
rb_assert_failure(const char *file, int line, const char *name, const char *expr)
{
FILE *out = stderr;
@@ -1127,8 +875,8 @@ rb_assert_failure(const char *file, int line, const char *name, const char *expr
if (name) fprintf(out, "%s:", name);
fprintf(out, "%s\n%s\n\n", expr, rb_dynamic_description);
preface_dump(out);
- rb_vm_bugreport(NULL, out);
- bug_report_end(out, -1);
+ rb_vm_bugreport(NULL);
+ bug_report_end(out);
die();
}
@@ -1322,7 +1070,7 @@ rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
actual = rb_str_new_cstr(name); /* or rb_fstring_cstr? not sure... */
}
else {
- return RTYPEDDATA_GET_DATA(obj);
+ return DATA_PTR(obj);
}
const char *expected = data_type->wrap_struct_name;
@@ -1834,7 +1582,7 @@ exc_set_backtrace(VALUE exc, VALUE bt)
return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt));
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_exc_set_backtrace(VALUE exc, VALUE bt)
{
return exc_set_backtrace(exc, bt);
@@ -2319,84 +2067,44 @@ name_err_mesg_to_str(VALUE obj)
mesg = ptr[NAME_ERR_MESG__MESG];
if (NIL_P(mesg)) return Qnil;
else {
- struct RString s_str, c_str, d_str;
- VALUE c, s, d = 0, args[4], c2;
- int state = 0;
+ struct RString s_str, d_str;
+ VALUE c, s, d = 0, args[4];
+ int state = 0, singleton = 0;
rb_encoding *usascii = rb_usascii_encoding();
#define FAKE_CSTR(v, str) rb_setup_fake_str((v), (str), rb_strlen_lit(str), usascii)
- c = s = FAKE_CSTR(&s_str, "");
obj = ptr[NAME_ERR_MESG__RECV];
switch (obj) {
case Qnil:
- c = d = FAKE_CSTR(&d_str, "nil");
+ d = FAKE_CSTR(&d_str, "nil");
break;
case Qtrue:
- c = d = FAKE_CSTR(&d_str, "true");
+ d = FAKE_CSTR(&d_str, "true");
break;
case Qfalse:
- c = d = FAKE_CSTR(&d_str, "false");
+ d = FAKE_CSTR(&d_str, "false");
break;
default:
- if (strstr(RSTRING_PTR(mesg), "%2$s")) {
- d = rb_protect(name_err_mesg_receiver_name, obj, &state);
- if (state || NIL_OR_UNDEF_P(d))
- d = rb_protect(rb_inspect, obj, &state);
- if (state) {
- rb_set_errinfo(Qnil);
- }
- d = rb_check_string_type(d);
- if (NIL_P(d)) {
- d = rb_any_to_s(obj);
- }
- }
-
- if (!RB_SPECIAL_CONST_P(obj)) {
- switch (RB_BUILTIN_TYPE(obj)) {
- case T_MODULE:
- s = FAKE_CSTR(&s_str, "module ");
- c = obj;
- break;
- case T_CLASS:
- s = FAKE_CSTR(&s_str, "class ");
- c = obj;
- break;
- default:
- goto object;
- }
- }
- else {
- VALUE klass;
- object:
- klass = CLASS_OF(obj);
- if (RB_TYPE_P(klass, T_CLASS) && FL_TEST(klass, FL_SINGLETON)) {
- s = FAKE_CSTR(&s_str, "");
- if (obj == rb_vm_top_self()) {
- c = FAKE_CSTR(&c_str, "main");
- }
- else {
- c = rb_any_to_s(obj);
- }
- break;
- }
- else {
- s = FAKE_CSTR(&s_str, "an instance of ");
- c = rb_class_real(klass);
- }
- }
- c2 = rb_protect(name_err_mesg_receiver_name, c, &state);
- if (state || NIL_OR_UNDEF_P(c2))
- c2 = rb_protect(rb_inspect, c, &state);
+ d = rb_protect(name_err_mesg_receiver_name, obj, &state);
+ if (state || NIL_OR_UNDEF_P(d))
+ d = rb_protect(rb_inspect, obj, &state);
if (state) {
rb_set_errinfo(Qnil);
}
- c2 = rb_check_string_type(c2);
- if (NIL_P(c2)) {
- c2 = rb_any_to_s(c);
+ d = rb_check_string_type(d);
+ if (NIL_P(d)) {
+ d = rb_any_to_s(obj);
}
- c = c2;
+ singleton = (RSTRING_LEN(d) > 0 && RSTRING_PTR(d)[0] == '#');
break;
}
+ if (!singleton) {
+ s = FAKE_CSTR(&s_str, ":");
+ c = rb_class_name(CLASS_OF(obj));
+ }
+ else {
+ c = s = FAKE_CSTR(&s_str, "");
+ }
args[0] = rb_obj_as_string(ptr[NAME_ERR_MESG__NAME]);
args[1] = d;
args[2] = s;
@@ -3401,7 +3109,6 @@ Init_Exception(void)
id_category = rb_intern_const("category");
id_deprecated = rb_intern_const("deprecated");
id_experimental = rb_intern_const("experimental");
- id_performance = rb_intern_const("performance");
id_top = rb_intern_const("top");
id_bottom = rb_intern_const("bottom");
id_iseq = rb_make_internal_id();
@@ -3413,13 +3120,11 @@ Init_Exception(void)
warning_categories.id2enum = rb_init_identtable();
st_add_direct(warning_categories.id2enum, id_deprecated, RB_WARN_CATEGORY_DEPRECATED);
st_add_direct(warning_categories.id2enum, id_experimental, RB_WARN_CATEGORY_EXPERIMENTAL);
- st_add_direct(warning_categories.id2enum, id_performance, RB_WARN_CATEGORY_PERFORMANCE);
warning_categories.enum2id = rb_init_identtable();
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_NONE, 0);
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_DEPRECATED, id_deprecated);
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_EXPERIMENTAL, id_experimental);
- st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_PERFORMANCE, id_performance);
}
void
@@ -3502,7 +3207,7 @@ rb_fatal(const char *fmt, ...)
/* The thread has no GVL. Object allocation impossible (cant run GC),
* thus no message can be printed out. */
fprintf(stderr, "[FATAL] rb_fatal() outside of GVL\n");
- rb_print_backtrace(stderr);
+ rb_print_backtrace();
die();
}
@@ -3565,14 +3270,12 @@ rb_syserr_fail_str(int e, VALUE mesg)
rb_exc_raise(rb_syserr_new_str(e, mesg));
}
-#undef rb_sys_fail
void
rb_sys_fail(const char *mesg)
{
rb_exc_raise(make_errno_exc(mesg));
}
-#undef rb_sys_fail_str
void
rb_sys_fail_str(VALUE mesg)
{
diff --git a/eval.c b/eval.c
index be450a02f5..a61dfb1289 100644
--- a/eval.c
+++ b/eval.c
@@ -18,12 +18,12 @@
#endif
#include "eval_intern.h"
+#include "gc.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/cont.h"
#include "internal/error.h"
#include "internal/eval.h"
-#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/inits.h"
#include "internal/io.h"
@@ -32,7 +32,7 @@
#include "internal/variable.h"
#include "ruby/fiber/scheduler.h"
#include "iseq.h"
-#include "rjit.h"
+#include "mjit.h"
#include "probes.h"
#include "probes_helper.h"
#include "ruby/vm.h"
@@ -257,6 +257,8 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex)
}
}
+ mjit_finish(true); // We still need ISeqs here, so it's before rb_ec_finalize().
+
rb_ec_finalize(ec);
/* unlock again if finalizer took mutexes. */
@@ -439,7 +441,7 @@ rb_class_modify_check(VALUE klass)
if (FL_TEST(klass, FL_SINGLETON)) {
desc = "object";
- klass = RCLASS_ATTACHED_OBJECT(klass);
+ klass = rb_ivar_get(klass, id__attached__);
if (!SPECIAL_CONST_P(klass)) {
switch (BUILTIN_TYPE(klass)) {
case T_MODULE:
@@ -1341,14 +1343,14 @@ rb_using_module(const rb_cref_t *cref, VALUE module)
{
Check_Type(module, T_MODULE);
using_module_recursive(cref, module);
- rb_clear_all_refinement_method_cache();
+ rb_clear_method_cache_all();
}
/*
* call-seq:
- * target -> class
+ * refined_class -> class
*
- * Return the class or module refined by the receiver.
+ * Return the class refined by the receiver.
*/
VALUE
rb_refinement_module_get_refined_class(VALUE module)
@@ -1359,19 +1361,6 @@ rb_refinement_module_get_refined_class(VALUE module)
return rb_attr_get(module, id_refined_class);
}
-/*
- * call-seq:
- * refined_class -> class
- *
- * Return the class refined by the receiver.
- */
-static VALUE
-rb_refinement_refined_class(VALUE module)
-{
- rb_warn_deprecated_to_remove("3.4", "Refinement#refined_class", "Refinement#target");
- return rb_refinement_module_get_refined_class(module);
-}
-
static void
add_activated_refinement(VALUE activated_refinements,
VALUE klass, VALUE refinement)
@@ -1788,6 +1777,16 @@ rb_obj_extend(int argc, VALUE *argv, VALUE obj)
return obj;
}
+VALUE
+rb_top_main_class(const char *method)
+{
+ VALUE klass = GET_THREAD()->top_wrapper;
+
+ if (!klass) return rb_cObject;
+ rb_warning("main.%s in the wrapped load is effective only in wrapper module", method);
+ return klass;
+}
+
/*
* call-seq:
* include(module, ...) -> self
@@ -1800,13 +1799,7 @@ rb_obj_extend(int argc, VALUE *argv, VALUE obj)
static VALUE
top_include(int argc, VALUE *argv, VALUE self)
{
- rb_thread_t *th = GET_THREAD();
-
- if (th->top_wrapper) {
- rb_warning("main.include in the wrapped load is effective only in wrapper module");
- return rb_mod_include(argc, argv, th->top_wrapper);
- }
- return rb_mod_include(argc, argv, rb_cObject);
+ return rb_mod_include(argc, argv, rb_top_main_class("include"));
}
/*
@@ -2080,8 +2073,7 @@ Init_eval(void)
rb_mod_s_used_refinements, 0);
rb_undef_method(rb_cClass, "refine");
rb_define_private_method(rb_cRefinement, "import_methods", refinement_import_methods, -1);
- rb_define_method(rb_cRefinement, "target", rb_refinement_module_get_refined_class, 0);
- rb_define_method(rb_cRefinement, "refined_class", rb_refinement_refined_class, 0);
+ rb_define_method(rb_cRefinement, "refined_class", rb_refinement_module_get_refined_class, 0);
rb_undef_method(rb_cRefinement, "append_features");
rb_undef_method(rb_cRefinement, "prepend_features");
rb_undef_method(rb_cRefinement, "extend_object");
@@ -2110,21 +2102,3 @@ Init_eval(void)
id_signo = rb_intern_const("signo");
id_status = rb_intern_const("status");
}
-
-int
-rb_errno(void)
-{
- return *rb_orig_errno_ptr();
-}
-
-void
-rb_errno_set(int e)
-{
- *rb_orig_errno_ptr() = e;
-}
-
-int *
-rb_errno_ptr(void)
-{
- return rb_orig_errno_ptr();
-}
diff --git a/eval_error.c b/eval_error.c
index bdce295f6e..9806683000 100644
--- a/eval_error.c
+++ b/eval_error.c
@@ -7,8 +7,6 @@
(NIL_P(str) ? warn_print(x) : (void)rb_str_cat_cstr(str, x))
#define write_warn2(str, x, l) \
(NIL_P(str) ? warn_print2(x, l) : (void)rb_str_cat(str, x, l))
-#define write_warn_enc(str, x, l, enc) \
- (NIL_P(str) ? warn_print2(x, l) : (void)rb_enc_str_buf_cat(str, x, l, enc))
#ifdef HAVE_BUILTIN___BUILTIN_CONSTANT_P
#define warn_print(x) RB_GNUC_EXTENSION_BLOCK( \
(__builtin_constant_p(x)) ? \
@@ -105,7 +103,7 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA
if (highlight) write_warn(str, underline);
write_warn(str, "unhandled exception");
if (highlight) write_warn(str, reset);
- write_warn(str, "\n");
+ write_warn2(str, "\n", 1);
}
else {
VALUE epath;
@@ -129,17 +127,13 @@ rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight)
{
const char *einfo = "";
long elen = 0;
- rb_encoding *eenc;
- VALUE str = rb_usascii_str_new_cstr("");
+ VALUE str = rb_str_new2("");
- if (!NIL_P(emesg) && rb_enc_asciicompat(eenc = rb_enc_get(emesg))) {
+ if (!NIL_P(emesg)) {
einfo = RSTRING_PTR(emesg);
elen = RSTRING_LEN(emesg);
}
- else {
- eenc = NULL;
- }
if (eclass == rb_eRuntimeError && elen == 0) {
if (highlight) write_warn(str, underline);
write_warn(str, "unhandled exception");
@@ -162,7 +156,7 @@ rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight)
if (RSTRING_PTR(epath)[0] == '#')
epath = 0;
if ((tail = memchr(einfo, '\n', elen)) != 0) {
- write_warn_enc(str, einfo, tail - einfo, eenc);
+ write_warn2(str, einfo, tail - einfo);
tail++; /* skip newline */
}
else {
@@ -176,23 +170,23 @@ rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight)
write_warn(str, reset);
write_warn(str, bold);
}
- write_warn(str, ")");
+ write_warn2(str, ")", 1);
if (highlight) write_warn(str, reset);
}
if (tail && einfo+elen > tail) {
if (!highlight) {
- write_warn(str, "\n");
- write_warn_enc(str, tail, einfo+elen-tail, eenc);
+ write_warn2(str, "\n", 1);
+ write_warn2(str, tail, einfo+elen-tail);
}
else {
elen -= tail - einfo;
einfo = tail;
- write_warn(str, "\n");
+ write_warn2(str, "\n", 1);
while (elen > 0) {
tail = memchr(einfo, '\n', elen);
if (!tail || tail > einfo) {
write_warn(str, bold);
- write_warn_enc(str, einfo, tail ? tail-einfo : elen, eenc);
+ write_warn2(str, einfo, tail ? tail-einfo : elen);
write_warn(str, reset);
if (!tail) {
break;
@@ -201,7 +195,7 @@ rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight)
elen -= tail - einfo;
einfo = tail;
do ++tail; while (tail < einfo+elen && *tail == '\n');
- write_warn_enc(str, einfo, tail-einfo, eenc);
+ write_warn2(str, einfo, tail-einfo);
elen -= tail - einfo;
einfo = tail;
}
diff --git a/eval_intern.h b/eval_intern.h
index 778b63e0ea..6cbaa51361 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -151,7 +151,6 @@ rb_ec_tag_state(const rb_execution_context_t *ec)
enum ruby_tag_type state = tag->state;
tag->state = TAG_NONE;
rb_ec_vm_lock_rec_check(ec, tag->lock_rec);
- RBIMPL_ASSUME(state != TAG_NONE);
return state;
}
@@ -159,7 +158,6 @@ NORETURN(static inline void rb_ec_tag_jump(const rb_execution_context_t *ec, enu
static inline void
rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
{
- RUBY_ASSERT(st != TAG_NONE);
ec->tag->state = st;
ruby_longjmp(ec->tag->buf, 1);
}
@@ -169,7 +167,7 @@ rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
[ISO/IEC 9899:1999] 7.13.1.1
*/
#define EC_EXEC_TAG() \
- (UNLIKELY(ruby_setjmp(_tag.buf)) ? rb_ec_tag_state(VAR_FROM_MEMORY(_ec)) : (EC_REPUSH_TAG(), 0))
+ (ruby_setjmp(_tag.buf) ? rb_ec_tag_state(VAR_FROM_MEMORY(_ec)) : (EC_REPUSH_TAG(), 0))
#define EC_JUMP_TAG(ec, st) rb_ec_tag_jump(ec, st)
diff --git a/ext/-test-/RUBY_ALIGNOF/depend b/ext/-test-/RUBY_ALIGNOF/depend
index 3011b637e5..21ef8c6dd0 100644
--- a/ext/-test-/RUBY_ALIGNOF/depend
+++ b/ext/-test-/RUBY_ALIGNOF/depend
@@ -52,7 +52,6 @@ c.o: $(hdrdir)/ruby/internal/attr/noexcept.h
c.o: $(hdrdir)/ruby/internal/attr/noinline.h
c.o: $(hdrdir)/ruby/internal/attr/nonnull.h
c.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-c.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
c.o: $(hdrdir)/ruby/internal/attr/pure.h
c.o: $(hdrdir)/ruby/internal/attr/restrict.h
c.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ c.o: $(hdrdir)/ruby/internal/intern/enumerator.h
c.o: $(hdrdir)/ruby/internal/intern/error.h
c.o: $(hdrdir)/ruby/internal/intern/eval.h
c.o: $(hdrdir)/ruby/internal/intern/file.h
+c.o: $(hdrdir)/ruby/internal/intern/gc.h
c.o: $(hdrdir)/ruby/internal/intern/hash.h
c.o: $(hdrdir)/ruby/internal/intern/io.h
c.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ c.o: $(hdrdir)/ruby/internal/memory.h
c.o: $(hdrdir)/ruby/internal/method.h
c.o: $(hdrdir)/ruby/internal/module.h
c.o: $(hdrdir)/ruby/internal/newobj.h
+c.o: $(hdrdir)/ruby/internal/rgengc.h
c.o: $(hdrdir)/ruby/internal/scan_args.h
c.o: $(hdrdir)/ruby/internal/special_consts.h
c.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/arith_seq/beg_len_step/depend b/ext/-test-/arith_seq/beg_len_step/depend
index dc807eaa99..36a2c4c71b 100644
--- a/ext/-test-/arith_seq/beg_len_step/depend
+++ b/ext/-test-/arith_seq/beg_len_step/depend
@@ -51,7 +51,6 @@ beg_len_step.o: $(hdrdir)/ruby/internal/attr/noexcept.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/noinline.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/nonnull.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-beg_len_step.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/pure.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/restrict.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ beg_len_step.o: $(hdrdir)/ruby/internal/intern/enumerator.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/error.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/eval.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/file.h
+beg_len_step.o: $(hdrdir)/ruby/internal/intern/gc.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/hash.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/io.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ beg_len_step.o: $(hdrdir)/ruby/internal/memory.h
beg_len_step.o: $(hdrdir)/ruby/internal/method.h
beg_len_step.o: $(hdrdir)/ruby/internal/module.h
beg_len_step.o: $(hdrdir)/ruby/internal/newobj.h
+beg_len_step.o: $(hdrdir)/ruby/internal/rgengc.h
beg_len_step.o: $(hdrdir)/ruby/internal/scan_args.h
beg_len_step.o: $(hdrdir)/ruby/internal/special_consts.h
beg_len_step.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/arith_seq/extract/depend b/ext/-test-/arith_seq/extract/depend
index 231736b277..57cbaa9a0c 100644
--- a/ext/-test-/arith_seq/extract/depend
+++ b/ext/-test-/arith_seq/extract/depend
@@ -51,7 +51,6 @@ extract.o: $(hdrdir)/ruby/internal/attr/noexcept.h
extract.o: $(hdrdir)/ruby/internal/attr/noinline.h
extract.o: $(hdrdir)/ruby/internal/attr/nonnull.h
extract.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-extract.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
extract.o: $(hdrdir)/ruby/internal/attr/pure.h
extract.o: $(hdrdir)/ruby/internal/attr/restrict.h
extract.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ extract.o: $(hdrdir)/ruby/internal/intern/enumerator.h
extract.o: $(hdrdir)/ruby/internal/intern/error.h
extract.o: $(hdrdir)/ruby/internal/intern/eval.h
extract.o: $(hdrdir)/ruby/internal/intern/file.h
+extract.o: $(hdrdir)/ruby/internal/intern/gc.h
extract.o: $(hdrdir)/ruby/internal/intern/hash.h
extract.o: $(hdrdir)/ruby/internal/intern/io.h
extract.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ extract.o: $(hdrdir)/ruby/internal/memory.h
extract.o: $(hdrdir)/ruby/internal/method.h
extract.o: $(hdrdir)/ruby/internal/module.h
extract.o: $(hdrdir)/ruby/internal/newobj.h
+extract.o: $(hdrdir)/ruby/internal/rgengc.h
extract.o: $(hdrdir)/ruby/internal/scan_args.h
extract.o: $(hdrdir)/ruby/internal/special_consts.h
extract.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/array/concat/depend b/ext/-test-/array/concat/depend
index d66e7a540f..79c833738e 100644
--- a/ext/-test-/array/concat/depend
+++ b/ext/-test-/array/concat/depend
@@ -52,7 +52,6 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/noinline.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-to_ary_concat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/pure.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/restrict.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/error.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/eval.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/file.h
+to_ary_concat.o: $(hdrdir)/ruby/internal/intern/gc.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/hash.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/io.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/memory.h
to_ary_concat.o: $(hdrdir)/ruby/internal/method.h
to_ary_concat.o: $(hdrdir)/ruby/internal/module.h
to_ary_concat.o: $(hdrdir)/ruby/internal/newobj.h
+to_ary_concat.o: $(hdrdir)/ruby/internal/rgengc.h
to_ary_concat.o: $(hdrdir)/ruby/internal/scan_args.h
to_ary_concat.o: $(hdrdir)/ruby/internal/special_consts.h
to_ary_concat.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/array/resize/depend b/ext/-test-/array/resize/depend
index a9c02b3db2..49e0f346d3 100644
--- a/ext/-test-/array/resize/depend
+++ b/ext/-test-/array/resize/depend
@@ -51,7 +51,6 @@ resize.o: $(hdrdir)/ruby/internal/attr/noexcept.h
resize.o: $(hdrdir)/ruby/internal/attr/noinline.h
resize.o: $(hdrdir)/ruby/internal/attr/nonnull.h
resize.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-resize.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
resize.o: $(hdrdir)/ruby/internal/attr/pure.h
resize.o: $(hdrdir)/ruby/internal/attr/restrict.h
resize.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ resize.o: $(hdrdir)/ruby/internal/intern/enumerator.h
resize.o: $(hdrdir)/ruby/internal/intern/error.h
resize.o: $(hdrdir)/ruby/internal/intern/eval.h
resize.o: $(hdrdir)/ruby/internal/intern/file.h
+resize.o: $(hdrdir)/ruby/internal/intern/gc.h
resize.o: $(hdrdir)/ruby/internal/intern/hash.h
resize.o: $(hdrdir)/ruby/internal/intern/io.h
resize.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ resize.o: $(hdrdir)/ruby/internal/memory.h
resize.o: $(hdrdir)/ruby/internal/method.h
resize.o: $(hdrdir)/ruby/internal/module.h
resize.o: $(hdrdir)/ruby/internal/newobj.h
+resize.o: $(hdrdir)/ruby/internal/rgengc.h
resize.o: $(hdrdir)/ruby/internal/scan_args.h
resize.o: $(hdrdir)/ruby/internal/special_consts.h
resize.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/bignum/depend b/ext/-test-/bignum/depend
index d4392bb6a1..d4072fb35c 100644
--- a/ext/-test-/bignum/depend
+++ b/ext/-test-/bignum/depend
@@ -51,7 +51,6 @@ big2str.o: $(hdrdir)/ruby/internal/attr/noexcept.h
big2str.o: $(hdrdir)/ruby/internal/attr/noinline.h
big2str.o: $(hdrdir)/ruby/internal/attr/nonnull.h
big2str.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-big2str.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
big2str.o: $(hdrdir)/ruby/internal/attr/pure.h
big2str.o: $(hdrdir)/ruby/internal/attr/restrict.h
big2str.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ big2str.o: $(hdrdir)/ruby/internal/intern/enumerator.h
big2str.o: $(hdrdir)/ruby/internal/intern/error.h
big2str.o: $(hdrdir)/ruby/internal/intern/eval.h
big2str.o: $(hdrdir)/ruby/internal/intern/file.h
+big2str.o: $(hdrdir)/ruby/internal/intern/gc.h
big2str.o: $(hdrdir)/ruby/internal/intern/hash.h
big2str.o: $(hdrdir)/ruby/internal/intern/io.h
big2str.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ big2str.o: $(hdrdir)/ruby/internal/memory.h
big2str.o: $(hdrdir)/ruby/internal/method.h
big2str.o: $(hdrdir)/ruby/internal/module.h
big2str.o: $(hdrdir)/ruby/internal/newobj.h
+big2str.o: $(hdrdir)/ruby/internal/rgengc.h
big2str.o: $(hdrdir)/ruby/internal/scan_args.h
big2str.o: $(hdrdir)/ruby/internal/special_consts.h
big2str.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -210,7 +211,6 @@ bigzero.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bigzero.o: $(hdrdir)/ruby/internal/attr/noinline.h
bigzero.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bigzero.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bigzero.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bigzero.o: $(hdrdir)/ruby/internal/attr/pure.h
bigzero.o: $(hdrdir)/ruby/internal/attr/restrict.h
bigzero.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -270,6 +270,7 @@ bigzero.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bigzero.o: $(hdrdir)/ruby/internal/intern/error.h
bigzero.o: $(hdrdir)/ruby/internal/intern/eval.h
bigzero.o: $(hdrdir)/ruby/internal/intern/file.h
+bigzero.o: $(hdrdir)/ruby/internal/intern/gc.h
bigzero.o: $(hdrdir)/ruby/internal/intern/hash.h
bigzero.o: $(hdrdir)/ruby/internal/intern/io.h
bigzero.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -300,6 +301,7 @@ bigzero.o: $(hdrdir)/ruby/internal/memory.h
bigzero.o: $(hdrdir)/ruby/internal/method.h
bigzero.o: $(hdrdir)/ruby/internal/module.h
bigzero.o: $(hdrdir)/ruby/internal/newobj.h
+bigzero.o: $(hdrdir)/ruby/internal/rgengc.h
bigzero.o: $(hdrdir)/ruby/internal/scan_args.h
bigzero.o: $(hdrdir)/ruby/internal/special_consts.h
bigzero.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -369,7 +371,6 @@ div.o: $(hdrdir)/ruby/internal/attr/noexcept.h
div.o: $(hdrdir)/ruby/internal/attr/noinline.h
div.o: $(hdrdir)/ruby/internal/attr/nonnull.h
div.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-div.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
div.o: $(hdrdir)/ruby/internal/attr/pure.h
div.o: $(hdrdir)/ruby/internal/attr/restrict.h
div.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -429,6 +430,7 @@ div.o: $(hdrdir)/ruby/internal/intern/enumerator.h
div.o: $(hdrdir)/ruby/internal/intern/error.h
div.o: $(hdrdir)/ruby/internal/intern/eval.h
div.o: $(hdrdir)/ruby/internal/intern/file.h
+div.o: $(hdrdir)/ruby/internal/intern/gc.h
div.o: $(hdrdir)/ruby/internal/intern/hash.h
div.o: $(hdrdir)/ruby/internal/intern/io.h
div.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -459,6 +461,7 @@ div.o: $(hdrdir)/ruby/internal/memory.h
div.o: $(hdrdir)/ruby/internal/method.h
div.o: $(hdrdir)/ruby/internal/module.h
div.o: $(hdrdir)/ruby/internal/newobj.h
+div.o: $(hdrdir)/ruby/internal/rgengc.h
div.o: $(hdrdir)/ruby/internal/scan_args.h
div.o: $(hdrdir)/ruby/internal/special_consts.h
div.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -529,7 +532,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -589,6 +591,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -619,6 +622,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -687,7 +691,6 @@ intpack.o: $(hdrdir)/ruby/internal/attr/noexcept.h
intpack.o: $(hdrdir)/ruby/internal/attr/noinline.h
intpack.o: $(hdrdir)/ruby/internal/attr/nonnull.h
intpack.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-intpack.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
intpack.o: $(hdrdir)/ruby/internal/attr/pure.h
intpack.o: $(hdrdir)/ruby/internal/attr/restrict.h
intpack.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -747,6 +750,7 @@ intpack.o: $(hdrdir)/ruby/internal/intern/enumerator.h
intpack.o: $(hdrdir)/ruby/internal/intern/error.h
intpack.o: $(hdrdir)/ruby/internal/intern/eval.h
intpack.o: $(hdrdir)/ruby/internal/intern/file.h
+intpack.o: $(hdrdir)/ruby/internal/intern/gc.h
intpack.o: $(hdrdir)/ruby/internal/intern/hash.h
intpack.o: $(hdrdir)/ruby/internal/intern/io.h
intpack.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -777,6 +781,7 @@ intpack.o: $(hdrdir)/ruby/internal/memory.h
intpack.o: $(hdrdir)/ruby/internal/method.h
intpack.o: $(hdrdir)/ruby/internal/module.h
intpack.o: $(hdrdir)/ruby/internal/newobj.h
+intpack.o: $(hdrdir)/ruby/internal/rgengc.h
intpack.o: $(hdrdir)/ruby/internal/scan_args.h
intpack.o: $(hdrdir)/ruby/internal/special_consts.h
intpack.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -846,7 +851,6 @@ mul.o: $(hdrdir)/ruby/internal/attr/noexcept.h
mul.o: $(hdrdir)/ruby/internal/attr/noinline.h
mul.o: $(hdrdir)/ruby/internal/attr/nonnull.h
mul.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-mul.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
mul.o: $(hdrdir)/ruby/internal/attr/pure.h
mul.o: $(hdrdir)/ruby/internal/attr/restrict.h
mul.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -906,6 +910,7 @@ mul.o: $(hdrdir)/ruby/internal/intern/enumerator.h
mul.o: $(hdrdir)/ruby/internal/intern/error.h
mul.o: $(hdrdir)/ruby/internal/intern/eval.h
mul.o: $(hdrdir)/ruby/internal/intern/file.h
+mul.o: $(hdrdir)/ruby/internal/intern/gc.h
mul.o: $(hdrdir)/ruby/internal/intern/hash.h
mul.o: $(hdrdir)/ruby/internal/intern/io.h
mul.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -936,6 +941,7 @@ mul.o: $(hdrdir)/ruby/internal/memory.h
mul.o: $(hdrdir)/ruby/internal/method.h
mul.o: $(hdrdir)/ruby/internal/module.h
mul.o: $(hdrdir)/ruby/internal/newobj.h
+mul.o: $(hdrdir)/ruby/internal/rgengc.h
mul.o: $(hdrdir)/ruby/internal/scan_args.h
mul.o: $(hdrdir)/ruby/internal/special_consts.h
mul.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1005,7 +1011,6 @@ str2big.o: $(hdrdir)/ruby/internal/attr/noexcept.h
str2big.o: $(hdrdir)/ruby/internal/attr/noinline.h
str2big.o: $(hdrdir)/ruby/internal/attr/nonnull.h
str2big.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-str2big.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
str2big.o: $(hdrdir)/ruby/internal/attr/pure.h
str2big.o: $(hdrdir)/ruby/internal/attr/restrict.h
str2big.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1065,6 +1070,7 @@ str2big.o: $(hdrdir)/ruby/internal/intern/enumerator.h
str2big.o: $(hdrdir)/ruby/internal/intern/error.h
str2big.o: $(hdrdir)/ruby/internal/intern/eval.h
str2big.o: $(hdrdir)/ruby/internal/intern/file.h
+str2big.o: $(hdrdir)/ruby/internal/intern/gc.h
str2big.o: $(hdrdir)/ruby/internal/intern/hash.h
str2big.o: $(hdrdir)/ruby/internal/intern/io.h
str2big.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1095,6 +1101,7 @@ str2big.o: $(hdrdir)/ruby/internal/memory.h
str2big.o: $(hdrdir)/ruby/internal/method.h
str2big.o: $(hdrdir)/ruby/internal/module.h
str2big.o: $(hdrdir)/ruby/internal/newobj.h
+str2big.o: $(hdrdir)/ruby/internal/rgengc.h
str2big.o: $(hdrdir)/ruby/internal/scan_args.h
str2big.o: $(hdrdir)/ruby/internal/special_consts.h
str2big.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/bug-14834/depend b/ext/-test-/bug-14834/depend
index bf26a571aa..7bac8409e8 100644
--- a/ext/-test-/bug-14834/depend
+++ b/ext/-test-/bug-14834/depend
@@ -52,7 +52,6 @@ bug-14384.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug-14384.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug-14384.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug-14384.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug-14384.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug-14384.o: $(hdrdir)/ruby/internal/attr/pure.h
bug-14384.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug-14384.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug-14384.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug-14384.o: $(hdrdir)/ruby/internal/intern/error.h
bug-14384.o: $(hdrdir)/ruby/internal/intern/eval.h
bug-14384.o: $(hdrdir)/ruby/internal/intern/file.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/gc.h
bug-14384.o: $(hdrdir)/ruby/internal/intern/hash.h
bug-14384.o: $(hdrdir)/ruby/internal/intern/io.h
bug-14384.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ bug-14384.o: $(hdrdir)/ruby/internal/memory.h
bug-14384.o: $(hdrdir)/ruby/internal/method.h
bug-14384.o: $(hdrdir)/ruby/internal/module.h
bug-14384.o: $(hdrdir)/ruby/internal/newobj.h
+bug-14384.o: $(hdrdir)/ruby/internal/rgengc.h
bug-14384.o: $(hdrdir)/ruby/internal/scan_args.h
bug-14384.o: $(hdrdir)/ruby/internal/special_consts.h
bug-14384.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/bug-3571/depend b/ext/-test-/bug-3571/depend
index 9105093b0d..2303f47594 100644
--- a/ext/-test-/bug-3571/depend
+++ b/ext/-test-/bug-3571/depend
@@ -52,7 +52,6 @@ bug.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug.o: $(hdrdir)/ruby/internal/attr/pure.h
bug.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug.o: $(hdrdir)/ruby/internal/intern/error.h
bug.o: $(hdrdir)/ruby/internal/intern/eval.h
bug.o: $(hdrdir)/ruby/internal/intern/file.h
+bug.o: $(hdrdir)/ruby/internal/intern/gc.h
bug.o: $(hdrdir)/ruby/internal/intern/hash.h
bug.o: $(hdrdir)/ruby/internal/intern/io.h
bug.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ bug.o: $(hdrdir)/ruby/internal/memory.h
bug.o: $(hdrdir)/ruby/internal/method.h
bug.o: $(hdrdir)/ruby/internal/module.h
bug.o: $(hdrdir)/ruby/internal/newobj.h
+bug.o: $(hdrdir)/ruby/internal/rgengc.h
bug.o: $(hdrdir)/ruby/internal/scan_args.h
bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/bug-5832/depend b/ext/-test-/bug-5832/depend
index 9105093b0d..2303f47594 100644
--- a/ext/-test-/bug-5832/depend
+++ b/ext/-test-/bug-5832/depend
@@ -52,7 +52,6 @@ bug.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug.o: $(hdrdir)/ruby/internal/attr/pure.h
bug.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug.o: $(hdrdir)/ruby/internal/intern/error.h
bug.o: $(hdrdir)/ruby/internal/intern/eval.h
bug.o: $(hdrdir)/ruby/internal/intern/file.h
+bug.o: $(hdrdir)/ruby/internal/intern/gc.h
bug.o: $(hdrdir)/ruby/internal/intern/hash.h
bug.o: $(hdrdir)/ruby/internal/intern/io.h
bug.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ bug.o: $(hdrdir)/ruby/internal/memory.h
bug.o: $(hdrdir)/ruby/internal/method.h
bug.o: $(hdrdir)/ruby/internal/module.h
bug.o: $(hdrdir)/ruby/internal/newobj.h
+bug.o: $(hdrdir)/ruby/internal/rgengc.h
bug.o: $(hdrdir)/ruby/internal/scan_args.h
bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/bug_reporter/depend b/ext/-test-/bug_reporter/depend
index 20882708d1..603dd53ebf 100644
--- a/ext/-test-/bug_reporter/depend
+++ b/ext/-test-/bug_reporter/depend
@@ -52,7 +52,6 @@ bug_reporter.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug_reporter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/pure.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug_reporter.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/error.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/eval.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/file.h
+bug_reporter.o: $(hdrdir)/ruby/internal/intern/gc.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/hash.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/io.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ bug_reporter.o: $(hdrdir)/ruby/internal/memory.h
bug_reporter.o: $(hdrdir)/ruby/internal/method.h
bug_reporter.o: $(hdrdir)/ruby/internal/module.h
bug_reporter.o: $(hdrdir)/ruby/internal/newobj.h
+bug_reporter.o: $(hdrdir)/ruby/internal/rgengc.h
bug_reporter.o: $(hdrdir)/ruby/internal/scan_args.h
bug_reporter.o: $(hdrdir)/ruby/internal/special_consts.h
bug_reporter.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/class/depend b/ext/-test-/class/depend
index 0a805f815e..a615eacd74 100644
--- a/ext/-test-/class/depend
+++ b/ext/-test-/class/depend
@@ -51,7 +51,6 @@ class2name.o: $(hdrdir)/ruby/internal/attr/noexcept.h
class2name.o: $(hdrdir)/ruby/internal/attr/noinline.h
class2name.o: $(hdrdir)/ruby/internal/attr/nonnull.h
class2name.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-class2name.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
class2name.o: $(hdrdir)/ruby/internal/attr/pure.h
class2name.o: $(hdrdir)/ruby/internal/attr/restrict.h
class2name.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ class2name.o: $(hdrdir)/ruby/internal/intern/enumerator.h
class2name.o: $(hdrdir)/ruby/internal/intern/error.h
class2name.o: $(hdrdir)/ruby/internal/intern/eval.h
class2name.o: $(hdrdir)/ruby/internal/intern/file.h
+class2name.o: $(hdrdir)/ruby/internal/intern/gc.h
class2name.o: $(hdrdir)/ruby/internal/intern/hash.h
class2name.o: $(hdrdir)/ruby/internal/intern/io.h
class2name.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ class2name.o: $(hdrdir)/ruby/internal/memory.h
class2name.o: $(hdrdir)/ruby/internal/method.h
class2name.o: $(hdrdir)/ruby/internal/module.h
class2name.o: $(hdrdir)/ruby/internal/newobj.h
+class2name.o: $(hdrdir)/ruby/internal/rgengc.h
class2name.o: $(hdrdir)/ruby/internal/scan_args.h
class2name.o: $(hdrdir)/ruby/internal/special_consts.h
class2name.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -210,7 +211,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -270,6 +270,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -300,6 +301,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/debug/depend b/ext/-test-/debug/depend
index 5feeea6d98..c3a0c278aa 100644
--- a/ext/-test-/debug/depend
+++ b/ext/-test-/debug/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ inspector.o: $(hdrdir)/ruby/internal/attr/noexcept.h
inspector.o: $(hdrdir)/ruby/internal/attr/noinline.h
inspector.o: $(hdrdir)/ruby/internal/attr/nonnull.h
inspector.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-inspector.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
inspector.o: $(hdrdir)/ruby/internal/attr/pure.h
inspector.o: $(hdrdir)/ruby/internal/attr/restrict.h
inspector.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ inspector.o: $(hdrdir)/ruby/internal/intern/enumerator.h
inspector.o: $(hdrdir)/ruby/internal/intern/error.h
inspector.o: $(hdrdir)/ruby/internal/intern/eval.h
inspector.o: $(hdrdir)/ruby/internal/intern/file.h
+inspector.o: $(hdrdir)/ruby/internal/intern/gc.h
inspector.o: $(hdrdir)/ruby/internal/intern/hash.h
inspector.o: $(hdrdir)/ruby/internal/intern/io.h
inspector.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ inspector.o: $(hdrdir)/ruby/internal/memory.h
inspector.o: $(hdrdir)/ruby/internal/method.h
inspector.o: $(hdrdir)/ruby/internal/module.h
inspector.o: $(hdrdir)/ruby/internal/newobj.h
+inspector.o: $(hdrdir)/ruby/internal/rgengc.h
inspector.o: $(hdrdir)/ruby/internal/scan_args.h
inspector.o: $(hdrdir)/ruby/internal/special_consts.h
inspector.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -370,7 +372,6 @@ profile_frames.o: $(hdrdir)/ruby/internal/attr/noexcept.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/noinline.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/nonnull.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-profile_frames.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/pure.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/restrict.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -430,6 +431,7 @@ profile_frames.o: $(hdrdir)/ruby/internal/intern/enumerator.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/error.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/eval.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/file.h
+profile_frames.o: $(hdrdir)/ruby/internal/intern/gc.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/hash.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/io.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -460,6 +462,7 @@ profile_frames.o: $(hdrdir)/ruby/internal/memory.h
profile_frames.o: $(hdrdir)/ruby/internal/method.h
profile_frames.o: $(hdrdir)/ruby/internal/module.h
profile_frames.o: $(hdrdir)/ruby/internal/newobj.h
+profile_frames.o: $(hdrdir)/ruby/internal/rgengc.h
profile_frames.o: $(hdrdir)/ruby/internal/scan_args.h
profile_frames.o: $(hdrdir)/ruby/internal/special_consts.h
profile_frames.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/debug/profile_frames.c b/ext/-test-/debug/profile_frames.c
index f9a77a5a78..d2bba7d183 100644
--- a/ext/-test-/debug/profile_frames.c
+++ b/ext/-test-/debug/profile_frames.c
@@ -37,29 +37,8 @@ profile_frames(VALUE self, VALUE start_v, VALUE num_v)
return result;
}
-static VALUE
-profile_thread_frames(VALUE self, VALUE thread, VALUE start_v, VALUE num_v)
-{
- int i, collected_size;
- int start = NUM2INT(start_v);
- int buff_size = NUM2INT(num_v);
- VALUE buff[MAX_BUF_SIZE];
- int lines[MAX_BUF_SIZE];
- VALUE result = rb_ary_new();
-
- if (buff_size > MAX_BUF_SIZE) rb_raise(rb_eRuntimeError, "too long buff_size");
-
- collected_size = rb_profile_thread_frames(thread, start, buff_size, buff, lines);
- for (i=0; i<collected_size; i++) {
- rb_ary_push(result, rb_profile_frame_full_label(buff[i]));
- }
-
- return result;
-}
-
void
Init_profile_frames(VALUE klass)
{
rb_define_module_function(klass, "profile_frames", profile_frames, 2);
- rb_define_module_function(klass, "profile_thread_frames", profile_thread_frames, 3);
}
diff --git a/ext/-test-/dln/empty/depend b/ext/-test-/dln/empty/depend
index a460159087..e16082a7dc 100644
--- a/ext/-test-/dln/empty/depend
+++ b/ext/-test-/dln/empty/depend
@@ -52,7 +52,6 @@ empty.o: $(hdrdir)/ruby/internal/attr/noexcept.h
empty.o: $(hdrdir)/ruby/internal/attr/noinline.h
empty.o: $(hdrdir)/ruby/internal/attr/nonnull.h
empty.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-empty.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
empty.o: $(hdrdir)/ruby/internal/attr/pure.h
empty.o: $(hdrdir)/ruby/internal/attr/restrict.h
empty.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ empty.o: $(hdrdir)/ruby/internal/intern/enumerator.h
empty.o: $(hdrdir)/ruby/internal/intern/error.h
empty.o: $(hdrdir)/ruby/internal/intern/eval.h
empty.o: $(hdrdir)/ruby/internal/intern/file.h
+empty.o: $(hdrdir)/ruby/internal/intern/gc.h
empty.o: $(hdrdir)/ruby/internal/intern/hash.h
empty.o: $(hdrdir)/ruby/internal/intern/io.h
empty.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ empty.o: $(hdrdir)/ruby/internal/memory.h
empty.o: $(hdrdir)/ruby/internal/method.h
empty.o: $(hdrdir)/ruby/internal/module.h
empty.o: $(hdrdir)/ruby/internal/newobj.h
+empty.o: $(hdrdir)/ruby/internal/rgengc.h
empty.o: $(hdrdir)/ruby/internal/scan_args.h
empty.o: $(hdrdir)/ruby/internal/special_consts.h
empty.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/enumerator_kw/depend b/ext/-test-/enumerator_kw/depend
index 49ea495421..14a9557e41 100644
--- a/ext/-test-/enumerator_kw/depend
+++ b/ext/-test-/enumerator_kw/depend
@@ -52,7 +52,6 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/noinline.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enumerator_kw.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/pure.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/restrict.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/error.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/eval.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/file.h
+enumerator_kw.o: $(hdrdir)/ruby/internal/intern/gc.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/hash.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/io.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/memory.h
enumerator_kw.o: $(hdrdir)/ruby/internal/method.h
enumerator_kw.o: $(hdrdir)/ruby/internal/module.h
enumerator_kw.o: $(hdrdir)/ruby/internal/newobj.h
+enumerator_kw.o: $(hdrdir)/ruby/internal/rgengc.h
enumerator_kw.o: $(hdrdir)/ruby/internal/scan_args.h
enumerator_kw.o: $(hdrdir)/ruby/internal/special_consts.h
enumerator_kw.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/exception/depend b/ext/-test-/exception/depend
index 818b4c79df..e00f0b279d 100644
--- a/ext/-test-/exception/depend
+++ b/ext/-test-/exception/depend
@@ -51,7 +51,6 @@ dataerror.o: $(hdrdir)/ruby/internal/attr/noexcept.h
dataerror.o: $(hdrdir)/ruby/internal/attr/noinline.h
dataerror.o: $(hdrdir)/ruby/internal/attr/nonnull.h
dataerror.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-dataerror.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
dataerror.o: $(hdrdir)/ruby/internal/attr/pure.h
dataerror.o: $(hdrdir)/ruby/internal/attr/restrict.h
dataerror.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ dataerror.o: $(hdrdir)/ruby/internal/intern/enumerator.h
dataerror.o: $(hdrdir)/ruby/internal/intern/error.h
dataerror.o: $(hdrdir)/ruby/internal/intern/eval.h
dataerror.o: $(hdrdir)/ruby/internal/intern/file.h
+dataerror.o: $(hdrdir)/ruby/internal/intern/gc.h
dataerror.o: $(hdrdir)/ruby/internal/intern/hash.h
dataerror.o: $(hdrdir)/ruby/internal/intern/io.h
dataerror.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ dataerror.o: $(hdrdir)/ruby/internal/memory.h
dataerror.o: $(hdrdir)/ruby/internal/method.h
dataerror.o: $(hdrdir)/ruby/internal/module.h
dataerror.o: $(hdrdir)/ruby/internal/newobj.h
+dataerror.o: $(hdrdir)/ruby/internal/rgengc.h
dataerror.o: $(hdrdir)/ruby/internal/scan_args.h
dataerror.o: $(hdrdir)/ruby/internal/special_consts.h
dataerror.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ enc_raise.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/noinline.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_raise.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/pure.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/restrict.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -280,6 +280,7 @@ enc_raise.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/error.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/eval.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/file.h
+enc_raise.o: $(hdrdir)/ruby/internal/intern/gc.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/hash.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/io.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -310,6 +311,7 @@ enc_raise.o: $(hdrdir)/ruby/internal/memory.h
enc_raise.o: $(hdrdir)/ruby/internal/method.h
enc_raise.o: $(hdrdir)/ruby/internal/module.h
enc_raise.o: $(hdrdir)/ruby/internal/newobj.h
+enc_raise.o: $(hdrdir)/ruby/internal/rgengc.h
enc_raise.o: $(hdrdir)/ruby/internal/scan_args.h
enc_raise.o: $(hdrdir)/ruby/internal/special_consts.h
enc_raise.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -381,7 +383,6 @@ ensured.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ensured.o: $(hdrdir)/ruby/internal/attr/noinline.h
ensured.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ensured.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ensured.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ensured.o: $(hdrdir)/ruby/internal/attr/pure.h
ensured.o: $(hdrdir)/ruby/internal/attr/restrict.h
ensured.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -441,6 +442,7 @@ ensured.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ensured.o: $(hdrdir)/ruby/internal/intern/error.h
ensured.o: $(hdrdir)/ruby/internal/intern/eval.h
ensured.o: $(hdrdir)/ruby/internal/intern/file.h
+ensured.o: $(hdrdir)/ruby/internal/intern/gc.h
ensured.o: $(hdrdir)/ruby/internal/intern/hash.h
ensured.o: $(hdrdir)/ruby/internal/intern/io.h
ensured.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -471,6 +473,7 @@ ensured.o: $(hdrdir)/ruby/internal/memory.h
ensured.o: $(hdrdir)/ruby/internal/method.h
ensured.o: $(hdrdir)/ruby/internal/module.h
ensured.o: $(hdrdir)/ruby/internal/newobj.h
+ensured.o: $(hdrdir)/ruby/internal/rgengc.h
ensured.o: $(hdrdir)/ruby/internal/scan_args.h
ensured.o: $(hdrdir)/ruby/internal/special_consts.h
ensured.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -540,7 +543,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -600,6 +602,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -630,6 +633,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/fatal/depend b/ext/-test-/fatal/depend
index 730a72e52a..5b1adb6607 100644
--- a/ext/-test-/fatal/depend
+++ b/ext/-test-/fatal/depend
@@ -52,7 +52,6 @@ rb_fatal.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_fatal.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ rb_fatal.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/error.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_fatal.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/io.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ rb_fatal.o: $(hdrdir)/ruby/internal/memory.h
rb_fatal.o: $(hdrdir)/ruby/internal/method.h
rb_fatal.o: $(hdrdir)/ruby/internal/module.h
rb_fatal.o: $(hdrdir)/ruby/internal/newobj.h
+rb_fatal.o: $(hdrdir)/ruby/internal/rgengc.h
rb_fatal.o: $(hdrdir)/ruby/internal/scan_args.h
rb_fatal.o: $(hdrdir)/ruby/internal/special_consts.h
rb_fatal.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/file/depend b/ext/-test-/file/depend
index 662136f1ba..f0fffc2485 100644
--- a/ext/-test-/file/depend
+++ b/ext/-test-/file/depend
@@ -52,7 +52,6 @@ fs.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fs.o: $(hdrdir)/ruby/internal/attr/noinline.h
fs.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fs.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fs.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fs.o: $(hdrdir)/ruby/internal/attr/pure.h
fs.o: $(hdrdir)/ruby/internal/attr/restrict.h
fs.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -121,6 +120,7 @@ fs.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fs.o: $(hdrdir)/ruby/internal/intern/error.h
fs.o: $(hdrdir)/ruby/internal/intern/eval.h
fs.o: $(hdrdir)/ruby/internal/intern/file.h
+fs.o: $(hdrdir)/ruby/internal/intern/gc.h
fs.o: $(hdrdir)/ruby/internal/intern/hash.h
fs.o: $(hdrdir)/ruby/internal/intern/io.h
fs.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -151,6 +151,7 @@ fs.o: $(hdrdir)/ruby/internal/memory.h
fs.o: $(hdrdir)/ruby/internal/method.h
fs.o: $(hdrdir)/ruby/internal/module.h
fs.o: $(hdrdir)/ruby/internal/newobj.h
+fs.o: $(hdrdir)/ruby/internal/rgengc.h
fs.o: $(hdrdir)/ruby/internal/scan_args.h
fs.o: $(hdrdir)/ruby/internal/special_consts.h
fs.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -223,7 +224,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -283,6 +283,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -313,6 +314,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -382,7 +384,6 @@ stat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
stat.o: $(hdrdir)/ruby/internal/attr/noinline.h
stat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
stat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-stat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
stat.o: $(hdrdir)/ruby/internal/attr/pure.h
stat.o: $(hdrdir)/ruby/internal/attr/restrict.h
stat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -451,6 +452,7 @@ stat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
stat.o: $(hdrdir)/ruby/internal/intern/error.h
stat.o: $(hdrdir)/ruby/internal/intern/eval.h
stat.o: $(hdrdir)/ruby/internal/intern/file.h
+stat.o: $(hdrdir)/ruby/internal/intern/gc.h
stat.o: $(hdrdir)/ruby/internal/intern/hash.h
stat.o: $(hdrdir)/ruby/internal/intern/io.h
stat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -481,6 +483,7 @@ stat.o: $(hdrdir)/ruby/internal/memory.h
stat.o: $(hdrdir)/ruby/internal/method.h
stat.o: $(hdrdir)/ruby/internal/module.h
stat.o: $(hdrdir)/ruby/internal/newobj.h
+stat.o: $(hdrdir)/ruby/internal/rgengc.h
stat.o: $(hdrdir)/ruby/internal/scan_args.h
stat.o: $(hdrdir)/ruby/internal/special_consts.h
stat.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/float/depend b/ext/-test-/float/depend
index 9580a0416c..9391a445a3 100644
--- a/ext/-test-/float/depend
+++ b/ext/-test-/float/depend
@@ -55,7 +55,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,6 +145,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -214,7 +215,6 @@ nextafter.o: $(hdrdir)/ruby/internal/attr/noexcept.h
nextafter.o: $(hdrdir)/ruby/internal/attr/noinline.h
nextafter.o: $(hdrdir)/ruby/internal/attr/nonnull.h
nextafter.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-nextafter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
nextafter.o: $(hdrdir)/ruby/internal/attr/pure.h
nextafter.o: $(hdrdir)/ruby/internal/attr/restrict.h
nextafter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -274,6 +274,7 @@ nextafter.o: $(hdrdir)/ruby/internal/intern/enumerator.h
nextafter.o: $(hdrdir)/ruby/internal/intern/error.h
nextafter.o: $(hdrdir)/ruby/internal/intern/eval.h
nextafter.o: $(hdrdir)/ruby/internal/intern/file.h
+nextafter.o: $(hdrdir)/ruby/internal/intern/gc.h
nextafter.o: $(hdrdir)/ruby/internal/intern/hash.h
nextafter.o: $(hdrdir)/ruby/internal/intern/io.h
nextafter.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -304,6 +305,7 @@ nextafter.o: $(hdrdir)/ruby/internal/memory.h
nextafter.o: $(hdrdir)/ruby/internal/method.h
nextafter.o: $(hdrdir)/ruby/internal/module.h
nextafter.o: $(hdrdir)/ruby/internal/newobj.h
+nextafter.o: $(hdrdir)/ruby/internal/rgengc.h
nextafter.o: $(hdrdir)/ruby/internal/scan_args.h
nextafter.o: $(hdrdir)/ruby/internal/special_consts.h
nextafter.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/funcall/depend b/ext/-test-/funcall/depend
index 6719e4e676..24e8c54bd9 100644
--- a/ext/-test-/funcall/depend
+++ b/ext/-test-/funcall/depend
@@ -52,7 +52,6 @@ funcall.o: $(hdrdir)/ruby/internal/attr/noexcept.h
funcall.o: $(hdrdir)/ruby/internal/attr/noinline.h
funcall.o: $(hdrdir)/ruby/internal/attr/nonnull.h
funcall.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-funcall.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
funcall.o: $(hdrdir)/ruby/internal/attr/pure.h
funcall.o: $(hdrdir)/ruby/internal/attr/restrict.h
funcall.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ funcall.o: $(hdrdir)/ruby/internal/intern/enumerator.h
funcall.o: $(hdrdir)/ruby/internal/intern/error.h
funcall.o: $(hdrdir)/ruby/internal/intern/eval.h
funcall.o: $(hdrdir)/ruby/internal/intern/file.h
+funcall.o: $(hdrdir)/ruby/internal/intern/gc.h
funcall.o: $(hdrdir)/ruby/internal/intern/hash.h
funcall.o: $(hdrdir)/ruby/internal/intern/io.h
funcall.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ funcall.o: $(hdrdir)/ruby/internal/memory.h
funcall.o: $(hdrdir)/ruby/internal/method.h
funcall.o: $(hdrdir)/ruby/internal/module.h
funcall.o: $(hdrdir)/ruby/internal/newobj.h
+funcall.o: $(hdrdir)/ruby/internal/rgengc.h
funcall.o: $(hdrdir)/ruby/internal/scan_args.h
funcall.o: $(hdrdir)/ruby/internal/special_consts.h
funcall.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/gvl/call_without_gvl/depend b/ext/-test-/gvl/call_without_gvl/depend
index a4987a65ca..cd184aa01c 100644
--- a/ext/-test-/gvl/call_without_gvl/depend
+++ b/ext/-test-/gvl/call_without_gvl/depend
@@ -51,7 +51,6 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noinline.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-call_without_gvl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/pure.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/restrict.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/error.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/eval.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/file.h
+call_without_gvl.o: $(hdrdir)/ruby/internal/intern/gc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/hash.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/io.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/memory.h
call_without_gvl.o: $(hdrdir)/ruby/internal/method.h
call_without_gvl.o: $(hdrdir)/ruby/internal/module.h
call_without_gvl.o: $(hdrdir)/ruby/internal/newobj.h
+call_without_gvl.o: $(hdrdir)/ruby/internal/rgengc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/scan_args.h
call_without_gvl.o: $(hdrdir)/ruby/internal/special_consts.h
call_without_gvl.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/hash/depend b/ext/-test-/hash/depend
index 58d9a6247e..a8bc47e640 100644
--- a/ext/-test-/hash/depend
+++ b/ext/-test-/hash/depend
@@ -52,7 +52,6 @@ delete.o: $(hdrdir)/ruby/internal/attr/noexcept.h
delete.o: $(hdrdir)/ruby/internal/attr/noinline.h
delete.o: $(hdrdir)/ruby/internal/attr/nonnull.h
delete.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-delete.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
delete.o: $(hdrdir)/ruby/internal/attr/pure.h
delete.o: $(hdrdir)/ruby/internal/attr/restrict.h
delete.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ delete.o: $(hdrdir)/ruby/internal/intern/enumerator.h
delete.o: $(hdrdir)/ruby/internal/intern/error.h
delete.o: $(hdrdir)/ruby/internal/intern/eval.h
delete.o: $(hdrdir)/ruby/internal/intern/file.h
+delete.o: $(hdrdir)/ruby/internal/intern/gc.h
delete.o: $(hdrdir)/ruby/internal/intern/hash.h
delete.o: $(hdrdir)/ruby/internal/intern/io.h
delete.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ delete.o: $(hdrdir)/ruby/internal/memory.h
delete.o: $(hdrdir)/ruby/internal/method.h
delete.o: $(hdrdir)/ruby/internal/module.h
delete.o: $(hdrdir)/ruby/internal/newobj.h
+delete.o: $(hdrdir)/ruby/internal/rgengc.h
delete.o: $(hdrdir)/ruby/internal/scan_args.h
delete.o: $(hdrdir)/ruby/internal/special_consts.h
delete.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/integer/depend b/ext/-test-/integer/depend
index b68a68ce73..b12159f308 100644
--- a/ext/-test-/integer/depend
+++ b/ext/-test-/integer/depend
@@ -52,7 +52,6 @@ core_ext.o: $(hdrdir)/ruby/internal/attr/noexcept.h
core_ext.o: $(hdrdir)/ruby/internal/attr/noinline.h
core_ext.o: $(hdrdir)/ruby/internal/attr/nonnull.h
core_ext.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-core_ext.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
core_ext.o: $(hdrdir)/ruby/internal/attr/pure.h
core_ext.o: $(hdrdir)/ruby/internal/attr/restrict.h
core_ext.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ core_ext.o: $(hdrdir)/ruby/internal/intern/enumerator.h
core_ext.o: $(hdrdir)/ruby/internal/intern/error.h
core_ext.o: $(hdrdir)/ruby/internal/intern/eval.h
core_ext.o: $(hdrdir)/ruby/internal/intern/file.h
+core_ext.o: $(hdrdir)/ruby/internal/intern/gc.h
core_ext.o: $(hdrdir)/ruby/internal/intern/hash.h
core_ext.o: $(hdrdir)/ruby/internal/intern/io.h
core_ext.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ core_ext.o: $(hdrdir)/ruby/internal/memory.h
core_ext.o: $(hdrdir)/ruby/internal/method.h
core_ext.o: $(hdrdir)/ruby/internal/module.h
core_ext.o: $(hdrdir)/ruby/internal/newobj.h
+core_ext.o: $(hdrdir)/ruby/internal/rgengc.h
core_ext.o: $(hdrdir)/ruby/internal/scan_args.h
core_ext.o: $(hdrdir)/ruby/internal/special_consts.h
core_ext.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -219,7 +220,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -279,6 +279,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -309,6 +310,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -378,7 +380,6 @@ my_integer.o: $(hdrdir)/ruby/internal/attr/noexcept.h
my_integer.o: $(hdrdir)/ruby/internal/attr/noinline.h
my_integer.o: $(hdrdir)/ruby/internal/attr/nonnull.h
my_integer.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-my_integer.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
my_integer.o: $(hdrdir)/ruby/internal/attr/pure.h
my_integer.o: $(hdrdir)/ruby/internal/attr/restrict.h
my_integer.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -438,6 +439,7 @@ my_integer.o: $(hdrdir)/ruby/internal/intern/enumerator.h
my_integer.o: $(hdrdir)/ruby/internal/intern/error.h
my_integer.o: $(hdrdir)/ruby/internal/intern/eval.h
my_integer.o: $(hdrdir)/ruby/internal/intern/file.h
+my_integer.o: $(hdrdir)/ruby/internal/intern/gc.h
my_integer.o: $(hdrdir)/ruby/internal/intern/hash.h
my_integer.o: $(hdrdir)/ruby/internal/intern/io.h
my_integer.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -468,6 +470,7 @@ my_integer.o: $(hdrdir)/ruby/internal/memory.h
my_integer.o: $(hdrdir)/ruby/internal/method.h
my_integer.o: $(hdrdir)/ruby/internal/module.h
my_integer.o: $(hdrdir)/ruby/internal/newobj.h
+my_integer.o: $(hdrdir)/ruby/internal/rgengc.h
my_integer.o: $(hdrdir)/ruby/internal/scan_args.h
my_integer.o: $(hdrdir)/ruby/internal/special_consts.h
my_integer.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/iseq_load/depend b/ext/-test-/iseq_load/depend
index 30deb6e039..308956550c 100644
--- a/ext/-test-/iseq_load/depend
+++ b/ext/-test-/iseq_load/depend
@@ -52,7 +52,6 @@ iseq_load.o: $(hdrdir)/ruby/internal/attr/noexcept.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/noinline.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/nonnull.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-iseq_load.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/pure.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/restrict.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ iseq_load.o: $(hdrdir)/ruby/internal/intern/enumerator.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/error.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/eval.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/file.h
+iseq_load.o: $(hdrdir)/ruby/internal/intern/gc.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/hash.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/io.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ iseq_load.o: $(hdrdir)/ruby/internal/memory.h
iseq_load.o: $(hdrdir)/ruby/internal/method.h
iseq_load.o: $(hdrdir)/ruby/internal/module.h
iseq_load.o: $(hdrdir)/ruby/internal/newobj.h
+iseq_load.o: $(hdrdir)/ruby/internal/rgengc.h
iseq_load.o: $(hdrdir)/ruby/internal/scan_args.h
iseq_load.o: $(hdrdir)/ruby/internal/special_consts.h
iseq_load.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/iter/depend b/ext/-test-/iter/depend
index 077a283532..d14c164cd4 100644
--- a/ext/-test-/iter/depend
+++ b/ext/-test-/iter/depend
@@ -52,7 +52,6 @@ break.o: $(hdrdir)/ruby/internal/attr/noexcept.h
break.o: $(hdrdir)/ruby/internal/attr/noinline.h
break.o: $(hdrdir)/ruby/internal/attr/nonnull.h
break.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-break.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
break.o: $(hdrdir)/ruby/internal/attr/pure.h
break.o: $(hdrdir)/ruby/internal/attr/restrict.h
break.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ break.o: $(hdrdir)/ruby/internal/intern/enumerator.h
break.o: $(hdrdir)/ruby/internal/intern/error.h
break.o: $(hdrdir)/ruby/internal/intern/eval.h
break.o: $(hdrdir)/ruby/internal/intern/file.h
+break.o: $(hdrdir)/ruby/internal/intern/gc.h
break.o: $(hdrdir)/ruby/internal/intern/hash.h
break.o: $(hdrdir)/ruby/internal/intern/io.h
break.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ break.o: $(hdrdir)/ruby/internal/memory.h
break.o: $(hdrdir)/ruby/internal/method.h
break.o: $(hdrdir)/ruby/internal/module.h
break.o: $(hdrdir)/ruby/internal/newobj.h
+break.o: $(hdrdir)/ruby/internal/rgengc.h
break.o: $(hdrdir)/ruby/internal/scan_args.h
break.o: $(hdrdir)/ruby/internal/special_consts.h
break.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -370,7 +372,6 @@ yield.o: $(hdrdir)/ruby/internal/attr/noexcept.h
yield.o: $(hdrdir)/ruby/internal/attr/noinline.h
yield.o: $(hdrdir)/ruby/internal/attr/nonnull.h
yield.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-yield.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
yield.o: $(hdrdir)/ruby/internal/attr/pure.h
yield.o: $(hdrdir)/ruby/internal/attr/restrict.h
yield.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -430,6 +431,7 @@ yield.o: $(hdrdir)/ruby/internal/intern/enumerator.h
yield.o: $(hdrdir)/ruby/internal/intern/error.h
yield.o: $(hdrdir)/ruby/internal/intern/eval.h
yield.o: $(hdrdir)/ruby/internal/intern/file.h
+yield.o: $(hdrdir)/ruby/internal/intern/gc.h
yield.o: $(hdrdir)/ruby/internal/intern/hash.h
yield.o: $(hdrdir)/ruby/internal/intern/io.h
yield.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -460,6 +462,7 @@ yield.o: $(hdrdir)/ruby/internal/memory.h
yield.o: $(hdrdir)/ruby/internal/method.h
yield.o: $(hdrdir)/ruby/internal/module.h
yield.o: $(hdrdir)/ruby/internal/newobj.h
+yield.o: $(hdrdir)/ruby/internal/rgengc.h
yield.o: $(hdrdir)/ruby/internal/scan_args.h
yield.o: $(hdrdir)/ruby/internal/special_consts.h
yield.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/load/dot.dot/depend b/ext/-test-/load/dot.dot/depend
index be835d3ea5..d8b8937c3c 100644
--- a/ext/-test-/load/dot.dot/depend
+++ b/ext/-test-/load/dot.dot/depend
@@ -52,7 +52,6 @@ dot.dot.o: $(hdrdir)/ruby/internal/attr/noexcept.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/noinline.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/nonnull.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-dot.dot.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/pure.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/restrict.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ dot.dot.o: $(hdrdir)/ruby/internal/intern/enumerator.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/error.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/eval.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/file.h
+dot.dot.o: $(hdrdir)/ruby/internal/intern/gc.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/hash.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/io.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ dot.dot.o: $(hdrdir)/ruby/internal/memory.h
dot.dot.o: $(hdrdir)/ruby/internal/method.h
dot.dot.o: $(hdrdir)/ruby/internal/module.h
dot.dot.o: $(hdrdir)/ruby/internal/newobj.h
+dot.dot.o: $(hdrdir)/ruby/internal/rgengc.h
dot.dot.o: $(hdrdir)/ruby/internal/scan_args.h
dot.dot.o: $(hdrdir)/ruby/internal/special_consts.h
dot.dot.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/load/protect/depend b/ext/-test-/load/protect/depend
index 57cf029901..dd4ee71b62 100644
--- a/ext/-test-/load/protect/depend
+++ b/ext/-test-/load/protect/depend
@@ -52,7 +52,6 @@ protect.o: $(hdrdir)/ruby/internal/attr/noexcept.h
protect.o: $(hdrdir)/ruby/internal/attr/noinline.h
protect.o: $(hdrdir)/ruby/internal/attr/nonnull.h
protect.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-protect.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
protect.o: $(hdrdir)/ruby/internal/attr/pure.h
protect.o: $(hdrdir)/ruby/internal/attr/restrict.h
protect.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ protect.o: $(hdrdir)/ruby/internal/intern/enumerator.h
protect.o: $(hdrdir)/ruby/internal/intern/error.h
protect.o: $(hdrdir)/ruby/internal/intern/eval.h
protect.o: $(hdrdir)/ruby/internal/intern/file.h
+protect.o: $(hdrdir)/ruby/internal/intern/gc.h
protect.o: $(hdrdir)/ruby/internal/intern/hash.h
protect.o: $(hdrdir)/ruby/internal/intern/io.h
protect.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ protect.o: $(hdrdir)/ruby/internal/memory.h
protect.o: $(hdrdir)/ruby/internal/method.h
protect.o: $(hdrdir)/ruby/internal/module.h
protect.o: $(hdrdir)/ruby/internal/newobj.h
+protect.o: $(hdrdir)/ruby/internal/rgengc.h
protect.o: $(hdrdir)/ruby/internal/scan_args.h
protect.o: $(hdrdir)/ruby/internal/special_consts.h
protect.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/marshal/compat/depend b/ext/-test-/marshal/compat/depend
index ff675ccabb..2c3ecf1ab9 100644
--- a/ext/-test-/marshal/compat/depend
+++ b/ext/-test-/marshal/compat/depend
@@ -52,7 +52,6 @@ usrcompat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/noinline.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-usrcompat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/pure.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/restrict.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ usrcompat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/error.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/eval.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/file.h
+usrcompat.o: $(hdrdir)/ruby/internal/intern/gc.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/hash.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/io.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ usrcompat.o: $(hdrdir)/ruby/internal/memory.h
usrcompat.o: $(hdrdir)/ruby/internal/method.h
usrcompat.o: $(hdrdir)/ruby/internal/module.h
usrcompat.o: $(hdrdir)/ruby/internal/newobj.h
+usrcompat.o: $(hdrdir)/ruby/internal/rgengc.h
usrcompat.o: $(hdrdir)/ruby/internal/scan_args.h
usrcompat.o: $(hdrdir)/ruby/internal/special_consts.h
usrcompat.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/marshal/internal_ivar/depend b/ext/-test-/marshal/internal_ivar/depend
index 4fe36834d8..cacb54a1a7 100644
--- a/ext/-test-/marshal/internal_ivar/depend
+++ b/ext/-test-/marshal/internal_ivar/depend
@@ -52,7 +52,6 @@ internal_ivar.o: $(hdrdir)/ruby/internal/attr/noexcept.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/noinline.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/nonnull.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-internal_ivar.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/pure.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/restrict.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ internal_ivar.o: $(hdrdir)/ruby/internal/intern/enumerator.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/error.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/eval.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/file.h
+internal_ivar.o: $(hdrdir)/ruby/internal/intern/gc.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/hash.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/io.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ internal_ivar.o: $(hdrdir)/ruby/internal/memory.h
internal_ivar.o: $(hdrdir)/ruby/internal/method.h
internal_ivar.o: $(hdrdir)/ruby/internal/module.h
internal_ivar.o: $(hdrdir)/ruby/internal/newobj.h
+internal_ivar.o: $(hdrdir)/ruby/internal/rgengc.h
internal_ivar.o: $(hdrdir)/ruby/internal/scan_args.h
internal_ivar.o: $(hdrdir)/ruby/internal/special_consts.h
internal_ivar.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/marshal/usr/depend b/ext/-test-/marshal/usr/depend
index 1d56cc8202..717101cbcf 100644
--- a/ext/-test-/marshal/usr/depend
+++ b/ext/-test-/marshal/usr/depend
@@ -52,7 +52,6 @@ usrmarshal.o: $(hdrdir)/ruby/internal/attr/noexcept.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/noinline.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/nonnull.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-usrmarshal.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/pure.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/restrict.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ usrmarshal.o: $(hdrdir)/ruby/internal/intern/enumerator.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/error.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/eval.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/file.h
+usrmarshal.o: $(hdrdir)/ruby/internal/intern/gc.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/hash.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/io.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ usrmarshal.o: $(hdrdir)/ruby/internal/memory.h
usrmarshal.o: $(hdrdir)/ruby/internal/method.h
usrmarshal.o: $(hdrdir)/ruby/internal/module.h
usrmarshal.o: $(hdrdir)/ruby/internal/newobj.h
+usrmarshal.o: $(hdrdir)/ruby/internal/rgengc.h
usrmarshal.o: $(hdrdir)/ruby/internal/scan_args.h
usrmarshal.o: $(hdrdir)/ruby/internal/special_consts.h
usrmarshal.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/memory_status/depend b/ext/-test-/memory_status/depend
index 52e2fe8e1f..a65fe66ae3 100644
--- a/ext/-test-/memory_status/depend
+++ b/ext/-test-/memory_status/depend
@@ -52,7 +52,6 @@ memory_status.o: $(hdrdir)/ruby/internal/attr/noexcept.h
memory_status.o: $(hdrdir)/ruby/internal/attr/noinline.h
memory_status.o: $(hdrdir)/ruby/internal/attr/nonnull.h
memory_status.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-memory_status.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
memory_status.o: $(hdrdir)/ruby/internal/attr/pure.h
memory_status.o: $(hdrdir)/ruby/internal/attr/restrict.h
memory_status.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ memory_status.o: $(hdrdir)/ruby/internal/intern/enumerator.h
memory_status.o: $(hdrdir)/ruby/internal/intern/error.h
memory_status.o: $(hdrdir)/ruby/internal/intern/eval.h
memory_status.o: $(hdrdir)/ruby/internal/intern/file.h
+memory_status.o: $(hdrdir)/ruby/internal/intern/gc.h
memory_status.o: $(hdrdir)/ruby/internal/intern/hash.h
memory_status.o: $(hdrdir)/ruby/internal/intern/io.h
memory_status.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ memory_status.o: $(hdrdir)/ruby/internal/memory.h
memory_status.o: $(hdrdir)/ruby/internal/method.h
memory_status.o: $(hdrdir)/ruby/internal/module.h
memory_status.o: $(hdrdir)/ruby/internal/newobj.h
+memory_status.o: $(hdrdir)/ruby/internal/rgengc.h
memory_status.o: $(hdrdir)/ruby/internal/scan_args.h
memory_status.o: $(hdrdir)/ruby/internal/special_consts.h
memory_status.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/memory_view/depend b/ext/-test-/memory_view/depend
index c9ef06a15c..7ce2d0374c 100644
--- a/ext/-test-/memory_view/depend
+++ b/ext/-test-/memory_view/depend
@@ -52,7 +52,6 @@ memory_view.o: $(hdrdir)/ruby/internal/attr/noexcept.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noinline.h
memory_view.o: $(hdrdir)/ruby/internal/attr/nonnull.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-memory_view.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
memory_view.o: $(hdrdir)/ruby/internal/attr/pure.h
memory_view.o: $(hdrdir)/ruby/internal/attr/restrict.h
memory_view.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ memory_view.o: $(hdrdir)/ruby/internal/intern/enumerator.h
memory_view.o: $(hdrdir)/ruby/internal/intern/error.h
memory_view.o: $(hdrdir)/ruby/internal/intern/eval.h
memory_view.o: $(hdrdir)/ruby/internal/intern/file.h
+memory_view.o: $(hdrdir)/ruby/internal/intern/gc.h
memory_view.o: $(hdrdir)/ruby/internal/intern/hash.h
memory_view.o: $(hdrdir)/ruby/internal/intern/io.h
memory_view.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ memory_view.o: $(hdrdir)/ruby/internal/memory.h
memory_view.o: $(hdrdir)/ruby/internal/method.h
memory_view.o: $(hdrdir)/ruby/internal/module.h
memory_view.o: $(hdrdir)/ruby/internal/newobj.h
+memory_view.o: $(hdrdir)/ruby/internal/rgengc.h
memory_view.o: $(hdrdir)/ruby/internal/scan_args.h
memory_view.o: $(hdrdir)/ruby/internal/special_consts.h
memory_view.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/method/depend b/ext/-test-/method/depend
index dbf513f48f..85cf4d174a 100644
--- a/ext/-test-/method/depend
+++ b/ext/-test-/method/depend
@@ -52,7 +52,6 @@ arity.o: $(hdrdir)/ruby/internal/attr/noexcept.h
arity.o: $(hdrdir)/ruby/internal/attr/noinline.h
arity.o: $(hdrdir)/ruby/internal/attr/nonnull.h
arity.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-arity.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
arity.o: $(hdrdir)/ruby/internal/attr/pure.h
arity.o: $(hdrdir)/ruby/internal/attr/restrict.h
arity.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ arity.o: $(hdrdir)/ruby/internal/intern/enumerator.h
arity.o: $(hdrdir)/ruby/internal/intern/error.h
arity.o: $(hdrdir)/ruby/internal/intern/eval.h
arity.o: $(hdrdir)/ruby/internal/intern/file.h
+arity.o: $(hdrdir)/ruby/internal/intern/gc.h
arity.o: $(hdrdir)/ruby/internal/intern/hash.h
arity.o: $(hdrdir)/ruby/internal/intern/io.h
arity.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ arity.o: $(hdrdir)/ruby/internal/memory.h
arity.o: $(hdrdir)/ruby/internal/method.h
arity.o: $(hdrdir)/ruby/internal/module.h
arity.o: $(hdrdir)/ruby/internal/newobj.h
+arity.o: $(hdrdir)/ruby/internal/rgengc.h
arity.o: $(hdrdir)/ruby/internal/scan_args.h
arity.o: $(hdrdir)/ruby/internal/special_consts.h
arity.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/notimplement/depend b/ext/-test-/notimplement/depend
index 9105093b0d..2303f47594 100644
--- a/ext/-test-/notimplement/depend
+++ b/ext/-test-/notimplement/depend
@@ -52,7 +52,6 @@ bug.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug.o: $(hdrdir)/ruby/internal/attr/pure.h
bug.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug.o: $(hdrdir)/ruby/internal/intern/error.h
bug.o: $(hdrdir)/ruby/internal/intern/eval.h
bug.o: $(hdrdir)/ruby/internal/intern/file.h
+bug.o: $(hdrdir)/ruby/internal/intern/gc.h
bug.o: $(hdrdir)/ruby/internal/intern/hash.h
bug.o: $(hdrdir)/ruby/internal/intern/io.h
bug.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ bug.o: $(hdrdir)/ruby/internal/memory.h
bug.o: $(hdrdir)/ruby/internal/method.h
bug.o: $(hdrdir)/ruby/internal/module.h
bug.o: $(hdrdir)/ruby/internal/newobj.h
+bug.o: $(hdrdir)/ruby/internal/rgengc.h
bug.o: $(hdrdir)/ruby/internal/scan_args.h
bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/num2int/depend b/ext/-test-/num2int/depend
index 4e05d1e8c1..a3283838dd 100644
--- a/ext/-test-/num2int/depend
+++ b/ext/-test-/num2int/depend
@@ -52,7 +52,6 @@ num2int.o: $(hdrdir)/ruby/internal/attr/noexcept.h
num2int.o: $(hdrdir)/ruby/internal/attr/noinline.h
num2int.o: $(hdrdir)/ruby/internal/attr/nonnull.h
num2int.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-num2int.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
num2int.o: $(hdrdir)/ruby/internal/attr/pure.h
num2int.o: $(hdrdir)/ruby/internal/attr/restrict.h
num2int.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ num2int.o: $(hdrdir)/ruby/internal/intern/enumerator.h
num2int.o: $(hdrdir)/ruby/internal/intern/error.h
num2int.o: $(hdrdir)/ruby/internal/intern/eval.h
num2int.o: $(hdrdir)/ruby/internal/intern/file.h
+num2int.o: $(hdrdir)/ruby/internal/intern/gc.h
num2int.o: $(hdrdir)/ruby/internal/intern/hash.h
num2int.o: $(hdrdir)/ruby/internal/intern/io.h
num2int.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ num2int.o: $(hdrdir)/ruby/internal/memory.h
num2int.o: $(hdrdir)/ruby/internal/method.h
num2int.o: $(hdrdir)/ruby/internal/module.h
num2int.o: $(hdrdir)/ruby/internal/newobj.h
+num2int.o: $(hdrdir)/ruby/internal/rgengc.h
num2int.o: $(hdrdir)/ruby/internal/scan_args.h
num2int.o: $(hdrdir)/ruby/internal/special_consts.h
num2int.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/path_to_class/depend b/ext/-test-/path_to_class/depend
index 8fe6ee37c2..17f8e957c3 100644
--- a/ext/-test-/path_to_class/depend
+++ b/ext/-test-/path_to_class/depend
@@ -52,7 +52,6 @@ path_to_class.o: $(hdrdir)/ruby/internal/attr/noexcept.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/noinline.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/nonnull.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-path_to_class.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/pure.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/restrict.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ path_to_class.o: $(hdrdir)/ruby/internal/intern/enumerator.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/error.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/eval.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/file.h
+path_to_class.o: $(hdrdir)/ruby/internal/intern/gc.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/hash.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/io.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ path_to_class.o: $(hdrdir)/ruby/internal/memory.h
path_to_class.o: $(hdrdir)/ruby/internal/method.h
path_to_class.o: $(hdrdir)/ruby/internal/module.h
path_to_class.o: $(hdrdir)/ruby/internal/newobj.h
+path_to_class.o: $(hdrdir)/ruby/internal/rgengc.h
path_to_class.o: $(hdrdir)/ruby/internal/scan_args.h
path_to_class.o: $(hdrdir)/ruby/internal/special_consts.h
path_to_class.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/popen_deadlock/depend b/ext/-test-/popen_deadlock/depend
index fb58ca30e9..22da87f2fe 100644
--- a/ext/-test-/popen_deadlock/depend
+++ b/ext/-test-/popen_deadlock/depend
@@ -52,7 +52,6 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/noexcept.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/noinline.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/nonnull.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/pure.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/restrict.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/enumerator.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/error.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/eval.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/file.h
+infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/gc.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/hash.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/io.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/memory.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/method.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/module.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/newobj.h
+infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/rgengc.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/scan_args.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/special_consts.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/postponed_job/depend b/ext/-test-/postponed_job/depend
index e44d9d51b7..35aca7f2b0 100644
--- a/ext/-test-/postponed_job/depend
+++ b/ext/-test-/postponed_job/depend
@@ -53,7 +53,6 @@ postponed_job.o: $(hdrdir)/ruby/internal/attr/noexcept.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/noinline.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/nonnull.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-postponed_job.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/pure.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/restrict.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -113,6 +112,7 @@ postponed_job.o: $(hdrdir)/ruby/internal/intern/enumerator.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/error.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/eval.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/file.h
+postponed_job.o: $(hdrdir)/ruby/internal/intern/gc.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/hash.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/io.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -143,6 +143,7 @@ postponed_job.o: $(hdrdir)/ruby/internal/memory.h
postponed_job.o: $(hdrdir)/ruby/internal/method.h
postponed_job.o: $(hdrdir)/ruby/internal/module.h
postponed_job.o: $(hdrdir)/ruby/internal/newobj.h
+postponed_job.o: $(hdrdir)/ruby/internal/rgengc.h
postponed_job.o: $(hdrdir)/ruby/internal/scan_args.h
postponed_job.o: $(hdrdir)/ruby/internal/special_consts.h
postponed_job.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/printf/depend b/ext/-test-/printf/depend
index b397041103..6dfe1fe03d 100644
--- a/ext/-test-/printf/depend
+++ b/ext/-test-/printf/depend
@@ -53,7 +53,6 @@ printf.o: $(hdrdir)/ruby/internal/attr/noexcept.h
printf.o: $(hdrdir)/ruby/internal/attr/noinline.h
printf.o: $(hdrdir)/ruby/internal/attr/nonnull.h
printf.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-printf.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
printf.o: $(hdrdir)/ruby/internal/attr/pure.h
printf.o: $(hdrdir)/ruby/internal/attr/restrict.h
printf.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ printf.o: $(hdrdir)/ruby/internal/intern/enumerator.h
printf.o: $(hdrdir)/ruby/internal/intern/error.h
printf.o: $(hdrdir)/ruby/internal/intern/eval.h
printf.o: $(hdrdir)/ruby/internal/intern/file.h
+printf.o: $(hdrdir)/ruby/internal/intern/gc.h
printf.o: $(hdrdir)/ruby/internal/intern/hash.h
printf.o: $(hdrdir)/ruby/internal/intern/io.h
printf.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ printf.o: $(hdrdir)/ruby/internal/memory.h
printf.o: $(hdrdir)/ruby/internal/method.h
printf.o: $(hdrdir)/ruby/internal/module.h
printf.o: $(hdrdir)/ruby/internal/newobj.h
+printf.o: $(hdrdir)/ruby/internal/rgengc.h
printf.o: $(hdrdir)/ruby/internal/scan_args.h
printf.o: $(hdrdir)/ruby/internal/special_consts.h
printf.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/proc/depend b/ext/-test-/proc/depend
index 7e78aa6f83..e3f1cf6ce9 100644
--- a/ext/-test-/proc/depend
+++ b/ext/-test-/proc/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ receiver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
receiver.o: $(hdrdir)/ruby/internal/attr/noinline.h
receiver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
receiver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-receiver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
receiver.o: $(hdrdir)/ruby/internal/attr/pure.h
receiver.o: $(hdrdir)/ruby/internal/attr/restrict.h
receiver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ receiver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
receiver.o: $(hdrdir)/ruby/internal/intern/error.h
receiver.o: $(hdrdir)/ruby/internal/intern/eval.h
receiver.o: $(hdrdir)/ruby/internal/intern/file.h
+receiver.o: $(hdrdir)/ruby/internal/intern/gc.h
receiver.o: $(hdrdir)/ruby/internal/intern/hash.h
receiver.o: $(hdrdir)/ruby/internal/intern/io.h
receiver.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ receiver.o: $(hdrdir)/ruby/internal/memory.h
receiver.o: $(hdrdir)/ruby/internal/method.h
receiver.o: $(hdrdir)/ruby/internal/module.h
receiver.o: $(hdrdir)/ruby/internal/newobj.h
+receiver.o: $(hdrdir)/ruby/internal/rgengc.h
receiver.o: $(hdrdir)/ruby/internal/scan_args.h
receiver.o: $(hdrdir)/ruby/internal/special_consts.h
receiver.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -370,7 +372,6 @@ super.o: $(hdrdir)/ruby/internal/attr/noexcept.h
super.o: $(hdrdir)/ruby/internal/attr/noinline.h
super.o: $(hdrdir)/ruby/internal/attr/nonnull.h
super.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-super.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
super.o: $(hdrdir)/ruby/internal/attr/pure.h
super.o: $(hdrdir)/ruby/internal/attr/restrict.h
super.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -430,6 +431,7 @@ super.o: $(hdrdir)/ruby/internal/intern/enumerator.h
super.o: $(hdrdir)/ruby/internal/intern/error.h
super.o: $(hdrdir)/ruby/internal/intern/eval.h
super.o: $(hdrdir)/ruby/internal/intern/file.h
+super.o: $(hdrdir)/ruby/internal/intern/gc.h
super.o: $(hdrdir)/ruby/internal/intern/hash.h
super.o: $(hdrdir)/ruby/internal/intern/io.h
super.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -460,6 +462,7 @@ super.o: $(hdrdir)/ruby/internal/memory.h
super.o: $(hdrdir)/ruby/internal/method.h
super.o: $(hdrdir)/ruby/internal/module.h
super.o: $(hdrdir)/ruby/internal/newobj.h
+super.o: $(hdrdir)/ruby/internal/rgengc.h
super.o: $(hdrdir)/ruby/internal/scan_args.h
super.o: $(hdrdir)/ruby/internal/special_consts.h
super.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/random/depend b/ext/-test-/random/depend
index 3f9a52be44..f2cbf7fc14 100644
--- a/ext/-test-/random/depend
+++ b/ext/-test-/random/depend
@@ -51,7 +51,6 @@ bad_version.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bad_version.o: $(hdrdir)/ruby/internal/attr/noinline.h
bad_version.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bad_version.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bad_version.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bad_version.o: $(hdrdir)/ruby/internal/attr/pure.h
bad_version.o: $(hdrdir)/ruby/internal/attr/restrict.h
bad_version.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ bad_version.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bad_version.o: $(hdrdir)/ruby/internal/intern/error.h
bad_version.o: $(hdrdir)/ruby/internal/intern/eval.h
bad_version.o: $(hdrdir)/ruby/internal/intern/file.h
+bad_version.o: $(hdrdir)/ruby/internal/intern/gc.h
bad_version.o: $(hdrdir)/ruby/internal/intern/hash.h
bad_version.o: $(hdrdir)/ruby/internal/intern/io.h
bad_version.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ bad_version.o: $(hdrdir)/ruby/internal/memory.h
bad_version.o: $(hdrdir)/ruby/internal/method.h
bad_version.o: $(hdrdir)/ruby/internal/module.h
bad_version.o: $(hdrdir)/ruby/internal/newobj.h
+bad_version.o: $(hdrdir)/ruby/internal/rgengc.h
bad_version.o: $(hdrdir)/ruby/internal/scan_args.h
bad_version.o: $(hdrdir)/ruby/internal/special_consts.h
bad_version.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -369,7 +371,6 @@ loop.o: $(hdrdir)/ruby/internal/attr/noexcept.h
loop.o: $(hdrdir)/ruby/internal/attr/noinline.h
loop.o: $(hdrdir)/ruby/internal/attr/nonnull.h
loop.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-loop.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
loop.o: $(hdrdir)/ruby/internal/attr/pure.h
loop.o: $(hdrdir)/ruby/internal/attr/restrict.h
loop.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -429,6 +430,7 @@ loop.o: $(hdrdir)/ruby/internal/intern/enumerator.h
loop.o: $(hdrdir)/ruby/internal/intern/error.h
loop.o: $(hdrdir)/ruby/internal/intern/eval.h
loop.o: $(hdrdir)/ruby/internal/intern/file.h
+loop.o: $(hdrdir)/ruby/internal/intern/gc.h
loop.o: $(hdrdir)/ruby/internal/intern/hash.h
loop.o: $(hdrdir)/ruby/internal/intern/io.h
loop.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -459,6 +461,7 @@ loop.o: $(hdrdir)/ruby/internal/memory.h
loop.o: $(hdrdir)/ruby/internal/method.h
loop.o: $(hdrdir)/ruby/internal/module.h
loop.o: $(hdrdir)/ruby/internal/newobj.h
+loop.o: $(hdrdir)/ruby/internal/rgengc.h
loop.o: $(hdrdir)/ruby/internal/scan_args.h
loop.o: $(hdrdir)/ruby/internal/special_consts.h
loop.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/rational/depend b/ext/-test-/rational/depend
index cff2eae38d..ce977821b8 100644
--- a/ext/-test-/rational/depend
+++ b/ext/-test-/rational/depend
@@ -56,7 +56,6 @@ rat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rat.o: $(hdrdir)/ruby/internal/attr/noinline.h
rat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rat.o: $(hdrdir)/ruby/internal/attr/pure.h
rat.o: $(hdrdir)/ruby/internal/attr/restrict.h
rat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -116,6 +115,7 @@ rat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rat.o: $(hdrdir)/ruby/internal/intern/error.h
rat.o: $(hdrdir)/ruby/internal/intern/eval.h
rat.o: $(hdrdir)/ruby/internal/intern/file.h
+rat.o: $(hdrdir)/ruby/internal/intern/gc.h
rat.o: $(hdrdir)/ruby/internal/intern/hash.h
rat.o: $(hdrdir)/ruby/internal/intern/io.h
rat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -146,6 +146,7 @@ rat.o: $(hdrdir)/ruby/internal/memory.h
rat.o: $(hdrdir)/ruby/internal/method.h
rat.o: $(hdrdir)/ruby/internal/module.h
rat.o: $(hdrdir)/ruby/internal/newobj.h
+rat.o: $(hdrdir)/ruby/internal/rgengc.h
rat.o: $(hdrdir)/ruby/internal/scan_args.h
rat.o: $(hdrdir)/ruby/internal/special_consts.h
rat.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/rb_call_super_kw/depend b/ext/-test-/rb_call_super_kw/depend
index a42ddc85ac..3512a081c9 100644
--- a/ext/-test-/rb_call_super_kw/depend
+++ b/ext/-test-/rb_call_super_kw/depend
@@ -52,7 +52,6 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/error.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/io.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/memory.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/method.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/module.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/newobj.h
+rb_call_super_kw.o: $(hdrdir)/ruby/internal/rgengc.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/scan_args.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/special_consts.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/recursion/depend b/ext/-test-/recursion/depend
index 49377250ef..e499f95e73 100644
--- a/ext/-test-/recursion/depend
+++ b/ext/-test-/recursion/depend
@@ -52,7 +52,6 @@ recursion.o: $(hdrdir)/ruby/internal/attr/noexcept.h
recursion.o: $(hdrdir)/ruby/internal/attr/noinline.h
recursion.o: $(hdrdir)/ruby/internal/attr/nonnull.h
recursion.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-recursion.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
recursion.o: $(hdrdir)/ruby/internal/attr/pure.h
recursion.o: $(hdrdir)/ruby/internal/attr/restrict.h
recursion.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ recursion.o: $(hdrdir)/ruby/internal/intern/enumerator.h
recursion.o: $(hdrdir)/ruby/internal/intern/error.h
recursion.o: $(hdrdir)/ruby/internal/intern/eval.h
recursion.o: $(hdrdir)/ruby/internal/intern/file.h
+recursion.o: $(hdrdir)/ruby/internal/intern/gc.h
recursion.o: $(hdrdir)/ruby/internal/intern/hash.h
recursion.o: $(hdrdir)/ruby/internal/intern/io.h
recursion.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ recursion.o: $(hdrdir)/ruby/internal/memory.h
recursion.o: $(hdrdir)/ruby/internal/method.h
recursion.o: $(hdrdir)/ruby/internal/module.h
recursion.o: $(hdrdir)/ruby/internal/newobj.h
+recursion.o: $(hdrdir)/ruby/internal/rgengc.h
recursion.o: $(hdrdir)/ruby/internal/scan_args.h
recursion.o: $(hdrdir)/ruby/internal/special_consts.h
recursion.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/regexp/depend b/ext/-test-/regexp/depend
index 484f0320dd..fa431e013a 100644
--- a/ext/-test-/regexp/depend
+++ b/ext/-test-/regexp/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/noexcept.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/noinline.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/nonnull.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/pure.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/restrict.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/enumerator.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/error.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/eval.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/file.h
+parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/gc.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/hash.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/io.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/memory.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/method.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/module.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/newobj.h
+parse_depth_limit.o: $(hdrdir)/ruby/internal/rgengc.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/scan_args.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/special_consts.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/scan_args/depend b/ext/-test-/scan_args/depend
index 3bedc6a7cf..2194936b04 100644
--- a/ext/-test-/scan_args/depend
+++ b/ext/-test-/scan_args/depend
@@ -52,7 +52,6 @@ scan_args.o: $(hdrdir)/ruby/internal/attr/noexcept.h
scan_args.o: $(hdrdir)/ruby/internal/attr/noinline.h
scan_args.o: $(hdrdir)/ruby/internal/attr/nonnull.h
scan_args.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-scan_args.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
scan_args.o: $(hdrdir)/ruby/internal/attr/pure.h
scan_args.o: $(hdrdir)/ruby/internal/attr/restrict.h
scan_args.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ scan_args.o: $(hdrdir)/ruby/internal/intern/enumerator.h
scan_args.o: $(hdrdir)/ruby/internal/intern/error.h
scan_args.o: $(hdrdir)/ruby/internal/intern/eval.h
scan_args.o: $(hdrdir)/ruby/internal/intern/file.h
+scan_args.o: $(hdrdir)/ruby/internal/intern/gc.h
scan_args.o: $(hdrdir)/ruby/internal/intern/hash.h
scan_args.o: $(hdrdir)/ruby/internal/intern/io.h
scan_args.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ scan_args.o: $(hdrdir)/ruby/internal/memory.h
scan_args.o: $(hdrdir)/ruby/internal/method.h
scan_args.o: $(hdrdir)/ruby/internal/module.h
scan_args.o: $(hdrdir)/ruby/internal/newobj.h
+scan_args.o: $(hdrdir)/ruby/internal/rgengc.h
scan_args.o: $(hdrdir)/ruby/internal/scan_args.h
scan_args.o: $(hdrdir)/ruby/internal/special_consts.h
scan_args.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/st/foreach/depend b/ext/-test-/st/foreach/depend
index fdfe356805..0464ee3c53 100644
--- a/ext/-test-/st/foreach/depend
+++ b/ext/-test-/st/foreach/depend
@@ -52,7 +52,6 @@ foreach.o: $(hdrdir)/ruby/internal/attr/noexcept.h
foreach.o: $(hdrdir)/ruby/internal/attr/noinline.h
foreach.o: $(hdrdir)/ruby/internal/attr/nonnull.h
foreach.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-foreach.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
foreach.o: $(hdrdir)/ruby/internal/attr/pure.h
foreach.o: $(hdrdir)/ruby/internal/attr/restrict.h
foreach.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ foreach.o: $(hdrdir)/ruby/internal/intern/enumerator.h
foreach.o: $(hdrdir)/ruby/internal/intern/error.h
foreach.o: $(hdrdir)/ruby/internal/intern/eval.h
foreach.o: $(hdrdir)/ruby/internal/intern/file.h
+foreach.o: $(hdrdir)/ruby/internal/intern/gc.h
foreach.o: $(hdrdir)/ruby/internal/intern/hash.h
foreach.o: $(hdrdir)/ruby/internal/intern/io.h
foreach.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ foreach.o: $(hdrdir)/ruby/internal/memory.h
foreach.o: $(hdrdir)/ruby/internal/method.h
foreach.o: $(hdrdir)/ruby/internal/module.h
foreach.o: $(hdrdir)/ruby/internal/newobj.h
+foreach.o: $(hdrdir)/ruby/internal/rgengc.h
foreach.o: $(hdrdir)/ruby/internal/scan_args.h
foreach.o: $(hdrdir)/ruby/internal/special_consts.h
foreach.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/st/foreach/foreach.c b/ext/-test-/st/foreach/foreach.c
index 7fbf064694..cde49fb26d 100644
--- a/ext/-test-/st/foreach/foreach.c
+++ b/ext/-test-/st/foreach/foreach.c
@@ -14,20 +14,20 @@ force_unpack_check(struct checker *c, st_data_t key, st_data_t val)
if (c->nr == 0) {
st_data_t i;
- if (c->tbl->bins != NULL) rb_bug("should be packed");
+ if (c->tbl->bins != NULL) rb_bug("should be packed\n");
/* force unpacking during iteration: */
for (i = 1; i < expect_size; i++)
st_add_direct(c->tbl, i, i);
- if (c->tbl->bins == NULL) rb_bug("should be unpacked");
+ if (c->tbl->bins == NULL) rb_bug("should be unpacked\n");
}
if (key != c->nr) {
- rb_bug("unexpected key: %"PRIuVALUE" (expected %"PRIuVALUE")", (VALUE)key, (VALUE)c->nr);
+ rb_bug("unexpected key: %"PRIuVALUE" (expected %"PRIuVALUE")\n", (VALUE)key, (VALUE)c->nr);
}
if (val != c->nr) {
- rb_bug("unexpected val: %"PRIuVALUE" (expected %"PRIuVALUE")", (VALUE)val, (VALUE)c->nr);
+ rb_bug("unexpected val: %"PRIuVALUE" (expected %"PRIuVALUE")\n", (VALUE)val, (VALUE)c->nr);
}
c->nr++;
@@ -60,7 +60,7 @@ unp_fec_i(st_data_t key, st_data_t val, st_data_t args, int error)
st_data_t v;
if (!st_delete(c->tbl, &k, &v)) {
- rb_bug("failed to delete");
+ rb_bug("failed to delete\n");
}
if (v != 0) {
rb_bug("unexpected value deleted: %"PRIuVALUE" (expected 0)", (VALUE)v);
@@ -84,21 +84,21 @@ unp_fec(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
+ if (tbl->bins != NULL) rb_bug("should still be packed\n");
st_foreach_check(tbl, unp_fec_i, (st_data_t)&c, -1);
if (c.test == ID2SYM(rb_intern("delete2"))) {
if (c.nr != 1) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)", (VALUE)c.nr);
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)\n", (VALUE)c.nr);
}
}
else if (c.nr != expect_size) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE")",
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE")\n",
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
+ if (tbl->bins == NULL) rb_bug("should be unpacked\n");
st_free_table(tbl);
@@ -120,14 +120,14 @@ unp_fe_i(st_data_t key, st_data_t val, st_data_t args)
st_data_t v;
if (!st_delete(c->tbl, &k, &v)) {
- rb_bug("failed to delete");
+ rb_bug("failed to delete\n");
}
if (v != 0) {
rb_bug("unexpected value deleted: %"PRIuVALUE" (expected 0)", (VALUE)v);
}
return ST_CONTINUE;
}
- rb_bug("should never get here");
+ rb_bug("should never get here\n");
}
rb_raise(rb_eArgError, "unexpected arg: %+"PRIsVALUE, c->test);
@@ -145,21 +145,21 @@ unp_fe(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
+ if (tbl->bins != NULL) rb_bug("should still be packed\n");
st_foreach(tbl, unp_fe_i, (st_data_t)&c);
if (c.test == ID2SYM(rb_intern("unpack_delete"))) {
if (c.nr != 1) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)", (VALUE)c.nr);
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)\n", (VALUE)c.nr);
}
}
else if (c.nr != expect_size) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE"o)",
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE"o)\n",
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
+ if (tbl->bins == NULL) rb_bug("should be unpacked\n");
st_free_table(tbl);
diff --git a/ext/-test-/st/numhash/depend b/ext/-test-/st/numhash/depend
index ef28c892f3..9665ed6e39 100644
--- a/ext/-test-/st/numhash/depend
+++ b/ext/-test-/st/numhash/depend
@@ -52,7 +52,6 @@ numhash.o: $(hdrdir)/ruby/internal/attr/noexcept.h
numhash.o: $(hdrdir)/ruby/internal/attr/noinline.h
numhash.o: $(hdrdir)/ruby/internal/attr/nonnull.h
numhash.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-numhash.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
numhash.o: $(hdrdir)/ruby/internal/attr/pure.h
numhash.o: $(hdrdir)/ruby/internal/attr/restrict.h
numhash.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ numhash.o: $(hdrdir)/ruby/internal/intern/enumerator.h
numhash.o: $(hdrdir)/ruby/internal/intern/error.h
numhash.o: $(hdrdir)/ruby/internal/intern/eval.h
numhash.o: $(hdrdir)/ruby/internal/intern/file.h
+numhash.o: $(hdrdir)/ruby/internal/intern/gc.h
numhash.o: $(hdrdir)/ruby/internal/intern/hash.h
numhash.o: $(hdrdir)/ruby/internal/intern/io.h
numhash.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ numhash.o: $(hdrdir)/ruby/internal/memory.h
numhash.o: $(hdrdir)/ruby/internal/method.h
numhash.o: $(hdrdir)/ruby/internal/module.h
numhash.o: $(hdrdir)/ruby/internal/newobj.h
+numhash.o: $(hdrdir)/ruby/internal/rgengc.h
numhash.o: $(hdrdir)/ruby/internal/scan_args.h
numhash.o: $(hdrdir)/ruby/internal/special_consts.h
numhash.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/st/update/depend b/ext/-test-/st/update/depend
index 2d5ff224a2..01960df965 100644
--- a/ext/-test-/st/update/depend
+++ b/ext/-test-/st/update/depend
@@ -52,7 +52,6 @@ update.o: $(hdrdir)/ruby/internal/attr/noexcept.h
update.o: $(hdrdir)/ruby/internal/attr/noinline.h
update.o: $(hdrdir)/ruby/internal/attr/nonnull.h
update.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-update.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
update.o: $(hdrdir)/ruby/internal/attr/pure.h
update.o: $(hdrdir)/ruby/internal/attr/restrict.h
update.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ update.o: $(hdrdir)/ruby/internal/intern/enumerator.h
update.o: $(hdrdir)/ruby/internal/intern/error.h
update.o: $(hdrdir)/ruby/internal/intern/eval.h
update.o: $(hdrdir)/ruby/internal/intern/file.h
+update.o: $(hdrdir)/ruby/internal/intern/gc.h
update.o: $(hdrdir)/ruby/internal/intern/hash.h
update.o: $(hdrdir)/ruby/internal/intern/io.h
update.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ update.o: $(hdrdir)/ruby/internal/memory.h
update.o: $(hdrdir)/ruby/internal/method.h
update.o: $(hdrdir)/ruby/internal/module.h
update.o: $(hdrdir)/ruby/internal/newobj.h
+update.o: $(hdrdir)/ruby/internal/rgengc.h
update.o: $(hdrdir)/ruby/internal/scan_args.h
update.o: $(hdrdir)/ruby/internal/special_consts.h
update.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/string/cstr.c b/ext/-test-/string/cstr.c
index b0b1ef5374..468ee7a3b1 100644
--- a/ext/-test-/string/cstr.c
+++ b/ext/-test-/string/cstr.c
@@ -61,12 +61,18 @@ bug_str_unterminated_substring(VALUE str, VALUE vbeg, VALUE vlen)
if (RSTRING_LEN(str) < beg) rb_raise(rb_eIndexError, "beg: %ld", beg);
if (RSTRING_LEN(str) < beg + len) rb_raise(rb_eIndexError, "end: %ld", beg + len);
str = rb_str_new_shared(str);
- RSTRING(str)->len = len;
if (STR_EMBED_P(str)) {
+#if USE_RVARGC
+ RSTRING(str)->as.embed.len = (short)len;
+#else
+ RSTRING(str)->basic.flags &= ~RSTRING_EMBED_LEN_MASK;
+ RSTRING(str)->basic.flags |= len << RSTRING_EMBED_LEN_SHIFT;
+#endif
memmove(RSTRING(str)->as.embed.ary, RSTRING(str)->as.embed.ary + beg, len);
}
else {
RSTRING(str)->as.heap.ptr += beg;
+ RSTRING(str)->as.heap.len = len;
}
return str;
}
@@ -110,10 +116,14 @@ bug_str_s_cstr_noembed(VALUE self, VALUE str)
Check_Type(str, T_STRING);
FL_SET((str2), STR_NOEMBED);
memcpy(buf, RSTRING_PTR(str), capacity);
+#if USE_RVARGC
RBASIC(str2)->flags &= ~(STR_SHARED | FL_USER5 | FL_USER6);
+#else
+ RBASIC(str2)->flags &= ~RSTRING_EMBED_LEN_MASK;
+#endif
RSTRING(str2)->as.heap.aux.capa = capacity;
RSTRING(str2)->as.heap.ptr = buf;
- RSTRING(str2)->len = RSTRING_LEN(str);
+ RSTRING(str2)->as.heap.len = RSTRING_LEN(str);
TERM_FILL(RSTRING_END(str2), TERM_LEN(str));
return str2;
}
diff --git a/ext/-test-/string/depend b/ext/-test-/string/depend
index eeb4914346..773231047e 100644
--- a/ext/-test-/string/depend
+++ b/ext/-test-/string/depend
@@ -54,7 +54,6 @@ capacity.o: $(hdrdir)/ruby/internal/attr/noexcept.h
capacity.o: $(hdrdir)/ruby/internal/attr/noinline.h
capacity.o: $(hdrdir)/ruby/internal/attr/nonnull.h
capacity.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-capacity.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
capacity.o: $(hdrdir)/ruby/internal/attr/pure.h
capacity.o: $(hdrdir)/ruby/internal/attr/restrict.h
capacity.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -123,6 +122,7 @@ capacity.o: $(hdrdir)/ruby/internal/intern/enumerator.h
capacity.o: $(hdrdir)/ruby/internal/intern/error.h
capacity.o: $(hdrdir)/ruby/internal/intern/eval.h
capacity.o: $(hdrdir)/ruby/internal/intern/file.h
+capacity.o: $(hdrdir)/ruby/internal/intern/gc.h
capacity.o: $(hdrdir)/ruby/internal/intern/hash.h
capacity.o: $(hdrdir)/ruby/internal/intern/io.h
capacity.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -153,6 +153,7 @@ capacity.o: $(hdrdir)/ruby/internal/memory.h
capacity.o: $(hdrdir)/ruby/internal/method.h
capacity.o: $(hdrdir)/ruby/internal/module.h
capacity.o: $(hdrdir)/ruby/internal/newobj.h
+capacity.o: $(hdrdir)/ruby/internal/rgengc.h
capacity.o: $(hdrdir)/ruby/internal/scan_args.h
capacity.o: $(hdrdir)/ruby/internal/special_consts.h
capacity.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -226,7 +227,6 @@ coderange.o: $(hdrdir)/ruby/internal/attr/noexcept.h
coderange.o: $(hdrdir)/ruby/internal/attr/noinline.h
coderange.o: $(hdrdir)/ruby/internal/attr/nonnull.h
coderange.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-coderange.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
coderange.o: $(hdrdir)/ruby/internal/attr/pure.h
coderange.o: $(hdrdir)/ruby/internal/attr/restrict.h
coderange.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -295,6 +295,7 @@ coderange.o: $(hdrdir)/ruby/internal/intern/enumerator.h
coderange.o: $(hdrdir)/ruby/internal/intern/error.h
coderange.o: $(hdrdir)/ruby/internal/intern/eval.h
coderange.o: $(hdrdir)/ruby/internal/intern/file.h
+coderange.o: $(hdrdir)/ruby/internal/intern/gc.h
coderange.o: $(hdrdir)/ruby/internal/intern/hash.h
coderange.o: $(hdrdir)/ruby/internal/intern/io.h
coderange.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -325,6 +326,7 @@ coderange.o: $(hdrdir)/ruby/internal/memory.h
coderange.o: $(hdrdir)/ruby/internal/method.h
coderange.o: $(hdrdir)/ruby/internal/module.h
coderange.o: $(hdrdir)/ruby/internal/newobj.h
+coderange.o: $(hdrdir)/ruby/internal/rgengc.h
coderange.o: $(hdrdir)/ruby/internal/scan_args.h
coderange.o: $(hdrdir)/ruby/internal/special_consts.h
coderange.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -397,7 +399,6 @@ cstr.o: $(hdrdir)/ruby/internal/attr/noexcept.h
cstr.o: $(hdrdir)/ruby/internal/attr/noinline.h
cstr.o: $(hdrdir)/ruby/internal/attr/nonnull.h
cstr.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-cstr.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
cstr.o: $(hdrdir)/ruby/internal/attr/pure.h
cstr.o: $(hdrdir)/ruby/internal/attr/restrict.h
cstr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -466,6 +467,7 @@ cstr.o: $(hdrdir)/ruby/internal/intern/enumerator.h
cstr.o: $(hdrdir)/ruby/internal/intern/error.h
cstr.o: $(hdrdir)/ruby/internal/intern/eval.h
cstr.o: $(hdrdir)/ruby/internal/intern/file.h
+cstr.o: $(hdrdir)/ruby/internal/intern/gc.h
cstr.o: $(hdrdir)/ruby/internal/intern/hash.h
cstr.o: $(hdrdir)/ruby/internal/intern/io.h
cstr.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -496,6 +498,7 @@ cstr.o: $(hdrdir)/ruby/internal/memory.h
cstr.o: $(hdrdir)/ruby/internal/method.h
cstr.o: $(hdrdir)/ruby/internal/module.h
cstr.o: $(hdrdir)/ruby/internal/newobj.h
+cstr.o: $(hdrdir)/ruby/internal/rgengc.h
cstr.o: $(hdrdir)/ruby/internal/scan_args.h
cstr.o: $(hdrdir)/ruby/internal/special_consts.h
cstr.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -570,7 +573,6 @@ ellipsize.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/noinline.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ellipsize.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/pure.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/restrict.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -630,6 +632,7 @@ ellipsize.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/error.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/eval.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/file.h
+ellipsize.o: $(hdrdir)/ruby/internal/intern/gc.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/hash.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/io.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -660,6 +663,7 @@ ellipsize.o: $(hdrdir)/ruby/internal/memory.h
ellipsize.o: $(hdrdir)/ruby/internal/method.h
ellipsize.o: $(hdrdir)/ruby/internal/module.h
ellipsize.o: $(hdrdir)/ruby/internal/newobj.h
+ellipsize.o: $(hdrdir)/ruby/internal/rgengc.h
ellipsize.o: $(hdrdir)/ruby/internal/scan_args.h
ellipsize.o: $(hdrdir)/ruby/internal/special_consts.h
ellipsize.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -730,7 +734,6 @@ enc_associate.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/noinline.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_associate.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/pure.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/restrict.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -799,6 +802,7 @@ enc_associate.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/error.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/eval.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/file.h
+enc_associate.o: $(hdrdir)/ruby/internal/intern/gc.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/hash.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/io.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -829,6 +833,7 @@ enc_associate.o: $(hdrdir)/ruby/internal/memory.h
enc_associate.o: $(hdrdir)/ruby/internal/method.h
enc_associate.o: $(hdrdir)/ruby/internal/module.h
enc_associate.o: $(hdrdir)/ruby/internal/newobj.h
+enc_associate.o: $(hdrdir)/ruby/internal/rgengc.h
enc_associate.o: $(hdrdir)/ruby/internal/scan_args.h
enc_associate.o: $(hdrdir)/ruby/internal/special_consts.h
enc_associate.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -847,177 +852,6 @@ enc_associate.o: $(hdrdir)/ruby/ruby.h
enc_associate.o: $(hdrdir)/ruby/st.h
enc_associate.o: $(hdrdir)/ruby/subst.h
enc_associate.o: enc_associate.c
-enc_dummy.o: $(RUBY_EXTCONF_H)
-enc_dummy.o: $(arch_hdrdir)/ruby/config.h
-enc_dummy.o: $(hdrdir)/ruby.h
-enc_dummy.o: $(hdrdir)/ruby/assert.h
-enc_dummy.o: $(hdrdir)/ruby/backward.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/assume.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/attributes.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/bool.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/inttypes.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/limits.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/long_long.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/stdalign.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/stdarg.h
-enc_dummy.o: $(hdrdir)/ruby/defines.h
-enc_dummy.o: $(hdrdir)/ruby/encoding.h
-enc_dummy.o: $(hdrdir)/ruby/intern.h
-enc_dummy.o: $(hdrdir)/ruby/internal/abi.h
-enc_dummy.o: $(hdrdir)/ruby/internal/anyargs.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/assume.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/artificial.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/cold.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/const.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/error.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/format.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noalias.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noinline.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/pure.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/restrict.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/warning.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/weakref.h
-enc_dummy.o: $(hdrdir)/ruby/internal/cast.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_since.h
-enc_dummy.o: $(hdrdir)/ruby/internal/config.h
-enc_dummy.o: $(hdrdir)/ruby/internal/constant_p.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rarray.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rbasic.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rbignum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rclass.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rdata.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rfile.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rhash.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/robject.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rregexp.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rstring.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rstruct.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-enc_dummy.o: $(hdrdir)/ruby/internal/ctype.h
-enc_dummy.o: $(hdrdir)/ruby/internal/dllexport.h
-enc_dummy.o: $(hdrdir)/ruby/internal/dosish.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/re.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/string.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-enc_dummy.o: $(hdrdir)/ruby/internal/error.h
-enc_dummy.o: $(hdrdir)/ruby/internal/eval.h
-enc_dummy.o: $(hdrdir)/ruby/internal/event.h
-enc_dummy.o: $(hdrdir)/ruby/internal/fl_type.h
-enc_dummy.o: $(hdrdir)/ruby/internal/gc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/glob.h
-enc_dummy.o: $(hdrdir)/ruby/internal/globals.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/builtin.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/extension.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/feature.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/warning.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/array.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/bignum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/class.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/compar.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/complex.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/cont.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/dir.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/enum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/error.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/eval.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/file.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/hash.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/io.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/load.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/marshal.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/numeric.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/object.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/parse.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/proc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/process.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/random.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/range.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/rational.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/re.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/ruby.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/select.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/signal.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/string.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/struct.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/thread.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/time.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/variable.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/vm.h
-enc_dummy.o: $(hdrdir)/ruby/internal/interpreter.h
-enc_dummy.o: $(hdrdir)/ruby/internal/iterator.h
-enc_dummy.o: $(hdrdir)/ruby/internal/memory.h
-enc_dummy.o: $(hdrdir)/ruby/internal/method.h
-enc_dummy.o: $(hdrdir)/ruby/internal/module.h
-enc_dummy.o: $(hdrdir)/ruby/internal/newobj.h
-enc_dummy.o: $(hdrdir)/ruby/internal/scan_args.h
-enc_dummy.o: $(hdrdir)/ruby/internal/special_consts.h
-enc_dummy.o: $(hdrdir)/ruby/internal/static_assert.h
-enc_dummy.o: $(hdrdir)/ruby/internal/stdalign.h
-enc_dummy.o: $(hdrdir)/ruby/internal/stdbool.h
-enc_dummy.o: $(hdrdir)/ruby/internal/symbol.h
-enc_dummy.o: $(hdrdir)/ruby/internal/value.h
-enc_dummy.o: $(hdrdir)/ruby/internal/value_type.h
-enc_dummy.o: $(hdrdir)/ruby/internal/variable.h
-enc_dummy.o: $(hdrdir)/ruby/internal/warning_push.h
-enc_dummy.o: $(hdrdir)/ruby/internal/xmalloc.h
-enc_dummy.o: $(hdrdir)/ruby/missing.h
-enc_dummy.o: $(hdrdir)/ruby/onigmo.h
-enc_dummy.o: $(hdrdir)/ruby/oniguruma.h
-enc_dummy.o: $(hdrdir)/ruby/ruby.h
-enc_dummy.o: $(hdrdir)/ruby/st.h
-enc_dummy.o: $(hdrdir)/ruby/subst.h
-enc_dummy.o: enc_dummy.c
enc_str_buf_cat.o: $(RUBY_EXTCONF_H)
enc_str_buf_cat.o: $(arch_hdrdir)/ruby/config.h
enc_str_buf_cat.o: $(hdrdir)/ruby/assert.h
@@ -1071,7 +905,6 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/noinline.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/pure.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/restrict.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1140,6 +973,7 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/error.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/eval.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/file.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/gc.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/hash.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/io.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1170,6 +1004,7 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/memory.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/method.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/module.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/newobj.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/internal/rgengc.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/scan_args.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/special_consts.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1196,7 +1031,6 @@ fstring.o: $(hdrdir)/ruby/backward.h
fstring.o: $(hdrdir)/ruby/backward/2/assume.h
fstring.o: $(hdrdir)/ruby/backward/2/attributes.h
fstring.o: $(hdrdir)/ruby/backward/2/bool.h
-fstring.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
fstring.o: $(hdrdir)/ruby/backward/2/inttypes.h
fstring.o: $(hdrdir)/ruby/backward/2/limits.h
fstring.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -1243,7 +1077,6 @@ fstring.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fstring.o: $(hdrdir)/ruby/internal/attr/noinline.h
fstring.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fstring.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fstring.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fstring.o: $(hdrdir)/ruby/internal/attr/pure.h
fstring.o: $(hdrdir)/ruby/internal/attr/restrict.h
fstring.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1312,6 +1145,7 @@ fstring.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fstring.o: $(hdrdir)/ruby/internal/intern/error.h
fstring.o: $(hdrdir)/ruby/internal/intern/eval.h
fstring.o: $(hdrdir)/ruby/internal/intern/file.h
+fstring.o: $(hdrdir)/ruby/internal/intern/gc.h
fstring.o: $(hdrdir)/ruby/internal/intern/hash.h
fstring.o: $(hdrdir)/ruby/internal/intern/io.h
fstring.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1342,6 +1176,7 @@ fstring.o: $(hdrdir)/ruby/internal/memory.h
fstring.o: $(hdrdir)/ruby/internal/method.h
fstring.o: $(hdrdir)/ruby/internal/module.h
fstring.o: $(hdrdir)/ruby/internal/newobj.h
+fstring.o: $(hdrdir)/ruby/internal/rgengc.h
fstring.o: $(hdrdir)/ruby/internal/scan_args.h
fstring.o: $(hdrdir)/ruby/internal/special_consts.h
fstring.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1359,8 +1194,6 @@ fstring.o: $(hdrdir)/ruby/oniguruma.h
fstring.o: $(hdrdir)/ruby/ruby.h
fstring.o: $(hdrdir)/ruby/st.h
fstring.o: $(hdrdir)/ruby/subst.h
-fstring.o: $(top_srcdir)/internal/compilers.h
-fstring.o: $(top_srcdir)/internal/string.h
fstring.o: fstring.c
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
@@ -1415,7 +1248,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1475,6 +1307,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1505,6 +1338,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1574,7 +1408,6 @@ modify.o: $(hdrdir)/ruby/internal/attr/noexcept.h
modify.o: $(hdrdir)/ruby/internal/attr/noinline.h
modify.o: $(hdrdir)/ruby/internal/attr/nonnull.h
modify.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-modify.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
modify.o: $(hdrdir)/ruby/internal/attr/pure.h
modify.o: $(hdrdir)/ruby/internal/attr/restrict.h
modify.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1634,6 +1467,7 @@ modify.o: $(hdrdir)/ruby/internal/intern/enumerator.h
modify.o: $(hdrdir)/ruby/internal/intern/error.h
modify.o: $(hdrdir)/ruby/internal/intern/eval.h
modify.o: $(hdrdir)/ruby/internal/intern/file.h
+modify.o: $(hdrdir)/ruby/internal/intern/gc.h
modify.o: $(hdrdir)/ruby/internal/intern/hash.h
modify.o: $(hdrdir)/ruby/internal/intern/io.h
modify.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1664,6 +1498,7 @@ modify.o: $(hdrdir)/ruby/internal/memory.h
modify.o: $(hdrdir)/ruby/internal/method.h
modify.o: $(hdrdir)/ruby/internal/module.h
modify.o: $(hdrdir)/ruby/internal/newobj.h
+modify.o: $(hdrdir)/ruby/internal/rgengc.h
modify.o: $(hdrdir)/ruby/internal/scan_args.h
modify.o: $(hdrdir)/ruby/internal/special_consts.h
modify.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1734,7 +1569,6 @@ new.o: $(hdrdir)/ruby/internal/attr/noexcept.h
new.o: $(hdrdir)/ruby/internal/attr/noinline.h
new.o: $(hdrdir)/ruby/internal/attr/nonnull.h
new.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-new.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
new.o: $(hdrdir)/ruby/internal/attr/pure.h
new.o: $(hdrdir)/ruby/internal/attr/restrict.h
new.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1803,6 +1637,7 @@ new.o: $(hdrdir)/ruby/internal/intern/enumerator.h
new.o: $(hdrdir)/ruby/internal/intern/error.h
new.o: $(hdrdir)/ruby/internal/intern/eval.h
new.o: $(hdrdir)/ruby/internal/intern/file.h
+new.o: $(hdrdir)/ruby/internal/intern/gc.h
new.o: $(hdrdir)/ruby/internal/intern/hash.h
new.o: $(hdrdir)/ruby/internal/intern/io.h
new.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1833,6 +1668,7 @@ new.o: $(hdrdir)/ruby/internal/memory.h
new.o: $(hdrdir)/ruby/internal/method.h
new.o: $(hdrdir)/ruby/internal/module.h
new.o: $(hdrdir)/ruby/internal/newobj.h
+new.o: $(hdrdir)/ruby/internal/rgengc.h
new.o: $(hdrdir)/ruby/internal/scan_args.h
new.o: $(hdrdir)/ruby/internal/special_consts.h
new.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1904,7 +1740,6 @@ nofree.o: $(hdrdir)/ruby/internal/attr/noexcept.h
nofree.o: $(hdrdir)/ruby/internal/attr/noinline.h
nofree.o: $(hdrdir)/ruby/internal/attr/nonnull.h
nofree.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-nofree.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
nofree.o: $(hdrdir)/ruby/internal/attr/pure.h
nofree.o: $(hdrdir)/ruby/internal/attr/restrict.h
nofree.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1964,6 +1799,7 @@ nofree.o: $(hdrdir)/ruby/internal/intern/enumerator.h
nofree.o: $(hdrdir)/ruby/internal/intern/error.h
nofree.o: $(hdrdir)/ruby/internal/intern/eval.h
nofree.o: $(hdrdir)/ruby/internal/intern/file.h
+nofree.o: $(hdrdir)/ruby/internal/intern/gc.h
nofree.o: $(hdrdir)/ruby/internal/intern/hash.h
nofree.o: $(hdrdir)/ruby/internal/intern/io.h
nofree.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1994,6 +1830,7 @@ nofree.o: $(hdrdir)/ruby/internal/memory.h
nofree.o: $(hdrdir)/ruby/internal/method.h
nofree.o: $(hdrdir)/ruby/internal/module.h
nofree.o: $(hdrdir)/ruby/internal/newobj.h
+nofree.o: $(hdrdir)/ruby/internal/rgengc.h
nofree.o: $(hdrdir)/ruby/internal/scan_args.h
nofree.o: $(hdrdir)/ruby/internal/special_consts.h
nofree.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2063,7 +1900,6 @@ normalize.o: $(hdrdir)/ruby/internal/attr/noexcept.h
normalize.o: $(hdrdir)/ruby/internal/attr/noinline.h
normalize.o: $(hdrdir)/ruby/internal/attr/nonnull.h
normalize.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-normalize.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
normalize.o: $(hdrdir)/ruby/internal/attr/pure.h
normalize.o: $(hdrdir)/ruby/internal/attr/restrict.h
normalize.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2132,6 +1968,7 @@ normalize.o: $(hdrdir)/ruby/internal/intern/enumerator.h
normalize.o: $(hdrdir)/ruby/internal/intern/error.h
normalize.o: $(hdrdir)/ruby/internal/intern/eval.h
normalize.o: $(hdrdir)/ruby/internal/intern/file.h
+normalize.o: $(hdrdir)/ruby/internal/intern/gc.h
normalize.o: $(hdrdir)/ruby/internal/intern/hash.h
normalize.o: $(hdrdir)/ruby/internal/intern/io.h
normalize.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2162,6 +1999,7 @@ normalize.o: $(hdrdir)/ruby/internal/memory.h
normalize.o: $(hdrdir)/ruby/internal/method.h
normalize.o: $(hdrdir)/ruby/internal/module.h
normalize.o: $(hdrdir)/ruby/internal/newobj.h
+normalize.o: $(hdrdir)/ruby/internal/rgengc.h
normalize.o: $(hdrdir)/ruby/internal/scan_args.h
normalize.o: $(hdrdir)/ruby/internal/special_consts.h
normalize.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2235,7 +2073,6 @@ qsort.o: $(hdrdir)/ruby/internal/attr/noexcept.h
qsort.o: $(hdrdir)/ruby/internal/attr/noinline.h
qsort.o: $(hdrdir)/ruby/internal/attr/nonnull.h
qsort.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-qsort.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
qsort.o: $(hdrdir)/ruby/internal/attr/pure.h
qsort.o: $(hdrdir)/ruby/internal/attr/restrict.h
qsort.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2304,6 +2141,7 @@ qsort.o: $(hdrdir)/ruby/internal/intern/enumerator.h
qsort.o: $(hdrdir)/ruby/internal/intern/error.h
qsort.o: $(hdrdir)/ruby/internal/intern/eval.h
qsort.o: $(hdrdir)/ruby/internal/intern/file.h
+qsort.o: $(hdrdir)/ruby/internal/intern/gc.h
qsort.o: $(hdrdir)/ruby/internal/intern/hash.h
qsort.o: $(hdrdir)/ruby/internal/intern/io.h
qsort.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2334,6 +2172,7 @@ qsort.o: $(hdrdir)/ruby/internal/memory.h
qsort.o: $(hdrdir)/ruby/internal/method.h
qsort.o: $(hdrdir)/ruby/internal/module.h
qsort.o: $(hdrdir)/ruby/internal/newobj.h
+qsort.o: $(hdrdir)/ruby/internal/rgengc.h
qsort.o: $(hdrdir)/ruby/internal/scan_args.h
qsort.o: $(hdrdir)/ruby/internal/special_consts.h
qsort.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2406,7 +2245,6 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_interned_str.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2466,6 +2304,7 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/error.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_interned_str.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/io.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2496,6 +2335,7 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/memory.h
rb_interned_str.o: $(hdrdir)/ruby/internal/method.h
rb_interned_str.o: $(hdrdir)/ruby/internal/module.h
rb_interned_str.o: $(hdrdir)/ruby/internal/newobj.h
+rb_interned_str.o: $(hdrdir)/ruby/internal/rgengc.h
rb_interned_str.o: $(hdrdir)/ruby/internal/scan_args.h
rb_interned_str.o: $(hdrdir)/ruby/internal/special_consts.h
rb_interned_str.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2565,7 +2405,6 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_str_dup.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2625,6 +2464,7 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/error.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_str_dup.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/io.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2655,6 +2495,7 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/memory.h
rb_str_dup.o: $(hdrdir)/ruby/internal/method.h
rb_str_dup.o: $(hdrdir)/ruby/internal/module.h
rb_str_dup.o: $(hdrdir)/ruby/internal/newobj.h
+rb_str_dup.o: $(hdrdir)/ruby/internal/rgengc.h
rb_str_dup.o: $(hdrdir)/ruby/internal/scan_args.h
rb_str_dup.o: $(hdrdir)/ruby/internal/special_consts.h
rb_str_dup.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2724,7 +2565,6 @@ set_len.o: $(hdrdir)/ruby/internal/attr/noexcept.h
set_len.o: $(hdrdir)/ruby/internal/attr/noinline.h
set_len.o: $(hdrdir)/ruby/internal/attr/nonnull.h
set_len.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-set_len.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
set_len.o: $(hdrdir)/ruby/internal/attr/pure.h
set_len.o: $(hdrdir)/ruby/internal/attr/restrict.h
set_len.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2784,6 +2624,7 @@ set_len.o: $(hdrdir)/ruby/internal/intern/enumerator.h
set_len.o: $(hdrdir)/ruby/internal/intern/error.h
set_len.o: $(hdrdir)/ruby/internal/intern/eval.h
set_len.o: $(hdrdir)/ruby/internal/intern/file.h
+set_len.o: $(hdrdir)/ruby/internal/intern/gc.h
set_len.o: $(hdrdir)/ruby/internal/intern/hash.h
set_len.o: $(hdrdir)/ruby/internal/intern/io.h
set_len.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2814,6 +2655,7 @@ set_len.o: $(hdrdir)/ruby/internal/memory.h
set_len.o: $(hdrdir)/ruby/internal/method.h
set_len.o: $(hdrdir)/ruby/internal/module.h
set_len.o: $(hdrdir)/ruby/internal/newobj.h
+set_len.o: $(hdrdir)/ruby/internal/rgengc.h
set_len.o: $(hdrdir)/ruby/internal/scan_args.h
set_len.o: $(hdrdir)/ruby/internal/special_consts.h
set_len.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/string/enc_dummy.c b/ext/-test-/string/enc_dummy.c
deleted file mode 100644
index 4169552655..0000000000
--- a/ext/-test-/string/enc_dummy.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "ruby.h"
-#include "ruby/encoding.h"
-
-VALUE
-bug_rb_define_dummy_encoding(VALUE self, VALUE name)
-{
- int idx = rb_define_dummy_encoding(RSTRING_PTR(name));
- return rb_enc_from_encoding(rb_enc_from_index(idx));
-}
-
-void
-Init_string_enc_dummy(VALUE klass)
-{
- rb_define_singleton_method(klass, "rb_define_dummy_encoding", bug_rb_define_dummy_encoding, 1);
-}
diff --git a/ext/-test-/string/fstring.c b/ext/-test-/string/fstring.c
index 7ee14a8570..64f079251d 100644
--- a/ext/-test-/string/fstring.c
+++ b/ext/-test-/string/fstring.c
@@ -1,6 +1,5 @@
#include "ruby.h"
#include "ruby/encoding.h"
-#include "internal/string.h"
VALUE rb_fstring(VALUE str);
@@ -11,30 +10,21 @@ bug_s_fstring(VALUE self, VALUE str)
}
VALUE
-bug_s_fstring_fake_str(VALUE self)
-{
- static const char literal[] = "abcdefghijklmnopqrstuvwxyz";
- struct RString fake_str;
- return rb_fstring(rb_setup_fake_str(&fake_str, literal, sizeof(literal) - 1, 0));
-}
-
-VALUE
bug_s_rb_enc_interned_str(VALUE self, VALUE encoding)
{
- return rb_enc_interned_str("foo", 3, RDATA(encoding)->data);
+ return rb_enc_interned_str("foo", 3, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
}
VALUE
bug_s_rb_enc_str_new(VALUE self, VALUE encoding)
{
- return rb_enc_str_new("foo", 3, RDATA(encoding)->data);
+ return rb_enc_str_new("foo", 3, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
}
void
Init_string_fstring(VALUE klass)
{
rb_define_singleton_method(klass, "fstring", bug_s_fstring, 1);
- rb_define_singleton_method(klass, "fstring_fake_str", bug_s_fstring_fake_str, 0);
rb_define_singleton_method(klass, "rb_enc_interned_str", bug_s_rb_enc_interned_str, 1);
rb_define_singleton_method(klass, "rb_enc_str_new", bug_s_rb_enc_str_new, 1);
}
diff --git a/ext/-test-/struct/data.c b/ext/-test-/struct/data.c
deleted file mode 100644
index 5841c342e7..0000000000
--- a/ext/-test-/struct/data.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "ruby.h"
-
-static VALUE
-bug_data_new(VALUE self, VALUE super)
-{
- return rb_data_define(super, "mem1", "mem2", NULL);
-}
-
-void
-Init_data(VALUE klass)
-{
- rb_define_singleton_method(klass, "data_new", bug_data_new, 1);
-}
diff --git a/ext/-test-/struct/depend b/ext/-test-/struct/depend
index 5db943e286..920a065216 100644
--- a/ext/-test-/struct/depend
+++ b/ext/-test-/struct/depend
@@ -1,163 +1,4 @@
# AUTOGENERATED DEPENDENCIES START
-data.o: $(RUBY_EXTCONF_H)
-data.o: $(arch_hdrdir)/ruby/config.h
-data.o: $(hdrdir)/ruby.h
-data.o: $(hdrdir)/ruby/assert.h
-data.o: $(hdrdir)/ruby/backward.h
-data.o: $(hdrdir)/ruby/backward/2/assume.h
-data.o: $(hdrdir)/ruby/backward/2/attributes.h
-data.o: $(hdrdir)/ruby/backward/2/bool.h
-data.o: $(hdrdir)/ruby/backward/2/inttypes.h
-data.o: $(hdrdir)/ruby/backward/2/limits.h
-data.o: $(hdrdir)/ruby/backward/2/long_long.h
-data.o: $(hdrdir)/ruby/backward/2/stdalign.h
-data.o: $(hdrdir)/ruby/backward/2/stdarg.h
-data.o: $(hdrdir)/ruby/defines.h
-data.o: $(hdrdir)/ruby/intern.h
-data.o: $(hdrdir)/ruby/internal/abi.h
-data.o: $(hdrdir)/ruby/internal/anyargs.h
-data.o: $(hdrdir)/ruby/internal/arithmetic.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-data.o: $(hdrdir)/ruby/internal/assume.h
-data.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-data.o: $(hdrdir)/ruby/internal/attr/artificial.h
-data.o: $(hdrdir)/ruby/internal/attr/cold.h
-data.o: $(hdrdir)/ruby/internal/attr/const.h
-data.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-data.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-data.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-data.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-data.o: $(hdrdir)/ruby/internal/attr/error.h
-data.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-data.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-data.o: $(hdrdir)/ruby/internal/attr/format.h
-data.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-data.o: $(hdrdir)/ruby/internal/attr/noalias.h
-data.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-data.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-data.o: $(hdrdir)/ruby/internal/attr/noinline.h
-data.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-data.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-data.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-data.o: $(hdrdir)/ruby/internal/attr/pure.h
-data.o: $(hdrdir)/ruby/internal/attr/restrict.h
-data.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-data.o: $(hdrdir)/ruby/internal/attr/warning.h
-data.o: $(hdrdir)/ruby/internal/attr/weakref.h
-data.o: $(hdrdir)/ruby/internal/cast.h
-data.o: $(hdrdir)/ruby/internal/compiler_is.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-data.o: $(hdrdir)/ruby/internal/compiler_since.h
-data.o: $(hdrdir)/ruby/internal/config.h
-data.o: $(hdrdir)/ruby/internal/constant_p.h
-data.o: $(hdrdir)/ruby/internal/core.h
-data.o: $(hdrdir)/ruby/internal/core/rarray.h
-data.o: $(hdrdir)/ruby/internal/core/rbasic.h
-data.o: $(hdrdir)/ruby/internal/core/rbignum.h
-data.o: $(hdrdir)/ruby/internal/core/rclass.h
-data.o: $(hdrdir)/ruby/internal/core/rdata.h
-data.o: $(hdrdir)/ruby/internal/core/rfile.h
-data.o: $(hdrdir)/ruby/internal/core/rhash.h
-data.o: $(hdrdir)/ruby/internal/core/robject.h
-data.o: $(hdrdir)/ruby/internal/core/rregexp.h
-data.o: $(hdrdir)/ruby/internal/core/rstring.h
-data.o: $(hdrdir)/ruby/internal/core/rstruct.h
-data.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-data.o: $(hdrdir)/ruby/internal/ctype.h
-data.o: $(hdrdir)/ruby/internal/dllexport.h
-data.o: $(hdrdir)/ruby/internal/dosish.h
-data.o: $(hdrdir)/ruby/internal/error.h
-data.o: $(hdrdir)/ruby/internal/eval.h
-data.o: $(hdrdir)/ruby/internal/event.h
-data.o: $(hdrdir)/ruby/internal/fl_type.h
-data.o: $(hdrdir)/ruby/internal/gc.h
-data.o: $(hdrdir)/ruby/internal/glob.h
-data.o: $(hdrdir)/ruby/internal/globals.h
-data.o: $(hdrdir)/ruby/internal/has/attribute.h
-data.o: $(hdrdir)/ruby/internal/has/builtin.h
-data.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-data.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-data.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-data.o: $(hdrdir)/ruby/internal/has/extension.h
-data.o: $(hdrdir)/ruby/internal/has/feature.h
-data.o: $(hdrdir)/ruby/internal/has/warning.h
-data.o: $(hdrdir)/ruby/internal/intern/array.h
-data.o: $(hdrdir)/ruby/internal/intern/bignum.h
-data.o: $(hdrdir)/ruby/internal/intern/class.h
-data.o: $(hdrdir)/ruby/internal/intern/compar.h
-data.o: $(hdrdir)/ruby/internal/intern/complex.h
-data.o: $(hdrdir)/ruby/internal/intern/cont.h
-data.o: $(hdrdir)/ruby/internal/intern/dir.h
-data.o: $(hdrdir)/ruby/internal/intern/enum.h
-data.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-data.o: $(hdrdir)/ruby/internal/intern/error.h
-data.o: $(hdrdir)/ruby/internal/intern/eval.h
-data.o: $(hdrdir)/ruby/internal/intern/file.h
-data.o: $(hdrdir)/ruby/internal/intern/hash.h
-data.o: $(hdrdir)/ruby/internal/intern/io.h
-data.o: $(hdrdir)/ruby/internal/intern/load.h
-data.o: $(hdrdir)/ruby/internal/intern/marshal.h
-data.o: $(hdrdir)/ruby/internal/intern/numeric.h
-data.o: $(hdrdir)/ruby/internal/intern/object.h
-data.o: $(hdrdir)/ruby/internal/intern/parse.h
-data.o: $(hdrdir)/ruby/internal/intern/proc.h
-data.o: $(hdrdir)/ruby/internal/intern/process.h
-data.o: $(hdrdir)/ruby/internal/intern/random.h
-data.o: $(hdrdir)/ruby/internal/intern/range.h
-data.o: $(hdrdir)/ruby/internal/intern/rational.h
-data.o: $(hdrdir)/ruby/internal/intern/re.h
-data.o: $(hdrdir)/ruby/internal/intern/ruby.h
-data.o: $(hdrdir)/ruby/internal/intern/select.h
-data.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-data.o: $(hdrdir)/ruby/internal/intern/signal.h
-data.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-data.o: $(hdrdir)/ruby/internal/intern/string.h
-data.o: $(hdrdir)/ruby/internal/intern/struct.h
-data.o: $(hdrdir)/ruby/internal/intern/thread.h
-data.o: $(hdrdir)/ruby/internal/intern/time.h
-data.o: $(hdrdir)/ruby/internal/intern/variable.h
-data.o: $(hdrdir)/ruby/internal/intern/vm.h
-data.o: $(hdrdir)/ruby/internal/interpreter.h
-data.o: $(hdrdir)/ruby/internal/iterator.h
-data.o: $(hdrdir)/ruby/internal/memory.h
-data.o: $(hdrdir)/ruby/internal/method.h
-data.o: $(hdrdir)/ruby/internal/module.h
-data.o: $(hdrdir)/ruby/internal/newobj.h
-data.o: $(hdrdir)/ruby/internal/scan_args.h
-data.o: $(hdrdir)/ruby/internal/special_consts.h
-data.o: $(hdrdir)/ruby/internal/static_assert.h
-data.o: $(hdrdir)/ruby/internal/stdalign.h
-data.o: $(hdrdir)/ruby/internal/stdbool.h
-data.o: $(hdrdir)/ruby/internal/symbol.h
-data.o: $(hdrdir)/ruby/internal/value.h
-data.o: $(hdrdir)/ruby/internal/value_type.h
-data.o: $(hdrdir)/ruby/internal/variable.h
-data.o: $(hdrdir)/ruby/internal/warning_push.h
-data.o: $(hdrdir)/ruby/internal/xmalloc.h
-data.o: $(hdrdir)/ruby/missing.h
-data.o: $(hdrdir)/ruby/ruby.h
-data.o: $(hdrdir)/ruby/st.h
-data.o: $(hdrdir)/ruby/subst.h
-data.o: data.c
duplicate.o: $(RUBY_EXTCONF_H)
duplicate.o: $(arch_hdrdir)/ruby/config.h
duplicate.o: $(hdrdir)/ruby.h
@@ -211,7 +52,6 @@ duplicate.o: $(hdrdir)/ruby/internal/attr/noexcept.h
duplicate.o: $(hdrdir)/ruby/internal/attr/noinline.h
duplicate.o: $(hdrdir)/ruby/internal/attr/nonnull.h
duplicate.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-duplicate.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
duplicate.o: $(hdrdir)/ruby/internal/attr/pure.h
duplicate.o: $(hdrdir)/ruby/internal/attr/restrict.h
duplicate.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +111,7 @@ duplicate.o: $(hdrdir)/ruby/internal/intern/enumerator.h
duplicate.o: $(hdrdir)/ruby/internal/intern/error.h
duplicate.o: $(hdrdir)/ruby/internal/intern/eval.h
duplicate.o: $(hdrdir)/ruby/internal/intern/file.h
+duplicate.o: $(hdrdir)/ruby/internal/intern/gc.h
duplicate.o: $(hdrdir)/ruby/internal/intern/hash.h
duplicate.o: $(hdrdir)/ruby/internal/intern/io.h
duplicate.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +142,7 @@ duplicate.o: $(hdrdir)/ruby/internal/memory.h
duplicate.o: $(hdrdir)/ruby/internal/method.h
duplicate.o: $(hdrdir)/ruby/internal/module.h
duplicate.o: $(hdrdir)/ruby/internal/newobj.h
+duplicate.o: $(hdrdir)/ruby/internal/rgengc.h
duplicate.o: $(hdrdir)/ruby/internal/scan_args.h
duplicate.o: $(hdrdir)/ruby/internal/special_consts.h
duplicate.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -370,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -430,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -460,6 +302,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -529,7 +372,6 @@ len.o: $(hdrdir)/ruby/internal/attr/noexcept.h
len.o: $(hdrdir)/ruby/internal/attr/noinline.h
len.o: $(hdrdir)/ruby/internal/attr/nonnull.h
len.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-len.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
len.o: $(hdrdir)/ruby/internal/attr/pure.h
len.o: $(hdrdir)/ruby/internal/attr/restrict.h
len.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -589,6 +431,7 @@ len.o: $(hdrdir)/ruby/internal/intern/enumerator.h
len.o: $(hdrdir)/ruby/internal/intern/error.h
len.o: $(hdrdir)/ruby/internal/intern/eval.h
len.o: $(hdrdir)/ruby/internal/intern/file.h
+len.o: $(hdrdir)/ruby/internal/intern/gc.h
len.o: $(hdrdir)/ruby/internal/intern/hash.h
len.o: $(hdrdir)/ruby/internal/intern/io.h
len.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -619,6 +462,7 @@ len.o: $(hdrdir)/ruby/internal/memory.h
len.o: $(hdrdir)/ruby/internal/method.h
len.o: $(hdrdir)/ruby/internal/module.h
len.o: $(hdrdir)/ruby/internal/newobj.h
+len.o: $(hdrdir)/ruby/internal/rgengc.h
len.o: $(hdrdir)/ruby/internal/scan_args.h
len.o: $(hdrdir)/ruby/internal/special_consts.h
len.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -688,7 +532,6 @@ member.o: $(hdrdir)/ruby/internal/attr/noexcept.h
member.o: $(hdrdir)/ruby/internal/attr/noinline.h
member.o: $(hdrdir)/ruby/internal/attr/nonnull.h
member.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-member.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
member.o: $(hdrdir)/ruby/internal/attr/pure.h
member.o: $(hdrdir)/ruby/internal/attr/restrict.h
member.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -748,6 +591,7 @@ member.o: $(hdrdir)/ruby/internal/intern/enumerator.h
member.o: $(hdrdir)/ruby/internal/intern/error.h
member.o: $(hdrdir)/ruby/internal/intern/eval.h
member.o: $(hdrdir)/ruby/internal/intern/file.h
+member.o: $(hdrdir)/ruby/internal/intern/gc.h
member.o: $(hdrdir)/ruby/internal/intern/hash.h
member.o: $(hdrdir)/ruby/internal/intern/io.h
member.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -778,6 +622,7 @@ member.o: $(hdrdir)/ruby/internal/memory.h
member.o: $(hdrdir)/ruby/internal/method.h
member.o: $(hdrdir)/ruby/internal/module.h
member.o: $(hdrdir)/ruby/internal/newobj.h
+member.o: $(hdrdir)/ruby/internal/rgengc.h
member.o: $(hdrdir)/ruby/internal/scan_args.h
member.o: $(hdrdir)/ruby/internal/special_consts.h
member.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/symbol/depend b/ext/-test-/symbol/depend
index dd1b5c305f..b94e4ce821 100644
--- a/ext/-test-/symbol/depend
+++ b/ext/-test-/symbol/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ type.o: $(hdrdir)/ruby/internal/attr/noexcept.h
type.o: $(hdrdir)/ruby/internal/attr/noinline.h
type.o: $(hdrdir)/ruby/internal/attr/nonnull.h
type.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-type.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
type.o: $(hdrdir)/ruby/internal/attr/pure.h
type.o: $(hdrdir)/ruby/internal/attr/restrict.h
type.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ type.o: $(hdrdir)/ruby/internal/intern/enumerator.h
type.o: $(hdrdir)/ruby/internal/intern/error.h
type.o: $(hdrdir)/ruby/internal/intern/eval.h
type.o: $(hdrdir)/ruby/internal/intern/file.h
+type.o: $(hdrdir)/ruby/internal/intern/gc.h
type.o: $(hdrdir)/ruby/internal/intern/hash.h
type.o: $(hdrdir)/ruby/internal/intern/io.h
type.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ type.o: $(hdrdir)/ruby/internal/memory.h
type.o: $(hdrdir)/ruby/internal/method.h
type.o: $(hdrdir)/ruby/internal/module.h
type.o: $(hdrdir)/ruby/internal/newobj.h
+type.o: $(hdrdir)/ruby/internal/rgengc.h
type.o: $(hdrdir)/ruby/internal/scan_args.h
type.o: $(hdrdir)/ruby/internal/special_consts.h
type.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/thread/instrumentation/depend b/ext/-test-/thread/instrumentation/depend
index b03f51870f..e2fcd060d8 100644
--- a/ext/-test-/thread/instrumentation/depend
+++ b/ext/-test-/thread/instrumentation/depend
@@ -52,7 +52,6 @@ instrumentation.o: $(hdrdir)/ruby/internal/attr/noexcept.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/noinline.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/nonnull.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-instrumentation.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/pure.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/restrict.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ instrumentation.o: $(hdrdir)/ruby/internal/intern/enumerator.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/error.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/eval.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/file.h
+instrumentation.o: $(hdrdir)/ruby/internal/intern/gc.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/hash.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/io.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ instrumentation.o: $(hdrdir)/ruby/internal/memory.h
instrumentation.o: $(hdrdir)/ruby/internal/method.h
instrumentation.o: $(hdrdir)/ruby/internal/module.h
instrumentation.o: $(hdrdir)/ruby/internal/newobj.h
+instrumentation.o: $(hdrdir)/ruby/internal/rgengc.h
instrumentation.o: $(hdrdir)/ruby/internal/scan_args.h
instrumentation.o: $(hdrdir)/ruby/internal/special_consts.h
instrumentation.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/thread/instrumentation/instrumentation.c b/ext/-test-/thread/instrumentation/instrumentation.c
index edb8738a29..d2a2c2740b 100644
--- a/ext/-test-/thread/instrumentation/instrumentation.c
+++ b/ext/-test-/thread/instrumentation/instrumentation.c
@@ -8,8 +8,13 @@ static rb_atomic_t resumed_count = 0;
static rb_atomic_t suspended_count = 0;
static rb_atomic_t exited_count = 0;
-#ifndef RB_THREAD_LOCAL_SPECIFIER
-# define RB_THREAD_LOCAL_SPECIFIER
+#if __STDC_VERSION__ >= 201112
+ #define RB_THREAD_LOCAL_SPECIFIER _Thread_local
+#elif defined(__GNUC__) && !defined(RB_THREAD_LOCAL_SPECIFIER_IS_UNSUPPORTED)
+ /* note that ICC (linux) and Clang are covered by __GNUC__ */
+ #define RB_THREAD_LOCAL_SPECIFIER __thread
+#else
+ #define RB_THREAD_LOCAL_SPECIFIER
#endif
static RB_THREAD_LOCAL_SPECIFIER unsigned int local_ready_count = 0;
diff --git a/ext/-test-/thread_fd/depend b/ext/-test-/thread_fd/depend
index d4cc772526..ecf738108a 100644
--- a/ext/-test-/thread_fd/depend
+++ b/ext/-test-/thread_fd/depend
@@ -51,7 +51,6 @@ thread_fd.o: $(hdrdir)/ruby/internal/attr/noexcept.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/noinline.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/nonnull.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/pure.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/restrict.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ thread_fd.o: $(hdrdir)/ruby/internal/intern/enumerator.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/error.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/eval.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/file.h
+thread_fd.o: $(hdrdir)/ruby/internal/intern/gc.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/hash.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/io.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ thread_fd.o: $(hdrdir)/ruby/internal/memory.h
thread_fd.o: $(hdrdir)/ruby/internal/method.h
thread_fd.o: $(hdrdir)/ruby/internal/module.h
thread_fd.o: $(hdrdir)/ruby/internal/newobj.h
+thread_fd.o: $(hdrdir)/ruby/internal/rgengc.h
thread_fd.o: $(hdrdir)/ruby/internal/scan_args.h
thread_fd.o: $(hdrdir)/ruby/internal/special_consts.h
thread_fd.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/time/depend b/ext/-test-/time/depend
index c015588b09..b7d1a2b114 100644
--- a/ext/-test-/time/depend
+++ b/ext/-test-/time/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -212,7 +213,6 @@ leap_second.o: $(hdrdir)/ruby/internal/attr/noexcept.h
leap_second.o: $(hdrdir)/ruby/internal/attr/noinline.h
leap_second.o: $(hdrdir)/ruby/internal/attr/nonnull.h
leap_second.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-leap_second.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
leap_second.o: $(hdrdir)/ruby/internal/attr/pure.h
leap_second.o: $(hdrdir)/ruby/internal/attr/restrict.h
leap_second.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +272,7 @@ leap_second.o: $(hdrdir)/ruby/internal/intern/enumerator.h
leap_second.o: $(hdrdir)/ruby/internal/intern/error.h
leap_second.o: $(hdrdir)/ruby/internal/intern/eval.h
leap_second.o: $(hdrdir)/ruby/internal/intern/file.h
+leap_second.o: $(hdrdir)/ruby/internal/intern/gc.h
leap_second.o: $(hdrdir)/ruby/internal/intern/hash.h
leap_second.o: $(hdrdir)/ruby/internal/intern/io.h
leap_second.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,6 +303,7 @@ leap_second.o: $(hdrdir)/ruby/internal/memory.h
leap_second.o: $(hdrdir)/ruby/internal/method.h
leap_second.o: $(hdrdir)/ruby/internal/module.h
leap_second.o: $(hdrdir)/ruby/internal/newobj.h
+leap_second.o: $(hdrdir)/ruby/internal/rgengc.h
leap_second.o: $(hdrdir)/ruby/internal/scan_args.h
leap_second.o: $(hdrdir)/ruby/internal/special_consts.h
leap_second.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -375,7 +377,6 @@ new.o: $(hdrdir)/ruby/internal/attr/noexcept.h
new.o: $(hdrdir)/ruby/internal/attr/noinline.h
new.o: $(hdrdir)/ruby/internal/attr/nonnull.h
new.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-new.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
new.o: $(hdrdir)/ruby/internal/attr/pure.h
new.o: $(hdrdir)/ruby/internal/attr/restrict.h
new.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -435,6 +436,7 @@ new.o: $(hdrdir)/ruby/internal/intern/enumerator.h
new.o: $(hdrdir)/ruby/internal/intern/error.h
new.o: $(hdrdir)/ruby/internal/intern/eval.h
new.o: $(hdrdir)/ruby/internal/intern/file.h
+new.o: $(hdrdir)/ruby/internal/intern/gc.h
new.o: $(hdrdir)/ruby/internal/intern/hash.h
new.o: $(hdrdir)/ruby/internal/intern/io.h
new.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -465,6 +467,7 @@ new.o: $(hdrdir)/ruby/internal/memory.h
new.o: $(hdrdir)/ruby/internal/method.h
new.o: $(hdrdir)/ruby/internal/module.h
new.o: $(hdrdir)/ruby/internal/newobj.h
+new.o: $(hdrdir)/ruby/internal/rgengc.h
new.o: $(hdrdir)/ruby/internal/scan_args.h
new.o: $(hdrdir)/ruby/internal/special_consts.h
new.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/tracepoint/depend b/ext/-test-/tracepoint/depend
index 396004926e..8e2aa7eab6 100644
--- a/ext/-test-/tracepoint/depend
+++ b/ext/-test-/tracepoint/depend
@@ -52,7 +52,6 @@ gc_hook.o: $(hdrdir)/ruby/internal/attr/noexcept.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/noinline.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/nonnull.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-gc_hook.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/pure.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/restrict.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ gc_hook.o: $(hdrdir)/ruby/internal/intern/enumerator.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/error.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/eval.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/file.h
+gc_hook.o: $(hdrdir)/ruby/internal/intern/gc.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/hash.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/io.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ gc_hook.o: $(hdrdir)/ruby/internal/memory.h
gc_hook.o: $(hdrdir)/ruby/internal/method.h
gc_hook.o: $(hdrdir)/ruby/internal/module.h
gc_hook.o: $(hdrdir)/ruby/internal/newobj.h
+gc_hook.o: $(hdrdir)/ruby/internal/rgengc.h
gc_hook.o: $(hdrdir)/ruby/internal/scan_args.h
gc_hook.o: $(hdrdir)/ruby/internal/special_consts.h
gc_hook.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -211,7 +212,6 @@ tracepoint.o: $(hdrdir)/ruby/internal/attr/noexcept.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/noinline.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/nonnull.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-tracepoint.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/pure.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/restrict.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +271,7 @@ tracepoint.o: $(hdrdir)/ruby/internal/intern/enumerator.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/error.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/eval.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/file.h
+tracepoint.o: $(hdrdir)/ruby/internal/intern/gc.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/hash.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/io.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,6 +302,7 @@ tracepoint.o: $(hdrdir)/ruby/internal/memory.h
tracepoint.o: $(hdrdir)/ruby/internal/method.h
tracepoint.o: $(hdrdir)/ruby/internal/module.h
tracepoint.o: $(hdrdir)/ruby/internal/newobj.h
+tracepoint.o: $(hdrdir)/ruby/internal/rgengc.h
tracepoint.o: $(hdrdir)/ruby/internal/scan_args.h
tracepoint.o: $(hdrdir)/ruby/internal/special_consts.h
tracepoint.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/typeddata/depend b/ext/-test-/typeddata/depend
index cbeafa8000..02f6de6e20 100644
--- a/ext/-test-/typeddata/depend
+++ b/ext/-test-/typeddata/depend
@@ -52,7 +52,6 @@ typeddata.o: $(hdrdir)/ruby/internal/attr/noexcept.h
typeddata.o: $(hdrdir)/ruby/internal/attr/noinline.h
typeddata.o: $(hdrdir)/ruby/internal/attr/nonnull.h
typeddata.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-typeddata.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
typeddata.o: $(hdrdir)/ruby/internal/attr/pure.h
typeddata.o: $(hdrdir)/ruby/internal/attr/restrict.h
typeddata.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ typeddata.o: $(hdrdir)/ruby/internal/intern/enumerator.h
typeddata.o: $(hdrdir)/ruby/internal/intern/error.h
typeddata.o: $(hdrdir)/ruby/internal/intern/eval.h
typeddata.o: $(hdrdir)/ruby/internal/intern/file.h
+typeddata.o: $(hdrdir)/ruby/internal/intern/gc.h
typeddata.o: $(hdrdir)/ruby/internal/intern/hash.h
typeddata.o: $(hdrdir)/ruby/internal/intern/io.h
typeddata.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ typeddata.o: $(hdrdir)/ruby/internal/memory.h
typeddata.o: $(hdrdir)/ruby/internal/method.h
typeddata.o: $(hdrdir)/ruby/internal/module.h
typeddata.o: $(hdrdir)/ruby/internal/newobj.h
+typeddata.o: $(hdrdir)/ruby/internal/rgengc.h
typeddata.o: $(hdrdir)/ruby/internal/scan_args.h
typeddata.o: $(hdrdir)/ruby/internal/special_consts.h
typeddata.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/vm/depend b/ext/-test-/vm/depend
index f0b3f3b1f4..7f110d48eb 100644
--- a/ext/-test-/vm/depend
+++ b/ext/-test-/vm/depend
@@ -51,7 +51,6 @@ at_exit.o: $(hdrdir)/ruby/internal/attr/noexcept.h
at_exit.o: $(hdrdir)/ruby/internal/attr/noinline.h
at_exit.o: $(hdrdir)/ruby/internal/attr/nonnull.h
at_exit.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-at_exit.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
at_exit.o: $(hdrdir)/ruby/internal/attr/pure.h
at_exit.o: $(hdrdir)/ruby/internal/attr/restrict.h
at_exit.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ at_exit.o: $(hdrdir)/ruby/internal/intern/enumerator.h
at_exit.o: $(hdrdir)/ruby/internal/intern/error.h
at_exit.o: $(hdrdir)/ruby/internal/intern/eval.h
at_exit.o: $(hdrdir)/ruby/internal/intern/file.h
+at_exit.o: $(hdrdir)/ruby/internal/intern/gc.h
at_exit.o: $(hdrdir)/ruby/internal/intern/hash.h
at_exit.o: $(hdrdir)/ruby/internal/intern/io.h
at_exit.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ at_exit.o: $(hdrdir)/ruby/internal/memory.h
at_exit.o: $(hdrdir)/ruby/internal/method.h
at_exit.o: $(hdrdir)/ruby/internal/module.h
at_exit.o: $(hdrdir)/ruby/internal/newobj.h
+at_exit.o: $(hdrdir)/ruby/internal/rgengc.h
at_exit.o: $(hdrdir)/ruby/internal/scan_args.h
at_exit.o: $(hdrdir)/ruby/internal/special_consts.h
at_exit.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/wait/depend b/ext/-test-/wait/depend
index 2e4887559c..e71bda9968 100644
--- a/ext/-test-/wait/depend
+++ b/ext/-test-/wait/depend
@@ -52,7 +52,6 @@ wait.o: $(hdrdir)/ruby/internal/attr/noexcept.h
wait.o: $(hdrdir)/ruby/internal/attr/noinline.h
wait.o: $(hdrdir)/ruby/internal/attr/nonnull.h
wait.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-wait.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
wait.o: $(hdrdir)/ruby/internal/attr/pure.h
wait.o: $(hdrdir)/ruby/internal/attr/restrict.h
wait.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -121,6 +120,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/enumerator.h
wait.o: $(hdrdir)/ruby/internal/intern/error.h
wait.o: $(hdrdir)/ruby/internal/intern/eval.h
wait.o: $(hdrdir)/ruby/internal/intern/file.h
+wait.o: $(hdrdir)/ruby/internal/intern/gc.h
wait.o: $(hdrdir)/ruby/internal/intern/hash.h
wait.o: $(hdrdir)/ruby/internal/intern/io.h
wait.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -151,6 +151,7 @@ wait.o: $(hdrdir)/ruby/internal/memory.h
wait.o: $(hdrdir)/ruby/internal/method.h
wait.o: $(hdrdir)/ruby/internal/module.h
wait.o: $(hdrdir)/ruby/internal/newobj.h
+wait.o: $(hdrdir)/ruby/internal/rgengc.h
wait.o: $(hdrdir)/ruby/internal/scan_args.h
wait.o: $(hdrdir)/ruby/internal/special_consts.h
wait.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/.document b/ext/.document
index 0efd511a61..aeb40c60fb 100644
--- a/ext/.document
+++ b/ext/.document
@@ -11,6 +11,7 @@ date/date_parse.c
date/date_strftime.c
date/date_strptime.c
date/lib
+dbm/dbm.c
digest/bubblebabble/bubblebabble.c
digest/digest.c
digest/lib
@@ -21,6 +22,7 @@ digest/sha2/sha2init.c
digest/sha2/lib
etc/etc.c
fcntl/fcntl.c
+fiber/fiber.c
fiddle/closure.c
fiddle/conversions.c
fiddle/fiddle.c
@@ -29,7 +31,9 @@ fiddle/pinned.c
fiddle/pointer.c
fiddle/handle.c
fiddle/lib
-io/console/
+gdbm/gdbm.c
+io/console/console.c
+io/console/lib
io/nonblock/nonblock.c
io/wait/wait.c
json/generator/generator.c
diff --git a/ext/Setup b/ext/Setup
index 9c3e2f48fe..0376e2fc6c 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -5,6 +5,7 @@
#continuation
#coverage
#date
+#dbm
#digest/bubblebabble
#digest
#digest/md5
@@ -13,7 +14,9 @@
#digest/sha2
#etc
#fcntl
+#fiber
#fiddle
+#gdbm
#io/console
#io/nonblock
#io/wait
diff --git a/ext/Setup.atheos b/ext/Setup.atheos
index 91f73f32f9..3f6263b1e2 100644
--- a/ext/Setup.atheos
+++ b/ext/Setup.atheos
@@ -1,19 +1,23 @@
option nodynamic
+#Win32API
bigdecimal
cgi/escape
+dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
+enumerator
etc
fcntl
+gdbm
io/wait
nkf
#openssl
pty
-#racc/cparse
+racc/parse
readline
ripper
socket
diff --git a/ext/Setup.nt b/ext/Setup.nt
index 1278f183e4..dc36aa8688 100644
--- a/ext/Setup.nt
+++ b/ext/Setup.nt
@@ -1,20 +1,24 @@
#option platform cygwin|mingw|mswin
#option nodynamic
+Win32API
bigdecimal
cgi/escape
+#dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
+enumerator
etc
fcntl
+#gdbm
#io/wait
nkf
#openssl
#pty
-#racc/cparse
+racc/cparse
#readline
#ripper
socket
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index 07c2bcf0b5..d6ea35c615 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -31,8 +31,6 @@
#include "bits.h"
#include "static_assert.h"
-#define BIGDECIMAL_VERSION "3.1.5"
-
/* #define ENABLE_NUMERIC_STRING */
#define SIGNED_VALUE_MAX INTPTR_MAX
@@ -315,7 +313,7 @@ static const rb_data_type_t BigDecimal_data_type = {
"BigDecimal",
{ 0, BigDecimal_delete, BigDecimal_memsize, },
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE
#endif
};
@@ -657,7 +655,7 @@ BigDecimal_precision(VALUE self)
* Returns the number of decimal digits following the decimal digits in +self+.
*
* BigDecimal("0").scale # => 0
- * BigDecimal("1").scale # => 0
+ * BigDecimal("1").scale # => 1
* BigDecimal("1.1").scale # => 1
* BigDecimal("3.1415").scale # => 4
* BigDecimal("-1e20").precision # => 0
@@ -2084,13 +2082,6 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
SAVE(b);
- if (VpIsPosInf(b) || VpIsNegInf(b)) {
- GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
- VpSetZero(*dv, 1);
- *rv = a;
- return Qnil;
- }
-
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
@@ -2689,7 +2680,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
* A space at the start of s returns positive values with a leading space.
*
* If s contains a number, a space is inserted after each group of that many
- * digits, starting from '.' and counting outwards.
+ * fractional digits.
*
* If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
*
@@ -2697,14 +2688,14 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
*
* Examples:
*
- * BigDecimal('-1234567890123.45678901234567890').to_s('5F')
- * #=> '-123 45678 90123.45678 90123 45678 9'
+ * BigDecimal('-123.45678901234567890').to_s('5F')
+ * #=> '-123.45678 90123 45678 9'
*
- * BigDecimal('1234567890123.45678901234567890').to_s('+8F')
- * #=> '+12345 67890123.45678901 23456789'
+ * BigDecimal('123.45678901234567890').to_s('+8F')
+ * #=> '+123.45678901 23456789'
*
- * BigDecimal('1234567890123.45678901234567890').to_s(' F')
- * #=> ' 1234567890123.4567890123456789'
+ * BigDecimal('123.45678901234567890').to_s(' F')
+ * #=> ' 123.4567890123456789'
*/
static VALUE
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
@@ -3722,7 +3713,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
* - Other type:
*
* - Raises an exception if keyword argument +exception+ is +true+.
- * - Returns +nil+ if keyword argument +exception+ is +false+.
+ * - Returns +nil+ if keyword argument +exception+ is +true+.
*
* Raises an exception if +value+ evaluates to a Float
* and +digits+ is larger than Float::DIG + 1.
@@ -4142,11 +4133,11 @@ get_vp_value:
}
x = VpCheckGetValue(vx);
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
- two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
+ RB_GC_GUARD(one) = VpCheckGetValue(NewOneWrapLimited(1, 1));
+ RB_GC_GUARD(two) = VpCheckGetValue(VpCreateRbObject(1, "2", true));
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
- vn = SSIZET2NUM(n);
+ RB_GC_GUARD(vn) = SSIZET2NUM(n);
expo = VpExponent10(vx);
if (expo < 0 || expo >= 3) {
char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
@@ -4158,9 +4149,9 @@ get_vp_value:
}
w = BigDecimal_sub(x, one);
x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
- x2 = BigDecimal_mult2(x, x, vn);
- y = x;
- d = y;
+ RB_GC_GUARD(x2) = BigDecimal_mult2(x, x, vn);
+ RB_GC_GUARD(y) = x;
+ RB_GC_GUARD(d) = y;
i = 1;
while (!VpIsZero((Real*)DATA_PTR(d))) {
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
@@ -4188,13 +4179,6 @@ get_vp_value:
y = BigDecimal_add(y, dy);
}
- RB_GC_GUARD(one);
- RB_GC_GUARD(two);
- RB_GC_GUARD(vn);
- RB_GC_GUARD(x2);
- RB_GC_GUARD(y);
- RB_GC_GUARD(d);
-
return y;
}
@@ -4411,10 +4395,13 @@ Init_bigdecimal(void)
/* Constants definition */
+#ifndef RUBY_BIGDECIMAL_VERSION
+# error RUBY_BIGDECIMAL_VERSION is not defined
+#endif
/*
* The version of bigdecimal library
*/
- rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(BIGDECIMAL_VERSION));
+ rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(RUBY_BIGDECIMAL_VERSION));
/*
* Base value used in internal calculations. On a 32 bit system, BASE
@@ -6466,7 +6453,7 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
}
}
nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
- nc += fprintf(fp, " (%"PRIdVALUE", %"PRIuSIZE", %"PRIuSIZE")", a->exponent, a->Prec, a->MaxPrec);
+ nc += fprintf(fp, " (%"PRIdVALUE", %lu, %lu)", a->exponent, a->Prec, a->MaxPrec);
}
else {
nc += fprintf(fp, "0.0");
@@ -6706,90 +6693,95 @@ VpToFString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
{
size_t i, n;
- DECDIG m, e;
+ DECDIG m, e, nn;
char *p = buf;
- size_t plen = buflen, delim = fFmt;
+ size_t plen = buflen;
ssize_t ex;
if (VpToSpecialString(a, buf, buflen, fPlus)) return;
-#define APPEND(c, group) do { \
- if (plen < 1) goto overflow; \
- if (group && delim == 0) { \
- *p = ' '; \
- p += 1; \
- plen -= 1; \
- } \
- if (plen < 1) goto overflow; \
- *p = c; \
- p += 1; \
- plen -= 1; \
- if (group) delim = (delim + 1) % fFmt; \
+#define ADVANCE(n) do { \
+ if (plen < n) goto overflow; \
+ p += n; \
+ plen -= n; \
} while (0)
if (BIGDECIMAL_NEGATIVE_P(a)) {
- APPEND('-', false);
+ *p = '-';
+ ADVANCE(1);
}
else if (fPlus == 1) {
- APPEND(' ', false);
+ *p = ' ';
+ ADVANCE(1);
}
else if (fPlus == 2) {
- APPEND('+', false);
+ *p = '+';
+ ADVANCE(1);
}
n = a->Prec;
ex = a->exponent;
if (ex <= 0) {
- APPEND('0', false);
- APPEND('.', false);
- }
- while (ex < 0) {
- for (i=0; i < BASE_FIG; ++i) {
- APPEND('0', fFmt > 0);
+ *p = '0'; ADVANCE(1);
+ *p = '.'; ADVANCE(1);
+ while (ex < 0) {
+ for (i=0; i < BASE_FIG; ++i) {
+ *p = '0'; ADVANCE(1);
+ }
+ ++ex;
}
- ++ex;
+ ex = -1;
}
for (i = 0; i < n; ++i) {
- m = BASE1;
- e = a->frac[i];
- if (i == 0 && ex > 0) {
- for (delim = 0; e / m == 0; delim++) {
+ --ex;
+ if (i == 0 && ex >= 0) {
+ size_t n = snprintf(p, plen, "%lu", (unsigned long)a->frac[i]);
+ if (n > plen) goto overflow;
+ ADVANCE(n);
+ }
+ else {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ *p = (char)(nn + '0');
+ ADVANCE(1);
+ e = e - nn * m;
m /= 10;
}
- if (fFmt > 0) {
- delim = 2*fFmt - (ex * BASE_FIG - delim) % fFmt;
- }
}
- while (m && (e || (i < n - 1) || ex > 0)) {
- APPEND((char)(e / m + '0'), fFmt > 0);
- e %= m;
- m /= 10;
- }
- if (--ex == 0) {
- APPEND('.', false);
- delim = fFmt;
+ if (ex == 0) {
+ *p = '.';
+ ADVANCE(1);
}
}
-
- while (ex > 0) {
- for (i=0; i < BASE_FIG; ++i) {
- APPEND('0', fFmt > 0);
+ while (--ex>=0) {
+ m = BASE;
+ while (m /= 10) {
+ *p = '0';
+ ADVANCE(1);
}
- if (--ex == 0) {
- APPEND('.', false);
+ if (ex == 0) {
+ *p = '.';
+ ADVANCE(1);
}
}
*p = '\0';
+ while (p - 1 > buf && p[-1] == '0') {
+ *(--p) = '\0';
+ ++plen;
+ }
if (p - 1 > buf && p[-1] == '.') {
snprintf(p, plen, "0");
}
+ if (fFmt) VpFormatSt(buf, fFmt);
overflow:
return;
-#undef APPEND
+#undef ADVANCE
}
/*
@@ -7166,6 +7158,7 @@ VpSqrt(Real *y, Real *x)
Real *r = NULL;
size_t y_prec;
SIGNED_VALUE n, e;
+ SIGNED_VALUE prec;
ssize_t nr;
double val;
@@ -7204,6 +7197,12 @@ VpSqrt(Real *y, Real *x)
nr = 0;
y_prec = y->MaxPrec;
+ prec = x->exponent - (ssize_t)y_prec;
+ if (x->exponent > 0)
+ ++prec;
+ else
+ --prec;
+
VpVtoD(&val, &e, x); /* val <- x */
e /= (SIGNED_VALUE)BASE_FIG;
n = e / 2;
diff --git a/ext/bigdecimal/bigdecimal.gemspec b/ext/bigdecimal/bigdecimal.gemspec
index f9f3b45616..d215757188 100644
--- a/ext/bigdecimal/bigdecimal.gemspec
+++ b/ext/bigdecimal/bigdecimal.gemspec
@@ -1,29 +1,28 @@
# coding: utf-8
-name = File.basename(__FILE__, '.*')
-source_version = ["", "ext/#{name}/"].find do |dir|
- begin
- break File.foreach(File.join(__dir__, "#{dir}#{name}.c")) {|line|
- break $1.sub("-", ".") if /^#define\s+#{name.upcase}_VERSION\s+"(.+)"/o =~ line
- }
- rescue Errno::ENOENT
- end
-end or raise "can't find #{name.upcase}_VERSION"
-
Gem::Specification.new do |s|
- s.name = name
- s.version = source_version
+ s.name = "bigdecimal"
+ s.version = "3.1.3"
s.authors = ["Kenta Murata", "Zachary Scott", "Shigeo Kobayashi"]
s.email = ["mrkn@mrkn.jp"]
s.summary = "Arbitrary-precision decimal floating-point number library."
s.description = "This library provides arbitrary-precision decimal floating-point number class."
s.homepage = "https://github.com/ruby/bigdecimal"
- s.licenses = ["Ruby", "BSD-2-Clause"]
+ s.licenses = ["Ruby", "bsd-2-clause"]
s.require_paths = %w[lib]
+ s.extensions = %w[ext/bigdecimal/extconf.rb]
s.files = %w[
bigdecimal.gemspec
+ ext/bigdecimal/bigdecimal.c
+ ext/bigdecimal/bigdecimal.h
+ ext/bigdecimal/bits.h
+ ext/bigdecimal/feature.h
+ ext/bigdecimal/missing.c
+ ext/bigdecimal/missing.h
+ ext/bigdecimal/missing/dtoa.c
+ ext/bigdecimal/static_assert.h
lib/bigdecimal.rb
lib/bigdecimal/jacobian.rb
lib/bigdecimal/ludcmp.rb
@@ -34,21 +33,6 @@ Gem::Specification.new do |s|
sample/nlsolve.rb
sample/pi.rb
]
- if Gem::Platform === s.platform and s.platform =~ 'java' or RUBY_ENGINE == 'jruby'
- s.platform = 'java'
- else
- s.extensions = %w[ext/bigdecimal/extconf.rb]
- s.files += %w[
- ext/bigdecimal/bigdecimal.c
- ext/bigdecimal/bigdecimal.h
- ext/bigdecimal/bits.h
- ext/bigdecimal/feature.h
- ext/bigdecimal/missing.c
- ext/bigdecimal/missing.h
- ext/bigdecimal/missing/dtoa.c
- ext/bigdecimal/static_assert.h
- ]
- end
s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
end
diff --git a/ext/bigdecimal/depend b/ext/bigdecimal/depend
index a2455ebbda..ee892162f2 100644
--- a/ext/bigdecimal/depend
+++ b/ext/bigdecimal/depend
@@ -1,3 +1,4 @@
+extconf.h: $(srcdir)/$(GEMSPEC)
Makefile: $(BIGDECIMAL_RB)
# AUTOGENERATED DEPENDENCIES START
@@ -52,7 +53,6 @@ bigdecimal.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bigdecimal.o: $(hdrdir)/ruby/internal/attr/noinline.h
bigdecimal.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bigdecimal.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bigdecimal.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bigdecimal.o: $(hdrdir)/ruby/internal/attr/pure.h
bigdecimal.o: $(hdrdir)/ruby/internal/attr/restrict.h
bigdecimal.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +112,7 @@ bigdecimal.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bigdecimal.o: $(hdrdir)/ruby/internal/intern/error.h
bigdecimal.o: $(hdrdir)/ruby/internal/intern/eval.h
bigdecimal.o: $(hdrdir)/ruby/internal/intern/file.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/gc.h
bigdecimal.o: $(hdrdir)/ruby/internal/intern/hash.h
bigdecimal.o: $(hdrdir)/ruby/internal/intern/io.h
bigdecimal.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +143,7 @@ bigdecimal.o: $(hdrdir)/ruby/internal/memory.h
bigdecimal.o: $(hdrdir)/ruby/internal/method.h
bigdecimal.o: $(hdrdir)/ruby/internal/module.h
bigdecimal.o: $(hdrdir)/ruby/internal/newobj.h
+bigdecimal.o: $(hdrdir)/ruby/internal/rgengc.h
bigdecimal.o: $(hdrdir)/ruby/internal/scan_args.h
bigdecimal.o: $(hdrdir)/ruby/internal/special_consts.h
bigdecimal.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -217,7 +219,6 @@ missing.o: $(hdrdir)/ruby/internal/attr/noexcept.h
missing.o: $(hdrdir)/ruby/internal/attr/noinline.h
missing.o: $(hdrdir)/ruby/internal/attr/nonnull.h
missing.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-missing.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
missing.o: $(hdrdir)/ruby/internal/attr/pure.h
missing.o: $(hdrdir)/ruby/internal/attr/restrict.h
missing.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -277,6 +278,7 @@ missing.o: $(hdrdir)/ruby/internal/intern/enumerator.h
missing.o: $(hdrdir)/ruby/internal/intern/error.h
missing.o: $(hdrdir)/ruby/internal/intern/eval.h
missing.o: $(hdrdir)/ruby/internal/intern/file.h
+missing.o: $(hdrdir)/ruby/internal/intern/gc.h
missing.o: $(hdrdir)/ruby/internal/intern/hash.h
missing.o: $(hdrdir)/ruby/internal/intern/io.h
missing.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -307,6 +309,7 @@ missing.o: $(hdrdir)/ruby/internal/memory.h
missing.o: $(hdrdir)/ruby/internal/method.h
missing.o: $(hdrdir)/ruby/internal/module.h
missing.o: $(hdrdir)/ruby/internal/newobj.h
+missing.o: $(hdrdir)/ruby/internal/rgengc.h
missing.o: $(hdrdir)/ruby/internal/scan_args.h
missing.o: $(hdrdir)/ruby/internal/special_consts.h
missing.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/bigdecimal/extconf.rb b/ext/bigdecimal/extconf.rb
index 23904ed60e..17e7905dd6 100644
--- a/ext/bigdecimal/extconf.rb
+++ b/ext/bigdecimal/extconf.rb
@@ -1,6 +1,18 @@
# frozen_string_literal: false
require 'mkmf'
+def check_bigdecimal_version(gemspec_path)
+ message "checking RUBY_BIGDECIMAL_VERSION... "
+ bigdecimal_version = File.read(gemspec_path).match(/^\s*s\.version\s+=\s+['"]([^'"]+)['"]\s*$/)[1]
+
+ version_components = bigdecimal_version.split('.')
+ bigdecimal_version = version_components[0, 3].join('.')
+ bigdecimal_version << "-#{version_components[3]}" if version_components[3]
+ $defs << %Q[-DRUBY_BIGDECIMAL_VERSION=\\"#{bigdecimal_version}\\"]
+
+ message "#{bigdecimal_version}\n"
+end
+
def have_builtin_func(name, check_expr, opt = "", &b)
checking_for checking_message(name.funcall_style, nil, opt) do
if try_compile(<<SRC, opt, &b)
@@ -15,6 +27,18 @@ SRC
end
end
+gemspec_name = gemspec_path = nil
+unless ['', '../../'].any? {|dir|
+ gemspec_name = "#{dir}bigdecimal.gemspec"
+ gemspec_path = File.expand_path("../#{gemspec_name}", __FILE__)
+ File.file?(gemspec_path)
+ }
+ $stderr.puts "Unable to find bigdecimal.gemspec"
+ abort
+end
+
+check_bigdecimal_version(gemspec_path)
+
have_builtin_func("__builtin_clz", "__builtin_clz(0)")
have_builtin_func("__builtin_clzl", "__builtin_clzl(0)")
have_builtin_func("__builtin_clzll", "__builtin_clzll(0)")
@@ -58,5 +82,6 @@ else
end
create_makefile('bigdecimal') {|mf|
+ mf << "GEMSPEC = #{gemspec_name}\n"
mf << "BIGDECIMAL_RB = #{bigdecimal_rb}\n"
}
diff --git a/ext/bigdecimal/lib/bigdecimal.rb b/ext/bigdecimal/lib/bigdecimal.rb
index 82b3e1b7b9..8fd2587c84 100644
--- a/ext/bigdecimal/lib/bigdecimal.rb
+++ b/ext/bigdecimal/lib/bigdecimal.rb
@@ -1,5 +1 @@
-if RUBY_ENGINE == 'jruby'
- JRuby::Util.load_ext("org.jruby.ext.bigdecimal.BigDecimalLibrary")
-else
- require 'bigdecimal.so'
-end
+require 'bigdecimal.so'
diff --git a/ext/bigdecimal/lib/bigdecimal/util.rb b/ext/bigdecimal/lib/bigdecimal/util.rb
index 8bfc0ed8ed..ad92f7cfe6 100644
--- a/ext/bigdecimal/lib/bigdecimal/util.rb
+++ b/ext/bigdecimal/lib/bigdecimal/util.rb
@@ -18,7 +18,7 @@ class Integer < Numeric
#
# 42.to_d # => 0.42e2
#
- # See also Kernel.BigDecimal.
+ # See also BigDecimal::new.
#
def to_d
BigDecimal(self)
@@ -45,7 +45,7 @@ class Float < Numeric
# 1.234.to_d # => 0.1234e1
# 1.234.to_d(2) # => 0.12e1
#
- # See also Kernel.BigDecimal.
+ # See also BigDecimal::new.
#
def to_d(precision=0)
BigDecimal(self, precision)
@@ -67,7 +67,7 @@ class String
# "123.45e1".to_d # => 0.12345e4
# "45.67 degrees".to_d # => 0.4567e2
#
- # See also Kernel.BigDecimal.
+ # See also BigDecimal::new.
#
def to_d
BigDecimal.interpret_loosely(self)
@@ -127,7 +127,7 @@ class Rational < Numeric
#
# Rational(22, 7).to_d(3) # => 0.314e1
#
- # See also Kernel.BigDecimal.
+ # See also BigDecimal::new.
#
def to_d(precision)
BigDecimal(self, precision)
@@ -152,7 +152,7 @@ class Complex < Numeric
# Complex(0.1234567, 0).to_d(4) # => 0.1235e0
# Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1
#
- # See also Kernel.BigDecimal.
+ # See also BigDecimal::new.
#
def to_d(*args)
BigDecimal(self) unless self.imag.zero? # to raise eerror
diff --git a/ext/cgi/escape/depend b/ext/cgi/escape/depend
index 37304a24f4..e3904d0695 100644
--- a/ext/cgi/escape/depend
+++ b/ext/cgi/escape/depend
@@ -53,7 +53,6 @@ escape.o: $(hdrdir)/ruby/internal/attr/noexcept.h
escape.o: $(hdrdir)/ruby/internal/attr/noinline.h
escape.o: $(hdrdir)/ruby/internal/attr/nonnull.h
escape.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-escape.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
escape.o: $(hdrdir)/ruby/internal/attr/pure.h
escape.o: $(hdrdir)/ruby/internal/attr/restrict.h
escape.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ escape.o: $(hdrdir)/ruby/internal/intern/enumerator.h
escape.o: $(hdrdir)/ruby/internal/intern/error.h
escape.o: $(hdrdir)/ruby/internal/intern/eval.h
escape.o: $(hdrdir)/ruby/internal/intern/file.h
+escape.o: $(hdrdir)/ruby/internal/intern/gc.h
escape.o: $(hdrdir)/ruby/internal/intern/hash.h
escape.o: $(hdrdir)/ruby/internal/intern/io.h
escape.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ escape.o: $(hdrdir)/ruby/internal/memory.h
escape.o: $(hdrdir)/ruby/internal/method.h
escape.o: $(hdrdir)/ruby/internal/module.h
escape.o: $(hdrdir)/ruby/internal/newobj.h
+escape.o: $(hdrdir)/ruby/internal/rgengc.h
escape.o: $(hdrdir)/ruby/internal/scan_args.h
escape.o: $(hdrdir)/ruby/internal/special_consts.h
escape.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c
index 17a134aa1a..c5b76de596 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -458,9 +458,7 @@ InitVM_escape(void)
rb_define_method(rb_mEscape, "escapeHTML", cgiesc_escape_html, 1);
rb_define_method(rb_mEscape, "unescapeHTML", cgiesc_unescape_html, 1);
rb_define_method(rb_mEscape, "escapeURIComponent", cgiesc_escape_uri_component, 1);
- rb_define_alias(rb_mEscape, "escape_uri_component", "escapeURIComponent");
rb_define_method(rb_mEscape, "unescapeURIComponent", cgiesc_unescape_uri_component, -1);
- rb_define_alias(rb_mEscape, "unescape_uri_component", "unescapeURIComponent");
rb_define_method(rb_mEscape, "escape", cgiesc_escape, 1);
rb_define_method(rb_mEscape, "unescape", cgiesc_unescape, -1);
rb_prepend_module(rb_mUtil, rb_mEscape);
diff --git a/ext/cgi/escape/extconf.rb b/ext/cgi/escape/extconf.rb
index 73acd89ca8..16e8ff224d 100644
--- a/ext/cgi/escape/extconf.rb
+++ b/ext/cgi/escape/extconf.rb
@@ -1,7 +1,3 @@
require 'mkmf'
-if RUBY_ENGINE == 'truffleruby'
- File.write("Makefile", dummy_makefile($srcdir).join(""))
-else
- create_makefile 'cgi/escape'
-end
+create_makefile 'cgi/escape'
diff --git a/ext/continuation/depend b/ext/continuation/depend
index f0333d7fe6..81218f9965 100644
--- a/ext/continuation/depend
+++ b/ext/continuation/depend
@@ -51,7 +51,6 @@ continuation.o: $(hdrdir)/ruby/internal/attr/noexcept.h
continuation.o: $(hdrdir)/ruby/internal/attr/noinline.h
continuation.o: $(hdrdir)/ruby/internal/attr/nonnull.h
continuation.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-continuation.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
continuation.o: $(hdrdir)/ruby/internal/attr/pure.h
continuation.o: $(hdrdir)/ruby/internal/attr/restrict.h
continuation.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ continuation.o: $(hdrdir)/ruby/internal/intern/enumerator.h
continuation.o: $(hdrdir)/ruby/internal/intern/error.h
continuation.o: $(hdrdir)/ruby/internal/intern/eval.h
continuation.o: $(hdrdir)/ruby/internal/intern/file.h
+continuation.o: $(hdrdir)/ruby/internal/intern/gc.h
continuation.o: $(hdrdir)/ruby/internal/intern/hash.h
continuation.o: $(hdrdir)/ruby/internal/intern/io.h
continuation.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ continuation.o: $(hdrdir)/ruby/internal/memory.h
continuation.o: $(hdrdir)/ruby/internal/method.h
continuation.o: $(hdrdir)/ruby/internal/module.h
continuation.o: $(hdrdir)/ruby/internal/newobj.h
+continuation.o: $(hdrdir)/ruby/internal/rgengc.h
continuation.o: $(hdrdir)/ruby/internal/scan_args.h
continuation.o: $(hdrdir)/ruby/internal/special_consts.h
continuation.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c
index a3381901ee..4578de54e4 100644
--- a/ext/coverage/coverage.c
+++ b/ext/coverage/coverage.c
@@ -8,7 +8,7 @@
************************************************/
-#include "internal/gc.h"
+#include "gc.h"
#include "internal/hash.h"
#include "internal/thread.h"
#include "internal/sanitizers.h"
@@ -29,7 +29,7 @@ static VALUE me2counter = Qnil;
* Returns true if coverage measurement is supported for the given mode.
*
* The mode should be one of the following symbols:
- * +:lines+, +:oneshot_lines+, +:branches+, +:methods+, +:eval+.
+ * +:lines+, +:branches+, +:methods+, +:eval+.
*
* Example:
*
@@ -43,7 +43,6 @@ rb_coverage_supported(VALUE self, VALUE _mode)
return RBOOL(
mode == rb_intern("lines") ||
- mode == rb_intern("oneshot_lines") ||
mode == rb_intern("branches") ||
mode == rb_intern("methods") ||
mode == rb_intern("eval")
diff --git a/ext/coverage/depend b/ext/coverage/depend
index 0a6c61d5c6..e7fab16484 100644
--- a/ext/coverage/depend
+++ b/ext/coverage/depend
@@ -15,7 +15,6 @@ coverage.o: $(hdrdir)/ruby/backward/2/long_long.h
coverage.o: $(hdrdir)/ruby/backward/2/stdalign.h
coverage.o: $(hdrdir)/ruby/backward/2/stdarg.h
coverage.o: $(hdrdir)/ruby/defines.h
-coverage.o: $(hdrdir)/ruby/encoding.h
coverage.o: $(hdrdir)/ruby/intern.h
coverage.o: $(hdrdir)/ruby/internal/abi.h
coverage.o: $(hdrdir)/ruby/internal/anyargs.h
@@ -55,7 +54,6 @@ coverage.o: $(hdrdir)/ruby/internal/attr/noexcept.h
coverage.o: $(hdrdir)/ruby/internal/attr/noinline.h
coverage.o: $(hdrdir)/ruby/internal/attr/nonnull.h
coverage.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-coverage.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
coverage.o: $(hdrdir)/ruby/internal/attr/pure.h
coverage.o: $(hdrdir)/ruby/internal/attr/restrict.h
coverage.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -88,15 +86,6 @@ coverage.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
coverage.o: $(hdrdir)/ruby/internal/ctype.h
coverage.o: $(hdrdir)/ruby/internal/dllexport.h
coverage.o: $(hdrdir)/ruby/internal/dosish.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/re.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/string.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/transcode.h
coverage.o: $(hdrdir)/ruby/internal/error.h
coverage.o: $(hdrdir)/ruby/internal/eval.h
coverage.o: $(hdrdir)/ruby/internal/event.h
@@ -124,6 +113,7 @@ coverage.o: $(hdrdir)/ruby/internal/intern/enumerator.h
coverage.o: $(hdrdir)/ruby/internal/intern/error.h
coverage.o: $(hdrdir)/ruby/internal/intern/eval.h
coverage.o: $(hdrdir)/ruby/internal/intern/file.h
+coverage.o: $(hdrdir)/ruby/internal/intern/gc.h
coverage.o: $(hdrdir)/ruby/internal/intern/hash.h
coverage.o: $(hdrdir)/ruby/internal/intern/io.h
coverage.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -154,6 +144,7 @@ coverage.o: $(hdrdir)/ruby/internal/memory.h
coverage.o: $(hdrdir)/ruby/internal/method.h
coverage.o: $(hdrdir)/ruby/internal/module.h
coverage.o: $(hdrdir)/ruby/internal/newobj.h
+coverage.o: $(hdrdir)/ruby/internal/rgengc.h
coverage.o: $(hdrdir)/ruby/internal/scan_args.h
coverage.o: $(hdrdir)/ruby/internal/special_consts.h
coverage.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -166,8 +157,6 @@ coverage.o: $(hdrdir)/ruby/internal/variable.h
coverage.o: $(hdrdir)/ruby/internal/warning_push.h
coverage.o: $(hdrdir)/ruby/internal/xmalloc.h
coverage.o: $(hdrdir)/ruby/missing.h
-coverage.o: $(hdrdir)/ruby/onigmo.h
-coverage.o: $(hdrdir)/ruby/oniguruma.h
coverage.o: $(hdrdir)/ruby/ruby.h
coverage.o: $(hdrdir)/ruby/st.h
coverage.o: $(hdrdir)/ruby/subst.h
@@ -177,6 +166,7 @@ coverage.o: $(top_srcdir)/ccan/container_of/container_of.h
coverage.o: $(top_srcdir)/ccan/list/list.h
coverage.o: $(top_srcdir)/ccan/str/str.h
coverage.o: $(top_srcdir)/constant.h
+coverage.o: $(top_srcdir)/gc.h
coverage.o: $(top_srcdir)/id_table.h
coverage.o: $(top_srcdir)/internal.h
coverage.o: $(top_srcdir)/internal/array.h
@@ -196,7 +186,6 @@ coverage.o: $(top_srcdir)/method.h
coverage.o: $(top_srcdir)/node.h
coverage.o: $(top_srcdir)/ruby_assert.h
coverage.o: $(top_srcdir)/ruby_atomic.h
-coverage.o: $(top_srcdir)/rubyparser.h
coverage.o: $(top_srcdir)/shape.h
coverage.o: $(top_srcdir)/thread_pthread.h
coverage.o: $(top_srcdir)/vm_core.h
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index f4b390584b..21367c0ddf 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -2589,6 +2589,8 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
*
* See argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
*
+ * Date.valid_date? is an alias for Date.valid_civil?.
+ *
* Related: Date.jd, Date.new.
*/
static VALUE
@@ -2984,6 +2986,8 @@ date_s_julian_leap_p(VALUE klass, VALUE y)
* Date.gregorian_leap?(2000) # => true
* Date.gregorian_leap?(2001) # => false
*
+ * Date.leap? is an alias for Date.gregorian_leap?.
+ *
* Related: Date.julian_leap?.
*/
static VALUE
@@ -3489,6 +3493,8 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
*
* See argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
*
+ * Date.civil is an alias for Date.new.
+ *
* Related: Date.jd.
*/
static VALUE
@@ -4826,6 +4832,8 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
*
* See argument {limit}[rdoc-ref:Date@Argument+limit].
*
+ * Date._rfc822 is an alias for Date._rfc2822.
+ *
* Related: Date.rfc2822 (returns a \Date object).
*/
static VALUE
@@ -4856,6 +4864,8 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
* - Argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
+ * Date.rfc822 is an alias for Date.rfc2822.
+ *
* Related: Date._rfc2822 (returns a hash).
*/
static VALUE
@@ -5336,6 +5346,7 @@ d_lite_yday(VALUE self)
*
* Date.new(2001, 2, 3).mon # => 2
*
+ * Date#month is an alias for Date#mon.
*/
static VALUE
d_lite_mon(VALUE self)
@@ -5352,6 +5363,7 @@ d_lite_mon(VALUE self)
*
* Date.new(2001, 2, 3).mday # => 3
*
+ * Date#day is an alias for Date#mday.
*/
static VALUE
d_lite_mday(VALUE self)
@@ -5601,6 +5613,7 @@ d_lite_hour(VALUE self)
*
* DateTime.new(2001, 2, 3, 4, 5, 6).min # => 5
*
+ * Date#minute is an alias for Date#min.
*/
static VALUE
d_lite_min(VALUE self)
@@ -5617,6 +5630,7 @@ d_lite_min(VALUE self)
*
* DateTime.new(2001, 2, 3, 4, 5, 6).sec # => 6
*
+ * Date#second is an alias for Date#sec.
*/
static VALUE
d_lite_sec(VALUE self)
@@ -5634,6 +5648,7 @@ d_lite_sec(VALUE self)
*
* DateTime.new(2001, 2, 3, 4, 5, 6.5).sec_fraction # => (1/2)
*
+ * Date#second_fraction is an alias for Date#sec_fraction.
*/
static VALUE
d_lite_sec_fraction(VALUE self)
@@ -6409,6 +6424,7 @@ d_lite_prev_day(int argc, VALUE *argv, VALUE self)
* d.to_s # => "2001-02-03"
* d.next.to_s # => "2001-02-04"
*
+ * Date#succ is an alias for Date#next.
*/
static VALUE
d_lite_next(VALUE self)
@@ -7282,6 +7298,7 @@ strftimev(const char *fmt, VALUE self,
*
* See {asctime}[https://linux.die.net/man/3/asctime].
*
+ * Date#ctime is an alias for Date#asctime.
*/
static VALUE
d_lite_asctime(VALUE self)
@@ -7299,6 +7316,7 @@ d_lite_asctime(VALUE self)
*
* Date.new(2001, 2, 3).iso8601 # => "2001-02-03"
*
+ * Date#xmlschema is an alias for Date#iso8601.
*/
static VALUE
d_lite_iso8601(VALUE self)
@@ -7331,6 +7349,7 @@ d_lite_rfc3339(VALUE self)
*
* Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
*
+ * Date#rfc822 is an alias for Date#rfc2822.
*/
static VALUE
d_lite_rfc2822(VALUE self)
@@ -8726,8 +8745,8 @@ dt_lite_to_s(VALUE self)
*
* DateTime.now.strftime # => "2022-07-01T11:03:19-05:00"
*
- * For other formats,
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * For other formats, see
+ * {Formats for Dates and Times}[doc/strftime_formatting.rdoc].
*
*/
static VALUE
diff --git a/ext/date/depend b/ext/date/depend
index 82f85f7bf3..3f550cd0a7 100644
--- a/ext/date/depend
+++ b/ext/date/depend
@@ -53,7 +53,6 @@ date_core.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_core.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_core.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_core.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_core.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_core.o: $(hdrdir)/ruby/internal/attr/pure.h
date_core.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_core.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ date_core.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_core.o: $(hdrdir)/ruby/internal/intern/error.h
date_core.o: $(hdrdir)/ruby/internal/intern/eval.h
date_core.o: $(hdrdir)/ruby/internal/intern/file.h
+date_core.o: $(hdrdir)/ruby/internal/intern/gc.h
date_core.o: $(hdrdir)/ruby/internal/intern/hash.h
date_core.o: $(hdrdir)/ruby/internal/intern/io.h
date_core.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ date_core.o: $(hdrdir)/ruby/internal/memory.h
date_core.o: $(hdrdir)/ruby/internal/method.h
date_core.o: $(hdrdir)/ruby/internal/module.h
date_core.o: $(hdrdir)/ruby/internal/newobj.h
+date_core.o: $(hdrdir)/ruby/internal/rgengc.h
date_core.o: $(hdrdir)/ruby/internal/scan_args.h
date_core.o: $(hdrdir)/ruby/internal/special_consts.h
date_core.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -226,7 +227,6 @@ date_parse.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_parse.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_parse.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_parse.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_parse.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_parse.o: $(hdrdir)/ruby/internal/attr/pure.h
date_parse.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_parse.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -296,6 +296,7 @@ date_parse.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_parse.o: $(hdrdir)/ruby/internal/intern/error.h
date_parse.o: $(hdrdir)/ruby/internal/intern/eval.h
date_parse.o: $(hdrdir)/ruby/internal/intern/file.h
+date_parse.o: $(hdrdir)/ruby/internal/intern/gc.h
date_parse.o: $(hdrdir)/ruby/internal/intern/hash.h
date_parse.o: $(hdrdir)/ruby/internal/intern/io.h
date_parse.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -326,6 +327,7 @@ date_parse.o: $(hdrdir)/ruby/internal/memory.h
date_parse.o: $(hdrdir)/ruby/internal/method.h
date_parse.o: $(hdrdir)/ruby/internal/module.h
date_parse.o: $(hdrdir)/ruby/internal/newobj.h
+date_parse.o: $(hdrdir)/ruby/internal/rgengc.h
date_parse.o: $(hdrdir)/ruby/internal/scan_args.h
date_parse.o: $(hdrdir)/ruby/internal/special_consts.h
date_parse.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -400,7 +402,6 @@ date_strftime.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_strftime.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/pure.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -460,6 +461,7 @@ date_strftime.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/error.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/eval.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/file.h
+date_strftime.o: $(hdrdir)/ruby/internal/intern/gc.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/hash.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/io.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -490,6 +492,7 @@ date_strftime.o: $(hdrdir)/ruby/internal/memory.h
date_strftime.o: $(hdrdir)/ruby/internal/method.h
date_strftime.o: $(hdrdir)/ruby/internal/module.h
date_strftime.o: $(hdrdir)/ruby/internal/newobj.h
+date_strftime.o: $(hdrdir)/ruby/internal/rgengc.h
date_strftime.o: $(hdrdir)/ruby/internal/scan_args.h
date_strftime.o: $(hdrdir)/ruby/internal/special_consts.h
date_strftime.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -561,7 +564,6 @@ date_strptime.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_strptime.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/pure.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -631,6 +633,7 @@ date_strptime.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/error.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/eval.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/file.h
+date_strptime.o: $(hdrdir)/ruby/internal/intern/gc.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/hash.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/io.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -661,6 +664,7 @@ date_strptime.o: $(hdrdir)/ruby/internal/memory.h
date_strptime.o: $(hdrdir)/ruby/internal/method.h
date_strptime.o: $(hdrdir)/ruby/internal/module.h
date_strptime.o: $(hdrdir)/ruby/internal/newobj.h
+date_strptime.o: $(hdrdir)/ruby/internal/rgengc.h
date_strptime.o: $(hdrdir)/ruby/internal/scan_args.h
date_strptime.o: $(hdrdir)/ruby/internal/special_consts.h
date_strptime.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb
index 6888bd2d4e..a9fe3ce4b0 100644
--- a/ext/date/lib/date.rb
+++ b/ext/date/lib/date.rb
@@ -4,7 +4,7 @@
require 'date_core'
class Date
- VERSION = "3.3.4" # :nodoc:
+ VERSION = "3.3.3" # :nodoc:
# call-seq:
# infinite? -> false
diff --git a/ext/digest/bubblebabble/depend b/ext/digest/bubblebabble/depend
index 6f0003a66d..38f5ddb1e2 100644
--- a/ext/digest/bubblebabble/depend
+++ b/ext/digest/bubblebabble/depend
@@ -52,7 +52,6 @@ bubblebabble.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/noinline.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bubblebabble.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/pure.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/restrict.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bubblebabble.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/error.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/eval.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/file.h
+bubblebabble.o: $(hdrdir)/ruby/internal/intern/gc.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/hash.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/io.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ bubblebabble.o: $(hdrdir)/ruby/internal/memory.h
bubblebabble.o: $(hdrdir)/ruby/internal/method.h
bubblebabble.o: $(hdrdir)/ruby/internal/module.h
bubblebabble.o: $(hdrdir)/ruby/internal/newobj.h
+bubblebabble.o: $(hdrdir)/ruby/internal/rgengc.h
bubblebabble.o: $(hdrdir)/ruby/internal/scan_args.h
bubblebabble.o: $(hdrdir)/ruby/internal/special_consts.h
bubblebabble.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/digest/depend b/ext/digest/depend
index 6df940a679..5a84fd53ec 100644
--- a/ext/digest/depend
+++ b/ext/digest/depend
@@ -52,7 +52,6 @@ digest.o: $(hdrdir)/ruby/internal/attr/noexcept.h
digest.o: $(hdrdir)/ruby/internal/attr/noinline.h
digest.o: $(hdrdir)/ruby/internal/attr/nonnull.h
digest.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-digest.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
digest.o: $(hdrdir)/ruby/internal/attr/pure.h
digest.o: $(hdrdir)/ruby/internal/attr/restrict.h
digest.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ digest.o: $(hdrdir)/ruby/internal/intern/enumerator.h
digest.o: $(hdrdir)/ruby/internal/intern/error.h
digest.o: $(hdrdir)/ruby/internal/intern/eval.h
digest.o: $(hdrdir)/ruby/internal/intern/file.h
+digest.o: $(hdrdir)/ruby/internal/intern/gc.h
digest.o: $(hdrdir)/ruby/internal/intern/hash.h
digest.o: $(hdrdir)/ruby/internal/intern/io.h
digest.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ digest.o: $(hdrdir)/ruby/internal/memory.h
digest.o: $(hdrdir)/ruby/internal/method.h
digest.o: $(hdrdir)/ruby/internal/module.h
digest.o: $(hdrdir)/ruby/internal/newobj.h
+digest.o: $(hdrdir)/ruby/internal/rgengc.h
digest.o: $(hdrdir)/ruby/internal/scan_args.h
digest.o: $(hdrdir)/ruby/internal/special_consts.h
digest.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/digest/digest.h b/ext/digest/digest.h
index 68a3da5dd2..8a4c5b7e4e 100644
--- a/ext/digest/digest.h
+++ b/ext/digest/digest.h
@@ -40,8 +40,7 @@ rb_digest_##name##_update(void *ctx, unsigned char *ptr, size_t size) \
for (; size > stride; size -= stride, ptr += stride) { \
name##_Update(ctx, ptr, stride); \
} \
- /* Since size <= stride, size should fit into an unsigned int */ \
- if (size > 0) name##_Update(ctx, ptr, (unsigned int)size); \
+ if (size > 0) name##_Update(ctx, ptr, size); \
}
#define DEFINE_FINISH_FUNC_FROM_FINAL(name) \
diff --git a/ext/digest/md5/depend b/ext/digest/md5/depend
index da1b345999..ea1ceec7fd 100644
--- a/ext/digest/md5/depend
+++ b/ext/digest/md5/depend
@@ -55,7 +55,6 @@ md5.o: $(hdrdir)/ruby/internal/attr/noexcept.h
md5.o: $(hdrdir)/ruby/internal/attr/noinline.h
md5.o: $(hdrdir)/ruby/internal/attr/nonnull.h
md5.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-md5.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
md5.o: $(hdrdir)/ruby/internal/attr/pure.h
md5.o: $(hdrdir)/ruby/internal/attr/restrict.h
md5.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ md5.o: $(hdrdir)/ruby/internal/intern/enumerator.h
md5.o: $(hdrdir)/ruby/internal/intern/error.h
md5.o: $(hdrdir)/ruby/internal/intern/eval.h
md5.o: $(hdrdir)/ruby/internal/intern/file.h
+md5.o: $(hdrdir)/ruby/internal/intern/gc.h
md5.o: $(hdrdir)/ruby/internal/intern/hash.h
md5.o: $(hdrdir)/ruby/internal/intern/io.h
md5.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,6 +145,7 @@ md5.o: $(hdrdir)/ruby/internal/memory.h
md5.o: $(hdrdir)/ruby/internal/method.h
md5.o: $(hdrdir)/ruby/internal/module.h
md5.o: $(hdrdir)/ruby/internal/newobj.h
+md5.o: $(hdrdir)/ruby/internal/rgengc.h
md5.o: $(hdrdir)/ruby/internal/scan_args.h
md5.o: $(hdrdir)/ruby/internal/special_consts.h
md5.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -216,7 +217,6 @@ md5init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
md5init.o: $(hdrdir)/ruby/internal/attr/noinline.h
md5init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
md5init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-md5init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
md5init.o: $(hdrdir)/ruby/internal/attr/pure.h
md5init.o: $(hdrdir)/ruby/internal/attr/restrict.h
md5init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -276,6 +276,7 @@ md5init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
md5init.o: $(hdrdir)/ruby/internal/intern/error.h
md5init.o: $(hdrdir)/ruby/internal/intern/eval.h
md5init.o: $(hdrdir)/ruby/internal/intern/file.h
+md5init.o: $(hdrdir)/ruby/internal/intern/gc.h
md5init.o: $(hdrdir)/ruby/internal/intern/hash.h
md5init.o: $(hdrdir)/ruby/internal/intern/io.h
md5init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -306,6 +307,7 @@ md5init.o: $(hdrdir)/ruby/internal/memory.h
md5init.o: $(hdrdir)/ruby/internal/method.h
md5init.o: $(hdrdir)/ruby/internal/module.h
md5init.o: $(hdrdir)/ruby/internal/newobj.h
+md5init.o: $(hdrdir)/ruby/internal/rgengc.h
md5init.o: $(hdrdir)/ruby/internal/scan_args.h
md5init.o: $(hdrdir)/ruby/internal/special_consts.h
md5init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/digest/rmd160/depend b/ext/digest/rmd160/depend
index abfa08b023..3a0ed72732 100644
--- a/ext/digest/rmd160/depend
+++ b/ext/digest/rmd160/depend
@@ -55,7 +55,6 @@ rmd160.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rmd160.o: $(hdrdir)/ruby/internal/attr/noinline.h
rmd160.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rmd160.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rmd160.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rmd160.o: $(hdrdir)/ruby/internal/attr/pure.h
rmd160.o: $(hdrdir)/ruby/internal/attr/restrict.h
rmd160.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ rmd160.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rmd160.o: $(hdrdir)/ruby/internal/intern/error.h
rmd160.o: $(hdrdir)/ruby/internal/intern/eval.h
rmd160.o: $(hdrdir)/ruby/internal/intern/file.h
+rmd160.o: $(hdrdir)/ruby/internal/intern/gc.h
rmd160.o: $(hdrdir)/ruby/internal/intern/hash.h
rmd160.o: $(hdrdir)/ruby/internal/intern/io.h
rmd160.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,6 +145,7 @@ rmd160.o: $(hdrdir)/ruby/internal/memory.h
rmd160.o: $(hdrdir)/ruby/internal/method.h
rmd160.o: $(hdrdir)/ruby/internal/module.h
rmd160.o: $(hdrdir)/ruby/internal/newobj.h
+rmd160.o: $(hdrdir)/ruby/internal/rgengc.h
rmd160.o: $(hdrdir)/ruby/internal/scan_args.h
rmd160.o: $(hdrdir)/ruby/internal/special_consts.h
rmd160.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -216,7 +217,6 @@ rmd160init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/noinline.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rmd160init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/pure.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/restrict.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -276,6 +276,7 @@ rmd160init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/error.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/eval.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/file.h
+rmd160init.o: $(hdrdir)/ruby/internal/intern/gc.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/hash.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/io.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -306,6 +307,7 @@ rmd160init.o: $(hdrdir)/ruby/internal/memory.h
rmd160init.o: $(hdrdir)/ruby/internal/method.h
rmd160init.o: $(hdrdir)/ruby/internal/module.h
rmd160init.o: $(hdrdir)/ruby/internal/newobj.h
+rmd160init.o: $(hdrdir)/ruby/internal/rgengc.h
rmd160init.o: $(hdrdir)/ruby/internal/scan_args.h
rmd160init.o: $(hdrdir)/ruby/internal/special_consts.h
rmd160init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/digest/sha1/depend b/ext/digest/sha1/depend
index d17338e92b..48aaef158b 100644
--- a/ext/digest/sha1/depend
+++ b/ext/digest/sha1/depend
@@ -55,7 +55,6 @@ sha1.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha1.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha1.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha1.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha1.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha1.o: $(hdrdir)/ruby/internal/attr/pure.h
sha1.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha1.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ sha1.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha1.o: $(hdrdir)/ruby/internal/intern/error.h
sha1.o: $(hdrdir)/ruby/internal/intern/eval.h
sha1.o: $(hdrdir)/ruby/internal/intern/file.h
+sha1.o: $(hdrdir)/ruby/internal/intern/gc.h
sha1.o: $(hdrdir)/ruby/internal/intern/hash.h
sha1.o: $(hdrdir)/ruby/internal/intern/io.h
sha1.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,6 +145,7 @@ sha1.o: $(hdrdir)/ruby/internal/memory.h
sha1.o: $(hdrdir)/ruby/internal/method.h
sha1.o: $(hdrdir)/ruby/internal/module.h
sha1.o: $(hdrdir)/ruby/internal/newobj.h
+sha1.o: $(hdrdir)/ruby/internal/rgengc.h
sha1.o: $(hdrdir)/ruby/internal/scan_args.h
sha1.o: $(hdrdir)/ruby/internal/special_consts.h
sha1.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -216,7 +217,6 @@ sha1init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha1init.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha1init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha1init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha1init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha1init.o: $(hdrdir)/ruby/internal/attr/pure.h
sha1init.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha1init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -276,6 +276,7 @@ sha1init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha1init.o: $(hdrdir)/ruby/internal/intern/error.h
sha1init.o: $(hdrdir)/ruby/internal/intern/eval.h
sha1init.o: $(hdrdir)/ruby/internal/intern/file.h
+sha1init.o: $(hdrdir)/ruby/internal/intern/gc.h
sha1init.o: $(hdrdir)/ruby/internal/intern/hash.h
sha1init.o: $(hdrdir)/ruby/internal/intern/io.h
sha1init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -306,6 +307,7 @@ sha1init.o: $(hdrdir)/ruby/internal/memory.h
sha1init.o: $(hdrdir)/ruby/internal/method.h
sha1init.o: $(hdrdir)/ruby/internal/module.h
sha1init.o: $(hdrdir)/ruby/internal/newobj.h
+sha1init.o: $(hdrdir)/ruby/internal/rgengc.h
sha1init.o: $(hdrdir)/ruby/internal/scan_args.h
sha1init.o: $(hdrdir)/ruby/internal/special_consts.h
sha1init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/digest/sha2/depend b/ext/digest/sha2/depend
index 7b88b6411f..47a859068c 100644
--- a/ext/digest/sha2/depend
+++ b/ext/digest/sha2/depend
@@ -55,7 +55,6 @@ sha2.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha2.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha2.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha2.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha2.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha2.o: $(hdrdir)/ruby/internal/attr/pure.h
sha2.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha2.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ sha2.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha2.o: $(hdrdir)/ruby/internal/intern/error.h
sha2.o: $(hdrdir)/ruby/internal/intern/eval.h
sha2.o: $(hdrdir)/ruby/internal/intern/file.h
+sha2.o: $(hdrdir)/ruby/internal/intern/gc.h
sha2.o: $(hdrdir)/ruby/internal/intern/hash.h
sha2.o: $(hdrdir)/ruby/internal/intern/io.h
sha2.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,6 +145,7 @@ sha2.o: $(hdrdir)/ruby/internal/memory.h
sha2.o: $(hdrdir)/ruby/internal/method.h
sha2.o: $(hdrdir)/ruby/internal/module.h
sha2.o: $(hdrdir)/ruby/internal/newobj.h
+sha2.o: $(hdrdir)/ruby/internal/rgengc.h
sha2.o: $(hdrdir)/ruby/internal/scan_args.h
sha2.o: $(hdrdir)/ruby/internal/special_consts.h
sha2.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -216,7 +217,6 @@ sha2init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha2init.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha2init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha2init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha2init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha2init.o: $(hdrdir)/ruby/internal/attr/pure.h
sha2init.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha2init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -276,6 +276,7 @@ sha2init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha2init.o: $(hdrdir)/ruby/internal/intern/error.h
sha2init.o: $(hdrdir)/ruby/internal/intern/eval.h
sha2init.o: $(hdrdir)/ruby/internal/intern/file.h
+sha2init.o: $(hdrdir)/ruby/internal/intern/gc.h
sha2init.o: $(hdrdir)/ruby/internal/intern/hash.h
sha2init.o: $(hdrdir)/ruby/internal/intern/io.h
sha2init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -306,6 +307,7 @@ sha2init.o: $(hdrdir)/ruby/internal/memory.h
sha2init.o: $(hdrdir)/ruby/internal/method.h
sha2init.o: $(hdrdir)/ruby/internal/module.h
sha2init.o: $(hdrdir)/ruby/internal/newobj.h
+sha2init.o: $(hdrdir)/ruby/internal/rgengc.h
sha2init.o: $(hdrdir)/ruby/internal/scan_args.h
sha2init.o: $(hdrdir)/ruby/internal/special_consts.h
sha2init.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/etc/depend b/ext/etc/depend
index 00787b6aaf..a541db6db6 100644
--- a/ext/etc/depend
+++ b/ext/etc/depend
@@ -58,7 +58,6 @@ etc.o: $(hdrdir)/ruby/internal/attr/noexcept.h
etc.o: $(hdrdir)/ruby/internal/attr/noinline.h
etc.o: $(hdrdir)/ruby/internal/attr/nonnull.h
etc.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-etc.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
etc.o: $(hdrdir)/ruby/internal/attr/pure.h
etc.o: $(hdrdir)/ruby/internal/attr/restrict.h
etc.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -127,6 +126,7 @@ etc.o: $(hdrdir)/ruby/internal/intern/enumerator.h
etc.o: $(hdrdir)/ruby/internal/intern/error.h
etc.o: $(hdrdir)/ruby/internal/intern/eval.h
etc.o: $(hdrdir)/ruby/internal/intern/file.h
+etc.o: $(hdrdir)/ruby/internal/intern/gc.h
etc.o: $(hdrdir)/ruby/internal/intern/hash.h
etc.o: $(hdrdir)/ruby/internal/intern/io.h
etc.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -157,6 +157,7 @@ etc.o: $(hdrdir)/ruby/internal/memory.h
etc.o: $(hdrdir)/ruby/internal/method.h
etc.o: $(hdrdir)/ruby/internal/module.h
etc.o: $(hdrdir)/ruby/internal/newobj.h
+etc.o: $(hdrdir)/ruby/internal/rgengc.h
etc.o: $(hdrdir)/ruby/internal/scan_args.h
etc.o: $(hdrdir)/ruby/internal/special_consts.h
etc.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 69c33f46b0..6c7145b40b 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -54,9 +54,9 @@ static VALUE sGroup;
# include <stdlib.h>
# endif
#endif
-RUBY_EXTERN char *getlogin(void);
+char *getlogin();
-#define RUBY_ETC_VERSION "1.4.3.dev.1"
+#define RUBY_ETC_VERSION "1.4.2"
#ifdef HAVE_RB_DEPRECATE_CONSTANT
void rb_deprecate_constant(VALUE mod, const char *name);
@@ -66,17 +66,6 @@ void rb_deprecate_constant(VALUE mod, const char *name);
#include "constdefs.h"
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
#ifdef HAVE_RUBY_ATOMIC_H
# include "ruby/atomic.h"
#else
@@ -952,11 +941,14 @@ io_pathconf(VALUE io, VALUE arg)
{
int name;
long ret;
+ rb_io_t *fptr;
name = NUM2INT(arg);
+ GetOpenFile(io, fptr);
+
errno = 0;
- ret = fpathconf(rb_io_descriptor(io), name);
+ ret = fpathconf(fptr->fd, name);
if (ret == -1) {
if (errno == 0) /* no limit */
return Qnil;
diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb
index 2e28d58037..159b1614b7 100644
--- a/ext/etc/extconf.rb
+++ b/ext/etc/extconf.rb
@@ -43,23 +43,13 @@ have_struct_member('struct group', 'gr_passwd', 'grp.h')
# for https://github.com/ruby/etc
srcdir = File.expand_path("..", __FILE__)
-constdefs = "#{srcdir}/constdefs.h"
-if !File.exist?(constdefs)
- ruby = RbConfig.ruby
- if File.file?(ruby)
- ruby = [ruby]
- else
- require "shellwords"
- ruby = Shellwords.split(ruby)
- end
- system(*ruby, "#{srcdir}/mkconstants.rb", "-o", constdefs)
+if !File.exist?("#{srcdir}/depend")
+ %x[#{RbConfig.ruby} #{srcdir}/mkconstants.rb -o #{srcdir}/constdefs.h]
end
# TODO: remove when dropping 2.7 support, as exported since 3.0
have_func('rb_deprecate_constant(Qnil, "None")')
-have_func("rb_io_descriptor")
-
$distcleanfiles << "constdefs.h"
create_makefile("etc")
diff --git a/ext/extmk.rb b/ext/extmk.rb
index 428ffc91a6..4e77a7167b 100755
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -43,7 +43,11 @@ $" << "mkmf.rb"
load File.expand_path("lib/mkmf.rb", srcdir)
require 'optparse/shellwords'
-@null = File::NULL
+if defined?(File::NULL)
+ @null = File::NULL
+elsif !File.chardev?(@null = "/dev/null")
+ @null = "nul"
+end
def verbose?
$mflags.defined?("V") == "1"
@@ -132,6 +136,14 @@ def extract_makefile(makefile, keep = true)
true
end
+def create_makefile(target, srcprefix = nil)
+ if $static and target.include?("/")
+ base = File.basename(target)
+ $defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
+ end
+ super
+end
+
def extmake(target, basedir = 'ext', maybestatic = true)
FileUtils.mkpath target unless File.directory?(target)
begin
@@ -159,8 +171,6 @@ def extmake(target, basedir = 'ext', maybestatic = true)
$mdir = target
$srcdir = File.join($top_srcdir, basedir, $mdir)
$preload = nil
- $objs = []
- $srcs = []
$extso = []
makefile = "./Makefile"
static = $static
@@ -194,7 +204,7 @@ def extmake(target, basedir = 'ext', maybestatic = true)
begin
$extconf_h = nil
ok &&= extract_makefile(makefile)
- old_objs = $objs
+ old_objs = $objs || []
old_cleanfiles = $distcleanfiles | $cleanfiles
conf = ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb"].find {|f| File.exist?(f)}
if (!ok || ($extconf_h && !File.exist?($extconf_h)) ||
@@ -257,6 +267,8 @@ def extmake(target, basedir = 'ext', maybestatic = true)
unless $destdir.to_s.empty? or $mflags.defined?("DESTDIR")
args += ["DESTDIR=" + relative_from($destdir, "../"+prefix)]
end
+ $objs ||= []
+ $srcs ||= []
if $static and ok and !$objs.empty? and !noinstall
args += ["static"]
$extlist.push [(maybestatic ? $static : false), target, $target, $preload]
@@ -545,7 +557,13 @@ extend Module.new {
end
def create_makefile(*args, &block)
- return super unless @gemname
+ unless @gemname
+ if $static and (target = args.first).include?("/")
+ base = File.basename(target)
+ $defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
+ end
+ return super
+ end
super(*args) do |conf|
conf.find do |s|
s.sub!(%r(^(srcdir *= *)\$\(top_srcdir\)/\.bundle/gems/[^/]+(?=/))) {
@@ -760,13 +778,6 @@ begin
mf.macro "NOTE_MESG", %w[$(RUBY) $(top_srcdir)/tool/lib/colorize.rb skip]
mf.macro "NOTE_NAME", %w[$(RUBY) $(top_srcdir)/tool/lib/colorize.rb fail]
%w[RM RMDIRS RMDIR RMALL].each {|w| mf.macro w, [RbConfig::CONFIG[w]]}
- if $nmake
- message = ['@(for %I in (', ') do @echo.%~I)']
- else
- message = ['@for line in', '; do echo "$$line"; done']
- end
- mf.macro "MESSAGE_BEGIN", [message.first]
- mf.macro "MESSAGE_END", [message.last]
mf.puts
targets = %w[all install static install-so install-rb clean distclean realclean]
targets.each do |tgt|
@@ -829,17 +840,15 @@ begin
fails.each do |ext, (parent, err)|
abandon ||= mandatory_exts[ext]
mf.puts %Q<\t@$(NOTE_NAME) "#{ext}:">
- mf.puts "\t$(MESSAGE_BEGIN) \\"
if parent
- mf.puts %Q<\t"\tCould not be configured. It will not be installed." \\>
+ mf.puts %Q<\t@echo "\tCould not be configured. It will not be installed.">
err and err.scan(/.+/) do |ee|
- mf.puts %Q<\t"\t#{ee.gsub(/["`$^]/, '\\\\\\&')}" \\>
+ mf.puts %Q<\t@echo "\t#{ee.gsub(/["`$^]/, '\\\\\\&')}">
end
- mf.puts %Q<\t"\tCheck #{ext_prefix}/#{ext}/mkmf.log for more details." \\>
+ mf.puts %Q<\t@echo "\tCheck #{ext_prefix}/#{ext}/mkmf.log for more details.">
else
- mf.puts %Q<\t"\tSkipped because its parent was not configured." \\>
+ mf.puts %Q<\t@echo "\tSkipped because its parent was not configured.">
end
- mf.puts "\t$(MESSAGE_END)"
end
mf.puts "note:\n"
mf.puts %Q<\t@$(NOTE_MESG) "*** Fix the problems, then remove these directories and try again if you want.">
diff --git a/ext/fcntl/depend b/ext/fcntl/depend
index 9ce9fa30ef..718de62e26 100644
--- a/ext/fcntl/depend
+++ b/ext/fcntl/depend
@@ -52,7 +52,6 @@ fcntl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fcntl.o: $(hdrdir)/ruby/internal/attr/noinline.h
fcntl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fcntl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fcntl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fcntl.o: $(hdrdir)/ruby/internal/attr/pure.h
fcntl.o: $(hdrdir)/ruby/internal/attr/restrict.h
fcntl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ fcntl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fcntl.o: $(hdrdir)/ruby/internal/intern/error.h
fcntl.o: $(hdrdir)/ruby/internal/intern/eval.h
fcntl.o: $(hdrdir)/ruby/internal/intern/file.h
+fcntl.o: $(hdrdir)/ruby/internal/intern/gc.h
fcntl.o: $(hdrdir)/ruby/internal/intern/hash.h
fcntl.o: $(hdrdir)/ruby/internal/intern/io.h
fcntl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ fcntl.o: $(hdrdir)/ruby/internal/memory.h
fcntl.o: $(hdrdir)/ruby/internal/method.h
fcntl.o: $(hdrdir)/ruby/internal/module.h
fcntl.o: $(hdrdir)/ruby/internal/newobj.h
+fcntl.o: $(hdrdir)/ruby/internal/rgengc.h
fcntl.o: $(hdrdir)/ruby/internal/scan_args.h
fcntl.o: $(hdrdir)/ruby/internal/special_consts.h
fcntl.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
index 4af2077a0a..3bccc41e4c 100644
--- a/ext/fcntl/fcntl.c
+++ b/ext/fcntl/fcntl.c
@@ -61,16 +61,10 @@ pack up your own arguments to pass as args for locking functions, etc.
* f.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK|m)
*
*/
-
-#define FCNTL_VERSION "1.1.0"
-
void
Init_fcntl(void)
{
VALUE mFcntl = rb_define_module("Fcntl");
-
- rb_define_const(mFcntl, "VERSION", rb_str_new_cstr(FCNTL_VERSION));
-
#ifdef F_DUPFD
/* Document-const: F_DUPFD
*
diff --git a/ext/fcntl/fcntl.gemspec b/ext/fcntl/fcntl.gemspec
index 54aadb4b81..09d3fc2568 100644
--- a/ext/fcntl/fcntl.gemspec
+++ b/ext/fcntl/fcntl.gemspec
@@ -1,19 +1,9 @@
# coding: utf-8
# frozen_string_literal: true
-source_version = ["", "ext/fcntl/"].find do |dir|
- begin
- break File.open(File.join(__dir__, "#{dir}fcntl.c")) {|f|
- f.gets("\n#define FCNTL_VERSION ")
- f.gets[/\s*"(.+)"/, 1]
- }
- rescue Errno::ENOENT
- end
-end
-
Gem::Specification.new do |spec|
spec.name = "fcntl"
- spec.version = source_version
+ spec.version = "1.0.2"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
diff --git a/ext/fiddle/closure.c b/ext/fiddle/closure.c
index 2b4cdb6608..892f522a62 100644
--- a/ext/fiddle/closure.c
+++ b/ext/fiddle/closure.c
@@ -1,5 +1,4 @@
#include <fiddle.h>
-#include <stdbool.h>
#include <ruby/thread.h>
int ruby_thread_has_gvl_p(void); /* from internal.h */
@@ -55,13 +54,10 @@ closure_memsize(const void * ptr)
}
const rb_data_type_t closure_data_type = {
- .wrap_struct_name = "fiddle/closure",
- .function = {
- .dmark = 0,
- .dfree = dealloc,
- .dsize = closure_memsize
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ "fiddle/closure",
+ {0, dealloc, closure_memsize,},
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
};
struct callback_args {
@@ -140,20 +136,6 @@ with_gvl_callback(void *ptr)
rb_ary_push(params,
rb_str_new_cstr(*((const char **)(x->args[i]))));
break;
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(char)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned char *)x->args[i]));
- } else if (sizeof(bool) == sizeof(short)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned short *)x->args[i]));
- } else if (sizeof(bool) == sizeof(int)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned int *)x->args[i]));
- } else if (sizeof(bool) == sizeof(long)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned long *)x->args[i]));
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
- break;
default:
rb_raise(rb_eRuntimeError, "closure args: %d", type);
}
@@ -203,13 +185,6 @@ with_gvl_callback(void *ptr)
/* Dangerous. Callback must keep reference of the String. */
*((const char **)(x->resp)) = StringValueCStr(ret);
break;
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(long)) {
- *(unsigned long *)x->resp = RB_TEST(ret);
- } else {
- *(ffi_arg *)x->resp = RB_TEST(ret);
- }
- break;
default:
rb_raise(rb_eRuntimeError, "closure retval: %d", type);
}
diff --git a/ext/fiddle/conversions.c b/ext/fiddle/conversions.c
index 796bf929c3..3b70f7de4c 100644
--- a/ext/fiddle/conversions.c
+++ b/ext/fiddle/conversions.c
@@ -1,5 +1,3 @@
-#include <stdbool.h>
-
#include <fiddle.h>
VALUE
@@ -46,7 +44,6 @@ rb_fiddle_type_ensure(VALUE type)
ID ptrdiff_t_id;
ID intptr_t_id;
ID uintptr_t_id;
- ID bool_id;
RUBY_CONST_ID(void_id, "void");
RUBY_CONST_ID(voidp_id, "voidp");
RUBY_CONST_ID(char_id, "char");
@@ -77,7 +74,6 @@ rb_fiddle_type_ensure(VALUE type)
RUBY_CONST_ID(ptrdiff_t_id, "ptrdiff_t");
RUBY_CONST_ID(intptr_t_id, "intptr_t");
RUBY_CONST_ID(uintptr_t_id, "uintptr_t");
- RUBY_CONST_ID(bool_id, "bool");
if (type_id == void_id) {
return INT2NUM(TYPE_VOID);
}
@@ -148,9 +144,6 @@ rb_fiddle_type_ensure(VALUE type)
else if (type_id == uintptr_t_id) {
return INT2NUM(TYPE_UINTPTR_T);
}
- else if (type_id == bool_id) {
- return INT2NUM(TYPE_BOOL);
- }
else {
type = original_type;
}
@@ -194,20 +187,6 @@ rb_fiddle_int_to_ffi_type(int type)
return &ffi_type_double;
case TYPE_CONST_STRING:
return &ffi_type_pointer;
- case TYPE_BOOL:
- signed_p = 0;
- if (sizeof(bool) == sizeof(char)) {
- return rb_ffi_type_of(char);
- } else if (sizeof(bool) == sizeof(short)) {
- return rb_ffi_type_of(short);
- } else if (sizeof(bool) == sizeof(int)) {
- return rb_ffi_type_of(int);
- } else if (sizeof(bool) == sizeof(long)) {
- return rb_ffi_type_of(long);
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
@@ -230,11 +209,7 @@ rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
dst->pointer = NUM2PTR(rb_Integer(*src));
break;
case TYPE_CHAR:
- if (RB_TYPE_P(*src, RUBY_T_STRING) && RSTRING_LEN(*src) == 1) {
- dst->schar = RSTRING_PTR(*src)[0];
- } else {
- dst->schar = (signed char)NUM2INT(*src);
- }
+ dst->schar = (signed char)NUM2INT(*src);
break;
case TYPE_UCHAR:
dst->uchar = (unsigned char)NUM2UINT(*src);
@@ -279,23 +254,8 @@ rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
dst->pointer = rb_string_value_cstr(src);
}
break;
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(char)) {
- dst->uchar = RB_TEST(*src);
- } else if (sizeof(bool) == sizeof(short)) {
- dst->ushort = RB_TEST(*src);
- } else if (sizeof(bool) == sizeof(int)) {
- dst->uint = RB_TEST(*src);
- } else if (sizeof(bool) == sizeof(long)) {
- dst->ulong = RB_TEST(*src);
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
- break;
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
- break;
}
}
@@ -354,19 +314,6 @@ rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
else {
return Qnil;
}
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(char)) {
- return CBOOL2RBBOOL((unsigned char)retval.fffi_arg);
- } else if (sizeof(bool) == sizeof(short)) {
- return CBOOL2RBBOOL((unsigned short)retval.fffi_arg);
- } else if (sizeof(bool) == sizeof(int)) {
- return CBOOL2RBBOOL((unsigned int)retval.fffi_arg);
- } else if (sizeof(bool) == sizeof(long)) {
- return CBOOL2RBBOOL(retval.ulong);
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
diff --git a/ext/fiddle/conversions.h b/ext/fiddle/conversions.h
index 7a1e928d56..c7c12a9234 100644
--- a/ext/fiddle/conversions.h
+++ b/ext/fiddle/conversions.h
@@ -50,6 +50,4 @@ VALUE generic_to_value(VALUE rettype, fiddle_generic retval);
# define NUM2PTR(x) ((void*)(NUM2ULL(x)))
#endif
-#define CBOOL2RBBOOL(cbool) ((cbool) ? RUBY_Qtrue : RUBY_Qfalse)
-
#endif
diff --git a/ext/fiddle/depend b/ext/fiddle/depend
index 561785275e..d6a053f05b 100644
--- a/ext/fiddle/depend
+++ b/ext/fiddle/depend
@@ -105,7 +105,6 @@ closure.o: $(hdrdir)/ruby/internal/attr/noexcept.h
closure.o: $(hdrdir)/ruby/internal/attr/noinline.h
closure.o: $(hdrdir)/ruby/internal/attr/nonnull.h
closure.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-closure.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
closure.o: $(hdrdir)/ruby/internal/attr/pure.h
closure.o: $(hdrdir)/ruby/internal/attr/restrict.h
closure.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -165,6 +164,7 @@ closure.o: $(hdrdir)/ruby/internal/intern/enumerator.h
closure.o: $(hdrdir)/ruby/internal/intern/error.h
closure.o: $(hdrdir)/ruby/internal/intern/eval.h
closure.o: $(hdrdir)/ruby/internal/intern/file.h
+closure.o: $(hdrdir)/ruby/internal/intern/gc.h
closure.o: $(hdrdir)/ruby/internal/intern/hash.h
closure.o: $(hdrdir)/ruby/internal/intern/io.h
closure.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -195,6 +195,7 @@ closure.o: $(hdrdir)/ruby/internal/memory.h
closure.o: $(hdrdir)/ruby/internal/method.h
closure.o: $(hdrdir)/ruby/internal/module.h
closure.o: $(hdrdir)/ruby/internal/newobj.h
+closure.o: $(hdrdir)/ruby/internal/rgengc.h
closure.o: $(hdrdir)/ruby/internal/scan_args.h
closure.o: $(hdrdir)/ruby/internal/special_consts.h
closure.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -269,7 +270,6 @@ conversions.o: $(hdrdir)/ruby/internal/attr/noexcept.h
conversions.o: $(hdrdir)/ruby/internal/attr/noinline.h
conversions.o: $(hdrdir)/ruby/internal/attr/nonnull.h
conversions.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-conversions.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
conversions.o: $(hdrdir)/ruby/internal/attr/pure.h
conversions.o: $(hdrdir)/ruby/internal/attr/restrict.h
conversions.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -329,6 +329,7 @@ conversions.o: $(hdrdir)/ruby/internal/intern/enumerator.h
conversions.o: $(hdrdir)/ruby/internal/intern/error.h
conversions.o: $(hdrdir)/ruby/internal/intern/eval.h
conversions.o: $(hdrdir)/ruby/internal/intern/file.h
+conversions.o: $(hdrdir)/ruby/internal/intern/gc.h
conversions.o: $(hdrdir)/ruby/internal/intern/hash.h
conversions.o: $(hdrdir)/ruby/internal/intern/io.h
conversions.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -359,6 +360,7 @@ conversions.o: $(hdrdir)/ruby/internal/memory.h
conversions.o: $(hdrdir)/ruby/internal/method.h
conversions.o: $(hdrdir)/ruby/internal/module.h
conversions.o: $(hdrdir)/ruby/internal/newobj.h
+conversions.o: $(hdrdir)/ruby/internal/rgengc.h
conversions.o: $(hdrdir)/ruby/internal/scan_args.h
conversions.o: $(hdrdir)/ruby/internal/special_consts.h
conversions.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -432,7 +434,6 @@ fiddle.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fiddle.o: $(hdrdir)/ruby/internal/attr/noinline.h
fiddle.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fiddle.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fiddle.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fiddle.o: $(hdrdir)/ruby/internal/attr/pure.h
fiddle.o: $(hdrdir)/ruby/internal/attr/restrict.h
fiddle.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -492,6 +493,7 @@ fiddle.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fiddle.o: $(hdrdir)/ruby/internal/intern/error.h
fiddle.o: $(hdrdir)/ruby/internal/intern/eval.h
fiddle.o: $(hdrdir)/ruby/internal/intern/file.h
+fiddle.o: $(hdrdir)/ruby/internal/intern/gc.h
fiddle.o: $(hdrdir)/ruby/internal/intern/hash.h
fiddle.o: $(hdrdir)/ruby/internal/intern/io.h
fiddle.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -522,6 +524,7 @@ fiddle.o: $(hdrdir)/ruby/internal/memory.h
fiddle.o: $(hdrdir)/ruby/internal/method.h
fiddle.o: $(hdrdir)/ruby/internal/module.h
fiddle.o: $(hdrdir)/ruby/internal/newobj.h
+fiddle.o: $(hdrdir)/ruby/internal/rgengc.h
fiddle.o: $(hdrdir)/ruby/internal/scan_args.h
fiddle.o: $(hdrdir)/ruby/internal/special_consts.h
fiddle.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -595,7 +598,6 @@ function.o: $(hdrdir)/ruby/internal/attr/noexcept.h
function.o: $(hdrdir)/ruby/internal/attr/noinline.h
function.o: $(hdrdir)/ruby/internal/attr/nonnull.h
function.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-function.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
function.o: $(hdrdir)/ruby/internal/attr/pure.h
function.o: $(hdrdir)/ruby/internal/attr/restrict.h
function.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -655,6 +657,7 @@ function.o: $(hdrdir)/ruby/internal/intern/enumerator.h
function.o: $(hdrdir)/ruby/internal/intern/error.h
function.o: $(hdrdir)/ruby/internal/intern/eval.h
function.o: $(hdrdir)/ruby/internal/intern/file.h
+function.o: $(hdrdir)/ruby/internal/intern/gc.h
function.o: $(hdrdir)/ruby/internal/intern/hash.h
function.o: $(hdrdir)/ruby/internal/intern/io.h
function.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -685,6 +688,7 @@ function.o: $(hdrdir)/ruby/internal/memory.h
function.o: $(hdrdir)/ruby/internal/method.h
function.o: $(hdrdir)/ruby/internal/module.h
function.o: $(hdrdir)/ruby/internal/newobj.h
+function.o: $(hdrdir)/ruby/internal/rgengc.h
function.o: $(hdrdir)/ruby/internal/scan_args.h
function.o: $(hdrdir)/ruby/internal/special_consts.h
function.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -759,7 +763,6 @@ handle.o: $(hdrdir)/ruby/internal/attr/noexcept.h
handle.o: $(hdrdir)/ruby/internal/attr/noinline.h
handle.o: $(hdrdir)/ruby/internal/attr/nonnull.h
handle.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-handle.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
handle.o: $(hdrdir)/ruby/internal/attr/pure.h
handle.o: $(hdrdir)/ruby/internal/attr/restrict.h
handle.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -819,6 +822,7 @@ handle.o: $(hdrdir)/ruby/internal/intern/enumerator.h
handle.o: $(hdrdir)/ruby/internal/intern/error.h
handle.o: $(hdrdir)/ruby/internal/intern/eval.h
handle.o: $(hdrdir)/ruby/internal/intern/file.h
+handle.o: $(hdrdir)/ruby/internal/intern/gc.h
handle.o: $(hdrdir)/ruby/internal/intern/hash.h
handle.o: $(hdrdir)/ruby/internal/intern/io.h
handle.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -849,6 +853,7 @@ handle.o: $(hdrdir)/ruby/internal/memory.h
handle.o: $(hdrdir)/ruby/internal/method.h
handle.o: $(hdrdir)/ruby/internal/module.h
handle.o: $(hdrdir)/ruby/internal/newobj.h
+handle.o: $(hdrdir)/ruby/internal/rgengc.h
handle.o: $(hdrdir)/ruby/internal/scan_args.h
handle.o: $(hdrdir)/ruby/internal/special_consts.h
handle.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -923,7 +928,6 @@ memory_view.o: $(hdrdir)/ruby/internal/attr/noexcept.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noinline.h
memory_view.o: $(hdrdir)/ruby/internal/attr/nonnull.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-memory_view.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
memory_view.o: $(hdrdir)/ruby/internal/attr/pure.h
memory_view.o: $(hdrdir)/ruby/internal/attr/restrict.h
memory_view.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -992,6 +996,7 @@ memory_view.o: $(hdrdir)/ruby/internal/intern/enumerator.h
memory_view.o: $(hdrdir)/ruby/internal/intern/error.h
memory_view.o: $(hdrdir)/ruby/internal/intern/eval.h
memory_view.o: $(hdrdir)/ruby/internal/intern/file.h
+memory_view.o: $(hdrdir)/ruby/internal/intern/gc.h
memory_view.o: $(hdrdir)/ruby/internal/intern/hash.h
memory_view.o: $(hdrdir)/ruby/internal/intern/io.h
memory_view.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1022,6 +1027,7 @@ memory_view.o: $(hdrdir)/ruby/internal/memory.h
memory_view.o: $(hdrdir)/ruby/internal/method.h
memory_view.o: $(hdrdir)/ruby/internal/module.h
memory_view.o: $(hdrdir)/ruby/internal/newobj.h
+memory_view.o: $(hdrdir)/ruby/internal/rgengc.h
memory_view.o: $(hdrdir)/ruby/internal/scan_args.h
memory_view.o: $(hdrdir)/ruby/internal/special_consts.h
memory_view.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1098,7 +1104,6 @@ pinned.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pinned.o: $(hdrdir)/ruby/internal/attr/noinline.h
pinned.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pinned.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pinned.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pinned.o: $(hdrdir)/ruby/internal/attr/pure.h
pinned.o: $(hdrdir)/ruby/internal/attr/restrict.h
pinned.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1158,6 +1163,7 @@ pinned.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pinned.o: $(hdrdir)/ruby/internal/intern/error.h
pinned.o: $(hdrdir)/ruby/internal/intern/eval.h
pinned.o: $(hdrdir)/ruby/internal/intern/file.h
+pinned.o: $(hdrdir)/ruby/internal/intern/gc.h
pinned.o: $(hdrdir)/ruby/internal/intern/hash.h
pinned.o: $(hdrdir)/ruby/internal/intern/io.h
pinned.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1188,6 +1194,7 @@ pinned.o: $(hdrdir)/ruby/internal/memory.h
pinned.o: $(hdrdir)/ruby/internal/method.h
pinned.o: $(hdrdir)/ruby/internal/module.h
pinned.o: $(hdrdir)/ruby/internal/newobj.h
+pinned.o: $(hdrdir)/ruby/internal/rgengc.h
pinned.o: $(hdrdir)/ruby/internal/scan_args.h
pinned.o: $(hdrdir)/ruby/internal/special_consts.h
pinned.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1262,7 +1269,6 @@ pointer.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pointer.o: $(hdrdir)/ruby/internal/attr/noinline.h
pointer.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pointer.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pointer.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pointer.o: $(hdrdir)/ruby/internal/attr/pure.h
pointer.o: $(hdrdir)/ruby/internal/attr/restrict.h
pointer.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1331,6 +1337,7 @@ pointer.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pointer.o: $(hdrdir)/ruby/internal/intern/error.h
pointer.o: $(hdrdir)/ruby/internal/intern/eval.h
pointer.o: $(hdrdir)/ruby/internal/intern/file.h
+pointer.o: $(hdrdir)/ruby/internal/intern/gc.h
pointer.o: $(hdrdir)/ruby/internal/intern/hash.h
pointer.o: $(hdrdir)/ruby/internal/intern/io.h
pointer.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1361,6 +1368,7 @@ pointer.o: $(hdrdir)/ruby/internal/memory.h
pointer.o: $(hdrdir)/ruby/internal/method.h
pointer.o: $(hdrdir)/ruby/internal/module.h
pointer.o: $(hdrdir)/ruby/internal/newobj.h
+pointer.o: $(hdrdir)/ruby/internal/rgengc.h
pointer.o: $(hdrdir)/ruby/internal/scan_args.h
pointer.o: $(hdrdir)/ruby/internal/special_consts.h
pointer.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/fiddle/extconf.rb b/ext/fiddle/extconf.rb
index 2d85b3eea5..cf8b5223bb 100644
--- a/ext/fiddle/extconf.rb
+++ b/ext/fiddle/extconf.rb
@@ -63,11 +63,6 @@ unless bundle
end
if have_ffi_header && (have_library('ffi') || have_library('libffi'))
have_libffi = true
- checking_for("undefined FFI_GO_CLOSURES is used") do
- if egrep_cpp(/warning: 'FFI_GO_CLOSURES' is not defined/, cpp_include(ffi_header), "2>&1")
- $defs.push('-DFFI_GO_CLOSURES=0')
- end
- end
end
end
diff --git a/ext/fiddle/fiddle.c b/ext/fiddle/fiddle.c
index f420d9fa3b..c06cd5634a 100644
--- a/ext/fiddle/fiddle.c
+++ b/ext/fiddle/fiddle.c
@@ -1,5 +1,3 @@
-#include <stdbool.h>
-
#include <fiddle.h>
VALUE mFiddle;
@@ -60,16 +58,18 @@ rb_fiddle_free(VALUE self, VALUE addr)
/*
* call-seq: Fiddle.dlunwrap(addr)
*
- * Returns the Ruby object stored at the memory address +addr+
+ * Returns the hexadecimal representation of a memory pointer address +addr+
*
* Example:
*
- * x = Object.new
- * # => #<Object:0x0000000107c7d870>
- * Fiddle.dlwrap(x)
- * # => 4425504880
- * Fiddle.dlunwrap(_)
- * # => #<Object:0x0000000107c7d870>
+ * lib = Fiddle.dlopen('/lib64/libc-2.15.so')
+ * => #<Fiddle::Handle:0x00000001342460>
+ *
+ * lib['strcpy'].to_s(16)
+ * => "7f59de6dd240"
+ *
+ * Fiddle.dlunwrap(Fiddle.dlwrap(lib['strcpy'].to_s(16)))
+ * => "7f59de6dd240"
*/
VALUE
rb_fiddle_ptr2value(VALUE self, VALUE addr)
@@ -80,22 +80,15 @@ rb_fiddle_ptr2value(VALUE self, VALUE addr)
/*
* call-seq: Fiddle.dlwrap(val)
*
- * Returns the memory address of the Ruby object stored at +val+
+ * Returns a memory pointer of a function's hexadecimal address location +val+
*
* Example:
*
- * x = Object.new
- * # => #<Object:0x0000000107c7d870>
- * Fiddle.dlwrap(x)
- * # => 4425504880
- *
- * In the case +val+ is not a heap allocated object, this method will return
- * the tagged pointer value.
+ * lib = Fiddle.dlopen('/lib64/libc-2.15.so')
+ * => #<Fiddle::Handle:0x00000001342460>
*
- * Example:
- *
- * Fiddle.dlwrap(123)
- * # => 247
+ * Fiddle.dlwrap(lib['strcpy'].to_s(16))
+ * => 25522520
*/
static VALUE
rb_fiddle_value2ptr(VALUE self, VALUE val)
@@ -359,12 +352,6 @@ Init_fiddle(void)
*/
rb_define_const(mFiddleTypes, "UINTPTR_T", INT2NUM(TYPE_UINTPTR_T));
- /* Document-const: Fiddle::Types::BOOL
- *
- * C type - bool
- */
- rb_define_const(mFiddleTypes, "BOOL" , INT2NUM(TYPE_BOOL));
-
/* Document-const: ALIGN_VOIDP
*
* The alignment size of a void*
@@ -469,12 +456,6 @@ Init_fiddle(void)
*/
rb_define_const(mFiddle, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t)));
- /* Document-const: ALIGN_BOOL
- *
- * The alignment size of a bool
- */
- rb_define_const(mFiddle, "ALIGN_BOOL", INT2NUM(ALIGN_OF(bool)));
-
/* Document-const: WINDOWS
*
* Returns a boolean regarding whether the host is WIN32
@@ -649,12 +630,6 @@ Init_fiddle(void)
*/
rb_define_const(mFiddle, "SIZEOF_CONST_STRING", INT2NUM(sizeof(const char*)));
- /* Document-const: SIZEOF_BOOL
- *
- * size of a bool
- */
- rb_define_const(mFiddle, "SIZEOF_BOOL", INT2NUM(sizeof(bool)));
-
/* Document-const: RUBY_FREE
*
* Address of the ruby_xfree() function
diff --git a/ext/fiddle/fiddle.h b/ext/fiddle/fiddle.h
index 348baa9ab9..10eb9ceedb 100644
--- a/ext/fiddle/fiddle.h
+++ b/ext/fiddle/fiddle.h
@@ -118,7 +118,7 @@
#define TYPE_UINT -TYPE_INT
#define TYPE_LONG 5
#define TYPE_ULONG -TYPE_LONG
-#ifdef HAVE_LONG_LONG
+#if HAVE_LONG_LONG
#define TYPE_LONG_LONG 6
#define TYPE_ULONG_LONG -TYPE_LONG_LONG
#endif
@@ -126,7 +126,6 @@
#define TYPE_DOUBLE 8
#define TYPE_VARIADIC 9
#define TYPE_CONST_STRING 10
-#define TYPE_BOOL 11
#define TYPE_INT8_T TYPE_CHAR
#define TYPE_UINT8_T -TYPE_INT8_T
@@ -197,20 +196,7 @@
#endif
#define TYPE_UINTPTR_T (-TYPE_INTPTR_T)
-/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023
- <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.
- clang versions < 8.0.0 have the same bug. */
-#if defined(HAVE__ALIGNOF)
-# /* Autoconf detected availability of a sane `_Alignof()`. */
-# define ALIGN_OF(type) RB_GNUC_EXTENSION(_Alignof(type))
-#elif (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112 \
- || (defined(__GNUC__) && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
- && !defined(__clang__)) \
- || (defined(__clang__) && __clang_major__ < 8))
-# define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)
-#else
-# define ALIGN_OF(type) _Alignof(type)
-#endif
+#define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)
#define ALIGN_VOIDP ALIGN_OF(void*)
#define ALIGN_CHAR ALIGN_OF(char)
diff --git a/ext/fiddle/function.c b/ext/fiddle/function.c
index 5469e09e37..274d181d17 100644
--- a/ext/fiddle/function.c
+++ b/ext/fiddle/function.c
@@ -53,13 +53,8 @@ function_memsize(const void *p)
}
const rb_data_type_t function_data_type = {
- .wrap_struct_name = "fiddle/function",
- .function = {
- .dmark = 0,
- .dfree = deallocate,
- .dsize = function_memsize
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ "fiddle/function",
+ {0, deallocate, function_memsize,},
};
static VALUE
diff --git a/ext/fiddle/handle.c b/ext/fiddle/handle.c
index 8ba416952a..ae8cc3a581 100644
--- a/ext/fiddle/handle.c
+++ b/ext/fiddle/handle.c
@@ -50,13 +50,8 @@ fiddle_handle_memsize(const void *ptr)
}
static const rb_data_type_t fiddle_handle_data_type = {
- .wrap_struct_name = "fiddle/handle",
- .function = {
- .dmark = 0,
- .dfree = fiddle_handle_free,
- .dsize = fiddle_handle_memsize
- },
- .flags = RUBY_TYPED_WB_PROTECTED,
+ "fiddle/handle",
+ {0, fiddle_handle_free, fiddle_handle_memsize,},
};
/*
diff --git a/ext/fiddle/lib/fiddle/cparser.rb b/ext/fiddle/lib/fiddle/cparser.rb
index 264ca166dd..9a70402953 100644
--- a/ext/fiddle/lib/fiddle/cparser.rb
+++ b/ext/fiddle/lib/fiddle/cparser.rb
@@ -165,30 +165,18 @@ module Fiddle
raise(RuntimeError, "unsupported type: #{ty}")
end
return TYPE_ULONG_LONG
- when /\Aunsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\Aunsigned\s+int\s+long(?:\s+\w+)?\z/,
- /\Along(?:\s+int)?\s+unsigned(?:\s+\w+)?\z/,
- /\Aint\s+unsigned\s+long(?:\s+\w+)?\z/,
- /\A(?:int\s+)?long\s+unsigned(?:\s+\w+)?\z/
- return TYPE_ULONG
- when /\A(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\A(?:signed\s+)?int\s+long(?:\s+\w+)?\z/,
- /\Along(?:\s+int)?\s+signed(?:\s+\w+)?\z/
+ when /\A(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?\z/
return TYPE_LONG
- when /\Aunsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\Aunsigned\s+int\s+short(?:\s+\w+)?\z/,
- /\Ashort(?:\s+int)?\s+unsigned(?:\s+\w+)?\z/,
- /\Aint\s+unsigned\s+short(?:\s+\w+)?\z/,
- /\A(?:int\s+)?short\s+unsigned(?:\s+\w+)?\z/
- return TYPE_USHORT
- when /\A(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\A(?:signed\s+)?int\s+short(?:\s+\w+)?\z/,
- /\Aint\s+(?:signed\s+)?short(?:\s+\w+)?\z/
- return TYPE_SHORT
+ when /\Aunsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?\z/
+ return TYPE_ULONG
when /\A(?:signed\s+)?int(?:\s+\w+)?\z/
return TYPE_INT
when /\A(?:unsigned\s+int|uint)(?:\s+\w+)?\z/
return TYPE_UINT
+ when /\A(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?\z/
+ return TYPE_SHORT
+ when /\Aunsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?\z/
+ return TYPE_USHORT
when /\A(?:signed\s+)?char(?:\s+\w+)?\z/
return TYPE_CHAR
when /\Aunsigned\s+char(?:\s+\w+)?\z/
@@ -247,8 +235,6 @@ module Fiddle
return TYPE_INTPTR_T
when /\Auintptr_t(?:\s+\w+)?\z/
return TYPE_UINTPTR_T
- when "bool"
- return TYPE_BOOL
when /\*/, /\[[\s\d]*\]/
return TYPE_VOIDP
when "..."
diff --git a/ext/fiddle/lib/fiddle/import.rb b/ext/fiddle/lib/fiddle/import.rb
index 050708fb96..09ffcef544 100644
--- a/ext/fiddle/lib/fiddle/import.rb
+++ b/ext/fiddle/lib/fiddle/import.rb
@@ -119,8 +119,6 @@ module Fiddle
return SIZEOF_VOIDP
when TYPE_CONST_STRING
return SIZEOF_CONST_STRING
- when TYPE_BOOL
- return SIZEOF_BOOL
else
if defined?(TYPE_LONG_LONG) and
ty == TYPE_LONG_LONG
diff --git a/ext/fiddle/lib/fiddle/pack.rb b/ext/fiddle/lib/fiddle/pack.rb
index 81088f402b..545b985d50 100644
--- a/ext/fiddle/lib/fiddle/pack.rb
+++ b/ext/fiddle/lib/fiddle/pack.rb
@@ -15,7 +15,6 @@ module Fiddle
TYPE_USHORT => ALIGN_SHORT,
TYPE_UINT => ALIGN_INT,
TYPE_ULONG => ALIGN_LONG,
- TYPE_BOOL => ALIGN_BOOL,
}
PACK_MAP = {
@@ -31,16 +30,6 @@ module Fiddle
TYPE_UINT => "I!",
TYPE_ULONG => "L!",
}
- case SIZEOF_BOOL
- when SIZEOF_CHAR
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_UCHAR]
- when SIZEOF_SHORT
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_USHORT]
- when SIZEOF_INT
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_UINT]
- when SIZEOF_LONG
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_ULONG]
- end
SIZE_MAP = {
TYPE_VOIDP => SIZEOF_VOIDP,
@@ -54,7 +43,6 @@ module Fiddle
TYPE_USHORT => SIZEOF_SHORT,
TYPE_UINT => SIZEOF_INT,
TYPE_ULONG => SIZEOF_LONG,
- TYPE_BOOL => SIZEOF_BOOL,
}
if defined?(TYPE_LONG_LONG)
ALIGN_MAP[TYPE_LONG_LONG] = ALIGN_MAP[TYPE_ULONG_LONG] = ALIGN_LONG_LONG
diff --git a/ext/fiddle/lib/fiddle/value.rb b/ext/fiddle/lib/fiddle/value.rb
index 5f0b2e951e..01fec1c206 100644
--- a/ext/fiddle/lib/fiddle/value.rb
+++ b/ext/fiddle/lib/fiddle/value.rb
@@ -6,17 +6,17 @@ module Fiddle
def unsigned_value(val, ty)
case ty.abs
when TYPE_CHAR
- [val].pack("c").unpack1("C")
+ [val].pack("c").unpack("C")[0]
when TYPE_SHORT
- [val].pack("s!").unpack1("S!")
+ [val].pack("s!").unpack("S!")[0]
when TYPE_INT
- [val].pack("i!").unpack1("I!")
+ [val].pack("i!").unpack("I!")[0]
when TYPE_LONG
- [val].pack("l!").unpack1("L!")
+ [val].pack("l!").unpack("L!")[0]
else
if defined?(TYPE_LONG_LONG) and
ty.abs == TYPE_LONG_LONG
- [val].pack("q").unpack1("Q")
+ [val].pack("q").unpack("Q")[0]
else
val
end
@@ -26,17 +26,17 @@ module Fiddle
def signed_value(val, ty)
case ty.abs
when TYPE_CHAR
- [val].pack("C").unpack1("c")
+ [val].pack("C").unpack("c")[0]
when TYPE_SHORT
- [val].pack("S!").unpack1("s!")
+ [val].pack("S!").unpack("s!")[0]
when TYPE_INT
- [val].pack("I!").unpack1("i!")
+ [val].pack("I!").unpack("i!")[0]
when TYPE_LONG
- [val].pack("L!").unpack1("l!")
+ [val].pack("L!").unpack("l!")[0]
else
if defined?(TYPE_LONG_LONG) and
ty.abs == TYPE_LONG_LONG
- [val].pack("Q").unpack1("q")
+ [val].pack("Q").unpack("q")[0]
else
val
end
@@ -80,11 +80,11 @@ module Fiddle
else
case SIZEOF_VOIDP
when SIZEOF_LONG
- return [arg].pack("p").unpack1("l!")
+ return [arg].pack("p").unpack("l!")[0]
else
if defined?(SIZEOF_LONG_LONG) and
SIZEOF_VOIDP == SIZEOF_LONG_LONG
- return [arg].pack("p").unpack1("q")
+ return [arg].pack("p").unpack("q")[0]
else
raise(RuntimeError, "sizeof(void*)?")
end
@@ -102,8 +102,10 @@ module Fiddle
return val.unpack('C*')
end
end
+ return arg
+ else
+ return arg
end
- return arg
else
if( arg.respond_to?(:to_ptr) )
return arg.to_ptr.to_i
diff --git a/ext/fiddle/lib/fiddle/version.rb b/ext/fiddle/lib/fiddle/version.rb
index 706d98a7b5..719dc62e37 100644
--- a/ext/fiddle/lib/fiddle/version.rb
+++ b/ext/fiddle/lib/fiddle/version.rb
@@ -1,3 +1,3 @@
module Fiddle
- VERSION = "1.1.2"
+ VERSION = "1.1.1"
end
diff --git a/ext/fiddle/pointer.c b/ext/fiddle/pointer.c
index 1b7d7a69f6..15107e3862 100644
--- a/ext/fiddle/pointer.c
+++ b/ext/fiddle/pointer.c
@@ -88,13 +88,8 @@ fiddle_ptr_memsize(const void *ptr)
}
static const rb_data_type_t fiddle_ptr_data_type = {
- .wrap_struct_name = "fiddle/pointer",
- .function = {
- .dmark = fiddle_ptr_mark,
- .dfree = fiddle_ptr_free,
- .dsize = fiddle_ptr_memsize,
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ "fiddle/pointer",
+ {fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
};
#ifdef HAVE_RUBY_MEMORY_VIEW_H
@@ -140,8 +135,8 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func, VALUE wra
data->free = func;
data->freed = false;
data->size = size;
- RB_OBJ_WRITE(val, &data->wrap[0], wrap0);
- RB_OBJ_WRITE(val, &data->wrap[1], wrap1);
+ data->wrap[0] = wrap0;
+ data->wrap[1] = wrap1;
return val;
}
@@ -240,8 +235,8 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
/* Free previous memory. Use of inappropriate initialize may cause SEGV. */
(*(data->free))(data->ptr);
}
- RB_OBJ_WRITE(self, &data->wrap[0], wrap);
- RB_OBJ_WRITE(self, &data->wrap[1], funcwrap);
+ data->wrap[0] = wrap;
+ data->wrap[1] = funcwrap;
data->ptr = p;
data->size = s;
data->free = f;
@@ -319,7 +314,7 @@ rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
}
obj = rb_fiddle_ptr_malloc(klass, s,f);
- if (wrap) RB_OBJ_WRITE(obj, &RPTR_DATA(obj)->wrap[1], wrap);
+ if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
if (rb_block_given_p()) {
if (!f) {
@@ -800,37 +795,10 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
if (num == val) wrap = 0;
ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
}
- if (wrap) RB_OBJ_WRITE(ptr, &RPTR_DATA(ptr)->wrap[0], wrap);
+ if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
return ptr;
}
-/*
- * call-seq:
- * Fiddle::Pointer.read(address, len) => string
- *
- * Or read the memory at address +address+ with length +len+ and return a
- * string with that memory
- */
-
-static VALUE
-rb_fiddle_ptr_read_mem(VALUE klass, VALUE address, VALUE len)
-{
- return rb_str_new((char *)NUM2PTR(address), NUM2ULONG(len));
-}
-
-/*
- * call-seq:
- * Fiddle::Pointer.write(address, str)
- *
- * Write bytes in +str+ to the location pointed to by +address+.
- */
-static VALUE
-rb_fiddle_ptr_write_mem(VALUE klass, VALUE addr, VALUE str)
-{
- memcpy(NUM2PTR(addr), StringValuePtr(str), RSTRING_LEN(str));
- return str;
-}
-
void
Init_fiddle_pointer(void)
{
@@ -847,8 +815,6 @@ Init_fiddle_pointer(void)
rb_define_singleton_method(rb_cPointer, "malloc", rb_fiddle_ptr_s_malloc, -1);
rb_define_singleton_method(rb_cPointer, "to_ptr", rb_fiddle_ptr_s_to_ptr, 1);
rb_define_singleton_method(rb_cPointer, "[]", rb_fiddle_ptr_s_to_ptr, 1);
- rb_define_singleton_method(rb_cPointer, "read", rb_fiddle_ptr_read_mem, 2);
- rb_define_singleton_method(rb_cPointer, "write", rb_fiddle_ptr_write_mem, 2);
rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
diff --git a/ext/fiddle/win32/libffi-config.rb b/ext/fiddle/win32/libffi-config.rb
index 8e8069a943..985fc29d36 100755
--- a/ext/fiddle/win32/libffi-config.rb
+++ b/ext/fiddle/win32/libffi-config.rb
@@ -23,7 +23,7 @@ until ARGV.empty?
end
end
-File.foreach("#{srcdir}/configure.ac") do |line|
+IO.foreach("#{srcdir}/configure.ac") do |line|
if /^AC_INIT\((.*)\)/ =~ line
version = $1.split(/,\s*/)[1]
version.gsub!(/\A\[|\]\z/, '')
@@ -38,11 +38,11 @@ conf['TARGET'] = /^x64/ =~ host ? "X86_WIN64" : "X86_WIN32"
FileUtils.mkdir_p([builddir, "#{builddir}/include", "#{builddir}/src/x86"])
FileUtils.cp("#{basedir}/fficonfig.h", ".", preserve: true)
-hdr = File.binread("#{srcdir}/include/ffi.h.in")
+hdr = IO.binread("#{srcdir}/include/ffi.h.in")
hdr.gsub!(/@(\w+)@/) {conf[$1] || $&}
hdr.gsub!(/^(#if\s+)@\w+@/, '\10')
-File.binwrite("#{builddir}/include/ffi.h", hdr)
+IO.binwrite("#{builddir}/include/ffi.h", hdr)
-mk = File.binread("#{basedir}/libffi.mk.tmpl")
+mk = IO.binread("#{basedir}/libffi.mk.tmpl")
mk.gsub!(/@(\w+)@/) {conf[$1] || $&}
-File.binwrite("Makefile", mk)
+IO.binwrite("Makefile", mk)
diff --git a/ext/io/console/.document b/ext/io/console/.document
deleted file mode 100644
index 945a377256..0000000000
--- a/ext/io/console/.document
+++ /dev/null
@@ -1,2 +0,0 @@
-console.c
-lib/size.rb
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 61b6e76327..21454a73fa 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -76,7 +76,9 @@ getattr(int fd, conmode *t)
#endif
static ID id_getc, id_console, id_close;
-static ID id_gets, id_flush, id_chomp_bang;
+#if ENABLE_IO_GETPASS
+static ID id_gets, id_chomp_bang;
+#endif
#if defined HAVE_RUBY_FIBER_SCHEDULER_H
# include "ruby/fiber/scheduler.h"
@@ -85,41 +87,7 @@ extern VALUE rb_scheduler_timeout(struct timeval *timeout);
# define rb_fiber_scheduler_make_timeout rb_scheduler_timeout
#endif
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
-#ifndef HAVE_RB_IO_PATH
-static VALUE
-io_path_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->pathv;
-}
-#define rb_io_path io_path_fallback
-#endif
-
-#ifndef HAVE_RB_IO_GET_WRITE_IO
-static VALUE
-io_get_write_io_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- VALUE wio = fptr->tied_io_for_writing;
- return wio ? wio : io;
-}
-#define rb_io_get_write_io io_get_write_io_fallback
-#endif
-
-#define sys_fail(io) rb_sys_fail_str(rb_io_path(io))
+#define sys_fail_fptr(fptr) rb_sys_fail_str((fptr)->pathv)
#ifndef HAVE_RB_F_SEND
#ifndef RB_PASS_CALLED_KEYWORDS
@@ -325,21 +293,33 @@ set_ttymode(int fd, conmode *t, void (*setter)(conmode *, void *), void *arg)
return setattr(fd, &r);
}
-#define GetReadFD(io) rb_io_descriptor(io)
-#define GetWriteFD(io) rb_io_descriptor(rb_io_get_write_io(io))
+#define GetReadFD(fptr) ((fptr)->fd)
+
+static inline int
+get_write_fd(const rb_io_t *fptr)
+{
+ VALUE wio = fptr->tied_io_for_writing;
+ rb_io_t *ofptr;
+ if (!wio) return fptr->fd;
+ GetOpenFile(wio, ofptr);
+ return ofptr->fd;
+}
+#define GetWriteFD(fptr) get_write_fd(fptr)
#define FD_PER_IO 2
static VALUE
ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
{
+ rb_io_t *fptr;
int status = -1;
int error = 0;
int fd[FD_PER_IO];
conmode t[FD_PER_IO];
VALUE result = Qnil;
- fd[0] = GetReadFD(io);
+ GetOpenFile(io, fptr);
+ fd[0] = GetReadFD(fptr);
if (fd[0] != -1) {
if (set_ttymode(fd[0], t+0, setter, arg)) {
status = 0;
@@ -349,7 +329,7 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
fd[0] = -1;
}
}
- fd[1] = GetWriteFD(io);
+ fd[1] = GetWriteFD(fptr);
if (fd[1] != -1 && fd[1] != fd[0]) {
if (set_ttymode(fd[1], t+1, setter, arg)) {
status = 0;
@@ -362,13 +342,14 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
if (status == 0) {
result = rb_protect(func, farg, &status);
}
- if (fd[0] != -1 && fd[0] == GetReadFD(io)) {
+ GetOpenFile(io, fptr);
+ if (fd[0] != -1 && fd[0] == GetReadFD(fptr)) {
if (!setattr(fd[0], t+0)) {
error = errno;
status = -1;
}
}
- if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(io)) {
+ if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(fptr)) {
if (!setattr(fd[1], t+1)) {
error = errno;
status = -1;
@@ -454,11 +435,15 @@ static VALUE
console_set_raw(int argc, VALUE *argv, VALUE io)
{
conmode t;
+ rb_io_t *fptr;
+ int fd;
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
- int fd = GetReadFD(io);
- if (!getattr(fd, &t)) sys_fail(io);
+
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
set_rawmode(&t, optp);
- if (!setattr(fd, &t)) sys_fail(io);
+ if (!setattr(fd, &t)) sys_fail_fptr(fptr);
return io;
}
@@ -494,10 +479,14 @@ static VALUE
console_set_cooked(VALUE io)
{
conmode t;
- int fd = GetReadFD(io);
- if (!getattr(fd, &t)) sys_fail(io);
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
set_cookedmode(&t, NULL);
- if (!setattr(fd, &t)) sys_fail(io);
+ if (!setattr(fd, &t)) sys_fail_fptr(fptr);
return io;
}
@@ -649,17 +638,17 @@ static VALUE
console_set_echo(VALUE io, VALUE f)
{
conmode t;
- int fd = GetReadFD(io);
-
- if (!getattr(fd, &t)) sys_fail(io);
+ rb_io_t *fptr;
+ int fd;
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
if (RTEST(f))
- set_echo(&t, NULL);
+ set_echo(&t, NULL);
else
- set_noecho(&t, NULL);
-
- if (!setattr(fd, &t)) sys_fail(io);
-
+ set_noecho(&t, NULL);
+ if (!setattr(fd, &t)) sys_fail_fptr(fptr);
return io;
}
@@ -675,9 +664,12 @@ static VALUE
console_echo_p(VALUE io)
{
conmode t;
- int fd = GetReadFD(io);
+ rb_io_t *fptr;
+ int fd;
- if (!getattr(fd, &t)) sys_fail(io);
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
return echo_p(&t) ? Qtrue : Qfalse;
}
@@ -756,9 +748,12 @@ static VALUE
console_conmode_get(VALUE io)
{
conmode t;
- int fd = GetReadFD(io);
+ rb_io_t *fptr;
+ int fd;
- if (!getattr(fd, &t)) sys_fail(io);
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
return conmode_new(cConmode, &t);
}
@@ -775,12 +770,14 @@ static VALUE
console_conmode_set(VALUE io, VALUE mode)
{
conmode *t, r;
- int fd = GetReadFD(io);
+ rb_io_t *fptr;
+ int fd;
TypedData_Get_Struct(mode, conmode, &conmode_type, t);
r = *t;
-
- if (!setattr(fd, &r)) sys_fail(io);
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!setattr(fd, &r)) sys_fail_fptr(fptr);
return mode;
}
@@ -816,9 +813,13 @@ typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
static VALUE
console_winsize(VALUE io)
{
+ rb_io_t *fptr;
+ int fd;
rb_console_size_t ws;
- int fd = GetWriteFD(io);
- if (!getwinsize(fd, &ws)) sys_fail(io);
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
+ if (!getwinsize(fd, &ws)) sys_fail_fptr(fptr);
return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}
@@ -834,6 +835,7 @@ console_winsize(VALUE io)
static VALUE
console_set_winsize(VALUE io, VALUE size)
{
+ rb_io_t *fptr;
rb_console_size_t ws;
#if defined _WIN32
HANDLE wh;
@@ -842,17 +844,20 @@ console_set_winsize(VALUE io, VALUE size)
#endif
VALUE row, col, xpixel, ypixel;
const VALUE *sz;
- long sizelen;
int fd;
+ long sizelen;
+ GetOpenFile(io, fptr);
size = rb_Array(size);
if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
- rb_raise(rb_eArgError, "wrong number of arguments (given %ld, expected 2 or 4)", sizelen);
+ rb_raise(rb_eArgError,
+ "wrong number of arguments (given %ld, expected 2 or 4)",
+ sizelen);
}
sz = RARRAY_CONST_PTR(size);
row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
- fd = GetWriteFD(io);
+ fd = GetWriteFD(fptr);
#if defined TIOCSWINSZ
ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
#define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
@@ -861,7 +866,7 @@ console_set_winsize(VALUE io, VALUE size)
SET(xpixel);
SET(ypixel);
#undef SET
- if (!setwinsize(fd, &ws)) sys_fail(io);
+ if (!setwinsize(fd, &ws)) sys_fail_fptr(fptr);
#elif defined _WIN32
wh = (HANDLE)rb_w32_get_osfhandle(fd);
#define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
@@ -899,10 +904,12 @@ console_set_winsize(VALUE io, VALUE size)
static VALUE
console_check_winsize_changed(VALUE io)
{
+ rb_io_t *fptr;
HANDLE h;
DWORD num;
- h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
INPUT_RECORD rec;
if (ReadConsoleInput(h, &rec, 1, &num)) {
@@ -928,11 +935,15 @@ console_check_winsize_changed(VALUE io)
static VALUE
console_iflush(VALUE io)
{
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
- int fd = GetReadFD(io);
- if (tcflush(fd, TCIFLUSH)) sys_fail(io);
+ if (tcflush(fd, TCIFLUSH)) sys_fail_fptr(fptr);
#endif
-
+ (void)fd;
return io;
}
@@ -947,9 +958,13 @@ console_iflush(VALUE io)
static VALUE
console_oflush(VALUE io)
{
- int fd = GetWriteFD(io);
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
- if (tcflush(fd, TCOFLUSH)) sys_fail(io);
+ if (tcflush(fd, TCOFLUSH)) sys_fail_fptr(fptr);
#endif
(void)fd;
return io;
@@ -966,30 +981,40 @@ console_oflush(VALUE io)
static VALUE
console_ioflush(VALUE io)
{
+ rb_io_t *fptr;
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
- int fd1 = GetReadFD(io);
- int fd2 = GetWriteFD(io);
+ int fd1, fd2;
+#endif
+ GetOpenFile(io, fptr);
+#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
+ fd1 = GetReadFD(fptr);
+ fd2 = GetWriteFD(fptr);
if (fd2 != -1 && fd1 != fd2) {
- if (tcflush(fd1, TCIFLUSH)) sys_fail(io);
- if (tcflush(fd2, TCOFLUSH)) sys_fail(io);
+ if (tcflush(fd1, TCIFLUSH)) sys_fail_fptr(fptr);
+ if (tcflush(fd2, TCOFLUSH)) sys_fail_fptr(fptr);
}
else {
- if (tcflush(fd1, TCIOFLUSH)) sys_fail(io);
+ if (tcflush(fd1, TCIOFLUSH)) sys_fail_fptr(fptr);
}
#endif
-
return io;
}
static VALUE
console_beep(VALUE io)
{
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
#ifdef _WIN32
+ (void)fd;
MessageBeep(0);
#else
- int fd = GetWriteFD(io);
- if (write(fd, "\a", 1) < 0) sys_fail(io);
+ if (write(fd, "\a", 1) < 0)
+ sys_fail_fptr(fptr);
#endif
return io;
}
@@ -1010,6 +1035,79 @@ mode_in_range(VALUE val, int high, const char *modename)
}
#if defined _WIN32
+static VALUE
+console_goto(VALUE io, VALUE y, VALUE x)
+{
+ rb_io_t *fptr;
+ int fd;
+ COORD pos;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
+ pos.X = NUM2UINT(x);
+ pos.Y = NUM2UINT(y);
+ if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return io;
+}
+
+static VALUE
+console_cursor_pos(VALUE io)
+{
+ rb_io_t *fptr;
+ int fd;
+ rb_console_size_t ws;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
+ if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
+}
+
+static VALUE
+console_move(VALUE io, int y, int x)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ pos->X += x;
+ pos->Y += y;
+ if (!SetConsoleCursorPosition(h, *pos)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return io;
+}
+
+static VALUE
+console_goto_column(VALUE io, VALUE val)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ pos->X = NUM2INT(val);
+ if (!SetConsoleCursorPosition(h, *pos)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return io;
+}
+
static void
constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
{
@@ -1020,12 +1118,86 @@ constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
}
static VALUE
+console_erase_line(VALUE io, VALUE val)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+ DWORD w;
+ int mode = mode_in_range(val, 2, "line erase");
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ w = winsize_col(&ws);
+ switch (mode) {
+ case 0: /* after cursor */
+ w -= pos->X;
+ break;
+ case 1: /* before *and* cursor */
+ w = pos->X + 1;
+ pos->X = 0;
+ break;
+ case 2: /* entire line */
+ pos->X = 0;
+ break;
+ }
+ constat_clear(h, ws.wAttributes, w, *pos);
+ return io;
+}
+
+static VALUE
+console_erase_screen(VALUE io, VALUE val)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+ DWORD w;
+ int mode = mode_in_range(val, 3, "screen erase");
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ w = winsize_col(&ws);
+ switch (mode) {
+ case 0: /* erase after cursor */
+ w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
+ break;
+ case 1: /* erase before *and* cursor */
+ w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
+ pos->X = 0;
+ pos->Y = ws.srWindow.Top;
+ break;
+ case 2: /* erase entire screen */
+ w = (w * winsize_row(&ws));
+ pos->X = 0;
+ pos->Y = ws.srWindow.Top;
+ break;
+ case 3: /* erase entire screen */
+ w = (w * ws.dwSize.Y);
+ pos->X = 0;
+ pos->Y = 0;
+ break;
+ }
+ constat_clear(h, ws.wAttributes, w, *pos);
+ return io;
+}
+
+static VALUE
console_scroll(VALUE io, int line)
{
+ rb_io_t *fptr;
HANDLE h;
rb_console_size_t ws;
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
if (!GetConsoleScreenBufferInfo(h, &ws)) {
rb_syserr_fail(LAST_ERROR, 0);
}
@@ -1084,11 +1256,23 @@ static int
direct_query(VALUE io, const struct query_args *query)
{
if (RB_TYPE_P(io, T_FILE)) {
- VALUE wio = rb_io_get_write_io(io);
- VALUE s = rb_str_new_cstr(query->qstr);
- rb_io_write(wio, s);
- rb_io_flush(wio);
- return 1;
+ rb_io_t *fptr;
+ VALUE wio;
+ GetOpenFile(io, fptr);
+ wio = fptr->tied_io_for_writing;
+ if (wio) {
+ VALUE s = rb_str_new_cstr(query->qstr);
+ rb_io_write(wio, s);
+ rb_io_flush(wio);
+ return 1;
+ }
+ if (write(fptr->fd, query->qstr, strlen(query->qstr)) != -1) {
+ return 1;
+ }
+ if (fptr->fd == 0 &&
+ write(1, query->qstr, strlen(query->qstr)) != -1) {
+ return 1;
+ }
}
return 0;
}
@@ -1139,30 +1323,8 @@ console_vt_response(int argc, VALUE *argv, VALUE io, const struct query_args *qa
}
static VALUE
-console_scroll(VALUE io, int line)
-{
- if (line) {
- VALUE s = rb_sprintf("\x1b[%d%c", line < 0 ? -line : line,
- line < 0 ? 'T' : 'S');
- rb_io_write(io, s);
- }
- return io;
-}
-
-# define console_key_pressed_p rb_f_notimplement
-#endif
-
-static VALUE
console_cursor_pos(VALUE io)
{
-#ifdef _WIN32
- rb_console_size_t ws;
- int fd = GetWriteFD(io);
- if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
-#else
static const struct query_args query = {"\033[6n", 0};
VALUE resp = console_vt_response(0, 0, io, &query);
VALUE row, column, term;
@@ -1179,44 +1341,18 @@ console_cursor_pos(VALUE io)
RARRAY_ASET(resp, 0, INT2NUM(r));
RARRAY_ASET(resp, 1, INT2NUM(c));
return resp;
-#endif
}
static VALUE
console_goto(VALUE io, VALUE y, VALUE x)
{
-#ifdef _WIN32
- COORD pos;
- int fd = GetWriteFD(io);
- pos.X = NUM2UINT(x);
- pos.Y = NUM2UINT(y);
- if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
-#else
rb_io_write(io, rb_sprintf("\x1b[%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
-#endif
return io;
}
static VALUE
console_move(VALUE io, int y, int x)
{
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
-
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- pos->X += x;
- pos->Y += y;
- if (!SetConsoleCursorPosition(h, *pos)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
-#else
if (x || y) {
VALUE s = rb_str_new_cstr("");
if (y) rb_str_catf(s, "\x1b[%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B');
@@ -1224,29 +1360,13 @@ console_move(VALUE io, int y, int x)
rb_io_write(io, s);
rb_io_flush(io);
}
-#endif
return io;
}
static VALUE
console_goto_column(VALUE io, VALUE val)
{
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
-
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- pos->X = NUM2INT(val);
- if (!SetConsoleCursorPosition(h, *pos)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
-#else
rb_io_write(io, rb_sprintf("\x1b[%dG", NUM2UINT(val)+1));
-#endif
return io;
}
@@ -1254,34 +1374,7 @@ static VALUE
console_erase_line(VALUE io, VALUE val)
{
int mode = mode_in_range(val, 2, "line erase");
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
- DWORD w;
-
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- w = winsize_col(&ws);
- switch (mode) {
- case 0: /* after cursor */
- w -= pos->X;
- break;
- case 1: /* before *and* cursor */
- w = pos->X + 1;
- pos->X = 0;
- break;
- case 2: /* entire line */
- pos->X = 0;
- break;
- }
- constat_clear(h, ws.wAttributes, w, *pos);
- return io;
-#else
rb_io_write(io, rb_sprintf("\x1b[%dK", mode));
-#endif
return io;
}
@@ -1289,43 +1382,22 @@ static VALUE
console_erase_screen(VALUE io, VALUE val)
{
int mode = mode_in_range(val, 3, "screen erase");
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
- DWORD w;
+ rb_io_write(io, rb_sprintf("\x1b[%dJ", mode));
+ return io;
+}
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- w = winsize_col(&ws);
- switch (mode) {
- case 0: /* erase after cursor */
- w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
- break;
- case 1: /* erase before *and* cursor */
- w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
- pos->X = 0;
- pos->Y = ws.srWindow.Top;
- break;
- case 2: /* erase entire screen */
- w = (w * winsize_row(&ws));
- pos->X = 0;
- pos->Y = ws.srWindow.Top;
- break;
- case 3: /* erase entire screen */
- w = (w * ws.dwSize.Y);
- pos->X = 0;
- pos->Y = 0;
- break;
+static VALUE
+console_scroll(VALUE io, int line)
+{
+ if (line) {
+ VALUE s = rb_sprintf("\x1b[%d%c", line < 0 ? -line : line,
+ line < 0 ? 'T' : 'S');
+ rb_io_write(io, s);
}
- constat_clear(h, ws.wAttributes, w, *pos);
-#else
- rb_io_write(io, rb_sprintf("\x1b[%dJ", mode));
-#endif
return io;
}
+# define console_key_pressed_p rb_f_notimplement
+#endif
static VALUE
console_cursor_set(VALUE io, VALUE cpos)
@@ -1379,38 +1451,6 @@ console_clear_screen(VALUE io)
return io;
}
-#ifndef HAVE_RB_IO_OPEN_DESCRIPTOR
-static VALUE
-io_open_descriptor_fallback(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, void *encoding)
-{
- rb_update_max_fd(descriptor);
-
- VALUE arguments[2] = {
- INT2NUM(descriptor),
- INT2FIX(mode),
- };
-
- VALUE self = rb_class_new_instance(2, arguments, klass);
-
- rb_io_t *fptr;
- GetOpenFile(self, fptr);
- fptr->pathv = path;
- fptr->mode |= mode;
-
- return self;
-}
-#define rb_io_open_descriptor io_open_descriptor_fallback
-#endif
-
-#ifndef HAVE_RB_IO_CLOSED_P
-static VALUE
-rb_io_closed_p(VALUE io)
-{
- rb_io_t *fptr = RFILE(io)->fptr;
- return fptr->fd == -1 ? Qtrue : Qfalse;
-}
-#endif
-
/*
* call-seq:
* IO.console -> #<File:/dev/tty>
@@ -1428,37 +1468,34 @@ static VALUE
console_dev(int argc, VALUE *argv, VALUE klass)
{
VALUE con = 0;
+ rb_io_t *fptr;
VALUE sym = 0;
rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
-
if (argc) {
- Check_Type(sym = argv[0], T_SYMBOL);
+ Check_Type(sym = argv[0], T_SYMBOL);
}
-
- // Force the class to be File.
if (klass == rb_cIO) klass = rb_cFile;
-
if (rb_const_defined(klass, id_console)) {
- con = rb_const_get(klass, id_console);
- if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) {
- rb_const_remove(klass, id_console);
- con = 0;
- }
+ con = rb_const_get(klass, id_console);
+ if (!RB_TYPE_P(con, T_FILE) ||
+ (!(fptr = RFILE(con)->fptr) || GetReadFD(fptr) == -1)) {
+ rb_const_remove(klass, id_console);
+ con = 0;
+ }
}
-
if (sym) {
- if (sym == ID2SYM(id_close) && argc == 1) {
- if (con) {
- rb_io_close(con);
- rb_const_remove(klass, id_console);
- con = 0;
- }
- return Qnil;
- }
+ if (sym == ID2SYM(id_close) && argc == 1) {
+ if (con) {
+ rb_io_close(con);
+ rb_const_remove(klass, id_console);
+ con = 0;
+ }
+ return Qnil;
+ }
}
-
if (!con) {
+ VALUE args[2];
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
# define CONSOLE_DEVICE "/dev/tty"
#elif defined _WIN32
@@ -1470,36 +1507,44 @@ console_dev(int argc, VALUE *argv, VALUE klass)
# define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
#endif
#ifdef CONSOLE_DEVICE_FOR_WRITING
- VALUE out;
- rb_io_t *ofptr;
+ VALUE out;
+ rb_io_t *ofptr;
#endif
- int fd;
- VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
+ int fd;
#ifdef CONSOLE_DEVICE_FOR_WRITING
- fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
- if (fd < 0) return Qnil;
- out = rb_io_open_descriptor(klass, fd, FMODE_WRITABLE | FMODE_SYNC, path, Qnil, NULL);
+ fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
+ if (fd < 0) return Qnil;
+ rb_update_max_fd(fd);
+ args[1] = INT2FIX(O_WRONLY);
+ args[0] = INT2NUM(fd);
+ out = rb_class_new_instance(2, args, klass);
#endif
- fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
- if (fd < 0) {
+ fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
+ if (fd < 0) {
#ifdef CONSOLE_DEVICE_FOR_WRITING
- rb_io_close(out);
+ rb_io_close(out);
#endif
- return Qnil;
- }
-
- con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL);
+ return Qnil;
+ }
+ rb_update_max_fd(fd);
+ args[1] = INT2FIX(O_RDWR);
+ args[0] = INT2NUM(fd);
+ con = rb_class_new_instance(2, args, klass);
+ GetOpenFile(con, fptr);
+ fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
#ifdef CONSOLE_DEVICE_FOR_WRITING
- rb_io_set_write_io(con, out);
+ GetOpenFile(out, ofptr);
+ ofptr->pathv = fptr->pathv;
+ fptr->tied_io_for_writing = out;
+ ofptr->mode |= FMODE_SYNC;
#endif
- rb_const_set(klass, id_console, con);
+ fptr->mode |= FMODE_SYNC;
+ rb_const_set(klass, id_console, con);
}
-
if (sym) {
- return rb_f_send(argc, argv, con);
+ return rb_f_send(argc, argv, con);
}
-
return con;
}
@@ -1515,6 +1560,7 @@ io_getch(int argc, VALUE *argv, VALUE io)
return rb_funcallv(io, id_getc, argc, argv);
}
+#if ENABLE_IO_GETPASS
static VALUE
puts_call(VALUE io)
{
@@ -1522,12 +1568,6 @@ puts_call(VALUE io)
}
static VALUE
-gets_call(VALUE io)
-{
- return rb_funcallv(io, id_gets, 0, 0);
-}
-
-static VALUE
getpass_call(VALUE io)
{
return ttymode(io, rb_io_gets, io, set_noecho, NULL);
@@ -1547,8 +1587,7 @@ static VALUE
str_chomp(VALUE str)
{
if (!NIL_P(str)) {
- const VALUE rs = rb_default_rs; /* rvalue in TruffleRuby */
- rb_funcallv(str, id_chomp_bang, 1, &rs);
+ rb_funcallv(str, id_chomp_bang, 0, 0);
}
return str;
}
@@ -1565,12 +1604,6 @@ str_chomp(VALUE str)
* see String#chomp!.
*
* You must require 'io/console' to use this method.
- *
- * require 'io/console'
- * IO::console.getpass("Enter password:")
- * Enter password:
- * # => "mypassword"
- *
*/
static VALUE
console_getpass(int argc, VALUE *argv, VALUE io)
@@ -1581,7 +1614,6 @@ console_getpass(int argc, VALUE *argv, VALUE io)
wio = rb_io_get_write_io(io);
if (wio == io && io == rb_stdin) wio = rb_stderr;
prompt(argc, argv, wio);
- rb_io_flush(wio);
str = rb_ensure(getpass_call, io, puts_call, wio);
return str_chomp(str);
}
@@ -1599,10 +1631,11 @@ io_getpass(int argc, VALUE *argv, VALUE io)
rb_check_arity(argc, 0, 1);
prompt(argc, argv, io);
- rb_check_funcall(io, id_flush, 0, 0);
- str = rb_ensure(gets_call, io, puts_call, io);
- return str_chomp(str);
+ str = str_chomp(rb_funcallv(io, id_gets, 0, 0));
+ puts_call(io);
+ return str;
}
+#endif
/*
* IO console methods
@@ -1612,9 +1645,10 @@ Init_console(void)
{
#undef rb_intern
id_getc = rb_intern("getc");
+#if ENABLE_IO_GETPASS
id_gets = rb_intern("gets");
- id_flush = rb_intern("flush");
id_chomp_bang = rb_intern("chomp!");
+#endif
id_console = rb_intern("console");
id_close = rb_intern("close");
#define init_rawmode_opt_id(name) \
@@ -1662,17 +1696,20 @@ InitVM_console(void)
rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0);
rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
rb_define_method(rb_cIO, "check_winsize_changed", console_check_winsize_changed, 0);
+#if ENABLE_IO_GETPASS
rb_define_method(rb_cIO, "getpass", console_getpass, -1);
+#endif
rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
{
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
rb_define_method(mReadable, "getch", io_getch, -1);
+#if ENABLE_IO_GETPASS
rb_define_method(mReadable, "getpass", io_getpass, -1);
+#endif
}
{
/* :stopdoc: */
cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
- rb_define_const(cConmode, "VERSION", rb_str_new_cstr(STRINGIZE(IO_CONSOLE_VERSION)));
rb_define_alloc_func(cConmode, conmode_alloc);
rb_undef_method(cConmode, "initialize");
rb_define_method(cConmode, "initialize_copy", conmode_init_copy, 1);
diff --git a/ext/io/console/depend b/ext/io/console/depend
index 59ca3442c2..36747ef583 100644
--- a/ext/io/console/depend
+++ b/ext/io/console/depend
@@ -54,7 +54,6 @@ console.o: $(hdrdir)/ruby/internal/attr/noexcept.h
console.o: $(hdrdir)/ruby/internal/attr/noinline.h
console.o: $(hdrdir)/ruby/internal/attr/nonnull.h
console.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-console.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
console.o: $(hdrdir)/ruby/internal/attr/pure.h
console.o: $(hdrdir)/ruby/internal/attr/restrict.h
console.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -123,6 +122,7 @@ console.o: $(hdrdir)/ruby/internal/intern/enumerator.h
console.o: $(hdrdir)/ruby/internal/intern/error.h
console.o: $(hdrdir)/ruby/internal/intern/eval.h
console.o: $(hdrdir)/ruby/internal/intern/file.h
+console.o: $(hdrdir)/ruby/internal/intern/gc.h
console.o: $(hdrdir)/ruby/internal/intern/hash.h
console.o: $(hdrdir)/ruby/internal/intern/io.h
console.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -153,6 +153,7 @@ console.o: $(hdrdir)/ruby/internal/memory.h
console.o: $(hdrdir)/ruby/internal/method.h
console.o: $(hdrdir)/ruby/internal/module.h
console.o: $(hdrdir)/ruby/internal/newobj.h
+console.o: $(hdrdir)/ruby/internal/rgengc.h
console.o: $(hdrdir)/ruby/internal/scan_args.h
console.o: $(hdrdir)/ruby/internal/special_consts.h
console.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -184,7 +185,7 @@ win32_vk.inc: win32_vk.list
-e 'n=$$F[1] and (n.strip!; /\AVK_/=~n) and' \
-e 'puts(%[#ifndef #{n}\n# define #{n} UNDEFINED_VK\n#endif])' \
$< && \
- gperf --ignore-case -E -C -P -p -j1 -i 1 -g -o -t -K ofs -N console_win32_vk -k* $< \
+ gperf --ignore-case -L ANSI-C -E -C -P -p -j1 -i 1 -g -o -t -K ofs -N console_win32_vk -k* $< \
| sed -f $(top_srcdir)/tool/gperf.sed \
) > $(@F)
diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb
index aa0b6c6cfb..e8c5923b18 100644
--- a/ext/io/console/extconf.rb
+++ b/ext/io/console/extconf.rb
@@ -1,17 +1,6 @@
# frozen_string_literal: false
require 'mkmf'
-version = ["../../..", "."].find do |dir|
- break File.read(File.join(__dir__, dir, "io-console.gemspec"))[/^_VERSION\s*=\s*"(.*?)"/, 1]
-rescue
-end
-
-have_func("rb_io_path")
-have_func("rb_io_descriptor")
-have_func("rb_io_get_write_io")
-have_func("rb_io_closed_p")
-have_func("rb_io_open_descriptor")
-
ok = true if RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby"
hdr = nil
case
@@ -40,7 +29,7 @@ when true
elsif have_func("rb_scheduler_timeout") # 3.0
have_func("rb_io_wait")
end
- $defs << "-D""IO_CONSOLE_VERSION=#{version}"
+ $defs << "-D""ENABLE_IO_GETPASS=1"
create_makefile("io/console") {|conf|
conf << "\n""VK_HEADER = #{vk_header}\n"
}
diff --git a/ext/io/console/io-console.gemspec b/ext/io/console/io-console.gemspec
index 32261e8c39..d26a757b01 100644
--- a/ext/io/console/io-console.gemspec
+++ b/ext/io/console/io-console.gemspec
@@ -1,5 +1,5 @@
# -*- ruby -*-
-_VERSION = "0.6.1.dev.1"
+_VERSION = "0.6.0"
Gem::Specification.new do |s|
s.name = "io-console"
@@ -13,7 +13,6 @@ Gem::Specification.new do |s|
s.authors = ["Nobu Nakada"]
s.require_path = %[lib]
s.files = %w[
- .document
LICENSE.txt
README.md
ext/io/console/console.c
@@ -26,16 +25,15 @@ Gem::Specification.new do |s|
if Gem::Platform === s.platform and s.platform =~ 'java'
s.files.delete_if {|f| f.start_with?("ext/")}
s.extensions.clear
- s.require_paths.unshift('lib/ffi')
s.files.concat(%w[
- lib/ffi/io/console.rb
- lib/ffi/io/console/bsd_console.rb
- lib/ffi/io/console/common.rb
- lib/ffi/io/console/linux_console.rb
- lib/ffi/io/console/native_console.rb
- lib/ffi/io/console/stty_console.rb
- lib/ffi/io/console/stub_console.rb
- lib/ffi/io/console/version.rb
+ lib/io/console.rb
+ lib/io/console/ffi/bsd_console.rb
+ lib/io/console/ffi/common.rb
+ lib/io/console/ffi/console.rb
+ lib/io/console/ffi/linux_console.rb
+ lib/io/console/ffi/native_console.rb
+ lib/io/console/ffi/stty_console.rb
+ lib/io/console/ffi/stub_console.rb
])
end
diff --git a/ext/io/console/win32_vk.inc b/ext/io/console/win32_vk.inc
index cbec7bef15..d15b1219fb 100644
--- a/ext/io/console/win32_vk.inc
+++ b/ext/io/console/win32_vk.inc
@@ -480,7 +480,7 @@
# define VK_OEM_CLEAR UNDEFINED_VK
#endif
/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf --ignore-case -E -C -P -p -j1 -i 1 -g -o -t -K ofs -N console_win32_vk -k'*' win32_vk.list */
+/* Command-line: gperf --ignore-case -L ANSI-C -E -C -P -p -j1 -i 1 -g -o -t -K ofs -N console_win32_vk -k'*' win32_vk.list */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -509,18 +509,17 @@
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
#endif
-#define gperf_offsetof(s, n) (short)offsetof(struct s##_t, s##_str##n)
#line 1 "win32_vk.list"
struct vktable {short ofs; unsigned short vk;};
-static const struct vktable *console_win32_vk(/*const char *, unsigned int*/);
+static const struct vktable *console_win32_vk(const char *, size_t);
#line 5 "win32_vk.list"
struct vktable;
/* maximum key range = 245, duplicates = 0 */
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
-static unsigned char gperf_downcase[256] =
+static const unsigned char gperf_downcase[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -1007,368 +1006,368 @@ console_win32_vk (register const char *str, register size_t len)
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1},
#line 40 "win32_vk.list"
- {gperf_offsetof(stringpool, 12), VK_UP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str12, VK_UP},
#line 52 "win32_vk.list"
- {gperf_offsetof(stringpool, 13), VK_APPS},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str13, VK_APPS},
#line 159 "win32_vk.list"
- {gperf_offsetof(stringpool, 14), VK_CRSEL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str14, VK_CRSEL},
#line 34 "win32_vk.list"
- {gperf_offsetof(stringpool, 15), VK_SPACE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str15, VK_SPACE},
#line 95 "win32_vk.list"
- {gperf_offsetof(stringpool, 16), VK_SCROLL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str16, VK_SCROLL},
#line 29 "win32_vk.list"
- {gperf_offsetof(stringpool, 17), VK_ESCAPE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str17, VK_ESCAPE},
#line 9 "win32_vk.list"
- {gperf_offsetof(stringpool, 18), VK_CANCEL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str18, VK_CANCEL},
#line 32 "win32_vk.list"
- {gperf_offsetof(stringpool, 19), VK_ACCEPT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str19, VK_ACCEPT},
#line 66 "win32_vk.list"
- {gperf_offsetof(stringpool, 20), VK_SEPARATOR},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str20, VK_SEPARATOR},
#line 43 "win32_vk.list"
- {gperf_offsetof(stringpool, 21), VK_SELECT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str21, VK_SELECT},
#line 18 "win32_vk.list"
- {gperf_offsetof(stringpool, 22), VK_CONTROL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str22, VK_CONTROL},
#line 166 "win32_vk.list"
- {gperf_offsetof(stringpool, 23), VK_OEM_CLEAR},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str23, VK_OEM_CLEAR},
#line 145 "win32_vk.list"
- {gperf_offsetof(stringpool, 24), VK_OEM_RESET},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str24, VK_OEM_RESET},
#line 155 "win32_vk.list"
- {gperf_offsetof(stringpool, 25), VK_OEM_AUTO},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str25, VK_OEM_AUTO},
#line 151 "win32_vk.list"
- {gperf_offsetof(stringpool, 26), VK_OEM_CUSEL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str26, VK_OEM_CUSEL},
{-1},
#line 22 "win32_vk.list"
- {gperf_offsetof(stringpool, 28), VK_KANA},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str28, VK_KANA},
#line 127 "win32_vk.list"
- {gperf_offsetof(stringpool, 29), VK_OEM_PLUS},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str29, VK_OEM_PLUS},
#line 35 "win32_vk.list"
- {gperf_offsetof(stringpool, 30), VK_PRIOR},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str30, VK_PRIOR},
#line 152 "win32_vk.list"
- {gperf_offsetof(stringpool, 31), VK_OEM_ATTN},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str31, VK_OEM_ATTN},
#line 20 "win32_vk.list"
- {gperf_offsetof(stringpool, 32), VK_PAUSE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str32, VK_PAUSE},
#line 13 "win32_vk.list"
- {gperf_offsetof(stringpool, 33), VK_BACK},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str33, VK_BACK},
#line 144 "win32_vk.list"
- {gperf_offsetof(stringpool, 34), VK_PACKET},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str34, VK_PACKET},
#line 105 "win32_vk.list"
- {gperf_offsetof(stringpool, 35), VK_RCONTROL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str35, VK_RCONTROL},
#line 104 "win32_vk.list"
- {gperf_offsetof(stringpool, 36), VK_LCONTROL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str36, VK_LCONTROL},
#line 37 "win32_vk.list"
- {gperf_offsetof(stringpool, 37), VK_END},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str37, VK_END},
#line 38 "win32_vk.list"
- {gperf_offsetof(stringpool, 38), VK_HOME},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str38, VK_HOME},
#line 44 "win32_vk.list"
- {gperf_offsetof(stringpool, 39), VK_PRINT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str39, VK_PRINT},
#line 94 "win32_vk.list"
- {gperf_offsetof(stringpool, 40), VK_NUMLOCK},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str40, VK_NUMLOCK},
#line 39 "win32_vk.list"
- {gperf_offsetof(stringpool, 41), VK_LEFT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str41, VK_LEFT},
#line 25 "win32_vk.list"
- {gperf_offsetof(stringpool, 42), VK_JUNJA},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str42, VK_JUNJA},
#line 19 "win32_vk.list"
- {gperf_offsetof(stringpool, 43), VK_MENU},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str43, VK_MENU},
#line 150 "win32_vk.list"
- {gperf_offsetof(stringpool, 44), VK_OEM_WSCTRL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str44, VK_OEM_WSCTRL},
#line 156 "win32_vk.list"
- {gperf_offsetof(stringpool, 45), VK_OEM_ENLW},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str45, VK_OEM_ENLW},
#line 36 "win32_vk.list"
- {gperf_offsetof(stringpool, 46), VK_NEXT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str46, VK_NEXT},
#line 51 "win32_vk.list"
- {gperf_offsetof(stringpool, 47), VK_RWIN},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str47, VK_RWIN},
#line 50 "win32_vk.list"
- {gperf_offsetof(stringpool, 48), VK_LWIN},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str48, VK_LWIN},
#line 21 "win32_vk.list"
- {gperf_offsetof(stringpool, 49), VK_CAPITAL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str49, VK_CAPITAL},
#line 49 "win32_vk.list"
- {gperf_offsetof(stringpool, 50), VK_HELP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str50, VK_HELP},
#line 164 "win32_vk.list"
- {gperf_offsetof(stringpool, 51), VK_NONAME},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str51, VK_NONAME},
#line 8 "win32_vk.list"
- {gperf_offsetof(stringpool, 52), VK_RBUTTON},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str52, VK_RBUTTON},
#line 7 "win32_vk.list"
- {gperf_offsetof(stringpool, 53), VK_LBUTTON},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str53, VK_LBUTTON},
#line 96 "win32_vk.list"
- {gperf_offsetof(stringpool, 54), VK_OEM_NEC_EQUAL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str54, VK_OEM_NEC_EQUAL},
{-1},
#line 47 "win32_vk.list"
- {gperf_offsetof(stringpool, 56), VK_INSERT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str56, VK_INSERT},
#line 27 "win32_vk.list"
- {gperf_offsetof(stringpool, 57), VK_HANJA},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str57, VK_HANJA},
{-1}, {-1},
#line 46 "win32_vk.list"
- {gperf_offsetof(stringpool, 60), VK_SNAPSHOT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str60, VK_SNAPSHOT},
#line 158 "win32_vk.list"
- {gperf_offsetof(stringpool, 61), VK_ATTN},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str61, VK_ATTN},
#line 14 "win32_vk.list"
- {gperf_offsetof(stringpool, 62), VK_TAB},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str62, VK_TAB},
#line 157 "win32_vk.list"
- {gperf_offsetof(stringpool, 63), VK_OEM_BACKTAB},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str63, VK_OEM_BACKTAB},
#line 143 "win32_vk.list"
- {gperf_offsetof(stringpool, 64), VK_ICO_CLEAR},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str64, VK_ICO_CLEAR},
#line 30 "win32_vk.list"
- {gperf_offsetof(stringpool, 65), VK_CONVERT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str65, VK_CONVERT},
#line 16 "win32_vk.list"
- {gperf_offsetof(stringpool, 66), VK_RETURN},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str66, VK_RETURN},
#line 146 "win32_vk.list"
- {gperf_offsetof(stringpool, 67), VK_OEM_JUMP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str67, VK_OEM_JUMP},
{-1}, {-1}, {-1},
#line 111 "win32_vk.list"
- {gperf_offsetof(stringpool, 71), VK_BROWSER_STOP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str71, VK_BROWSER_STOP},
#line 26 "win32_vk.list"
- {gperf_offsetof(stringpool, 72), VK_FINAL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str72, VK_FINAL},
#line 163 "win32_vk.list"
- {gperf_offsetof(stringpool, 73), VK_ZOOM},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str73, VK_ZOOM},
#line 28 "win32_vk.list"
- {gperf_offsetof(stringpool, 74), VK_KANJI},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str74, VK_KANJI},
#line 48 "win32_vk.list"
- {gperf_offsetof(stringpool, 75), VK_DELETE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str75, VK_DELETE},
#line 128 "win32_vk.list"
- {gperf_offsetof(stringpool, 76), VK_OEM_COMMA},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str76, VK_OEM_COMMA},
#line 67 "win32_vk.list"
- {gperf_offsetof(stringpool, 77), VK_SUBTRACT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str77, VK_SUBTRACT},
{-1},
#line 10 "win32_vk.list"
- {gperf_offsetof(stringpool, 79), VK_MBUTTON},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str79, VK_MBUTTON},
#line 78 "win32_vk.list"
- {gperf_offsetof(stringpool, 80), VK_F9},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str80, VK_F9},
#line 17 "win32_vk.list"
- {gperf_offsetof(stringpool, 81), VK_SHIFT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str81, VK_SHIFT},
#line 103 "win32_vk.list"
- {gperf_offsetof(stringpool, 82), VK_RSHIFT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str82, VK_RSHIFT},
#line 102 "win32_vk.list"
- {gperf_offsetof(stringpool, 83), VK_LSHIFT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str83, VK_LSHIFT},
#line 65 "win32_vk.list"
- {gperf_offsetof(stringpool, 84), VK_ADD},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str84, VK_ADD},
#line 31 "win32_vk.list"
- {gperf_offsetof(stringpool, 85), VK_NONCONVERT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str85, VK_NONCONVERT},
#line 160 "win32_vk.list"
- {gperf_offsetof(stringpool, 86), VK_EXSEL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str86, VK_EXSEL},
#line 126 "win32_vk.list"
- {gperf_offsetof(stringpool, 87), VK_OEM_1},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str87, VK_OEM_1},
#line 138 "win32_vk.list"
- {gperf_offsetof(stringpool, 88), VK_OEM_AX},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str88, VK_OEM_AX},
#line 108 "win32_vk.list"
- {gperf_offsetof(stringpool, 89), VK_BROWSER_BACK},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str89, VK_BROWSER_BACK},
#line 137 "win32_vk.list"
- {gperf_offsetof(stringpool, 90), VK_OEM_8},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str90, VK_OEM_8},
#line 129 "win32_vk.list"
- {gperf_offsetof(stringpool, 91), VK_OEM_MINUS},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str91, VK_OEM_MINUS},
#line 162 "win32_vk.list"
- {gperf_offsetof(stringpool, 92), VK_PLAY},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str92, VK_PLAY},
#line 131 "win32_vk.list"
- {gperf_offsetof(stringpool, 93), VK_OEM_2},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str93, VK_OEM_2},
#line 15 "win32_vk.list"
- {gperf_offsetof(stringpool, 94), VK_CLEAR},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str94, VK_CLEAR},
#line 99 "win32_vk.list"
- {gperf_offsetof(stringpool, 95), VK_OEM_FJ_TOUROKU},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str95, VK_OEM_FJ_TOUROKU},
#line 147 "win32_vk.list"
- {gperf_offsetof(stringpool, 96), VK_OEM_PA1},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str96, VK_OEM_PA1},
#line 140 "win32_vk.list"
- {gperf_offsetof(stringpool, 97), VK_ICO_HELP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str97, VK_ICO_HELP},
#line 112 "win32_vk.list"
- {gperf_offsetof(stringpool, 98), VK_BROWSER_SEARCH},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str98, VK_BROWSER_SEARCH},
#line 53 "win32_vk.list"
- {gperf_offsetof(stringpool, 99), VK_SLEEP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str99, VK_SLEEP},
{-1},
#line 70 "win32_vk.list"
- {gperf_offsetof(stringpool, 101), VK_F1},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str101, VK_F1},
#line 148 "win32_vk.list"
- {gperf_offsetof(stringpool, 102), VK_OEM_PA2},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str102, VK_OEM_PA2},
#line 154 "win32_vk.list"
- {gperf_offsetof(stringpool, 103), VK_OEM_COPY},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str103, VK_OEM_COPY},
#line 77 "win32_vk.list"
- {gperf_offsetof(stringpool, 104), VK_F8},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str104, VK_F8},
#line 88 "win32_vk.list"
- {gperf_offsetof(stringpool, 105), VK_F19},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str105, VK_F19},
#line 41 "win32_vk.list"
- {gperf_offsetof(stringpool, 106), VK_RIGHT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str106, VK_RIGHT},
#line 71 "win32_vk.list"
- {gperf_offsetof(stringpool, 107), VK_F2},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str107, VK_F2},
#line 135 "win32_vk.list"
- {gperf_offsetof(stringpool, 108), VK_OEM_6},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str108, VK_OEM_6},
#line 87 "win32_vk.list"
- {gperf_offsetof(stringpool, 109), VK_F18},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str109, VK_F18},
{-1},
#line 117 "win32_vk.list"
- {gperf_offsetof(stringpool, 111), VK_VOLUME_UP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str111, VK_VOLUME_UP},
{-1}, {-1},
#line 120 "win32_vk.list"
- {gperf_offsetof(stringpool, 114), VK_MEDIA_STOP},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str114, VK_MEDIA_STOP},
#line 130 "win32_vk.list"
- {gperf_offsetof(stringpool, 115), VK_OEM_PERIOD},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str115, VK_OEM_PERIOD},
{-1},
#line 161 "win32_vk.list"
- {gperf_offsetof(stringpool, 117), VK_EREOF},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str117, VK_EREOF},
{-1}, {-1}, {-1},
#line 114 "win32_vk.list"
- {gperf_offsetof(stringpool, 121), VK_BROWSER_HOME},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str121, VK_BROWSER_HOME},
#line 75 "win32_vk.list"
- {gperf_offsetof(stringpool, 122), VK_F6},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str122, VK_F6},
{-1},
#line 110 "win32_vk.list"
- {gperf_offsetof(stringpool, 124), VK_BROWSER_REFRESH},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str124, VK_BROWSER_REFRESH},
{-1},
#line 165 "win32_vk.list"
- {gperf_offsetof(stringpool, 126), VK_PA1},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str126, VK_PA1},
#line 142 "win32_vk.list"
- {gperf_offsetof(stringpool, 127), VK_PROCESSKEY},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str127, VK_PROCESSKEY},
#line 68 "win32_vk.list"
- {gperf_offsetof(stringpool, 128), VK_DECIMAL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str128, VK_DECIMAL},
#line 132 "win32_vk.list"
- {gperf_offsetof(stringpool, 129), VK_OEM_3},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str129, VK_OEM_3},
#line 107 "win32_vk.list"
- {gperf_offsetof(stringpool, 130), VK_RMENU},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str130, VK_RMENU},
#line 106 "win32_vk.list"
- {gperf_offsetof(stringpool, 131), VK_LMENU},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str131, VK_LMENU},
#line 98 "win32_vk.list"
- {gperf_offsetof(stringpool, 132), VK_OEM_FJ_MASSHOU},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str132, VK_OEM_FJ_MASSHOU},
#line 54 "win32_vk.list"
- {gperf_offsetof(stringpool, 133), VK_NUMPAD0},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str133, VK_NUMPAD0},
#line 24 "win32_vk.list"
- {gperf_offsetof(stringpool, 134), VK_HANGUL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str134, VK_HANGUL},
#line 63 "win32_vk.list"
- {gperf_offsetof(stringpool, 135), VK_NUMPAD9},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str135, VK_NUMPAD9},
#line 23 "win32_vk.list"
- {gperf_offsetof(stringpool, 136), VK_HANGEUL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str136, VK_HANGEUL},
#line 134 "win32_vk.list"
- {gperf_offsetof(stringpool, 137), VK_OEM_5},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str137, VK_OEM_5},
#line 149 "win32_vk.list"
- {gperf_offsetof(stringpool, 138), VK_OEM_PA3},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str138, VK_OEM_PA3},
#line 115 "win32_vk.list"
- {gperf_offsetof(stringpool, 139), VK_VOLUME_MUTE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str139, VK_VOLUME_MUTE},
#line 133 "win32_vk.list"
- {gperf_offsetof(stringpool, 140), VK_OEM_4},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str140, VK_OEM_4},
#line 122 "win32_vk.list"
- {gperf_offsetof(stringpool, 141), VK_LAUNCH_MAIL},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str141, VK_LAUNCH_MAIL},
#line 97 "win32_vk.list"
- {gperf_offsetof(stringpool, 142), VK_OEM_FJ_JISHO},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str142, VK_OEM_FJ_JISHO},
#line 72 "win32_vk.list"
- {gperf_offsetof(stringpool, 143), VK_F3},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str143, VK_F3},
#line 101 "win32_vk.list"
- {gperf_offsetof(stringpool, 144), VK_OEM_FJ_ROYA},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str144, VK_OEM_FJ_ROYA},
#line 100 "win32_vk.list"
- {gperf_offsetof(stringpool, 145), VK_OEM_FJ_LOYA},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str145, VK_OEM_FJ_LOYA},
{-1},
#line 42 "win32_vk.list"
- {gperf_offsetof(stringpool, 147), VK_DOWN},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str147, VK_DOWN},
{-1},
#line 153 "win32_vk.list"
- {gperf_offsetof(stringpool, 149), VK_OEM_FINISH},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str149, VK_OEM_FINISH},
{-1},
#line 74 "win32_vk.list"
- {gperf_offsetof(stringpool, 151), VK_F5},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str151, VK_F5},
{-1},
#line 136 "win32_vk.list"
- {gperf_offsetof(stringpool, 153), VK_OEM_7},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str153, VK_OEM_7},
#line 73 "win32_vk.list"
- {gperf_offsetof(stringpool, 154), VK_F4},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str154, VK_F4},
#line 86 "win32_vk.list"
- {gperf_offsetof(stringpool, 155), VK_F17},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str155, VK_F17},
#line 55 "win32_vk.list"
- {gperf_offsetof(stringpool, 156), VK_NUMPAD1},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str156, VK_NUMPAD1},
#line 141 "win32_vk.list"
- {gperf_offsetof(stringpool, 157), VK_ICO_00},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str157, VK_ICO_00},
{-1},
#line 62 "win32_vk.list"
- {gperf_offsetof(stringpool, 159), VK_NUMPAD8},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str159, VK_NUMPAD8},
{-1}, {-1},
#line 56 "win32_vk.list"
- {gperf_offsetof(stringpool, 162), VK_NUMPAD2},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str162, VK_NUMPAD2},
{-1},
#line 124 "win32_vk.list"
- {gperf_offsetof(stringpool, 164), VK_LAUNCH_APP1},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str164, VK_LAUNCH_APP1},
#line 109 "win32_vk.list"
- {gperf_offsetof(stringpool, 165), VK_BROWSER_FORWARD},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str165, VK_BROWSER_FORWARD},
{-1},
#line 76 "win32_vk.list"
- {gperf_offsetof(stringpool, 167), VK_F7},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str167, VK_F7},
{-1}, {-1},
#line 125 "win32_vk.list"
- {gperf_offsetof(stringpool, 170), VK_LAUNCH_APP2},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str170, VK_LAUNCH_APP2},
#line 64 "win32_vk.list"
- {gperf_offsetof(stringpool, 171), VK_MULTIPLY},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str171, VK_MULTIPLY},
{-1}, {-1},
#line 45 "win32_vk.list"
- {gperf_offsetof(stringpool, 174), VK_EXECUTE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str174, VK_EXECUTE},
{-1},
#line 113 "win32_vk.list"
- {gperf_offsetof(stringpool, 176), VK_BROWSER_FAVORITES},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str176, VK_BROWSER_FAVORITES},
#line 60 "win32_vk.list"
- {gperf_offsetof(stringpool, 177), VK_NUMPAD6},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str177, VK_NUMPAD6},
{-1},
#line 85 "win32_vk.list"
- {gperf_offsetof(stringpool, 179), VK_F16},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str179, VK_F16},
{-1}, {-1},
#line 79 "win32_vk.list"
- {gperf_offsetof(stringpool, 182), VK_F10},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str182, VK_F10},
{-1}, {-1},
#line 116 "win32_vk.list"
- {gperf_offsetof(stringpool, 185), VK_VOLUME_DOWN},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str185, VK_VOLUME_DOWN},
{-1}, {-1},
#line 89 "win32_vk.list"
- {gperf_offsetof(stringpool, 188), VK_F20},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str188, VK_F20},
#line 119 "win32_vk.list"
- {gperf_offsetof(stringpool, 189), VK_MEDIA_PREV_TRACK},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str189, VK_MEDIA_PREV_TRACK},
{-1},
#line 33 "win32_vk.list"
- {gperf_offsetof(stringpool, 191), VK_MODECHANGE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str191, VK_MODECHANGE},
{-1}, {-1}, {-1}, {-1}, {-1},
#line 83 "win32_vk.list"
- {gperf_offsetof(stringpool, 197), VK_F14},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str197, VK_F14},
#line 57 "win32_vk.list"
- {gperf_offsetof(stringpool, 198), VK_NUMPAD3},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str198, VK_NUMPAD3},
#line 11 "win32_vk.list"
- {gperf_offsetof(stringpool, 199), VK_XBUTTON1},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str199, VK_XBUTTON1},
{-1}, {-1}, {-1},
#line 93 "win32_vk.list"
- {gperf_offsetof(stringpool, 203), VK_F24},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str203, VK_F24},
{-1},
#line 12 "win32_vk.list"
- {gperf_offsetof(stringpool, 205), VK_XBUTTON2},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str205, VK_XBUTTON2},
#line 59 "win32_vk.list"
- {gperf_offsetof(stringpool, 206), VK_NUMPAD5},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str206, VK_NUMPAD5},
{-1}, {-1},
#line 58 "win32_vk.list"
- {gperf_offsetof(stringpool, 209), VK_NUMPAD4},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str209, VK_NUMPAD4},
{-1}, {-1}, {-1}, {-1}, {-1},
#line 121 "win32_vk.list"
- {gperf_offsetof(stringpool, 215), VK_MEDIA_PLAY_PAUSE},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str215, VK_MEDIA_PLAY_PAUSE},
{-1},
#line 123 "win32_vk.list"
- {gperf_offsetof(stringpool, 217), VK_LAUNCH_MEDIA_SELECT},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str217, VK_LAUNCH_MEDIA_SELECT},
#line 80 "win32_vk.list"
- {gperf_offsetof(stringpool, 218), VK_F11},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str218, VK_F11},
{-1},
#line 139 "win32_vk.list"
- {gperf_offsetof(stringpool, 220), VK_OEM_102},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str220, VK_OEM_102},
#line 118 "win32_vk.list"
- {gperf_offsetof(stringpool, 221), VK_MEDIA_NEXT_TRACK},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str221, VK_MEDIA_NEXT_TRACK},
#line 61 "win32_vk.list"
- {gperf_offsetof(stringpool, 222), VK_NUMPAD7},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str222, VK_NUMPAD7},
{-1},
#line 90 "win32_vk.list"
- {gperf_offsetof(stringpool, 224), VK_F21},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str224, VK_F21},
{-1},
#line 82 "win32_vk.list"
- {gperf_offsetof(stringpool, 226), VK_F13},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str226, VK_F13},
{-1}, {-1},
#line 81 "win32_vk.list"
- {gperf_offsetof(stringpool, 229), VK_F12},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str229, VK_F12},
{-1}, {-1},
#line 92 "win32_vk.list"
- {gperf_offsetof(stringpool, 232), VK_F23},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str232, VK_F23},
{-1}, {-1},
#line 91 "win32_vk.list"
- {gperf_offsetof(stringpool, 235), VK_F22},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str235, VK_F22},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1},
#line 84 "win32_vk.list"
- {gperf_offsetof(stringpool, 242), VK_F15},
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str242, VK_F15},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1},
#line 69 "win32_vk.list"
- {gperf_offsetof(stringpool, 256), VK_DIVIDE}
+ {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str256, VK_DIVIDE}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/ext/io/console/win32_vk.list b/ext/io/console/win32_vk.list
index 7909a4d1f0..5df3d6da57 100644
--- a/ext/io/console/win32_vk.list
+++ b/ext/io/console/win32_vk.list
@@ -1,6 +1,6 @@
%{
struct vktable {short ofs; unsigned short vk;};
-static const struct vktable *console_win32_vk(/*!ANSI{*/const char *, unsigned int/*}!ANSI*/);
+static const struct vktable *console_win32_vk(const char *, size_t);
%}
struct vktable
%%
diff --git a/ext/io/nonblock/depend b/ext/io/nonblock/depend
index 48384fca62..7f2db65732 100644
--- a/ext/io/nonblock/depend
+++ b/ext/io/nonblock/depend
@@ -53,7 +53,6 @@ nonblock.o: $(hdrdir)/ruby/internal/attr/noexcept.h
nonblock.o: $(hdrdir)/ruby/internal/attr/noinline.h
nonblock.o: $(hdrdir)/ruby/internal/attr/nonnull.h
nonblock.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-nonblock.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
nonblock.o: $(hdrdir)/ruby/internal/attr/pure.h
nonblock.o: $(hdrdir)/ruby/internal/attr/restrict.h
nonblock.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ nonblock.o: $(hdrdir)/ruby/internal/intern/enumerator.h
nonblock.o: $(hdrdir)/ruby/internal/intern/error.h
nonblock.o: $(hdrdir)/ruby/internal/intern/eval.h
nonblock.o: $(hdrdir)/ruby/internal/intern/file.h
+nonblock.o: $(hdrdir)/ruby/internal/intern/gc.h
nonblock.o: $(hdrdir)/ruby/internal/intern/hash.h
nonblock.o: $(hdrdir)/ruby/internal/intern/io.h
nonblock.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ nonblock.o: $(hdrdir)/ruby/internal/memory.h
nonblock.o: $(hdrdir)/ruby/internal/method.h
nonblock.o: $(hdrdir)/ruby/internal/module.h
nonblock.o: $(hdrdir)/ruby/internal/newobj.h
+nonblock.o: $(hdrdir)/ruby/internal/rgengc.h
nonblock.o: $(hdrdir)/ruby/internal/scan_args.h
nonblock.o: $(hdrdir)/ruby/internal/special_consts.h
nonblock.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/io/nonblock/extconf.rb b/ext/io/nonblock/extconf.rb
index a1e6075c9b..d813a01e7c 100644
--- a/ext/io/nonblock/extconf.rb
+++ b/ext/io/nonblock/extconf.rb
@@ -2,13 +2,6 @@
require 'mkmf'
target = "io/nonblock"
-unless RUBY_ENGINE == 'ruby'
- File.write("Makefile", dummy_makefile($srcdir).join(""))
- return
-end
-
-have_func("rb_io_descriptor")
-
hdr = %w"fcntl.h"
if have_macro("O_NONBLOCK", hdr) and
(have_macro("F_GETFL", hdr) or have_macro("F_SETFL", hdr))
diff --git a/ext/io/nonblock/nonblock.c b/ext/io/nonblock/nonblock.c
index d90538f735..b8a40ff38e 100644
--- a/ext/io/nonblock/nonblock.c
+++ b/ext/io/nonblock/nonblock.c
@@ -17,17 +17,6 @@
#endif
#include <fcntl.h>
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
#ifdef F_GETFL
static int
get_fcntl_flags(int fd)
@@ -50,8 +39,10 @@ get_fcntl_flags(int fd)
static VALUE
rb_io_nonblock_p(VALUE io)
{
- if (get_fcntl_flags(rb_io_descriptor(io)) & O_NONBLOCK)
- return Qtrue;
+ rb_io_t *fptr;
+ GetOpenFile(io, fptr);
+ if (get_fcntl_flags(fptr->fd) & O_NONBLOCK)
+ return Qtrue;
return Qfalse;
}
#else
@@ -66,8 +57,6 @@ set_fcntl_flags(int fd, int f)
rb_sys_fail(0);
}
-#ifndef RUBY_IO_NONBLOCK_METHODS
-
static int
io_nonblock_set(int fd, int f, int nb)
{
@@ -133,23 +122,17 @@ io_nonblock_set(int fd, int f, int nb)
*
*/
static VALUE
-rb_io_nonblock_set(VALUE self, VALUE value)
+rb_io_nonblock_set(VALUE io, VALUE nb)
{
- if (RTEST(value)) {
- rb_io_t *fptr;
- GetOpenFile(self, fptr);
- rb_io_set_nonblock(fptr);
- }
- else {
- int descriptor = rb_io_descriptor(self);
- io_nonblock_set(descriptor, get_fcntl_flags(descriptor), RTEST(value));
- }
-
- return self;
+ rb_io_t *fptr;
+ GetOpenFile(io, fptr);
+ if (RTEST(nb))
+ rb_io_set_nonblock(fptr);
+ else
+ io_nonblock_set(fptr->fd, get_fcntl_flags(fptr->fd), RTEST(nb));
+ return io;
}
-#endif /* RUBY_IO_NONBLOCK_METHODS */
-
static VALUE
io_nonblock_restore(VALUE arg)
{
@@ -169,25 +152,24 @@ io_nonblock_restore(VALUE arg)
* The original mode is restored after the block is executed.
*/
static VALUE
-rb_io_nonblock_block(int argc, VALUE *argv, VALUE self)
+rb_io_nonblock_block(int argc, VALUE *argv, VALUE io)
{
int nb = 1;
+ rb_io_t *fptr;
+ int f, restore[2];
- int descriptor = rb_io_descriptor(self);
-
+ GetOpenFile(io, fptr);
if (argc > 0) {
- VALUE v;
- rb_scan_args(argc, argv, "01", &v);
- nb = RTEST(v);
+ VALUE v;
+ rb_scan_args(argc, argv, "01", &v);
+ nb = RTEST(v);
}
-
- int current_flags = get_fcntl_flags(descriptor);
- int restore[2] = {descriptor, current_flags};
-
- if (!io_nonblock_set(descriptor, current_flags, nb))
- return rb_yield(self);
-
- return rb_ensure(rb_yield, self, io_nonblock_restore, (VALUE)restore);
+ f = get_fcntl_flags(fptr->fd);
+ restore[0] = fptr->fd;
+ restore[1] = f;
+ if (!io_nonblock_set(fptr->fd, f, nb))
+ return rb_yield(io);
+ return rb_ensure(rb_yield, io, io_nonblock_restore, (VALUE)restore);
}
#else
#define rb_io_nonblock_set rb_f_notimplement
@@ -197,10 +179,7 @@ rb_io_nonblock_block(int argc, VALUE *argv, VALUE self)
void
Init_nonblock(void)
{
-#ifndef RUBY_IO_NONBLOCK_METHODS
rb_define_method(rb_cIO, "nonblock?", rb_io_nonblock_p, 0);
rb_define_method(rb_cIO, "nonblock=", rb_io_nonblock_set, 1);
-#endif
-
rb_define_method(rb_cIO, "nonblock", rb_io_nonblock_block, -1);
}
diff --git a/ext/io/wait/depend b/ext/io/wait/depend
index 83cf8f94c8..51e1af8280 100644
--- a/ext/io/wait/depend
+++ b/ext/io/wait/depend
@@ -54,7 +54,6 @@ wait.o: $(hdrdir)/ruby/internal/attr/noexcept.h
wait.o: $(hdrdir)/ruby/internal/attr/noinline.h
wait.o: $(hdrdir)/ruby/internal/attr/nonnull.h
wait.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-wait.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
wait.o: $(hdrdir)/ruby/internal/attr/pure.h
wait.o: $(hdrdir)/ruby/internal/attr/restrict.h
wait.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -123,6 +122,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/enumerator.h
wait.o: $(hdrdir)/ruby/internal/intern/error.h
wait.o: $(hdrdir)/ruby/internal/intern/eval.h
wait.o: $(hdrdir)/ruby/internal/intern/file.h
+wait.o: $(hdrdir)/ruby/internal/intern/gc.h
wait.o: $(hdrdir)/ruby/internal/intern/hash.h
wait.o: $(hdrdir)/ruby/internal/intern/io.h
wait.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -153,6 +153,7 @@ wait.o: $(hdrdir)/ruby/internal/memory.h
wait.o: $(hdrdir)/ruby/internal/method.h
wait.o: $(hdrdir)/ruby/internal/module.h
wait.o: $(hdrdir)/ruby/internal/newobj.h
+wait.o: $(hdrdir)/ruby/internal/rgengc.h
wait.o: $(hdrdir)/ruby/internal/scan_args.h
wait.o: $(hdrdir)/ruby/internal/special_consts.h
wait.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb
index e63c046187..c6230b7783 100644
--- a/ext/io/wait/extconf.rb
+++ b/ext/io/wait/extconf.rb
@@ -5,8 +5,7 @@ if RUBY_VERSION < "2.6"
File.write("Makefile", dummy_makefile($srcdir).join(""))
else
target = "io/wait"
- have_func("rb_io_wait")
- have_func("rb_io_descriptor")
+ have_func("rb_io_wait", "ruby/io.h")
unless macro_defined?("DOSISH", "#include <ruby.h>")
have_header(ioctl_h = "sys/ioctl.h") or ioctl_h = nil
fionread = %w[sys/ioctl.h sys/filio.h sys/socket.h].find do |h|
diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c
index 8835670e59..d74afb580b 100644
--- a/ext/io/wait/wait.c
+++ b/ext/io/wait/wait.c
@@ -87,15 +87,8 @@ io_nread(VALUE io)
rb_io_check_readable(fptr);
len = rb_io_read_pending(fptr);
if (len > 0) return INT2FIX(len);
-
-#ifdef HAVE_RB_IO_DESCRIPTOR
- int fd = rb_io_descriptor(io);
-#else
- int fd = fptr->fd;
-#endif
-
- if (!FIONREAD_POSSIBLE_P(fd)) return INT2FIX(0);
- if (ioctl(fd, FIONREAD, &n)) return INT2FIX(0);
+ if (!FIONREAD_POSSIBLE_P(fptr->fd)) return INT2FIX(0);
+ if (ioctl(fptr->fd, FIONREAD, &n)) return INT2FIX(0);
if (n > 0) return ioctl_arg2num(n);
return INT2FIX(0);
}
diff --git a/ext/json/generator/depend b/ext/json/generator/depend
index 42752d1a35..28ef06b36d 100644
--- a/ext/json/generator/depend
+++ b/ext/json/generator/depend
@@ -56,7 +56,6 @@ generator.o: $(hdrdir)/ruby/internal/attr/noexcept.h
generator.o: $(hdrdir)/ruby/internal/attr/noinline.h
generator.o: $(hdrdir)/ruby/internal/attr/nonnull.h
generator.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-generator.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
generator.o: $(hdrdir)/ruby/internal/attr/pure.h
generator.o: $(hdrdir)/ruby/internal/attr/restrict.h
generator.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -126,6 +125,7 @@ generator.o: $(hdrdir)/ruby/internal/intern/enumerator.h
generator.o: $(hdrdir)/ruby/internal/intern/error.h
generator.o: $(hdrdir)/ruby/internal/intern/eval.h
generator.o: $(hdrdir)/ruby/internal/intern/file.h
+generator.o: $(hdrdir)/ruby/internal/intern/gc.h
generator.o: $(hdrdir)/ruby/internal/intern/hash.h
generator.o: $(hdrdir)/ruby/internal/intern/io.h
generator.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -156,6 +156,7 @@ generator.o: $(hdrdir)/ruby/internal/memory.h
generator.o: $(hdrdir)/ruby/internal/method.h
generator.o: $(hdrdir)/ruby/internal/module.h
generator.o: $(hdrdir)/ruby/internal/newobj.h
+generator.o: $(hdrdir)/ruby/internal/rgengc.h
generator.o: $(hdrdir)/ruby/internal/scan_args.h
generator.o: $(hdrdir)/ruby/internal/special_consts.h
generator.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index 8f7c57e042..98d0ea46c3 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -478,7 +478,6 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
*/
static VALUE mString_included_s(VALUE self, VALUE modul) {
VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
- rb_call_super(1, &modul);
return result;
}
diff --git a/ext/json/json.gemspec b/ext/json/json.gemspec
index f4b2ae791d..948e92c501 100644
--- a/ext/json/json.gemspec
+++ b/ext/json/json.gemspec
@@ -53,12 +53,12 @@ Gem::Specification.new do |s|
"lib/json/pure/parser.rb",
"lib/json/version.rb",
]
- s.homepage = "https://flori.github.io/json"
+ s.homepage = "http://flori.github.com/json"
s.metadata = {
'bug_tracker_uri' => 'https://github.com/flori/json/issues',
'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md',
- 'documentation_uri' => 'https://flori.github.io/json/doc/index.html',
- 'homepage_uri' => s.homepage,
+ 'documentation_uri' => 'http://flori.github.io/json/doc/index.html',
+ 'homepage_uri' => 'http://flori.github.io/json/',
'source_code_uri' => 'https://github.com/flori/json',
'wiki_uri' => 'https://github.com/flori/json/wiki'
}
diff --git a/ext/json/lib/json/add/bigdecimal.rb b/ext/json/lib/json/add/bigdecimal.rb
index 25383f28ed..c8b4f567cb 100644
--- a/ext/json/lib/json/add/bigdecimal.rb
+++ b/ext/json/lib/json/add/bigdecimal.rb
@@ -2,10 +2,7 @@
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
require 'json'
end
-begin
- require 'bigdecimal'
-rescue LoadError
-end
+defined?(::BigDecimal) or require 'bigdecimal'
class BigDecimal
# Import a JSON Marshalled object.
@@ -29,4 +26,4 @@ class BigDecimal
def to_json(*args)
as_json.to_json(*args)
end
-end if defined?(::BigDecimal)
+end
diff --git a/ext/json/lib/json/add/range.rb b/ext/json/lib/json/add/range.rb
index d1210c5625..93529fb1c4 100644
--- a/ext/json/lib/json/add/range.rb
+++ b/ext/json/lib/json/add/range.rb
@@ -5,25 +5,14 @@ end
class Range
- # Returns a new \Range object constructed from <tt>object['a']</tt>,
- # which must be an array of values suitable for a call to Range.new:
- #
- # require 'json/add/range'
- # Range.json_create({"a"=>[1, 4]}) # => 1..4
- # Range.json_create({"a"=>[1, 4, true]}) # => 1...4
- # Range.json_create({"a" => ['a', 'd']}) # => "a".."d"
- #
+ # Deserializes JSON string by constructing new Range object with arguments
+ # <tt>a</tt> serialized by <tt>to_json</tt>.
def self.json_create(object)
new(*object['a'])
end
- # Returns a 2-element hash representing +self+:
- #
- # require 'json/add/range'
- # (1..4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, false]}
- # (1...4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, true]}
- # ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]}
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -31,13 +20,9 @@ class Range
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/range'
- # (1..4).to_json # => "{\"json_class\":\"Range\",\"a\":[1,4,false]}"
- # (1...4).to_json # => "{\"json_class\":\"Range\",\"a\":[1,4,true]}"
- # ('a'..'d').to_json # => "{\"json_class\":\"Range\",\"a\":[\"a\",\"d\",false]}"
- #
+ # Stores class name (Range) with JSON array of arguments <tt>a</tt> which
+ # include <tt>first</tt> (integer), <tt>last</tt> (integer), and
+ # <tt>exclude_end?</tt> (boolean) as JSON string.
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb
index 173af04be0..ea46896fcc 100644
--- a/ext/json/lib/json/common.rb
+++ b/ext/json/lib/json/common.rb
@@ -295,9 +295,19 @@ module JSON
#
def generate(obj, opts = nil)
if State === opts
- state = opts
+ state, opts = opts, nil
else
- state = State.new(opts)
+ state = State.new
+ end
+ if opts
+ if opts.respond_to? :to_hash
+ opts = opts.to_hash
+ elsif opts.respond_to? :to_h
+ opts = opts.to_h
+ else
+ raise TypeError, "can't convert #{opts.class} into Hash"
+ end
+ state = state.configure(opts)
end
state.generate(obj)
end
@@ -324,9 +334,19 @@ module JSON
# JSON.fast_generate(a)
def fast_generate(obj, opts = nil)
if State === opts
- state = opts
+ state, opts = opts, nil
else
- state = JSON.create_fast_state.configure(opts)
+ state = JSON.create_fast_state
+ end
+ if opts
+ if opts.respond_to? :to_hash
+ opts = opts.to_hash
+ elsif opts.respond_to? :to_h
+ opts = opts.to_h
+ else
+ raise TypeError, "can't convert #{opts.class} into Hash"
+ end
+ state.configure(opts)
end
state.generate(obj)
end
diff --git a/ext/json/parser/depend b/ext/json/parser/depend
index cb6e547d29..a8e066ce15 100644
--- a/ext/json/parser/depend
+++ b/ext/json/parser/depend
@@ -56,7 +56,6 @@ parser.o: $(hdrdir)/ruby/internal/attr/noexcept.h
parser.o: $(hdrdir)/ruby/internal/attr/noinline.h
parser.o: $(hdrdir)/ruby/internal/attr/nonnull.h
parser.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-parser.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
parser.o: $(hdrdir)/ruby/internal/attr/pure.h
parser.o: $(hdrdir)/ruby/internal/attr/restrict.h
parser.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -125,6 +124,7 @@ parser.o: $(hdrdir)/ruby/internal/intern/enumerator.h
parser.o: $(hdrdir)/ruby/internal/intern/error.h
parser.o: $(hdrdir)/ruby/internal/intern/eval.h
parser.o: $(hdrdir)/ruby/internal/intern/file.h
+parser.o: $(hdrdir)/ruby/internal/intern/gc.h
parser.o: $(hdrdir)/ruby/internal/intern/hash.h
parser.o: $(hdrdir)/ruby/internal/intern/io.h
parser.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -155,6 +155,7 @@ parser.o: $(hdrdir)/ruby/internal/memory.h
parser.o: $(hdrdir)/ruby/internal/method.h
parser.o: $(hdrdir)/ruby/internal/module.h
parser.o: $(hdrdir)/ruby/internal/newobj.h
+parser.o: $(hdrdir)/ruby/internal/rgengc.h
parser.o: $(hdrdir)/ruby/internal/scan_args.h
parser.o: $(hdrdir)/ruby/internal/special_consts.h
parser.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb
index feb586e1b4..4723a02aee 100644
--- a/ext/json/parser/extconf.rb
+++ b/ext/json/parser/extconf.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: false
require 'mkmf'
-have_func("rb_enc_raise", "ruby.h")
-have_func("rb_enc_interned_str", "ruby.h")
+have_func("rb_enc_raise", "ruby/encoding.h")
+have_func("rb_enc_interned_str", "ruby/encoding.h")
# checking if String#-@ (str_uminus) dedupes... '
begin
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index 876bec5769..9bd7f1971e 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -9,14 +9,14 @@
static void
enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
{
- va_list args;
- VALUE mesg;
+ va_list args;
+ VALUE mesg;
- va_start(args, fmt);
- mesg = rb_enc_vsprintf(enc, fmt, args);
- va_end(args);
+ va_start(args, fmt);
+ mesg = rb_enc_vsprintf(enc, fmt, args);
+ va_end(args);
- rb_exc_raise(rb_exc_new3(exc, mesg));
+ rb_exc_raise(rb_exc_new3(exc, mesg));
}
# define rb_enc_raise enc_raise
# endif
@@ -28,2184 +28,3320 @@ enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
/* unicode */
static const signed char digit_values[256] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
- -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
+ -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1
};
static UTF32 unescape_unicode(const unsigned char *p)
{
- signed char b;
- UTF32 result = 0;
- b = digit_values[p[0]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[1]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[2]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[3]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- return result;
+ signed char b;
+ UTF32 result = 0;
+ b = digit_values[p[0]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ b = digit_values[p[1]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ b = digit_values[p[2]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ b = digit_values[p[3]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ return result;
}
static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
{
- int len = 1;
- if (ch <= 0x7F) {
- buf[0] = (char) ch;
- } else if (ch <= 0x07FF) {
- buf[0] = (char) ((ch >> 6) | 0xC0);
- buf[1] = (char) ((ch & 0x3F) | 0x80);
- len++;
- } else if (ch <= 0xFFFF) {
- buf[0] = (char) ((ch >> 12) | 0xE0);
- buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
- buf[2] = (char) ((ch & 0x3F) | 0x80);
- len += 2;
- } else if (ch <= 0x1fffff) {
- buf[0] =(char) ((ch >> 18) | 0xF0);
- buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
- buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
- buf[3] =(char) ((ch & 0x3F) | 0x80);
- len += 3;
- } else {
- buf[0] = '?';
- }
- return len;
+ int len = 1;
+ if (ch <= 0x7F) {
+ buf[0] = (char) ch;
+ } else if (ch <= 0x07FF) {
+ buf[0] = (char) ((ch >> 6) | 0xC0);
+ buf[1] = (char) ((ch & 0x3F) | 0x80);
+ len++;
+ } else if (ch <= 0xFFFF) {
+ buf[0] = (char) ((ch >> 12) | 0xE0);
+ buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
+ buf[2] = (char) ((ch & 0x3F) | 0x80);
+ len += 2;
+ } else if (ch <= 0x1fffff) {
+ buf[0] =(char) ((ch >> 18) | 0xF0);
+ buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
+ buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
+ buf[3] =(char) ((ch & 0x3F) | 0x80);
+ len += 3;
+ } else {
+ buf[0] = '?';
+ }
+ return len;
}
static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
static VALUE CNaN, CInfinity, CMinusInfinity;
static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
- i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
- i_object_class, i_array_class, i_decimal_class, i_key_p,
- i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
- i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
+i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
+i_object_class, i_array_class, i_decimal_class, i_key_p,
+i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
+i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
#line 125 "parser.rl"
-#line 107 "parser.c"
enum {JSON_object_start = 1};
enum {JSON_object_first_final = 27};
enum {JSON_object_error = 0};
enum {JSON_object_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_object_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_object_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_object_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_object_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 167 "parser.rl"
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
- int cs = EVIL;
- VALUE last_name = Qnil;
- VALUE object_class = json->object_class;
+ int cs = EVIL;
+ VALUE last_name = Qnil;
+ VALUE object_class = json->object_class;
- if (json->max_nesting && current_nesting > json->max_nesting) {
- rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
- }
+ if (json->max_nesting && current_nesting > json->max_nesting) {
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
+ }
- *result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
+ *result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
-#line 131 "parser.c"
{
- cs = JSON_object_start;
+ cs = (int)JSON_object_start;
}
-#line 182 "parser.rl"
+ #line 182 "parser.rl"
+
-#line 138 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- if ( (*p) == 123 )
- goto st2;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 10:
+ goto st_case_10;
+ case 11:
+ goto st_case_11;
+ case 12:
+ goto st_case_12;
+ case 13:
+ goto st_case_13;
+ case 14:
+ goto st_case_14;
+ case 15:
+ goto st_case_15;
+ case 16:
+ goto st_case_16;
+ case 17:
+ goto st_case_17;
+ case 18:
+ goto st_case_18;
+ case 27:
+ goto st_case_27;
+ case 19:
+ goto st_case_19;
+ case 20:
+ goto st_case_20;
+ case 21:
+ goto st_case_21;
+ case 22:
+ goto st_case_22;
+ case 23:
+ goto st_case_23;
+ case 24:
+ goto st_case_24;
+ case 25:
+ goto st_case_25;
+ case 26:
+ goto st_case_26;
+ }
+ goto st_out;
+ st_case_1:
+ if ( ( (*( p))) == 123 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 13: goto st2;
- case 32: goto st2;
- case 34: goto tr2;
- case 47: goto st23;
- case 125: goto tr4;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
- goto st2;
- goto st0;
-tr2:
-#line 149 "parser.rl"
- {
- char *np;
- json->parsing_name = 1;
- np = JSON_parse_string(json, p, pe, &last_name);
- json->parsing_name = 0;
- if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else {p = (( np))-1;}
- }
- goto st3;
-st3:
- if ( ++p == pe )
- goto _test_eof3;
-case 3:
-#line 179 "parser.c"
- switch( (*p) ) {
- case 13: goto st3;
- case 32: goto st3;
- case 47: goto st4;
- case 58: goto st8;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st2;
+ }
+ case 32: {
+ goto st2;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st23;
+ }
+ case 125: {
+ goto ctr4;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ ctr2:
+ {
+ #line 149 "parser.rl"
+
+ char *np;
+ json->parsing_name = 1;
+ np = JSON_parse_string(json, p, pe, &last_name);
+ json->parsing_name = 0;
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 3; goto _out;} } else {p = (( np))-1;}
+
+ }
+
goto st3;
- goto st0;
-st4:
- if ( ++p == pe )
+ st3:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof3;
+ st_case_3:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st3;
+ }
+ case 32: {
+ goto st3;
+ }
+ case 47: {
+ goto st4;
+ }
+ case 58: {
+ goto st8;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st3;
+ }
+ {
+ goto st0;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 42: goto st5;
- case 47: goto st7;
- }
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st5;
+ }
+ case 47: {
+ goto st7;
+ }
+ }
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) == 42 )
- goto st6;
- goto st5;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ if ( ( (*( p))) == 42 ) {
+ goto st6;
+ }
+ {
+ goto st5;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- switch( (*p) ) {
- case 42: goto st6;
- case 47: goto st3;
- }
- goto st5;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st6;
+ }
+ case 47: {
+ goto st3;
+ }
+ }
+ {
+ goto st5;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) == 10 )
- goto st3;
- goto st7;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ if ( ( (*( p))) == 10 ) {
+ goto st3;
+ }
+ {
+ goto st7;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 13: goto st8;
- case 32: goto st8;
- case 34: goto tr11;
- case 45: goto tr11;
- case 47: goto st19;
- case 73: goto tr11;
- case 78: goto tr11;
- case 91: goto tr11;
- case 102: goto tr11;
- case 110: goto tr11;
- case 116: goto tr11;
- case 123: goto tr11;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr11;
- } else if ( (*p) >= 9 )
- goto st8;
- goto st0;
-tr11:
-#line 133 "parser.rl"
- {
- VALUE v = Qnil;
- char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
- if (np == NULL) {
- p--; {p++; cs = 9; goto _out;}
- } else {
- if (NIL_P(json->object_class)) {
- OBJ_FREEZE(last_name);
- rb_hash_aset(*result, last_name, v);
- } else {
- rb_funcall(*result, i_aset, 2, last_name, v);
- }
- {p = (( np))-1;}
- }
- }
- goto st9;
-st9:
- if ( ++p == pe )
- goto _test_eof9;
-case 9:
-#line 267 "parser.c"
- switch( (*p) ) {
- case 13: goto st9;
- case 32: goto st9;
- case 44: goto st10;
- case 47: goto st15;
- case 125: goto tr4;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st8;
+ }
+ case 32: {
+ goto st8;
+ }
+ case 34: {
+ goto ctr11;
+ }
+ case 45: {
+ goto ctr11;
+ }
+ case 47: {
+ goto st19;
+ }
+ case 73: {
+ goto ctr11;
+ }
+ case 78: {
+ goto ctr11;
+ }
+ case 91: {
+ goto ctr11;
+ }
+ case 102: {
+ goto ctr11;
+ }
+ case 110: {
+ goto ctr11;
+ }
+ case 116: {
+ goto ctr11;
+ }
+ case 123: {
+ goto ctr11;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr11;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st8;
+ }
+ {
+ goto st0;
+ }
+ ctr11:
+ {
+ #line 133 "parser.rl"
+
+ VALUE v = Qnil;
+ char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
+ if (np == NULL) {
+ {p = p - 1; } {p+= 1; cs = 9; goto _out;}
+ } else {
+ if (NIL_P(json->object_class)) {
+ OBJ_FREEZE(last_name);
+ rb_hash_aset(*result, last_name, v);
+ } else {
+ rb_funcall(*result, i_aset, 2, last_name, v);
+ }
+ {p = (( np))-1;}
+
+ }
+ }
+
goto st9;
- goto st0;
-st10:
- if ( ++p == pe )
+ st9:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof9;
+ st_case_9:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st9;
+ }
+ case 32: {
+ goto st9;
+ }
+ case 44: {
+ goto st10;
+ }
+ case 47: {
+ goto st15;
+ }
+ case 125: {
+ goto ctr4;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st9;
+ }
+ {
+ goto st0;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
goto _test_eof10;
-case 10:
- switch( (*p) ) {
- case 13: goto st10;
- case 32: goto st10;
- case 34: goto tr2;
- case 47: goto st11;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
- goto st10;
- goto st0;
-st11:
- if ( ++p == pe )
+ st_case_10:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st10;
+ }
+ case 32: {
+ goto st10;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st11;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st10;
+ }
+ {
+ goto st0;
+ }
+ st11:
+ p+= 1;
+ if ( p == pe )
goto _test_eof11;
-case 11:
- switch( (*p) ) {
- case 42: goto st12;
- case 47: goto st14;
- }
- goto st0;
-st12:
- if ( ++p == pe )
+ st_case_11:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st12;
+ }
+ case 47: {
+ goto st14;
+ }
+ }
+ {
+ goto st0;
+ }
+ st12:
+ p+= 1;
+ if ( p == pe )
goto _test_eof12;
-case 12:
- if ( (*p) == 42 )
- goto st13;
- goto st12;
-st13:
- if ( ++p == pe )
+ st_case_12:
+ if ( ( (*( p))) == 42 ) {
+ goto st13;
+ }
+ {
+ goto st12;
+ }
+ st13:
+ p+= 1;
+ if ( p == pe )
goto _test_eof13;
-case 13:
- switch( (*p) ) {
- case 42: goto st13;
- case 47: goto st10;
- }
- goto st12;
-st14:
- if ( ++p == pe )
+ st_case_13:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st13;
+ }
+ case 47: {
+ goto st10;
+ }
+ }
+ {
+ goto st12;
+ }
+ st14:
+ p+= 1;
+ if ( p == pe )
goto _test_eof14;
-case 14:
- if ( (*p) == 10 )
- goto st10;
- goto st14;
-st15:
- if ( ++p == pe )
+ st_case_14:
+ if ( ( (*( p))) == 10 ) {
+ goto st10;
+ }
+ {
+ goto st14;
+ }
+ st15:
+ p+= 1;
+ if ( p == pe )
goto _test_eof15;
-case 15:
- switch( (*p) ) {
- case 42: goto st16;
- case 47: goto st18;
- }
- goto st0;
-st16:
- if ( ++p == pe )
+ st_case_15:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st16;
+ }
+ case 47: {
+ goto st18;
+ }
+ }
+ {
+ goto st0;
+ }
+ st16:
+ p+= 1;
+ if ( p == pe )
goto _test_eof16;
-case 16:
- if ( (*p) == 42 )
- goto st17;
- goto st16;
-st17:
- if ( ++p == pe )
+ st_case_16:
+ if ( ( (*( p))) == 42 ) {
+ goto st17;
+ }
+ {
+ goto st16;
+ }
+ st17:
+ p+= 1;
+ if ( p == pe )
goto _test_eof17;
-case 17:
- switch( (*p) ) {
- case 42: goto st17;
- case 47: goto st9;
- }
- goto st16;
-st18:
- if ( ++p == pe )
+ st_case_17:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st17;
+ }
+ case 47: {
+ goto st9;
+ }
+ }
+ {
+ goto st16;
+ }
+ st18:
+ p+= 1;
+ if ( p == pe )
goto _test_eof18;
-case 18:
- if ( (*p) == 10 )
- goto st9;
- goto st18;
-tr4:
-#line 157 "parser.rl"
- { p--; {p++; cs = 27; goto _out;} }
- goto st27;
-st27:
- if ( ++p == pe )
+ st_case_18:
+ if ( ( (*( p))) == 10 ) {
+ goto st9;
+ }
+ {
+ goto st18;
+ }
+ ctr4:
+ {
+ #line 157 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 27; goto _out;} }
+
+ goto st27;
+ st27:
+ p+= 1;
+ if ( p == pe )
goto _test_eof27;
-case 27:
-#line 363 "parser.c"
- goto st0;
-st19:
- if ( ++p == pe )
+ st_case_27:
+ {
+ goto st0;
+ }
+ st19:
+ p+= 1;
+ if ( p == pe )
goto _test_eof19;
-case 19:
- switch( (*p) ) {
- case 42: goto st20;
- case 47: goto st22;
- }
- goto st0;
-st20:
- if ( ++p == pe )
+ st_case_19:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st20;
+ }
+ case 47: {
+ goto st22;
+ }
+ }
+ {
+ goto st0;
+ }
+ st20:
+ p+= 1;
+ if ( p == pe )
goto _test_eof20;
-case 20:
- if ( (*p) == 42 )
- goto st21;
- goto st20;
-st21:
- if ( ++p == pe )
+ st_case_20:
+ if ( ( (*( p))) == 42 ) {
+ goto st21;
+ }
+ {
+ goto st20;
+ }
+ st21:
+ p+= 1;
+ if ( p == pe )
goto _test_eof21;
-case 21:
- switch( (*p) ) {
- case 42: goto st21;
- case 47: goto st8;
- }
- goto st20;
-st22:
- if ( ++p == pe )
+ st_case_21:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st21;
+ }
+ case 47: {
+ goto st8;
+ }
+ }
+ {
+ goto st20;
+ }
+ st22:
+ p+= 1;
+ if ( p == pe )
goto _test_eof22;
-case 22:
- if ( (*p) == 10 )
- goto st8;
- goto st22;
-st23:
- if ( ++p == pe )
+ st_case_22:
+ if ( ( (*( p))) == 10 ) {
+ goto st8;
+ }
+ {
+ goto st22;
+ }
+ st23:
+ p+= 1;
+ if ( p == pe )
goto _test_eof23;
-case 23:
- switch( (*p) ) {
- case 42: goto st24;
- case 47: goto st26;
- }
- goto st0;
-st24:
- if ( ++p == pe )
+ st_case_23:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st24;
+ }
+ case 47: {
+ goto st26;
+ }
+ }
+ {
+ goto st0;
+ }
+ st24:
+ p+= 1;
+ if ( p == pe )
goto _test_eof24;
-case 24:
- if ( (*p) == 42 )
- goto st25;
- goto st24;
-st25:
- if ( ++p == pe )
+ st_case_24:
+ if ( ( (*( p))) == 42 ) {
+ goto st25;
+ }
+ {
+ goto st24;
+ }
+ st25:
+ p+= 1;
+ if ( p == pe )
goto _test_eof25;
-case 25:
- switch( (*p) ) {
- case 42: goto st25;
- case 47: goto st2;
- }
- goto st24;
-st26:
- if ( ++p == pe )
+ st_case_25:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st25;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ {
+ goto st24;
+ }
+ st26:
+ p+= 1;
+ if ( p == pe )
goto _test_eof26;
-case 26:
- if ( (*p) == 10 )
- goto st2;
- goto st26;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof11: cs = 11; goto _test_eof;
- _test_eof12: cs = 12; goto _test_eof;
- _test_eof13: cs = 13; goto _test_eof;
- _test_eof14: cs = 14; goto _test_eof;
- _test_eof15: cs = 15; goto _test_eof;
- _test_eof16: cs = 16; goto _test_eof;
- _test_eof17: cs = 17; goto _test_eof;
- _test_eof18: cs = 18; goto _test_eof;
- _test_eof27: cs = 27; goto _test_eof;
- _test_eof19: cs = 19; goto _test_eof;
- _test_eof20: cs = 20; goto _test_eof;
- _test_eof21: cs = 21; goto _test_eof;
- _test_eof22: cs = 22; goto _test_eof;
- _test_eof23: cs = 23; goto _test_eof;
- _test_eof24: cs = 24; goto _test_eof;
- _test_eof25: cs = 25; goto _test_eof;
- _test_eof26: cs = 26; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_26:
+ if ( ( (*( p))) == 10 ) {
+ goto st2;
+ }
+ {
+ goto st26;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 183 "parser.rl"
+
+
+ if (cs >= JSON_object_first_final) {
+ if (json->create_additions) {
+ VALUE klassname;
+ if (NIL_P(json->object_class)) {
+ klassname = rb_hash_aref(*result, json->create_id);
+ } else {
+ klassname = rb_funcall(*result, i_aref, 1, json->create_id);
+ }
+ if (!NIL_P(klassname)) {
+ VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
+ if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
+ *result = rb_funcall(klass, i_json_create, 1, *result);
+ }
+ }
+ }
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 183 "parser.rl"
-
- if (cs >= JSON_object_first_final) {
- if (json->create_additions) {
- VALUE klassname;
- if (NIL_P(json->object_class)) {
- klassname = rb_hash_aref(*result, json->create_id);
- } else {
- klassname = rb_funcall(*result, i_aref, 1, json->create_id);
- }
- if (!NIL_P(klassname)) {
- VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
- *result = rb_funcall(klass, i_json_create, 1, *result);
- }
- }
- }
- return p + 1;
- } else {
- return NULL;
- }
}
-#line 486 "parser.c"
enum {JSON_value_start = 1};
enum {JSON_value_first_final = 29};
enum {JSON_value_error = 0};
enum {JSON_value_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_value_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_value_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_value_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_value_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 283 "parser.rl"
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
- int cs = EVIL;
+ int cs = EVIL;
-#line 502 "parser.c"
{
- cs = JSON_value_start;
+ cs = (int)JSON_value_start;
}
-#line 290 "parser.rl"
+ #line 290 "parser.rl"
+
-#line 509 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-st1:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 29:
+ goto st_case_29;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 10:
+ goto st_case_10;
+ case 11:
+ goto st_case_11;
+ case 12:
+ goto st_case_12;
+ case 13:
+ goto st_case_13;
+ case 14:
+ goto st_case_14;
+ case 15:
+ goto st_case_15;
+ case 16:
+ goto st_case_16;
+ case 17:
+ goto st_case_17;
+ case 18:
+ goto st_case_18;
+ case 19:
+ goto st_case_19;
+ case 20:
+ goto st_case_20;
+ case 21:
+ goto st_case_21;
+ case 22:
+ goto st_case_22;
+ case 23:
+ goto st_case_23;
+ case 24:
+ goto st_case_24;
+ case 25:
+ goto st_case_25;
+ case 26:
+ goto st_case_26;
+ case 27:
+ goto st_case_27;
+ case 28:
+ goto st_case_28;
+ }
+ goto st_out;
+ st1:
+ p+= 1;
+ if ( p == pe )
goto _test_eof1;
-case 1:
- switch( (*p) ) {
- case 13: goto st1;
- case 32: goto st1;
- case 34: goto tr2;
- case 45: goto tr3;
- case 47: goto st6;
- case 73: goto st10;
- case 78: goto st17;
- case 91: goto tr7;
- case 102: goto st19;
- case 110: goto st23;
- case 116: goto st26;
- case 123: goto tr11;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr3;
- } else if ( (*p) >= 9 )
- goto st1;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-tr2:
-#line 235 "parser.rl"
- {
- char *np = JSON_parse_string(json, p, pe, result);
- if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
- }
- goto st29;
-tr3:
-#line 240 "parser.rl"
- {
- char *np;
- if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) {
- if (json->allow_nan) {
- *result = CMinusInfinity;
- {p = (( p + 10))-1;}
- p--; {p++; cs = 29; goto _out;}
- } else {
- rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
- }
- }
- np = JSON_parse_float(json, p, pe, result);
- if (np != NULL) {p = (( np))-1;}
- np = JSON_parse_integer(json, p, pe, result);
- if (np != NULL) {p = (( np))-1;}
- p--; {p++; cs = 29; goto _out;}
- }
- goto st29;
-tr7:
-#line 258 "parser.rl"
- {
- char *np;
- np = JSON_parse_array(json, p, pe, result, current_nesting + 1);
- if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
- }
- goto st29;
-tr11:
-#line 264 "parser.rl"
- {
- char *np;
- np = JSON_parse_object(json, p, pe, result, current_nesting + 1);
- if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
- }
- goto st29;
-tr25:
-#line 228 "parser.rl"
- {
- if (json->allow_nan) {
- *result = CInfinity;
- } else {
- rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8);
- }
- }
- goto st29;
-tr27:
-#line 221 "parser.rl"
- {
- if (json->allow_nan) {
- *result = CNaN;
- } else {
- rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2);
- }
- }
- goto st29;
-tr31:
-#line 215 "parser.rl"
- {
- *result = Qfalse;
- }
- goto st29;
-tr34:
-#line 212 "parser.rl"
- {
- *result = Qnil;
- }
- goto st29;
-tr37:
-#line 218 "parser.rl"
- {
- *result = Qtrue;
- }
- goto st29;
-st29:
- if ( ++p == pe )
- goto _test_eof29;
-case 29:
-#line 270 "parser.rl"
- { p--; {p++; cs = 29; goto _out;} }
-#line 629 "parser.c"
- switch( (*p) ) {
- case 13: goto st29;
- case 32: goto st29;
- case 47: goto st2;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st1;
+ }
+ case 32: {
+ goto st1;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr3;
+ }
+ case 47: {
+ goto st6;
+ }
+ case 73: {
+ goto st10;
+ }
+ case 78: {
+ goto st17;
+ }
+ case 91: {
+ goto ctr7;
+ }
+ case 102: {
+ goto st19;
+ }
+ case 110: {
+ goto st23;
+ }
+ case 116: {
+ goto st26;
+ }
+ case 123: {
+ goto ctr11;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr3;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st1;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ ctr2:
+ {
+ #line 235 "parser.rl"
+
+ char *np = JSON_parse_string(json, p, pe, result);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else {p = (( np))-1;}
+
+ }
+
+ goto st29;
+ ctr3:
+ {
+ #line 240 "parser.rl"
+
+ char *np;
+ if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) {
+ if (json->allow_nan) {
+ *result = CMinusInfinity;
+ {p = (( p + 10))-1;}
+
+ {p = p - 1; } {p+= 1; cs = 29; goto _out;}
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
+ }
+ }
+ np = JSON_parse_float(json, p, pe, result);
+ if (np != NULL) {p = (( np))-1;}
+
+ np = JSON_parse_integer(json, p, pe, result);
+ if (np != NULL) {p = (( np))-1;}
+
+ {p = p - 1; } {p+= 1; cs = 29; goto _out;}
+ }
+
+ goto st29;
+ ctr7:
+ {
+ #line 258 "parser.rl"
+
+ char *np;
+ np = JSON_parse_array(json, p, pe, result, current_nesting + 1);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else {p = (( np))-1;}
+
+ }
+
+ goto st29;
+ ctr11:
+ {
+ #line 264 "parser.rl"
+
+ char *np;
+ np = JSON_parse_object(json, p, pe, result, current_nesting + 1);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else {p = (( np))-1;}
+
+ }
+
+ goto st29;
+ ctr25:
+ {
+ #line 228 "parser.rl"
+
+ if (json->allow_nan) {
+ *result = CInfinity;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8);
+ }
+ }
+
+ goto st29;
+ ctr27:
+ {
+ #line 221 "parser.rl"
+
+ if (json->allow_nan) {
+ *result = CNaN;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2);
+ }
+ }
+
+ goto st29;
+ ctr31:
+ {
+ #line 215 "parser.rl"
+
+ *result = Qfalse;
+ }
+
+ goto st29;
+ ctr34:
+ {
+ #line 212 "parser.rl"
+
+ *result = Qnil;
+ }
+
+ goto st29;
+ ctr37:
+ {
+ #line 218 "parser.rl"
+
+ *result = Qtrue;
+ }
+
goto st29;
- goto st0;
-st2:
- if ( ++p == pe )
+ st29:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof29;
+ st_case_29:
+ {
+ #line 270 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 29; goto _out;} }
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st29;
+ }
+ case 32: {
+ goto st29;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st29;
+ }
+ {
+ goto st0;
+ }
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 42: goto st3;
- case 47: goto st5;
- }
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st3;
+ }
+ case 47: {
+ goto st5;
+ }
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( (*p) == 42 )
- goto st4;
- goto st3;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( ( (*( p))) == 42 ) {
+ goto st4;
+ }
+ {
+ goto st3;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 42: goto st4;
- case 47: goto st29;
- }
- goto st3;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st4;
+ }
+ case 47: {
+ goto st29;
+ }
+ }
+ {
+ goto st3;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) == 10 )
- goto st29;
- goto st5;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ if ( ( (*( p))) == 10 ) {
+ goto st29;
+ }
+ {
+ goto st5;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- switch( (*p) ) {
- case 42: goto st7;
- case 47: goto st9;
- }
- goto st0;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st7;
+ }
+ case 47: {
+ goto st9;
+ }
+ }
+ {
+ goto st0;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) == 42 )
- goto st8;
- goto st7;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ if ( ( (*( p))) == 42 ) {
+ goto st8;
+ }
+ {
+ goto st7;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 42: goto st8;
- case 47: goto st1;
- }
- goto st7;
-st9:
- if ( ++p == pe )
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st8;
+ }
+ case 47: {
+ goto st1;
+ }
+ }
+ {
+ goto st7;
+ }
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
- if ( (*p) == 10 )
- goto st1;
- goto st9;
-st10:
- if ( ++p == pe )
+ st_case_9:
+ if ( ( (*( p))) == 10 ) {
+ goto st1;
+ }
+ {
+ goto st9;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
goto _test_eof10;
-case 10:
- if ( (*p) == 110 )
- goto st11;
- goto st0;
-st11:
- if ( ++p == pe )
+ st_case_10:
+ if ( ( (*( p))) == 110 ) {
+ goto st11;
+ }
+ {
+ goto st0;
+ }
+ st11:
+ p+= 1;
+ if ( p == pe )
goto _test_eof11;
-case 11:
- if ( (*p) == 102 )
- goto st12;
- goto st0;
-st12:
- if ( ++p == pe )
+ st_case_11:
+ if ( ( (*( p))) == 102 ) {
+ goto st12;
+ }
+ {
+ goto st0;
+ }
+ st12:
+ p+= 1;
+ if ( p == pe )
goto _test_eof12;
-case 12:
- if ( (*p) == 105 )
- goto st13;
- goto st0;
-st13:
- if ( ++p == pe )
+ st_case_12:
+ if ( ( (*( p))) == 105 ) {
+ goto st13;
+ }
+ {
+ goto st0;
+ }
+ st13:
+ p+= 1;
+ if ( p == pe )
goto _test_eof13;
-case 13:
- if ( (*p) == 110 )
- goto st14;
- goto st0;
-st14:
- if ( ++p == pe )
+ st_case_13:
+ if ( ( (*( p))) == 110 ) {
+ goto st14;
+ }
+ {
+ goto st0;
+ }
+ st14:
+ p+= 1;
+ if ( p == pe )
goto _test_eof14;
-case 14:
- if ( (*p) == 105 )
- goto st15;
- goto st0;
-st15:
- if ( ++p == pe )
+ st_case_14:
+ if ( ( (*( p))) == 105 ) {
+ goto st15;
+ }
+ {
+ goto st0;
+ }
+ st15:
+ p+= 1;
+ if ( p == pe )
goto _test_eof15;
-case 15:
- if ( (*p) == 116 )
- goto st16;
- goto st0;
-st16:
- if ( ++p == pe )
+ st_case_15:
+ if ( ( (*( p))) == 116 ) {
+ goto st16;
+ }
+ {
+ goto st0;
+ }
+ st16:
+ p+= 1;
+ if ( p == pe )
goto _test_eof16;
-case 16:
- if ( (*p) == 121 )
- goto tr25;
- goto st0;
-st17:
- if ( ++p == pe )
+ st_case_16:
+ if ( ( (*( p))) == 121 ) {
+ goto ctr25;
+ }
+ {
+ goto st0;
+ }
+ st17:
+ p+= 1;
+ if ( p == pe )
goto _test_eof17;
-case 17:
- if ( (*p) == 97 )
- goto st18;
- goto st0;
-st18:
- if ( ++p == pe )
+ st_case_17:
+ if ( ( (*( p))) == 97 ) {
+ goto st18;
+ }
+ {
+ goto st0;
+ }
+ st18:
+ p+= 1;
+ if ( p == pe )
goto _test_eof18;
-case 18:
- if ( (*p) == 78 )
- goto tr27;
- goto st0;
-st19:
- if ( ++p == pe )
+ st_case_18:
+ if ( ( (*( p))) == 78 ) {
+ goto ctr27;
+ }
+ {
+ goto st0;
+ }
+ st19:
+ p+= 1;
+ if ( p == pe )
goto _test_eof19;
-case 19:
- if ( (*p) == 97 )
- goto st20;
- goto st0;
-st20:
- if ( ++p == pe )
+ st_case_19:
+ if ( ( (*( p))) == 97 ) {
+ goto st20;
+ }
+ {
+ goto st0;
+ }
+ st20:
+ p+= 1;
+ if ( p == pe )
goto _test_eof20;
-case 20:
- if ( (*p) == 108 )
- goto st21;
- goto st0;
-st21:
- if ( ++p == pe )
+ st_case_20:
+ if ( ( (*( p))) == 108 ) {
+ goto st21;
+ }
+ {
+ goto st0;
+ }
+ st21:
+ p+= 1;
+ if ( p == pe )
goto _test_eof21;
-case 21:
- if ( (*p) == 115 )
- goto st22;
- goto st0;
-st22:
- if ( ++p == pe )
+ st_case_21:
+ if ( ( (*( p))) == 115 ) {
+ goto st22;
+ }
+ {
+ goto st0;
+ }
+ st22:
+ p+= 1;
+ if ( p == pe )
goto _test_eof22;
-case 22:
- if ( (*p) == 101 )
- goto tr31;
- goto st0;
-st23:
- if ( ++p == pe )
+ st_case_22:
+ if ( ( (*( p))) == 101 ) {
+ goto ctr31;
+ }
+ {
+ goto st0;
+ }
+ st23:
+ p+= 1;
+ if ( p == pe )
goto _test_eof23;
-case 23:
- if ( (*p) == 117 )
- goto st24;
- goto st0;
-st24:
- if ( ++p == pe )
+ st_case_23:
+ if ( ( (*( p))) == 117 ) {
+ goto st24;
+ }
+ {
+ goto st0;
+ }
+ st24:
+ p+= 1;
+ if ( p == pe )
goto _test_eof24;
-case 24:
- if ( (*p) == 108 )
- goto st25;
- goto st0;
-st25:
- if ( ++p == pe )
+ st_case_24:
+ if ( ( (*( p))) == 108 ) {
+ goto st25;
+ }
+ {
+ goto st0;
+ }
+ st25:
+ p+= 1;
+ if ( p == pe )
goto _test_eof25;
-case 25:
- if ( (*p) == 108 )
- goto tr34;
- goto st0;
-st26:
- if ( ++p == pe )
+ st_case_25:
+ if ( ( (*( p))) == 108 ) {
+ goto ctr34;
+ }
+ {
+ goto st0;
+ }
+ st26:
+ p+= 1;
+ if ( p == pe )
goto _test_eof26;
-case 26:
- if ( (*p) == 114 )
- goto st27;
- goto st0;
-st27:
- if ( ++p == pe )
+ st_case_26:
+ if ( ( (*( p))) == 114 ) {
+ goto st27;
+ }
+ {
+ goto st0;
+ }
+ st27:
+ p+= 1;
+ if ( p == pe )
goto _test_eof27;
-case 27:
- if ( (*p) == 117 )
- goto st28;
- goto st0;
-st28:
- if ( ++p == pe )
+ st_case_27:
+ if ( ( (*( p))) == 117 ) {
+ goto st28;
+ }
+ {
+ goto st0;
+ }
+ st28:
+ p+= 1;
+ if ( p == pe )
goto _test_eof28;
-case 28:
- if ( (*p) == 101 )
- goto tr37;
- goto st0;
- }
- _test_eof1: cs = 1; goto _test_eof;
- _test_eof29: cs = 29; goto _test_eof;
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof11: cs = 11; goto _test_eof;
- _test_eof12: cs = 12; goto _test_eof;
- _test_eof13: cs = 13; goto _test_eof;
- _test_eof14: cs = 14; goto _test_eof;
- _test_eof15: cs = 15; goto _test_eof;
- _test_eof16: cs = 16; goto _test_eof;
- _test_eof17: cs = 17; goto _test_eof;
- _test_eof18: cs = 18; goto _test_eof;
- _test_eof19: cs = 19; goto _test_eof;
- _test_eof20: cs = 20; goto _test_eof;
- _test_eof21: cs = 21; goto _test_eof;
- _test_eof22: cs = 22; goto _test_eof;
- _test_eof23: cs = 23; goto _test_eof;
- _test_eof24: cs = 24; goto _test_eof;
- _test_eof25: cs = 25; goto _test_eof;
- _test_eof26: cs = 26; goto _test_eof;
- _test_eof27: cs = 27; goto _test_eof;
- _test_eof28: cs = 28; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_28:
+ if ( ( (*( p))) == 101 ) {
+ goto ctr37;
+ }
+ {
+ goto st0;
+ }
+ st_out:
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 291 "parser.rl"
+
+
+ if (json->freeze) {
+ OBJ_FREEZE(*result);
+ }
+
+ if (cs >= JSON_value_first_final) {
+ return p;
+ } else {
+ return NULL;
}
-
-#line 291 "parser.rl"
-
- if (json->freeze) {
- OBJ_FREEZE(*result);
- }
-
- if (cs >= JSON_value_first_final) {
- return p;
- } else {
- return NULL;
- }
}
-#line 884 "parser.c"
enum {JSON_integer_start = 1};
enum {JSON_integer_first_final = 3};
enum {JSON_integer_error = 0};
enum {JSON_integer_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_integer_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_integer_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_integer_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_integer_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 311 "parser.rl"
static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
- int cs = EVIL;
+ int cs = EVIL;
-#line 900 "parser.c"
{
- cs = JSON_integer_start;
+ cs = (int)JSON_integer_start;
}
-#line 318 "parser.rl"
- json->memo = p;
+ #line 318 "parser.rl"
+
+ json->memo = p;
-#line 908 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- switch( (*p) ) {
- case 45: goto st2;
- case 48: goto st3;
- }
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st5;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ }
+ goto st_out;
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 45: {
+ goto st2;
+ }
+ case 48: {
+ goto st3;
+ }
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- if ( (*p) == 48 )
- goto st3;
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st5;
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ if ( ( (*( p))) == 48 ) {
+ goto st3;
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st0;
- goto tr4;
-tr4:
-#line 308 "parser.rl"
- { p--; {p++; cs = 4; goto _out;} }
- goto st4;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st0;
+ }
+ {
+ goto ctr4;
+ }
+ ctr4:
+ {
+ #line 308 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 4; goto _out;} }
+
+ goto st4;
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
-#line 949 "parser.c"
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st5;
- goto tr4;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_5:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ {
+ goto ctr4;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 320 "parser.rl"
+
+
+ if (cs >= JSON_integer_first_final) {
+ long len = p - json->memo;
+ fbuffer_clear(json->fbuffer);
+ fbuffer_append(json->fbuffer, json->memo, len);
+ fbuffer_append_char(json->fbuffer, '\0');
+ *result = rb_cstr2inum(FBUFFER_PTR(json->fbuffer), 10);
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 320 "parser.rl"
-
- if (cs >= JSON_integer_first_final) {
- long len = p - json->memo;
- fbuffer_clear(json->fbuffer);
- fbuffer_append(json->fbuffer, json->memo, len);
- fbuffer_append_char(json->fbuffer, '\0');
- *result = rb_cstr2inum(FBUFFER_PTR(json->fbuffer), 10);
- return p + 1;
- } else {
- return NULL;
- }
}
-#line 983 "parser.c"
enum {JSON_float_start = 1};
enum {JSON_float_first_final = 8};
enum {JSON_float_error = 0};
enum {JSON_float_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_float_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_float_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_float_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_float_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 345 "parser.rl"
static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
- int cs = EVIL;
+ int cs = EVIL;
-#line 999 "parser.c"
{
- cs = JSON_float_start;
+ cs = (int)JSON_float_start;
}
-#line 352 "parser.rl"
- json->memo = p;
+ #line 352 "parser.rl"
+
+ json->memo = p;
-#line 1007 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- switch( (*p) ) {
- case 45: goto st2;
- case 48: goto st3;
- }
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st7;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 10:
+ goto st_case_10;
+ case 7:
+ goto st_case_7;
+ }
+ goto st_out;
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 45: {
+ goto st2;
+ }
+ case 48: {
+ goto st3;
+ }
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- if ( (*p) == 48 )
- goto st3;
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st7;
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ if ( ( (*( p))) == 48 ) {
+ goto st3;
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- switch( (*p) ) {
- case 46: goto st4;
- case 69: goto st5;
- case 101: goto st5;
- }
- goto st0;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ switch( ( (*( p))) ) {
+ case 46: {
+ goto st4;
+ }
+ case 69: {
+ goto st5;
+ }
+ case 101: {
+ goto st5;
+ }
+ }
+ {
+ goto st0;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st8;
- goto st0;
-st8:
- if ( ++p == pe )
- goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 69: goto st5;
- case 101: goto st5;
- }
- if ( (*p) > 46 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_4:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
goto st8;
- } else if ( (*p) >= 45 )
- goto st0;
- goto tr9;
-tr9:
-#line 339 "parser.rl"
- { p--; {p++; cs = 9; goto _out;} }
- goto st9;
-st9:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof8;
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 69: {
+ goto st5;
+ }
+ case 101: {
+ goto st5;
+ }
+ }
+ if ( ( (*( p))) > 46 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st8;
+ }
+ } else if ( ( (*( p))) >= 45 ) {
+ goto st0;
+ }
+ {
+ goto ctr9;
+ }
+ ctr9:
+ {
+ #line 339 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 9; goto _out;} }
+
+ goto st9;
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
-#line 1072 "parser.c"
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_9:
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- switch( (*p) ) {
- case 43: goto st6;
- case 45: goto st6;
- }
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st10;
- goto st0;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ switch( ( (*( p))) ) {
+ case 43: {
+ goto st6;
+ }
+ case 45: {
+ goto st6;
+ }
+ }
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st10;
+ }
+ {
+ goto st0;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st10;
- goto st0;
-st10:
- if ( ++p == pe )
- goto _test_eof10;
-case 10:
- switch( (*p) ) {
- case 69: goto st0;
- case 101: goto st0;
- }
- if ( (*p) > 46 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_6:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
goto st10;
- } else if ( (*p) >= 45 )
- goto st0;
- goto tr9;
-st7:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof10;
+ st_case_10:
+ switch( ( (*( p))) ) {
+ case 69: {
+ goto st0;
+ }
+ case 101: {
+ goto st0;
+ }
+ }
+ if ( ( (*( p))) > 46 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st10;
+ }
+ } else if ( ( (*( p))) >= 45 ) {
+ goto st0;
+ }
+ {
+ goto ctr9;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- switch( (*p) ) {
- case 46: goto st4;
- case 69: goto st5;
- case 101: goto st5;
- }
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st7;
- goto st0;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_7:
+ switch( ( (*( p))) ) {
+ case 46: {
+ goto st4;
+ }
+ case 69: {
+ goto st5;
+ }
+ case 101: {
+ goto st5;
+ }
+ }
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ {
+ goto st0;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 354 "parser.rl"
+
+
+ if (cs >= JSON_float_first_final) {
+ VALUE mod = Qnil;
+ ID method_id = 0;
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
+ mod = json->decimal_class;
+ method_id = i_try_convert;
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
+ mod = json->decimal_class;
+ method_id = i_new;
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
+ VALUE name = rb_class_name(json->decimal_class);
+ const char *name_cstr = RSTRING_PTR(name);
+ const char *last_colon = strrchr(name_cstr, ':');
+ if (last_colon) {
+ const char *mod_path_end = last_colon - 1;
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
+ mod = rb_path_to_class(mod_path);
+
+ const char *method_name_beg = last_colon + 1;
+ long before_len = method_name_beg - name_cstr;
+ long len = RSTRING_LEN(name) - before_len;
+ VALUE method_name = rb_str_substr(name, before_len, len);
+ method_id = SYM2ID(rb_str_intern(method_name));
+ } else {
+ mod = rb_mKernel;
+ method_id = SYM2ID(rb_str_intern(name));
+ }
+ }
+
+ long len = p - json->memo;
+ fbuffer_clear(json->fbuffer);
+ fbuffer_append(json->fbuffer, json->memo, len);
+ fbuffer_append_char(json->fbuffer, '\0');
+
+ if (method_id) {
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
+ *result = rb_funcallv(mod, method_id, 1, &text);
+ } else {
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
+ }
+
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 354 "parser.rl"
-
- if (cs >= JSON_float_first_final) {
- VALUE mod = Qnil;
- ID method_id = 0;
- if (rb_respond_to(json->decimal_class, i_try_convert)) {
- mod = json->decimal_class;
- method_id = i_try_convert;
- } else if (rb_respond_to(json->decimal_class, i_new)) {
- mod = json->decimal_class;
- method_id = i_new;
- } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
- VALUE name = rb_class_name(json->decimal_class);
- const char *name_cstr = RSTRING_PTR(name);
- const char *last_colon = strrchr(name_cstr, ':');
- if (last_colon) {
- const char *mod_path_end = last_colon - 1;
- VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
- mod = rb_path_to_class(mod_path);
-
- const char *method_name_beg = last_colon + 1;
- long before_len = method_name_beg - name_cstr;
- long len = RSTRING_LEN(name) - before_len;
- VALUE method_name = rb_str_substr(name, before_len, len);
- method_id = SYM2ID(rb_str_intern(method_name));
- } else {
- mod = rb_mKernel;
- method_id = SYM2ID(rb_str_intern(name));
- }
- }
-
- long len = p - json->memo;
- fbuffer_clear(json->fbuffer);
- fbuffer_append(json->fbuffer, json->memo, len);
- fbuffer_append_char(json->fbuffer, '\0');
-
- if (method_id) {
- VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
- *result = rb_funcallv(mod, method_id, 1, &text);
- } else {
- *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
- }
-
- return p + 1;
- } else {
- return NULL;
- }
}
-#line 1184 "parser.c"
enum {JSON_array_start = 1};
enum {JSON_array_first_final = 17};
enum {JSON_array_error = 0};
enum {JSON_array_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_array_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_array_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_array_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_array_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 432 "parser.rl"
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
- int cs = EVIL;
- VALUE array_class = json->array_class;
+ int cs = EVIL;
+ VALUE array_class = json->array_class;
- if (json->max_nesting && current_nesting > json->max_nesting) {
- rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
- }
- *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
+ if (json->max_nesting && current_nesting > json->max_nesting) {
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
+ }
+ *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
-#line 1206 "parser.c"
{
- cs = JSON_array_start;
+ cs = (int)JSON_array_start;
}
-#line 445 "parser.rl"
+ #line 445 "parser.rl"
+
-#line 1213 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- if ( (*p) == 91 )
- goto st2;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 10:
+ goto st_case_10;
+ case 11:
+ goto st_case_11;
+ case 12:
+ goto st_case_12;
+ case 17:
+ goto st_case_17;
+ case 13:
+ goto st_case_13;
+ case 14:
+ goto st_case_14;
+ case 15:
+ goto st_case_15;
+ case 16:
+ goto st_case_16;
+ }
+ goto st_out;
+ st_case_1:
+ if ( ( (*( p))) == 91 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 13: goto st2;
- case 32: goto st2;
- case 34: goto tr2;
- case 45: goto tr2;
- case 47: goto st13;
- case 73: goto tr2;
- case 78: goto tr2;
- case 91: goto tr2;
- case 93: goto tr4;
- case 102: goto tr2;
- case 110: goto tr2;
- case 116: goto tr2;
- case 123: goto tr2;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr2;
- } else if ( (*p) >= 9 )
- goto st2;
- goto st0;
-tr2:
-#line 409 "parser.rl"
- {
- VALUE v = Qnil;
- char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
- if (np == NULL) {
- p--; {p++; cs = 3; goto _out;}
- } else {
- if (NIL_P(json->array_class)) {
- rb_ary_push(*result, v);
- } else {
- rb_funcall(*result, i_leftshift, 1, v);
- }
- {p = (( np))-1;}
- }
- }
- goto st3;
-st3:
- if ( ++p == pe )
- goto _test_eof3;
-case 3:
-#line 1272 "parser.c"
- switch( (*p) ) {
- case 13: goto st3;
- case 32: goto st3;
- case 44: goto st4;
- case 47: goto st9;
- case 93: goto tr4;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st2;
+ }
+ case 32: {
+ goto st2;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st13;
+ }
+ case 73: {
+ goto ctr2;
+ }
+ case 78: {
+ goto ctr2;
+ }
+ case 91: {
+ goto ctr2;
+ }
+ case 93: {
+ goto ctr4;
+ }
+ case 102: {
+ goto ctr2;
+ }
+ case 110: {
+ goto ctr2;
+ }
+ case 116: {
+ goto ctr2;
+ }
+ case 123: {
+ goto ctr2;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr2;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ ctr2:
+ {
+ #line 409 "parser.rl"
+
+ VALUE v = Qnil;
+ char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
+ if (np == NULL) {
+ {p = p - 1; } {p+= 1; cs = 3; goto _out;}
+ } else {
+ if (NIL_P(json->array_class)) {
+ rb_ary_push(*result, v);
+ } else {
+ rb_funcall(*result, i_leftshift, 1, v);
+ }
+ {p = (( np))-1;}
+
+ }
+ }
+
goto st3;
- goto st0;
-st4:
- if ( ++p == pe )
+ st3:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof3;
+ st_case_3:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st3;
+ }
+ case 32: {
+ goto st3;
+ }
+ case 44: {
+ goto st4;
+ }
+ case 47: {
+ goto st9;
+ }
+ case 93: {
+ goto ctr4;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st3;
+ }
+ {
+ goto st0;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 13: goto st4;
- case 32: goto st4;
- case 34: goto tr2;
- case 45: goto tr2;
- case 47: goto st5;
- case 73: goto tr2;
- case 78: goto tr2;
- case 91: goto tr2;
- case 102: goto tr2;
- case 110: goto tr2;
- case 116: goto tr2;
- case 123: goto tr2;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr2;
- } else if ( (*p) >= 9 )
- goto st4;
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st4;
+ }
+ case 32: {
+ goto st4;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st5;
+ }
+ case 73: {
+ goto ctr2;
+ }
+ case 78: {
+ goto ctr2;
+ }
+ case 91: {
+ goto ctr2;
+ }
+ case 102: {
+ goto ctr2;
+ }
+ case 110: {
+ goto ctr2;
+ }
+ case 116: {
+ goto ctr2;
+ }
+ case 123: {
+ goto ctr2;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr2;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st4;
+ }
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- switch( (*p) ) {
- case 42: goto st6;
- case 47: goto st8;
- }
- goto st0;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st6;
+ }
+ case 47: {
+ goto st8;
+ }
+ }
+ {
+ goto st0;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- if ( (*p) == 42 )
- goto st7;
- goto st6;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ if ( ( (*( p))) == 42 ) {
+ goto st7;
+ }
+ {
+ goto st6;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- switch( (*p) ) {
- case 42: goto st7;
- case 47: goto st4;
- }
- goto st6;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st7;
+ }
+ case 47: {
+ goto st4;
+ }
+ }
+ {
+ goto st6;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- if ( (*p) == 10 )
- goto st4;
- goto st8;
-st9:
- if ( ++p == pe )
+ st_case_8:
+ if ( ( (*( p))) == 10 ) {
+ goto st4;
+ }
+ {
+ goto st8;
+ }
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
- switch( (*p) ) {
- case 42: goto st10;
- case 47: goto st12;
- }
- goto st0;
-st10:
- if ( ++p == pe )
+ st_case_9:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st10;
+ }
+ case 47: {
+ goto st12;
+ }
+ }
+ {
+ goto st0;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
goto _test_eof10;
-case 10:
- if ( (*p) == 42 )
- goto st11;
- goto st10;
-st11:
- if ( ++p == pe )
+ st_case_10:
+ if ( ( (*( p))) == 42 ) {
+ goto st11;
+ }
+ {
+ goto st10;
+ }
+ st11:
+ p+= 1;
+ if ( p == pe )
goto _test_eof11;
-case 11:
- switch( (*p) ) {
- case 42: goto st11;
- case 47: goto st3;
- }
- goto st10;
-st12:
- if ( ++p == pe )
+ st_case_11:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st11;
+ }
+ case 47: {
+ goto st3;
+ }
+ }
+ {
+ goto st10;
+ }
+ st12:
+ p+= 1;
+ if ( p == pe )
goto _test_eof12;
-case 12:
- if ( (*p) == 10 )
- goto st3;
- goto st12;
-tr4:
-#line 424 "parser.rl"
- { p--; {p++; cs = 17; goto _out;} }
- goto st17;
-st17:
- if ( ++p == pe )
+ st_case_12:
+ if ( ( (*( p))) == 10 ) {
+ goto st3;
+ }
+ {
+ goto st12;
+ }
+ ctr4:
+ {
+ #line 424 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 17; goto _out;} }
+
+ goto st17;
+ st17:
+ p+= 1;
+ if ( p == pe )
goto _test_eof17;
-case 17:
-#line 1379 "parser.c"
- goto st0;
-st13:
- if ( ++p == pe )
+ st_case_17:
+ {
+ goto st0;
+ }
+ st13:
+ p+= 1;
+ if ( p == pe )
goto _test_eof13;
-case 13:
- switch( (*p) ) {
- case 42: goto st14;
- case 47: goto st16;
- }
- goto st0;
-st14:
- if ( ++p == pe )
+ st_case_13:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st14;
+ }
+ case 47: {
+ goto st16;
+ }
+ }
+ {
+ goto st0;
+ }
+ st14:
+ p+= 1;
+ if ( p == pe )
goto _test_eof14;
-case 14:
- if ( (*p) == 42 )
- goto st15;
- goto st14;
-st15:
- if ( ++p == pe )
+ st_case_14:
+ if ( ( (*( p))) == 42 ) {
+ goto st15;
+ }
+ {
+ goto st14;
+ }
+ st15:
+ p+= 1;
+ if ( p == pe )
goto _test_eof15;
-case 15:
- switch( (*p) ) {
- case 42: goto st15;
- case 47: goto st2;
- }
- goto st14;
-st16:
- if ( ++p == pe )
+ st_case_15:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st15;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ {
+ goto st14;
+ }
+ st16:
+ p+= 1;
+ if ( p == pe )
goto _test_eof16;
-case 16:
- if ( (*p) == 10 )
- goto st2;
- goto st16;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof11: cs = 11; goto _test_eof;
- _test_eof12: cs = 12; goto _test_eof;
- _test_eof17: cs = 17; goto _test_eof;
- _test_eof13: cs = 13; goto _test_eof;
- _test_eof14: cs = 14; goto _test_eof;
- _test_eof15: cs = 15; goto _test_eof;
- _test_eof16: cs = 16; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_16:
+ if ( ( (*( p))) == 10 ) {
+ goto st2;
+ }
+ {
+ goto st16;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 446 "parser.rl"
+
+
+ if(cs >= JSON_array_first_final) {
+ return p + 1;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
+ return NULL;
}
-
-#line 446 "parser.rl"
-
- if(cs >= JSON_array_first_final) {
- return p + 1;
- } else {
- rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
- return NULL;
- }
}
static const size_t MAX_STACK_BUFFER_SIZE = 128;
static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int symbolize)
{
- VALUE result = Qnil;
- size_t bufferSize = stringEnd - string;
- char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
- int unescape_len;
- char buf[4];
+ VALUE result = Qnil;
+ size_t bufferSize = stringEnd - string;
+ char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
+ int unescape_len;
+ char buf[4];
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
# ifdef HAVE_RB_ENC_INTERNED_STR
- bufferStart = buffer = ALLOC_N(char, bufferSize ? bufferSize : 1);
+ bufferStart = buffer = ALLOC_N(char, bufferSize ? bufferSize : 1);
# else
- bufferStart = buffer = ALLOC_N(char, bufferSize);
+ bufferStart = buffer = ALLOC_N(char, bufferSize);
# endif
- } else {
+ } else {
# ifdef HAVE_RB_ENC_INTERNED_STR
- bufferStart = buffer = ALLOCA_N(char, bufferSize ? bufferSize : 1);
+ bufferStart = buffer = ALLOCA_N(char, bufferSize ? bufferSize : 1);
# else
- bufferStart = buffer = ALLOCA_N(char, bufferSize);
+ bufferStart = buffer = ALLOCA_N(char, bufferSize);
# endif
- }
-
- while (pe < stringEnd) {
- if (*pe == '\\') {
- unescape = (char *) "?";
- unescape_len = 1;
- if (pe > p) {
- MEMCPY(buffer, p, char, pe - p);
- buffer += pe - p;
- }
- switch (*++pe) {
- case 'n':
- unescape = (char *) "\n";
- break;
- case 'r':
- unescape = (char *) "\r";
- break;
- case 't':
- unescape = (char *) "\t";
- break;
- case '"':
- unescape = (char *) "\"";
- break;
- case '\\':
- unescape = (char *) "\\";
- break;
- case 'b':
- unescape = (char *) "\b";
- break;
- case 'f':
- unescape = (char *) "\f";
- break;
- case 'u':
- if (pe > stringEnd - 4) {
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- free(bufferStart);
- }
- rb_enc_raise(
- EXC_ENCODING eParserError,
- "incomplete unicode character escape sequence at '%s'", p
- );
- } else {
- UTF32 ch = unescape_unicode((unsigned char *) ++pe);
- pe += 3;
- if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
- pe++;
- if (pe > stringEnd - 6) {
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- free(bufferStart);
- }
- rb_enc_raise(
- EXC_ENCODING eParserError,
- "incomplete surrogate pair at '%s'", p
- );
- }
- if (pe[0] == '\\' && pe[1] == 'u') {
- UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
- ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
- | (sur & 0x3FF));
- pe += 5;
- } else {
- unescape = (char *) "?";
- break;
- }
- }
- unescape_len = convert_UTF32_to_UTF8(buf, ch);
- unescape = buf;
- }
- break;
- default:
- p = pe;
- continue;
- }
- MEMCPY(buffer, unescape, char, unescape_len);
- buffer += unescape_len;
- p = ++pe;
- } else {
- pe++;
- }
- }
-
- if (pe > p) {
- MEMCPY(buffer, p, char, pe - p);
- buffer += pe - p;
- }
+ }
-# ifdef HAVE_RB_ENC_INTERNED_STR
- if (intern) {
- result = rb_enc_interned_str(bufferStart, (long)(buffer - bufferStart), rb_utf8_encoding());
- } else {
- result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
- }
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- free(bufferStart);
- }
-# else
- result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
-
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- free(bufferStart);
- }
-
- if (intern) {
- # if STR_UMINUS_DEDUPE_FROZEN
- // Starting from MRI 2.8 it is preferable to freeze the string
- // before deduplication so that it can be interned directly
- // otherwise it would be duplicated first which is wasteful.
- result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
- # elif STR_UMINUS_DEDUPE
- // MRI 2.5 and older do not deduplicate strings that are already
- // frozen.
- result = rb_funcall(result, i_uminus, 0);
- # else
- result = rb_str_freeze(result);
- # endif
- }
-# endif
+ while (pe < stringEnd) {
+ if (*pe == '\\') {
+ unescape = (char *) "?";
+ unescape_len = 1;
+ if (pe > p) {
+ MEMCPY(buffer, p, char, pe - p);
+ buffer += pe - p;
+ }
+ switch (*++pe) {
+ case 'n':
+ unescape = (char *) "\n";
+ break;
+ case 'r':
+ unescape = (char *) "\r";
+ break;
+ case 't':
+ unescape = (char *) "\t";
+ break;
+ case '"':
+ unescape = (char *) "\"";
+ break;
+ case '\\':
+ unescape = (char *) "\\";
+ break;
+ case 'b':
+ unescape = (char *) "\b";
+ break;
+ case 'f':
+ unescape = (char *) "\f";
+ break;
+ case 'u':
+ if (pe > stringEnd - 4) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
+ rb_enc_raise(
+ EXC_ENCODING eParserError,
+ "incomplete unicode character escape sequence at '%s'", p
+ );
+ } else {
+ UTF32 ch = unescape_unicode((unsigned char *) ++pe);
+ pe += 3;
+ if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
+ pe++;
+ if (pe > stringEnd - 6) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
+ rb_enc_raise(
+ EXC_ENCODING eParserError,
+ "incomplete surrogate pair at '%s'", p
+ );
+ }
+ if (pe[0] == '\\' && pe[1] == 'u') {
+ UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
+ ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
+ | (sur & 0x3FF));
+ pe += 5;
+ } else {
+ unescape = (char *) "?";
+ break;
+ }
+ }
+ unescape_len = convert_UTF32_to_UTF8(buf, ch);
+ unescape = buf;
+ }
+ break;
+ default:
+ p = pe;
+ continue;
+ }
+ MEMCPY(buffer, unescape, char, unescape_len);
+ buffer += unescape_len;
+ p = ++pe;
+ } else {
+ pe++;
+ }
+ }
+
+ if (pe > p) {
+ MEMCPY(buffer, p, char, pe - p);
+ buffer += pe - p;
+ }
+
+ # ifdef HAVE_RB_ENC_INTERNED_STR
+ if (intern) {
+ result = rb_enc_interned_str(bufferStart, (long)(buffer - bufferStart), rb_utf8_encoding());
+ } else {
+ result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
+ }
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
+ # else
+ result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
+
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
- if (symbolize) {
- result = rb_str_intern(result);
- }
+ if (intern) {
+ # if STR_UMINUS_DEDUPE_FROZEN
+ // Starting from MRI 2.8 it is preferable to freeze the string
+ // before deduplication so that it can be interned directly
+ // otherwise it would be duplicated first which is wasteful.
+ result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
+ # elif STR_UMINUS_DEDUPE
+ // MRI 2.5 and older do not deduplicate strings that are already
+ // frozen.
+ result = rb_funcall(result, i_uminus, 0);
+ # else
+ result = rb_str_freeze(result);
+ # endif
+ }
+ # endif
- return result;
+ if (symbolize) {
+ result = rb_str_intern(result);
+ }
+
+ return result;
}
-#line 1592 "parser.c"
enum {JSON_string_start = 1};
enum {JSON_string_first_final = 8};
enum {JSON_string_error = 0};
enum {JSON_string_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_string_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_string_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
-#line 620 "parser.rl"
+static const char MAYBE_UNUSED(_JSON_string_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_string_nfa_pop_trans)[] = {
+ 0, 0
+};
+
+
+#line 612 "parser.rl"
static int
match_i(VALUE regexp, VALUE klass, VALUE memo)
{
- if (regexp == Qundef) return ST_STOP;
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
- RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
- rb_ary_push(memo, klass);
- return ST_STOP;
- }
- return ST_CONTINUE;
+ if (regexp == Qundef) return ST_STOP;
+ if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
+ RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
+ rb_ary_push(memo, klass);
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
}
static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
- int cs = EVIL;
- VALUE match_string;
+ int cs = EVIL;
+ VALUE match_string;
-#line 1621 "parser.c"
{
- cs = JSON_string_start;
+ cs = (int)JSON_string_start;
}
-#line 640 "parser.rl"
- json->memo = p;
+ #line 632 "parser.rl"
+
+ json->memo = p;
-#line 1629 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- if ( (*p) == 34 )
- goto st2;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 8:
+ goto st_case_8;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ }
+ goto st_out;
+ st_case_1:
+ if ( ( (*( p))) == 34 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 34: goto tr2;
- case 92: goto st3;
- }
- if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 )
- goto st0;
- goto st2;
-tr2:
-#line 607 "parser.rl"
- {
- *result = json_string_unescape(json->memo + 1, p, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
- if (NIL_P(*result)) {
- p--;
- {p++; cs = 8; goto _out;}
- } else {
- {p = (( p + 1))-1;}
- }
- }
-#line 617 "parser.rl"
- { p--; {p++; cs = 8; goto _out;} }
- goto st8;
-st8:
- if ( ++p == pe )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 34: {
+ goto ctr2;
+ }
+ case 92: {
+ goto st3;
+ }
+ }
+ if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 ) {
+ goto st0;
+ }
+ {
+ goto st2;
+ }
+ ctr2:
+ {
+ #line 599 "parser.rl"
+
+ *result = json_string_unescape(json->memo + 1, p, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
+ if (NIL_P(*result)) {
+ {p = p - 1; }
+ {p+= 1; cs = 8; goto _out;}
+ } else {
+ {p = (( p + 1))-1;}
+
+ }
+ }
+ {
+ #line 609 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 8; goto _out;} }
+
+ goto st8;
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
-#line 1671 "parser.c"
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_8:
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( (*p) == 117 )
- goto st4;
- if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 )
- goto st0;
- goto st2;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( ( (*( p))) == 117 ) {
+ goto st4;
+ }
+ if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 ) {
+ goto st0;
+ }
+ {
+ goto st2;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_4:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st5;
+ }
+ } else {
goto st5;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
- goto st5;
- } else
- goto st5;
- goto st0;
-st5:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st6;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
+ st_case_5:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st6;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st6;
+ }
+ } else {
goto st6;
- } else
- goto st6;
- goto st0;
-st6:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_6:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st7;
+ }
+ } else {
goto st7;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
- goto st7;
- } else
- goto st7;
- goto st0;
-st7:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st2;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
+ st_case_7:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st2;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st2;
+ }
+ } else {
goto st2;
- } else
- goto st2;
- goto st0;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ }
+ {
+ goto st0;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 634 "parser.rl"
+
+
+ if (json->create_additions && RTEST(match_string = json->match_string)) {
+ VALUE klass;
+ VALUE memo = rb_ary_new2(2);
+ rb_ary_push(memo, *result);
+ rb_hash_foreach(match_string, match_i, memo);
+ klass = rb_ary_entry(memo, 1);
+ if (RTEST(klass)) {
+ *result = rb_funcall(klass, i_json_create, 1, *result);
+ }
+ }
+
+ if (cs >= JSON_string_first_final) {
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 642 "parser.rl"
-
- if (json->create_additions && RTEST(match_string = json->match_string)) {
- VALUE klass;
- VALUE memo = rb_ary_new2(2);
- rb_ary_push(memo, *result);
- rb_hash_foreach(match_string, match_i, memo);
- klass = rb_ary_entry(memo, 1);
- if (RTEST(klass)) {
- *result = rb_funcall(klass, i_json_create, 1, *result);
- }
- }
-
- if (cs >= JSON_string_first_final) {
- return p + 1;
- } else {
- return NULL;
- }
}
/*
- * Document-class: JSON::Ext::Parser
- *
- * This is the JSON parser implemented as a C extension. It can be configured
- * to be used by setting
- *
- * JSON.parser = JSON::Ext::Parser
- *
- * with the method parser= in JSON.
- *
- */
+* Document-class: JSON::Ext::Parser
+*
+* This is the JSON parser implemented as a C extension. It can be configured
+* to be used by setting
+*
+* JSON.parser = JSON::Ext::Parser
+*
+* with the method parser= in JSON.
+*
+*/
static VALUE convert_encoding(VALUE source)
{
-#ifdef HAVE_RUBY_ENCODING_H
- rb_encoding *enc = rb_enc_get(source);
- if (enc == rb_ascii8bit_encoding()) {
- if (OBJ_FROZEN(source)) {
- source = rb_str_dup(source);
- }
- FORCE_UTF8(source);
- } else {
- source = rb_str_conv_enc(source, rb_enc_get(source), rb_utf8_encoding());
- }
-#endif
- return source;
+ #ifdef HAVE_RUBY_ENCODING_H
+ rb_encoding *enc = rb_enc_get(source);
+ if (enc == rb_ascii8bit_encoding()) {
+ if (OBJ_FROZEN(source)) {
+ source = rb_str_dup(source);
+ }
+ FORCE_UTF8(source);
+ } else {
+ source = rb_str_conv_enc(source, rb_enc_get(source), rb_utf8_encoding());
+ }
+ #endif
+ return source;
}
/*
- * call-seq: new(source, opts => {})
- *
- * Creates a new JSON::Ext::Parser instance for the string _source_.
- *
- * It will be configured by the _opts_ hash. _opts_ can have the following
- * keys:
- *
- * _opts_ can have the following keys:
- * * *max_nesting*: The maximum depth of nesting allowed in the parsed data
- * structures. Disable depth checking with :max_nesting => false|nil|0, it
- * defaults to 100.
- * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
- * defiance of RFC 4627 to be parsed by the Parser. This option defaults to
- * false.
- * * *symbolize_names*: If set to true, returns symbols for the names
- * (keys) in a JSON object. Otherwise strings are returned, which is
- * also the default. It's not possible to use this option in
- * conjunction with the *create_additions* option.
- * * *create_additions*: If set to false, the Parser doesn't create
- * additions even if a matching class and create_id was found. This option
- * defaults to false.
- * * *object_class*: Defaults to Hash
- * * *array_class*: Defaults to Array
- */
+* call-seq: new(source, opts => {})
+*
+* Creates a new JSON::Ext::Parser instance for the string _source_.
+*
+* Creates a new JSON::Ext::Parser instance for the string _source_.
+*
+* It will be configured by the _opts_ hash. _opts_ can have the following
+* keys:
+*
+* _opts_ can have the following keys:
+* * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+* structures. Disable depth checking with :max_nesting => false|nil|0, it
+* defaults to 100.
+* * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+* defiance of RFC 4627 to be parsed by the Parser. This option defaults to
+* false.
+* * *symbolize_names*: If set to true, returns symbols for the names
+* (keys) in a JSON object. Otherwise strings are returned, which is
+* also the default. It's not possible to use this option in
+* conjunction with the *create_additions* option.
+* * *create_additions*: If set to false, the Parser doesn't create
+* additions even if a matching class and create_id was found. This option
+* defaults to false.
+* * *object_class*: Defaults to Hash
+* * *array_class*: Defaults to Array
+*/
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
- VALUE source, opts;
- GET_PARSER_INIT;
-
- if (json->Vsource) {
- rb_raise(rb_eTypeError, "already initialized instance");
- }
- rb_scan_args(argc, argv, "1:", &source, &opts);
- if (!NIL_P(opts)) {
- VALUE tmp = ID2SYM(i_max_nesting);
- if (option_given_p(opts, tmp)) {
- VALUE max_nesting = rb_hash_aref(opts, tmp);
- if (RTEST(max_nesting)) {
- Check_Type(max_nesting, T_FIXNUM);
- json->max_nesting = FIX2INT(max_nesting);
- } else {
- json->max_nesting = 0;
- }
- } else {
- json->max_nesting = 100;
- }
- tmp = ID2SYM(i_allow_nan);
- if (option_given_p(opts, tmp)) {
- json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->allow_nan = 0;
- }
- tmp = ID2SYM(i_symbolize_names);
- if (option_given_p(opts, tmp)) {
- json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->symbolize_names = 0;
- }
- tmp = ID2SYM(i_freeze);
- if (option_given_p(opts, tmp)) {
- json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->freeze = 0;
- }
- tmp = ID2SYM(i_create_additions);
- if (option_given_p(opts, tmp)) {
- json->create_additions = RTEST(rb_hash_aref(opts, tmp));
- } else {
- json->create_additions = 0;
- }
- if (json->symbolize_names && json->create_additions) {
- rb_raise(rb_eArgError,
- "options :symbolize_names and :create_additions cannot be "
- " used in conjunction");
- }
- tmp = ID2SYM(i_create_id);
- if (option_given_p(opts, tmp)) {
- json->create_id = rb_hash_aref(opts, tmp);
- } else {
- json->create_id = rb_funcall(mJSON, i_create_id, 0);
- }
- tmp = ID2SYM(i_object_class);
- if (option_given_p(opts, tmp)) {
- json->object_class = rb_hash_aref(opts, tmp);
- } else {
- json->object_class = Qnil;
- }
- tmp = ID2SYM(i_array_class);
- if (option_given_p(opts, tmp)) {
- json->array_class = rb_hash_aref(opts, tmp);
- } else {
- json->array_class = Qnil;
- }
- tmp = ID2SYM(i_decimal_class);
- if (option_given_p(opts, tmp)) {
- json->decimal_class = rb_hash_aref(opts, tmp);
+ VALUE source, opts;
+ GET_PARSER_INIT;
+
+ if (json->Vsource) {
+ rb_raise(rb_eTypeError, "already initialized instance");
+ }
+ #ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ rb_scan_args(argc, argv, "1:", &source, &opts);
+ #else
+ rb_scan_args(argc, argv, "11", &source, &opts);
+ #endif
+ if (!NIL_P(opts)) {
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
+ if (NIL_P(opts)) {
+ rb_raise(rb_eArgError, "opts needs to be like a hash");
+ } else {
+ #endif
+ VALUE tmp = ID2SYM(i_max_nesting);
+ if (option_given_p(opts, tmp)) {
+ VALUE max_nesting = rb_hash_aref(opts, tmp);
+ if (RTEST(max_nesting)) {
+ Check_Type(max_nesting, T_FIXNUM);
+ json->max_nesting = FIX2INT(max_nesting);
+ } else {
+ json->max_nesting = 0;
+ }
+ } else {
+ json->max_nesting = 100;
+ }
+ tmp = ID2SYM(i_allow_nan);
+ if (option_given_p(opts, tmp)) {
+ json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->allow_nan = 0;
+ }
+ tmp = ID2SYM(i_symbolize_names);
+ if (option_given_p(opts, tmp)) {
+ json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->symbolize_names = 0;
+ }
+ tmp = ID2SYM(i_freeze);
+ if (option_given_p(opts, tmp)) {
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->freeze = 0;
+ }
+ tmp = ID2SYM(i_create_additions);
+ if (option_given_p(opts, tmp)) {
+ json->create_additions = RTEST(rb_hash_aref(opts, tmp));
+ } else {
+ json->create_additions = 0;
+ }
+ if (json->symbolize_names && json->create_additions) {
+ rb_raise(rb_eArgError,
+ "options :symbolize_names and :create_additions cannot be "
+ " used in conjunction");
+ }
+ tmp = ID2SYM(i_create_id);
+ if (option_given_p(opts, tmp)) {
+ json->create_id = rb_hash_aref(opts, tmp);
+ } else {
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
+ }
+ tmp = ID2SYM(i_object_class);
+ if (option_given_p(opts, tmp)) {
+ json->object_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->object_class = Qnil;
+ }
+ tmp = ID2SYM(i_array_class);
+ if (option_given_p(opts, tmp)) {
+ json->array_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->array_class = Qnil;
+ }
+ tmp = ID2SYM(i_decimal_class);
+ if (option_given_p(opts, tmp)) {
+ json->decimal_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->decimal_class = Qnil;
+ }
+ tmp = ID2SYM(i_match_string);
+ if (option_given_p(opts, tmp)) {
+ VALUE match_string = rb_hash_aref(opts, tmp);
+ json->match_string = RTEST(match_string) ? match_string : Qnil;
+ } else {
+ json->match_string = Qnil;
+ }
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ }
+ #endif
} else {
- json->decimal_class = Qnil;
- }
- tmp = ID2SYM(i_match_string);
- if (option_given_p(opts, tmp)) {
- VALUE match_string = rb_hash_aref(opts, tmp);
- json->match_string = RTEST(match_string) ? match_string : Qnil;
- } else {
- json->match_string = Qnil;
- }
- } else {
- json->max_nesting = 100;
- json->allow_nan = 0;
- json->create_additions = 0;
- json->create_id = rb_funcall(mJSON, i_create_id, 0);
- json->object_class = Qnil;
- json->array_class = Qnil;
- json->decimal_class = Qnil;
- }
- source = convert_encoding(StringValue(source));
- StringValue(source);
- json->len = RSTRING_LEN(source);
- json->source = RSTRING_PTR(source);;
- json->Vsource = source;
- return self;
+ json->max_nesting = 100;
+ json->allow_nan = 0;
+ json->create_additions = 0;
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
+ json->object_class = Qnil;
+ json->array_class = Qnil;
+ json->decimal_class = Qnil;
+ }
+ source = convert_encoding(StringValue(source));
+ StringValue(source);
+ json->len = RSTRING_LEN(source);
+ json->source = RSTRING_PTR(source);;
+ json->Vsource = source;
+ return self;
}
-#line 1920 "parser.c"
enum {JSON_start = 1};
enum {JSON_first_final = 10};
enum {JSON_error = 0};
enum {JSON_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_nfa_pop_trans)[] = {
+ 0, 0
+};
+
-#line 828 "parser.rl"
+#line 835 "parser.rl"
/*
- * call-seq: parse()
- *
- * Parses the current JSON text _source_ and returns the complete data
- * structure as a result.
- * It raises JSON::ParserError if fail to parse.
- */
+* call-seq: parse()
+*
+* Parses the current JSON text _source_ and returns the complete data
+* structure as a result.
+* It raises JSON::ParseError if fail to parse.
+*/
static VALUE cParser_parse(VALUE self)
{
- char *p, *pe;
- int cs = EVIL;
- VALUE result = Qnil;
- GET_PARSER;
+ char *p, *pe;
+ int cs = EVIL;
+ VALUE result = Qnil;
+ GET_PARSER;
-#line 1946 "parser.c"
{
- cs = JSON_start;
+ cs = (int)JSON_start;
}
-#line 845 "parser.rl"
- p = json->source;
- pe = p + json->len;
+ #line 851 "parser.rl"
+
+ p = json->source;
+ pe = p + json->len;
-#line 1955 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-st1:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 10:
+ goto st_case_10;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ }
+ goto st_out;
+ st1:
+ p+= 1;
+ if ( p == pe )
goto _test_eof1;
-case 1:
- switch( (*p) ) {
- case 13: goto st1;
- case 32: goto st1;
- case 34: goto tr2;
- case 45: goto tr2;
- case 47: goto st6;
- case 73: goto tr2;
- case 78: goto tr2;
- case 91: goto tr2;
- case 102: goto tr2;
- case 110: goto tr2;
- case 116: goto tr2;
- case 123: goto tr2;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr2;
- } else if ( (*p) >= 9 )
- goto st1;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-tr2:
-#line 820 "parser.rl"
- {
- char *np = JSON_parse_value(json, p, pe, &result, 0);
- if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
- }
- goto st10;
-st10:
- if ( ++p == pe )
- goto _test_eof10;
-case 10:
-#line 1999 "parser.c"
- switch( (*p) ) {
- case 13: goto st10;
- case 32: goto st10;
- case 47: goto st2;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st1;
+ }
+ case 32: {
+ goto st1;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st6;
+ }
+ case 73: {
+ goto ctr2;
+ }
+ case 78: {
+ goto ctr2;
+ }
+ case 91: {
+ goto ctr2;
+ }
+ case 102: {
+ goto ctr2;
+ }
+ case 110: {
+ goto ctr2;
+ }
+ case 116: {
+ goto ctr2;
+ }
+ case 123: {
+ goto ctr2;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr2;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st1;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ ctr2:
+ {
+ #line 827 "parser.rl"
+
+ char *np = JSON_parse_value(json, p, pe, &result, 0);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 10; goto _out;} } else {p = (( np))-1;}
+
+ }
+
goto st10;
- goto st0;
-st2:
- if ( ++p == pe )
+ st10:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof10;
+ st_case_10:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st10;
+ }
+ case 32: {
+ goto st10;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st10;
+ }
+ {
+ goto st0;
+ }
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 42: goto st3;
- case 47: goto st5;
- }
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st3;
+ }
+ case 47: {
+ goto st5;
+ }
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( (*p) == 42 )
- goto st4;
- goto st3;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( ( (*( p))) == 42 ) {
+ goto st4;
+ }
+ {
+ goto st3;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 42: goto st4;
- case 47: goto st10;
- }
- goto st3;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st4;
+ }
+ case 47: {
+ goto st10;
+ }
+ }
+ {
+ goto st3;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) == 10 )
- goto st10;
- goto st5;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ if ( ( (*( p))) == 10 ) {
+ goto st10;
+ }
+ {
+ goto st5;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- switch( (*p) ) {
- case 42: goto st7;
- case 47: goto st9;
- }
- goto st0;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st7;
+ }
+ case 47: {
+ goto st9;
+ }
+ }
+ {
+ goto st0;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) == 42 )
- goto st8;
- goto st7;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ if ( ( (*( p))) == 42 ) {
+ goto st8;
+ }
+ {
+ goto st7;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 42: goto st8;
- case 47: goto st1;
- }
- goto st7;
-st9:
- if ( ++p == pe )
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st8;
+ }
+ case 47: {
+ goto st1;
+ }
+ }
+ {
+ goto st7;
+ }
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
- if ( (*p) == 10 )
- goto st1;
- goto st9;
- }
- _test_eof1: cs = 1; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_9:
+ if ( ( (*( p))) == 10 ) {
+ goto st1;
+ }
+ {
+ goto st9;
+ }
+ st_out:
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 854 "parser.rl"
+
+
+ if (cs >= JSON_first_final && p == pe) {
+ return result;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
+ return Qnil;
}
-
-#line 848 "parser.rl"
-
- if (cs >= JSON_first_final && p == pe) {
- return result;
- } else {
- rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
- return Qnil;
- }
}
static void JSON_mark(void *ptr)
{
- JSON_Parser *json = ptr;
- rb_gc_mark_maybe(json->Vsource);
- rb_gc_mark_maybe(json->create_id);
- rb_gc_mark_maybe(json->object_class);
- rb_gc_mark_maybe(json->array_class);
- rb_gc_mark_maybe(json->decimal_class);
- rb_gc_mark_maybe(json->match_string);
+ JSON_Parser *json = ptr;
+ rb_gc_mark_maybe(json->Vsource);
+ rb_gc_mark_maybe(json->create_id);
+ rb_gc_mark_maybe(json->object_class);
+ rb_gc_mark_maybe(json->array_class);
+ rb_gc_mark_maybe(json->decimal_class);
+ rb_gc_mark_maybe(json->match_string);
}
static void JSON_free(void *ptr)
{
- JSON_Parser *json = ptr;
- fbuffer_free(json->fbuffer);
- ruby_xfree(json);
+ JSON_Parser *json = ptr;
+ fbuffer_free(json->fbuffer);
+ ruby_xfree(json);
}
static size_t JSON_memsize(const void *ptr)
{
- const JSON_Parser *json = ptr;
- return sizeof(*json) + FBUFFER_CAPA(json->fbuffer);
+ const JSON_Parser *json = ptr;
+ return sizeof(*json) + FBUFFER_CAPA(json->fbuffer);
}
#ifdef NEW_TYPEDDATA_WRAPPER
static const rb_data_type_t JSON_Parser_type = {
- "JSON/Parser",
- {JSON_mark, JSON_free, JSON_memsize,},
-#ifdef RUBY_TYPED_FREE_IMMEDIATELY
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY,
-#endif
+ "JSON/Parser",
+ {JSON_mark, JSON_free, JSON_memsize,},
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
+ #endif
};
#endif
static VALUE cJSON_parser_s_allocate(VALUE klass)
{
- JSON_Parser *json;
- VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
- json->fbuffer = fbuffer_alloc(0);
- return obj;
+ JSON_Parser *json;
+ VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
+ json->fbuffer = fbuffer_alloc(0);
+ return obj;
}
/*
- * call-seq: source()
- *
- * Returns a copy of the current _source_ string, that was used to construct
- * this Parser.
- */
+* call-seq: source()
+*
+* Returns a copy of the current _source_ string, that was used to construct
+* this Parser.
+*/
static VALUE cParser_source(VALUE self)
{
- GET_PARSER;
- return rb_str_dup(json->Vsource);
+ GET_PARSER;
+ return rb_str_dup(json->Vsource);
}
void Init_parser(void)
{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
-#endif
-
-#undef rb_intern
- rb_require("json/common");
- mJSON = rb_define_module("JSON");
- mExt = rb_define_module_under(mJSON, "Ext");
- cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
- eParserError = rb_path2class("JSON::ParserError");
- eNestingError = rb_path2class("JSON::NestingError");
- rb_gc_register_mark_object(eParserError);
- rb_gc_register_mark_object(eNestingError);
- rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
- rb_define_method(cParser, "initialize", cParser_initialize, -1);
- rb_define_method(cParser, "parse", cParser_parse, 0);
- rb_define_method(cParser, "source", cParser_source, 0);
-
- CNaN = rb_const_get(mJSON, rb_intern("NaN"));
- rb_gc_register_mark_object(CNaN);
-
- CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
- rb_gc_register_mark_object(CInfinity);
-
- CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
- rb_gc_register_mark_object(CMinusInfinity);
-
- i_json_creatable_p = rb_intern("json_creatable?");
- i_json_create = rb_intern("json_create");
- i_create_id = rb_intern("create_id");
- i_create_additions = rb_intern("create_additions");
- i_chr = rb_intern("chr");
- i_max_nesting = rb_intern("max_nesting");
- i_allow_nan = rb_intern("allow_nan");
- i_symbolize_names = rb_intern("symbolize_names");
- i_object_class = rb_intern("object_class");
- i_array_class = rb_intern("array_class");
- i_decimal_class = rb_intern("decimal_class");
- i_match = rb_intern("match");
- i_match_string = rb_intern("match_string");
- i_key_p = rb_intern("key?");
- i_deep_const_get = rb_intern("deep_const_get");
- i_aset = rb_intern("[]=");
- i_aref = rb_intern("[]");
- i_leftshift = rb_intern("<<");
- i_new = rb_intern("new");
- i_try_convert = rb_intern("try_convert");
- i_freeze = rb_intern("freeze");
- i_uminus = rb_intern("-@");
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+ #endif
+
+ #undef rb_intern
+ rb_require("json/common");
+ mJSON = rb_define_module("JSON");
+ mExt = rb_define_module_under(mJSON, "Ext");
+ cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
+ eParserError = rb_path2class("JSON::ParserError");
+ eNestingError = rb_path2class("JSON::NestingError");
+ rb_gc_register_mark_object(eParserError);
+ rb_gc_register_mark_object(eNestingError);
+ rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
+ rb_define_method(cParser, "initialize", cParser_initialize, -1);
+ rb_define_method(cParser, "parse", cParser_parse, 0);
+ rb_define_method(cParser, "source", cParser_source, 0);
+
+ CNaN = rb_const_get(mJSON, rb_intern("NaN"));
+ rb_gc_register_mark_object(CNaN);
+
+ CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
+ rb_gc_register_mark_object(CInfinity);
+
+ CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
+ rb_gc_register_mark_object(CMinusInfinity);
+
+ i_json_creatable_p = rb_intern("json_creatable?");
+ i_json_create = rb_intern("json_create");
+ i_create_id = rb_intern("create_id");
+ i_create_additions = rb_intern("create_additions");
+ i_chr = rb_intern("chr");
+ i_max_nesting = rb_intern("max_nesting");
+ i_allow_nan = rb_intern("allow_nan");
+ i_symbolize_names = rb_intern("symbolize_names");
+ i_object_class = rb_intern("object_class");
+ i_array_class = rb_intern("array_class");
+ i_decimal_class = rb_intern("decimal_class");
+ i_match = rb_intern("match");
+ i_match_string = rb_intern("match_string");
+ i_key_p = rb_intern("key?");
+ i_deep_const_get = rb_intern("deep_const_get");
+ i_aset = rb_intern("[]=");
+ i_aref = rb_intern("[]");
+ i_leftshift = rb_intern("<<");
+ i_new = rb_intern("new");
+ i_try_convert = rb_intern("try_convert");
+ i_freeze = rb_intern("freeze");
+ i_uminus = rb_intern("-@");
}
/*
- * Local variables:
- * mode: c
- * c-file-style: ruby
- * indent-tabs-mode: nil
- * End:
- */
+* Local variables:
+* mode: c
+* c-file-style: ruby
+* indent-tabs-mode: nil
+* End:
+*/
diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl
index 1ecf3317c7..2dbdc7ef24 100644
--- a/ext/json/parser/parser.rl
+++ b/ext/json/parser/parser.rl
@@ -691,6 +691,8 @@ static VALUE convert_encoding(VALUE source)
*
* Creates a new JSON::Ext::Parser instance for the string _source_.
*
+ * Creates a new JSON::Ext::Parser instance for the string _source_.
+ *
* It will be configured by the _opts_ hash. _opts_ can have the following
* keys:
*
@@ -719,80 +721,93 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (json->Vsource) {
rb_raise(rb_eTypeError, "already initialized instance");
}
+#ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
rb_scan_args(argc, argv, "1:", &source, &opts);
+#else
+ rb_scan_args(argc, argv, "11", &source, &opts);
+#endif
if (!NIL_P(opts)) {
- VALUE tmp = ID2SYM(i_max_nesting);
- if (option_given_p(opts, tmp)) {
- VALUE max_nesting = rb_hash_aref(opts, tmp);
- if (RTEST(max_nesting)) {
- Check_Type(max_nesting, T_FIXNUM);
- json->max_nesting = FIX2INT(max_nesting);
- } else {
- json->max_nesting = 0;
- }
- } else {
- json->max_nesting = 100;
- }
- tmp = ID2SYM(i_allow_nan);
- if (option_given_p(opts, tmp)) {
- json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->allow_nan = 0;
- }
- tmp = ID2SYM(i_symbolize_names);
- if (option_given_p(opts, tmp)) {
- json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->symbolize_names = 0;
- }
- tmp = ID2SYM(i_freeze);
- if (option_given_p(opts, tmp)) {
- json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->freeze = 0;
- }
- tmp = ID2SYM(i_create_additions);
- if (option_given_p(opts, tmp)) {
- json->create_additions = RTEST(rb_hash_aref(opts, tmp));
- } else {
- json->create_additions = 0;
- }
- if (json->symbolize_names && json->create_additions) {
- rb_raise(rb_eArgError,
- "options :symbolize_names and :create_additions cannot be "
- " used in conjunction");
- }
- tmp = ID2SYM(i_create_id);
- if (option_given_p(opts, tmp)) {
- json->create_id = rb_hash_aref(opts, tmp);
- } else {
- json->create_id = rb_funcall(mJSON, i_create_id, 0);
- }
- tmp = ID2SYM(i_object_class);
- if (option_given_p(opts, tmp)) {
- json->object_class = rb_hash_aref(opts, tmp);
- } else {
- json->object_class = Qnil;
- }
- tmp = ID2SYM(i_array_class);
- if (option_given_p(opts, tmp)) {
- json->array_class = rb_hash_aref(opts, tmp);
- } else {
- json->array_class = Qnil;
- }
- tmp = ID2SYM(i_decimal_class);
- if (option_given_p(opts, tmp)) {
- json->decimal_class = rb_hash_aref(opts, tmp);
- } else {
- json->decimal_class = Qnil;
- }
- tmp = ID2SYM(i_match_string);
- if (option_given_p(opts, tmp)) {
- VALUE match_string = rb_hash_aref(opts, tmp);
- json->match_string = RTEST(match_string) ? match_string : Qnil;
- } else {
- json->match_string = Qnil;
- }
+#ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
+ if (NIL_P(opts)) {
+ rb_raise(rb_eArgError, "opts needs to be like a hash");
+ } else {
+#endif
+ VALUE tmp = ID2SYM(i_max_nesting);
+ if (option_given_p(opts, tmp)) {
+ VALUE max_nesting = rb_hash_aref(opts, tmp);
+ if (RTEST(max_nesting)) {
+ Check_Type(max_nesting, T_FIXNUM);
+ json->max_nesting = FIX2INT(max_nesting);
+ } else {
+ json->max_nesting = 0;
+ }
+ } else {
+ json->max_nesting = 100;
+ }
+ tmp = ID2SYM(i_allow_nan);
+ if (option_given_p(opts, tmp)) {
+ json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->allow_nan = 0;
+ }
+ tmp = ID2SYM(i_symbolize_names);
+ if (option_given_p(opts, tmp)) {
+ json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->symbolize_names = 0;
+ }
+ tmp = ID2SYM(i_freeze);
+ if (option_given_p(opts, tmp)) {
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->freeze = 0;
+ }
+ tmp = ID2SYM(i_create_additions);
+ if (option_given_p(opts, tmp)) {
+ json->create_additions = RTEST(rb_hash_aref(opts, tmp));
+ } else {
+ json->create_additions = 0;
+ }
+ if (json->symbolize_names && json->create_additions) {
+ rb_raise(rb_eArgError,
+ "options :symbolize_names and :create_additions cannot be "
+ " used in conjunction");
+ }
+ tmp = ID2SYM(i_create_id);
+ if (option_given_p(opts, tmp)) {
+ json->create_id = rb_hash_aref(opts, tmp);
+ } else {
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
+ }
+ tmp = ID2SYM(i_object_class);
+ if (option_given_p(opts, tmp)) {
+ json->object_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->object_class = Qnil;
+ }
+ tmp = ID2SYM(i_array_class);
+ if (option_given_p(opts, tmp)) {
+ json->array_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->array_class = Qnil;
+ }
+ tmp = ID2SYM(i_decimal_class);
+ if (option_given_p(opts, tmp)) {
+ json->decimal_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->decimal_class = Qnil;
+ }
+ tmp = ID2SYM(i_match_string);
+ if (option_given_p(opts, tmp)) {
+ VALUE match_string = rb_hash_aref(opts, tmp);
+ json->match_string = RTEST(match_string) ? match_string : Qnil;
+ } else {
+ json->match_string = Qnil;
+ }
+#ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ }
+#endif
} else {
json->max_nesting = 100;
json->allow_nan = 0;
@@ -832,7 +847,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
*
* Parses the current JSON text _source_ and returns the complete data
* structure as a result.
- * It raises JSON::ParserError if fail to parse.
+ * It raises JSON::ParseError if fail to parse.
*/
static VALUE cParser_parse(VALUE self)
{
diff --git a/ext/monitor/depend b/ext/monitor/depend
index 38e21b3f66..3030da71d0 100644
--- a/ext/monitor/depend
+++ b/ext/monitor/depend
@@ -51,7 +51,6 @@ monitor.o: $(hdrdir)/ruby/internal/attr/noexcept.h
monitor.o: $(hdrdir)/ruby/internal/attr/noinline.h
monitor.o: $(hdrdir)/ruby/internal/attr/nonnull.h
monitor.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-monitor.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
monitor.o: $(hdrdir)/ruby/internal/attr/pure.h
monitor.o: $(hdrdir)/ruby/internal/attr/restrict.h
monitor.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ monitor.o: $(hdrdir)/ruby/internal/intern/enumerator.h
monitor.o: $(hdrdir)/ruby/internal/intern/error.h
monitor.o: $(hdrdir)/ruby/internal/intern/eval.h
monitor.o: $(hdrdir)/ruby/internal/intern/file.h
+monitor.o: $(hdrdir)/ruby/internal/intern/gc.h
monitor.o: $(hdrdir)/ruby/internal/intern/hash.h
monitor.o: $(hdrdir)/ruby/internal/intern/io.h
monitor.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ monitor.o: $(hdrdir)/ruby/internal/memory.h
monitor.o: $(hdrdir)/ruby/internal/method.h
monitor.o: $(hdrdir)/ruby/internal/module.h
monitor.o: $(hdrdir)/ruby/internal/newobj.h
+monitor.o: $(hdrdir)/ruby/internal/rgengc.h
monitor.o: $(hdrdir)/ruby/internal/scan_args.h
monitor.o: $(hdrdir)/ruby/internal/special_consts.h
monitor.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/monitor/lib/monitor.rb b/ext/monitor/lib/monitor.rb
index 31d6d2b3c4..11c5ac17d9 100644
--- a/ext/monitor/lib/monitor.rb
+++ b/ext/monitor/lib/monitor.rb
@@ -7,19 +7,17 @@
# You can freely distribute/modify this library.
#
-require 'monitor.so'
-
#
# In concurrent programming, a monitor is an object or module intended to be
-# used safely by more than one thread. The defining characteristic of a
-# monitor is that its methods are executed with mutual exclusion. That is, at
+# used safely by more than one thread. The defining characteristic of a
+# monitor is that its methods are executed with mutual exclusion. That is, at
# each point in time, at most one thread may be executing any of its methods.
# This mutual exclusion greatly simplifies reasoning about the implementation
# of monitors compared to reasoning about parallel code that updates a data
# structure.
#
# You can read more about the general principles on the Wikipedia page for
-# Monitors[https://en.wikipedia.org/wiki/Monitor_%28synchronization%29].
+# Monitors[https://en.wikipedia.org/wiki/Monitor_%28synchronization%29]
#
# == Examples
#
@@ -50,7 +48,7 @@ require 'monitor.so'
# end
#
# The consumer thread waits for the producer thread to push a line to buf
-# while <tt>buf.empty?</tt>. The producer thread (main thread) reads a
+# while <tt>buf.empty?</tt>. The producer thread (main thread) reads a
# line from ARGF and pushes it into buf then calls <tt>empty_cond.signal</tt>
# to notify the consumer thread of new data.
#
@@ -88,6 +86,9 @@ require 'monitor.so'
# This Class is implemented as subclass of Array which includes the
# MonitorMixin module.
#
+
+require 'monitor.so'
+
module MonitorMixin
#
# FIXME: This isn't documented in Nutshell.
diff --git a/ext/monitor/monitor.c b/ext/monitor/monitor.c
index 86613f6ade..10209cf2aa 100644
--- a/ext/monitor/monitor.c
+++ b/ext/monitor/monitor.c
@@ -102,7 +102,7 @@ monitor_exit(VALUE monitor)
struct rb_monitor *mc = monitor_ptr(monitor);
- if (mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)mc->count);
+ if (mc->count <= 0) rb_bug("monitor_exit: count:%d\n", (int)mc->count);
mc->count--;
if (mc->count == 0) {
diff --git a/ext/nkf/depend b/ext/nkf/depend
index 98afc5f201..9e2f468ba1 100644
--- a/ext/nkf/depend
+++ b/ext/nkf/depend
@@ -56,7 +56,6 @@ nkf.o: $(hdrdir)/ruby/internal/attr/noexcept.h
nkf.o: $(hdrdir)/ruby/internal/attr/noinline.h
nkf.o: $(hdrdir)/ruby/internal/attr/nonnull.h
nkf.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-nkf.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
nkf.o: $(hdrdir)/ruby/internal/attr/pure.h
nkf.o: $(hdrdir)/ruby/internal/attr/restrict.h
nkf.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -125,6 +124,7 @@ nkf.o: $(hdrdir)/ruby/internal/intern/enumerator.h
nkf.o: $(hdrdir)/ruby/internal/intern/error.h
nkf.o: $(hdrdir)/ruby/internal/intern/eval.h
nkf.o: $(hdrdir)/ruby/internal/intern/file.h
+nkf.o: $(hdrdir)/ruby/internal/intern/gc.h
nkf.o: $(hdrdir)/ruby/internal/intern/hash.h
nkf.o: $(hdrdir)/ruby/internal/intern/io.h
nkf.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -155,6 +155,7 @@ nkf.o: $(hdrdir)/ruby/internal/memory.h
nkf.o: $(hdrdir)/ruby/internal/method.h
nkf.o: $(hdrdir)/ruby/internal/module.h
nkf.o: $(hdrdir)/ruby/internal/newobj.h
+nkf.o: $(hdrdir)/ruby/internal/rgengc.h
nkf.o: $(hdrdir)/ruby/internal/scan_args.h
nkf.o: $(hdrdir)/ruby/internal/special_consts.h
nkf.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/nkf/nkf.c b/ext/nkf/nkf.c
index 73b616a54f..c6ddee1976 100644
--- a/ext/nkf/nkf.c
+++ b/ext/nkf/nkf.c
@@ -9,7 +9,6 @@
#define RUBY_NKF_REVISION "$Revision$"
#define RUBY_NKF_VERSION NKF_VERSION " (" NKF_RELEASE_DATE ")"
-#define NKF_GEM_VERSION "0.1.3"
#include "ruby/ruby.h"
#include "ruby/encoding.h"
@@ -501,6 +500,4 @@ Init_nkf(void)
rb_define_const(mNKF, "NKF_VERSION", rb_str_new2(NKF_VERSION));
/* Release date of nkf */
rb_define_const(mNKF, "NKF_RELEASE_DATE", rb_str_new2(NKF_RELEASE_DATE));
- /* Version of nkf library */
- rb_define_const(mNKF, "GEM_VERSION", rb_str_new_cstr(NKF_GEM_VERSION));
}
diff --git a/ext/nkf/nkf.gemspec b/ext/nkf/nkf.gemspec
index 097a9485ed..7f3bd4a4b1 100644
--- a/ext/nkf/nkf.gemspec
+++ b/ext/nkf/nkf.gemspec
@@ -1,16 +1,6 @@
-source_version = ["", "ext/nkf/"].find do |dir|
- begin
- break File.open(File.join(__dir__, "#{dir}nkf.c")) {|f|
- f.gets("\n#define NKF_GEM_VERSION ")
- f.gets[/\s*"(.+)"/, 1]
- }
- rescue Errno::ENOENT
- end
-end
-
Gem::Specification.new do |spec|
spec.name = "nkf"
- spec.version = source_version
+ spec.version = "0.1.2"
spec.authors = ["NARUSE Yui"]
spec.email = ["naruse@airemix.jp"]
@@ -31,5 +21,4 @@ Gem::Specification.new do |spec|
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
- spec.extensions = ["ext/nkf/extconf.rb"]
end
diff --git a/ext/objspace/depend b/ext/objspace/depend
index 40c2f90a3c..52797664e0 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -2,12 +2,10 @@
object_tracing.o: $(RUBY_EXTCONF_H)
object_tracing.o: $(arch_hdrdir)/ruby/config.h
object_tracing.o: $(hdrdir)/ruby/assert.h
-object_tracing.o: $(hdrdir)/ruby/atomic.h
object_tracing.o: $(hdrdir)/ruby/backward.h
object_tracing.o: $(hdrdir)/ruby/backward/2/assume.h
object_tracing.o: $(hdrdir)/ruby/backward/2/attributes.h
object_tracing.o: $(hdrdir)/ruby/backward/2/bool.h
-object_tracing.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
object_tracing.o: $(hdrdir)/ruby/backward/2/inttypes.h
object_tracing.o: $(hdrdir)/ruby/backward/2/limits.h
object_tracing.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -15,7 +13,6 @@ object_tracing.o: $(hdrdir)/ruby/backward/2/stdalign.h
object_tracing.o: $(hdrdir)/ruby/backward/2/stdarg.h
object_tracing.o: $(hdrdir)/ruby/debug.h
object_tracing.o: $(hdrdir)/ruby/defines.h
-object_tracing.o: $(hdrdir)/ruby/encoding.h
object_tracing.o: $(hdrdir)/ruby/intern.h
object_tracing.o: $(hdrdir)/ruby/internal/abi.h
object_tracing.o: $(hdrdir)/ruby/internal/anyargs.h
@@ -55,7 +52,6 @@ object_tracing.o: $(hdrdir)/ruby/internal/attr/noexcept.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/noinline.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/nonnull.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-object_tracing.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/pure.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/restrict.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -88,15 +84,6 @@ object_tracing.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
object_tracing.o: $(hdrdir)/ruby/internal/ctype.h
object_tracing.o: $(hdrdir)/ruby/internal/dllexport.h
object_tracing.o: $(hdrdir)/ruby/internal/dosish.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/re.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/string.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/transcode.h
object_tracing.o: $(hdrdir)/ruby/internal/error.h
object_tracing.o: $(hdrdir)/ruby/internal/eval.h
object_tracing.o: $(hdrdir)/ruby/internal/event.h
@@ -124,6 +111,7 @@ object_tracing.o: $(hdrdir)/ruby/internal/intern/enumerator.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/error.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/eval.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/file.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/gc.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/hash.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/io.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -154,6 +142,7 @@ object_tracing.o: $(hdrdir)/ruby/internal/memory.h
object_tracing.o: $(hdrdir)/ruby/internal/method.h
object_tracing.o: $(hdrdir)/ruby/internal/module.h
object_tracing.o: $(hdrdir)/ruby/internal/newobj.h
+object_tracing.o: $(hdrdir)/ruby/internal/rgengc.h
object_tracing.o: $(hdrdir)/ruby/internal/scan_args.h
object_tracing.o: $(hdrdir)/ruby/internal/special_consts.h
object_tracing.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -166,37 +155,13 @@ object_tracing.o: $(hdrdir)/ruby/internal/variable.h
object_tracing.o: $(hdrdir)/ruby/internal/warning_push.h
object_tracing.o: $(hdrdir)/ruby/internal/xmalloc.h
object_tracing.o: $(hdrdir)/ruby/missing.h
-object_tracing.o: $(hdrdir)/ruby/onigmo.h
-object_tracing.o: $(hdrdir)/ruby/oniguruma.h
object_tracing.o: $(hdrdir)/ruby/ruby.h
object_tracing.o: $(hdrdir)/ruby/st.h
object_tracing.o: $(hdrdir)/ruby/subst.h
-object_tracing.o: $(hdrdir)/ruby/thread_native.h
-object_tracing.o: $(top_srcdir)/ccan/check_type/check_type.h
-object_tracing.o: $(top_srcdir)/ccan/container_of/container_of.h
-object_tracing.o: $(top_srcdir)/ccan/list/list.h
-object_tracing.o: $(top_srcdir)/ccan/str/str.h
+object_tracing.o: $(top_srcdir)/gc.h
object_tracing.o: $(top_srcdir)/internal.h
-object_tracing.o: $(top_srcdir)/internal/array.h
-object_tracing.o: $(top_srcdir)/internal/basic_operators.h
-object_tracing.o: $(top_srcdir)/internal/compilers.h
-object_tracing.o: $(top_srcdir)/internal/gc.h
-object_tracing.o: $(top_srcdir)/internal/imemo.h
-object_tracing.o: $(top_srcdir)/internal/serial.h
-object_tracing.o: $(top_srcdir)/internal/static_assert.h
-object_tracing.o: $(top_srcdir)/internal/vm.h
-object_tracing.o: $(top_srcdir)/internal/warnings.h
-object_tracing.o: $(top_srcdir)/method.h
-object_tracing.o: $(top_srcdir)/node.h
-object_tracing.o: $(top_srcdir)/ruby_assert.h
-object_tracing.o: $(top_srcdir)/ruby_atomic.h
-object_tracing.o: $(top_srcdir)/rubyparser.h
-object_tracing.o: $(top_srcdir)/thread_pthread.h
-object_tracing.o: $(top_srcdir)/vm_core.h
-object_tracing.o: $(top_srcdir)/vm_opts.h
object_tracing.o: object_tracing.c
object_tracing.o: objspace.h
-object_tracing.o: {$(VPATH)}id.h
objspace.o: $(RUBY_EXTCONF_H)
objspace.o: $(arch_hdrdir)/ruby/config.h
objspace.o: $(hdrdir)/ruby/assert.h
@@ -252,7 +217,6 @@ objspace.o: $(hdrdir)/ruby/internal/attr/noexcept.h
objspace.o: $(hdrdir)/ruby/internal/attr/noinline.h
objspace.o: $(hdrdir)/ruby/internal/attr/nonnull.h
objspace.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-objspace.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
objspace.o: $(hdrdir)/ruby/internal/attr/pure.h
objspace.o: $(hdrdir)/ruby/internal/attr/restrict.h
objspace.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -322,6 +286,7 @@ objspace.o: $(hdrdir)/ruby/internal/intern/enumerator.h
objspace.o: $(hdrdir)/ruby/internal/intern/error.h
objspace.o: $(hdrdir)/ruby/internal/intern/eval.h
objspace.o: $(hdrdir)/ruby/internal/intern/file.h
+objspace.o: $(hdrdir)/ruby/internal/intern/gc.h
objspace.o: $(hdrdir)/ruby/internal/intern/hash.h
objspace.o: $(hdrdir)/ruby/internal/intern/io.h
objspace.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -352,6 +317,7 @@ objspace.o: $(hdrdir)/ruby/internal/memory.h
objspace.o: $(hdrdir)/ruby/internal/method.h
objspace.o: $(hdrdir)/ruby/internal/module.h
objspace.o: $(hdrdir)/ruby/internal/newobj.h
+objspace.o: $(hdrdir)/ruby/internal/rgengc.h
objspace.o: $(hdrdir)/ruby/internal/scan_args.h
objspace.o: $(hdrdir)/ruby/internal/special_consts.h
objspace.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -377,7 +343,7 @@ objspace.o: $(top_srcdir)/ccan/check_type/check_type.h
objspace.o: $(top_srcdir)/ccan/container_of/container_of.h
objspace.o: $(top_srcdir)/ccan/list/list.h
objspace.o: $(top_srcdir)/ccan/str/str.h
-objspace.o: $(top_srcdir)/constant.h
+objspace.o: $(top_srcdir)/gc.h
objspace.o: $(top_srcdir)/id_table.h
objspace.o: $(top_srcdir)/internal.h
objspace.o: $(top_srcdir)/internal/array.h
@@ -390,14 +356,12 @@ objspace.o: $(top_srcdir)/internal/imemo.h
objspace.o: $(top_srcdir)/internal/sanitizers.h
objspace.o: $(top_srcdir)/internal/serial.h
objspace.o: $(top_srcdir)/internal/static_assert.h
-objspace.o: $(top_srcdir)/internal/variable.h
objspace.o: $(top_srcdir)/internal/vm.h
objspace.o: $(top_srcdir)/internal/warnings.h
objspace.o: $(top_srcdir)/method.h
objspace.o: $(top_srcdir)/node.h
objspace.o: $(top_srcdir)/ruby_assert.h
objspace.o: $(top_srcdir)/ruby_atomic.h
-objspace.o: $(top_srcdir)/rubyparser.h
objspace.o: $(top_srcdir)/shape.h
objspace.o: $(top_srcdir)/symbol.h
objspace.o: $(top_srcdir)/thread_pthread.h
@@ -461,7 +425,6 @@ objspace_dump.o: $(hdrdir)/ruby/internal/attr/noexcept.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/noinline.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/nonnull.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-objspace_dump.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/pure.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/restrict.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -530,6 +493,7 @@ objspace_dump.o: $(hdrdir)/ruby/internal/intern/enumerator.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/error.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/eval.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/file.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/gc.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/hash.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/io.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -560,6 +524,7 @@ objspace_dump.o: $(hdrdir)/ruby/internal/memory.h
objspace_dump.o: $(hdrdir)/ruby/internal/method.h
objspace_dump.o: $(hdrdir)/ruby/internal/module.h
objspace_dump.o: $(hdrdir)/ruby/internal/newobj.h
+objspace_dump.o: $(hdrdir)/ruby/internal/rgengc.h
objspace_dump.o: $(hdrdir)/ruby/internal/scan_args.h
objspace_dump.o: $(hdrdir)/ruby/internal/special_consts.h
objspace_dump.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -585,7 +550,7 @@ objspace_dump.o: $(top_srcdir)/ccan/container_of/container_of.h
objspace_dump.o: $(top_srcdir)/ccan/list/list.h
objspace_dump.o: $(top_srcdir)/ccan/str/str.h
objspace_dump.o: $(top_srcdir)/constant.h
-objspace_dump.o: $(top_srcdir)/debug_counter.h
+objspace_dump.o: $(top_srcdir)/gc.h
objspace_dump.o: $(top_srcdir)/id_table.h
objspace_dump.o: $(top_srcdir)/internal.h
objspace_dump.o: $(top_srcdir)/internal/array.h
@@ -595,7 +560,6 @@ objspace_dump.o: $(top_srcdir)/internal/compilers.h
objspace_dump.o: $(top_srcdir)/internal/gc.h
objspace_dump.o: $(top_srcdir)/internal/hash.h
objspace_dump.o: $(top_srcdir)/internal/imemo.h
-objspace_dump.o: $(top_srcdir)/internal/io.h
objspace_dump.o: $(top_srcdir)/internal/sanitizers.h
objspace_dump.o: $(top_srcdir)/internal/serial.h
objspace_dump.o: $(top_srcdir)/internal/static_assert.h
@@ -607,11 +571,9 @@ objspace_dump.o: $(top_srcdir)/method.h
objspace_dump.o: $(top_srcdir)/node.h
objspace_dump.o: $(top_srcdir)/ruby_assert.h
objspace_dump.o: $(top_srcdir)/ruby_atomic.h
-objspace_dump.o: $(top_srcdir)/rubyparser.h
objspace_dump.o: $(top_srcdir)/shape.h
objspace_dump.o: $(top_srcdir)/symbol.h
objspace_dump.o: $(top_srcdir)/thread_pthread.h
-objspace_dump.o: $(top_srcdir)/vm_callinfo.h
objspace_dump.o: $(top_srcdir)/vm_core.h
objspace_dump.o: $(top_srcdir)/vm_opts.h
objspace_dump.o: objspace.h
diff --git a/ext/objspace/lib/objspace.rb b/ext/objspace/lib/objspace.rb
index 47873f5112..6865fdda4c 100644
--- a/ext/objspace/lib/objspace.rb
+++ b/ext/objspace/lib/objspace.rb
@@ -11,15 +11,12 @@ module ObjectSpace
module_function
- # Dump the contents of a ruby object as JSON.
- #
- # _output_ can be one of: +:stdout+, +:file+, +:string+, or IO object.
+ # call-seq:
+ # ObjectSpace.dump(obj[, output: :string]) -> "{ ... }"
+ # ObjectSpace.dump(obj, output: :file) -> #<File:/tmp/rubyobj20131125-88733-1xkfmpv.json>
+ # ObjectSpace.dump(obj, output: :stdout) -> nil
#
- # * +:file+ means dumping to a tempfile and returning corresponding File object;
- # * +:stdout+ means printing the dump and returning +nil+;
- # * +:string+ means returning a string with the dump;
- # * if an instance of IO object is provided, the output goes there, and the object
- # is returned.
+ # Dump the contents of a ruby object as JSON.
#
# This method is only expected to work with C Ruby.
# This is an experimental method and is subject to change.
@@ -46,11 +43,16 @@ module ObjectSpace
end
- # Dump the contents of the ruby heap as JSON.
+ # call-seq:
+ # ObjectSpace.dump_all([output: :file]) -> #<File:/tmp/rubyheap20131125-88469-laoj3v.json>
+ # ObjectSpace.dump_all(output: :stdout) -> nil
+ # ObjectSpace.dump_all(output: :string) -> "{...}\n{...}\n..."
+ # ObjectSpace.dump_all(output: File.open('heap.json','w')) -> #<File:heap.json>
+ # ObjectSpace.dump_all(output: :string, since: 42) -> "{...}\n{...}\n..."
#
- # _output_ argument is the same as for #dump.
+ # Dump the contents of the ruby heap as JSON.
#
- # _full_ must be a boolean. If true, all heap slots are dumped including the empty ones (+T_NONE+).
+ # _full_ must be a boolean. If true all heap slots are dumped including the empty ones (T_NONE).
#
# _since_ must be a non-negative integer or +nil+.
#
@@ -102,11 +104,16 @@ module ObjectSpace
ret
end
- # Dump the contents of the ruby shape tree as JSON.
+ # call-seq:
+ # ObjectSpace.dump_shapes([output: :file]) -> #<File:/tmp/rubyshapes20131125-88469-laoj3v.json>
+ # ObjectSpace.dump_shapes(output: :stdout) -> nil
+ # ObjectSpace.dump_shapes(output: :string) -> "{...}\n{...}\n..."
+ # ObjectSpace.dump_shapes(output: File.open('shapes.json','w')) -> #<File:shapes.json>
+ # ObjectSpace.dump_all(output: :string, since: 42) -> "{...}\n{...}\n..."
#
- # _output_ argument is the same as for #dump.
+ # Dump the contents of the ruby shape tree as JSON.
#
- # If _since_ is a positive integer, only shapes newer than the provided
+ # If _shapes_ is a positive integer, only shapes newer than the provided
# shape id are dumped. The current shape_id can be accessed using <tt>RubyVM.stat(:next_shape_id)</tt>.
#
# This method is only expected to work with C Ruby.
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index c1c93c51f5..8c54d51eab 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -13,8 +13,8 @@
**********************************************************************/
+#include "gc.h"
#include "internal.h"
-#include "internal/gc.h"
#include "ruby/debug.h"
#include "objspace.h"
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index ae869a3ed4..ca08604c95 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -12,10 +12,10 @@
**********************************************************************/
+#include "gc.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/compilers.h"
-#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/imemo.h"
#include "internal/sanitizers.h"
@@ -434,6 +434,7 @@ count_nodes(int argc, VALUE *argv, VALUE os)
COUNT_NODE(NODE_ZSUPER);
COUNT_NODE(NODE_LIST);
COUNT_NODE(NODE_ZLIST);
+ COUNT_NODE(NODE_VALUES);
COUNT_NODE(NODE_HASH);
COUNT_NODE(NODE_RETURN);
COUNT_NODE(NODE_YIELD);
@@ -492,8 +493,6 @@ count_nodes(int argc, VALUE *argv, VALUE os)
COUNT_NODE(NODE_ARYPTN);
COUNT_NODE(NODE_FNDPTN);
COUNT_NODE(NODE_HSHPTN);
- COUNT_NODE(NODE_RIPPER);
- COUNT_NODE(NODE_RIPPER_VALUES);
COUNT_NODE(NODE_ERROR);
#undef COUNT_NODE
case NODE_LAST: break;
@@ -955,7 +954,7 @@ void Init_objspace_dump(VALUE rb_mObjSpace);
*
* You need to <code>require 'objspace'</code> to use this extension module.
*
- * Generally, you *SHOULD* *NOT* use this library if you do not know
+ * Generally, you *SHOULD NOT* use this library if you do not know
* about the MRI implementation. Mainly, this library is for (memory)
* profiler developers and MRI developers who need to know about MRI
* memory usage.
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index c80c38eba4..c3cc9a1e7b 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -12,13 +12,12 @@
**********************************************************************/
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/array.h"
#include "internal/class.h"
-#include "internal/gc.h"
#include "internal/hash.h"
-#include "internal/io.h"
#include "internal/string.h"
#include "internal/sanitizers.h"
#include "symbol.h"
@@ -28,7 +27,6 @@
#include "ruby/debug.h"
#include "ruby/util.h"
#include "ruby/io.h"
-#include "vm_callinfo.h"
#include "vm_core.h"
RUBY_EXTERN const char ruby_hexdigits[];
@@ -379,7 +377,6 @@ dump_object(VALUE obj, struct dump_config *dc)
rb_io_t *fptr;
ID flags[RB_OBJ_GC_FLAGS_MAX];
size_t n, i;
- ID mid;
if (SPECIAL_CONST_P(obj)) {
dump_append_special_const(dc, obj);
@@ -431,19 +428,6 @@ dump_object(VALUE obj, struct dump_config *dc)
dump_append(dc, ", \"imemo_type\":\"");
dump_append(dc, rb_imemo_name(imemo_type(obj)));
dump_append(dc, "\"");
-
- switch (imemo_type(obj)) {
- case imemo_callinfo:
- mid = vm_ci_mid((const struct rb_callinfo *)obj);
- if (mid != 0) {
- dump_append(dc, ", \"mid\":");
- dump_append_string_value(dc, rb_id2str(mid));
- }
- break;
-
- default:
- break;
- }
break;
case T_SYMBOL:
@@ -560,10 +544,6 @@ dump_object(VALUE obj, struct dump_config *dc)
break;
case T_OBJECT:
- if (FL_TEST(obj, ROBJECT_EMBED)) {
- dump_append(dc, ", \"embedded\":true");
- }
-
dump_append(dc, ", \"ivars\":");
dump_append_lu(dc, ROBJECT_IV_COUNT(obj));
if (rb_shape_obj_too_complex(obj)) {
@@ -776,6 +756,11 @@ shape_i(rb_shape_t *shape, void *data)
dump_append(dc, ", \"capacity\":");
dump_append_sizet(dc, shape->capacity);
break;
+ case SHAPE_INITIAL_CAPACITY:
+ dump_append(dc, "\"INITIAL_CAPACITY\"");
+ dump_append(dc, ", \"capacity\":");
+ dump_append_sizet(dc, shape->capacity);
+ break;
case SHAPE_T_OBJECT:
dump_append(dc, "\"T_OBJECT\"");
break;
diff --git a/ext/openssl/History.md b/ext/openssl/History.md
index bd7b1ec1b1..1e0df7dd87 100644
--- a/ext/openssl/History.md
+++ b/ext/openssl/History.md
@@ -1,43 +1,3 @@
-Version 3.2.0
-=============
-
-Compatibility
--------------
-
-* Ruby >= 2.7
- - Support for Ruby 2.6 has been removed. Note that Ruby 2.6 reached the
- end-of-life in 2022-04.
- [[GitHub #639]](https://github.com/ruby/openssl/pull/639)
-* OpenSSL >= 1.0.2 or LibreSSL >= 3.1
-
-Notable changes
----------------
-
-* Add a stub gemspec for JRuby, which depends on the `jruby-openssl` gem.
- [[GitHub #598]](https://github.com/ruby/openssl/pull/598)
-* Add support for the FIPS module in OpenSSL 3.0/3.1.
- [[GitHub #608]](https://github.com/ruby/openssl/pull/608)
-* Rework `OpenSSL::PKey` routines for loading DER or PEM encoded keys for better
- compatibility with OpenSSL 3.0/3.1 with the FIPS module.
- [[GitHub #615]](https://github.com/ruby/openssl/pull/615)
- [[GitHub #669]](https://github.com/ruby/openssl/pull/669)
-* Add `OpenSSL::Provider` module for loading and unloading OpenSSL 3 providers.
- [[GitHub #635]](https://github.com/ruby/openssl/pull/635)
-* Add `OpenSSL::PKey.new_raw_private_key`, `.new_raw_public_key`,
- `OpenSSL::PKey::PKey#raw_private_key`, and `#raw_public_key` for public key
- algorithms that use "raw private/public key", such as X25519 and Ed25519.
- [[GitHub #646]](https://github.com/ruby/openssl/pull/646)
-* Improve OpenSSL error messages to include additional information when
- it is available in OpenSSL's error queue.
- [[GitHub #648]](https://github.com/ruby/openssl/pull/648)
-* Change `OpenSSL::SSL::SSLContext#ca_file=` and `#ca_path=` to raise
- `OpenSSL::SSL::SSLError` instead of printing a warning message.
- [[GitHub #659]](https://github.com/ruby/openssl/pull/659)
-* Allow `OpenSSL::X509::ExtensionFactory#create_extension` to take OIDs in the
- dotted-decimal notation.
- [[GitHub #141]](https://github.com/ruby/openssl/pull/141)
-
-
Version 3.1.0
=============
diff --git a/ext/openssl/depend b/ext/openssl/depend
index 0d03c85b80..c38d224c85 100644
--- a/ext/openssl/depend
+++ b/ext/openssl/depend
@@ -57,7 +57,6 @@ ossl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -126,6 +125,7 @@ ossl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl.o: $(hdrdir)/ruby/internal/intern/error.h
ossl.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl.o: $(hdrdir)/ruby/internal/intern/io.h
ossl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -156,6 +156,7 @@ ossl.o: $(hdrdir)/ruby/internal/memory.h
ossl.o: $(hdrdir)/ruby/internal/method.h
ossl.o: $(hdrdir)/ruby/internal/module.h
ossl.o: $(hdrdir)/ruby/internal/newobj.h
+ossl.o: $(hdrdir)/ruby/internal/rgengc.h
ossl.o: $(hdrdir)/ruby/internal/scan_args.h
ossl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -192,7 +193,6 @@ ossl.o: ossl_ocsp.h
ossl.o: ossl_pkcs12.h
ossl.o: ossl_pkcs7.h
ossl.o: ossl_pkey.h
-ossl.o: ossl_provider.h
ossl.o: ossl_rand.h
ossl.o: ossl_ssl.h
ossl.o: ossl_ts.h
@@ -251,7 +251,6 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_asn1.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -320,6 +319,7 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_asn1.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -350,6 +350,7 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/memory.h
ossl_asn1.o: $(hdrdir)/ruby/internal/method.h
ossl_asn1.o: $(hdrdir)/ruby/internal/module.h
ossl_asn1.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_asn1.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_asn1.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_asn1.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_asn1.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -386,7 +387,6 @@ ossl_asn1.o: ossl_ocsp.h
ossl_asn1.o: ossl_pkcs12.h
ossl_asn1.o: ossl_pkcs7.h
ossl_asn1.o: ossl_pkey.h
-ossl_asn1.o: ossl_provider.h
ossl_asn1.o: ossl_rand.h
ossl_asn1.o: ossl_ssl.h
ossl_asn1.o: ossl_ts.h
@@ -445,7 +445,6 @@ ossl_bio.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_bio.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -514,6 +513,7 @@ ossl_bio.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_bio.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -544,6 +544,7 @@ ossl_bio.o: $(hdrdir)/ruby/internal/memory.h
ossl_bio.o: $(hdrdir)/ruby/internal/method.h
ossl_bio.o: $(hdrdir)/ruby/internal/module.h
ossl_bio.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_bio.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_bio.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_bio.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_bio.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -580,7 +581,6 @@ ossl_bio.o: ossl_ocsp.h
ossl_bio.o: ossl_pkcs12.h
ossl_bio.o: ossl_pkcs7.h
ossl_bio.o: ossl_pkey.h
-ossl_bio.o: ossl_provider.h
ossl_bio.o: ossl_rand.h
ossl_bio.o: ossl_ssl.h
ossl_bio.o: ossl_ts.h
@@ -639,7 +639,6 @@ ossl_bn.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_bn.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -708,6 +707,7 @@ ossl_bn.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_bn.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -738,6 +738,7 @@ ossl_bn.o: $(hdrdir)/ruby/internal/memory.h
ossl_bn.o: $(hdrdir)/ruby/internal/method.h
ossl_bn.o: $(hdrdir)/ruby/internal/module.h
ossl_bn.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_bn.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_bn.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_bn.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_bn.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -775,7 +776,6 @@ ossl_bn.o: ossl_ocsp.h
ossl_bn.o: ossl_pkcs12.h
ossl_bn.o: ossl_pkcs7.h
ossl_bn.o: ossl_pkey.h
-ossl_bn.o: ossl_provider.h
ossl_bn.o: ossl_rand.h
ossl_bn.o: ossl_ssl.h
ossl_bn.o: ossl_ts.h
@@ -834,7 +834,6 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_cipher.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -903,6 +902,7 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_cipher.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -933,6 +933,7 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/memory.h
ossl_cipher.o: $(hdrdir)/ruby/internal/method.h
ossl_cipher.o: $(hdrdir)/ruby/internal/module.h
ossl_cipher.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_cipher.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_cipher.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_cipher.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_cipher.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -969,7 +970,6 @@ ossl_cipher.o: ossl_ocsp.h
ossl_cipher.o: ossl_pkcs12.h
ossl_cipher.o: ossl_pkcs7.h
ossl_cipher.o: ossl_pkey.h
-ossl_cipher.o: ossl_provider.h
ossl_cipher.o: ossl_rand.h
ossl_cipher.o: ossl_ssl.h
ossl_cipher.o: ossl_ts.h
@@ -1028,7 +1028,6 @@ ossl_config.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_config.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1097,6 +1096,7 @@ ossl_config.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_config.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1127,6 +1127,7 @@ ossl_config.o: $(hdrdir)/ruby/internal/memory.h
ossl_config.o: $(hdrdir)/ruby/internal/method.h
ossl_config.o: $(hdrdir)/ruby/internal/module.h
ossl_config.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_config.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_config.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_config.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_config.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1163,7 +1164,6 @@ ossl_config.o: ossl_ocsp.h
ossl_config.o: ossl_pkcs12.h
ossl_config.o: ossl_pkcs7.h
ossl_config.o: ossl_pkey.h
-ossl_config.o: ossl_provider.h
ossl_config.o: ossl_rand.h
ossl_config.o: ossl_ssl.h
ossl_config.o: ossl_ts.h
@@ -1222,7 +1222,6 @@ ossl_digest.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_digest.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1291,6 +1290,7 @@ ossl_digest.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_digest.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1321,6 +1321,7 @@ ossl_digest.o: $(hdrdir)/ruby/internal/memory.h
ossl_digest.o: $(hdrdir)/ruby/internal/method.h
ossl_digest.o: $(hdrdir)/ruby/internal/module.h
ossl_digest.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_digest.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_digest.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_digest.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_digest.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1357,7 +1358,6 @@ ossl_digest.o: ossl_ocsp.h
ossl_digest.o: ossl_pkcs12.h
ossl_digest.o: ossl_pkcs7.h
ossl_digest.o: ossl_pkey.h
-ossl_digest.o: ossl_provider.h
ossl_digest.o: ossl_rand.h
ossl_digest.o: ossl_ssl.h
ossl_digest.o: ossl_ts.h
@@ -1416,7 +1416,6 @@ ossl_engine.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_engine.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1485,6 +1484,7 @@ ossl_engine.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_engine.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1515,6 +1515,7 @@ ossl_engine.o: $(hdrdir)/ruby/internal/memory.h
ossl_engine.o: $(hdrdir)/ruby/internal/method.h
ossl_engine.o: $(hdrdir)/ruby/internal/module.h
ossl_engine.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_engine.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_engine.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_engine.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_engine.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1551,7 +1552,6 @@ ossl_engine.o: ossl_ocsp.h
ossl_engine.o: ossl_pkcs12.h
ossl_engine.o: ossl_pkcs7.h
ossl_engine.o: ossl_pkey.h
-ossl_engine.o: ossl_provider.h
ossl_engine.o: ossl_rand.h
ossl_engine.o: ossl_ssl.h
ossl_engine.o: ossl_ts.h
@@ -1610,7 +1610,6 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_hmac.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1679,6 +1678,7 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_hmac.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1709,6 +1709,7 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/memory.h
ossl_hmac.o: $(hdrdir)/ruby/internal/method.h
ossl_hmac.o: $(hdrdir)/ruby/internal/module.h
ossl_hmac.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_hmac.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_hmac.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_hmac.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_hmac.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1745,7 +1746,6 @@ ossl_hmac.o: ossl_ocsp.h
ossl_hmac.o: ossl_pkcs12.h
ossl_hmac.o: ossl_pkcs7.h
ossl_hmac.o: ossl_pkey.h
-ossl_hmac.o: ossl_provider.h
ossl_hmac.o: ossl_rand.h
ossl_hmac.o: ossl_ssl.h
ossl_hmac.o: ossl_ts.h
@@ -1804,7 +1804,6 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_kdf.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1873,6 +1872,7 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_kdf.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1903,6 +1903,7 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/memory.h
ossl_kdf.o: $(hdrdir)/ruby/internal/method.h
ossl_kdf.o: $(hdrdir)/ruby/internal/module.h
ossl_kdf.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_kdf.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_kdf.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_kdf.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_kdf.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1939,7 +1940,6 @@ ossl_kdf.o: ossl_ocsp.h
ossl_kdf.o: ossl_pkcs12.h
ossl_kdf.o: ossl_pkcs7.h
ossl_kdf.o: ossl_pkey.h
-ossl_kdf.o: ossl_provider.h
ossl_kdf.o: ossl_rand.h
ossl_kdf.o: ossl_ssl.h
ossl_kdf.o: ossl_ts.h
@@ -1998,7 +1998,6 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2067,6 +2066,7 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2097,6 +2097,7 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/memory.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/method.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/module.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ns_spki.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2133,7 +2134,6 @@ ossl_ns_spki.o: ossl_ocsp.h
ossl_ns_spki.o: ossl_pkcs12.h
ossl_ns_spki.o: ossl_pkcs7.h
ossl_ns_spki.o: ossl_pkey.h
-ossl_ns_spki.o: ossl_provider.h
ossl_ns_spki.o: ossl_rand.h
ossl_ns_spki.o: ossl_ssl.h
ossl_ns_spki.o: ossl_ts.h
@@ -2192,7 +2192,6 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2261,6 +2260,7 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2291,6 +2291,7 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/memory.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/method.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/module.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ocsp.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2327,7 +2328,6 @@ ossl_ocsp.o: ossl_ocsp.h
ossl_ocsp.o: ossl_pkcs12.h
ossl_ocsp.o: ossl_pkcs7.h
ossl_ocsp.o: ossl_pkey.h
-ossl_ocsp.o: ossl_provider.h
ossl_ocsp.o: ossl_rand.h
ossl_ocsp.o: ossl_ssl.h
ossl_ocsp.o: ossl_ts.h
@@ -2386,7 +2386,6 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2455,6 +2454,7 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2485,6 +2485,7 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/method.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/module.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkcs12.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2521,7 +2522,6 @@ ossl_pkcs12.o: ossl_pkcs12.c
ossl_pkcs12.o: ossl_pkcs12.h
ossl_pkcs12.o: ossl_pkcs7.h
ossl_pkcs12.o: ossl_pkey.h
-ossl_pkcs12.o: ossl_provider.h
ossl_pkcs12.o: ossl_rand.h
ossl_pkcs12.o: ossl_ssl.h
ossl_pkcs12.o: ossl_ts.h
@@ -2580,7 +2580,6 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2649,6 +2648,7 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2679,6 +2679,7 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/method.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/module.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkcs7.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2715,7 +2716,6 @@ ossl_pkcs7.o: ossl_pkcs12.h
ossl_pkcs7.o: ossl_pkcs7.c
ossl_pkcs7.o: ossl_pkcs7.h
ossl_pkcs7.o: ossl_pkey.h
-ossl_pkcs7.o: ossl_provider.h
ossl_pkcs7.o: ossl_rand.h
ossl_pkcs7.o: ossl_ssl.h
ossl_pkcs7.o: ossl_ts.h
@@ -2774,7 +2774,6 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2843,6 +2842,7 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2873,6 +2873,7 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2909,7 +2910,6 @@ ossl_pkey.o: ossl_pkcs12.h
ossl_pkey.o: ossl_pkcs7.h
ossl_pkey.o: ossl_pkey.c
ossl_pkey.o: ossl_pkey.h
-ossl_pkey.o: ossl_provider.h
ossl_pkey.o: ossl_rand.h
ossl_pkey.o: ossl_ssl.h
ossl_pkey.o: ossl_ts.h
@@ -2968,7 +2968,6 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3037,6 +3036,7 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3067,6 +3067,7 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_dh.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -3103,7 +3104,6 @@ ossl_pkey_dh.o: ossl_pkcs12.h
ossl_pkey_dh.o: ossl_pkcs7.h
ossl_pkey_dh.o: ossl_pkey.h
ossl_pkey_dh.o: ossl_pkey_dh.c
-ossl_pkey_dh.o: ossl_provider.h
ossl_pkey_dh.o: ossl_rand.h
ossl_pkey_dh.o: ossl_ssl.h
ossl_pkey_dh.o: ossl_ts.h
@@ -3162,7 +3162,6 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3231,6 +3230,7 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3261,6 +3261,7 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -3297,7 +3298,6 @@ ossl_pkey_dsa.o: ossl_pkcs12.h
ossl_pkey_dsa.o: ossl_pkcs7.h
ossl_pkey_dsa.o: ossl_pkey.h
ossl_pkey_dsa.o: ossl_pkey_dsa.c
-ossl_pkey_dsa.o: ossl_provider.h
ossl_pkey_dsa.o: ossl_rand.h
ossl_pkey_dsa.o: ossl_ssl.h
ossl_pkey_dsa.o: ossl_ts.h
@@ -3356,7 +3356,6 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3425,6 +3424,7 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3455,6 +3455,7 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_ec.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -3491,7 +3492,6 @@ ossl_pkey_ec.o: ossl_pkcs12.h
ossl_pkey_ec.o: ossl_pkcs7.h
ossl_pkey_ec.o: ossl_pkey.h
ossl_pkey_ec.o: ossl_pkey_ec.c
-ossl_pkey_ec.o: ossl_provider.h
ossl_pkey_ec.o: ossl_rand.h
ossl_pkey_ec.o: ossl_ssl.h
ossl_pkey_ec.o: ossl_ts.h
@@ -3550,7 +3550,6 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3619,6 +3618,7 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3649,6 +3649,7 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -3685,205 +3686,10 @@ ossl_pkey_rsa.o: ossl_pkcs12.h
ossl_pkey_rsa.o: ossl_pkcs7.h
ossl_pkey_rsa.o: ossl_pkey.h
ossl_pkey_rsa.o: ossl_pkey_rsa.c
-ossl_pkey_rsa.o: ossl_provider.h
ossl_pkey_rsa.o: ossl_rand.h
ossl_pkey_rsa.o: ossl_ssl.h
ossl_pkey_rsa.o: ossl_ts.h
ossl_pkey_rsa.o: ossl_x509.h
-ossl_provider.o: $(RUBY_EXTCONF_H)
-ossl_provider.o: $(arch_hdrdir)/ruby/config.h
-ossl_provider.o: $(hdrdir)/ruby.h
-ossl_provider.o: $(hdrdir)/ruby/assert.h
-ossl_provider.o: $(hdrdir)/ruby/backward.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/assume.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/attributes.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/bool.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/inttypes.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/limits.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/long_long.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/stdalign.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/stdarg.h
-ossl_provider.o: $(hdrdir)/ruby/defines.h
-ossl_provider.o: $(hdrdir)/ruby/encoding.h
-ossl_provider.o: $(hdrdir)/ruby/intern.h
-ossl_provider.o: $(hdrdir)/ruby/internal/abi.h
-ossl_provider.o: $(hdrdir)/ruby/internal/anyargs.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/assume.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/artificial.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/cold.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/const.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/error.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/format.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noalias.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noinline.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/pure.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/restrict.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/warning.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/weakref.h
-ossl_provider.o: $(hdrdir)/ruby/internal/cast.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_since.h
-ossl_provider.o: $(hdrdir)/ruby/internal/config.h
-ossl_provider.o: $(hdrdir)/ruby/internal/constant_p.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rarray.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rbasic.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rbignum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rclass.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rdata.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rfile.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rhash.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/robject.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rregexp.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rstring.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rstruct.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-ossl_provider.o: $(hdrdir)/ruby/internal/ctype.h
-ossl_provider.o: $(hdrdir)/ruby/internal/dllexport.h
-ossl_provider.o: $(hdrdir)/ruby/internal/dosish.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/re.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/string.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-ossl_provider.o: $(hdrdir)/ruby/internal/error.h
-ossl_provider.o: $(hdrdir)/ruby/internal/eval.h
-ossl_provider.o: $(hdrdir)/ruby/internal/event.h
-ossl_provider.o: $(hdrdir)/ruby/internal/fl_type.h
-ossl_provider.o: $(hdrdir)/ruby/internal/gc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/glob.h
-ossl_provider.o: $(hdrdir)/ruby/internal/globals.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/builtin.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/extension.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/feature.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/warning.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/array.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/bignum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/class.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/compar.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/complex.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/cont.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/dir.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/enum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/error.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/eval.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/file.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/hash.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/io.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/load.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/marshal.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/numeric.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/object.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/parse.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/proc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/process.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/random.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/range.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/rational.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/re.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/ruby.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/select.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/signal.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/string.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/struct.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/thread.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/time.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/variable.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/vm.h
-ossl_provider.o: $(hdrdir)/ruby/internal/interpreter.h
-ossl_provider.o: $(hdrdir)/ruby/internal/iterator.h
-ossl_provider.o: $(hdrdir)/ruby/internal/memory.h
-ossl_provider.o: $(hdrdir)/ruby/internal/method.h
-ossl_provider.o: $(hdrdir)/ruby/internal/module.h
-ossl_provider.o: $(hdrdir)/ruby/internal/newobj.h
-ossl_provider.o: $(hdrdir)/ruby/internal/scan_args.h
-ossl_provider.o: $(hdrdir)/ruby/internal/special_consts.h
-ossl_provider.o: $(hdrdir)/ruby/internal/static_assert.h
-ossl_provider.o: $(hdrdir)/ruby/internal/stdalign.h
-ossl_provider.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_provider.o: $(hdrdir)/ruby/internal/symbol.h
-ossl_provider.o: $(hdrdir)/ruby/internal/value.h
-ossl_provider.o: $(hdrdir)/ruby/internal/value_type.h
-ossl_provider.o: $(hdrdir)/ruby/internal/variable.h
-ossl_provider.o: $(hdrdir)/ruby/internal/warning_push.h
-ossl_provider.o: $(hdrdir)/ruby/internal/xmalloc.h
-ossl_provider.o: $(hdrdir)/ruby/io.h
-ossl_provider.o: $(hdrdir)/ruby/missing.h
-ossl_provider.o: $(hdrdir)/ruby/onigmo.h
-ossl_provider.o: $(hdrdir)/ruby/oniguruma.h
-ossl_provider.o: $(hdrdir)/ruby/ruby.h
-ossl_provider.o: $(hdrdir)/ruby/st.h
-ossl_provider.o: $(hdrdir)/ruby/subst.h
-ossl_provider.o: $(hdrdir)/ruby/thread.h
-ossl_provider.o: openssl_missing.h
-ossl_provider.o: ossl.h
-ossl_provider.o: ossl_asn1.h
-ossl_provider.o: ossl_bio.h
-ossl_provider.o: ossl_bn.h
-ossl_provider.o: ossl_cipher.h
-ossl_provider.o: ossl_config.h
-ossl_provider.o: ossl_digest.h
-ossl_provider.o: ossl_engine.h
-ossl_provider.o: ossl_hmac.h
-ossl_provider.o: ossl_kdf.h
-ossl_provider.o: ossl_ns_spki.h
-ossl_provider.o: ossl_ocsp.h
-ossl_provider.o: ossl_pkcs12.h
-ossl_provider.o: ossl_pkcs7.h
-ossl_provider.o: ossl_pkey.h
-ossl_provider.o: ossl_provider.c
-ossl_provider.o: ossl_provider.h
-ossl_provider.o: ossl_rand.h
-ossl_provider.o: ossl_ssl.h
-ossl_provider.o: ossl_ts.h
-ossl_provider.o: ossl_x509.h
ossl_rand.o: $(RUBY_EXTCONF_H)
ossl_rand.o: $(arch_hdrdir)/ruby/config.h
ossl_rand.o: $(hdrdir)/ruby.h
@@ -3938,7 +3744,6 @@ ossl_rand.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_rand.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4007,6 +3812,7 @@ ossl_rand.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_rand.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4037,6 +3843,7 @@ ossl_rand.o: $(hdrdir)/ruby/internal/memory.h
ossl_rand.o: $(hdrdir)/ruby/internal/method.h
ossl_rand.o: $(hdrdir)/ruby/internal/module.h
ossl_rand.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_rand.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_rand.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_rand.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_rand.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -4072,7 +3879,6 @@ ossl_rand.o: ossl_ocsp.h
ossl_rand.o: ossl_pkcs12.h
ossl_rand.o: ossl_pkcs7.h
ossl_rand.o: ossl_pkey.h
-ossl_rand.o: ossl_provider.h
ossl_rand.o: ossl_rand.c
ossl_rand.o: ossl_rand.h
ossl_rand.o: ossl_ssl.h
@@ -4132,7 +3938,6 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ssl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4201,6 +4006,7 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ssl.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4231,6 +4037,7 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/memory.h
ossl_ssl.o: $(hdrdir)/ruby/internal/method.h
ossl_ssl.o: $(hdrdir)/ruby/internal/module.h
ossl_ssl.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ssl.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ssl.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ssl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ssl.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -4266,7 +4073,6 @@ ossl_ssl.o: ossl_ocsp.h
ossl_ssl.o: ossl_pkcs12.h
ossl_ssl.o: ossl_pkcs7.h
ossl_ssl.o: ossl_pkey.h
-ossl_ssl.o: ossl_provider.h
ossl_ssl.o: ossl_rand.h
ossl_ssl.o: ossl_ssl.c
ossl_ssl.o: ossl_ssl.h
@@ -4326,7 +4132,6 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4395,6 +4200,7 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4425,6 +4231,7 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/memory.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/method.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/module.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ssl_session.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -4460,7 +4267,6 @@ ossl_ssl_session.o: ossl_ocsp.h
ossl_ssl_session.o: ossl_pkcs12.h
ossl_ssl_session.o: ossl_pkcs7.h
ossl_ssl_session.o: ossl_pkey.h
-ossl_ssl_session.o: ossl_provider.h
ossl_ssl_session.o: ossl_rand.h
ossl_ssl_session.o: ossl_ssl.h
ossl_ssl_session.o: ossl_ssl_session.c
@@ -4520,7 +4326,6 @@ ossl_ts.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ts.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4589,6 +4394,7 @@ ossl_ts.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ts.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4619,6 +4425,7 @@ ossl_ts.o: $(hdrdir)/ruby/internal/memory.h
ossl_ts.o: $(hdrdir)/ruby/internal/method.h
ossl_ts.o: $(hdrdir)/ruby/internal/module.h
ossl_ts.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ts.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ts.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ts.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ts.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -4654,7 +4461,6 @@ ossl_ts.o: ossl_ocsp.h
ossl_ts.o: ossl_pkcs12.h
ossl_ts.o: ossl_pkcs7.h
ossl_ts.o: ossl_pkey.h
-ossl_ts.o: ossl_provider.h
ossl_ts.o: ossl_rand.h
ossl_ts.o: ossl_ssl.h
ossl_ts.o: ossl_ts.c
@@ -4714,7 +4520,6 @@ ossl_x509.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4783,6 +4588,7 @@ ossl_x509.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4813,6 +4619,7 @@ ossl_x509.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509.o: $(hdrdir)/ruby/internal/method.h
ossl_x509.o: $(hdrdir)/ruby/internal/module.h
ossl_x509.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -4848,7 +4655,6 @@ ossl_x509.o: ossl_ocsp.h
ossl_x509.o: ossl_pkcs12.h
ossl_x509.o: ossl_pkcs7.h
ossl_x509.o: ossl_pkey.h
-ossl_x509.o: ossl_provider.h
ossl_x509.o: ossl_rand.h
ossl_x509.o: ossl_ssl.h
ossl_x509.o: ossl_ts.h
@@ -4908,7 +4714,6 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4977,6 +4782,7 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5007,6 +4813,7 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/method.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/module.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509attr.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -5042,7 +4849,6 @@ ossl_x509attr.o: ossl_ocsp.h
ossl_x509attr.o: ossl_pkcs12.h
ossl_x509attr.o: ossl_pkcs7.h
ossl_x509attr.o: ossl_pkey.h
-ossl_x509attr.o: ossl_provider.h
ossl_x509attr.o: ossl_rand.h
ossl_x509attr.o: ossl_ssl.h
ossl_x509attr.o: ossl_ts.h
@@ -5102,7 +4908,6 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5171,6 +4976,7 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5201,6 +5007,7 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/method.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/module.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509cert.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -5236,7 +5043,6 @@ ossl_x509cert.o: ossl_ocsp.h
ossl_x509cert.o: ossl_pkcs12.h
ossl_x509cert.o: ossl_pkcs7.h
ossl_x509cert.o: ossl_pkey.h
-ossl_x509cert.o: ossl_provider.h
ossl_x509cert.o: ossl_rand.h
ossl_x509cert.o: ossl_ssl.h
ossl_x509cert.o: ossl_ts.h
@@ -5296,7 +5102,6 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5365,6 +5170,7 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5395,6 +5201,7 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/method.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/module.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509crl.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -5430,7 +5237,6 @@ ossl_x509crl.o: ossl_ocsp.h
ossl_x509crl.o: ossl_pkcs12.h
ossl_x509crl.o: ossl_pkcs7.h
ossl_x509crl.o: ossl_pkey.h
-ossl_x509crl.o: ossl_provider.h
ossl_x509crl.o: ossl_rand.h
ossl_x509crl.o: ossl_ssl.h
ossl_x509crl.o: ossl_ts.h
@@ -5490,7 +5296,6 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5559,6 +5364,7 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5589,6 +5395,7 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/method.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/module.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509ext.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -5624,7 +5431,6 @@ ossl_x509ext.o: ossl_ocsp.h
ossl_x509ext.o: ossl_pkcs12.h
ossl_x509ext.o: ossl_pkcs7.h
ossl_x509ext.o: ossl_pkey.h
-ossl_x509ext.o: ossl_provider.h
ossl_x509ext.o: ossl_rand.h
ossl_x509ext.o: ossl_ssl.h
ossl_x509ext.o: ossl_ts.h
@@ -5684,7 +5490,6 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509name.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5753,6 +5558,7 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509name.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5783,6 +5589,7 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509name.o: $(hdrdir)/ruby/internal/method.h
ossl_x509name.o: $(hdrdir)/ruby/internal/module.h
ossl_x509name.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509name.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509name.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509name.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509name.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -5818,7 +5625,6 @@ ossl_x509name.o: ossl_ocsp.h
ossl_x509name.o: ossl_pkcs12.h
ossl_x509name.o: ossl_pkcs7.h
ossl_x509name.o: ossl_pkey.h
-ossl_x509name.o: ossl_provider.h
ossl_x509name.o: ossl_rand.h
ossl_x509name.o: ossl_ssl.h
ossl_x509name.o: ossl_ts.h
@@ -5878,7 +5684,6 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509req.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5947,6 +5752,7 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509req.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5977,6 +5783,7 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509req.o: $(hdrdir)/ruby/internal/method.h
ossl_x509req.o: $(hdrdir)/ruby/internal/module.h
ossl_x509req.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509req.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509req.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509req.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509req.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -6012,7 +5819,6 @@ ossl_x509req.o: ossl_ocsp.h
ossl_x509req.o: ossl_pkcs12.h
ossl_x509req.o: ossl_pkcs7.h
ossl_x509req.o: ossl_pkey.h
-ossl_x509req.o: ossl_provider.h
ossl_x509req.o: ossl_rand.h
ossl_x509req.o: ossl_ssl.h
ossl_x509req.o: ossl_ts.h
@@ -6072,7 +5878,6 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -6141,6 +5946,7 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -6171,6 +5977,7 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/method.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/module.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509revoked.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -6206,7 +6013,6 @@ ossl_x509revoked.o: ossl_ocsp.h
ossl_x509revoked.o: ossl_pkcs12.h
ossl_x509revoked.o: ossl_pkcs7.h
ossl_x509revoked.o: ossl_pkey.h
-ossl_x509revoked.o: ossl_provider.h
ossl_x509revoked.o: ossl_rand.h
ossl_x509revoked.o: ossl_ssl.h
ossl_x509revoked.o: ossl_ts.h
@@ -6266,7 +6072,6 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509store.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -6335,6 +6140,7 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509store.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -6365,6 +6171,7 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509store.o: $(hdrdir)/ruby/internal/method.h
ossl_x509store.o: $(hdrdir)/ruby/internal/module.h
ossl_x509store.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509store.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509store.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509store.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509store.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -6400,7 +6207,6 @@ ossl_x509store.o: ossl_ocsp.h
ossl_x509store.o: ossl_pkcs12.h
ossl_x509store.o: ossl_pkcs7.h
ossl_x509store.o: ossl_pkey.h
-ossl_x509store.o: ossl_provider.h
ossl_x509store.o: ossl_rand.h
ossl_x509store.o: ossl_ssl.h
ossl_x509store.o: ossl_ts.h
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 56f4a1c3ab..bc3e4d3a21 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -13,41 +13,20 @@
require "mkmf"
-ssl_dirs = nil
-if defined?(::TruffleRuby)
- # Always respect the openssl prefix chosen by truffle/openssl-prefix
- require 'truffle/openssl-prefix'
- ssl_dirs = dir_config("openssl", ENV["OPENSSL_PREFIX"])
-else
- ssl_dirs = dir_config("openssl")
-end
-dir_config_given = ssl_dirs.any?
-
-_, ssl_ldir = ssl_dirs
-if ssl_ldir&.split(File::PATH_SEPARATOR)&.none? { |dir| File.directory?(dir) }
- # According to the `mkmf.rb#dir_config`, the `--with-openssl-dir=<dir>` uses
- # the value of the `File.basename(RbConfig::MAKEFILE_CONFIG["libdir"])` as a
- # loaded library directory name.
- ruby_ldir_name = File.basename(RbConfig::MAKEFILE_CONFIG["libdir"])
-
- raise "OpenSSL library directory could not be found in '#{ssl_ldir}'. " \
- "You might want to fix this error in one of the following ways.\n" \
- " * Recompile OpenSSL by configuring it with --libdir=#{ruby_ldir_name} " \
- " to specify the OpenSSL library directory.\n" \
- " * Recompile Ruby by configuring it with --libdir=<dir> to specify the " \
- "Ruby library directory.\n" \
- " * Compile this openssl gem with --with-openssl-include=<dir> and " \
- "--with-openssl-lib=<dir> options to specify the OpenSSL include and " \
- "library directories."
-end
-
+dir_config_given = dir_config("openssl").any?
dir_config("kerberos")
Logging::message "=== OpenSSL for Ruby configurator ===\n"
+##
+# Adds -DOSSL_DEBUG for compilation and some more targets when GCC is used
+# To turn it on, use: --with-debug or --enable-debug
+#
+if with_config("debug") or enable_config("debug")
+ $defs.push("-DOSSL_DEBUG")
+end
$defs.push("-D""OPENSSL_SUPPRESS_DEPRECATED")
-have_func("rb_io_descriptor")
have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") # Ruby 3.1
Logging::message "=== Checking for system dependent stuff... ===\n"
@@ -212,12 +191,6 @@ have_func("EVP_PKEY_dup(NULL)", evp_h)
Logging::message "=== Checking done. ===\n"
-# Append flags from environment variables.
-extcflags = ENV["RUBY_OPENSSL_EXTCFLAGS"]
-append_cflags(extcflags.split) if extcflags
-extldflags = ENV["RUBY_OPENSSL_EXTLDFLAGS"]
-append_ldflags(extldflags.split) if extldflags
-
create_header
create_makefile("openssl")
Logging::message "Done.\n"
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb
index 9570f14f37..d47e1082ef 100644
--- a/ext/openssl/lib/openssl/buffering.rb
+++ b/ext/openssl/lib/openssl/buffering.rb
@@ -93,7 +93,9 @@ module OpenSSL::Buffering
nil
else
size = @rbuffer.size unless size
- @rbuffer.slice!(0, size)
+ ret = @rbuffer[0, size]
+ @rbuffer[0, size] = ""
+ ret
end
end
@@ -104,7 +106,8 @@ module OpenSSL::Buffering
#
# Get the next 8bit byte from `ssl`. Returns `nil` on EOF
def getbyte
- read(1)&.ord
+ byte = read(1)
+ byte && byte.unpack1("C")
end
##
diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb
index 0f35ddadd3..2ff8398e44 100644
--- a/ext/openssl/lib/openssl/digest.rb
+++ b/ext/openssl/lib/openssl/digest.rb
@@ -18,9 +18,13 @@ module OpenSSL
# Return the hash value computed with _name_ Digest. _name_ is either the
# long name or short name of a supported digest algorithm.
#
- # === Example
+ # === Examples
#
# OpenSSL::Digest.digest("SHA256", "abc")
+ #
+ # which is equivalent to:
+ #
+ # OpenSSL::Digest.digest('SHA256', "abc")
def self.digest(name, data)
super(data, name)
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index e557b8b483..ea8bb2a18e 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -34,21 +34,21 @@ module OpenSSL
}
if defined?(OpenSSL::PKey::DH)
- DH_ffdhe2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
+ DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
-----BEGIN DH PARAMETERS-----
-MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
-+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
-87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
-YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
-7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
-ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
+MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY
+JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab
+VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6
+YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
+1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD
+7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg==
-----END DH PARAMETERS-----
_end_of_pem_
- private_constant :DH_ffdhe2048
+ private_constant :DEFAULT_2048
DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
warn "using default DH parameters." if $VERBOSE
- DH_ffdhe2048
+ DEFAULT_2048
}
end
@@ -494,7 +494,7 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
unless ctx.session_id_context
# see #6137 - session id may not exceed 32 bytes
prng = ::Random.new($0.hash)
- session_id = prng.bytes(16).unpack1('H*')
+ session_id = prng.bytes(16).unpack('H*')[0]
@ctx.session_id_context = session_id
end
@start_immediately = true
diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb
index 9315a79381..4163f55064 100644
--- a/ext/openssl/lib/openssl/version.rb
+++ b/ext/openssl/lib/openssl/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module OpenSSL
- VERSION = "3.2.0"
+ VERSION = "3.1.0"
end
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec
index 2765f55401..8d83b69193 100644
--- a/ext/openssl/openssl.gemspec
+++ b/ext/openssl/openssl.gemspec
@@ -1,27 +1,21 @@
Gem::Specification.new do |spec|
spec.name = "openssl"
- spec.version = "3.2.0"
+ spec.version = "3.1.0"
spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"]
spec.email = ["ruby-core@ruby-lang.org"]
- spec.summary = %q{SSL/TLS and general-purpose cryptography for Ruby}
- spec.description = %q{OpenSSL for Ruby provides access to SSL/TLS and general-purpose cryptography based on the OpenSSL library.}
+ spec.summary = %q{OpenSSL provides SSL, TLS and general purpose cryptography.}
+ spec.description = %q{It wraps the OpenSSL library.}
spec.homepage = "https://github.com/ruby/openssl"
spec.license = "Ruby"
- if Gem::Platform === spec.platform and spec.platform =~ 'java' or RUBY_ENGINE == 'jruby'
- spec.platform = "java"
- spec.files = []
- spec.add_runtime_dependency('jruby-openssl', '~> 0.14')
- else
- spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "LICENSE.txt"]
- spec.require_paths = ["lib"]
- spec.extensions = ["ext/openssl/extconf.rb"]
- end
+ spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "LICENSE.txt"]
+ spec.require_paths = ["lib"]
+ spec.extensions = ["ext/openssl/extconf.rb"]
spec.extra_rdoc_files = Dir["*.md"]
spec.rdoc_options = ["--main", "README.md"]
- spec.required_ruby_version = ">= 2.7.0"
+ spec.required_ruby_version = ">= 2.6.0"
spec.metadata["msys2_mingw_dependencies"] = "openssl"
end
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 00eded55cb..6c532aca94 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -207,7 +207,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)
while (1) {
/*
- * when the flag is nonzero, this password
+ * when the flag is nonzero, this passphrase
* will be used to perform encryption; otherwise it will
* be used to perform decryption.
*/
@@ -272,28 +272,23 @@ VALUE
ossl_make_error(VALUE exc, VALUE str)
{
unsigned long e;
- const char *data;
- int flags;
- if (NIL_P(str))
- str = rb_str_new(NULL, 0);
-
-#ifdef HAVE_ERR_GET_ERROR_ALL
- e = ERR_peek_last_error_all(NULL, NULL, NULL, &data, &flags);
-#else
- e = ERR_peek_last_error_line_data(NULL, NULL, &data, &flags);
-#endif
+ e = ERR_peek_last_error();
if (e) {
- const char *msg = ERR_reason_error_string(e);
+ const char *msg = ERR_reason_error_string(e);
- if (RSTRING_LEN(str)) rb_str_cat_cstr(str, ": ");
- rb_str_cat_cstr(str, msg ? msg : "(null)");
- if (flags & ERR_TXT_STRING && data)
- rb_str_catf(str, " (%s)", data);
- ossl_clear_error();
+ if (NIL_P(str)) {
+ if (msg) str = rb_str_new_cstr(msg);
+ }
+ else {
+ if (RSTRING_LEN(str)) rb_str_cat2(str, ": ");
+ rb_str_cat2(str, msg ? msg : "(null)");
+ }
+ ossl_clear_error();
}
- return rb_exc_new_str(exc, str);
+ if (NIL_P(str)) str = rb_str_new(0, 0);
+ return rb_exc_new3(exc, str);
}
void
@@ -374,6 +369,22 @@ ossl_get_errors(VALUE _)
*/
VALUE dOSSL;
+#if !defined(HAVE_VA_ARGS_MACRO)
+void
+ossl_debug(const char *fmt, ...)
+{
+ va_list args;
+
+ if (dOSSL == Qtrue) {
+ fprintf(stderr, "OSSL_DEBUG: ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, " [CONTEXT N/A]\n");
+ }
+}
+#endif
+
/*
* call-seq:
* OpenSSL.debug -> true | false
@@ -407,11 +418,7 @@ static VALUE
ossl_fips_mode_get(VALUE self)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
- VALUE enabled;
- enabled = EVP_default_properties_is_fips_enabled(NULL) ? Qtrue : Qfalse;
- return enabled;
-#elif defined(OPENSSL_FIPS)
+#ifdef OPENSSL_FIPS
VALUE enabled;
enabled = FIPS_mode() ? Qtrue : Qfalse;
return enabled;
@@ -435,18 +442,8 @@ ossl_fips_mode_get(VALUE self)
static VALUE
ossl_fips_mode_set(VALUE self, VALUE enabled)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
- if (RTEST(enabled)) {
- if (!EVP_default_properties_enable_fips(NULL, 1)) {
- ossl_raise(eOSSLError, "Turning on FIPS mode failed");
- }
- } else {
- if (!EVP_default_properties_enable_fips(NULL, 0)) {
- ossl_raise(eOSSLError, "Turning off FIPS mode failed");
- }
- }
- return enabled;
-#elif defined(OPENSSL_FIPS)
+
+#ifdef OPENSSL_FIPS
if (RTEST(enabled)) {
int mode = FIPS_mode();
if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
@@ -463,6 +460,75 @@ ossl_fips_mode_set(VALUE self, VALUE enabled)
#endif
}
+#if defined(OSSL_DEBUG)
+#if !defined(LIBRESSL_VERSION_NUMBER) && \
+ (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_NO_CRYPTO_MDEBUG) || \
+ defined(CRYPTO_malloc_debug_init))
+/*
+ * call-seq:
+ * OpenSSL.mem_check_start -> nil
+ *
+ * Calls CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON). Starts tracking memory
+ * allocations. See also OpenSSL.print_mem_leaks.
+ *
+ * This is available only when built with a capable OpenSSL and --enable-debug
+ * configure option.
+ */
+static VALUE
+mem_check_start(VALUE self)
+{
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * OpenSSL.print_mem_leaks -> true | false
+ *
+ * For debugging the Ruby/OpenSSL library. Calls CRYPTO_mem_leaks_fp(stderr).
+ * Prints detected memory leaks to standard error. This cleans the global state
+ * up thus you cannot use any methods of the library after calling this.
+ *
+ * Returns +true+ if leaks detected, +false+ otherwise.
+ *
+ * This is available only when built with a capable OpenSSL and --enable-debug
+ * configure option.
+ *
+ * === Example
+ * OpenSSL.mem_check_start
+ * NOT_GCED = OpenSSL::PKey::RSA.new(256)
+ *
+ * END {
+ * GC.start
+ * OpenSSL.print_mem_leaks # will print the leakage
+ * }
+ */
+static VALUE
+print_mem_leaks(VALUE self)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+ int ret;
+#endif
+
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+ // for Ruby 2.x
+ void ossl_bn_ctx_free(void); // ossl_bn.c
+ ossl_bn_ctx_free();
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+ ret = CRYPTO_mem_leaks_fp(stderr);
+ if (ret < 0)
+ ossl_raise(eOSSLError, "CRYPTO_mem_leaks_fp");
+ return ret ? Qfalse : Qtrue;
+#else
+ CRYPTO_mem_leaks_fp(stderr);
+ return Qnil;
+#endif
+}
+#endif
+#endif
+
#if !defined(HAVE_OPENSSL_110_THREADING_API)
/**
* Stores locks needed for OpenSSL thread safety
@@ -605,21 +671,23 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* key = OpenSSL::PKey::RSA.new 2048
*
- * File.write 'private_key.pem', key.private_to_pem
- * File.write 'public_key.pem', key.public_to_pem
+ * open 'private_key.pem', 'w' do |io| io.write key.to_pem end
+ * open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end
*
* === Exporting a Key
*
* Keys saved to disk without encryption are not secure as anyone who gets
* ahold of the key may use it unless it is encrypted. In order to securely
- * export a key you may export it with a password.
+ * export a key you may export it with a pass phrase.
*
* cipher = OpenSSL::Cipher.new 'aes-256-cbc'
- * password = 'my secure password goes here'
+ * pass_phrase = 'my secure pass phrase goes here'
*
- * key_secure = key.private_to_pem cipher, password
+ * key_secure = key.export cipher, pass_phrase
*
- * File.write 'private.secure.pem', key_secure
+ * open 'private.secure.pem', 'w' do |io|
+ * io.write key_secure
+ * end
*
* OpenSSL::Cipher.ciphers returns a list of available ciphers.
*
@@ -639,13 +707,13 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Loading an Encrypted Key
*
- * OpenSSL will prompt you for your password when loading an encrypted key.
- * If you will not be able to type in the password you may provide it when
+ * OpenSSL will prompt you for your pass phrase when loading an encrypted key.
+ * If you will not be able to type in the pass phrase you may provide it when
* loading the key:
*
* key4_pem = File.read 'private.secure.pem'
- * password = 'my secure password goes here'
- * key4 = OpenSSL::PKey.read key4_pem, password
+ * pass_phrase = 'my secure pass phrase goes here'
+ * key4 = OpenSSL::PKey.read key4_pem, pass_phrase
*
* == RSA Encryption
*
@@ -761,6 +829,45 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* decrypted = cipher.update encrypted
* decrypted << cipher.final
*
+ * == PKCS #5 Password-based Encryption
+ *
+ * PKCS #5 is a password-based encryption standard documented at
+ * RFC2898[http://www.ietf.org/rfc/rfc2898.txt]. It allows a short password or
+ * passphrase to be used to create a secure encryption key. If possible, PBKDF2
+ * as described above should be used if the circumstances allow it.
+ *
+ * PKCS #5 uses a Cipher, a pass phrase and a salt to generate an encryption
+ * key.
+ *
+ * pass_phrase = 'my secure pass phrase goes here'
+ * salt = '8 octets'
+ *
+ * === Encryption
+ *
+ * First set up the cipher for encryption
+ *
+ * encryptor = OpenSSL::Cipher.new 'aes-256-cbc'
+ * encryptor.encrypt
+ * encryptor.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to encrypt through
+ *
+ * encrypted = encryptor.update 'top secret document'
+ * encrypted << encryptor.final
+ *
+ * === Decryption
+ *
+ * Use a new Cipher instance set up for decryption
+ *
+ * decryptor = OpenSSL::Cipher.new 'aes-256-cbc'
+ * decryptor.decrypt
+ * decryptor.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to decrypt through
+ *
+ * plain = decryptor.update encrypted
+ * plain << decryptor.final
+ *
* == X509 Certificates
*
* === Creating a Certificate
@@ -838,12 +945,12 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* not readable by other users.
*
* ca_key = OpenSSL::PKey::RSA.new 2048
- * password = 'my secure password goes here'
+ * pass_phrase = 'my secure pass phrase goes here'
*
- * cipher = 'aes-256-cbc'
+ * cipher = OpenSSL::Cipher.new 'aes-256-cbc'
*
* open 'ca_key.pem', 'w', 0400 do |io|
- * io.write ca_key.private_to_pem(cipher, password)
+ * io.write ca_key.export(cipher, pass_phrase)
* end
*
* === CA Certificate
@@ -1063,8 +1170,8 @@ Init_openssl(void)
/*
* Init main module
*/
- rb_global_variable(&mOSSL);
mOSSL = rb_define_module("OpenSSL");
+ rb_global_variable(&mOSSL);
rb_define_singleton_method(mOSSL, "fixed_length_secure_compare", ossl_crypto_fixed_length_secure_compare, 2);
/*
@@ -1083,35 +1190,15 @@ Init_openssl(void)
/*
* Version number of OpenSSL the ruby OpenSSL extension was built with
- * (base 16). The formats are below.
- *
- * [OpenSSL 3] <tt>0xMNN00PP0 (major minor 00 patch 0)</tt>
- * [OpenSSL before 3] <tt>0xMNNFFPPS (major minor fix patch status)</tt>
- * [LibreSSL] <tt>0x20000000 (fixed value)</tt>
- *
- * See also the man page OPENSSL_VERSION_NUMBER(3).
+ * (base 16)
*/
rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER));
-#if defined(LIBRESSL_VERSION_NUMBER)
- /*
- * Version number of LibreSSL the ruby OpenSSL extension was built with
- * (base 16). The format is <tt>0xMNNFF00f (major minor fix 00
- * status)</tt>. This constant is only defined in LibreSSL cases.
- *
- * See also the man page LIBRESSL_VERSION_NUMBER(3).
- */
- rb_define_const(mOSSL, "LIBRESSL_VERSION_NUMBER", INT2NUM(LIBRESSL_VERSION_NUMBER));
-#endif
-
/*
* Boolean indicating whether OpenSSL is FIPS-capable or not
*/
rb_define_const(mOSSL, "OPENSSL_FIPS",
-/* OpenSSL 3 is FIPS-capable even when it is installed without fips option */
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
- Qtrue
-#elif defined(OPENSSL_FIPS)
+#ifdef OPENSSL_FIPS
Qtrue
#else
Qfalse
@@ -1121,12 +1208,12 @@ Init_openssl(void)
rb_define_module_function(mOSSL, "fips_mode", ossl_fips_mode_get, 0);
rb_define_module_function(mOSSL, "fips_mode=", ossl_fips_mode_set, 1);
- rb_global_variable(&eOSSLError);
/*
* Generic error,
* common for all classes under OpenSSL module
*/
eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_global_variable(&eOSSLError);
/*
* Init debug core
@@ -1167,7 +1254,42 @@ Init_openssl(void)
Init_ossl_x509();
Init_ossl_ocsp();
Init_ossl_engine();
- Init_ossl_provider();
Init_ossl_asn1();
Init_ossl_kdf();
+
+#if defined(OSSL_DEBUG)
+ /*
+ * For debugging Ruby/OpenSSL. Enable only when built with --enable-debug
+ */
+#if !defined(LIBRESSL_VERSION_NUMBER) && \
+ (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_NO_CRYPTO_MDEBUG) || \
+ defined(CRYPTO_malloc_debug_init))
+ rb_define_module_function(mOSSL, "mem_check_start", mem_check_start, 0);
+ rb_define_module_function(mOSSL, "print_mem_leaks", print_mem_leaks, 0);
+
+#if defined(CRYPTO_malloc_debug_init) /* <= 1.0.2 */
+ CRYPTO_malloc_debug_init();
+#endif
+
+#if defined(V_CRYPTO_MDEBUG_ALL) /* <= 1.0.2 */
+ CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000 /* <= 1.0.2 */
+ {
+ int i;
+ /*
+ * See crypto/ex_data.c; call def_get_class() immediately to avoid
+ * allocations. 15 is the maximum number that is used as the class index
+ * in OpenSSL 1.0.2.
+ */
+ for (i = 0; i <= 15; i++) {
+ if (CRYPTO_get_ex_new_index(i, 0, (void *)"ossl-mdebug-dummy", 0, 0, 0) < 0)
+ rb_raise(rb_eRuntimeError, "CRYPTO_get_ex_new_index for "
+ "class index %d failed", i);
+ }
+ }
+#endif
+#endif
+#endif
}
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index 68d42b71e2..facb80aa73 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -62,10 +62,6 @@
# define OSSL_USE_ENGINE
#endif
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
-# define OSSL_USE_PROVIDER
-#endif
-
/*
* Common Module
*/
@@ -161,6 +157,7 @@ VALUE ossl_to_der_if_possible(VALUE);
*/
extern VALUE dOSSL;
+#if defined(HAVE_VA_ARGS_MACRO)
#define OSSL_Debug(...) do { \
if (dOSSL == Qtrue) { \
fprintf(stderr, "OSSL_DEBUG: "); \
@@ -169,6 +166,11 @@ extern VALUE dOSSL;
} \
} while (0)
+#else
+void ossl_debug(const char *, ...);
+#define OSSL_Debug ossl_debug
+#endif
+
/*
* Include all parts
*/
@@ -192,7 +194,6 @@ extern VALUE dOSSL;
#endif
#include "ossl_x509.h"
#include "ossl_engine.h"
-#include "ossl_provider.h"
#include "ossl_kdf.h"
void Init_openssl(void);
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index ce0d3ec7ee..bf2bac3679 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_bn_type = {
{
0, ossl_bn_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index 110610e1f9..cb8fbc3ca2 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -42,7 +42,7 @@ static const rb_data_type_t ossl_cipher_type = {
{
0, ossl_cipher_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c
index 0e598b4d51..0bac027487 100644
--- a/ext/openssl/ossl_config.c
+++ b/ext/openssl/ossl_config.c
@@ -22,7 +22,7 @@ static const rb_data_type_t ossl_config_type = {
{
0, nconf_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
CONF *
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index 16aeeb8106..fc326ec14a 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -35,7 +35,7 @@ static const rb_data_type_t ossl_digest_type = {
{
0, ossl_digest_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index 9e86321d06..1abde7f766 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -78,7 +78,7 @@ static const rb_data_type_t ossl_engine_type = {
{
0, ossl_engine_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index c485ba7e67..1a5f471a27 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -42,7 +42,7 @@ static const rb_data_type_t ossl_hmac_type = {
{
0, ossl_hmac_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index 48b161d4f4..0d25a7304b 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -21,7 +21,7 @@ static VALUE mKDF, eKDF;
* (https://tools.ietf.org/html/rfc2898#section-5.2).
*
* === Parameters
- * pass :: The password.
+ * pass :: The passphrase.
* salt :: The salt. Salts prevent attacks based on dictionaries of common
* passwords and attacks based on rainbow tables. It is a public
* value that can be safely stored along with the password (e.g.
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index 9bed1f330e..9b1147367a 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -50,7 +50,7 @@ static const rb_data_type_t ossl_netscape_spki_type = {
{
0, ossl_netscape_spki_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c
index df986bb3ee..9c8d768d87 100644
--- a/ext/openssl/ossl_ocsp.c
+++ b/ext/openssl/ossl_ocsp.c
@@ -86,7 +86,7 @@ static const rb_data_type_t ossl_ocsp_request_type = {
{
0, ossl_ocsp_request_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -100,7 +100,7 @@ static const rb_data_type_t ossl_ocsp_response_type = {
{
0, ossl_ocsp_response_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -114,7 +114,7 @@ static const rb_data_type_t ossl_ocsp_basicresp_type = {
{
0, ossl_ocsp_basicresp_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -128,7 +128,7 @@ static const rb_data_type_t ossl_ocsp_singleresp_type = {
{
0, ossl_ocsp_singleresp_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -142,7 +142,7 @@ static const rb_data_type_t ossl_ocsp_certid_type = {
{
0, ossl_ocsp_certid_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -1701,7 +1701,7 @@ Init_ossl_ocsp(void)
* require 'net/http'
*
* http_response =
- * Net::HTTP.start ocsp_uri.hostname, ocsp_uri.port do |http|
+ * Net::HTTP.start ocsp_uri.hostname, ocsp.port do |http|
* http.post ocsp_uri.path, request.to_der,
* 'content-type' => 'application/ocsp-request'
* end
diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c
index 164b2da465..fb947df1d0 100644
--- a/ext/openssl/ossl_pkcs12.c
+++ b/ext/openssl/ossl_pkcs12.c
@@ -44,7 +44,7 @@ static const rb_data_type_t ossl_pkcs12_type = {
{
0, ossl_pkcs12_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c
index 78dcbd667a..dbe5347639 100644
--- a/ext/openssl/ossl_pkcs7.c
+++ b/ext/openssl/ossl_pkcs7.c
@@ -65,7 +65,7 @@ const rb_data_type_t ossl_pkcs7_type = {
{
0, ossl_pkcs7_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -79,7 +79,7 @@ static const rb_data_type_t ossl_pkcs7_signer_info_type = {
{
0, ossl_pkcs7_signer_info_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -93,7 +93,7 @@ static const rb_data_type_t ossl_pkcs7_recip_info_type = {
{
0, ossl_pkcs7_recip_info_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 013412c27f..476256679b 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -35,7 +35,7 @@ const rb_data_type_t ossl_evp_pkey_type = {
{
0, ossl_evp_pkey_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -82,62 +82,31 @@ ossl_pkey_new(EVP_PKEY *pkey)
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
# include <openssl/decoder.h>
-static EVP_PKEY *
-ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
+EVP_PKEY *
+ossl_pkey_read_generic(BIO *bio, VALUE pass)
{
void *ppass = (void *)pass;
OSSL_DECODER_CTX *dctx;
EVP_PKEY *pkey = NULL;
int pos = 0, pos2;
- dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL,
- selection, NULL, NULL);
+ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL);
if (!dctx)
goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
- ppass) != 1)
+ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
+ goto out;
+
+ /* First check DER */
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
goto out;
- while (1) {
- if (OSSL_DECODER_from_bio(dctx, bio) == 1)
- goto out;
- if (BIO_eof(bio))
- break;
- pos2 = BIO_tell(bio);
- if (pos2 < 0 || pos2 <= pos)
- break;
- ossl_clear_error();
- pos = pos2;
- }
- out:
OSSL_BIO_reset(bio);
- OSSL_DECODER_CTX_free(dctx);
- return pkey;
-}
-EVP_PKEY *
-ossl_pkey_read_generic(BIO *bio, VALUE pass)
-{
- EVP_PKEY *pkey = NULL;
- /* First check DER, then check PEM. */
- const char *input_types[] = {"DER", "PEM"};
- int input_type_num = (int)(sizeof(input_types) / sizeof(char *));
+ /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */
+ if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1)
+ goto out;
/*
- * Non-zero selections to try to decode.
- *
- * See EVP_PKEY_fromdata(3) - Selections to see all the selections.
- *
- * This is a workaround for the decoder failing to decode or returning
- * bogus keys with selection 0, if a key management provider is different
- * from a decoder provider. The workaround is to avoid using selection 0.
- *
- * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10
- * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z
- *
- * See https://github.com/openssl/openssl/pull/21519 for details.
- *
- * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep
- * compatibility with ruby/openssl < 3.0 which decoded the following as a
- * private key.
+ * First check for private key formats. This is to keep compatibility with
+ * ruby/openssl < 3.0 which decoded the following as a private key.
*
* $ openssl ecparam -name prime256v1 -genkey -outform PEM
* -----BEGIN EC PARAMETERS-----
@@ -155,28 +124,36 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
*
* Note that normally, the input is supposed to contain a single decodable
* PEM block only, so this special handling should not create a new problem.
- *
- * Note that we need to create the OSSL_DECODER_CTX variable each time when
- * we use the different selection as a workaround.
- * See https://github.com/openssl/openssl/issues/20657 for details.
*/
- int selections[] = {
- EVP_PKEY_KEYPAIR,
- EVP_PKEY_KEY_PARAMETERS,
- EVP_PKEY_PUBLIC_KEY
- };
- int selection_num = (int)(sizeof(selections) / sizeof(int));
- int i, j;
-
- for (i = 0; i < input_type_num; i++) {
- for (j = 0; j < selection_num; j++) {
- pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass);
- if (pkey) {
- goto out;
- }
- }
+ OSSL_DECODER_CTX_set_selection(dctx, EVP_PKEY_KEYPAIR);
+ while (1) {
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
+ goto out;
+ if (BIO_eof(bio))
+ break;
+ pos2 = BIO_tell(bio);
+ if (pos2 < 0 || pos2 <= pos)
+ break;
+ ossl_clear_error();
+ pos = pos2;
}
+
+ OSSL_BIO_reset(bio);
+ OSSL_DECODER_CTX_set_selection(dctx, 0);
+ while (1) {
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
+ goto out;
+ if (BIO_eof(bio))
+ break;
+ pos2 = BIO_tell(bio);
+ if (pos2 < 0 || pos2 <= pos)
+ break;
+ ossl_clear_error();
+ pos = pos2;
+ }
+
out:
+ OSSL_DECODER_CTX_free(dctx);
return pkey;
}
#else
@@ -283,9 +260,9 @@ struct pkey_blocking_generate_arg {
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey;
int state;
- unsigned int yield: 1;
- unsigned int genparam: 1;
- unsigned int interrupted: 1;
+ int yield: 1;
+ int genparam: 1;
+ int interrupted: 1;
};
static VALUE
@@ -635,72 +612,6 @@ ossl_pkey_initialize_copy(VALUE self, VALUE other)
}
#endif
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey
- *
- * See the OpenSSL documentation for EVP_PKEY_new_raw_private_key()
- */
-
-static VALUE
-ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)
-{
- EVP_PKEY *pkey;
- const EVP_PKEY_ASN1_METHOD *ameth;
- int pkey_id;
- size_t keylen;
-
- StringValue(type);
- StringValue(key);
- ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
- if (!ameth)
- ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
- EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
-
- keylen = RSTRING_LEN(key);
-
- pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
- if (!pkey)
- ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key");
-
- return ossl_pkey_new(pkey);
-}
-#endif
-
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * OpenSSL::PKey.new_raw_public_key(algo, string) -> PKey
- *
- * See the OpenSSL documentation for EVP_PKEY_new_raw_public_key()
- */
-
-static VALUE
-ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)
-{
- EVP_PKEY *pkey;
- const EVP_PKEY_ASN1_METHOD *ameth;
- int pkey_id;
- size_t keylen;
-
- StringValue(type);
- StringValue(key);
- ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
- if (!ameth)
- ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
- EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
-
- keylen = RSTRING_LEN(key);
-
- pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
- if (!pkey)
- ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key");
-
- return ossl_pkey_new(pkey);
-}
-#endif
-
/*
* call-seq:
* pkey.oid -> string
@@ -882,18 +793,6 @@ ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
*
* Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der
* for more details.
- *
- * An unencrypted PEM-encoded key will look like:
- *
- * -----BEGIN PRIVATE KEY-----
- * [...]
- * -----END PRIVATE KEY-----
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN ENCRYPTED PRIVATE KEY-----
- * [...]
- * -----END ENCRYPTED PRIVATE KEY-----
*/
static VALUE
ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
@@ -901,35 +800,6 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
return do_pkcs8_export(argc, argv, self, 0);
}
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * pkey.raw_private_key => string
- *
- * See the OpenSSL documentation for EVP_PKEY_get_raw_private_key()
- */
-
-static VALUE
-ossl_pkey_raw_private_key(VALUE self)
-{
- EVP_PKEY *pkey;
- VALUE str;
- size_t len;
-
- GetPKey(self, pkey);
- if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
- str = rb_str_new(NULL, len);
-
- if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
-
- rb_str_set_len(str, len);
-
- return str;
-}
-#endif
-
VALUE
ossl_pkey_export_spki(VALUE self, int to_der)
{
@@ -972,12 +842,6 @@ ossl_pkey_public_to_der(VALUE self)
* pkey.public_to_pem -> string
*
* Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
*/
static VALUE
ossl_pkey_public_to_pem(VALUE self)
@@ -985,35 +849,6 @@ ossl_pkey_public_to_pem(VALUE self)
return ossl_pkey_export_spki(self, 0);
}
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * pkey.raw_public_key => string
- *
- * See the OpenSSL documentation for EVP_PKEY_get_raw_public_key()
- */
-
-static VALUE
-ossl_pkey_raw_public_key(VALUE self)
-{
- EVP_PKEY *pkey;
- VALUE str;
- size_t len;
-
- GetPKey(self, pkey);
- if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
- str = rb_str_new(NULL, len);
-
- if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
-
- rb_str_set_len(str, len);
-
- return str;
-}
-#endif
-
/*
* call-seq:
* pkey.compare?(another_pkey) -> true | false
@@ -1751,10 +1586,6 @@ Init_ossl_pkey(void)
rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
- rb_define_module_function(mPKey, "new_raw_private_key", ossl_pkey_new_raw_private_key, 2);
- rb_define_module_function(mPKey, "new_raw_public_key", ossl_pkey_new_raw_public_key, 2);
-#endif
rb_define_alloc_func(cPKey, ossl_pkey_alloc);
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
@@ -1770,10 +1601,6 @@ Init_ossl_pkey(void)
rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
- rb_define_method(cPKey, "raw_private_key", ossl_pkey_raw_private_key, 0);
- rb_define_method(cPKey, "raw_public_key", ossl_pkey_raw_public_key, 0);
-#endif
rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1);
rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index a231814a99..83c41378fe 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -216,20 +216,9 @@ ossl_dh_is_private(VALUE self)
* dh.to_pem -> aString
* dh.to_s -> aString
*
- * Serializes the DH parameters to a PEM-encoding.
- *
- * Note that any existing per-session public/private keys will *not* get
- * encoded, just the Diffie-Hellman parameters will be encoded.
- *
- * PEM-encoded parameters will look like:
- *
- * -----BEGIN DH PARAMETERS-----
- * [...]
- * -----END DH PARAMETERS-----
- *
- * See also #public_to_pem (X.509 SubjectPublicKeyInfo) and
- * #private_to_pem (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for
- * serialization with the private or public key components.
+ * Encodes this DH to its PEM encoding. Note that any existing per-session
+ * public/private keys will *not* get encoded, just the Diffie-Hellman
+ * parameters will be encoded.
*/
static VALUE
ossl_dh_export(VALUE self)
@@ -255,14 +244,10 @@ ossl_dh_export(VALUE self)
* call-seq:
* dh.to_der -> aString
*
- * Serializes the DH parameters to a DER-encoding
- *
- * Note that any existing per-session public/private keys will *not* get
- * encoded, just the Diffie-Hellman parameters will be encoded.
- *
- * See also #public_to_der (X.509 SubjectPublicKeyInfo) and
- * #private_to_der (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for
- * serialization with the private or public key components.
+ * Encodes this DH to its DER encoding. Note that any existing per-session
+ * public/private keys will *not* get encoded, just the Diffie-Hellman
+ * parameters will be encoded.
+
*/
static VALUE
ossl_dh_to_der(VALUE self)
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 058ce73888..b097f8c9d2 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -211,58 +211,16 @@ ossl_dsa_is_private(VALUE self)
* dsa.to_pem([cipher, password]) -> aString
* dsa.to_s([cipher, password]) -> aString
*
- * Serializes a private or public key to a PEM-encoding.
+ * Encodes this DSA to its PEM encoding.
*
- * [When the key contains public components only]
+ * === Parameters
+ * * _cipher_ is an OpenSSL::Cipher.
+ * * _password_ is a string containing your password.
*
- * Serializes it into an X.509 SubjectPublicKeyInfo.
- * The parameters _cipher_ and _password_ are ignored.
+ * === Examples
+ * DSA.to_pem -> aString
+ * DSA.to_pem(cipher, 'mypassword') -> aString
*
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
- *
- * Consider using #public_to_pem instead. This serializes the key into an
- * X.509 SubjectPublicKeyInfo regardless of whether it is a public key
- * or a private key.
- *
- * [When the key contains private components, and no parameters are given]
- *
- * Serializes it into a traditional \OpenSSL DSAPrivateKey.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN DSA PRIVATE KEY-----
- * [...]
- * -----END DSA PRIVATE KEY-----
- *
- * [When the key contains private components, and _cipher_ and _password_ are given]
- *
- * Serializes it into a traditional \OpenSSL DSAPrivateKey and encrypts it in
- * OpenSSL's traditional PEM encryption format.
- * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
- * instance of OpenSSL::Cipher.
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN DSA PRIVATE KEY-----
- * Proc-Type: 4,ENCRYPTED
- * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
- *
- * [...]
- * -----END DSA PRIVATE KEY-----
- *
- * Note that this format uses MD5 to derive the encryption key, and hence
- * will not be available on FIPS-compliant systems.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the traditional, non-standard \OpenSSL format
- * is required.
- *
- * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
- * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
*/
static VALUE
ossl_dsa_export(int argc, VALUE *argv, VALUE self)
@@ -280,15 +238,8 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* dsa.to_der -> aString
*
- * Serializes a private or public key to a DER-encoding.
- *
- * See #to_pem for details.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the traditional, non-standard \OpenSSL format
- * is required.
+ * Encodes this DSA to its DER encoding.
*
- * Consider using #public_to_der or #private_to_der instead.
*/
static VALUE
ossl_dsa_to_der(VALUE self)
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index 4b3a1fd0fe..92842f95ac 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -400,61 +400,13 @@ static VALUE ossl_ec_key_is_private(VALUE self)
/*
* call-seq:
- * key.export([cipher, password]) => String
- * key.to_pem([cipher, password]) => String
+ * key.export([cipher, pass_phrase]) => String
+ * key.to_pem([cipher, pass_phrase]) => String
*
- * Serializes a private or public key to a PEM-encoding.
- *
- * [When the key contains public components only]
- *
- * Serializes it into an X.509 SubjectPublicKeyInfo.
- * The parameters _cipher_ and _password_ are ignored.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
- *
- * Consider using #public_to_pem instead. This serializes the key into an
- * X.509 SubjectPublicKeyInfo regardless of whether it is a public key
- * or a private key.
- *
- * [When the key contains private components, and no parameters are given]
- *
- * Serializes it into a SEC 1/RFC 5915 ECPrivateKey.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN EC PRIVATE KEY-----
- * [...]
- * -----END EC PRIVATE KEY-----
- *
- * [When the key contains private components, and _cipher_ and _password_ are given]
- *
- * Serializes it into a SEC 1/RFC 5915 ECPrivateKey
- * and encrypts it in OpenSSL's traditional PEM encryption format.
- * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
- * instance of OpenSSL::Cipher.
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN EC PRIVATE KEY-----
- * Proc-Type: 4,ENCRYPTED
- * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
- *
- * [...]
- * -----END EC PRIVATE KEY-----
- *
- * Note that this format uses MD5 to derive the encryption key, and hence
- * will not be available on FIPS-compliant systems.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is
- * required.
- *
- * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
- * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
+ * Outputs the EC key in PEM encoding. If _cipher_ and _pass_phrase_ are given
+ * they will be used to encrypt the key. _cipher_ must be an OpenSSL::Cipher
+ * instance. Note that encryption will only be effective for a private key,
+ * public keys will always be encoded in plain text.
*/
static VALUE
ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
@@ -474,15 +426,7 @@ ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* key.to_der => String
*
- * Serializes a private or public key to a DER-encoding.
- *
- * See #to_pem for details.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is
- * required.
- *
- * Consider using #public_to_der or #private_to_der instead.
+ * See the OpenSSL documentation for i2d_ECPrivateKey_bio()
*/
static VALUE
ossl_ec_key_to_der(VALUE self)
@@ -586,7 +530,7 @@ static const rb_data_type_t ossl_ec_group_type = {
{
0, ossl_ec_group_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -1171,7 +1115,7 @@ static const rb_data_type_t ossl_ec_point_type = {
{
0, ossl_ec_point_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 389f76f309..072adabe62 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -50,8 +50,8 @@ VALUE eRSAError;
/*
* call-seq:
* RSA.new -> rsa
- * RSA.new(encoded_key [, password ]) -> rsa
- * RSA.new(encoded_key) { password } -> rsa
+ * RSA.new(encoded_key [, passphrase]) -> rsa
+ * RSA.new(encoded_key) { passphrase } -> rsa
* RSA.new(size [, exponent]) -> rsa
*
* Generates or loads an \RSA keypair.
@@ -61,9 +61,9 @@ VALUE eRSAError;
* #set_crt_params.
*
* If called with a String, tries to parse as DER or PEM encoding of an \RSA key.
- * Note that if _password_ is not specified, but the key is encrypted with a
- * password, \OpenSSL will prompt for it.
- * See also OpenSSL::PKey.read which can parse keys of any kind.
+ * Note that, if _passphrase_ is not specified but the key is encrypted with a
+ * passphrase, \OpenSSL will prompt for it.
+ * See also OpenSSL::PKey.read which can parse keys of any kinds.
*
* If called with a number, generates a new key pair. This form works as an
* alias of RSA.generate.
@@ -71,7 +71,7 @@ VALUE eRSAError;
* Examples:
* OpenSSL::PKey::RSA.new 2048
* OpenSSL::PKey::RSA.new File.read 'rsa.pem'
- * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my password'
+ * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase'
*/
static VALUE
ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
@@ -217,61 +217,13 @@ can_export_rsaprivatekey(VALUE self)
/*
* call-seq:
- * rsa.export([cipher, password]) => PEM-format String
- * rsa.to_pem([cipher, password]) => PEM-format String
- * rsa.to_s([cipher, password]) => PEM-format String
+ * rsa.export([cipher, pass_phrase]) => PEM-format String
+ * rsa.to_pem([cipher, pass_phrase]) => PEM-format String
+ * rsa.to_s([cipher, pass_phrase]) => PEM-format String
*
- * Serializes a private or public key to a PEM-encoding.
- *
- * [When the key contains public components only]
- *
- * Serializes it into an X.509 SubjectPublicKeyInfo.
- * The parameters _cipher_ and _password_ are ignored.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
- *
- * Consider using #public_to_pem instead. This serializes the key into an
- * X.509 SubjectPublicKeyInfo regardless of whether the key is a public key
- * or a private key.
- *
- * [When the key contains private components, and no parameters are given]
- *
- * Serializes it into a PKCS #1 RSAPrivateKey.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN RSA PRIVATE KEY-----
- * [...]
- * -----END RSA PRIVATE KEY-----
- *
- * [When the key contains private components, and _cipher_ and _password_ are given]
- *
- * Serializes it into a PKCS #1 RSAPrivateKey
- * and encrypts it in OpenSSL's traditional PEM encryption format.
- * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
- * instance of OpenSSL::Cipher.
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN RSA PRIVATE KEY-----
- * Proc-Type: 4,ENCRYPTED
- * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
- *
- * [...]
- * -----END RSA PRIVATE KEY-----
- *
- * Note that this format uses MD5 to derive the encryption key, and hence
- * will not be available on FIPS-compliant systems.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the PKCS #1 RSAPrivateKey format is required.
- *
- * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
- * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
+ * Outputs this keypair in PEM encoding. If _cipher_ and _pass_phrase_ are
+ * given they will be used to encrypt the key. _cipher_ must be an
+ * OpenSSL::Cipher instance.
*/
static VALUE
ossl_rsa_export(int argc, VALUE *argv, VALUE self)
@@ -286,14 +238,7 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* rsa.to_der => DER-format String
*
- * Serializes a private or public key to a DER-encoding.
- *
- * See #to_pem for details.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the PKCS #1 RSAPrivateKey format is required.
- *
- * Consider using #public_to_der or #private_to_der instead.
+ * Outputs this keypair in DER encoding.
*/
static VALUE
ossl_rsa_to_der(VALUE self)
diff --git a/ext/openssl/ossl_provider.c b/ext/openssl/ossl_provider.c
deleted file mode 100644
index 981c6ccdc7..0000000000
--- a/ext/openssl/ossl_provider.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * This program is licensed under the same licence as Ruby.
- * (See the file 'LICENCE'.)
- */
-#include "ossl.h"
-
-#ifdef OSSL_USE_PROVIDER
-# include <openssl/provider.h>
-
-#define NewProvider(klass) \
- TypedData_Wrap_Struct((klass), &ossl_provider_type, 0)
-#define SetProvider(obj, provider) do { \
- if (!(provider)) { \
- ossl_raise(rb_eRuntimeError, "Provider wasn't initialized."); \
- } \
- RTYPEDDATA_DATA(obj) = (provider); \
-} while(0)
-#define GetProvider(obj, provider) do { \
- TypedData_Get_Struct((obj), OSSL_PROVIDER, &ossl_provider_type, (provider)); \
- if (!(provider)) { \
- ossl_raise(rb_eRuntimeError, "PROVIDER wasn't initialized."); \
- } \
-} while (0)
-
-static const rb_data_type_t ossl_provider_type = {
- "OpenSSL/Provider",
- {
- 0,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
-};
-
-/*
- * Classes
- */
-/* Document-class: OpenSSL::Provider
- *
- * This class is the access to openssl's Provider
- * See also, https://www.openssl.org/docs/manmaster/man7/provider.html
- */
-static VALUE cProvider;
-/* Document-class: OpenSSL::Provider::ProviderError
- *
- * This is the generic exception for OpenSSL::Provider related errors
- */
-static VALUE eProviderError;
-
-/*
- * call-seq:
- * OpenSSL::Provider.load(name) -> provider
- *
- * This method loads and initializes a provider
- */
-static VALUE
-ossl_provider_s_load(VALUE klass, VALUE name)
-{
- OSSL_PROVIDER *provider = NULL;
- VALUE obj;
-
- const char *provider_name_ptr = StringValueCStr(name);
-
- provider = OSSL_PROVIDER_load(NULL, provider_name_ptr);
- if (provider == NULL) {
- ossl_raise(eProviderError, "Failed to load %s provider", provider_name_ptr);
- }
- obj = NewProvider(klass);
- SetProvider(obj, provider);
-
- return obj;
-}
-
-struct ary_with_state { VALUE ary; int state; };
-struct rb_push_provider_name_args { OSSL_PROVIDER *prov; VALUE ary; };
-
-static VALUE
-rb_push_provider_name(VALUE rb_push_provider_name_args)
-{
- struct rb_push_provider_name_args *args = (struct rb_push_provider_name_args *)rb_push_provider_name_args;
-
- VALUE name = rb_str_new2(OSSL_PROVIDER_get0_name(args->prov));
- return rb_ary_push(args->ary, name);
-}
-
-static int
-push_provider(OSSL_PROVIDER *prov, void *cbdata)
-{
- struct ary_with_state *ary_with_state = (struct ary_with_state *)cbdata;
- struct rb_push_provider_name_args args = { prov, ary_with_state->ary };
-
- rb_protect(rb_push_provider_name, (VALUE)&args, &ary_with_state->state);
- if (ary_with_state->state) {
- return 0;
- } else {
- return 1;
- }
-}
-
-/*
- * call-seq:
- * OpenSSL::Provider.provider_names -> [provider_name, ...]
- *
- * Returns an array of currently loaded provider names.
- */
-static VALUE
-ossl_provider_s_provider_names(VALUE klass)
-{
- VALUE ary = rb_ary_new();
- struct ary_with_state cbdata = { ary, 0 };
-
- int result = OSSL_PROVIDER_do_all(NULL, &push_provider, (void*)&cbdata);
- if (result != 1 ) {
- if (cbdata.state) {
- rb_jump_tag(cbdata.state);
- } else {
- ossl_raise(eProviderError, "Failed to load provider names");
- }
- }
-
- return ary;
-}
-
-/*
- * call-seq:
- * provider.unload -> true
- *
- * This method unloads this provider.
- *
- * if provider unload fails or already unloaded, it raises OpenSSL::Provider::ProviderError
- */
-static VALUE
-ossl_provider_unload(VALUE self)
-{
- OSSL_PROVIDER *prov;
- if (RTYPEDDATA_DATA(self) == NULL) {
- ossl_raise(eProviderError, "Provider already unloaded.");
- }
- GetProvider(self, prov);
-
- int result = OSSL_PROVIDER_unload(prov);
-
- if (result != 1) {
- ossl_raise(eProviderError, "Failed to unload provider");
- }
- RTYPEDDATA_DATA(self) = NULL;
- return Qtrue;
-}
-
-/*
- * call-seq:
- * provider.name -> string
- *
- * Get the name of this provider.
- *
- * if this provider is already unloaded, it raises OpenSSL::Provider::ProviderError
- */
-static VALUE
-ossl_provider_get_name(VALUE self)
-{
- OSSL_PROVIDER *prov;
- if (RTYPEDDATA_DATA(self) == NULL) {
- ossl_raise(eProviderError, "Provider already unloaded.");
- }
- GetProvider(self, prov);
-
- return rb_str_new2(OSSL_PROVIDER_get0_name(prov));
-}
-
-/*
- * call-seq:
- * provider.inspect -> string
- *
- * Pretty prints this provider.
- */
-static VALUE
-ossl_provider_inspect(VALUE self)
-{
- OSSL_PROVIDER *prov;
- if (RTYPEDDATA_DATA(self) == NULL ) {
- return rb_sprintf("#<%"PRIsVALUE" unloaded provider>", rb_obj_class(self));
- }
- GetProvider(self, prov);
-
- return rb_sprintf("#<%"PRIsVALUE" name=\"%s\">",
- rb_obj_class(self), OSSL_PROVIDER_get0_name(prov));
-}
-
-void
-Init_ossl_provider(void)
-{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
- cProvider = rb_define_class_under(mOSSL, "Provider", rb_cObject);
- eProviderError = rb_define_class_under(cProvider, "ProviderError", eOSSLError);
-
- rb_undef_alloc_func(cProvider);
- rb_define_singleton_method(cProvider, "load", ossl_provider_s_load, 1);
- rb_define_singleton_method(cProvider, "provider_names", ossl_provider_s_provider_names, 0);
-
- rb_define_method(cProvider, "unload", ossl_provider_unload, 0);
- rb_define_method(cProvider, "name", ossl_provider_get_name, 0);
- rb_define_method(cProvider, "inspect", ossl_provider_inspect, 0);
-}
-#else
-void
-Init_ossl_provider(void)
-{
-}
-#endif
diff --git a/ext/openssl/ossl_provider.h b/ext/openssl/ossl_provider.h
deleted file mode 100644
index 1d69cb1e44..0000000000
--- a/ext/openssl/ossl_provider.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if !defined(OSSL_PROVIDER_H)
-#define OSSL_PROVIDER_H
-
-void Init_ossl_provider(void);
-#endif
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 236d455ff2..f63992664a 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -77,7 +77,7 @@ static const rb_data_type_t ossl_sslctx_type = {
{
ossl_sslctx_mark, ossl_sslctx_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -885,9 +885,9 @@ ossl_sslctx_setup(VALUE self)
if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path))
ossl_raise(eSSLError, "SSL_CTX_load_verify_dir");
#else
- if (ca_file || ca_path) {
- if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
- ossl_raise(eSSLError, "SSL_CTX_load_verify_locations");
+ if(ca_file || ca_path){
+ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
+ rb_warning("can't set verify locations");
}
#endif
@@ -1553,10 +1553,6 @@ ossl_ssl_mark(void *ptr)
{
SSL *ssl = ptr;
rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx));
-
- // Note: this reference is stored as @verify_callback so we don't need to mark it.
- // However we do need to ensure GC compaction won't move it, hence why
- // we call rb_gc_mark here.
rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx));
}
@@ -1571,7 +1567,7 @@ const rb_data_type_t ossl_ssl_type = {
{
ossl_ssl_mark, ossl_ssl_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -1650,8 +1646,6 @@ ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self);
SSL_set_info_callback(ssl, ssl_info_cb);
verify_cb = rb_attr_get(v_ctx, id_i_verify_callback);
- // We don't need to trigger a write barrier because it's already
- // an instance variable of this object.
SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)verify_cb);
rb_call_super(0, NULL);
@@ -1659,17 +1653,6 @@ ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
static VALUE
ossl_ssl_setup(VALUE self)
{
@@ -1685,8 +1668,8 @@ ossl_ssl_setup(VALUE self)
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
rb_io_check_writable(fptr);
- if (!SSL_set_fd(ssl, TO_SOCKET(rb_io_descriptor(io))))
- ossl_raise(eSSLError, "SSL_set_fd");
+ if (!SSL_set_fd(ssl, TO_SOCKET(fptr->fd)))
+ ossl_raise(eSSLError, "SSL_set_fd");
return Qtrue;
}
@@ -1726,25 +1709,21 @@ no_exception_p(VALUE opts)
#endif
static void
-io_wait_writable(VALUE io)
+io_wait_writable(rb_io_t *fptr)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT);
+ rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
#else
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
rb_io_wait_writable(fptr->fd);
#endif
}
static void
-io_wait_readable(VALUE io)
+io_wait_readable(rb_io_t *fptr)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT);
+ rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
#else
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
rb_io_wait_readable(fptr->fd);
#endif
}
@@ -1753,74 +1732,75 @@ static VALUE
ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
{
SSL *ssl;
+ rb_io_t *fptr;
int ret, ret2;
VALUE cb_state;
int nonblock = opts != Qfalse;
+#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED)
+ unsigned long err;
+#endif
rb_ivar_set(self, ID_callback_state, Qnil);
GetSSL(self, ssl);
- VALUE io = rb_attr_get(self, id_i_io);
- for (;;) {
- ret = func(ssl);
+ GetOpenFile(rb_attr_get(self, id_i_io), fptr);
+ for(;;){
+ ret = func(ssl);
- cb_state = rb_attr_get(self, ID_callback_state);
+ cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
- /* must cleanup OpenSSL error stack before re-raising */
- ossl_clear_error();
- rb_jump_tag(NUM2INT(cb_state));
- }
+ /* must cleanup OpenSSL error stack before re-raising */
+ ossl_clear_error();
+ rb_jump_tag(NUM2INT(cb_state));
+ }
- if (ret > 0)
- break;
+ if (ret > 0)
+ break;
- switch ((ret2 = ssl_get_error(ssl, ret))) {
- case SSL_ERROR_WANT_WRITE:
+ switch((ret2 = ssl_get_error(ssl, ret))){
+ case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
- io_wait_writable(io);
+ io_wait_writable(fptr);
continue;
- case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_READ:
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
- io_wait_readable(io);
+ io_wait_readable(fptr);
continue;
- case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
/* See ossl_ssl_write_internal() */
if (errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(funcname);
- /* fallthrough */
- default: {
- VALUE error_append = Qnil;
+ if (errno) rb_sys_fail(funcname);
+ ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s",
+ funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl));
+
#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED)
- unsigned long err = ERR_peek_last_error();
- if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
- ERR_GET_REASON(err) == SSL_R_CERTIFICATE_VERIFY_FAILED) {
- const char *err_msg = ERR_reason_error_string(err),
- *verify_msg = X509_verify_cert_error_string(SSL_get_verify_result(ssl));
- if (!err_msg)
- err_msg = "(null)";
- if (!verify_msg)
- verify_msg = "(null)";
- ossl_clear_error(); /* let ossl_raise() not append message */
- error_append = rb_sprintf(": %s (%s)", err_msg, verify_msg);
- }
+ case SSL_ERROR_SSL:
+ err = ERR_peek_last_error();
+ if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
+ ERR_GET_REASON(err) == SSL_R_CERTIFICATE_VERIFY_FAILED) {
+ const char *err_msg = ERR_reason_error_string(err),
+ *verify_msg = X509_verify_cert_error_string(SSL_get_verify_result(ssl));
+ if (!err_msg)
+ err_msg = "(null)";
+ if (!verify_msg)
+ verify_msg = "(null)";
+ ossl_clear_error(); /* let ossl_raise() not append message */
+ ossl_raise(eSSLError, "%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s: %s (%s)",
+ funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl),
+ err_msg, verify_msg);
+ }
#endif
- ossl_raise(eSSLError,
- "%s%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s%"PRIsVALUE,
- funcname,
- ret2 == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
- ret2,
- errno,
- peeraddr_ip_str(self),
- SSL_state_string_long(ssl),
- error_append);
- }
- }
+ /* fallthrough */
+ default:
+ ossl_raise(eSSLError, "%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s",
+ funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl));
+ }
}
return self;
@@ -1926,7 +1906,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
SSL *ssl;
int ilen;
VALUE len, str;
- VALUE opts = Qnil;
+ rb_io_t *fptr;
+ VALUE io, opts = Qnil;
if (nonblock) {
rb_scan_args(argc, argv, "11:", &len, &str, &opts);
@@ -1951,7 +1932,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
if (ilen == 0)
return str;
- VALUE io = rb_attr_get(self, id_i_io);
+ io = rb_attr_get(self, id_i_io);
+ GetOpenFile(io, fptr);
rb_str_locktmp(str);
for (;;) {
@@ -1971,7 +1953,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
}
- io_wait_writable(io);
+ io_wait_writable(fptr);
continue;
case SSL_ERROR_WANT_READ:
if (nonblock) {
@@ -1979,7 +1961,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
}
- io_wait_readable(io);
+ io_wait_readable(fptr);
continue;
case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) {
@@ -2045,14 +2027,14 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)
SSL *ssl;
rb_io_t *fptr;
int num, nonblock = opts != Qfalse;
- VALUE tmp;
+ VALUE tmp, io;
GetSSL(self, ssl);
if (!ssl_started(ssl))
rb_raise(eSSLError, "SSL session is not started yet");
tmp = rb_str_new_frozen(StringValue(str));
- VALUE io = rb_attr_get(self, id_i_io);
+ io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
/* SSL_write(3ssl) manpage states num == 0 is undefined */
@@ -2068,12 +2050,12 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
- io_wait_writable(io);
+ io_wait_writable(fptr);
continue;
case SSL_ERROR_WANT_READ:
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
- io_wait_readable(io);
+ io_wait_readable(fptr);
continue;
case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c
index c5df902c60..139a474b04 100644
--- a/ext/openssl/ossl_ssl_session.c
+++ b/ext/openssl/ossl_ssl_session.c
@@ -19,7 +19,7 @@ const rb_data_type_t ossl_ssl_session_type = {
{
0, ossl_ssl_session_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE ossl_ssl_session_alloc(VALUE klass)
diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c
index f698bdc7ff..b33ff10c10 100644
--- a/ext/openssl/ossl_ts.c
+++ b/ext/openssl/ossl_ts.c
@@ -83,7 +83,7 @@ static const rb_data_type_t ossl_ts_req_type = {
{
0, ossl_ts_req_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -97,7 +97,7 @@ static const rb_data_type_t ossl_ts_resp_type = {
{
0, ossl_ts_resp_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -111,7 +111,7 @@ static const rb_data_type_t ossl_ts_token_info_type = {
{
0, ossl_ts_token_info_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c
index d1d8bb5e95..60846cfe9d 100644
--- a/ext/openssl/ossl_x509attr.c
+++ b/ext/openssl/ossl_x509attr.c
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509attr_type = {
{
0, ossl_x509attr_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index aa6b9bb7ce..9443541645 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509_type = {
{
0, ossl_x509_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 80e29f9df2..6c1d915370 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509crl_type = {
{
0, ossl_x509crl_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c
index 192d09bd3f..e54102c771 100644
--- a/ext/openssl/ossl_x509ext.c
+++ b/ext/openssl/ossl_x509ext.c
@@ -55,7 +55,7 @@ static const rb_data_type_t ossl_x509ext_type = {
{
0, ossl_x509ext_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -108,7 +108,7 @@ static const rb_data_type_t ossl_x509extfactory_type = {
{
0, ossl_x509extfactory_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -209,16 +209,15 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
int nid;
VALUE rconf;
CONF *conf;
- const char *oid_cstr = NULL;
rb_scan_args(argc, argv, "21", &oid, &value, &critical);
+ StringValueCStr(oid);
StringValue(value);
if(NIL_P(critical)) critical = Qfalse;
- oid_cstr = StringValueCStr(oid);
- nid = OBJ_ln2nid(oid_cstr);
- if (nid != NID_undef)
- oid_cstr = OBJ_nid2sn(nid);
+ nid = OBJ_ln2nid(RSTRING_PTR(oid));
+ if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid));
+ if(!nid) ossl_raise(eX509ExtError, "unknown OID `%"PRIsVALUE"'", oid);
valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
rb_str_append(valstr, value);
@@ -229,12 +228,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
rconf = rb_iv_get(self, "@config");
conf = NIL_P(rconf) ? NULL : GetConfig(rconf);
X509V3_set_nconf(ctx, conf);
-
-#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
- ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr));
-#else
- ext = X509V3_EXT_nconf(conf, ctx, (char *)oid_cstr, RSTRING_PTR(valstr));
-#endif
+ ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr));
X509V3_set_ctx_nodb(ctx);
if (!ext){
ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index 9591912f70..13a2b2c030 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -46,7 +46,7 @@ static const rb_data_type_t ossl_x509name_type = {
{
0, ossl_x509name_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index f058185151..77a7d3f2ff 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509req_type = {
{
0, ossl_x509req_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index 108447c868..10b8aa4ad6 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509rev_type = {
{
0, ossl_x509rev_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index f27381ca90..7c546187c3 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -116,9 +116,6 @@ static void
ossl_x509store_mark(void *ptr)
{
X509_STORE *store = ptr;
- // Note: this reference is stored as @verify_callback so we don't need to mark it.
- // However we do need to ensure GC compaction won't move it, hence why
- // we call rb_gc_mark here.
rb_gc_mark((VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx));
}
@@ -133,7 +130,7 @@ static const rb_data_type_t ossl_x509store_type = {
{
ossl_x509store_mark, ossl_x509store_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -190,9 +187,8 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
X509_STORE *store;
GetX509Store(self, store);
- rb_iv_set(self, "@verify_callback", cb);
- // We don't need to trigger a write barrier because `rb_iv_set` did it.
X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb);
+ rb_iv_set(self, "@verify_callback", cb);
return cb;
}
@@ -511,9 +507,6 @@ static void
ossl_x509stctx_mark(void *ptr)
{
X509_STORE_CTX *ctx = ptr;
- // Note: this reference is stored as @verify_callback so we don't need to mark it.
- // However we do need to ensure GC compaction won't move it, hence why
- // we call rb_gc_mark here.
rb_gc_mark((VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx));
}
@@ -533,7 +526,7 @@ static const rb_data_type_t ossl_x509stctx_type = {
{
ossl_x509stctx_mark, ossl_x509stctx_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -621,8 +614,8 @@ ossl_x509stctx_verify(VALUE self)
X509_STORE_CTX *ctx;
GetX509StCtx(self, ctx);
- VALUE cb = rb_iv_get(self, "@verify_callback");
- X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb);
+ X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx,
+ (void *)rb_iv_get(self, "@verify_callback"));
switch (X509_verify_cert(ctx)) {
case 1:
diff --git a/ext/pathname/depend b/ext/pathname/depend
index 5dd8b042de..a6b000e305 100644
--- a/ext/pathname/depend
+++ b/ext/pathname/depend
@@ -53,7 +53,6 @@ pathname.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pathname.o: $(hdrdir)/ruby/internal/attr/noinline.h
pathname.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pathname.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pathname.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pathname.o: $(hdrdir)/ruby/internal/attr/pure.h
pathname.o: $(hdrdir)/ruby/internal/attr/restrict.h
pathname.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ pathname.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pathname.o: $(hdrdir)/ruby/internal/intern/error.h
pathname.o: $(hdrdir)/ruby/internal/intern/eval.h
pathname.o: $(hdrdir)/ruby/internal/intern/file.h
+pathname.o: $(hdrdir)/ruby/internal/intern/gc.h
pathname.o: $(hdrdir)/ruby/internal/intern/hash.h
pathname.o: $(hdrdir)/ruby/internal/intern/io.h
pathname.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ pathname.o: $(hdrdir)/ruby/internal/memory.h
pathname.o: $(hdrdir)/ruby/internal/method.h
pathname.o: $(hdrdir)/ruby/internal/module.h
pathname.o: $(hdrdir)/ruby/internal/newobj.h
+pathname.o: $(hdrdir)/ruby/internal/rgengc.h
pathname.o: $(hdrdir)/ruby/internal/scan_args.h
pathname.o: $(hdrdir)/ruby/internal/special_consts.h
pathname.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
index 8eeba6aad2..7bdfd0eb39 100644
--- a/ext/pathname/lib/pathname.rb
+++ b/ext/pathname/lib/pathname.rb
@@ -14,8 +14,6 @@ require 'pathname.so'
class Pathname
- VERSION = "0.3.0"
-
# :stopdoc:
# to_path is implemented so Pathname objects are usable with File.open, etc.
diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c
index 878f216fb5..8ee4bcec5b 100644
--- a/ext/pathname/pathname.c
+++ b/ext/pathname/pathname.c
@@ -131,6 +131,32 @@ path_freeze(VALUE self)
}
/*
+ * call-seq:
+ * pathname.taint -> obj
+ *
+ * Returns pathname. This method is deprecated and will be removed in Ruby 3.2.
+ */
+static VALUE
+path_taint(VALUE self)
+{
+ rb_warn("Pathname#taint is deprecated and will be removed in Ruby 3.2.");
+ return self;
+}
+
+/*
+ * call-seq:
+ * pathname.untaint -> obj
+ *
+ * Returns pathname. This method is deprecated and will be removed in Ruby 3.2.
+ */
+static VALUE
+path_untaint(VALUE self)
+{
+ rb_warn("Pathname#untaint is deprecated and will be removed in Ruby 3.2.");
+ return self;
+}
+
+/*
* Compare this pathname with +other+. The comparison is string-based.
* Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
* can refer to the same file.
@@ -1511,6 +1537,8 @@ Init_pathname(void)
rb_cPathname = rb_define_class("Pathname", rb_cObject);
rb_define_method(rb_cPathname, "initialize", path_initialize, 1);
rb_define_method(rb_cPathname, "freeze", path_freeze, 0);
+ rb_define_method(rb_cPathname, "taint", path_taint, 0);
+ rb_define_method(rb_cPathname, "untaint", path_untaint, 0);
rb_define_method(rb_cPathname, "==", path_eq, 1);
rb_define_method(rb_cPathname, "===", path_eq, 1);
rb_define_method(rb_cPathname, "eql?", path_eq, 1);
diff --git a/ext/pathname/pathname.gemspec b/ext/pathname/pathname.gemspec
index 890bc2fde9..92bc02b0db 100644
--- a/ext/pathname/pathname.gemspec
+++ b/ext/pathname/pathname.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", "ext/lib"].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "pathname"
+ spec.version = "0.2.1"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/ext/psych/depend b/ext/psych/depend
index 13fbe3fb19..78bde9a53d 100644
--- a/ext/psych/depend
+++ b/ext/psych/depend
@@ -67,7 +67,6 @@ psych.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych.o: $(hdrdir)/ruby/internal/attr/pure.h
psych.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -136,6 +135,7 @@ psych.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych.o: $(hdrdir)/ruby/internal/intern/error.h
psych.o: $(hdrdir)/ruby/internal/intern/eval.h
psych.o: $(hdrdir)/ruby/internal/intern/file.h
+psych.o: $(hdrdir)/ruby/internal/intern/gc.h
psych.o: $(hdrdir)/ruby/internal/intern/hash.h
psych.o: $(hdrdir)/ruby/internal/intern/io.h
psych.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -166,6 +166,7 @@ psych.o: $(hdrdir)/ruby/internal/memory.h
psych.o: $(hdrdir)/ruby/internal/method.h
psych.o: $(hdrdir)/ruby/internal/module.h
psych.o: $(hdrdir)/ruby/internal/newobj.h
+psych.o: $(hdrdir)/ruby/internal/rgengc.h
psych.o: $(hdrdir)/ruby/internal/scan_args.h
psych.o: $(hdrdir)/ruby/internal/special_consts.h
psych.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -243,7 +244,6 @@ psych_emitter.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_emitter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -312,6 +312,7 @@ psych_emitter.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/error.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_emitter.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/io.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -342,6 +343,7 @@ psych_emitter.o: $(hdrdir)/ruby/internal/memory.h
psych_emitter.o: $(hdrdir)/ruby/internal/method.h
psych_emitter.o: $(hdrdir)/ruby/internal/module.h
psych_emitter.o: $(hdrdir)/ruby/internal/newobj.h
+psych_emitter.o: $(hdrdir)/ruby/internal/rgengc.h
psych_emitter.o: $(hdrdir)/ruby/internal/scan_args.h
psych_emitter.o: $(hdrdir)/ruby/internal/special_consts.h
psych_emitter.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -419,7 +421,6 @@ psych_parser.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_parser.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -488,6 +489,7 @@ psych_parser.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/error.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_parser.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/io.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -518,6 +520,7 @@ psych_parser.o: $(hdrdir)/ruby/internal/memory.h
psych_parser.o: $(hdrdir)/ruby/internal/method.h
psych_parser.o: $(hdrdir)/ruby/internal/module.h
psych_parser.o: $(hdrdir)/ruby/internal/newobj.h
+psych_parser.o: $(hdrdir)/ruby/internal/rgengc.h
psych_parser.o: $(hdrdir)/ruby/internal/scan_args.h
psych_parser.o: $(hdrdir)/ruby/internal/special_consts.h
psych_parser.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -595,7 +598,6 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -664,6 +666,7 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/error.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/io.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -694,6 +697,7 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/memory.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/method.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/module.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/newobj.h
+psych_to_ruby.o: $(hdrdir)/ruby/internal/rgengc.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/scan_args.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/special_consts.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -771,7 +775,6 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -840,6 +843,7 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/error.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/io.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -870,6 +874,7 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/memory.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/method.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/module.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/newobj.h
+psych_yaml_tree.o: $(hdrdir)/ruby/internal/rgengc.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/scan_args.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/special_consts.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/psych/extconf.rb b/ext/psych/extconf.rb
index e7dd0bb60a..41daf8c238 100644
--- a/ext/psych/extconf.rb
+++ b/ext/psych/extconf.rb
@@ -22,7 +22,7 @@ if yaml_source
args = [
yaml_configure,
"--enable-#{shared ? 'shared' : 'static'}",
- "--host=#{RbConfig::CONFIG['host'].sub(/-unknown-/, '-').sub(/arm64/, 'arm')}",
+ "--host=#{RbConfig::CONFIG['host'].sub(/-unknown-/, '-')}",
"CC=#{RbConfig::CONFIG['CC']}",
*(["CFLAGS=-w"] if RbConfig::CONFIG["GCC"] == "yes"),
]
diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb
index ae167472f2..4a2ab58514 100644
--- a/ext/psych/lib/psych.rb
+++ b/ext/psych/lib/psych.rb
@@ -694,8 +694,26 @@ module Psych
dump_tags[klass] = tag
end
+ # Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower.
+ def self.warn_with_uplevel(message, uplevel: 1)
+ at = parse_caller(caller[uplevel]).join(':')
+ warn "#{at}: #{message}"
+ end
+
+ def self.parse_caller(at)
+ if /^(.+?):(\d+)(?::in `.*')?/ =~ at
+ file = $1
+ line = $2.to_i
+ [file, line]
+ end
+ end
+ private_class_method :warn_with_uplevel, :parse_caller
+
class << self
if defined?(Ractor)
+ require 'forwardable'
+ extend Forwardable
+
class Config
attr_accessor :load_tags, :dump_tags, :domain_types
def initialize
@@ -709,29 +727,7 @@ module Psych
Ractor.current[:PsychConfig] ||= Config.new
end
- def load_tags
- config.load_tags
- end
-
- def dump_tags
- config.dump_tags
- end
-
- def domain_types
- config.domain_types
- end
-
- def load_tags=(value)
- config.load_tags = value
- end
-
- def dump_tags=(value)
- config.dump_tags = value
- end
-
- def domain_types=(value)
- config.domain_types = value
- end
+ def_delegators :config, :load_tags, :dump_tags, :domain_types, :load_tags=, :dump_tags=, :domain_types=
else
attr_accessor :load_tags
attr_accessor :dump_tags
diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb
index 50efc35ee2..c2e4ea4c93 100644
--- a/ext/psych/lib/psych/class_loader.rb
+++ b/ext/psych/lib/psych/class_loader.rb
@@ -35,7 +35,7 @@ module Psych
constants.each do |const|
konst = const_get const
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
+ class_eval <<~RUBY
def #{const.to_s.downcase}
load #{konst.inspect}
end
diff --git a/ext/psych/lib/psych/tree_builder.rb b/ext/psych/lib/psych/tree_builder.rb
index 83115bd721..414ca02bf7 100644
--- a/ext/psych/lib/psych/tree_builder.rb
+++ b/ext/psych/lib/psych/tree_builder.rb
@@ -41,7 +41,7 @@ module Psych
Sequence
Mapping
}.each do |node|
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
+ class_eval %{
def start_#{node.downcase}(anchor, tag, implicit, style)
n = Nodes::#{node}.new(anchor, tag, implicit, style)
set_start_location(n)
@@ -54,7 +54,7 @@ module Psych
set_end_location(n)
n
end
- RUBY
+ }
end
###
diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb
index ce9cdf448c..a592a6916c 100644
--- a/ext/psych/lib/psych/versions.rb
+++ b/ext/psych/lib/psych/versions.rb
@@ -2,9 +2,9 @@
module Psych
# The version of Psych you are using
- VERSION = '5.1.1.1'
+ VERSION = '5.0.1'
if RUBY_ENGINE == 'jruby'
- DEFAULT_SNAKEYAML_VERSION = '2.7'.freeze
+ DEFAULT_SNAKEYAML_VERSION = '1.33'.freeze
end
end
diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb
index 51491783c3..31858798e4 100644
--- a/ext/psych/lib/psych/visitors/yaml_tree.rb
+++ b/ext/psych/lib/psych/visitors/yaml_tree.rb
@@ -568,7 +568,7 @@ module Psych
raise BadAlias, "Tried to dump an aliased object"
end
- unless Symbol === target || @permitted_classes[target.class]
+ unless @permitted_classes[target.class]
raise DisallowedClass.new('dump', target.class.name || target.class.inspect)
end
@@ -576,7 +576,7 @@ module Psych
end
def visit_Symbol sym
- unless @permitted_classes[Symbol] || @permitted_symbols[sym]
+ unless @permitted_symbols[sym]
raise DisallowedClass.new('dump', "Symbol(#{sym.inspect})")
end
diff --git a/ext/psych/psych.gemspec b/ext/psych/psych.gemspec
index 34f70095d3..5f5168ddb0 100644
--- a/ext/psych/psych.gemspec
+++ b/ext/psych/psych.gemspec
@@ -21,41 +21,28 @@ DESCRIPTION
s.licenses = ["MIT"]
s.require_paths = ["lib"]
- # for ruby core repository.
- # It was generated by
- # `git ls-files -z`.split("\x0").reject { |f|
- # f.match(%r{^\.git|^(test|spec|features|bin|tool)/|^[A-Z]\w+file$|/extlibs$|\.(gemspec|java)$|jar})
- # }
+ # for ruby core repository. It was generated by `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
s.files = [
- "CONTRIBUTING.md", "LICENSE", "README.md", "ext/psych/depend",
- "ext/psych/extconf.rb", "ext/psych/psych.c", "ext/psych/psych.h",
- "ext/psych/psych_emitter.c", "ext/psych/psych_emitter.h",
- "ext/psych/psych_parser.c", "ext/psych/psych_parser.h",
- "ext/psych/psych_to_ruby.c", "ext/psych/psych_to_ruby.h",
- "ext/psych/psych_yaml_tree.c", "ext/psych/psych_yaml_tree.h",
- "lib/psych.rb", "lib/psych/class_loader.rb", "lib/psych/coder.rb",
- "lib/psych/core_ext.rb", "lib/psych/exception.rb", "lib/psych/handler.rb",
- "lib/psych/handlers/document_stream.rb", "lib/psych/handlers/recorder.rb",
- "lib/psych/json/ruby_events.rb", "lib/psych/json/stream.rb",
- "lib/psych/json/tree_builder.rb", "lib/psych/json/yaml_events.rb",
- "lib/psych/nodes.rb", "lib/psych/nodes/alias.rb",
- "lib/psych/nodes/document.rb", "lib/psych/nodes/mapping.rb",
- "lib/psych/nodes/node.rb", "lib/psych/nodes/scalar.rb",
- "lib/psych/nodes/sequence.rb", "lib/psych/nodes/stream.rb",
- "lib/psych/omap.rb", "lib/psych/parser.rb", "lib/psych/scalar_scanner.rb",
- "lib/psych/set.rb", "lib/psych/stream.rb", "lib/psych/streaming.rb",
- "lib/psych/syntax_error.rb", "lib/psych/tree_builder.rb",
- "lib/psych/versions.rb", "lib/psych/visitors.rb",
- "lib/psych/visitors/depth_first.rb", "lib/psych/visitors/emitter.rb",
- "lib/psych/visitors/json_tree.rb", "lib/psych/visitors/to_ruby.rb",
- "lib/psych/visitors/visitor.rb", "lib/psych/visitors/yaml_tree.rb",
- "lib/psych/y.rb"
+ ".gitignore", "Gemfile", "LICENSE", "Mavenfile", "README.md", "Rakefile", "bin/console",
+ "bin/setup", "ext/psych/depend", "ext/psych/extconf.rb", "ext/psych/psych.c", "ext/psych/psych.h",
+ "ext/psych/psych_emitter.c", "ext/psych/psych_emitter.h", "ext/psych/psych_parser.c", "ext/psych/psych_parser.h",
+ "ext/psych/psych_to_ruby.c", "ext/psych/psych_to_ruby.h", "ext/psych/psych_yaml_tree.c", "ext/psych/psych_yaml_tree.h",
+ "lib/psych.rb", "lib/psych/class_loader.rb", "lib/psych/coder.rb", "lib/psych/core_ext.rb", "lib/psych/exception.rb",
+ "lib/psych/handler.rb", "lib/psych/handlers/document_stream.rb", "lib/psych/handlers/recorder.rb",
+ "lib/psych/json/ruby_events.rb", "lib/psych/json/stream.rb", "lib/psych/json/tree_builder.rb",
+ "lib/psych/json/yaml_events.rb", "lib/psych/nodes.rb", "lib/psych/nodes/alias.rb", "lib/psych/nodes/document.rb",
+ "lib/psych/nodes/mapping.rb", "lib/psych/nodes/node.rb", "lib/psych/nodes/scalar.rb", "lib/psych/nodes/sequence.rb",
+ "lib/psych/nodes/stream.rb", "lib/psych/omap.rb", "lib/psych/parser.rb", "lib/psych/scalar_scanner.rb",
+ "lib/psych/set.rb", "lib/psych/stream.rb", "lib/psych/streaming.rb", "lib/psych/syntax_error.rb",
+ "lib/psych/tree_builder.rb", "lib/psych/versions.rb", "lib/psych/visitors.rb","lib/psych/visitors/depth_first.rb",
+ "lib/psych/visitors/emitter.rb", "lib/psych/visitors/json_tree.rb", "lib/psych/visitors/to_ruby.rb",
+ "lib/psych/visitors/visitor.rb", "lib/psych/visitors/yaml_tree.rb", "lib/psych/y.rb", "psych.gemspec"
]
s.rdoc_options = ["--main", "README.md"]
s.extra_rdoc_files = ["README.md"]
- s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
+ s.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
s.required_rubygems_version = Gem::Requirement.new(">= 0")
if RUBY_ENGINE == 'jruby'
@@ -65,16 +52,15 @@ DESCRIPTION
"ext/java/org/jruby/ext/psych/PsychLibrary.java",
"ext/java/org/jruby/ext/psych/PsychParser.java",
"ext/java/org/jruby/ext/psych/PsychToRuby.java",
+ "ext/java/org/jruby/ext/psych/PsychYamlTree.java",
"lib/psych_jars.rb",
"lib/psych.jar"
]
- s.requirements = "jar org.snakeyaml:snakeyaml-engine, #{version_module::Psych::DEFAULT_SNAKEYAML_VERSION}"
+ s.requirements = "jar org.yaml:snakeyaml, #{version_module::Psych::DEFAULT_SNAKEYAML_VERSION}"
s.add_dependency 'jar-dependencies', '>= 0.1.7'
else
s.extensions = ["ext/psych/extconf.rb"]
s.add_dependency 'stringio'
end
- s.metadata['msys2_mingw_dependencies'] = 'libyaml'
-
end
diff --git a/ext/pty/depend b/ext/pty/depend
index d4d0d558ef..f251caae3f 100644
--- a/ext/pty/depend
+++ b/ext/pty/depend
@@ -53,7 +53,6 @@ pty.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pty.o: $(hdrdir)/ruby/internal/attr/noinline.h
pty.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pty.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pty.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pty.o: $(hdrdir)/ruby/internal/attr/pure.h
pty.o: $(hdrdir)/ruby/internal/attr/restrict.h
pty.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ pty.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pty.o: $(hdrdir)/ruby/internal/intern/error.h
pty.o: $(hdrdir)/ruby/internal/intern/eval.h
pty.o: $(hdrdir)/ruby/internal/intern/file.h
+pty.o: $(hdrdir)/ruby/internal/intern/gc.h
pty.o: $(hdrdir)/ruby/internal/intern/hash.h
pty.o: $(hdrdir)/ruby/internal/intern/io.h
pty.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ pty.o: $(hdrdir)/ruby/internal/memory.h
pty.o: $(hdrdir)/ruby/internal/method.h
pty.o: $(hdrdir)/ruby/internal/module.h
pty.o: $(hdrdir)/ruby/internal/newobj.h
+pty.o: $(hdrdir)/ruby/internal/rgengc.h
pty.o: $(hdrdir)/ruby/internal/scan_args.h
pty.o: $(hdrdir)/ruby/internal/special_consts.h
pty.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 0aca10bfa0..acec33f9bf 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -448,10 +448,8 @@ pty_close_pty(VALUE assoc)
for (i = 0; i < 2; i++) {
io = rb_ary_entry(assoc, i);
- if (RB_TYPE_P(io, T_FILE)) {
- /* it's OK to call rb_io_close again even if it's already closed */
+ if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
rb_io_close(io);
- }
}
return Qnil;
}
@@ -501,21 +499,28 @@ pty_open(VALUE klass)
{
int master_fd, slave_fd;
char slavename[DEVICELEN];
+ VALUE master_io, slave_file;
+ rb_io_t *master_fptr, *slave_fptr;
+ VALUE assoc;
getDevice(&master_fd, &slave_fd, slavename, 1);
- VALUE master_path = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
- VALUE master_io = rb_io_open_descriptor(rb_cIO, master_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX, master_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
-
- VALUE slave_path = rb_obj_freeze(rb_str_new_cstr(slavename));
- VALUE slave_file = rb_io_open_descriptor(rb_cFile, slave_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY, slave_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
+ master_io = rb_obj_alloc(rb_cIO);
+ MakeOpenFile(master_io, master_fptr);
+ master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
+ master_fptr->fd = master_fd;
+ master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
- VALUE assoc = rb_assoc_new(master_io, slave_file);
+ slave_file = rb_obj_alloc(rb_cFile);
+ MakeOpenFile(slave_file, slave_fptr);
+ slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
+ slave_fptr->fd = slave_fd;
+ slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
+ assoc = rb_assoc_new(master_io, slave_file);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
}
-
return assoc;
}
@@ -572,27 +577,30 @@ pty_getpty(int argc, VALUE *argv, VALUE self)
{
VALUE res;
struct pty_info info;
+ rb_io_t *wfptr,*rfptr;
+ VALUE rport = rb_obj_alloc(rb_cFile);
+ VALUE wport = rb_obj_alloc(rb_cFile);
char SlaveName[DEVICELEN];
+ MakeOpenFile(rport, rfptr);
+ MakeOpenFile(wport, wfptr);
+
establishShell(argc, argv, &info, SlaveName);
- VALUE pty_path = rb_obj_freeze(rb_str_new_cstr(SlaveName));
- VALUE rport = rb_io_open_descriptor(
- rb_cFile, info.fd, FMODE_READABLE, pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
- );
+ rfptr->mode = rb_io_modestr_fmode("r");
+ rfptr->fd = info.fd;
+ rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
- int wpty_fd = rb_cloexec_dup(info.fd);
- if (wpty_fd == -1) {
+ wfptr->mode = rb_io_modestr_fmode("w") | FMODE_SYNC;
+ wfptr->fd = rb_cloexec_dup(info.fd);
+ if (wfptr->fd == -1)
rb_sys_fail("dup()");
- }
- VALUE wport = rb_io_open_descriptor(
- rb_cFile, wpty_fd, FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE | FMODE_SYNC,
- pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
- );
+ rb_update_max_fd(wfptr->fd);
+ wfptr->pathv = rfptr->pathv;
res = rb_ary_new2(3);
- rb_ary_store(res, 0, rport);
- rb_ary_store(res, 1, wport);
+ rb_ary_store(res,0,(VALUE)rport);
+ rb_ary_store(res,1,(VALUE)wport);
rb_ary_store(res,2,PIDT2NUM(info.child_pid));
if (rb_block_given_p()) {
diff --git a/ext/racc/cparse/README b/ext/racc/cparse/README
new file mode 100644
index 0000000000..550e8d49fe
--- /dev/null
+++ b/ext/racc/cparse/README
@@ -0,0 +1,11 @@
+Racc Runtime README
+===================
+
+This directory contains a runtime library of
+Racc parser generator. If you want to generate
+your own parser, you must get Racc full package.
+Get it from:
+
+ - http://i.loveruby.net/en/projects/racc
+ - https://github.com/ruby/racc
+
diff --git a/ext/racc/cparse/cparse.c b/ext/racc/cparse/cparse.c
new file mode 100644
index 0000000000..f752eb7749
--- /dev/null
+++ b/ext/racc/cparse/cparse.c
@@ -0,0 +1,861 @@
+/*
+
+ cparse.c -- Racc Runtime Core
+
+ Copyright (c) 1999-2006 Minero Aoki
+
+ This library is free software.
+ You can distribute/modify this program under the same terms of ruby.
+
+*/
+
+#include <ruby.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* -----------------------------------------------------------------------
+ Important Constants
+----------------------------------------------------------------------- */
+
+#define RACC_VERSION "1.6.2"
+
+#define DEFAULT_TOKEN -1
+#define ERROR_TOKEN 1
+#define FINAL_TOKEN 0
+
+#define vDEFAULT_TOKEN INT2FIX(DEFAULT_TOKEN)
+#define vERROR_TOKEN INT2FIX(ERROR_TOKEN)
+#define vFINAL_TOKEN INT2FIX(FINAL_TOKEN)
+
+/* -----------------------------------------------------------------------
+ File Local Variables
+----------------------------------------------------------------------- */
+
+static VALUE RaccBug;
+static VALUE CparseParams;
+
+static ID id_yydebug;
+static ID id_nexttoken;
+static ID id_onerror;
+static ID id_noreduce;
+static ID id_errstatus;
+
+static ID id_d_shift;
+static ID id_d_reduce;
+static ID id_d_accept;
+static ID id_d_read_token;
+static ID id_d_next_state;
+static ID id_d_e_pop;
+
+/* -----------------------------------------------------------------------
+ Utils
+----------------------------------------------------------------------- */
+
+/* For backward compatibility */
+#ifndef ID2SYM
+# define ID2SYM(i) ULONG2NUM(i)
+#endif
+#ifndef SYM2ID
+# define SYM2ID(v) ((ID)NUM2ULONG(v))
+#endif
+#ifndef SYMBOL_P
+# define SYMBOL_P(v) FIXNUM_P(v)
+#endif
+#ifndef LONG2NUM
+# define LONG2NUM(i) INT2NUM(i)
+#endif
+
+#ifndef HAVE_RB_ARY_SUBSEQ
+# define rb_ary_subseq(ary, beg, len) rb_ary_new4(len, RARRAY_PTR(ary) + beg)
+#endif
+
+static ID value_to_id _((VALUE v));
+static inline long num_to_long _((VALUE n));
+
+static ID
+value_to_id(VALUE v)
+{
+ if (! SYMBOL_P(v)) {
+ rb_raise(rb_eTypeError, "not symbol");
+ }
+ return SYM2ID(v);
+}
+
+static inline long
+num_to_long(VALUE n)
+{
+ return NUM2LONG(n);
+}
+
+#define AREF(s, idx) \
+ ((0 <= idx && idx < RARRAY_LEN(s)) ? rb_ary_entry(s, idx) : Qnil)
+
+/* -----------------------------------------------------------------------
+ Parser Stack Interfaces
+----------------------------------------------------------------------- */
+
+static VALUE get_stack_tail _((VALUE stack, long len));
+static void cut_stack_tail _((VALUE stack, long len));
+
+static VALUE
+get_stack_tail(VALUE stack, long len)
+{
+ if (len < 0) return Qnil; /* system error */
+ if (len > RARRAY_LEN(stack)) len = RARRAY_LEN(stack);
+ return rb_ary_subseq(stack, RARRAY_LEN(stack) - len, len);
+}
+
+static void
+cut_stack_tail(VALUE stack, long len)
+{
+ while (len > 0) {
+ rb_ary_pop(stack);
+ len--;
+ }
+}
+
+#define STACK_INIT_LEN 64
+#define NEW_STACK() rb_ary_new2(STACK_INIT_LEN)
+#define PUSH(s, i) rb_ary_store(s, RARRAY_LEN(s), i)
+#define POP(s) rb_ary_pop(s)
+#define LAST_I(s) \
+ ((RARRAY_LEN(s) > 0) ? rb_ary_entry(s, RARRAY_LEN(s) - 1) : Qnil)
+#define GET_TAIL(s, len) get_stack_tail(s, len)
+#define CUT_TAIL(s, len) cut_stack_tail(s, len)
+
+/* -----------------------------------------------------------------------
+ struct cparse_params
+----------------------------------------------------------------------- */
+
+struct cparse_params {
+ VALUE value_v; /* VALUE version of this struct */
+
+ VALUE parser; /* parser object */
+
+ int lex_is_iterator;
+ VALUE lexer; /* scanner object */
+ ID lexmid; /* name of scanner method (must be an iterator) */
+
+ /* State transition tables (immutable)
+ Data structure is from Dragon Book 4.9 */
+ /* action table */
+ VALUE action_table;
+ VALUE action_check;
+ VALUE action_default;
+ VALUE action_pointer;
+ /* goto table */
+ VALUE goto_table;
+ VALUE goto_check;
+ VALUE goto_default;
+ VALUE goto_pointer;
+
+ long nt_base; /* NonTerminal BASE index */
+ VALUE reduce_table; /* reduce data table */
+ VALUE token_table; /* token conversion table */
+
+ /* parser stacks and parameters */
+ VALUE state;
+ long curstate;
+ VALUE vstack;
+ VALUE tstack;
+ VALUE t;
+ long shift_n;
+ long reduce_n;
+ long ruleno;
+
+ long errstatus; /* nonzero in error recovering mode */
+ long nerr; /* number of error */
+
+ int use_result_var;
+
+ VALUE retval; /* return value of parser routine */
+ long fin; /* parse result status */
+#define CP_FIN_ACCEPT 1
+#define CP_FIN_EOT 2
+#define CP_FIN_CANTPOP 3
+
+ int debug; /* user level debug */
+ int sys_debug; /* system level debug */
+
+ long i; /* table index */
+};
+
+/* -----------------------------------------------------------------------
+ Parser Main Routines
+----------------------------------------------------------------------- */
+
+static VALUE racc_cparse _((VALUE parser, VALUE arg, VALUE sysdebug));
+static VALUE racc_yyparse _((VALUE parser, VALUE lexer, VALUE lexmid,
+ VALUE arg, VALUE sysdebug));
+
+static void call_lexer _((struct cparse_params *v));
+static VALUE lexer_i _((RB_BLOCK_CALL_FUNC_ARGLIST(block_args, data)));
+
+static VALUE assert_array _((VALUE a));
+static long assert_integer _((VALUE n));
+static VALUE assert_hash _((VALUE h));
+static VALUE initialize_params _((VALUE vparams, VALUE parser, VALUE arg,
+ VALUE lexer, VALUE lexmid));
+static void cparse_params_mark _((void *ptr));
+static size_t cparse_params_memsize _((const void *ptr));
+
+static void parse_main _((struct cparse_params *v,
+ VALUE tok, VALUE val, int resume));
+static void extract_user_token _((struct cparse_params *v,
+ VALUE block_args, VALUE *tok, VALUE *val));
+static void shift _((struct cparse_params* v, long act, VALUE tok, VALUE val));
+static int reduce _((struct cparse_params* v, long act));
+static rb_block_call_func reduce0;
+
+#ifdef DEBUG
+# define D_puts(msg) if (v->sys_debug) puts(msg)
+# define D_printf(fmt,arg) if (v->sys_debug) printf(fmt,arg)
+#else
+# define D_puts(msg)
+# define D_printf(fmt,arg)
+#endif
+
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 1
+
+static const rb_data_type_t cparse_params_type = {
+ "racc/cparse",
+ {
+ cparse_params_mark,
+ RUBY_TYPED_DEFAULT_FREE,
+ cparse_params_memsize,
+ },
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
+#endif
+};
+
+static VALUE
+racc_cparse(VALUE parser, VALUE arg, VALUE sysdebug)
+{
+ VALUE vparams;
+ struct cparse_params *v;
+
+ vparams = TypedData_Make_Struct(CparseParams, struct cparse_params,
+ &cparse_params_type, v);
+ D_puts("starting cparse");
+ v->sys_debug = RTEST(sysdebug);
+ vparams = initialize_params(vparams, parser, arg, Qnil, Qnil);
+ v->lex_is_iterator = FALSE;
+ parse_main(v, Qnil, Qnil, 0);
+
+ RB_GC_GUARD(vparams);
+ return v->retval;
+}
+
+static VALUE
+racc_yyparse(VALUE parser, VALUE lexer, VALUE lexmid, VALUE arg, VALUE sysdebug)
+{
+ VALUE vparams;
+ struct cparse_params *v;
+
+ vparams = TypedData_Make_Struct(CparseParams, struct cparse_params,
+ &cparse_params_type, v);
+ v->sys_debug = RTEST(sysdebug);
+ D_puts("start C yyparse");
+ vparams = initialize_params(vparams, parser, arg, lexer, lexmid);
+ v->lex_is_iterator = TRUE;
+ D_puts("params initialized");
+ parse_main(v, Qnil, Qnil, 0);
+ call_lexer(v);
+ if (!v->fin) {
+ rb_raise(rb_eArgError, "%s() is finished before EndOfToken",
+ rb_id2name(v->lexmid));
+ }
+
+ RB_GC_GUARD(vparams);
+ return v->retval;
+}
+
+#ifdef HAVE_RB_BLOCK_CALL
+static void
+call_lexer(struct cparse_params *v)
+{
+ rb_block_call(v->lexer, v->lexmid, 0, NULL, lexer_i, v->value_v);
+}
+#else
+static VALUE
+lexer_iter(VALUE data)
+{
+ struct cparse_params *v = rb_check_typeddata(data, &cparse_params_type);
+
+ rb_funcall(v->lexer, v->lexmid, 0);
+ return Qnil;
+}
+
+static void
+call_lexer(struct cparse_params *v)
+{
+ rb_iterate(lexer_iter, v->value_v, lexer_i, v->value_v);
+}
+#endif
+
+static VALUE
+lexer_i(RB_BLOCK_CALL_FUNC_ARGLIST(block_args, data))
+{
+ struct cparse_params *v = rb_check_typeddata(data, &cparse_params_type);
+ VALUE tok, val;
+
+ if (v->fin)
+ rb_raise(rb_eArgError, "extra token after EndOfToken");
+ extract_user_token(v, block_args, &tok, &val);
+ parse_main(v, tok, val, 1);
+ if (v->fin && v->fin != CP_FIN_ACCEPT)
+ rb_iter_break();
+ return Qnil;
+}
+
+static VALUE
+assert_array(VALUE a)
+{
+ Check_Type(a, T_ARRAY);
+ return a;
+}
+
+static VALUE
+assert_hash(VALUE h)
+{
+ Check_Type(h, T_HASH);
+ return h;
+}
+
+static long
+assert_integer(VALUE n)
+{
+ return NUM2LONG(n);
+}
+
+static VALUE
+initialize_params(VALUE vparams, VALUE parser, VALUE arg, VALUE lexer, VALUE lexmid)
+{
+ struct cparse_params *v = rb_check_typeddata(vparams, &cparse_params_type);
+
+ v->value_v = vparams;
+ v->parser = parser;
+ v->lexer = lexer;
+ if (! NIL_P(lexmid))
+ v->lexmid = value_to_id(lexmid);
+
+ v->debug = RTEST(rb_ivar_get(parser, id_yydebug));
+
+ Check_Type(arg, T_ARRAY);
+ if (!(13 <= RARRAY_LEN(arg) && RARRAY_LEN(arg) <= 14))
+ rb_raise(RaccBug, "[Racc Bug] wrong arg.size %ld", RARRAY_LEN(arg));
+ v->action_table = assert_array (rb_ary_entry(arg, 0));
+ v->action_check = assert_array (rb_ary_entry(arg, 1));
+ v->action_default = assert_array (rb_ary_entry(arg, 2));
+ v->action_pointer = assert_array (rb_ary_entry(arg, 3));
+ v->goto_table = assert_array (rb_ary_entry(arg, 4));
+ v->goto_check = assert_array (rb_ary_entry(arg, 5));
+ v->goto_default = assert_array (rb_ary_entry(arg, 6));
+ v->goto_pointer = assert_array (rb_ary_entry(arg, 7));
+ v->nt_base = assert_integer(rb_ary_entry(arg, 8));
+ v->reduce_table = assert_array (rb_ary_entry(arg, 9));
+ v->token_table = assert_hash (rb_ary_entry(arg, 10));
+ v->shift_n = assert_integer(rb_ary_entry(arg, 11));
+ v->reduce_n = assert_integer(rb_ary_entry(arg, 12));
+ if (RARRAY_LEN(arg) > 13) {
+ v->use_result_var = RTEST(rb_ary_entry(arg, 13));
+ }
+ else {
+ v->use_result_var = TRUE;
+ }
+
+ v->tstack = v->debug ? NEW_STACK() : Qnil;
+ v->vstack = NEW_STACK();
+ v->state = NEW_STACK();
+ v->curstate = 0;
+ PUSH(v->state, INT2FIX(0));
+ v->t = INT2FIX(FINAL_TOKEN + 1); /* must not init to FINAL_TOKEN */
+ v->nerr = 0;
+ v->errstatus = 0;
+ rb_ivar_set(parser, id_errstatus, LONG2NUM(v->errstatus));
+
+ v->retval = Qnil;
+ v->fin = 0;
+
+ v->lex_is_iterator = FALSE;
+
+ rb_iv_set(parser, "@vstack", v->vstack);
+ if (v->debug) {
+ rb_iv_set(parser, "@tstack", v->tstack);
+ }
+ else {
+ rb_iv_set(parser, "@tstack", Qnil);
+ }
+
+ return vparams;
+}
+
+static void
+cparse_params_mark(void *ptr)
+{
+ struct cparse_params *v = (struct cparse_params*)ptr;
+
+ rb_gc_mark(v->value_v);
+ rb_gc_mark(v->parser);
+ rb_gc_mark(v->lexer);
+ rb_gc_mark(v->action_table);
+ rb_gc_mark(v->action_check);
+ rb_gc_mark(v->action_default);
+ rb_gc_mark(v->action_pointer);
+ rb_gc_mark(v->goto_table);
+ rb_gc_mark(v->goto_check);
+ rb_gc_mark(v->goto_default);
+ rb_gc_mark(v->goto_pointer);
+ rb_gc_mark(v->reduce_table);
+ rb_gc_mark(v->token_table);
+ rb_gc_mark(v->state);
+ rb_gc_mark(v->vstack);
+ rb_gc_mark(v->tstack);
+ rb_gc_mark(v->t);
+ rb_gc_mark(v->retval);
+}
+
+static size_t
+cparse_params_memsize(const void *ptr)
+{
+ return sizeof(struct cparse_params);
+}
+
+static void
+extract_user_token(struct cparse_params *v, VALUE block_args,
+ VALUE *tok, VALUE *val)
+{
+ if (NIL_P(block_args)) {
+ /* EOF */
+ *tok = Qfalse;
+ *val = rb_str_new("$", 1);
+ return;
+ }
+
+ if (!RB_TYPE_P(block_args, T_ARRAY)) {
+ rb_raise(rb_eTypeError,
+ "%s() %s %"PRIsVALUE" (must be Array[2])",
+ v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token",
+ v->lex_is_iterator ? "yielded" : "returned",
+ rb_obj_class(block_args));
+ }
+ if (RARRAY_LEN(block_args) != 2) {
+ rb_raise(rb_eArgError,
+ "%s() %s wrong size of array (%ld for 2)",
+ v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token",
+ v->lex_is_iterator ? "yielded" : "returned",
+ RARRAY_LEN(block_args));
+ }
+ *tok = AREF(block_args, 0);
+ *val = AREF(block_args, 1);
+}
+
+#define SHIFT(v,act,tok,val) shift(v,act,tok,val)
+#define REDUCE(v,act) do {\
+ switch (reduce(v,act)) { \
+ case 0: /* normal */ \
+ break; \
+ case 1: /* yyerror */ \
+ goto user_yyerror; \
+ case 2: /* yyaccept */ \
+ D_puts("u accept"); \
+ goto accept; \
+ default: \
+ break; \
+ } \
+} while (0)
+
+static void
+parse_main(struct cparse_params *v, VALUE tok, VALUE val, int resume)
+{
+ long i; /* table index */
+ long act; /* action type */
+ VALUE act_value; /* action type, VALUE version */
+ int read_next = 1; /* true if we need to read next token */
+ VALUE tmp;
+
+ if (resume)
+ goto resume;
+
+ while (1) {
+ D_puts("");
+ D_puts("---- enter new loop ----");
+ D_puts("");
+
+ D_printf("(act) k1=%ld\n", v->curstate);
+ tmp = AREF(v->action_pointer, v->curstate);
+ if (NIL_P(tmp)) goto notfound;
+ D_puts("(act) pointer[k1] ok");
+ i = NUM2LONG(tmp);
+
+ D_printf("read_next=%d\n", read_next);
+ if (read_next && (v->t != vFINAL_TOKEN)) {
+ if (v->lex_is_iterator) {
+ D_puts("resuming...");
+ if (v->fin) rb_raise(rb_eArgError, "token given after EOF");
+ v->i = i; /* save i */
+ return;
+ resume:
+ D_puts("resumed");
+ i = v->i; /* load i */
+ }
+ else {
+ D_puts("next_token");
+ tmp = rb_funcall(v->parser, id_nexttoken, 0);
+ extract_user_token(v, tmp, &tok, &val);
+ }
+ /* convert token */
+ v->t = rb_hash_aref(v->token_table, tok);
+ if (NIL_P(v->t)) {
+ v->t = vERROR_TOKEN;
+ }
+ D_printf("(act) t(k2)=%ld\n", NUM2LONG(v->t));
+ if (v->debug) {
+ rb_funcall(v->parser, id_d_read_token,
+ 3, v->t, tok, val);
+ }
+ }
+ read_next = 0;
+
+ i += NUM2LONG(v->t);
+ D_printf("(act) i=%ld\n", i);
+ if (i < 0) goto notfound;
+
+ act_value = AREF(v->action_table, i);
+ if (NIL_P(act_value)) goto notfound;
+ act = NUM2LONG(act_value);
+ D_printf("(act) table[i]=%ld\n", act);
+
+ tmp = AREF(v->action_check, i);
+ if (NIL_P(tmp)) goto notfound;
+ if (NUM2LONG(tmp) != v->curstate) goto notfound;
+ D_printf("(act) check[i]=%ld\n", NUM2LONG(tmp));
+
+ D_puts("(act) found");
+ act_fixed:
+ D_printf("act=%ld\n", act);
+ goto handle_act;
+
+ notfound:
+ D_puts("(act) not found: use default");
+ act_value = AREF(v->action_default, v->curstate);
+ act = NUM2LONG(act_value);
+ goto act_fixed;
+
+
+ handle_act:
+ if (act > 0 && act < v->shift_n) {
+ D_puts("shift");
+ if (v->errstatus > 0) {
+ v->errstatus--;
+ rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus));
+ }
+ SHIFT(v, act, v->t, val);
+ read_next = 1;
+ }
+ else if (act < 0 && act > -(v->reduce_n)) {
+ D_puts("reduce");
+ REDUCE(v, act);
+ }
+ else if (act == -(v->reduce_n)) {
+ goto error;
+ error_recovered:
+ ; /* goto label requires stmt */
+ }
+ else if (act == v->shift_n) {
+ D_puts("accept");
+ goto accept;
+ }
+ else {
+ rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act);
+ }
+
+ if (v->debug) {
+ rb_funcall(v->parser, id_d_next_state,
+ 2, LONG2NUM(v->curstate), v->state);
+ }
+ }
+ /* not reach */
+
+
+ accept:
+ if (v->debug) rb_funcall(v->parser, id_d_accept, 0);
+ v->retval = rb_ary_entry(v->vstack, 0);
+ v->fin = CP_FIN_ACCEPT;
+ return;
+
+
+ error:
+ D_printf("error detected, status=%ld\n", v->errstatus);
+ if (v->errstatus == 0) {
+ v->nerr++;
+ rb_funcall(v->parser, id_onerror,
+ 3, v->t, val, v->vstack);
+ }
+ user_yyerror:
+ if (v->errstatus == 3) {
+ if (v->t == vFINAL_TOKEN) {
+ v->retval = Qnil;
+ v->fin = CP_FIN_EOT;
+ return;
+ }
+ read_next = 1;
+ }
+ v->errstatus = 3;
+ rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus));
+
+ /* check if we can shift/reduce error token */
+ D_printf("(err) k1=%ld\n", v->curstate);
+ D_printf("(err) k2=%d (error)\n", ERROR_TOKEN);
+ while (1) {
+ tmp = AREF(v->action_pointer, v->curstate);
+ if (NIL_P(tmp)) goto error_pop;
+ D_puts("(err) pointer[k1] ok");
+
+ i = NUM2LONG(tmp) + ERROR_TOKEN;
+ D_printf("(err) i=%ld\n", i);
+ if (i < 0) goto error_pop;
+
+ act_value = AREF(v->action_table, i);
+ if (NIL_P(act_value)) {
+ D_puts("(err) table[i] == nil");
+ goto error_pop;
+ }
+ act = NUM2LONG(act_value);
+ D_printf("(err) table[i]=%ld\n", act);
+
+ tmp = AREF(v->action_check, i);
+ if (NIL_P(tmp)) {
+ D_puts("(err) check[i] == nil");
+ goto error_pop;
+ }
+ if (NUM2LONG(tmp) != v->curstate) {
+ D_puts("(err) check[i] != k1");
+ goto error_pop;
+ }
+
+ D_puts("(err) found: can handle error token");
+ break;
+
+ error_pop:
+ D_puts("(err) act not found: can't handle error token; pop");
+
+ if (RARRAY_LEN(v->state) <= 1) {
+ v->retval = Qnil;
+ v->fin = CP_FIN_CANTPOP;
+ return;
+ }
+ POP(v->state);
+ POP(v->vstack);
+ v->curstate = num_to_long(LAST_I(v->state));
+ if (v->debug) {
+ POP(v->tstack);
+ rb_funcall(v->parser, id_d_e_pop,
+ 3, v->state, v->tstack, v->vstack);
+ }
+ }
+
+ /* shift/reduce error token */
+ if (act > 0 && act < v->shift_n) {
+ D_puts("e shift");
+ SHIFT(v, act, ERROR_TOKEN, val);
+ }
+ else if (act < 0 && act > -(v->reduce_n)) {
+ D_puts("e reduce");
+ REDUCE(v, act);
+ }
+ else if (act == v->shift_n) {
+ D_puts("e accept");
+ goto accept;
+ }
+ else {
+ rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act);
+ }
+ goto error_recovered;
+}
+
+static void
+shift(struct cparse_params *v, long act, VALUE tok, VALUE val)
+{
+ PUSH(v->vstack, val);
+ if (v->debug) {
+ PUSH(v->tstack, tok);
+ rb_funcall(v->parser, id_d_shift,
+ 3, tok, v->tstack, v->vstack);
+ }
+ v->curstate = act;
+ PUSH(v->state, LONG2NUM(v->curstate));
+}
+
+static int
+reduce(struct cparse_params *v, long act)
+{
+ VALUE code;
+ v->ruleno = -act * 3;
+ code = rb_catch("racc_jump", reduce0, v->value_v);
+ v->errstatus = num_to_long(rb_ivar_get(v->parser, id_errstatus));
+ return NUM2INT(code);
+}
+
+static VALUE
+reduce0(RB_BLOCK_CALL_FUNC_ARGLIST(_, data))
+{
+ struct cparse_params *v = rb_check_typeddata(data, &cparse_params_type);
+ VALUE reduce_to, reduce_len, method_id;
+ long len;
+ ID mid;
+ VALUE tmp, tmp_t = Qundef, tmp_v = Qundef;
+ long i, k1, k2;
+ VALUE goto_state;
+
+ reduce_len = rb_ary_entry(v->reduce_table, v->ruleno);
+ reduce_to = rb_ary_entry(v->reduce_table, v->ruleno+1);
+ method_id = rb_ary_entry(v->reduce_table, v->ruleno+2);
+ len = NUM2LONG(reduce_len);
+ mid = value_to_id(method_id);
+
+ /* call action */
+ if (len == 0) {
+ tmp = Qnil;
+ if (mid != id_noreduce)
+ tmp_v = rb_ary_new();
+ if (v->debug)
+ tmp_t = rb_ary_new();
+ }
+ else {
+ if (mid != id_noreduce) {
+ tmp_v = GET_TAIL(v->vstack, len);
+ tmp = rb_ary_entry(tmp_v, 0);
+ }
+ else {
+ tmp = rb_ary_entry(v->vstack, RARRAY_LEN(v->vstack) - len);
+ }
+ CUT_TAIL(v->vstack, len);
+ if (v->debug) {
+ tmp_t = GET_TAIL(v->tstack, len);
+ CUT_TAIL(v->tstack, len);
+ }
+ CUT_TAIL(v->state, len);
+ }
+ if (mid != id_noreduce) {
+ if (v->use_result_var) {
+ tmp = rb_funcall(v->parser, mid,
+ 3, tmp_v, v->vstack, tmp);
+ }
+ else {
+ tmp = rb_funcall(v->parser, mid,
+ 2, tmp_v, v->vstack);
+ }
+ }
+
+ /* then push result */
+ PUSH(v->vstack, tmp);
+ if (v->debug) {
+ PUSH(v->tstack, reduce_to);
+ rb_funcall(v->parser, id_d_reduce,
+ 4, tmp_t, reduce_to, v->tstack, v->vstack);
+ }
+
+ /* calculate transition state */
+ if (RARRAY_LEN(v->state) == 0)
+ rb_raise(RaccBug, "state stack unexpectedly empty");
+ k2 = num_to_long(LAST_I(v->state));
+ k1 = num_to_long(reduce_to) - v->nt_base;
+ D_printf("(goto) k1=%ld\n", k1);
+ D_printf("(goto) k2=%ld\n", k2);
+
+ tmp = AREF(v->goto_pointer, k1);
+ if (NIL_P(tmp)) goto notfound;
+
+ i = NUM2LONG(tmp) + k2;
+ D_printf("(goto) i=%ld\n", i);
+ if (i < 0) goto notfound;
+
+ goto_state = AREF(v->goto_table, i);
+ if (NIL_P(goto_state)) {
+ D_puts("(goto) table[i] == nil");
+ goto notfound;
+ }
+ D_printf("(goto) table[i]=%ld (goto_state)\n", NUM2LONG(goto_state));
+
+ tmp = AREF(v->goto_check, i);
+ if (NIL_P(tmp)) {
+ D_puts("(goto) check[i] == nil");
+ goto notfound;
+ }
+ if (tmp != LONG2NUM(k1)) {
+ D_puts("(goto) check[i] != table[i]");
+ goto notfound;
+ }
+ D_printf("(goto) check[i]=%ld\n", NUM2LONG(tmp));
+
+ D_puts("(goto) found");
+ transit:
+ PUSH(v->state, goto_state);
+ v->curstate = NUM2LONG(goto_state);
+ return INT2FIX(0);
+
+ notfound:
+ D_puts("(goto) not found: use default");
+ /* overwrite `goto-state' by default value */
+ goto_state = AREF(v->goto_default, k1);
+ goto transit;
+}
+
+/* -----------------------------------------------------------------------
+ Ruby Interface
+----------------------------------------------------------------------- */
+
+void
+Init_cparse(void)
+{
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+
+ VALUE Racc, Parser;
+ ID id_racc = rb_intern_const("Racc");
+
+ if (rb_const_defined(rb_cObject, id_racc)) {
+ Racc = rb_const_get(rb_cObject, id_racc);
+ Parser = rb_const_get_at(Racc, rb_intern_const("Parser"));
+ }
+ else {
+ Racc = rb_define_module("Racc");
+ Parser = rb_define_class_under(Racc, "Parser", rb_cObject);
+ }
+ rb_define_private_method(Parser, "_racc_do_parse_c", racc_cparse, 2);
+ rb_define_private_method(Parser, "_racc_yyparse_c", racc_yyparse, 4);
+ rb_define_const(Parser, "Racc_Runtime_Core_Version_C",
+ rb_str_new2(RACC_VERSION));
+ rb_define_const(Parser, "Racc_Runtime_Core_Id_C",
+ rb_str_new2("$originalId: cparse.c,v 1.8 2006/07/06 11:39:46 aamine Exp $"));
+
+ CparseParams = rb_define_class_under(Racc, "CparseParams", rb_cObject);
+ rb_undef_alloc_func(CparseParams);
+ rb_undef_method(CparseParams, "initialize");
+ rb_undef_method(CparseParams, "initialize_copy");
+
+ RaccBug = rb_eRuntimeError;
+
+ id_yydebug = rb_intern_const("@yydebug");
+ id_nexttoken = rb_intern_const("next_token");
+ id_onerror = rb_intern_const("on_error");
+ id_noreduce = rb_intern_const("_reduce_none");
+ id_errstatus = rb_intern_const("@racc_error_status");
+
+ id_d_shift = rb_intern_const("racc_shift");
+ id_d_reduce = rb_intern_const("racc_reduce");
+ id_d_accept = rb_intern_const("racc_accept");
+ id_d_read_token = rb_intern_const("racc_read_token");
+ id_d_next_state = rb_intern_const("racc_next_state");
+ id_d_e_pop = rb_intern_const("racc_e_pop");
+}
diff --git a/ext/racc/cparse/depend b/ext/racc/cparse/depend
new file mode 100644
index 0000000000..9dc509dc7c
--- /dev/null
+++ b/ext/racc/cparse/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+cparse.o: $(RUBY_EXTCONF_H)
+cparse.o: $(arch_hdrdir)/ruby/config.h
+cparse.o: $(hdrdir)/ruby.h
+cparse.o: $(hdrdir)/ruby/assert.h
+cparse.o: $(hdrdir)/ruby/backward.h
+cparse.o: $(hdrdir)/ruby/backward/2/assume.h
+cparse.o: $(hdrdir)/ruby/backward/2/attributes.h
+cparse.o: $(hdrdir)/ruby/backward/2/bool.h
+cparse.o: $(hdrdir)/ruby/backward/2/inttypes.h
+cparse.o: $(hdrdir)/ruby/backward/2/limits.h
+cparse.o: $(hdrdir)/ruby/backward/2/long_long.h
+cparse.o: $(hdrdir)/ruby/backward/2/stdalign.h
+cparse.o: $(hdrdir)/ruby/backward/2/stdarg.h
+cparse.o: $(hdrdir)/ruby/defines.h
+cparse.o: $(hdrdir)/ruby/intern.h
+cparse.o: $(hdrdir)/ruby/internal/abi.h
+cparse.o: $(hdrdir)/ruby/internal/anyargs.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+cparse.o: $(hdrdir)/ruby/internal/assume.h
+cparse.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+cparse.o: $(hdrdir)/ruby/internal/attr/artificial.h
+cparse.o: $(hdrdir)/ruby/internal/attr/cold.h
+cparse.o: $(hdrdir)/ruby/internal/attr/const.h
+cparse.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+cparse.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+cparse.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+cparse.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+cparse.o: $(hdrdir)/ruby/internal/attr/error.h
+cparse.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+cparse.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+cparse.o: $(hdrdir)/ruby/internal/attr/format.h
+cparse.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noalias.h
+cparse.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noinline.h
+cparse.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+cparse.o: $(hdrdir)/ruby/internal/attr/pure.h
+cparse.o: $(hdrdir)/ruby/internal/attr/restrict.h
+cparse.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+cparse.o: $(hdrdir)/ruby/internal/attr/warning.h
+cparse.o: $(hdrdir)/ruby/internal/attr/weakref.h
+cparse.o: $(hdrdir)/ruby/internal/cast.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_since.h
+cparse.o: $(hdrdir)/ruby/internal/config.h
+cparse.o: $(hdrdir)/ruby/internal/constant_p.h
+cparse.o: $(hdrdir)/ruby/internal/core.h
+cparse.o: $(hdrdir)/ruby/internal/core/rarray.h
+cparse.o: $(hdrdir)/ruby/internal/core/rbasic.h
+cparse.o: $(hdrdir)/ruby/internal/core/rbignum.h
+cparse.o: $(hdrdir)/ruby/internal/core/rclass.h
+cparse.o: $(hdrdir)/ruby/internal/core/rdata.h
+cparse.o: $(hdrdir)/ruby/internal/core/rfile.h
+cparse.o: $(hdrdir)/ruby/internal/core/rhash.h
+cparse.o: $(hdrdir)/ruby/internal/core/robject.h
+cparse.o: $(hdrdir)/ruby/internal/core/rregexp.h
+cparse.o: $(hdrdir)/ruby/internal/core/rstring.h
+cparse.o: $(hdrdir)/ruby/internal/core/rstruct.h
+cparse.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+cparse.o: $(hdrdir)/ruby/internal/ctype.h
+cparse.o: $(hdrdir)/ruby/internal/dllexport.h
+cparse.o: $(hdrdir)/ruby/internal/dosish.h
+cparse.o: $(hdrdir)/ruby/internal/error.h
+cparse.o: $(hdrdir)/ruby/internal/eval.h
+cparse.o: $(hdrdir)/ruby/internal/event.h
+cparse.o: $(hdrdir)/ruby/internal/fl_type.h
+cparse.o: $(hdrdir)/ruby/internal/gc.h
+cparse.o: $(hdrdir)/ruby/internal/glob.h
+cparse.o: $(hdrdir)/ruby/internal/globals.h
+cparse.o: $(hdrdir)/ruby/internal/has/attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/builtin.h
+cparse.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/extension.h
+cparse.o: $(hdrdir)/ruby/internal/has/feature.h
+cparse.o: $(hdrdir)/ruby/internal/has/warning.h
+cparse.o: $(hdrdir)/ruby/internal/intern/array.h
+cparse.o: $(hdrdir)/ruby/internal/intern/bignum.h
+cparse.o: $(hdrdir)/ruby/internal/intern/class.h
+cparse.o: $(hdrdir)/ruby/internal/intern/compar.h
+cparse.o: $(hdrdir)/ruby/internal/intern/complex.h
+cparse.o: $(hdrdir)/ruby/internal/intern/cont.h
+cparse.o: $(hdrdir)/ruby/internal/intern/dir.h
+cparse.o: $(hdrdir)/ruby/internal/intern/enum.h
+cparse.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+cparse.o: $(hdrdir)/ruby/internal/intern/error.h
+cparse.o: $(hdrdir)/ruby/internal/intern/eval.h
+cparse.o: $(hdrdir)/ruby/internal/intern/file.h
+cparse.o: $(hdrdir)/ruby/internal/intern/gc.h
+cparse.o: $(hdrdir)/ruby/internal/intern/hash.h
+cparse.o: $(hdrdir)/ruby/internal/intern/io.h
+cparse.o: $(hdrdir)/ruby/internal/intern/load.h
+cparse.o: $(hdrdir)/ruby/internal/intern/marshal.h
+cparse.o: $(hdrdir)/ruby/internal/intern/numeric.h
+cparse.o: $(hdrdir)/ruby/internal/intern/object.h
+cparse.o: $(hdrdir)/ruby/internal/intern/parse.h
+cparse.o: $(hdrdir)/ruby/internal/intern/proc.h
+cparse.o: $(hdrdir)/ruby/internal/intern/process.h
+cparse.o: $(hdrdir)/ruby/internal/intern/random.h
+cparse.o: $(hdrdir)/ruby/internal/intern/range.h
+cparse.o: $(hdrdir)/ruby/internal/intern/rational.h
+cparse.o: $(hdrdir)/ruby/internal/intern/re.h
+cparse.o: $(hdrdir)/ruby/internal/intern/ruby.h
+cparse.o: $(hdrdir)/ruby/internal/intern/select.h
+cparse.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+cparse.o: $(hdrdir)/ruby/internal/intern/signal.h
+cparse.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+cparse.o: $(hdrdir)/ruby/internal/intern/string.h
+cparse.o: $(hdrdir)/ruby/internal/intern/struct.h
+cparse.o: $(hdrdir)/ruby/internal/intern/thread.h
+cparse.o: $(hdrdir)/ruby/internal/intern/time.h
+cparse.o: $(hdrdir)/ruby/internal/intern/variable.h
+cparse.o: $(hdrdir)/ruby/internal/intern/vm.h
+cparse.o: $(hdrdir)/ruby/internal/interpreter.h
+cparse.o: $(hdrdir)/ruby/internal/iterator.h
+cparse.o: $(hdrdir)/ruby/internal/memory.h
+cparse.o: $(hdrdir)/ruby/internal/method.h
+cparse.o: $(hdrdir)/ruby/internal/module.h
+cparse.o: $(hdrdir)/ruby/internal/newobj.h
+cparse.o: $(hdrdir)/ruby/internal/rgengc.h
+cparse.o: $(hdrdir)/ruby/internal/scan_args.h
+cparse.o: $(hdrdir)/ruby/internal/special_consts.h
+cparse.o: $(hdrdir)/ruby/internal/static_assert.h
+cparse.o: $(hdrdir)/ruby/internal/stdalign.h
+cparse.o: $(hdrdir)/ruby/internal/stdbool.h
+cparse.o: $(hdrdir)/ruby/internal/symbol.h
+cparse.o: $(hdrdir)/ruby/internal/value.h
+cparse.o: $(hdrdir)/ruby/internal/value_type.h
+cparse.o: $(hdrdir)/ruby/internal/variable.h
+cparse.o: $(hdrdir)/ruby/internal/warning_push.h
+cparse.o: $(hdrdir)/ruby/internal/xmalloc.h
+cparse.o: $(hdrdir)/ruby/missing.h
+cparse.o: $(hdrdir)/ruby/ruby.h
+cparse.o: $(hdrdir)/ruby/st.h
+cparse.o: $(hdrdir)/ruby/subst.h
+cparse.o: cparse.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/racc/cparse/extconf.rb b/ext/racc/cparse/extconf.rb
new file mode 100644
index 0000000000..18c5689ad8
--- /dev/null
+++ b/ext/racc/cparse/extconf.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: false
+#
+
+require 'mkmf'
+
+have_func('rb_block_call')
+have_func('rb_ary_subseq')
+
+create_makefile 'racc/cparse'
diff --git a/ext/rbconfig/sizeof/depend b/ext/rbconfig/sizeof/depend
index 4e4ebd4ae5..5b65b83772 100644
--- a/ext/rbconfig/sizeof/depend
+++ b/ext/rbconfig/sizeof/depend
@@ -66,7 +66,6 @@ limits.o: $(hdrdir)/ruby/internal/attr/noexcept.h
limits.o: $(hdrdir)/ruby/internal/attr/noinline.h
limits.o: $(hdrdir)/ruby/internal/attr/nonnull.h
limits.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-limits.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
limits.o: $(hdrdir)/ruby/internal/attr/pure.h
limits.o: $(hdrdir)/ruby/internal/attr/restrict.h
limits.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -126,6 +125,7 @@ limits.o: $(hdrdir)/ruby/internal/intern/enumerator.h
limits.o: $(hdrdir)/ruby/internal/intern/error.h
limits.o: $(hdrdir)/ruby/internal/intern/eval.h
limits.o: $(hdrdir)/ruby/internal/intern/file.h
+limits.o: $(hdrdir)/ruby/internal/intern/gc.h
limits.o: $(hdrdir)/ruby/internal/intern/hash.h
limits.o: $(hdrdir)/ruby/internal/intern/io.h
limits.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -156,6 +156,7 @@ limits.o: $(hdrdir)/ruby/internal/memory.h
limits.o: $(hdrdir)/ruby/internal/method.h
limits.o: $(hdrdir)/ruby/internal/module.h
limits.o: $(hdrdir)/ruby/internal/newobj.h
+limits.o: $(hdrdir)/ruby/internal/rgengc.h
limits.o: $(hdrdir)/ruby/internal/scan_args.h
limits.o: $(hdrdir)/ruby/internal/special_consts.h
limits.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -224,7 +225,6 @@ sizes.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sizes.o: $(hdrdir)/ruby/internal/attr/noinline.h
sizes.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sizes.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sizes.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sizes.o: $(hdrdir)/ruby/internal/attr/pure.h
sizes.o: $(hdrdir)/ruby/internal/attr/restrict.h
sizes.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -284,6 +284,7 @@ sizes.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sizes.o: $(hdrdir)/ruby/internal/intern/error.h
sizes.o: $(hdrdir)/ruby/internal/intern/eval.h
sizes.o: $(hdrdir)/ruby/internal/intern/file.h
+sizes.o: $(hdrdir)/ruby/internal/intern/gc.h
sizes.o: $(hdrdir)/ruby/internal/intern/hash.h
sizes.o: $(hdrdir)/ruby/internal/intern/io.h
sizes.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -314,6 +315,7 @@ sizes.o: $(hdrdir)/ruby/internal/memory.h
sizes.o: $(hdrdir)/ruby/internal/method.h
sizes.o: $(hdrdir)/ruby/internal/module.h
sizes.o: $(hdrdir)/ruby/internal/newobj.h
+sizes.o: $(hdrdir)/ruby/internal/rgengc.h
sizes.o: $(hdrdir)/ruby/internal/scan_args.h
sizes.o: $(hdrdir)/ruby/internal/special_consts.h
sizes.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/readline/.gitignore b/ext/readline/.gitignore
new file mode 100644
index 0000000000..3d372989ae
--- /dev/null
+++ b/ext/readline/.gitignore
@@ -0,0 +1 @@
+/readline-[1-9]*.*
diff --git a/ext/readline/README b/ext/readline/README
new file mode 100644
index 0000000000..57c51b5f5d
--- /dev/null
+++ b/ext/readline/README
@@ -0,0 +1,10 @@
+The Readline module provides interface for GNU Readline.
+This module defines a number of methods to facilitate completion
+and accesses input history from the Ruby interpreter.
+This module supported Edit Line(libedit) too.
+libedit is compatible with GNU Readline.
+
+GNU Readline:: http://www.gnu.org/directory/readline.html
+libedit:: http://www.thrysoee.dk/editline/
+
+See RDoc for Readline module.
diff --git a/ext/readline/README.ja b/ext/readline/README.ja
new file mode 100644
index 0000000000..57a6ee4126
--- /dev/null
+++ b/ext/readline/README.ja
@@ -0,0 +1,386 @@
+GNU Readline によるコマンドライン入力インタフェースを提供するモジュール
+です。GNU Readline の互換ライブラリのひとつである Edit Line(libedit) も
+サポートしています。
+
+GNU Readline:: http://www.gnu.org/directory/readline.html
+libedit:: http://www.thrysoee.dk/editline/
+
+Readline.readline を使用してユーザからの入力を取得できます。このとき、
+GNU Readline のように入力の補完やEmacs のようなキー操作などができます。
+
+ require "readline"
+ while buf = Readline.readline("> ", true)
+ p buf
+ end
+
+ユーザが入力した内容を履歴(以下、ヒストリ)として記録することができます。
+定数 Readline::HISTORY を使用してヒストリにアクセスできます。
+
+ require "readline"
+ while buf = Readline.readline("> ", true)
+ p Readline::HISTORY.to_a
+ print("-> ", buf, "\n")
+ end
+
+使用するライブラリにより、いくつかのメソッドで例外 NotImplementedError
+が発生します。
+
+== Readline モジュール
+
+=== モジュール関数
+
+readline([prompt, [add_hist]]) -> String | nil
+
+ prompt を出力し、ユーザからのキー入力を待ちます。
+ エンターキーの押下などでユーザが文字列を入力し終えると、
+ 入力した文字列を返します。
+ このとき、add_hist が true であれば、入力した文字列をヒストリに追加します。
+
+ 何も入力していない状態で EOF(UNIX では ^D) を入力するなどで、
+ ユーザからの入力がない場合は nil を返します。
+
+ 次の条件を全て満たす場合、例外 IOError が発生します。
+ 1. 標準入力が tty でない。
+ 2. 標準入力をクローズしている。(isatty(2) の errno が EBADF である。)
+
+ 本メソッドはスレッドに対応しています。
+ 入力待ち状態のときはスレッドコンテキストの切替えが発生します。
+
+ 入力時には行内編集が可能で、vi モードと Emacs モードが用意されています。
+ デフォルトは Emacs モードです。
+
+ 本メソッドには注意事項があります。
+ 入力待ちの状態で ^C すると ruby インタプリタが終了し、端末状態を復帰しません。
+ これを回避するための例を3つ挙げます。
+
+ * ^CによるInterrupt例外を補足して、端末状態を復帰します:
+
+ require "readline"
+
+ stty_save = `stty -g`.chomp
+ begin
+ while buf = Readline.readline
+ p buf
+ end
+ rescue Interrupt
+ system("stty", stty_save)
+ exit
+ end
+ end
+ end
+
+ * INTシグナルを補足して、端末状態を復帰します:
+
+ require "readline"
+
+ stty_save = `stty -g`.chomp
+ trap("INT") { system "stty", stty_save; exit }
+
+ while buf = Readline.readline
+ p buf
+ end
+
+ * 単に ^C を無視する方法もあります:
+
+ require "readline"
+
+ trap("INT", "SIG_IGN")
+
+ while buf = Readline.readline
+ p buf
+ end
+
+ 入力履歴 Readline::HISTORY を使用して、空行や直前の入力と同じ内容は入力
+ 履歴に残さないということもできます。
+
+ require "readline"
+
+ while buf = Readline.readline("> ", true)
+ # p Readline::HISTORY.to_a
+ Readline::HISTORY.pop if /^\s*$/ =~ buf
+
+ begin
+ if Readline::HISTORY[Readline::HISTORY.length-2] == buf
+ Readline::HISTORY.pop
+ end
+ rescue IndexError
+ end
+
+ # p Readline::HISTORY.to_a
+ print "-> ", buf, "\n"
+ end
+
+=== クラスメソッド
+
+Readline.input = input
+
+ Readline.readline メソッドで使用する入力用の File オブジェクト input
+ を指定します。
+
+Readline.output = output
+
+ Readline.readline メソッドで使用する出力用の File オブジェクト
+ output を指定します。
+
+Readline.completion_proc = proc
+
+ ユーザからの入力を補完する時の候補を取得する Proc オブジェクト proc を
+ 指定します。proc は、次のものを想定しています。
+ 1. call メソッドを持ちます。
+ call メソッドを持たない場合、例外 ArgumentError が発生します。
+ 2. 引数にユーザからの入力文字列(注1)を取ります。
+ 3. 候補の文字列の配列を返します。
+
+ 注1:「/var/lib /v」の後で補完を行うと、
+ デフォルトでは proc の引数に「/v」が渡されます。
+ このように、ユーザが入力した文字列を
+ Readline.completer_word_break_characters に含まれる文字で区切ったも
+ のを単語とすると、カーソルがある単語の最初の文字から現在のカーソル位
+ 置までの文字列が proc の引数に渡されます。
+
+Readline.completion_proc -> proc
+
+ ユーザからの入力を補完する時の候補を取得する Proc オブジェクト proc
+ を取得します。
+
+Readline.completion_case_fold = bool
+
+ ユーザの入力を補完する際、大文字と小文字を区別する/しないを指定します。
+ bool が真ならば区別しません。bool が偽ならば区別します。
+
+Readline.completion_case_fold -> bool
+
+ ユーザの入力を補完する際、大文字と小文字を区別する/しないを取得します。
+ bool が真ならば区別しません。bool が偽ならば区別します。
+
+ なお、Readline.completion_case_fold= メソッドで指定したオブジェクトを
+ そのまま取得するので、次のような動作をします。
+
+ require "readline"
+
+ Readline.completion_case_fold = "This is a String."
+ p Readline.completion_case_fold # => "This is a String."
+
+Readline.line_buffer -> string
+
+ 入力中の行全体を返します。complete_proc の中で使用することを想定し
+ ています。Readline.line_buffer の長さは GNU Readline の rl_end 変数の
+ 値と一致します。
+
+Readline.point -> int
+
+ 現在のカーソルの位置を返します。
+ Readline モジュールは補完対象の単語の開始位置の情報を提供していません。
+ しかしながら、 completion_proc の中で入力した単語 text と
+ Readline.point を使用することで開始位置を導くことができます。
+
+ 開始位置 = 入力した単語の長さ - Readline.point
+
+Readline.vi_editing_mode -> nil
+
+ 編集モードを vi モードにします。
+ vi モードの詳細は、GNU Readline のマニュアルを参照してください。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.vi_editing_mode? -> bool
+
+ 編集モードが vi モードの場合、true を返します。そうでなければ false
+ を返します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.emacs_editing_mode -> nil
+
+ 編集モードを Emacs モードにします。
+ デフォルトは Emacs モードです。
+ Emacs モードの詳細は、GNU Readline のマニュアルを参照してください。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.emacs_editing_mode? -> bool
+
+ 編集モードが Emacs モードの場合、true を返します。そうでなければ false
+ を返します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.completion_append_character = char
+
+ ユーザの入力の補完が完了した場合に、最後に付加する文字 char を指定し
+ ます。半角スペース「" "」などの単語を区切る文字を指定すれば、連続して
+ 入力する際に便利です。
+
+ 使用例:
+
+ require "readline"
+
+ Readline.readline("> ", true)
+ Readline.completion_append_character = " "
+
+ 実行例:
+
+ >
+ ここで "/var/li" を入力します。
+
+ > /var/li
+ ここで TAB キーを入力します。
+
+ > /var/lib
+ "b" が補完され、最後に " " が追加されるので、"/usr" を連続して入力できます。
+
+ > /var/lib /usr
+
+ なお、1文字しか指定することはできません。
+ 例えば、"string"を指定した場合は最初の文字である"s"だけを使用します。
+
+ require "readline"
+
+ Readline.completion_append_character = "string"
+ p Readline.completion_append_character # => "s"
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.completion_append_character -> char
+
+ ユーザの入力の補完が完了した場合に、最後に付加する文字を取得します。
+ デフォルトは空白 (" ") です。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.basic_word_break_characters = string
+
+ ユーザの入力の補完を行う際、単語の区切りを示す複数の文字で構成される
+ 文字列 string を指定します。
+
+ GNU Readline のデフォルトの値は、Bash の補完処理で使用している文字列
+ " \t\n\"\\'`@$><=;|&{(" (スペースを含む) になっています。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.basic_word_break_characters -> string
+
+ ユーザの入力の補完を行う際、単語の区切りを示す複数の文字で構成される
+ 文字列を取得します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.completer_word_break_characters = string
+
+ ユーザの入力の補完を行う際、単語の区切りを示す複数の文字で構成される
+ 文字列 string を指定します。
+ Readline.basic_word_break_characters= との違いは、
+ GNU Readline の rl_complete_internal 関数で使用されることです。
+
+ GNU Readline のデフォルトの値は、
+ Readline.basic_word_break_characters と同じです。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.completer_word_break_characters -> string
+
+ ユーザの入力の補完を行う際、単語の区切りを示す複数の文字で構成された
+ 文字列を取得します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.basic_quote_characters = string
+
+ スペースなどの単語の区切りをクオートするための複数の文字で構成される
+ 文字列 string を指定します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.basic_quote_characters -> string
+
+ スペースなどの単語の区切りをクオートするための複数の文字で構成される
+ 文字列を取得します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.completer_quote_characters = string
+
+ ユーザの入力の補完を行う際、スペースなどの単語の区切りを
+ クオートするための複数の文字で構成される文字列 string を指定します。
+ 指定した文字の間では、Readline.completer_word_break_characters=
+ で指定した文字列に含まれる文字も、普通の文字列として扱われます。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.completer_quote_characters -> string
+
+ ユーザの入力の補完を行う際、スペースなどの単語の区切りを
+ クオートするための複数の文字で構成される文字列を取得します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.filename_quote_characters = string
+
+ ユーザの入力時にファイル名の補完を行う際、スペースなどの単語の区切りを
+ クオートするための複数の文字で構成される文字列 string を指定します。
+
+ GNU Readline のデフォルト値は nil です。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+Readline.filename_quote_characters -> string
+
+ ユーザの入力時にファイル名の補完を行う際、スペースなどの単語の区切りを
+ クオートするための複数の文字で構成される文字列を取得します。
+
+ サポートしていない環境では、例外 NotImplementedError が発生します。
+
+=== クラス定数
+
+HISTORY
+
+ 定数 HISTORY を使用してヒストリにアクセスできます。
+ Enumerable モジュールを extend しており、
+ 配列のように振る舞うことができます。
+ 例えば、HISTORY[4] により 5 番目に入力した内容を取り出すことができます。
+
+ require "readline"
+
+ Readline::HISTORY.push("a", "b", "c", "d", "e")
+ p Readline::HISTORY[4] # => "e"
+
+ 実装しているメソッドを次に挙げます。
+ * HISTORY.to_s -> "HISTORY"
+ * HISTORY[index] -> string
+ * HISTORY[index] = string
+ * HISTORY.push(string[, string, ...]) -> self
+ * HISTORY << string -> self
+ * HISTORY.pop -> string
+ * HISTORY.shift -> string
+ * HISTORY.each -> Enumerator
+ * HISTORY.each { |i| } -> [string]
+ * HISTORY.length -> Integer
+ * HISTORY.empty? -> true or false
+ * HISTORY.delete_at(index) -> string
+ * HISTORY.clear -> self
+
+ サポートしていない環境では、次のメソッドで例外 NotImplementedError が
+ 発生します。
+ * HISTORY[index] = string
+ * HISTORY.pop -> string
+ * HISTORY.shift -> string
+ * HISTORY.delete_at(index) -> string
+ * HISTORY.clear -> self
+
+FILENAME_COMPLETION_PROC
+
+ ファイル名の補完を行う call メソッドを持つオブジェクトです。
+
+ Readline.completion_proc= により、ユーザの入力時にファイル名の補完を
+ 行うように設定するために使用することを想定してます。
+
+USERNAME_COMPLETION_PROC
+
+ ユーザ名の補完を行う call メソッドを持つオブジェクトです。
+
+ Readline.completion_proc= により、ユーザの入力時にユーザ名の補完を行
+ うように設定するために使用することを想定してます。
+
+VERSION
+
+ 使用している GNU Readline または libedit のバージョンです。
diff --git a/ext/readline/depend b/ext/readline/depend
new file mode 100644
index 0000000000..c62309622a
--- /dev/null
+++ b/ext/readline/depend
@@ -0,0 +1,175 @@
+# AUTOGENERATED DEPENDENCIES START
+readline.o: $(RUBY_EXTCONF_H)
+readline.o: $(arch_hdrdir)/ruby/config.h
+readline.o: $(hdrdir)/ruby/assert.h
+readline.o: $(hdrdir)/ruby/backward.h
+readline.o: $(hdrdir)/ruby/backward/2/assume.h
+readline.o: $(hdrdir)/ruby/backward/2/attributes.h
+readline.o: $(hdrdir)/ruby/backward/2/bool.h
+readline.o: $(hdrdir)/ruby/backward/2/inttypes.h
+readline.o: $(hdrdir)/ruby/backward/2/limits.h
+readline.o: $(hdrdir)/ruby/backward/2/long_long.h
+readline.o: $(hdrdir)/ruby/backward/2/stdalign.h
+readline.o: $(hdrdir)/ruby/backward/2/stdarg.h
+readline.o: $(hdrdir)/ruby/defines.h
+readline.o: $(hdrdir)/ruby/encoding.h
+readline.o: $(hdrdir)/ruby/intern.h
+readline.o: $(hdrdir)/ruby/internal/abi.h
+readline.o: $(hdrdir)/ruby/internal/anyargs.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+readline.o: $(hdrdir)/ruby/internal/assume.h
+readline.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+readline.o: $(hdrdir)/ruby/internal/attr/artificial.h
+readline.o: $(hdrdir)/ruby/internal/attr/cold.h
+readline.o: $(hdrdir)/ruby/internal/attr/const.h
+readline.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+readline.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+readline.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+readline.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+readline.o: $(hdrdir)/ruby/internal/attr/error.h
+readline.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+readline.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+readline.o: $(hdrdir)/ruby/internal/attr/format.h
+readline.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+readline.o: $(hdrdir)/ruby/internal/attr/noalias.h
+readline.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+readline.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+readline.o: $(hdrdir)/ruby/internal/attr/noinline.h
+readline.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+readline.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+readline.o: $(hdrdir)/ruby/internal/attr/pure.h
+readline.o: $(hdrdir)/ruby/internal/attr/restrict.h
+readline.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+readline.o: $(hdrdir)/ruby/internal/attr/warning.h
+readline.o: $(hdrdir)/ruby/internal/attr/weakref.h
+readline.o: $(hdrdir)/ruby/internal/cast.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+readline.o: $(hdrdir)/ruby/internal/compiler_since.h
+readline.o: $(hdrdir)/ruby/internal/config.h
+readline.o: $(hdrdir)/ruby/internal/constant_p.h
+readline.o: $(hdrdir)/ruby/internal/core.h
+readline.o: $(hdrdir)/ruby/internal/core/rarray.h
+readline.o: $(hdrdir)/ruby/internal/core/rbasic.h
+readline.o: $(hdrdir)/ruby/internal/core/rbignum.h
+readline.o: $(hdrdir)/ruby/internal/core/rclass.h
+readline.o: $(hdrdir)/ruby/internal/core/rdata.h
+readline.o: $(hdrdir)/ruby/internal/core/rfile.h
+readline.o: $(hdrdir)/ruby/internal/core/rhash.h
+readline.o: $(hdrdir)/ruby/internal/core/robject.h
+readline.o: $(hdrdir)/ruby/internal/core/rregexp.h
+readline.o: $(hdrdir)/ruby/internal/core/rstring.h
+readline.o: $(hdrdir)/ruby/internal/core/rstruct.h
+readline.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+readline.o: $(hdrdir)/ruby/internal/ctype.h
+readline.o: $(hdrdir)/ruby/internal/dllexport.h
+readline.o: $(hdrdir)/ruby/internal/dosish.h
+readline.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+readline.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+readline.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+readline.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+readline.o: $(hdrdir)/ruby/internal/encoding/re.h
+readline.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+readline.o: $(hdrdir)/ruby/internal/encoding/string.h
+readline.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+readline.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+readline.o: $(hdrdir)/ruby/internal/error.h
+readline.o: $(hdrdir)/ruby/internal/eval.h
+readline.o: $(hdrdir)/ruby/internal/event.h
+readline.o: $(hdrdir)/ruby/internal/fl_type.h
+readline.o: $(hdrdir)/ruby/internal/gc.h
+readline.o: $(hdrdir)/ruby/internal/glob.h
+readline.o: $(hdrdir)/ruby/internal/globals.h
+readline.o: $(hdrdir)/ruby/internal/has/attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/builtin.h
+readline.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/extension.h
+readline.o: $(hdrdir)/ruby/internal/has/feature.h
+readline.o: $(hdrdir)/ruby/internal/has/warning.h
+readline.o: $(hdrdir)/ruby/internal/intern/array.h
+readline.o: $(hdrdir)/ruby/internal/intern/bignum.h
+readline.o: $(hdrdir)/ruby/internal/intern/class.h
+readline.o: $(hdrdir)/ruby/internal/intern/compar.h
+readline.o: $(hdrdir)/ruby/internal/intern/complex.h
+readline.o: $(hdrdir)/ruby/internal/intern/cont.h
+readline.o: $(hdrdir)/ruby/internal/intern/dir.h
+readline.o: $(hdrdir)/ruby/internal/intern/enum.h
+readline.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+readline.o: $(hdrdir)/ruby/internal/intern/error.h
+readline.o: $(hdrdir)/ruby/internal/intern/eval.h
+readline.o: $(hdrdir)/ruby/internal/intern/file.h
+readline.o: $(hdrdir)/ruby/internal/intern/gc.h
+readline.o: $(hdrdir)/ruby/internal/intern/hash.h
+readline.o: $(hdrdir)/ruby/internal/intern/io.h
+readline.o: $(hdrdir)/ruby/internal/intern/load.h
+readline.o: $(hdrdir)/ruby/internal/intern/marshal.h
+readline.o: $(hdrdir)/ruby/internal/intern/numeric.h
+readline.o: $(hdrdir)/ruby/internal/intern/object.h
+readline.o: $(hdrdir)/ruby/internal/intern/parse.h
+readline.o: $(hdrdir)/ruby/internal/intern/proc.h
+readline.o: $(hdrdir)/ruby/internal/intern/process.h
+readline.o: $(hdrdir)/ruby/internal/intern/random.h
+readline.o: $(hdrdir)/ruby/internal/intern/range.h
+readline.o: $(hdrdir)/ruby/internal/intern/rational.h
+readline.o: $(hdrdir)/ruby/internal/intern/re.h
+readline.o: $(hdrdir)/ruby/internal/intern/ruby.h
+readline.o: $(hdrdir)/ruby/internal/intern/select.h
+readline.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+readline.o: $(hdrdir)/ruby/internal/intern/signal.h
+readline.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+readline.o: $(hdrdir)/ruby/internal/intern/string.h
+readline.o: $(hdrdir)/ruby/internal/intern/struct.h
+readline.o: $(hdrdir)/ruby/internal/intern/thread.h
+readline.o: $(hdrdir)/ruby/internal/intern/time.h
+readline.o: $(hdrdir)/ruby/internal/intern/variable.h
+readline.o: $(hdrdir)/ruby/internal/intern/vm.h
+readline.o: $(hdrdir)/ruby/internal/interpreter.h
+readline.o: $(hdrdir)/ruby/internal/iterator.h
+readline.o: $(hdrdir)/ruby/internal/memory.h
+readline.o: $(hdrdir)/ruby/internal/method.h
+readline.o: $(hdrdir)/ruby/internal/module.h
+readline.o: $(hdrdir)/ruby/internal/newobj.h
+readline.o: $(hdrdir)/ruby/internal/rgengc.h
+readline.o: $(hdrdir)/ruby/internal/scan_args.h
+readline.o: $(hdrdir)/ruby/internal/special_consts.h
+readline.o: $(hdrdir)/ruby/internal/static_assert.h
+readline.o: $(hdrdir)/ruby/internal/stdalign.h
+readline.o: $(hdrdir)/ruby/internal/stdbool.h
+readline.o: $(hdrdir)/ruby/internal/symbol.h
+readline.o: $(hdrdir)/ruby/internal/value.h
+readline.o: $(hdrdir)/ruby/internal/value_type.h
+readline.o: $(hdrdir)/ruby/internal/variable.h
+readline.o: $(hdrdir)/ruby/internal/warning_push.h
+readline.o: $(hdrdir)/ruby/internal/xmalloc.h
+readline.o: $(hdrdir)/ruby/io.h
+readline.o: $(hdrdir)/ruby/missing.h
+readline.o: $(hdrdir)/ruby/onigmo.h
+readline.o: $(hdrdir)/ruby/oniguruma.h
+readline.o: $(hdrdir)/ruby/ruby.h
+readline.o: $(hdrdir)/ruby/st.h
+readline.o: $(hdrdir)/ruby/subst.h
+readline.o: $(hdrdir)/ruby/thread.h
+readline.o: readline.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/readline/depend-gem b/ext/readline/depend-gem
new file mode 100644
index 0000000000..df01bd2a86
--- /dev/null
+++ b/ext/readline/depend-gem
@@ -0,0 +1,4 @@
+# AUTOGENERATED DEPENDENCIES START
+readline.o: $(RUBY_EXTCONF_H)
+readline.o: readline.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb
new file mode 100644
index 0000000000..d3e7872e65
--- /dev/null
+++ b/ext/readline/extconf.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: false
+require "mkmf"
+
+readline = Struct.new(:headers, :extra_check).new(["stdio.h"])
+
+def readline.have_header(header)
+ if super(header, &extra_check)
+ headers.push(header)
+ return true
+ else
+ return false
+ end
+end
+
+def readline.have_var(var)
+ return super(var, headers)
+end
+
+def readline.have_func(func)
+ return super(func, headers)
+end
+
+def readline.have_type(type)
+ return super(type, headers)
+end
+
+dir_config('curses')
+dir_config('ncurses')
+dir_config('termcap')
+dir_config("readline")
+enable_libedit = enable_config("libedit")
+
+have_library("user32", nil) if /cygwin/ === RUBY_PLATFORM
+have_library("ncurses", "tgetnum") ||
+ have_library("termcap", "tgetnum") ||
+ have_library("curses", "tgetnum")
+
+case enable_libedit
+when true
+ # --enable-libedit
+ dir_config("libedit")
+ unless (readline.have_header("editline/readline.h") ||
+ readline.have_header("readline/readline.h")) &&
+ have_library("edit", "readline")
+ raise "libedit not found"
+ end
+when false
+ # --disable-libedit
+ unless ((readline.have_header("readline/readline.h") &&
+ readline.have_header("readline/history.h")) &&
+ have_library("readline", "readline"))
+ raise "readline not found"
+ end
+else
+ # does not specify
+ unless ((readline.have_header("readline/readline.h") &&
+ readline.have_header("readline/history.h")) &&
+ (have_library("readline", "readline") ||
+ have_library("edit", "readline"))) ||
+ (readline.have_header("editline/readline.h") &&
+ have_library("edit", "readline"))
+ raise "Neither readline nor libedit was found"
+ end
+end
+
+readline.have_func("rl_getc")
+readline.have_func("rl_getc_function")
+readline.have_func("rl_filename_completion_function")
+readline.have_func("rl_username_completion_function")
+readline.have_func("rl_completion_matches")
+readline.have_func("rl_refresh_line")
+readline.have_var("rl_deprep_term_function")
+readline.have_var("rl_completion_append_character")
+readline.have_var("rl_completion_quote_character")
+readline.have_var("rl_basic_word_break_characters")
+readline.have_var("rl_completer_word_break_characters")
+readline.have_var("rl_basic_quote_characters")
+readline.have_var("rl_completer_quote_characters")
+readline.have_var("rl_filename_quote_characters")
+readline.have_var("rl_attempted_completion_over")
+readline.have_var("rl_library_version")
+readline.have_var("rl_editing_mode")
+readline.have_var("rl_line_buffer")
+readline.have_var("rl_point")
+readline.have_var("rl_char_is_quoted_p")
+# workaround for native windows.
+/mswin|bccwin/ !~ RUBY_PLATFORM && readline.have_var("rl_event_hook")
+/mswin|bccwin/ !~ RUBY_PLATFORM && readline.have_var("rl_catch_sigwinch")
+/mswin|bccwin/ !~ RUBY_PLATFORM && readline.have_var("rl_catch_signals")
+readline.have_var("rl_pre_input_hook")
+readline.have_var("rl_special_prefixes")
+readline.have_func("rl_cleanup_after_signal")
+readline.have_func("rl_free_line_state")
+readline.have_func("rl_clear_signals")
+readline.have_func("rl_set_screen_size")
+readline.have_func("rl_get_screen_size")
+readline.have_func("rl_vi_editing_mode")
+readline.have_func("rl_emacs_editing_mode")
+readline.have_func("replace_history_entry")
+readline.have_func("remove_history")
+readline.have_func("clear_history")
+readline.have_func("rl_redisplay")
+readline.have_func("rl_insert_text")
+readline.have_func("rl_delete_text")
+unless readline.have_type("rl_hook_func_t*")
+ # rl_hook_func_t is available since readline-4.2 (2001).
+ # Function is removed at readline-6.3 (2014).
+ # However, editline (NetBSD 6.1.3, 2014) doesn't have rl_hook_func_t.
+ $defs << "-Drl_hook_func_t=Function"
+end
+
+create_makefile("readline")
diff --git a/ext/readline/readline-ext.gemspec b/ext/readline/readline-ext.gemspec
new file mode 100644
index 0000000000..1e16edbfe6
--- /dev/null
+++ b/ext/readline/readline-ext.gemspec
@@ -0,0 +1,22 @@
+Gem::Specification.new do |spec|
+ spec.name = "readline-ext"
+ spec.version = "0.1.5"
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Provides an interface for GNU Readline and Edit Line (libedit).}
+ spec.description = %q{Provides an interface for GNU Readline and Edit Line (libedit).}
+ spec.homepage = "https://github.com/ruby/readline-ext"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+ spec.extensions = %w[ext/readline/extconf.rb]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/ext/readline/readline.c b/ext/readline/readline.c
new file mode 100644
index 0000000000..fc254ce315
--- /dev/null
+++ b/ext/readline/readline.c
@@ -0,0 +1,2144 @@
+/************************************************
+
+ readline.c - GNU Readline module
+
+ $Author$
+ created at: Wed Jan 20 13:59:32 JST 1999
+
+ Copyright (C) 1997-2008 Shugo Maeda
+ Copyright (C) 2008-2013 Kouji Takao
+
+ $Id$
+
+ Contact:
+ - Kouji Takao <kouji dot takao at gmail dot com> (current maintainer)
+
+************************************************/
+
+#ifdef RUBY_EXTCONF_H
+#include RUBY_EXTCONF_H
+#endif
+
+#include "ruby/config.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_READLINE_READLINE_H
+#include <readline/readline.h>
+#endif
+#ifdef HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif
+#ifdef HAVE_EDITLINE_READLINE_H
+#include <editline/readline.h>
+#endif
+
+#include "ruby/io.h"
+#include "ruby/thread.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+static VALUE mReadline;
+
+#define EDIT_LINE_LIBRARY_VERSION "EditLine wrapper"
+#ifndef USE_INSERT_IGNORE_ESCAPE
+# if !defined(HAVE_EDITLINE_READLINE_H) && defined(RL_PROMPT_START_IGNORE) && defined(RL_PROMPT_END_IGNORE)
+# define USE_INSERT_IGNORE_ESCAPE 1
+# else
+# define USE_INSERT_IGNORE_ESCAPE 0
+# endif
+#endif
+
+#define COMPLETION_PROC "completion_proc"
+#define COMPLETION_CASE_FOLD "completion_case_fold"
+static ID id_call, completion_proc, completion_case_fold;
+#if defined HAVE_RL_CHAR_IS_QUOTED_P
+#define QUOTING_DETECTION_PROC "quoting_detection_proc"
+static ID quoting_detection_proc;
+#endif
+#if USE_INSERT_IGNORE_ESCAPE
+static ID id_orig_prompt, id_last_prompt;
+#endif
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+static ID id_pre_input_hook;
+#endif
+#if defined(HAVE_RL_SPECIAL_PREFIXES)
+static ID id_special_prefixes;
+#endif
+
+#ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION
+# define rl_filename_completion_function filename_completion_function
+#endif
+#ifndef HAVE_RL_USERNAME_COMPLETION_FUNCTION
+# define rl_username_completion_function username_completion_function
+#else
+RUBY_EXTERN char *rl_username_completion_function(const char *, int);
+#endif
+#ifndef HAVE_RL_COMPLETION_MATCHES
+# define rl_completion_matches completion_matches
+#endif
+
+static int (*history_get_offset_func)(int);
+static int (*history_replace_offset_func)(int);
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+static int readline_completion_append_character;
+#endif
+
+static char **readline_attempted_completion_function(const char *text,
+ int start, int end);
+
+#define OutputStringValue(str) do {\
+ StringValueCStr(str);\
+ (str) = rb_str_conv_enc((str), rb_enc_get(str), rb_locale_encoding());\
+} while (0)\
+
+
+/*
+ * Document-class: Readline
+ *
+ * The Readline module provides interface for GNU Readline.
+ * This module defines a number of methods to facilitate completion
+ * and accesses input history from the Ruby interpreter.
+ * This module supported Edit Line(libedit) too.
+ * libedit is compatible with GNU Readline.
+ *
+ * GNU Readline:: http://www.gnu.org/directory/readline.html
+ * libedit:: http://www.thrysoee.dk/editline/
+ *
+ * Reads one inputted line with line edit by Readline.readline method.
+ * At this time, the facilitatation completion and the key
+ * bind like Emacs can be operated like GNU Readline.
+ *
+ * require "readline"
+ * while buf = Readline.readline("> ", true)
+ * p buf
+ * end
+ *
+ * The content that the user input can be recorded to the history.
+ * The history can be accessed by Readline::HISTORY constant.
+ *
+ * require "readline"
+ * while buf = Readline.readline("> ", true)
+ * p Readline::HISTORY.to_a
+ * print("-> ", buf, "\n")
+ * end
+ *
+ * Documented by Kouji Takao <kouji dot takao at gmail dot com>.
+ */
+
+static VALUE readline_instream;
+static VALUE readline_outstream;
+static FILE *readline_rl_instream;
+static FILE *readline_rl_outstream;
+
+static void
+mustbe_callable(VALUE proc)
+{
+ if (!NIL_P(proc) && !rb_respond_to(proc, id_call))
+ rb_raise(rb_eArgError, "argument must respond to `call'");
+}
+
+#if defined HAVE_RL_GETC_FUNCTION
+
+#ifndef HAVE_RL_GETC
+#define rl_getc(f) EOF
+#endif
+
+struct getc_struct {
+ FILE *input;
+ int fd;
+ int ret;
+ int err;
+};
+
+static int
+getc_body(struct getc_struct *p)
+{
+ char ch;
+ ssize_t ss;
+
+#if defined(_WIN32)
+ {
+ INPUT_RECORD ir;
+ DWORD n;
+ static int prior_key = '0';
+ for (;;) {
+ HANDLE h;
+ if (prior_key > 0xff) {
+ prior_key = rl_getc(p->input);
+ return prior_key;
+ }
+ h = (HANDLE)_get_osfhandle(p->fd);
+ if (PeekConsoleInput(h, &ir, 1, &n)) {
+ if (n == 1) {
+ if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) {
+ prior_key = rl_getc(p->input);
+ return prior_key;
+ } else {
+ ReadConsoleInput(h, &ir, 1, &n);
+ }
+ } else {
+ rb_w32_wait_events_blocking(&h, 1, INFINITE);
+ }
+ } else {
+ break;
+ }
+ }
+ }
+#endif
+
+ ss = read(p->fd, &ch, 1);
+ if (ss == 0) {
+ errno = 0;
+ return EOF;
+ }
+ if (ss != 1)
+ return EOF;
+ return (unsigned char)ch;
+}
+
+static void *
+getc_func(void *data1)
+{
+ struct getc_struct *p = data1;
+ errno = 0;
+ p->ret = getc_body(p);
+ p->err = errno;
+ return NULL;
+}
+
+static int
+readline_getc(FILE *input)
+{
+ struct getc_struct data;
+ if (input == NULL) /* editline may give NULL as input. */
+ input = stdin;
+ data.input = input;
+ data.fd = fileno(input);
+ again:
+ data.ret = EOF;
+ data.err = EINTR; /* getc_func is not called if already interrupted. */
+ rb_thread_call_without_gvl2(getc_func, &data, RUBY_UBF_IO, NULL);
+ if (data.ret == EOF) {
+ if (data.err == 0) {
+ return EOF;
+ }
+ if (data.err == EINTR) {
+ rb_thread_check_ints();
+ goto again;
+ }
+ if (data.err == EWOULDBLOCK || data.err == EAGAIN) {
+ int ret;
+ if (fileno(input) != data.fd)
+ rb_bug("readline_getc: input closed unexpectedly or memory corrupted");
+ ret = rb_wait_for_single_fd(data.fd, RB_WAITFD_IN, NULL);
+ if (ret != -1 || errno == EINTR)
+ goto again;
+ rb_sys_fail("rb_wait_for_single_fd");
+ }
+ rb_syserr_fail(data.err, "read");
+ }
+ return data.ret;
+}
+
+#elif defined HAVE_RL_EVENT_HOOK
+#define BUSY_WAIT 0
+
+static int readline_event(void);
+static int
+readline_event(void)
+{
+#if BUSY_WAIT
+ rb_thread_schedule();
+#else
+ rb_wait_for_single_fd(fileno(rl_instream), RB_WAITFD_IN, NULL);
+ return 0;
+#endif
+}
+#endif
+
+#if USE_INSERT_IGNORE_ESCAPE
+static VALUE
+insert_ignore_escape(VALUE self, VALUE prompt)
+{
+ VALUE last_prompt, orig_prompt = rb_attr_get(self, id_orig_prompt);
+ int ignoring = 0;
+ const char *s0, *s, *e;
+ long len;
+ static const char ignore_code[2] = {RL_PROMPT_START_IGNORE, RL_PROMPT_END_IGNORE};
+
+ prompt = rb_str_new_shared(prompt);
+ last_prompt = rb_attr_get(self, id_last_prompt);
+ if (orig_prompt == prompt) return last_prompt;
+ len = RSTRING_LEN(prompt);
+ if (NIL_P(last_prompt)) {
+ last_prompt = rb_str_tmp_new(len);
+ }
+
+ s = s0 = RSTRING_PTR(prompt);
+ e = s0 + len;
+ rb_str_set_len(last_prompt, 0);
+ while (s < e && *s) {
+ switch (*s) {
+ case RL_PROMPT_START_IGNORE:
+ ignoring = -1;
+ rb_str_cat(last_prompt, s0, ++s - s0);
+ s0 = s;
+ break;
+ case RL_PROMPT_END_IGNORE:
+ ignoring = 0;
+ rb_str_cat(last_prompt, s0, ++s - s0);
+ s0 = s;
+ break;
+ case '\033':
+ if (++s < e && *s == '[') {
+ rb_str_cat(last_prompt, s0, s - s0 - 1);
+ s0 = s - 1;
+ while (++s < e && *s) {
+ if (ISALPHA(*(unsigned char *)s)) {
+ if (!ignoring) {
+ ignoring = 1;
+ rb_str_cat(last_prompt, ignore_code+0, 1);
+ }
+ rb_str_cat(last_prompt, s0, ++s - s0);
+ s0 = s;
+ break;
+ }
+ else if (!(('0' <= *s && *s <= '9') || *s == ';')) {
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ if (ignoring > 0) {
+ ignoring = 0;
+ rb_str_cat(last_prompt, ignore_code+1, 1);
+ }
+ s++;
+ break;
+ }
+ }
+ if (ignoring > 0) {
+ ignoring = 0;
+ rb_str_cat(last_prompt, ignore_code+1, 1);
+ }
+ rb_str_cat(last_prompt, s0, s - s0);
+
+ rb_ivar_set(self, id_orig_prompt, prompt);
+ rb_ivar_set(self, id_last_prompt, last_prompt);
+
+ return last_prompt;
+}
+#endif
+
+static VALUE
+readline_get(VALUE prompt)
+{
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+ readline_completion_append_character = rl_completion_append_character;
+#endif
+ return (VALUE)readline((char *)prompt);
+}
+
+static void
+clear_rl_instream(void)
+{
+ if (readline_rl_instream) {
+ fclose(readline_rl_instream);
+ if (rl_instream == readline_rl_instream)
+ rl_instream = NULL;
+ readline_rl_instream = NULL;
+ }
+ readline_instream = Qfalse;
+}
+
+static void
+clear_rl_outstream(void)
+{
+ if (readline_rl_outstream) {
+ fclose(readline_rl_outstream);
+ if (rl_outstream == readline_rl_outstream)
+ rl_outstream = NULL;
+ readline_rl_outstream = NULL;
+ }
+ readline_outstream = Qfalse;
+}
+
+static void
+prepare_readline(void)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ rl_initialize();
+ initialized = 1;
+ }
+
+ if (readline_instream) {
+ rb_io_t *ifp;
+ rb_io_check_initialized(ifp = RFILE(rb_io_taint_check(readline_instream))->fptr);
+ if (ifp->fd < 0) {
+ clear_rl_instream();
+ rb_raise(rb_eIOError, "closed readline input");
+ }
+ }
+
+ if (readline_outstream) {
+ rb_io_t *ofp;
+ rb_io_check_initialized(ofp = RFILE(rb_io_taint_check(readline_outstream))->fptr);
+ if (ofp->fd < 0) {
+ clear_rl_outstream();
+ rb_raise(rb_eIOError, "closed readline output");
+ }
+ }
+}
+
+/*
+ * call-seq:
+ * Readline.readline(prompt = "", add_hist = false) -> string or nil
+ *
+ * Shows the +prompt+ and reads the inputted line with line editing.
+ * The inputted line is added to the history if +add_hist+ is true.
+ *
+ * Returns nil when the inputted line is empty and user inputs EOF
+ * (Presses ^D on UNIX).
+ *
+ * Raises IOError exception if one of below conditions are satisfied.
+ * 1. stdin was closed.
+ * 2. stdout was closed.
+ *
+ * This method supports thread. Switches the thread context when waits
+ * inputting line.
+ *
+ * Supports line edit when inputs line. Provides VI and Emacs editing mode.
+ * Default is Emacs editing mode.
+ *
+ * NOTE: Terminates ruby interpreter and does not return the terminal
+ * status after user pressed '^C' when wait inputting line.
+ * Give 3 examples that avoid it.
+ *
+ * * Catches the Interrupt exception by pressed ^C after returns
+ * terminal status:
+ *
+ * require "readline"
+ *
+ * stty_save = `stty -g`.chomp
+ * begin
+ * while buf = Readline.readline
+ * p buf
+ * end
+ * rescue Interrupt
+ * system("stty", stty_save)
+ * exit
+ * end
+ * end
+ * end
+ *
+ * * Catches the INT signal by pressed ^C after returns terminal
+ * status:
+ *
+ * require "readline"
+ *
+ * stty_save = `stty -g`.chomp
+ * trap("INT") { system "stty", stty_save; exit }
+ *
+ * while buf = Readline.readline
+ * p buf
+ * end
+ *
+ * * Ignores pressing ^C:
+ *
+ * require "readline"
+ *
+ * trap("INT", "SIG_IGN")
+ *
+ * while buf = Readline.readline
+ * p buf
+ * end
+ *
+ * Can make as follows with Readline::HISTORY constant.
+ * It does not record to the history if the inputted line is empty or
+ * the same it as last one.
+ *
+ * require "readline"
+ *
+ * while buf = Readline.readline("> ", true)
+ * # p Readline::HISTORY.to_a
+ * Readline::HISTORY.pop if /^\s*$/ =~ buf
+ *
+ * begin
+ * if Readline::HISTORY[Readline::HISTORY.length-2] == buf
+ * Readline::HISTORY.pop
+ * end
+ * rescue IndexError
+ * end
+ *
+ * # p Readline::HISTORY.to_a
+ * print "-> ", buf, "\n"
+ * end
+ */
+static VALUE
+readline_readline(int argc, VALUE *argv, VALUE self)
+{
+ VALUE tmp, add_hist, result;
+ char *prompt = NULL;
+ char *buff;
+ int status;
+
+ if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) {
+ OutputStringValue(tmp);
+#if USE_INSERT_IGNORE_ESCAPE
+ tmp = insert_ignore_escape(self, tmp);
+ rb_str_locktmp(tmp);
+#endif
+ prompt = RSTRING_PTR(tmp);
+ }
+
+ prepare_readline();
+
+#ifdef _WIN32
+ rl_prep_terminal(1);
+#endif
+ buff = (char*)rb_protect(readline_get, (VALUE)prompt, &status);
+#if USE_INSERT_IGNORE_ESCAPE
+ if (prompt) {
+ rb_str_unlocktmp(tmp);
+ }
+#endif
+ if (status) {
+#if defined HAVE_RL_CLEANUP_AFTER_SIGNAL
+ /* restore terminal mode and signal handler*/
+#if defined HAVE_RL_FREE_LINE_STATE
+ rl_free_line_state();
+#endif
+ rl_cleanup_after_signal();
+#elif defined HAVE_RL_DEPREP_TERM_FUNCTION
+ /* restore terminal mode */
+ if (rl_deprep_term_function != NULL) /* NULL in libedit. [ruby-dev:29116] */
+ (*rl_deprep_term_function)();
+ else
+#else
+ rl_deprep_terminal();
+#endif
+ rb_jump_tag(status);
+ }
+
+ if (RTEST(add_hist) && buff) {
+ add_history(buff);
+ }
+ if (buff) {
+ result = rb_locale_str_new_cstr(buff);
+ }
+ else
+ result = Qnil;
+ if (buff) free(buff);
+ return result;
+}
+
+/*
+ * call-seq:
+ * Readline.input = input
+ *
+ * Specifies a File object +input+ that is input stream for
+ * Readline.readline method.
+ */
+static VALUE
+readline_s_set_input(VALUE self, VALUE input)
+{
+ rb_io_t *ifp;
+ int fd;
+ FILE *f;
+
+ if (NIL_P(input)) {
+ clear_rl_instream();
+ }
+ else {
+ Check_Type(input, T_FILE);
+ GetOpenFile(input, ifp);
+ clear_rl_instream();
+ fd = rb_cloexec_dup(ifp->fd);
+ if (fd == -1)
+ rb_sys_fail("dup");
+ f = fdopen(fd, "r");
+ if (f == NULL) {
+ int save_errno = errno;
+ close(fd);
+ rb_syserr_fail(save_errno, "fdopen");
+ }
+ rl_instream = readline_rl_instream = f;
+ readline_instream = input;
+ }
+ return input;
+}
+
+/*
+ * call-seq:
+ * Readline.output = output
+ *
+ * Specifies a File object +output+ that is output stream for
+ * Readline.readline method.
+ */
+static VALUE
+readline_s_set_output(VALUE self, VALUE output)
+{
+ rb_io_t *ofp;
+ int fd;
+ FILE *f;
+
+ if (NIL_P(output)) {
+ clear_rl_outstream();
+ }
+ else {
+ Check_Type(output, T_FILE);
+ GetOpenFile(output, ofp);
+ clear_rl_outstream();
+ fd = rb_cloexec_dup(ofp->fd);
+ if (fd == -1)
+ rb_sys_fail("dup");
+ f = fdopen(fd, "w");
+ if (f == NULL) {
+ int save_errno = errno;
+ close(fd);
+ rb_syserr_fail(save_errno, "fdopen");
+ }
+ rl_outstream = readline_rl_outstream = f;
+ readline_outstream = output;
+ }
+ return output;
+}
+
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+/*
+ * call-seq:
+ * Readline.pre_input_hook = proc
+ *
+ * Specifies a Proc object +proc+ to call after the first prompt has
+ * been printed and just before readline starts reading input
+ * characters.
+ *
+ * See GNU Readline's rl_pre_input_hook variable.
+ *
+ * Raises ArgumentError if +proc+ does not respond to the call method.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_pre_input_hook(VALUE self, VALUE proc)
+{
+ mustbe_callable(proc);
+ return rb_ivar_set(mReadline, id_pre_input_hook, proc);
+}
+
+/*
+ * call-seq:
+ * Readline.pre_input_hook -> proc
+ *
+ * Returns a Proc object +proc+ to call after the first prompt has
+ * been printed and just before readline starts reading input
+ * characters. The default is nil.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_pre_input_hook(VALUE self)
+{
+ return rb_attr_get(mReadline, id_pre_input_hook);
+}
+
+static int
+readline_pre_input_hook(void)
+{
+ VALUE proc;
+
+ proc = rb_attr_get(mReadline, id_pre_input_hook);
+ if (!NIL_P(proc))
+ rb_funcall(proc, id_call, 0);
+ return 0;
+}
+#else
+#define readline_s_set_pre_input_hook rb_f_notimplement
+#define readline_s_get_pre_input_hook rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_INSERT_TEXT)
+/*
+ * call-seq:
+ * Readline.insert_text(string) -> self
+ *
+ * Insert text into the line at the current cursor position.
+ *
+ * See GNU Readline's rl_insert_text function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_insert_text(VALUE self, VALUE str)
+{
+ OutputStringValue(str);
+ rl_insert_text(RSTRING_PTR(str));
+ return self;
+}
+#else
+#define readline_s_insert_text rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_DELETE_TEXT)
+RUBY_EXTERN int rl_delete_text(int, int);
+static const char *
+str_subpos(const char *ptr, const char *end, long beg, long *sublen, rb_encoding *enc)
+{
+ VALUE str = rb_enc_str_new_static(ptr, end-ptr, enc);
+ OBJ_FREEZE(str);
+ ptr = rb_str_subpos(str, beg, sublen);
+ return ptr;
+}
+
+/*
+ * call-seq:
+ * Readline.delete_text([start[, length]]) -> self
+ * Readline.delete_text(start..end) -> self
+ * Readline.delete_text() -> self
+ *
+ * Delete text between start and end in the current line.
+ *
+ * See GNU Readline's rl_delete_text function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_delete_text(int argc, VALUE *argv, VALUE self)
+{
+ rb_check_arity(argc, 0, 2);
+ if (rl_line_buffer) {
+ const char *p, *ptr = rl_line_buffer;
+ long beg = 0, len = strlen(ptr);
+ const char *end = ptr + len;
+ rb_encoding *enc = rb_locale_encoding();
+ if (argc == 2) {
+ beg = NUM2LONG(argv[0]);
+ len = NUM2LONG(argv[1]);
+ num_pos:
+ p = str_subpos(ptr, end, beg, &len, enc);
+ if (!p) rb_raise(rb_eArgError, "invalid index");
+ beg = p - ptr;
+ }
+ else if (argc == 1) {
+ len = rb_enc_strlen(ptr, ptr + len, enc);
+ if (!rb_range_beg_len(argv[0], &beg, &len, len, 1)) {
+ beg = NUM2LONG(argv[0]);
+ goto num_pos;
+ }
+ }
+ rl_delete_text(rb_long2int(beg), rb_long2int(beg + len));
+ }
+ return self;
+}
+#else
+#define readline_s_delete_text rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_REDISPLAY)
+/*
+ * call-seq:
+ * Readline.redisplay -> self
+ *
+ * Change what's displayed on the screen to reflect the current
+ * contents.
+ *
+ * See GNU Readline's rl_redisplay function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_redisplay(VALUE self)
+{
+ rl_redisplay();
+ return self;
+}
+#else
+#define readline_s_redisplay rb_f_notimplement
+#endif
+
+/*
+ * call-seq:
+ * Readline.completion_proc = proc
+ *
+ * Specifies a Proc object +proc+ to determine completion behavior. It
+ * should take input string and return an array of completion candidates.
+ *
+ * The default completion is used if +proc+ is nil.
+ *
+ * The String that is passed to the Proc depends on the
+ * Readline.completer_word_break_characters property. By default the word
+ * under the cursor is passed to the Proc. For example, if the input is "foo
+ * bar" then only "bar" would be passed to the completion Proc.
+ *
+ * Upon successful completion the Readline.completion_append_character will be
+ * appended to the input so the user can start working on their next argument.
+ *
+ * = Examples
+ *
+ * == Completion for a Static List
+ *
+ * require 'readline'
+ *
+ * LIST = [
+ * 'search', 'download', 'open',
+ * 'help', 'history', 'quit',
+ * 'url', 'next', 'clear',
+ * 'prev', 'past'
+ * ].sort
+ *
+ * comp = proc { |s| LIST.grep(/^#{Regexp.escape(s)}/) }
+ *
+ * Readline.completion_append_character = " "
+ * Readline.completion_proc = comp
+ *
+ * while line = Readline.readline('> ', true)
+ * p line
+ * end
+ *
+ * == Completion For Directory Contents
+ *
+ * require 'readline'
+ *
+ * Readline.completion_append_character = " "
+ * Readline.completion_proc = Proc.new do |str|
+ * Dir[str+'*'].grep(/^#{Regexp.escape(str)}/)
+ * end
+ *
+ * while line = Readline.readline('> ', true)
+ * p line
+ * end
+ *
+ * = Autocomplete strategies
+ *
+ * When working with auto-complete there are some strategies that work well.
+ * To get some ideas you can take a look at the
+ * completion.rb[https://git.ruby-lang.org/ruby.git/tree/lib/irb/completion.rb]
+ * file for irb.
+ *
+ * The common strategy is to take a list of possible completions and filter it
+ * down to those completions that start with the user input. In the above
+ * examples Enumerator.grep is used. The input is escaped to prevent Regexp
+ * special characters from interfering with the matching.
+ *
+ * It may also be helpful to use the Abbrev library to generate completions.
+ *
+ * Raises ArgumentError if +proc+ does not respond to the call method.
+ */
+static VALUE
+readline_s_set_completion_proc(VALUE self, VALUE proc)
+{
+ mustbe_callable(proc);
+ return rb_ivar_set(mReadline, completion_proc, proc);
+}
+
+/*
+ * call-seq:
+ * Readline.completion_proc -> proc
+ *
+ * Returns the completion Proc object.
+ */
+static VALUE
+readline_s_get_completion_proc(VALUE self)
+{
+ return rb_attr_get(mReadline, completion_proc);
+}
+
+#ifdef HAVE_RL_CHAR_IS_QUOTED_P
+/*
+ * call-seq:
+ * Readline.quoting_detection_proc = proc
+ *
+ * Specifies a Proc object +proc+ to determine if a character in the user's
+ * input is escaped. It should take the user's input and the index of the
+ * character in question as input, and return a boolean (true if the specified
+ * character is escaped).
+ *
+ * Readline will only call this proc with characters specified in
+ * +completer_quote_characters+, to discover if they indicate the end of a
+ * quoted argument, or characters specified in
+ * +completer_word_break_characters+, to discover if they indicate a break
+ * between arguments.
+ *
+ * If +completer_quote_characters+ is not set, or if the user input doesn't
+ * contain one of the +completer_quote_characters+ or a +\+ character,
+ * Readline will not attempt to use this proc at all.
+ *
+ * Raises ArgumentError if +proc+ does not respond to the call method.
+ */
+static VALUE
+readline_s_set_quoting_detection_proc(VALUE self, VALUE proc)
+{
+ mustbe_callable(proc);
+ return rb_ivar_set(mReadline, quoting_detection_proc, proc);
+}
+
+/*
+ * call-seq:
+ * Readline.quoting_detection_proc -> proc
+ *
+ * Returns the quoting detection Proc object.
+ */
+static VALUE
+readline_s_get_quoting_detection_proc(VALUE self)
+{
+ return rb_attr_get(mReadline, quoting_detection_proc);
+}
+#else
+#define readline_s_set_quoting_detection_proc rb_f_notimplement
+#define readline_s_get_quoting_detection_proc rb_f_notimplement
+#endif
+
+/*
+ * call-seq:
+ * Readline.completion_case_fold = bool
+ *
+ * Sets whether or not to ignore case on completion.
+ */
+static VALUE
+readline_s_set_completion_case_fold(VALUE self, VALUE val)
+{
+ return rb_ivar_set(mReadline, completion_case_fold, val);
+}
+
+/*
+ * call-seq:
+ * Readline.completion_case_fold -> bool
+ *
+ * Returns true if completion ignores case. If no, returns false.
+ *
+ * NOTE: Returns the same object that is specified by
+ * Readline.completion_case_fold= method.
+ *
+ * require "readline"
+ *
+ * Readline.completion_case_fold = "This is a String."
+ * p Readline.completion_case_fold # => "This is a String."
+ */
+static VALUE
+readline_s_get_completion_case_fold(VALUE self)
+{
+ return rb_attr_get(mReadline, completion_case_fold);
+}
+
+#ifdef HAVE_RL_LINE_BUFFER
+/*
+ * call-seq:
+ * Readline.line_buffer -> string
+ *
+ * Returns the full line that is being edited. This is useful from
+ * within the complete_proc for determining the context of the
+ * completion request.
+ *
+ * The length of +Readline.line_buffer+ and GNU Readline's rl_end are
+ * same.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_line_buffer(VALUE self)
+{
+ if (rl_line_buffer == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_line_buffer);
+}
+#else
+#define readline_s_get_line_buffer rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_POINT
+/*
+ * call-seq:
+ * Readline.point -> int
+ *
+ * Returns the index of the current cursor position in
+ * +Readline.line_buffer+.
+ *
+ * The index in +Readline.line_buffer+ which matches the start of
+ * input-string passed to completion_proc is computed by subtracting
+ * the length of input-string from +Readline.point+.
+ *
+ * start = (the length of input-string) - Readline.point
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_point(VALUE self)
+{
+ return INT2NUM(rl_point);
+}
+
+/*
+ * call-seq:
+ * Readline.point = int
+ *
+ * Set the index of the current cursor position in
+ * +Readline.line_buffer+.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ *
+ * See +Readline.point+.
+ */
+static VALUE
+readline_s_set_point(VALUE self, VALUE pos)
+{
+ rl_point = NUM2INT(pos);
+ return pos;
+}
+#else
+#define readline_s_get_point rb_f_notimplement
+#define readline_s_set_point rb_f_notimplement
+#endif
+
+static char **
+readline_attempted_completion_function(const char *text, int start, int end)
+{
+ VALUE proc, ary, temp;
+ char **result;
+ int case_fold;
+ long i, matches;
+ rb_encoding *enc;
+ VALUE encobj;
+
+ proc = rb_attr_get(mReadline, completion_proc);
+ if (NIL_P(proc))
+ return NULL;
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+ rl_completion_append_character = readline_completion_append_character;
+#endif
+#ifdef HAVE_RL_ATTEMPTED_COMPLETION_OVER
+ rl_attempted_completion_over = 1;
+#endif
+ case_fold = RTEST(rb_attr_get(mReadline, completion_case_fold));
+ ary = rb_funcall(proc, id_call, 1, rb_locale_str_new_cstr(text));
+ if (!RB_TYPE_P(ary, T_ARRAY))
+ ary = rb_Array(ary);
+ matches = RARRAY_LEN(ary);
+ if (matches == 0) return NULL;
+ result = (char**)malloc((matches + 2)*sizeof(char*));
+ if (result == NULL) rb_memerror();
+ enc = rb_locale_encoding();
+ encobj = rb_enc_from_encoding(enc);
+ for (i = 0; i < matches; i++) {
+ temp = rb_obj_as_string(RARRAY_AREF(ary, i));
+ StringValueCStr(temp); /* must be NUL-terminated */
+ rb_enc_check(encobj, temp);
+ result[i + 1] = (char*)malloc(RSTRING_LEN(temp) + 1);
+ if (result[i + 1] == NULL) rb_memerror();
+ strcpy(result[i + 1], RSTRING_PTR(temp));
+ }
+ result[matches + 1] = NULL;
+
+ if (matches == 1) {
+ result[0] = strdup(result[1]);
+ }
+ else {
+ const char *result1 = result[1];
+ long low = strlen(result1);
+
+ for (i = 1; i < matches; ++i) {
+ register int c1, c2;
+ long i1, i2, l2;
+ int n1, n2;
+ const char *p2 = result[i + 1];
+
+ l2 = strlen(p2);
+ for (i1 = i2 = 0; i1 < low && i2 < l2; i1 += n1, i2 += n2) {
+ c1 = rb_enc_codepoint_len(result1 + i1, result1 + low, &n1, enc);
+ c2 = rb_enc_codepoint_len(p2 + i2, p2 + l2, &n2, enc);
+ if (case_fold) {
+ c1 = rb_tolower(c1);
+ c2 = rb_tolower(c2);
+ }
+ if (c1 != c2) break;
+ }
+
+ low = i1;
+ }
+ result[0] = (char*)malloc(low + 1);
+ if (result[0] == NULL) rb_memerror();
+ strncpy(result[0], result[1], low);
+ result[0][low] = '\0';
+ }
+
+ return result;
+}
+
+#ifdef HAVE_RL_CHAR_IS_QUOTED_P
+static int
+readline_char_is_quoted(char *text, int byte_index)
+{
+ VALUE proc, result, str;
+ long char_index;
+ size_t len;
+
+ proc = rb_attr_get(mReadline, quoting_detection_proc);
+ if (NIL_P(proc)) {
+ return 0;
+ }
+
+ len = strlen(text);
+ if (byte_index < 0 || len < (size_t)byte_index) {
+ rb_raise(rb_eIndexError, "invalid byte index (%d in %"PRIdSIZE")",
+ byte_index, len);
+ }
+
+ str = rb_locale_str_new(text, len);
+ char_index = rb_str_sublen(str, byte_index);
+ result = rb_funcall(proc, id_call, 2, str, LONG2FIX(char_index));
+ return RTEST(result);
+}
+#endif
+
+#ifdef HAVE_RL_SET_SCREEN_SIZE
+/*
+ * call-seq:
+ * Readline.set_screen_size(rows, columns) -> self
+ *
+ * Set terminal size to +rows+ and +columns+.
+ *
+ * See GNU Readline's rl_set_screen_size function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_screen_size(VALUE self, VALUE rows, VALUE columns)
+{
+ rl_set_screen_size(NUM2INT(rows), NUM2INT(columns));
+ return self;
+}
+#else
+#define readline_s_set_screen_size rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_GET_SCREEN_SIZE
+/*
+ * call-seq:
+ * Readline.get_screen_size -> [rows, columns]
+ *
+ * Returns the terminal's rows and columns.
+ *
+ * See GNU Readline's rl_get_screen_size function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_screen_size(VALUE self)
+{
+ int rows, columns;
+ VALUE res;
+
+ rl_get_screen_size(&rows, &columns);
+ res = rb_ary_new();
+ rb_ary_push(res, INT2NUM(rows));
+ rb_ary_push(res, INT2NUM(columns));
+ return res;
+}
+#else
+#define readline_s_get_screen_size rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_VI_EDITING_MODE
+RUBY_EXTERN int rl_vi_editing_mode(int, int);
+/*
+ * call-seq:
+ * Readline.vi_editing_mode -> nil
+ *
+ * Specifies VI editing mode. See the manual of GNU Readline for
+ * details of VI editing mode.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_vi_editing_mode(VALUE self)
+{
+ rl_vi_editing_mode(1,0);
+ return Qnil;
+}
+#else
+#define readline_s_vi_editing_mode rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_EDITING_MODE
+/*
+ * call-seq:
+ * Readline.vi_editing_mode? -> bool
+ *
+ * Returns true if vi mode is active. Returns false if not.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_vi_editing_mode_p(VALUE self)
+{
+ return rl_editing_mode == 0 ? Qtrue : Qfalse;
+}
+#else
+#define readline_s_vi_editing_mode_p rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_EMACS_EDITING_MODE
+RUBY_EXTERN int rl_emacs_editing_mode(int, int);
+/*
+ * call-seq:
+ * Readline.emacs_editing_mode -> nil
+ *
+ * Specifies Emacs editing mode. The default is this mode. See the
+ * manual of GNU Readline for details of Emacs editing mode.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_emacs_editing_mode(VALUE self)
+{
+ rl_emacs_editing_mode(1,0);
+ return Qnil;
+}
+#else
+#define readline_s_emacs_editing_mode rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_EDITING_MODE
+/*
+ * call-seq:
+ * Readline.emacs_editing_mode? -> bool
+ *
+ * Returns true if emacs mode is active. Returns false if not.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_emacs_editing_mode_p(VALUE self)
+{
+ return rl_editing_mode == 1 ? Qtrue : Qfalse;
+}
+#else
+#define readline_s_emacs_editing_mode_p rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+/*
+ * call-seq:
+ * Readline.completion_append_character = char
+ *
+ * Specifies a character to be appended on completion.
+ * Nothing will be appended if an empty string ("") or nil is
+ * specified.
+ *
+ * For example:
+ * require "readline"
+ *
+ * Readline.readline("> ", true)
+ * Readline.completion_append_character = " "
+ *
+ * Result:
+ * >
+ * Input "/var/li".
+ *
+ * > /var/li
+ * Press TAB key.
+ *
+ * > /var/lib
+ * Completes "b" and appends " ". So, you can continuously input "/usr".
+ *
+ * > /var/lib /usr
+ *
+ * NOTE: Only one character can be specified. When "string" is
+ * specified, sets only "s" that is the first.
+ *
+ * require "readline"
+ *
+ * Readline.completion_append_character = "string"
+ * p Readline.completion_append_character # => "s"
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_completion_append_character(VALUE self, VALUE str)
+{
+ if (NIL_P(str)) {
+ rl_completion_append_character = '\0';
+ }
+ else {
+ OutputStringValue(str);
+ if (RSTRING_LEN(str) == 0) {
+ rl_completion_append_character = '\0';
+ } else {
+ rl_completion_append_character = RSTRING_PTR(str)[0];
+ }
+ }
+ return self;
+}
+#else
+#define readline_s_set_completion_append_character rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+/*
+ * call-seq:
+ * Readline.completion_append_character -> char
+ *
+ * Returns a string containing a character to be appended on
+ * completion. The default is a space (" ").
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_completion_append_character(VALUE self)
+{
+ char buf[1];
+
+ if (rl_completion_append_character == '\0')
+ return Qnil;
+
+ buf[0] = (char) rl_completion_append_character;
+ return rb_locale_str_new(buf, 1);
+}
+#else
+#define readline_s_get_completion_append_character rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETION_QUOTE_CHARACTER
+/*
+ * call-seq:
+ * Readline.completion_quote_character -> char
+ *
+ * When called during a completion (e.g. from within your completion_proc),
+ * it will return a string containing the character used to quote the
+ * argument being completed, or nil if the argument is unquoted.
+ *
+ * When called at other times, it will always return nil.
+ *
+ * Note that Readline.completer_quote_characters must be set,
+ * or this method will always return nil.
+ */
+static VALUE
+readline_s_get_completion_quote_character(VALUE self)
+{
+ char buf[1];
+
+ if (rl_completion_quote_character == '\0')
+ return Qnil;
+
+ buf[0] = (char) rl_completion_quote_character;
+ return rb_locale_str_new(buf, 1);
+}
+#else
+#define readline_s_get_completion_quote_character rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_word_break_characters = string
+ *
+ * Sets the basic list of characters that signal a break between words
+ * for the completer routine. The default is the characters which
+ * break words for completion in Bash: " \t\n\"\\'`@$><=;|&{(".
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_basic_word_break_characters(VALUE self, VALUE str)
+{
+ static char *basic_word_break_characters = NULL;
+
+ OutputStringValue(str);
+ if (basic_word_break_characters == NULL) {
+ basic_word_break_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(basic_word_break_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(basic_word_break_characters,
+ RSTRING_PTR(str), RSTRING_LEN(str));
+ basic_word_break_characters[RSTRING_LEN(str)] = '\0';
+ rl_basic_word_break_characters = basic_word_break_characters;
+ return self;
+}
+#else
+#define readline_s_set_basic_word_break_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_word_break_characters -> string
+ *
+ * Gets the basic list of characters that signal a break between words
+ * for the completer routine.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_basic_word_break_characters(VALUE self)
+{
+ if (rl_basic_word_break_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_basic_word_break_characters);
+}
+#else
+#define readline_s_get_basic_word_break_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_word_break_characters = string
+ *
+ * Sets the basic list of characters that signal a break between words
+ * for rl_complete_internal(). The default is the value of
+ * Readline.basic_word_break_characters.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_completer_word_break_characters(VALUE self, VALUE str)
+{
+ static char *completer_word_break_characters = NULL;
+
+ OutputStringValue(str);
+ if (completer_word_break_characters == NULL) {
+ completer_word_break_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(completer_word_break_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(completer_word_break_characters,
+ RSTRING_PTR(str), RSTRING_LEN(str));
+ completer_word_break_characters[RSTRING_LEN(str)] = '\0';
+ rl_completer_word_break_characters = completer_word_break_characters;
+ return self;
+}
+#else
+#define readline_s_set_completer_word_break_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_word_break_characters -> string
+ *
+ * Gets the basic list of characters that signal a break between words
+ * for rl_complete_internal().
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_completer_word_break_characters(VALUE self)
+{
+ if (rl_completer_word_break_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_completer_word_break_characters);
+}
+#else
+#define readline_s_get_completer_word_break_characters rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_SPECIAL_PREFIXES)
+/*
+ * call-seq:
+ * Readline.special_prefixes = string
+ *
+ * Sets the list of characters that are word break characters, but
+ * should be left in text when it is passed to the completion
+ * function. Programs can use this to help determine what kind of
+ * completing to do. For instance, Bash sets this variable to "$@" so
+ * that it can complete shell variables and hostnames.
+ *
+ * See GNU Readline's rl_special_prefixes variable.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_special_prefixes(VALUE self, VALUE str)
+{
+ if (!NIL_P(str)) {
+ OutputStringValue(str);
+ str = rb_str_dup_frozen(str);
+ rb_obj_hide(str);
+ }
+ rb_ivar_set(mReadline, id_special_prefixes, str);
+ if (NIL_P(str)) {
+ rl_special_prefixes = NULL;
+ }
+ else {
+ rl_special_prefixes = RSTRING_PTR(str);
+ }
+ return self;
+}
+
+/*
+ * call-seq:
+ * Readline.special_prefixes -> string
+ *
+ * Gets the list of characters that are word break characters, but
+ * should be left in text when it is passed to the completion
+ * function.
+ *
+ * See GNU Readline's rl_special_prefixes variable.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_special_prefixes(VALUE self)
+{
+ VALUE str;
+ if (rl_special_prefixes == NULL) return Qnil;
+ str = rb_ivar_get(mReadline, id_special_prefixes);
+ if (!NIL_P(str)) {
+ str = rb_str_dup_frozen(str);
+ rb_obj_reveal(str, rb_cString);
+ }
+ return str;
+}
+#else
+#define readline_s_set_special_prefixes rb_f_notimplement
+#define readline_s_get_special_prefixes rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_quote_characters = string
+ *
+ * Sets a list of quote characters which can cause a word break.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_basic_quote_characters(VALUE self, VALUE str)
+{
+ static char *basic_quote_characters = NULL;
+
+ OutputStringValue(str);
+ if (basic_quote_characters == NULL) {
+ basic_quote_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(basic_quote_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(basic_quote_characters,
+ RSTRING_PTR(str), RSTRING_LEN(str));
+ basic_quote_characters[RSTRING_LEN(str)] = '\0';
+ rl_basic_quote_characters = basic_quote_characters;
+
+ return self;
+}
+#else
+#define readline_s_set_basic_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_quote_characters -> string
+ *
+ * Gets a list of quote characters which can cause a word break.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_basic_quote_characters(VALUE self)
+{
+ if (rl_basic_quote_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_basic_quote_characters);
+}
+#else
+#define readline_s_get_basic_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_quote_characters = string
+ *
+ * Sets a list of characters which can be used to quote a substring of
+ * the line. Completion occurs on the entire substring, and within
+ * the substring Readline.completer_word_break_characters are treated
+ * as any other character, unless they also appear within this list.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_completer_quote_characters(VALUE self, VALUE str)
+{
+ static char *completer_quote_characters = NULL;
+
+ OutputStringValue(str);
+ if (completer_quote_characters == NULL) {
+ completer_quote_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(completer_quote_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(completer_quote_characters, RSTRING_PTR(str), RSTRING_LEN(str));
+ completer_quote_characters[RSTRING_LEN(str)] = '\0';
+ rl_completer_quote_characters = completer_quote_characters;
+
+ return self;
+}
+#else
+#define readline_s_set_completer_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_quote_characters -> string
+ *
+ * Gets a list of characters which can be used to quote a substring of
+ * the line.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_completer_quote_characters(VALUE self)
+{
+ if (rl_completer_quote_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_completer_quote_characters);
+}
+#else
+#define readline_s_get_completer_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.filename_quote_characters = string
+ *
+ * Sets a list of characters that cause a filename to be quoted by the completer
+ * when they appear in a completed filename. The default is nil.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_filename_quote_characters(VALUE self, VALUE str)
+{
+ static char *filename_quote_characters = NULL;
+
+ OutputStringValue(str);
+ if (filename_quote_characters == NULL) {
+ filename_quote_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(filename_quote_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(filename_quote_characters, RSTRING_PTR(str), RSTRING_LEN(str));
+ filename_quote_characters[RSTRING_LEN(str)] = '\0';
+ rl_filename_quote_characters = filename_quote_characters;
+
+ return self;
+}
+#else
+#define readline_s_set_filename_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.filename_quote_characters -> string
+ *
+ * Gets a list of characters that cause a filename to be quoted by the completer
+ * when they appear in a completed filename.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_filename_quote_characters(VALUE self)
+{
+ if (rl_filename_quote_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_filename_quote_characters);
+}
+#else
+#define readline_s_get_filename_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_REFRESH_LINE
+RUBY_EXTERN int rl_refresh_line(int, int);
+/*
+ * call-seq:
+ * Readline.refresh_line -> nil
+ *
+ * Clear the current input line.
+ */
+static VALUE
+readline_s_refresh_line(VALUE self)
+{
+ prepare_readline();
+ rl_refresh_line(0, 0);
+ return Qnil;
+}
+#else
+#define readline_s_refresh_line rb_f_notimplement
+#endif
+
+static VALUE
+hist_to_s(VALUE self)
+{
+ return rb_str_new_cstr("HISTORY");
+}
+
+static int
+history_get_offset_history_base(int offset)
+{
+ return history_base + offset;
+}
+
+static int
+history_get_offset_0(int offset)
+{
+ return offset;
+}
+
+static VALUE
+hist_get(VALUE self, VALUE index)
+{
+ HIST_ENTRY *entry = NULL;
+ int i;
+
+ i = NUM2INT(index);
+ if (i < 0) {
+ i += history_length;
+ }
+ if (i >= 0) {
+ entry = history_get(history_get_offset_func(i));
+ }
+ if (entry == NULL) {
+ rb_raise(rb_eIndexError, "invalid index");
+ }
+ return rb_locale_str_new_cstr(entry->line);
+}
+
+#ifdef HAVE_REPLACE_HISTORY_ENTRY
+static VALUE
+hist_set(VALUE self, VALUE index, VALUE str)
+{
+ HIST_ENTRY *entry = NULL;
+ int i;
+
+ i = NUM2INT(index);
+ OutputStringValue(str);
+ if (i < 0) {
+ i += history_length;
+ }
+ if (i >= 0) {
+ entry = replace_history_entry(history_replace_offset_func(i), RSTRING_PTR(str), NULL);
+ }
+ if (entry == NULL) {
+ rb_raise(rb_eIndexError, "invalid index");
+ }
+ return str;
+}
+#else
+#define hist_set rb_f_notimplement
+#endif
+
+static VALUE
+hist_push(VALUE self, VALUE str)
+{
+ OutputStringValue(str);
+ add_history(RSTRING_PTR(str));
+ return self;
+}
+
+static VALUE
+hist_push_method(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str;
+
+ while (argc--) {
+ str = *argv++;
+ OutputStringValue(str);
+ add_history(RSTRING_PTR(str));
+ }
+ return self;
+}
+
+static VALUE
+rb_remove_history(int index)
+{
+#ifdef HAVE_REMOVE_HISTORY
+ HIST_ENTRY *entry;
+ VALUE val;
+
+ entry = remove_history(index);
+ if (entry) {
+ val = rb_locale_str_new_cstr(entry->line);
+ free((void *) entry->line);
+ free(entry);
+ return val;
+ }
+ return Qnil;
+#else
+ rb_notimplement();
+
+ UNREACHABLE_RETURN(Qnil);
+#endif
+}
+
+static VALUE
+hist_pop(VALUE self)
+{
+ if (history_length > 0) {
+ return rb_remove_history(history_length - 1);
+ } else {
+ return Qnil;
+ }
+}
+
+static VALUE
+hist_shift(VALUE self)
+{
+ if (history_length > 0) {
+ return rb_remove_history(0);
+ } else {
+ return Qnil;
+ }
+}
+
+static VALUE
+hist_each(VALUE self)
+{
+ HIST_ENTRY *entry;
+ int i;
+
+ RETURN_ENUMERATOR(self, 0, 0);
+
+ for (i = 0; i < history_length; i++) {
+ entry = history_get(history_get_offset_func(i));
+ if (entry == NULL)
+ break;
+ rb_yield(rb_locale_str_new_cstr(entry->line));
+ }
+ return self;
+}
+
+static VALUE
+hist_length(VALUE self)
+{
+ return INT2NUM(history_length);
+}
+
+static VALUE
+hist_empty_p(VALUE self)
+{
+ return history_length == 0 ? Qtrue : Qfalse;
+}
+
+static VALUE
+hist_delete_at(VALUE self, VALUE index)
+{
+ int i;
+
+ i = NUM2INT(index);
+ if (i < 0)
+ i += history_length;
+ if (i < 0 || i > history_length - 1) {
+ rb_raise(rb_eIndexError, "invalid index");
+ }
+ return rb_remove_history(i);
+}
+
+#ifdef HAVE_CLEAR_HISTORY
+static VALUE
+hist_clear(VALUE self)
+{
+ clear_history();
+ return self;
+}
+#else
+#define hist_clear rb_f_notimplement
+#endif
+
+static VALUE
+filename_completion_proc_call(VALUE self, VALUE str)
+{
+ VALUE result;
+ char **matches;
+ int i;
+
+ matches = rl_completion_matches(StringValuePtr(str),
+ rl_filename_completion_function);
+ if (matches) {
+ result = rb_ary_new();
+ for (i = 0; matches[i]; i++) {
+ rb_ary_push(result, rb_locale_str_new_cstr(matches[i]));
+ free(matches[i]);
+ }
+ free(matches);
+ if (RARRAY_LEN(result) >= 2)
+ rb_ary_shift(result);
+ }
+ else {
+ result = Qnil;
+ }
+ return result;
+}
+
+static VALUE
+username_completion_proc_call(VALUE self, VALUE str)
+{
+ VALUE result;
+ char **matches;
+ int i;
+
+ matches = rl_completion_matches(StringValuePtr(str),
+ rl_username_completion_function);
+ if (matches) {
+ result = rb_ary_new();
+ for (i = 0; matches[i]; i++) {
+ rb_ary_push(result, rb_locale_str_new_cstr(matches[i]));
+ free(matches[i]);
+ }
+ free(matches);
+ if (RARRAY_LEN(result) >= 2)
+ rb_ary_shift(result);
+ }
+ else {
+ result = Qnil;
+ }
+ return result;
+}
+
+#ifdef HAVE_RL_CATCH_SIGNALS
+RUBY_EXTERN int rl_catch_signals;
+#endif
+#ifdef HAVE_RL_CLEAR_SIGNALS
+RUBY_EXTERN int rl_clear_signals(void);
+#endif
+
+#undef rb_intern
+void
+Init_readline(void)
+{
+ VALUE history, fcomp, ucomp, version;
+
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = (char *)"Ruby";
+
+#if defined HAVE_RL_GETC_FUNCTION
+ /* libedit check rl_getc_function only when rl_initialize() is called, */
+ /* and using_history() call rl_initialize(). */
+ /* This assignment should be placed before using_history() */
+ rl_getc_function = readline_getc;
+#elif defined HAVE_RL_EVENT_HOOK
+ rl_event_hook = readline_event;
+#endif
+
+ using_history();
+
+ id_call = rb_intern("call");
+ completion_proc = rb_intern(COMPLETION_PROC);
+ completion_case_fold = rb_intern(COMPLETION_CASE_FOLD);
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+ id_pre_input_hook = rb_intern("pre_input_hook");
+#endif
+#if defined(HAVE_RL_SPECIAL_PREFIXES)
+ id_special_prefixes = rb_intern("special_prefixes");
+#endif
+#if defined HAVE_RL_CHAR_IS_QUOTED_P
+ quoting_detection_proc = rb_intern(QUOTING_DETECTION_PROC);
+#endif
+
+ mReadline = rb_define_module("Readline");
+ rb_define_module_function(mReadline, "readline",
+ readline_readline, -1);
+ rb_define_singleton_method(mReadline, "input=",
+ readline_s_set_input, 1);
+ rb_define_singleton_method(mReadline, "output=",
+ readline_s_set_output, 1);
+ rb_define_singleton_method(mReadline, "completion_proc=",
+ readline_s_set_completion_proc, 1);
+ rb_define_singleton_method(mReadline, "completion_proc",
+ readline_s_get_completion_proc, 0);
+ rb_define_singleton_method(mReadline, "quoting_detection_proc=",
+ readline_s_set_quoting_detection_proc, 1);
+ rb_define_singleton_method(mReadline, "quoting_detection_proc",
+ readline_s_get_quoting_detection_proc, 0);
+ rb_define_singleton_method(mReadline, "completion_case_fold=",
+ readline_s_set_completion_case_fold, 1);
+ rb_define_singleton_method(mReadline, "completion_case_fold",
+ readline_s_get_completion_case_fold, 0);
+ rb_define_singleton_method(mReadline, "line_buffer",
+ readline_s_get_line_buffer, 0);
+ rb_define_singleton_method(mReadline, "point",
+ readline_s_get_point, 0);
+ rb_define_singleton_method(mReadline, "point=",
+ readline_s_set_point, 1);
+ rb_define_singleton_method(mReadline, "set_screen_size",
+ readline_s_set_screen_size, 2);
+ rb_define_singleton_method(mReadline, "get_screen_size",
+ readline_s_get_screen_size, 0);
+ rb_define_singleton_method(mReadline, "vi_editing_mode",
+ readline_s_vi_editing_mode, 0);
+ rb_define_singleton_method(mReadline, "vi_editing_mode?",
+ readline_s_vi_editing_mode_p, 0);
+ rb_define_singleton_method(mReadline, "emacs_editing_mode",
+ readline_s_emacs_editing_mode, 0);
+ rb_define_singleton_method(mReadline, "emacs_editing_mode?",
+ readline_s_emacs_editing_mode_p, 0);
+ rb_define_singleton_method(mReadline, "completion_append_character=",
+ readline_s_set_completion_append_character, 1);
+ rb_define_singleton_method(mReadline, "completion_append_character",
+ readline_s_get_completion_append_character, 0);
+ rb_define_singleton_method(mReadline, "completion_quote_character",
+ readline_s_get_completion_quote_character, 0);
+ rb_define_singleton_method(mReadline, "basic_word_break_characters=",
+ readline_s_set_basic_word_break_characters, 1);
+ rb_define_singleton_method(mReadline, "basic_word_break_characters",
+ readline_s_get_basic_word_break_characters, 0);
+ rb_define_singleton_method(mReadline, "completer_word_break_characters=",
+ readline_s_set_completer_word_break_characters, 1);
+ rb_define_singleton_method(mReadline, "completer_word_break_characters",
+ readline_s_get_completer_word_break_characters, 0);
+ rb_define_singleton_method(mReadline, "basic_quote_characters=",
+ readline_s_set_basic_quote_characters, 1);
+ rb_define_singleton_method(mReadline, "basic_quote_characters",
+ readline_s_get_basic_quote_characters, 0);
+ rb_define_singleton_method(mReadline, "completer_quote_characters=",
+ readline_s_set_completer_quote_characters, 1);
+ rb_define_singleton_method(mReadline, "completer_quote_characters",
+ readline_s_get_completer_quote_characters, 0);
+ rb_define_singleton_method(mReadline, "filename_quote_characters=",
+ readline_s_set_filename_quote_characters, 1);
+ rb_define_singleton_method(mReadline, "filename_quote_characters",
+ readline_s_get_filename_quote_characters, 0);
+ rb_define_singleton_method(mReadline, "refresh_line",
+ readline_s_refresh_line, 0);
+ rb_define_singleton_method(mReadline, "pre_input_hook=",
+ readline_s_set_pre_input_hook, 1);
+ rb_define_singleton_method(mReadline, "pre_input_hook",
+ readline_s_get_pre_input_hook, 0);
+ rb_define_singleton_method(mReadline, "insert_text",
+ readline_s_insert_text, 1);
+ rb_define_singleton_method(mReadline, "delete_text",
+ readline_s_delete_text, -1);
+ rb_define_singleton_method(mReadline, "redisplay",
+ readline_s_redisplay, 0);
+ rb_define_singleton_method(mReadline, "special_prefixes=",
+ readline_s_set_special_prefixes, 1);
+ rb_define_singleton_method(mReadline, "special_prefixes",
+ readline_s_get_special_prefixes, 0);
+
+#if USE_INSERT_IGNORE_ESCAPE
+ id_orig_prompt = rb_intern("orig_prompt");
+ id_last_prompt = rb_intern("last_prompt");
+#endif
+
+ history = rb_obj_alloc(rb_cObject);
+ rb_extend_object(history, rb_mEnumerable);
+ rb_define_singleton_method(history,"to_s", hist_to_s, 0);
+ rb_define_singleton_method(history,"[]", hist_get, 1);
+ rb_define_singleton_method(history,"[]=", hist_set, 2);
+ rb_define_singleton_method(history,"<<", hist_push, 1);
+ rb_define_singleton_method(history,"push", hist_push_method, -1);
+ rb_define_singleton_method(history,"pop", hist_pop, 0);
+ rb_define_singleton_method(history,"shift", hist_shift, 0);
+ rb_define_singleton_method(history,"each", hist_each, 0);
+ rb_define_singleton_method(history,"length", hist_length, 0);
+ rb_define_singleton_method(history,"size", hist_length, 0);
+ rb_define_singleton_method(history,"empty?", hist_empty_p, 0);
+ rb_define_singleton_method(history,"delete_at", hist_delete_at, 1);
+ rb_define_singleton_method(history,"clear", hist_clear, 0);
+
+ /*
+ * The history buffer. It extends Enumerable module, so it behaves
+ * just like an array.
+ * For example, gets the fifth content that the user input by
+ * <code>HISTORY[4]</code>.
+ */
+ rb_define_const(mReadline, "HISTORY", history);
+
+ fcomp = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(fcomp, "call",
+ filename_completion_proc_call, 1);
+ /*
+ * The Object with the call method that is a completion for filename.
+ * This is sets by Readline.completion_proc= method.
+ */
+ rb_define_const(mReadline, "FILENAME_COMPLETION_PROC", fcomp);
+
+ ucomp = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(ucomp, "call",
+ username_completion_proc_call, 1);
+ /*
+ * The Object with the call method that is a completion for usernames.
+ * This is sets by Readline.completion_proc= method.
+ */
+ rb_define_const(mReadline, "USERNAME_COMPLETION_PROC", ucomp);
+ history_get_offset_func = history_get_offset_history_base;
+ history_replace_offset_func = history_get_offset_0;
+#if defined HAVE_RL_LIBRARY_VERSION
+ version = rb_str_new_cstr(rl_library_version);
+#if defined HAVE_CLEAR_HISTORY || defined HAVE_REMOVE_HISTORY
+ if (strncmp(rl_library_version, EDIT_LINE_LIBRARY_VERSION,
+ strlen(EDIT_LINE_LIBRARY_VERSION)) == 0) {
+ prepare_readline();
+ add_history("1");
+ if (history_get(history_get_offset_func(0)) == NULL) {
+ history_get_offset_func = history_get_offset_0;
+ }
+#ifdef HAVE_REPLACE_HISTORY_ENTRY
+ if (replace_history_entry(0, "a", NULL) == NULL) {
+ history_replace_offset_func = history_get_offset_history_base;
+ }
+#endif
+#ifdef HAVE_CLEAR_HISTORY
+ clear_history();
+#else
+ {
+ HIST_ENTRY *entry = remove_history(0);
+ if (entry) {
+ free((char *)entry->line);
+ free(entry);
+ }
+ }
+#endif
+ }
+#endif
+#else
+ version = rb_str_new_cstr("2.0 or prior version");
+#endif
+ /* Version string of GNU Readline or libedit. */
+ rb_define_const(mReadline, "VERSION", version);
+
+ rl_attempted_completion_function = readline_attempted_completion_function;
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+ rl_pre_input_hook = (rl_hook_func_t *)readline_pre_input_hook;
+#endif
+#if defined HAVE_RL_CHAR_IS_QUOTED_P
+ rl_char_is_quoted_p = &readline_char_is_quoted;
+#endif
+#ifdef HAVE_RL_CATCH_SIGNALS
+ rl_catch_signals = 0;
+#endif
+#ifdef HAVE_RL_CLEAR_SIGNALS
+ rl_clear_signals();
+#endif
+
+ rb_gc_register_address(&readline_instream);
+ rb_gc_register_address(&readline_outstream);
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * end:
+ */
diff --git a/ext/ripper/README b/ext/ripper/README
index 70fa208920..2ae2470e13 100644
--- a/ext/ripper/README
+++ b/ext/ripper/README
@@ -13,6 +13,7 @@ Requirements
------------
* ruby 1.9 (support CVS HEAD only)
+ * bison 1.28 or later (Other yaccs do not work)
Usage
-----
diff --git a/ext/ripper/depend b/ext/ripper/depend
index a2de09f280..856283e177 100644
--- a/ext/ripper/depend
+++ b/ext/ripper/depend
@@ -1,26 +1,27 @@
GEN = $(srcdir)/tools/generate.rb
SRC1 = $(top_srcdir)/parse.y
SRC2 = $(srcdir)/eventids2.c
-BISON = $(BASERUBY) $(top_srcdir)/tool/lrama/exe/lrama
.SUFFIXES: .y
-src: ripper.c ripper_init.c eventids1.c eventids1.h eventids2table.c
-ripper.c ripper_init.c eventids1.c eventids1.h eventids2table.c: depend
+src: ripper.c eventids1.c eventids2table.c
ripper.o: ripper.c
.y.c:
$(ECHO) compiling compiler $<
- $(Q) $(BISON) -t -v -o$@ - $< < $<
+ $(Q) $(BISON) -t -v -oy.tab.c $<
+ $(Q) sed -e "/^#/s!y\.tab\.c!$@!" -f $(top_srcdir)/tool/ytab.sed y.tab.c > $@
+ @$(RM) y.tab.c
all: check
static: check
ripper.y: $(srcdir)/tools/preproc.rb $(srcdir)/tools/dsl.rb $(top_srcdir)/parse.y $(top_srcdir)/defs/id.def
$(ECHO) extracting $@ from $(top_srcdir)/parse.y
- $(Q) $(RUBY) $(top_srcdir)/tool/id2token.rb $(top_srcdir)/parse.y | \
- $(RUBY) $(srcdir)/tools/preproc.rb --output=$@ - ripper.y
+ $(Q) $(RUBY) $(top_srcdir)/tool/id2token.rb $(top_srcdir)/parse.y > ripper.tmp.y
+ $(Q) $(RUBY) $(srcdir)/tools/preproc.rb ripper.tmp.y --output=$@
+ $(Q) $(RM) ripper.tmp.y
check: .eventids2-check
@@ -29,10 +30,6 @@ check: .eventids2-check
$(Q) $(RUBY) $(GEN) --mode=check --ids1src=$(SRC1) --ids2src=$(SRC2)
@exit > $@
-eventids1.h: $(GEN) $(srcdir)/tools/dsl.rb $(SRC1)
- $(ECHO) generating $@ from $(SRC1)
- $(Q) $(RUBY) $(GEN) --mode=eventids1_h --ids1src=$(SRC1) --output=$@
-
eventids1.c: $(GEN) $(srcdir)/tools/dsl.rb $(SRC1)
$(ECHO) generating $@ from $(SRC1)
$(Q) $(RUBY) $(GEN) --mode=eventids1 --ids1src=$(SRC1) --output=$@
@@ -41,10 +38,6 @@ eventids2table.c: $(GEN) $(srcdir)/tools/dsl.rb $(SRC2)
$(ECHO) generating $@ from $(SRC2)
$(Q) $(RUBY) $(GEN) --mode=eventids2table --ids2src=$(SRC2) --output=$@
-ripper_init.c: $(srcdir)/ripper_init.c.tmpl ripper.y $(srcdir)/tools/preproc.rb $(top_srcdir)/internal/ruby_parser.h
- $(ECHO) generating $@ from $(srcdir)/ripper_init.c.tmpl
- $(Q) $(RUBY) $(srcdir)/tools/preproc.rb --output=$@ --template=$(srcdir)/ripper_init.c.tmpl $(top_srcdir)/internal/ruby_parser.h
-
# Entries for Ripper maintainer
preproc: ripper.E
@@ -53,347 +46,10 @@ ripper.E: ripper.c
$(Q) $(CC) -E $(INCFLAGS) $(CPPFLAGS) $< | $(RUBY) $(srcdir)/tools/strip.rb > $@
# AUTOGENERATED DEPENDENCIES START
-eventids1.o: $(RUBY_EXTCONF_H)
-eventids1.o: $(arch_hdrdir)/ruby/config.h
-eventids1.o: $(hdrdir)/ruby/assert.h
-eventids1.o: $(hdrdir)/ruby/backward.h
-eventids1.o: $(hdrdir)/ruby/backward/2/assume.h
-eventids1.o: $(hdrdir)/ruby/backward/2/attributes.h
-eventids1.o: $(hdrdir)/ruby/backward/2/bool.h
-eventids1.o: $(hdrdir)/ruby/backward/2/inttypes.h
-eventids1.o: $(hdrdir)/ruby/backward/2/limits.h
-eventids1.o: $(hdrdir)/ruby/backward/2/long_long.h
-eventids1.o: $(hdrdir)/ruby/backward/2/stdalign.h
-eventids1.o: $(hdrdir)/ruby/backward/2/stdarg.h
-eventids1.o: $(hdrdir)/ruby/defines.h
-eventids1.o: $(hdrdir)/ruby/intern.h
-eventids1.o: $(hdrdir)/ruby/internal/abi.h
-eventids1.o: $(hdrdir)/ruby/internal/anyargs.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-eventids1.o: $(hdrdir)/ruby/internal/assume.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/artificial.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/cold.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/const.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/error.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/format.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noalias.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noinline.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/pure.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/restrict.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/warning.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/weakref.h
-eventids1.o: $(hdrdir)/ruby/internal/cast.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_since.h
-eventids1.o: $(hdrdir)/ruby/internal/config.h
-eventids1.o: $(hdrdir)/ruby/internal/constant_p.h
-eventids1.o: $(hdrdir)/ruby/internal/core.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rarray.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rbasic.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rbignum.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rclass.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rdata.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rfile.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rhash.h
-eventids1.o: $(hdrdir)/ruby/internal/core/robject.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rregexp.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rstring.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rstruct.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-eventids1.o: $(hdrdir)/ruby/internal/ctype.h
-eventids1.o: $(hdrdir)/ruby/internal/dllexport.h
-eventids1.o: $(hdrdir)/ruby/internal/dosish.h
-eventids1.o: $(hdrdir)/ruby/internal/error.h
-eventids1.o: $(hdrdir)/ruby/internal/eval.h
-eventids1.o: $(hdrdir)/ruby/internal/event.h
-eventids1.o: $(hdrdir)/ruby/internal/fl_type.h
-eventids1.o: $(hdrdir)/ruby/internal/gc.h
-eventids1.o: $(hdrdir)/ruby/internal/glob.h
-eventids1.o: $(hdrdir)/ruby/internal/globals.h
-eventids1.o: $(hdrdir)/ruby/internal/has/attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/builtin.h
-eventids1.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/extension.h
-eventids1.o: $(hdrdir)/ruby/internal/has/feature.h
-eventids1.o: $(hdrdir)/ruby/internal/has/warning.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/array.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/bignum.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/class.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/compar.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/complex.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/cont.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/dir.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/enum.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/error.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/eval.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/file.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/hash.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/io.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/load.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/marshal.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/numeric.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/object.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/parse.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/proc.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/process.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/random.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/range.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/rational.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/re.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/ruby.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/select.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/signal.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/string.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/struct.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/thread.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/time.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/variable.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/vm.h
-eventids1.o: $(hdrdir)/ruby/internal/interpreter.h
-eventids1.o: $(hdrdir)/ruby/internal/iterator.h
-eventids1.o: $(hdrdir)/ruby/internal/memory.h
-eventids1.o: $(hdrdir)/ruby/internal/method.h
-eventids1.o: $(hdrdir)/ruby/internal/module.h
-eventids1.o: $(hdrdir)/ruby/internal/newobj.h
-eventids1.o: $(hdrdir)/ruby/internal/scan_args.h
-eventids1.o: $(hdrdir)/ruby/internal/special_consts.h
-eventids1.o: $(hdrdir)/ruby/internal/static_assert.h
-eventids1.o: $(hdrdir)/ruby/internal/stdalign.h
-eventids1.o: $(hdrdir)/ruby/internal/stdbool.h
-eventids1.o: $(hdrdir)/ruby/internal/symbol.h
-eventids1.o: $(hdrdir)/ruby/internal/value.h
-eventids1.o: $(hdrdir)/ruby/internal/value_type.h
-eventids1.o: $(hdrdir)/ruby/internal/variable.h
-eventids1.o: $(hdrdir)/ruby/internal/warning_push.h
-eventids1.o: $(hdrdir)/ruby/internal/xmalloc.h
-eventids1.o: $(hdrdir)/ruby/missing.h
-eventids1.o: $(hdrdir)/ruby/ruby.h
-eventids1.o: $(hdrdir)/ruby/st.h
-eventids1.o: $(hdrdir)/ruby/subst.h
-eventids1.o: eventids1.h
-eventids1.o: {$(VPATH)}eventids1.c
-eventids1.o: {$(VPATH)}eventids1.h
-eventids2.o: $(RUBY_EXTCONF_H)
-eventids2.o: $(arch_hdrdir)/ruby/config.h
-eventids2.o: $(hdrdir)/ruby/assert.h
-eventids2.o: $(hdrdir)/ruby/backward.h
-eventids2.o: $(hdrdir)/ruby/backward/2/assume.h
-eventids2.o: $(hdrdir)/ruby/backward/2/attributes.h
-eventids2.o: $(hdrdir)/ruby/backward/2/bool.h
-eventids2.o: $(hdrdir)/ruby/backward/2/inttypes.h
-eventids2.o: $(hdrdir)/ruby/backward/2/limits.h
-eventids2.o: $(hdrdir)/ruby/backward/2/long_long.h
-eventids2.o: $(hdrdir)/ruby/backward/2/stdalign.h
-eventids2.o: $(hdrdir)/ruby/backward/2/stdarg.h
-eventids2.o: $(hdrdir)/ruby/defines.h
-eventids2.o: $(hdrdir)/ruby/encoding.h
-eventids2.o: $(hdrdir)/ruby/intern.h
-eventids2.o: $(hdrdir)/ruby/internal/abi.h
-eventids2.o: $(hdrdir)/ruby/internal/anyargs.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-eventids2.o: $(hdrdir)/ruby/internal/assume.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/artificial.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/cold.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/const.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/error.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/format.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noalias.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noinline.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/pure.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/restrict.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/warning.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/weakref.h
-eventids2.o: $(hdrdir)/ruby/internal/cast.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_since.h
-eventids2.o: $(hdrdir)/ruby/internal/config.h
-eventids2.o: $(hdrdir)/ruby/internal/constant_p.h
-eventids2.o: $(hdrdir)/ruby/internal/core.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rarray.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rbasic.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rbignum.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rclass.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rdata.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rfile.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rhash.h
-eventids2.o: $(hdrdir)/ruby/internal/core/robject.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rregexp.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rstring.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rstruct.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-eventids2.o: $(hdrdir)/ruby/internal/ctype.h
-eventids2.o: $(hdrdir)/ruby/internal/dllexport.h
-eventids2.o: $(hdrdir)/ruby/internal/dosish.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/re.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/string.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-eventids2.o: $(hdrdir)/ruby/internal/error.h
-eventids2.o: $(hdrdir)/ruby/internal/eval.h
-eventids2.o: $(hdrdir)/ruby/internal/event.h
-eventids2.o: $(hdrdir)/ruby/internal/fl_type.h
-eventids2.o: $(hdrdir)/ruby/internal/gc.h
-eventids2.o: $(hdrdir)/ruby/internal/glob.h
-eventids2.o: $(hdrdir)/ruby/internal/globals.h
-eventids2.o: $(hdrdir)/ruby/internal/has/attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/builtin.h
-eventids2.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/extension.h
-eventids2.o: $(hdrdir)/ruby/internal/has/feature.h
-eventids2.o: $(hdrdir)/ruby/internal/has/warning.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/array.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/bignum.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/class.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/compar.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/complex.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/cont.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/dir.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/enum.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/error.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/eval.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/file.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/hash.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/io.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/load.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/marshal.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/numeric.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/object.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/parse.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/proc.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/process.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/random.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/range.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/rational.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/re.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/ruby.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/select.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/signal.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/string.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/struct.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/thread.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/time.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/variable.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/vm.h
-eventids2.o: $(hdrdir)/ruby/internal/interpreter.h
-eventids2.o: $(hdrdir)/ruby/internal/iterator.h
-eventids2.o: $(hdrdir)/ruby/internal/memory.h
-eventids2.o: $(hdrdir)/ruby/internal/method.h
-eventids2.o: $(hdrdir)/ruby/internal/module.h
-eventids2.o: $(hdrdir)/ruby/internal/newobj.h
-eventids2.o: $(hdrdir)/ruby/internal/scan_args.h
-eventids2.o: $(hdrdir)/ruby/internal/special_consts.h
-eventids2.o: $(hdrdir)/ruby/internal/static_assert.h
-eventids2.o: $(hdrdir)/ruby/internal/stdalign.h
-eventids2.o: $(hdrdir)/ruby/internal/stdbool.h
-eventids2.o: $(hdrdir)/ruby/internal/symbol.h
-eventids2.o: $(hdrdir)/ruby/internal/value.h
-eventids2.o: $(hdrdir)/ruby/internal/value_type.h
-eventids2.o: $(hdrdir)/ruby/internal/variable.h
-eventids2.o: $(hdrdir)/ruby/internal/warning_push.h
-eventids2.o: $(hdrdir)/ruby/internal/xmalloc.h
-eventids2.o: $(hdrdir)/ruby/missing.h
-eventids2.o: $(hdrdir)/ruby/onigmo.h
-eventids2.o: $(hdrdir)/ruby/oniguruma.h
-eventids2.o: $(hdrdir)/ruby/ruby.h
-eventids2.o: $(hdrdir)/ruby/st.h
-eventids2.o: $(hdrdir)/ruby/subst.h
-eventids2.o: $(top_srcdir)/internal.h
-eventids2.o: $(top_srcdir)/internal/static_assert.h
-eventids2.o: $(top_srcdir)/rubyparser.h
-eventids2.o: eventids2.c
-eventids2.o: eventids2.h
-eventids2.o: {$(VPATH)}eventids2table.c
-eventids2.o: {$(VPATH)}parse.h
ripper.o: $(RUBY_EXTCONF_H)
ripper.o: $(arch_hdrdir)/ruby/config.h
ripper.o: $(hdrdir)/ruby.h
ripper.o: $(hdrdir)/ruby/assert.h
-ripper.o: $(hdrdir)/ruby/atomic.h
ripper.o: $(hdrdir)/ruby/backward.h
ripper.o: $(hdrdir)/ruby/backward/2/assume.h
ripper.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -445,7 +101,6 @@ ripper.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ripper.o: $(hdrdir)/ruby/internal/attr/noinline.h
ripper.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ripper.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ripper.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ripper.o: $(hdrdir)/ruby/internal/attr/pure.h
ripper.o: $(hdrdir)/ruby/internal/attr/restrict.h
ripper.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -514,6 +169,7 @@ ripper.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ripper.o: $(hdrdir)/ruby/internal/intern/error.h
ripper.o: $(hdrdir)/ruby/internal/intern/eval.h
ripper.o: $(hdrdir)/ruby/internal/intern/file.h
+ripper.o: $(hdrdir)/ruby/internal/intern/gc.h
ripper.o: $(hdrdir)/ruby/internal/intern/hash.h
ripper.o: $(hdrdir)/ruby/internal/intern/io.h
ripper.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -544,6 +200,7 @@ ripper.o: $(hdrdir)/ruby/internal/memory.h
ripper.o: $(hdrdir)/ruby/internal/method.h
ripper.o: $(hdrdir)/ruby/internal/module.h
ripper.o: $(hdrdir)/ruby/internal/newobj.h
+ripper.o: $(hdrdir)/ruby/internal/rgengc.h
ripper.o: $(hdrdir)/ruby/internal/scan_args.h
ripper.o: $(hdrdir)/ruby/internal/special_consts.h
ripper.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -564,17 +221,11 @@ ripper.o: $(hdrdir)/ruby/regex.h
ripper.o: $(hdrdir)/ruby/ruby.h
ripper.o: $(hdrdir)/ruby/st.h
ripper.o: $(hdrdir)/ruby/subst.h
-ripper.o: $(hdrdir)/ruby/thread_native.h
ripper.o: $(hdrdir)/ruby/util.h
-ripper.o: $(top_srcdir)/ccan/check_type/check_type.h
-ripper.o: $(top_srcdir)/ccan/container_of/container_of.h
-ripper.o: $(top_srcdir)/ccan/list/list.h
-ripper.o: $(top_srcdir)/ccan/str/str.h
ripper.o: $(top_srcdir)/constant.h
ripper.o: $(top_srcdir)/id_table.h
ripper.o: $(top_srcdir)/internal.h
ripper.o: $(top_srcdir)/internal/array.h
-ripper.o: $(top_srcdir)/internal/basic_operators.h
ripper.o: $(top_srcdir)/internal/bignum.h
ripper.o: $(top_srcdir)/internal/bits.h
ripper.o: $(top_srcdir)/internal/compile.h
@@ -591,7 +242,6 @@ ripper.o: $(top_srcdir)/internal/numeric.h
ripper.o: $(top_srcdir)/internal/parse.h
ripper.o: $(top_srcdir)/internal/rational.h
ripper.o: $(top_srcdir)/internal/re.h
-ripper.o: $(top_srcdir)/internal/ruby_parser.h
ripper.o: $(top_srcdir)/internal/serial.h
ripper.o: $(top_srcdir)/internal/static_assert.h
ripper.o: $(top_srcdir)/internal/string.h
@@ -600,25 +250,14 @@ ripper.o: $(top_srcdir)/internal/thread.h
ripper.o: $(top_srcdir)/internal/variable.h
ripper.o: $(top_srcdir)/internal/vm.h
ripper.o: $(top_srcdir)/internal/warnings.h
-ripper.o: $(top_srcdir)/method.h
ripper.o: $(top_srcdir)/node.h
-ripper.o: $(top_srcdir)/parser_node.h
-ripper.o: $(top_srcdir)/parser_st.h
ripper.o: $(top_srcdir)/regenc.h
ripper.o: $(top_srcdir)/ruby_assert.h
-ripper.o: $(top_srcdir)/ruby_atomic.h
-ripper.o: $(top_srcdir)/rubyparser.h
ripper.o: $(top_srcdir)/shape.h
ripper.o: $(top_srcdir)/symbol.h
-ripper.o: $(top_srcdir)/thread_pthread.h
-ripper.o: $(top_srcdir)/vm_core.h
-ripper.o: $(top_srcdir)/vm_opts.h
ripper.o: ../../probes.h
-ripper.o: eventids1.h
ripper.o: eventids2.c
-ripper.o: eventids2.h
ripper.o: ripper.y
-ripper.o: ripper_init.h
ripper.o: {$(VPATH)}eventids1.c
ripper.o: {$(VPATH)}eventids2table.c
ripper.o: {$(VPATH)}id.h
@@ -626,188 +265,4 @@ ripper.o: {$(VPATH)}lex.c
ripper.o: {$(VPATH)}parse.h
ripper.o: {$(VPATH)}probes.dmyh
ripper.o: {$(VPATH)}ripper.c
-ripper_init.o: $(RUBY_EXTCONF_H)
-ripper_init.o: $(arch_hdrdir)/ruby/config.h
-ripper_init.o: $(hdrdir)/ruby/assert.h
-ripper_init.o: $(hdrdir)/ruby/backward.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/assume.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/attributes.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/bool.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/inttypes.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/limits.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/long_long.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/stdalign.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/stdarg.h
-ripper_init.o: $(hdrdir)/ruby/defines.h
-ripper_init.o: $(hdrdir)/ruby/encoding.h
-ripper_init.o: $(hdrdir)/ruby/intern.h
-ripper_init.o: $(hdrdir)/ruby/internal/abi.h
-ripper_init.o: $(hdrdir)/ruby/internal/anyargs.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/assume.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/artificial.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/cold.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/const.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/error.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/format.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noalias.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noinline.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/pure.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/restrict.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/warning.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/weakref.h
-ripper_init.o: $(hdrdir)/ruby/internal/cast.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_since.h
-ripper_init.o: $(hdrdir)/ruby/internal/config.h
-ripper_init.o: $(hdrdir)/ruby/internal/constant_p.h
-ripper_init.o: $(hdrdir)/ruby/internal/core.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rarray.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rbasic.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rbignum.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rclass.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rdata.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rfile.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rhash.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/robject.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rregexp.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rstring.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rstruct.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-ripper_init.o: $(hdrdir)/ruby/internal/ctype.h
-ripper_init.o: $(hdrdir)/ruby/internal/dllexport.h
-ripper_init.o: $(hdrdir)/ruby/internal/dosish.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/re.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/string.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-ripper_init.o: $(hdrdir)/ruby/internal/error.h
-ripper_init.o: $(hdrdir)/ruby/internal/eval.h
-ripper_init.o: $(hdrdir)/ruby/internal/event.h
-ripper_init.o: $(hdrdir)/ruby/internal/fl_type.h
-ripper_init.o: $(hdrdir)/ruby/internal/gc.h
-ripper_init.o: $(hdrdir)/ruby/internal/glob.h
-ripper_init.o: $(hdrdir)/ruby/internal/globals.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/builtin.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/extension.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/feature.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/warning.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/array.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/bignum.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/class.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/compar.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/complex.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/cont.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/dir.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/enum.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/error.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/eval.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/file.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/hash.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/io.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/load.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/marshal.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/numeric.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/object.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/parse.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/proc.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/process.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/random.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/range.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/rational.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/re.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/ruby.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/select.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/signal.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/string.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/struct.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/thread.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/time.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/variable.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/vm.h
-ripper_init.o: $(hdrdir)/ruby/internal/interpreter.h
-ripper_init.o: $(hdrdir)/ruby/internal/iterator.h
-ripper_init.o: $(hdrdir)/ruby/internal/memory.h
-ripper_init.o: $(hdrdir)/ruby/internal/method.h
-ripper_init.o: $(hdrdir)/ruby/internal/module.h
-ripper_init.o: $(hdrdir)/ruby/internal/newobj.h
-ripper_init.o: $(hdrdir)/ruby/internal/scan_args.h
-ripper_init.o: $(hdrdir)/ruby/internal/special_consts.h
-ripper_init.o: $(hdrdir)/ruby/internal/static_assert.h
-ripper_init.o: $(hdrdir)/ruby/internal/stdalign.h
-ripper_init.o: $(hdrdir)/ruby/internal/stdbool.h
-ripper_init.o: $(hdrdir)/ruby/internal/symbol.h
-ripper_init.o: $(hdrdir)/ruby/internal/value.h
-ripper_init.o: $(hdrdir)/ruby/internal/value_type.h
-ripper_init.o: $(hdrdir)/ruby/internal/variable.h
-ripper_init.o: $(hdrdir)/ruby/internal/warning_push.h
-ripper_init.o: $(hdrdir)/ruby/internal/xmalloc.h
-ripper_init.o: $(hdrdir)/ruby/missing.h
-ripper_init.o: $(hdrdir)/ruby/onigmo.h
-ripper_init.o: $(hdrdir)/ruby/oniguruma.h
-ripper_init.o: $(hdrdir)/ruby/ruby.h
-ripper_init.o: $(hdrdir)/ruby/st.h
-ripper_init.o: $(hdrdir)/ruby/subst.h
-ripper_init.o: $(top_srcdir)/internal.h
-ripper_init.o: $(top_srcdir)/internal/array.h
-ripper_init.o: $(top_srcdir)/internal/imemo.h
-ripper_init.o: $(top_srcdir)/internal/parse.h
-ripper_init.o: $(top_srcdir)/internal/ruby_parser.h
-ripper_init.o: $(top_srcdir)/internal/serial.h
-ripper_init.o: $(top_srcdir)/internal/static_assert.h
-ripper_init.o: $(top_srcdir)/internal/vm.h
-ripper_init.o: $(top_srcdir)/node.h
-ripper_init.o: $(top_srcdir)/rubyparser.h
-ripper_init.o: eventids1.h
-ripper_init.o: eventids2.h
-ripper_init.o: ripper_init.h
-ripper_init.o: {$(VPATH)}parse.h
-ripper_init.o: {$(VPATH)}ripper_init.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/ripper/eventids2.c b/ext/ripper/eventids2.c
index ac54955857..05687497ac 100644
--- a/ext/ripper/eventids2.c
+++ b/ext/ripper/eventids2.c
@@ -1,11 +1,3 @@
-#include "ruby/ruby.h"
-#include "rubyparser.h"
-#define YYSTYPE_IS_DECLARED
-#include "parse.h"
-#include "eventids2.h"
-#include "internal.h"
-#include "internal/static_assert.h"
-
typedef struct {
ID ripper_id_backref;
ID ripper_id_backtick;
@@ -65,7 +57,7 @@ static ripper_scanner_ids_t ripper_scanner_ids;
#include "eventids2table.c"
-void
+static void
ripper_init_eventids2(void)
{
#define set_id2(name) ripper_scanner_ids.ripper_id_##name = rb_intern_const("on_"#name)
@@ -126,7 +118,7 @@ ripper_init_eventids2(void)
STATIC_ASSERT(k__END___range, k__END__ < SHRT_MAX);
STATIC_ASSERT(ripper_scanner_ids_size, sizeof(ripper_scanner_ids) < SHRT_MAX);
-ID
+static ID
ripper_token2eventid(enum yytokentype tok)
{
#define O(member) (int)offsetof(ripper_scanner_ids_t, ripper_id_##member)+1
diff --git a/ext/ripper/eventids2.h b/ext/ripper/eventids2.h
deleted file mode 100644
index 49e46432b9..0000000000
--- a/ext/ripper/eventids2.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef RIPPER_EVENTIDS2
-#define RIPPER_EVENTIDS2
-
-void ripper_init_eventids2(void);
-void ripper_init_eventids2_table(VALUE self);
-ID ripper_token2eventid(enum yytokentype tok);
-
-#endif /* RIPPER_EVENTIDS2 */
diff --git a/ext/ripper/extconf.rb b/ext/ripper/extconf.rb
index c3c56c27c5..65cb5030d3 100644
--- a/ext/ripper/extconf.rb
+++ b/ext/ripper/extconf.rb
@@ -5,14 +5,23 @@ require 'mkmf'
require 'rbconfig'
def main
- $objs = %w(eventids1.o eventids2.o ripper.o ripper_init.o)
- $distcleanfiles.concat %w(ripper.y ripper.c eventids1.c eventids1.h eventids2table.c ripper_init.c)
+ yacc = ENV["YACC"] || "bison"
+
+ unless find_executable(yacc)
+ unless File.exist?('ripper.c') or File.exist?("#{$srcdir}/ripper.c")
+ raise 'missing bison; abort'
+ end
+ end
+ $objs = %w(ripper.o)
+ $distcleanfiles.concat %w(ripper.y ripper.c eventids1.c eventids2table.c)
$cleanfiles.concat %w(ripper.E ripper.output y.output .eventids2-check)
$defs << '-DRIPPER'
$defs << '-DRIPPER_DEBUG' if $debug
$VPATH << '$(topdir)' << '$(top_srcdir)'
$INCFLAGS << ' -I$(topdir) -I$(top_srcdir)'
- create_makefile 'ripper'
+ create_makefile 'ripper' do |conf|
+ conf << "BISON = #{yacc}"
+ end
end
main
diff --git a/ext/ripper/lib/ripper/lexer.rb b/ext/ripper/lib/ripper/lexer.rb
index 6a3c04af30..a0f1cbeaa8 100644
--- a/ext/ripper/lib/ripper/lexer.rb
+++ b/ext/ripper/lib/ripper/lexer.rb
@@ -242,7 +242,12 @@ class Ripper
end
def on_error2(mesg, elem)
- @errors.push Elem.new(elem.pos, __callee__, elem.tok, elem.state, mesg)
+ if elem
+ elem = Elem.new(elem.pos, __callee__, elem.tok, elem.state, mesg)
+ else
+ elem = Elem.new([lineno(), column()], __callee__, token(), state(), mesg)
+ end
+ @errors.push elem
end
PARSER_EVENTS.grep(/_error\z/) do |e|
arity = PARSER_EVENT_TABLE.fetch(e)
diff --git a/ext/ripper/ripper_init.c.tmpl b/ext/ripper/ripper_init.c.tmpl
deleted file mode 100644
index 5c1a4e5bb5..0000000000
--- a/ext/ripper/ripper_init.c.tmpl
+++ /dev/null
@@ -1,618 +0,0 @@
-%# -*- c -*-
-#include "ruby/ruby.h"
-#include "ruby/encoding.h"
-#include "internal.h"
-#include "internal/imemo.h" /* needed by ruby_parser.h */
-#include "internal/parse.h"
-#include "internal/ruby_parser.h"
-#include "node.h"
-#include "rubyparser.h"
-#include "eventids1.h"
-#define YYSTYPE_IS_DECLARED
-#include "parse.h"
-#include "eventids2.h"
-#include "ripper_init.h"
-
-#define STR_NEW2(ptr) rb_enc_str_new((ptr),strlen(ptr),rb_ruby_parser_enc(p))
-#define RIPPER_VERSION "0.1.0"
-
-ID id_warn, id_warning, id_gets, id_assoc;
-
-struct ripper {
- rb_parser_t *p;
-};
-
-static void
-ripper_parser_mark2(void *ptr)
-{
- struct ripper *r = (struct ripper*)ptr;
- if (r->p) ripper_parser_mark(r->p);
-}
-
-static void
-ripper_parser_free2(void *ptr)
-{
- struct ripper *r = (struct ripper*)ptr;
- if (r->p) ripper_parser_free(r->p);
- xfree(r);
-}
-
-static size_t
-ripper_parser_memsize2(const void *ptr)
-{
- struct ripper *r = (struct ripper*)ptr;
- return (r->p) ? ripper_parser_memsize(r->p) : 0;
-}
-
-static const rb_data_type_t parser_data_type = {
- "ripper",
- {
- ripper_parser_mark2,
- ripper_parser_free2,
- ripper_parser_memsize2,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-ID
-ripper_get_id(VALUE v)
-{
- NODE *nd;
- if (!RB_TYPE_P(v, T_NODE)) return 0;
- nd = (NODE *)v;
- if (!nd_type_p(nd, NODE_RIPPER)) return 0;
- return RNODE_RIPPER(nd)->nd_vid;
-}
-
-VALUE
-ripper_get_value(VALUE v)
-{
- NODE *nd;
- if (UNDEF_P(v)) return Qnil;
- if (!RB_TYPE_P(v, T_NODE)) return v;
- nd = (NODE *)v;
- if (!nd_type_p(nd, NODE_RIPPER)) return Qnil;
- return RNODE_RIPPER(nd)->nd_rval;
-}
-
-static VALUE
-ripper_lex_get_generic(struct parser_params *p, VALUE src)
-{
- VALUE line = rb_funcallv_public(src, id_gets, 0, 0);
- if (!NIL_P(line) && !RB_TYPE_P(line, T_STRING)) {
- rb_raise(rb_eTypeError,
- "gets returned %"PRIsVALUE" (expected String or nil)",
- rb_obj_class(line));
- }
- return line;
-}
-
-void
-ripper_compile_error(struct parser_params *p, const char *fmt, ...)
-{
- VALUE str;
- va_list args;
-
- va_start(args, fmt);
- str = rb_vsprintf(fmt, args);
- va_end(args);
- rb_funcall(ripper_value(p), rb_intern("compile_error"), 1, str);
- ripper_error(p);
-}
-
-static VALUE
-ripper_lex_io_get(struct parser_params *p, VALUE src)
-{
- return rb_io_gets(src);
-}
-
-static VALUE
-ripper_s_allocate(VALUE klass)
-{
- struct ripper *r;
-
- VALUE self = TypedData_Make_Struct(klass, struct ripper,
- &parser_data_type, r);
-
-#ifdef UNIVERSAL_PARSER
- rb_parser_config_t *config;
- config = rb_ruby_parser_config_new(ruby_xmalloc);
- rb_parser_config_initialize(config);
- r->p = rb_ruby_parser_allocate(config);
-#else
- r->p = rb_ruby_ripper_parser_allocate();
-#endif
- rb_ruby_parser_set_value(r->p, self);
- return self;
-}
-
-static struct parser_params *
-ripper_parser_params(VALUE self, bool initialized)
-{
- struct ripper *r;
- struct parser_params *p;
-
- TypedData_Get_Struct(self, struct ripper, &parser_data_type, r);
- p = r->p;
- if (initialized && !rb_ruby_ripper_initialized_p(p)) {
- rb_raise(rb_eArgError, "method called for uninitialized object");
- }
- return p;
-}
-
-/*
- * call-seq:
- * ripper.error? -> Boolean
- *
- * Return true if parsed source has errors.
- */
-static VALUE
-ripper_error_p(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- return RBOOL(rb_ruby_parser_error_p(p));
-}
-
-/*
- * call-seq:
- * ripper.end_seen? -> Boolean
- *
- * Return true if parsed source ended by +\_\_END\_\_+.
- */
-static VALUE
-ripper_parser_end_seen_p(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- return RBOOL(rb_ruby_parser_end_seen_p(p));
-}
-
-/*
- * call-seq:
- * ripper.encoding -> encoding
- *
- * Return encoding of the source.
- */
-static VALUE
-ripper_parser_encoding(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- return rb_ruby_parser_encoding(p);
-}
-
-/*
- * call-seq:
- * ripper.yydebug -> true or false
- *
- * Get yydebug.
- */
-static VALUE
-ripper_parser_get_yydebug(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- return RBOOL(rb_ruby_parser_get_yydebug(p));
-}
-
-/*
- * call-seq:
- * ripper.yydebug = flag
- *
- * Set yydebug.
- */
-static VALUE
-ripper_parser_set_yydebug(VALUE self, VALUE flag)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- rb_ruby_parser_set_yydebug(p, RTEST(flag));
- return flag;
-}
-
-/*
- * call-seq:
- * ripper.debug_output -> obj
- *
- * Get debug output.
- */
-static VALUE
-ripper_parser_get_debug_output(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- return rb_ruby_parser_debug_output(p);
-}
-
-/*
- * call-seq:
- * ripper.debug_output = obj
- *
- * Set debug output.
- */
-static VALUE
-ripper_parser_set_debug_output(VALUE self, VALUE output)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- rb_ruby_parser_set_debug_output(p, output);
- return output;
-}
-
-#ifdef UNIVERSAL_PARSER
-struct dedent_string_arg {
- struct parser_params *p;
- VALUE input;
- VALUE width;
-};
-
-static VALUE
-parser_dedent_string0(VALUE a)
-{
- struct dedent_string_arg *arg = (void *)a;
- int wid, col;
-
- StringValue(arg->input);
- wid = NUM2UINT(arg->width);
- col = rb_ruby_ripper_dedent_string(arg->p, arg->input, wid);
- return INT2NUM(col);
-}
-
-static VALUE
-parser_config_free(VALUE a)
-{
- rb_parser_config_t *config = (void *)a;
-
- rb_ruby_parser_config_free(config);
- return Qnil;
-}
-#endif
-
-/*
- * call-seq:
- * Ripper.dedent_string(input, width) -> Integer
- *
- * USE OF RIPPER LIBRARY ONLY.
- *
- * Strips up to +width+ leading whitespaces from +input+,
- * and returns the stripped column width.
- */
-#ifdef UNIVERSAL_PARSER
-static VALUE
-parser_dedent_string(VALUE self, VALUE input, VALUE width)
-{
- struct parser_params *p;
- rb_parser_config_t *config;
- struct dedent_string_arg args;
-
- config = rb_ruby_parser_config_new(ruby_xmalloc);
- rb_parser_config_initialize(config);
- p = rb_ruby_parser_new(config);
-
- args.p = p;
- args.input = input;
- args.width = width;
- return rb_ensure(parser_dedent_string0, (VALUE)&args, parser_config_free, (VALUE)config);
-}
-#else
-static VALUE
-parser_dedent_string(VALUE self, VALUE input, VALUE width)
-{
- int wid, col;
-
- StringValue(input);
- wid = NUM2UINT(width);
- col = rb_ruby_ripper_dedent_string(0, input, wid);
- return INT2NUM(col);
-}
-#endif
-
-/*
- * call-seq:
- * Ripper.new(src, filename="(ripper)", lineno=1) -> ripper
- *
- * Create a new Ripper object.
- * _src_ must be a String, an IO, or an Object which has #gets method.
- *
- * This method does not starts parsing.
- * See also Ripper#parse and Ripper.parse.
- */
-static VALUE
-ripper_initialize(int argc, VALUE *argv, VALUE self)
-{
- struct parser_params *p;
- VALUE src, fname, lineno;
- VALUE (*gets)(struct parser_params*,VALUE);
- VALUE input, sourcefile_string;
- const char *sourcefile;
- int sourceline;
-
- p = ripper_parser_params(self, false);
- rb_scan_args(argc, argv, "12", &src, &fname, &lineno);
- if (RB_TYPE_P(src, T_FILE)) {
- gets = ripper_lex_io_get;
- }
- else if (rb_respond_to(src, id_gets)) {
- gets = ripper_lex_get_generic;
- }
- else {
- StringValue(src);
- gets = rb_ruby_ripper_lex_get_str;
- }
- input = src;
- if (NIL_P(fname)) {
- fname = STR_NEW2("(ripper)");
- OBJ_FREEZE(fname);
- }
- else {
- StringValueCStr(fname);
- fname = rb_str_new_frozen(fname);
- }
- rb_ruby_ripper_parser_initialize(p);
-
- sourcefile_string = fname;
- sourcefile = RSTRING_PTR(fname);
- sourceline = NIL_P(lineno) ? 0 : NUM2INT(lineno) - 1;
-
- rb_ruby_parser_ripper_initialize(p, gets, input, sourcefile_string, sourcefile, sourceline);
-
- return Qnil;
-}
-
-static VALUE
-ripper_parse0(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- rb_ruby_ripper_parse0(p);
- return rb_ruby_parser_result(p);
-}
-
-static VALUE
-ripper_ensure(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- rb_ruby_parser_set_parsing_thread(p, Qnil);
- return Qnil;
-}
-
-/*
- * call-seq:
- * ripper.parse
- *
- * Start parsing and returns the value of the root action.
- */
-static VALUE
-ripper_parse(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
- VALUE result;
-
- if (!NIL_P(rb_ruby_parser_parsing_thread(p))) {
- if (rb_ruby_parser_parsing_thread(p) == rb_thread_current())
- rb_raise(rb_eArgError, "Ripper#parse is not reentrant");
- else
- rb_raise(rb_eArgError, "Ripper#parse is not multithread-safe");
- }
- rb_ruby_parser_set_parsing_thread(p, rb_thread_current());
- result = rb_ensure(ripper_parse0, self, ripper_ensure, self);
- RB_GC_GUARD(self);
-
- return result;
-}
-
-/*
- * call-seq:
- * ripper.column -> Integer
- *
- * Return column number of current parsing line.
- * This number starts from 0.
- */
-static VALUE
-ripper_column(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
- long col;
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- col = rb_ruby_ripper_column(p);
- return LONG2NUM(col);
-}
-
-/*
- * call-seq:
- * ripper.filename -> String
- *
- * Return current parsing filename.
- */
-static VALUE
-ripper_filename(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
-
- return rb_ruby_parser_ruby_sourcefile_string(p);
-}
-
-/*
- * call-seq:
- * ripper.lineno -> Integer
- *
- * Return line number of current parsing line.
- * This number starts from 1.
- */
-static VALUE
-ripper_lineno(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- return INT2NUM(rb_ruby_parser_ruby_sourceline(p));
-}
-
-/*
- * call-seq:
- * ripper.state -> Integer
- *
- * Return scanner state of current token.
- */
-static VALUE
-ripper_state(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- return INT2NUM(rb_ruby_parser_lex_state(p));
-}
-
-/*
- * call-seq:
- * ripper.token -> String
- *
- * Return the current token string.
- */
-static VALUE
-ripper_token(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
- long pos, len;
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- pos = rb_ruby_ripper_column(p);
- len = rb_ruby_ripper_token_len(p);
- return rb_str_subseq(rb_ruby_ripper_lex_lastline(p), pos, len);
-}
-
-#ifdef RIPPER_DEBUG
-/* :nodoc: */
-static VALUE
-ripper_assert_Qundef(VALUE self, VALUE obj, VALUE msg)
-{
- StringValue(msg);
- if (UNDEF_P(obj)) {
- rb_raise(rb_eArgError, "%"PRIsVALUE, msg);
- }
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-ripper_raw_value(VALUE self, VALUE obj)
-{
- return ULONG2NUM(obj);
-}
-#endif
-
-#ifdef UNIVERSAL_PARSER
-struct lex_state_name_arg {
- struct parser_params *p;
- VALUE state;
-};
-
-static VALUE
-lex_state_name0(VALUE a)
-{
- struct lex_state_name_arg *arg = (void *)a;
-
- return rb_ruby_ripper_lex_state_name(arg->p, NUM2INT(arg->state));
-}
-#endif
-
-/*
- * call-seq:
- * Ripper.lex_state_name(integer) -> string
- *
- * Returns a string representation of lex_state.
- */
-#ifdef UNIVERSAL_PARSER
-static VALUE
-ripper_lex_state_name(VALUE self, VALUE state)
-{
- struct parser_params *p;
- rb_parser_config_t *config;
- struct lex_state_name_arg args;
-
- config = rb_ruby_parser_config_new(ruby_xmalloc);
- rb_parser_config_initialize(config);
- p = rb_ruby_parser_new(config);
-
- args.p = p;
- args.state = state;
-
- return rb_ensure(lex_state_name0, (VALUE)&args, parser_config_free, (VALUE)config);
-}
-#else
-static VALUE
-ripper_lex_state_name(VALUE self, VALUE state)
-{
- return rb_ruby_ripper_lex_state_name(0, NUM2INT(state));
-}
-#endif
-
-void
-Init_ripper(void)
-{
- ripper_init_eventids1();
- ripper_init_eventids2();
- id_warn = rb_intern_const("warn");
- id_warning = rb_intern_const("warning");
- id_gets = rb_intern_const("gets");
- id_assoc = rb_intern_const("=>");
-
- InitVM(ripper);
-}
-
-void
-InitVM_ripper(void)
-{
- VALUE Ripper;
-
- Ripper = rb_define_class("Ripper", rb_cObject);
- /* version of Ripper */
- rb_define_const(Ripper, "Version", rb_usascii_str_new2(RIPPER_VERSION));
- rb_define_alloc_func(Ripper, ripper_s_allocate);
- rb_define_method(Ripper, "initialize", ripper_initialize, -1);
- rb_define_method(Ripper, "parse", ripper_parse, 0);
- rb_define_method(Ripper, "column", ripper_column, 0);
- rb_define_method(Ripper, "filename", ripper_filename, 0);
- rb_define_method(Ripper, "lineno", ripper_lineno, 0);
- rb_define_method(Ripper, "state", ripper_state, 0);
- rb_define_method(Ripper, "token", ripper_token, 0);
- rb_define_method(Ripper, "end_seen?", ripper_parser_end_seen_p, 0);
- rb_define_method(Ripper, "encoding", ripper_parser_encoding, 0);
- rb_define_method(Ripper, "yydebug", ripper_parser_get_yydebug, 0);
- rb_define_method(Ripper, "yydebug=", ripper_parser_set_yydebug, 1);
- rb_define_method(Ripper, "debug_output", ripper_parser_get_debug_output, 0);
- rb_define_method(Ripper, "debug_output=", ripper_parser_set_debug_output, 1);
- rb_define_method(Ripper, "error?", ripper_error_p, 0);
-#ifdef RIPPER_DEBUG
- rb_define_method(Ripper, "assert_Qundef", ripper_assert_Qundef, 2);
- rb_define_method(Ripper, "rawVALUE", ripper_raw_value, 1);
- rb_define_method(Ripper, "validate_object", ripper_validate_object, 1);
-#endif
-
- rb_define_singleton_method(Ripper, "dedent_string", parser_dedent_string, 2);
- rb_define_private_method(Ripper, "dedent_string", parser_dedent_string, 2);
-
- rb_define_singleton_method(Ripper, "lex_state_name", ripper_lex_state_name, 1);
-
-<% @exprs.each do |expr, desc| -%>
- /* <%=desc%> */
- rb_define_const(Ripper, "<%=expr%>", INT2NUM(<%=expr%>));
-<% end %>
- ripper_init_eventids1_table(Ripper);
- ripper_init_eventids2_table(Ripper);
-
-# if 0
- /* Hack to let RDoc document SCRIPT_LINES__ */
-
- /*
- * When a Hash is assigned to +SCRIPT_LINES__+ the contents of files loaded
- * after the assignment will be added as an Array of lines with the file
- * name as the key.
- */
- rb_define_global_const("SCRIPT_LINES__", Qnil);
-#endif
-
-}
diff --git a/ext/ripper/ripper_init.h b/ext/ripper/ripper_init.h
deleted file mode 100644
index 82ff13b95f..0000000000
--- a/ext/ripper/ripper_init.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef RIPPER_INIT_H
-#define RIPPER_INIT_H
-
-VALUE ripper_get_value(VALUE v);
-ID ripper_get_id(VALUE v);
-PRINTF_ARGS(void ripper_compile_error(struct parser_params*, const char *fmt, ...), 2, 3);
-
-#endif /* RIPPER_INIT_H */
diff --git a/ext/ripper/tools/dsl.rb b/ext/ripper/tools/dsl.rb
index 6d662b3fb8..49ff51711f 100644
--- a/ext/ripper/tools/dsl.rb
+++ b/ext/ripper/tools/dsl.rb
@@ -6,18 +6,11 @@
# v1 = dispatch0(stmts_new);
# v2 = dispatch0(void_stmt);
# $$ = dispatch2(stmts_add, v1, v2);
-#
-# - The code must be a single line.
-#
-# - The code is basically Ruby code, even if it appears like in C and
-# the result will be processed as C. e.g., comments need to be in
-# Ruby style.
-class DSL
- TAG_PATTERN = /(?><[a-zA-Z0-9_]+>)/.source
- NAME_PATTERN = /(?>\$|\d+|[a-zA-Z_][a-zA-Z0-9_]*|\[[a-zA-Z_.][-a-zA-Z0-9_.]*\])(?>(?:\.|->)[a-zA-Z_][a-zA-Z0-9_]*)*/.source
- NOT_REF_PATTERN = /(?>\#.*|[^\"$@]*|"(?>\\.|[^\"])*")/.source
+$dollar = "$$"
+alias $$ $dollar
+class DSL
def initialize(code, options)
@events = {}
@error = options.include?("error")
@@ -25,15 +18,19 @@ class DSL
if options.include?("final")
@final = "p->result"
else
- @final = (options.grep(/\A\$#{NAME_PATTERN}\z/o)[0] || "$$")
+ @final = (options.grep(/\A\$(?:\$|\d+)\z/)[0] || "$$")
end
@vars = 0
+ # create $1 == "$1", $2 == "$2", ...
+ s = (1..20).map {|n| "$#{n}"}
+ re = Array.new(s.size, "([^\0]+)")
+ /#{re.join("\0")}/ =~ s.join("\0")
+
# struct parser_params *p
p = p = "p"
@code = ""
- code = code.gsub(%r[\G#{NOT_REF_PATTERN}\K[$@]#{TAG_PATTERN}?#{NAME_PATTERN}]o, '"\&"')
@last_value = eval(code)
end
diff --git a/ext/ripper/tools/generate.rb b/ext/ripper/tools/generate.rb
index bb64d2fe8b..883e6ef2df 100644
--- a/ext/ripper/tools/generate.rb
+++ b/ext/ripper/tools/generate.rb
@@ -11,7 +11,7 @@ def main
parser = @parser = OptionParser.new
parser.banner = "Usage: #{File.basename($0)} --mode=MODE [--ids1src=PATH] [--ids2src=PATH] [--output=PATH]"
- parser.on('--mode=MODE', 'check, eventids1_h, eventids1, or eventids2table.') {|m|
+ parser.on('--mode=MODE', 'check, eventids1, or eventids2table.') {|m|
mode = m
}
parser.on('--ids1src=PATH', 'A source file of event-IDs 1 (parse.y).') {|path|
@@ -45,9 +45,6 @@ def main
abort "event crash: #{common.join(' ')}"
end
exit 0
- when 'eventids1_h'
- usage 'no --ids1src' unless ids1src
- result = generate_eventids1_h(read_ids1(ids1src))
when 'eventids1'
usage 'no --ids1src' unless ids1src
result = generate_eventids1(read_ids1(ids1src))
@@ -70,35 +67,19 @@ def usage(msg)
exit false
end
-def generate_eventids1_h(ids)
+def generate_eventids1(ids)
buf = "".dup
- buf << %Q[#ifndef RIPPER_EVENTIDS1\n]
- buf << %Q[#define RIPPER_EVENTIDS1\n]
- buf << %Q[\n]
- buf << %Q[void ripper_init_eventids1(void);\n]
- buf << %Q[void ripper_init_eventids1_table(VALUE self);\n]
- buf << %Q[\n]
- buf << %Q[struct ripper_parser_ids {\n]
+ buf << %Q[static struct {\n]
ids.each do |id, arity|
buf << %Q[ ID id_#{id};\n]
end
- buf << %Q[};\n]
+ buf << %Q[} ripper_parser_ids;\n]
buf << %Q[\n]
ids.each do |id, arity|
buf << %Q[#define ripper_id_#{id} ripper_parser_ids.id_#{id}\n]
end
- buf << %Q[#endif /* RIPPER_EVENTIDS1 */\n]
buf << %Q[\n]
-end
-
-def generate_eventids1(ids)
- buf = "".dup
- buf << %Q[#include "ruby/ruby.h"\n]
- buf << %Q[#include "eventids1.h"\n]
- buf << %Q[\n]
- buf << %Q[struct ripper_parser_ids ripper_parser_ids;\n]
- buf << %Q[\n]
- buf << %Q[void\n]
+ buf << %Q[static void\n]
buf << %Q[ripper_init_eventids1(void)\n]
buf << %Q[{\n]
buf << %Q[#define set_id1(name) ripper_id_##name = rb_intern_const("on_"#name)\n]
@@ -107,9 +88,7 @@ def generate_eventids1(ids)
end
buf << %Q[}\n]
buf << %Q[\n]
- buf << %Q[#define intern_sym(name) ID2SYM(rb_intern_const(name))\n]
- buf << %Q[\n]
- buf << %Q[void\n]
+ buf << %Q[static void\n]
buf << %Q[ripper_init_eventids1_table(VALUE self)\n]
buf << %Q[{\n]
buf << %Q[ VALUE h = rb_hash_new();\n]
@@ -123,11 +102,7 @@ end
def generate_eventids2_table(ids)
buf = "".dup
- buf << %Q[#include "ruby/ruby.h"\n]
- buf << %Q[\n]
- buf << %Q[#define intern_sym(name) ID2SYM(rb_intern_const(name))\n]
- buf << %Q[\n]
- buf << %Q[void\n]
+ buf << %Q[static void\n]
buf << %Q[ripper_init_eventids2_table(VALUE self)\n]
buf << %Q[{\n]
buf << %Q[ VALUE h = rb_hash_new();\n]
diff --git a/ext/ripper/tools/preproc.rb b/ext/ripper/tools/preproc.rb
index a0d5e79d7d..cd85a5da61 100644
--- a/ext/ripper/tools/preproc.rb
+++ b/ext/ripper/tools/preproc.rb
@@ -5,15 +5,11 @@ require 'optparse'
def main
output = nil
- template = nil
parser = OptionParser.new
- parser.banner = "Usage: #{File.basename($0)} [--output=PATH] [--template=PATH] <parse.y>"
+ parser.banner = "Usage: #{File.basename($0)} [--output=PATH] <parse.y>"
parser.on('--output=PATH', 'An output file.') {|path|
output = path
}
- parser.on('--template=PATH', 'An template file.') {|path|
- template = path
- }
parser.on('--help', 'Prints this message and quit.') {
puts parser.help
exit true
@@ -21,36 +17,28 @@ def main
begin
parser.parse!
rescue OptionParser::ParseError => err
- warn err.message
- abort parser.help
+ $stderr.puts err.message
+ $stderr.puts parser.help
+ exit false
end
- out = "".dup
- if ARGV[0] == "-"
- unless ARGV.size == 2
- abort "wrong number of arguments (#{ARGV.size} for 2)"
- end
- process STDIN, out, ARGV[1], template
- else
- unless ARGV.size == 1
- abort "wrong number of arguments (#{ARGV.size} for 1)"
- end
- File.open(ARGV[0]) {|f|
- process f, out, ARGV[0], template
- }
+ unless ARGV.size == 1
+ abort "wrong number of arguments (#{ARGV.size} for 1)"
end
+ out = "".dup
+ File.open(ARGV[0]) {|f|
+ prelude f, out
+ grammar f, out
+ usercode f, out
+ }
if output
- File.write(output, out)
+ File.open(output, 'w') {|f|
+ f.write out
+ }
else
print out
end
end
-def process(f, out, path, template)
- prelude f, out
- grammar f, out
- usercode f, out, path, template
-end
-
def prelude(f, out)
@exprs = {}
lex_state_def = false
@@ -59,9 +47,10 @@ def prelude(f, out)
when /\A%%/
out << "%%\n"
return
- when /\A%token/, /\A%type/, /\A} <node(?>_\w+)?>/
- # types in %union which have corresponding set_yylval_* macro.
- out << line.sub(/<(?:node(?>_\w+)?|num|id)>/, '<val>')
+ when /\A%token/, /\A} <node>/
+ out << line.sub(/<\w+>/, '<val>')
+ when /\A%type/
+ out << line.sub(/<\w+>/, '<val>')
when /^enum lex_state_(?:bits|e) \{/
lex_state_def = true
out << line
@@ -106,26 +95,13 @@ def grammar(f, out)
end
end
-def usercode(f, out, path, template)
+def usercode(f, out)
require 'erb'
- lineno = nil
- src = nil
compiler = ERB::Compiler.new('%-')
compiler.put_cmd = compiler.insert_cmd = "out.<<"
-
- if template
- File.open(template) do |f|
- out.clear
- lineno = f.lineno
- src, = compiler.compile(f.read)
- path = template
- end
- else
- lineno = f.lineno
- src, = compiler.compile(f.read)
- end
-
- eval(src, binding, path, lineno)
+ lineno = f.lineno
+ src, = compiler.compile(f.read)
+ eval(src, binding, f.path, lineno)
end
main
diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c
index 6ef040b692..7406177de2 100644
--- a/ext/socket/ancdata.c
+++ b/ext/socket/ancdata.c
@@ -1555,10 +1555,6 @@ bsock_recvmsg_internal(VALUE sock,
ss = rb_recvmsg(fptr->fd, &mh, flags);
- if (ss == 0 && !rsock_is_dgram(fptr)) {
- return Qnil;
- }
-
if (ss == -1) {
int e;
if (!nonblock && rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
diff --git a/ext/socket/depend b/ext/socket/depend
index 675520c0b5..28c5540cd6 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -13,7 +13,6 @@ constdefs.c: constdefs.h
ancdata.o: $(RUBY_EXTCONF_H)
ancdata.o: $(arch_hdrdir)/ruby/config.h
ancdata.o: $(hdrdir)/ruby/assert.h
-ancdata.o: $(hdrdir)/ruby/atomic.h
ancdata.o: $(hdrdir)/ruby/backward.h
ancdata.o: $(hdrdir)/ruby/backward/2/assume.h
ancdata.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -66,7 +65,6 @@ ancdata.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ancdata.o: $(hdrdir)/ruby/internal/attr/noinline.h
ancdata.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ancdata.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ancdata.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ancdata.o: $(hdrdir)/ruby/internal/attr/pure.h
ancdata.o: $(hdrdir)/ruby/internal/attr/restrict.h
ancdata.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -135,6 +133,7 @@ ancdata.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ancdata.o: $(hdrdir)/ruby/internal/intern/error.h
ancdata.o: $(hdrdir)/ruby/internal/intern/eval.h
ancdata.o: $(hdrdir)/ruby/internal/intern/file.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/gc.h
ancdata.o: $(hdrdir)/ruby/internal/intern/hash.h
ancdata.o: $(hdrdir)/ruby/internal/intern/io.h
ancdata.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -165,6 +164,7 @@ ancdata.o: $(hdrdir)/ruby/internal/memory.h
ancdata.o: $(hdrdir)/ruby/internal/method.h
ancdata.o: $(hdrdir)/ruby/internal/module.h
ancdata.o: $(hdrdir)/ruby/internal/newobj.h
+ancdata.o: $(hdrdir)/ruby/internal/rgengc.h
ancdata.o: $(hdrdir)/ruby/internal/scan_args.h
ancdata.o: $(hdrdir)/ruby/internal/special_consts.h
ancdata.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -184,19 +184,12 @@ ancdata.o: $(hdrdir)/ruby/ruby.h
ancdata.o: $(hdrdir)/ruby/st.h
ancdata.o: $(hdrdir)/ruby/subst.h
ancdata.o: $(hdrdir)/ruby/thread.h
-ancdata.o: $(hdrdir)/ruby/thread_native.h
ancdata.o: $(hdrdir)/ruby/util.h
-ancdata.o: $(top_srcdir)/ccan/check_type/check_type.h
-ancdata.o: $(top_srcdir)/ccan/container_of/container_of.h
-ancdata.o: $(top_srcdir)/ccan/list/list.h
-ancdata.o: $(top_srcdir)/ccan/str/str.h
ancdata.o: $(top_srcdir)/internal.h
ancdata.o: $(top_srcdir)/internal/array.h
-ancdata.o: $(top_srcdir)/internal/basic_operators.h
ancdata.o: $(top_srcdir)/internal/compilers.h
ancdata.o: $(top_srcdir)/internal/error.h
ancdata.o: $(top_srcdir)/internal/gc.h
-ancdata.o: $(top_srcdir)/internal/imemo.h
ancdata.o: $(top_srcdir)/internal/io.h
ancdata.o: $(top_srcdir)/internal/serial.h
ancdata.o: $(top_srcdir)/internal/static_assert.h
@@ -204,24 +197,14 @@ ancdata.o: $(top_srcdir)/internal/string.h
ancdata.o: $(top_srcdir)/internal/thread.h
ancdata.o: $(top_srcdir)/internal/vm.h
ancdata.o: $(top_srcdir)/internal/warnings.h
-ancdata.o: $(top_srcdir)/method.h
-ancdata.o: $(top_srcdir)/node.h
-ancdata.o: $(top_srcdir)/ruby_assert.h
-ancdata.o: $(top_srcdir)/ruby_atomic.h
-ancdata.o: $(top_srcdir)/rubyparser.h
ancdata.o: $(top_srcdir)/shape.h
-ancdata.o: $(top_srcdir)/thread_pthread.h
-ancdata.o: $(top_srcdir)/vm_core.h
-ancdata.o: $(top_srcdir)/vm_opts.h
ancdata.o: ancdata.c
ancdata.o: constdefs.h
ancdata.o: rubysocket.h
ancdata.o: sockport.h
-ancdata.o: {$(VPATH)}id.h
basicsocket.o: $(RUBY_EXTCONF_H)
basicsocket.o: $(arch_hdrdir)/ruby/config.h
basicsocket.o: $(hdrdir)/ruby/assert.h
-basicsocket.o: $(hdrdir)/ruby/atomic.h
basicsocket.o: $(hdrdir)/ruby/backward.h
basicsocket.o: $(hdrdir)/ruby/backward/2/assume.h
basicsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -274,7 +257,6 @@ basicsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-basicsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -343,6 +325,7 @@ basicsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/error.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/io.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -373,6 +356,7 @@ basicsocket.o: $(hdrdir)/ruby/internal/memory.h
basicsocket.o: $(hdrdir)/ruby/internal/method.h
basicsocket.o: $(hdrdir)/ruby/internal/module.h
basicsocket.o: $(hdrdir)/ruby/internal/newobj.h
+basicsocket.o: $(hdrdir)/ruby/internal/rgengc.h
basicsocket.o: $(hdrdir)/ruby/internal/scan_args.h
basicsocket.o: $(hdrdir)/ruby/internal/special_consts.h
basicsocket.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -392,19 +376,12 @@ basicsocket.o: $(hdrdir)/ruby/ruby.h
basicsocket.o: $(hdrdir)/ruby/st.h
basicsocket.o: $(hdrdir)/ruby/subst.h
basicsocket.o: $(hdrdir)/ruby/thread.h
-basicsocket.o: $(hdrdir)/ruby/thread_native.h
basicsocket.o: $(hdrdir)/ruby/util.h
-basicsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-basicsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-basicsocket.o: $(top_srcdir)/ccan/list/list.h
-basicsocket.o: $(top_srcdir)/ccan/str/str.h
basicsocket.o: $(top_srcdir)/internal.h
basicsocket.o: $(top_srcdir)/internal/array.h
-basicsocket.o: $(top_srcdir)/internal/basic_operators.h
basicsocket.o: $(top_srcdir)/internal/compilers.h
basicsocket.o: $(top_srcdir)/internal/error.h
basicsocket.o: $(top_srcdir)/internal/gc.h
-basicsocket.o: $(top_srcdir)/internal/imemo.h
basicsocket.o: $(top_srcdir)/internal/io.h
basicsocket.o: $(top_srcdir)/internal/serial.h
basicsocket.o: $(top_srcdir)/internal/static_assert.h
@@ -412,24 +389,14 @@ basicsocket.o: $(top_srcdir)/internal/string.h
basicsocket.o: $(top_srcdir)/internal/thread.h
basicsocket.o: $(top_srcdir)/internal/vm.h
basicsocket.o: $(top_srcdir)/internal/warnings.h
-basicsocket.o: $(top_srcdir)/method.h
-basicsocket.o: $(top_srcdir)/node.h
-basicsocket.o: $(top_srcdir)/ruby_assert.h
-basicsocket.o: $(top_srcdir)/ruby_atomic.h
-basicsocket.o: $(top_srcdir)/rubyparser.h
basicsocket.o: $(top_srcdir)/shape.h
-basicsocket.o: $(top_srcdir)/thread_pthread.h
-basicsocket.o: $(top_srcdir)/vm_core.h
-basicsocket.o: $(top_srcdir)/vm_opts.h
basicsocket.o: basicsocket.c
basicsocket.o: constdefs.h
basicsocket.o: rubysocket.h
basicsocket.o: sockport.h
-basicsocket.o: {$(VPATH)}id.h
constants.o: $(RUBY_EXTCONF_H)
constants.o: $(arch_hdrdir)/ruby/config.h
constants.o: $(hdrdir)/ruby/assert.h
-constants.o: $(hdrdir)/ruby/atomic.h
constants.o: $(hdrdir)/ruby/backward.h
constants.o: $(hdrdir)/ruby/backward/2/assume.h
constants.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -482,7 +449,6 @@ constants.o: $(hdrdir)/ruby/internal/attr/noexcept.h
constants.o: $(hdrdir)/ruby/internal/attr/noinline.h
constants.o: $(hdrdir)/ruby/internal/attr/nonnull.h
constants.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-constants.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
constants.o: $(hdrdir)/ruby/internal/attr/pure.h
constants.o: $(hdrdir)/ruby/internal/attr/restrict.h
constants.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -551,6 +517,7 @@ constants.o: $(hdrdir)/ruby/internal/intern/enumerator.h
constants.o: $(hdrdir)/ruby/internal/intern/error.h
constants.o: $(hdrdir)/ruby/internal/intern/eval.h
constants.o: $(hdrdir)/ruby/internal/intern/file.h
+constants.o: $(hdrdir)/ruby/internal/intern/gc.h
constants.o: $(hdrdir)/ruby/internal/intern/hash.h
constants.o: $(hdrdir)/ruby/internal/intern/io.h
constants.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -581,6 +548,7 @@ constants.o: $(hdrdir)/ruby/internal/memory.h
constants.o: $(hdrdir)/ruby/internal/method.h
constants.o: $(hdrdir)/ruby/internal/module.h
constants.o: $(hdrdir)/ruby/internal/newobj.h
+constants.o: $(hdrdir)/ruby/internal/rgengc.h
constants.o: $(hdrdir)/ruby/internal/scan_args.h
constants.o: $(hdrdir)/ruby/internal/special_consts.h
constants.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -600,19 +568,12 @@ constants.o: $(hdrdir)/ruby/ruby.h
constants.o: $(hdrdir)/ruby/st.h
constants.o: $(hdrdir)/ruby/subst.h
constants.o: $(hdrdir)/ruby/thread.h
-constants.o: $(hdrdir)/ruby/thread_native.h
constants.o: $(hdrdir)/ruby/util.h
-constants.o: $(top_srcdir)/ccan/check_type/check_type.h
-constants.o: $(top_srcdir)/ccan/container_of/container_of.h
-constants.o: $(top_srcdir)/ccan/list/list.h
-constants.o: $(top_srcdir)/ccan/str/str.h
constants.o: $(top_srcdir)/internal.h
constants.o: $(top_srcdir)/internal/array.h
-constants.o: $(top_srcdir)/internal/basic_operators.h
constants.o: $(top_srcdir)/internal/compilers.h
constants.o: $(top_srcdir)/internal/error.h
constants.o: $(top_srcdir)/internal/gc.h
-constants.o: $(top_srcdir)/internal/imemo.h
constants.o: $(top_srcdir)/internal/io.h
constants.o: $(top_srcdir)/internal/serial.h
constants.o: $(top_srcdir)/internal/static_assert.h
@@ -620,25 +581,15 @@ constants.o: $(top_srcdir)/internal/string.h
constants.o: $(top_srcdir)/internal/thread.h
constants.o: $(top_srcdir)/internal/vm.h
constants.o: $(top_srcdir)/internal/warnings.h
-constants.o: $(top_srcdir)/method.h
-constants.o: $(top_srcdir)/node.h
-constants.o: $(top_srcdir)/ruby_assert.h
-constants.o: $(top_srcdir)/ruby_atomic.h
-constants.o: $(top_srcdir)/rubyparser.h
constants.o: $(top_srcdir)/shape.h
-constants.o: $(top_srcdir)/thread_pthread.h
-constants.o: $(top_srcdir)/vm_core.h
-constants.o: $(top_srcdir)/vm_opts.h
constants.o: constants.c
constants.o: constdefs.c
constants.o: constdefs.h
constants.o: rubysocket.h
constants.o: sockport.h
-constants.o: {$(VPATH)}id.h
ifaddr.o: $(RUBY_EXTCONF_H)
ifaddr.o: $(arch_hdrdir)/ruby/config.h
ifaddr.o: $(hdrdir)/ruby/assert.h
-ifaddr.o: $(hdrdir)/ruby/atomic.h
ifaddr.o: $(hdrdir)/ruby/backward.h
ifaddr.o: $(hdrdir)/ruby/backward/2/assume.h
ifaddr.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -691,7 +642,6 @@ ifaddr.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/noinline.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ifaddr.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/pure.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/restrict.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -760,6 +710,7 @@ ifaddr.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/error.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/eval.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/file.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/gc.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/hash.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/io.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -790,6 +741,7 @@ ifaddr.o: $(hdrdir)/ruby/internal/memory.h
ifaddr.o: $(hdrdir)/ruby/internal/method.h
ifaddr.o: $(hdrdir)/ruby/internal/module.h
ifaddr.o: $(hdrdir)/ruby/internal/newobj.h
+ifaddr.o: $(hdrdir)/ruby/internal/rgengc.h
ifaddr.o: $(hdrdir)/ruby/internal/scan_args.h
ifaddr.o: $(hdrdir)/ruby/internal/special_consts.h
ifaddr.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -809,19 +761,12 @@ ifaddr.o: $(hdrdir)/ruby/ruby.h
ifaddr.o: $(hdrdir)/ruby/st.h
ifaddr.o: $(hdrdir)/ruby/subst.h
ifaddr.o: $(hdrdir)/ruby/thread.h
-ifaddr.o: $(hdrdir)/ruby/thread_native.h
ifaddr.o: $(hdrdir)/ruby/util.h
-ifaddr.o: $(top_srcdir)/ccan/check_type/check_type.h
-ifaddr.o: $(top_srcdir)/ccan/container_of/container_of.h
-ifaddr.o: $(top_srcdir)/ccan/list/list.h
-ifaddr.o: $(top_srcdir)/ccan/str/str.h
ifaddr.o: $(top_srcdir)/internal.h
ifaddr.o: $(top_srcdir)/internal/array.h
-ifaddr.o: $(top_srcdir)/internal/basic_operators.h
ifaddr.o: $(top_srcdir)/internal/compilers.h
ifaddr.o: $(top_srcdir)/internal/error.h
ifaddr.o: $(top_srcdir)/internal/gc.h
-ifaddr.o: $(top_srcdir)/internal/imemo.h
ifaddr.o: $(top_srcdir)/internal/io.h
ifaddr.o: $(top_srcdir)/internal/serial.h
ifaddr.o: $(top_srcdir)/internal/static_assert.h
@@ -829,24 +774,14 @@ ifaddr.o: $(top_srcdir)/internal/string.h
ifaddr.o: $(top_srcdir)/internal/thread.h
ifaddr.o: $(top_srcdir)/internal/vm.h
ifaddr.o: $(top_srcdir)/internal/warnings.h
-ifaddr.o: $(top_srcdir)/method.h
-ifaddr.o: $(top_srcdir)/node.h
-ifaddr.o: $(top_srcdir)/ruby_assert.h
-ifaddr.o: $(top_srcdir)/ruby_atomic.h
-ifaddr.o: $(top_srcdir)/rubyparser.h
ifaddr.o: $(top_srcdir)/shape.h
-ifaddr.o: $(top_srcdir)/thread_pthread.h
-ifaddr.o: $(top_srcdir)/vm_core.h
-ifaddr.o: $(top_srcdir)/vm_opts.h
ifaddr.o: constdefs.h
ifaddr.o: ifaddr.c
ifaddr.o: rubysocket.h
ifaddr.o: sockport.h
-ifaddr.o: {$(VPATH)}id.h
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
init.o: $(hdrdir)/ruby/assert.h
-init.o: $(hdrdir)/ruby/atomic.h
init.o: $(hdrdir)/ruby/backward.h
init.o: $(hdrdir)/ruby/backward/2/assume.h
init.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -899,7 +834,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -968,6 +902,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -998,6 +933,7 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1017,19 +953,12 @@ init.o: $(hdrdir)/ruby/ruby.h
init.o: $(hdrdir)/ruby/st.h
init.o: $(hdrdir)/ruby/subst.h
init.o: $(hdrdir)/ruby/thread.h
-init.o: $(hdrdir)/ruby/thread_native.h
init.o: $(hdrdir)/ruby/util.h
-init.o: $(top_srcdir)/ccan/check_type/check_type.h
-init.o: $(top_srcdir)/ccan/container_of/container_of.h
-init.o: $(top_srcdir)/ccan/list/list.h
-init.o: $(top_srcdir)/ccan/str/str.h
init.o: $(top_srcdir)/internal.h
init.o: $(top_srcdir)/internal/array.h
-init.o: $(top_srcdir)/internal/basic_operators.h
init.o: $(top_srcdir)/internal/compilers.h
init.o: $(top_srcdir)/internal/error.h
init.o: $(top_srcdir)/internal/gc.h
-init.o: $(top_srcdir)/internal/imemo.h
init.o: $(top_srcdir)/internal/io.h
init.o: $(top_srcdir)/internal/serial.h
init.o: $(top_srcdir)/internal/static_assert.h
@@ -1037,24 +966,14 @@ init.o: $(top_srcdir)/internal/string.h
init.o: $(top_srcdir)/internal/thread.h
init.o: $(top_srcdir)/internal/vm.h
init.o: $(top_srcdir)/internal/warnings.h
-init.o: $(top_srcdir)/method.h
-init.o: $(top_srcdir)/node.h
-init.o: $(top_srcdir)/ruby_assert.h
-init.o: $(top_srcdir)/ruby_atomic.h
-init.o: $(top_srcdir)/rubyparser.h
init.o: $(top_srcdir)/shape.h
-init.o: $(top_srcdir)/thread_pthread.h
-init.o: $(top_srcdir)/vm_core.h
-init.o: $(top_srcdir)/vm_opts.h
init.o: constdefs.h
init.o: init.c
init.o: rubysocket.h
init.o: sockport.h
-init.o: {$(VPATH)}id.h
ipsocket.o: $(RUBY_EXTCONF_H)
ipsocket.o: $(arch_hdrdir)/ruby/config.h
ipsocket.o: $(hdrdir)/ruby/assert.h
-ipsocket.o: $(hdrdir)/ruby/atomic.h
ipsocket.o: $(hdrdir)/ruby/backward.h
ipsocket.o: $(hdrdir)/ruby/backward/2/assume.h
ipsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1107,7 +1026,6 @@ ipsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ipsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1176,6 +1094,7 @@ ipsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/error.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/io.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1206,6 +1125,7 @@ ipsocket.o: $(hdrdir)/ruby/internal/memory.h
ipsocket.o: $(hdrdir)/ruby/internal/method.h
ipsocket.o: $(hdrdir)/ruby/internal/module.h
ipsocket.o: $(hdrdir)/ruby/internal/newobj.h
+ipsocket.o: $(hdrdir)/ruby/internal/rgengc.h
ipsocket.o: $(hdrdir)/ruby/internal/scan_args.h
ipsocket.o: $(hdrdir)/ruby/internal/special_consts.h
ipsocket.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1225,19 +1145,12 @@ ipsocket.o: $(hdrdir)/ruby/ruby.h
ipsocket.o: $(hdrdir)/ruby/st.h
ipsocket.o: $(hdrdir)/ruby/subst.h
ipsocket.o: $(hdrdir)/ruby/thread.h
-ipsocket.o: $(hdrdir)/ruby/thread_native.h
ipsocket.o: $(hdrdir)/ruby/util.h
-ipsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-ipsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-ipsocket.o: $(top_srcdir)/ccan/list/list.h
-ipsocket.o: $(top_srcdir)/ccan/str/str.h
ipsocket.o: $(top_srcdir)/internal.h
ipsocket.o: $(top_srcdir)/internal/array.h
-ipsocket.o: $(top_srcdir)/internal/basic_operators.h
ipsocket.o: $(top_srcdir)/internal/compilers.h
ipsocket.o: $(top_srcdir)/internal/error.h
ipsocket.o: $(top_srcdir)/internal/gc.h
-ipsocket.o: $(top_srcdir)/internal/imemo.h
ipsocket.o: $(top_srcdir)/internal/io.h
ipsocket.o: $(top_srcdir)/internal/serial.h
ipsocket.o: $(top_srcdir)/internal/static_assert.h
@@ -1245,24 +1158,14 @@ ipsocket.o: $(top_srcdir)/internal/string.h
ipsocket.o: $(top_srcdir)/internal/thread.h
ipsocket.o: $(top_srcdir)/internal/vm.h
ipsocket.o: $(top_srcdir)/internal/warnings.h
-ipsocket.o: $(top_srcdir)/method.h
-ipsocket.o: $(top_srcdir)/node.h
-ipsocket.o: $(top_srcdir)/ruby_assert.h
-ipsocket.o: $(top_srcdir)/ruby_atomic.h
-ipsocket.o: $(top_srcdir)/rubyparser.h
ipsocket.o: $(top_srcdir)/shape.h
-ipsocket.o: $(top_srcdir)/thread_pthread.h
-ipsocket.o: $(top_srcdir)/vm_core.h
-ipsocket.o: $(top_srcdir)/vm_opts.h
ipsocket.o: constdefs.h
ipsocket.o: ipsocket.c
ipsocket.o: rubysocket.h
ipsocket.o: sockport.h
-ipsocket.o: {$(VPATH)}id.h
option.o: $(RUBY_EXTCONF_H)
option.o: $(arch_hdrdir)/ruby/config.h
option.o: $(hdrdir)/ruby/assert.h
-option.o: $(hdrdir)/ruby/atomic.h
option.o: $(hdrdir)/ruby/backward.h
option.o: $(hdrdir)/ruby/backward/2/assume.h
option.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1315,7 +1218,6 @@ option.o: $(hdrdir)/ruby/internal/attr/noexcept.h
option.o: $(hdrdir)/ruby/internal/attr/noinline.h
option.o: $(hdrdir)/ruby/internal/attr/nonnull.h
option.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-option.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
option.o: $(hdrdir)/ruby/internal/attr/pure.h
option.o: $(hdrdir)/ruby/internal/attr/restrict.h
option.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1384,6 +1286,7 @@ option.o: $(hdrdir)/ruby/internal/intern/enumerator.h
option.o: $(hdrdir)/ruby/internal/intern/error.h
option.o: $(hdrdir)/ruby/internal/intern/eval.h
option.o: $(hdrdir)/ruby/internal/intern/file.h
+option.o: $(hdrdir)/ruby/internal/intern/gc.h
option.o: $(hdrdir)/ruby/internal/intern/hash.h
option.o: $(hdrdir)/ruby/internal/intern/io.h
option.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1414,6 +1317,7 @@ option.o: $(hdrdir)/ruby/internal/memory.h
option.o: $(hdrdir)/ruby/internal/method.h
option.o: $(hdrdir)/ruby/internal/module.h
option.o: $(hdrdir)/ruby/internal/newobj.h
+option.o: $(hdrdir)/ruby/internal/rgengc.h
option.o: $(hdrdir)/ruby/internal/scan_args.h
option.o: $(hdrdir)/ruby/internal/special_consts.h
option.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1433,19 +1337,12 @@ option.o: $(hdrdir)/ruby/ruby.h
option.o: $(hdrdir)/ruby/st.h
option.o: $(hdrdir)/ruby/subst.h
option.o: $(hdrdir)/ruby/thread.h
-option.o: $(hdrdir)/ruby/thread_native.h
option.o: $(hdrdir)/ruby/util.h
-option.o: $(top_srcdir)/ccan/check_type/check_type.h
-option.o: $(top_srcdir)/ccan/container_of/container_of.h
-option.o: $(top_srcdir)/ccan/list/list.h
-option.o: $(top_srcdir)/ccan/str/str.h
option.o: $(top_srcdir)/internal.h
option.o: $(top_srcdir)/internal/array.h
-option.o: $(top_srcdir)/internal/basic_operators.h
option.o: $(top_srcdir)/internal/compilers.h
option.o: $(top_srcdir)/internal/error.h
option.o: $(top_srcdir)/internal/gc.h
-option.o: $(top_srcdir)/internal/imemo.h
option.o: $(top_srcdir)/internal/io.h
option.o: $(top_srcdir)/internal/serial.h
option.o: $(top_srcdir)/internal/static_assert.h
@@ -1453,24 +1350,14 @@ option.o: $(top_srcdir)/internal/string.h
option.o: $(top_srcdir)/internal/thread.h
option.o: $(top_srcdir)/internal/vm.h
option.o: $(top_srcdir)/internal/warnings.h
-option.o: $(top_srcdir)/method.h
-option.o: $(top_srcdir)/node.h
-option.o: $(top_srcdir)/ruby_assert.h
-option.o: $(top_srcdir)/ruby_atomic.h
-option.o: $(top_srcdir)/rubyparser.h
option.o: $(top_srcdir)/shape.h
-option.o: $(top_srcdir)/thread_pthread.h
-option.o: $(top_srcdir)/vm_core.h
-option.o: $(top_srcdir)/vm_opts.h
option.o: constdefs.h
option.o: option.c
option.o: rubysocket.h
option.o: sockport.h
-option.o: {$(VPATH)}id.h
raddrinfo.o: $(RUBY_EXTCONF_H)
raddrinfo.o: $(arch_hdrdir)/ruby/config.h
raddrinfo.o: $(hdrdir)/ruby/assert.h
-raddrinfo.o: $(hdrdir)/ruby/atomic.h
raddrinfo.o: $(hdrdir)/ruby/backward.h
raddrinfo.o: $(hdrdir)/ruby/backward/2/assume.h
raddrinfo.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1523,7 +1410,6 @@ raddrinfo.o: $(hdrdir)/ruby/internal/attr/noexcept.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/noinline.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/nonnull.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-raddrinfo.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/pure.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/restrict.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1592,6 +1478,7 @@ raddrinfo.o: $(hdrdir)/ruby/internal/intern/enumerator.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/error.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/eval.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/file.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/gc.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/hash.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/io.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1622,6 +1509,7 @@ raddrinfo.o: $(hdrdir)/ruby/internal/memory.h
raddrinfo.o: $(hdrdir)/ruby/internal/method.h
raddrinfo.o: $(hdrdir)/ruby/internal/module.h
raddrinfo.o: $(hdrdir)/ruby/internal/newobj.h
+raddrinfo.o: $(hdrdir)/ruby/internal/rgengc.h
raddrinfo.o: $(hdrdir)/ruby/internal/scan_args.h
raddrinfo.o: $(hdrdir)/ruby/internal/special_consts.h
raddrinfo.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1641,19 +1529,12 @@ raddrinfo.o: $(hdrdir)/ruby/ruby.h
raddrinfo.o: $(hdrdir)/ruby/st.h
raddrinfo.o: $(hdrdir)/ruby/subst.h
raddrinfo.o: $(hdrdir)/ruby/thread.h
-raddrinfo.o: $(hdrdir)/ruby/thread_native.h
raddrinfo.o: $(hdrdir)/ruby/util.h
-raddrinfo.o: $(top_srcdir)/ccan/check_type/check_type.h
-raddrinfo.o: $(top_srcdir)/ccan/container_of/container_of.h
-raddrinfo.o: $(top_srcdir)/ccan/list/list.h
-raddrinfo.o: $(top_srcdir)/ccan/str/str.h
raddrinfo.o: $(top_srcdir)/internal.h
raddrinfo.o: $(top_srcdir)/internal/array.h
-raddrinfo.o: $(top_srcdir)/internal/basic_operators.h
raddrinfo.o: $(top_srcdir)/internal/compilers.h
raddrinfo.o: $(top_srcdir)/internal/error.h
raddrinfo.o: $(top_srcdir)/internal/gc.h
-raddrinfo.o: $(top_srcdir)/internal/imemo.h
raddrinfo.o: $(top_srcdir)/internal/io.h
raddrinfo.o: $(top_srcdir)/internal/serial.h
raddrinfo.o: $(top_srcdir)/internal/static_assert.h
@@ -1661,24 +1542,14 @@ raddrinfo.o: $(top_srcdir)/internal/string.h
raddrinfo.o: $(top_srcdir)/internal/thread.h
raddrinfo.o: $(top_srcdir)/internal/vm.h
raddrinfo.o: $(top_srcdir)/internal/warnings.h
-raddrinfo.o: $(top_srcdir)/method.h
-raddrinfo.o: $(top_srcdir)/node.h
-raddrinfo.o: $(top_srcdir)/ruby_assert.h
-raddrinfo.o: $(top_srcdir)/ruby_atomic.h
-raddrinfo.o: $(top_srcdir)/rubyparser.h
raddrinfo.o: $(top_srcdir)/shape.h
-raddrinfo.o: $(top_srcdir)/thread_pthread.h
-raddrinfo.o: $(top_srcdir)/vm_core.h
-raddrinfo.o: $(top_srcdir)/vm_opts.h
raddrinfo.o: constdefs.h
raddrinfo.o: raddrinfo.c
raddrinfo.o: rubysocket.h
raddrinfo.o: sockport.h
-raddrinfo.o: {$(VPATH)}id.h
socket.o: $(RUBY_EXTCONF_H)
socket.o: $(arch_hdrdir)/ruby/config.h
socket.o: $(hdrdir)/ruby/assert.h
-socket.o: $(hdrdir)/ruby/atomic.h
socket.o: $(hdrdir)/ruby/backward.h
socket.o: $(hdrdir)/ruby/backward/2/assume.h
socket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1731,7 +1602,6 @@ socket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
socket.o: $(hdrdir)/ruby/internal/attr/noinline.h
socket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
socket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-socket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
socket.o: $(hdrdir)/ruby/internal/attr/pure.h
socket.o: $(hdrdir)/ruby/internal/attr/restrict.h
socket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1800,6 +1670,7 @@ socket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
socket.o: $(hdrdir)/ruby/internal/intern/error.h
socket.o: $(hdrdir)/ruby/internal/intern/eval.h
socket.o: $(hdrdir)/ruby/internal/intern/file.h
+socket.o: $(hdrdir)/ruby/internal/intern/gc.h
socket.o: $(hdrdir)/ruby/internal/intern/hash.h
socket.o: $(hdrdir)/ruby/internal/intern/io.h
socket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1830,6 +1701,7 @@ socket.o: $(hdrdir)/ruby/internal/memory.h
socket.o: $(hdrdir)/ruby/internal/method.h
socket.o: $(hdrdir)/ruby/internal/module.h
socket.o: $(hdrdir)/ruby/internal/newobj.h
+socket.o: $(hdrdir)/ruby/internal/rgengc.h
socket.o: $(hdrdir)/ruby/internal/scan_args.h
socket.o: $(hdrdir)/ruby/internal/special_consts.h
socket.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -1849,19 +1721,12 @@ socket.o: $(hdrdir)/ruby/ruby.h
socket.o: $(hdrdir)/ruby/st.h
socket.o: $(hdrdir)/ruby/subst.h
socket.o: $(hdrdir)/ruby/thread.h
-socket.o: $(hdrdir)/ruby/thread_native.h
socket.o: $(hdrdir)/ruby/util.h
-socket.o: $(top_srcdir)/ccan/check_type/check_type.h
-socket.o: $(top_srcdir)/ccan/container_of/container_of.h
-socket.o: $(top_srcdir)/ccan/list/list.h
-socket.o: $(top_srcdir)/ccan/str/str.h
socket.o: $(top_srcdir)/internal.h
socket.o: $(top_srcdir)/internal/array.h
-socket.o: $(top_srcdir)/internal/basic_operators.h
socket.o: $(top_srcdir)/internal/compilers.h
socket.o: $(top_srcdir)/internal/error.h
socket.o: $(top_srcdir)/internal/gc.h
-socket.o: $(top_srcdir)/internal/imemo.h
socket.o: $(top_srcdir)/internal/io.h
socket.o: $(top_srcdir)/internal/serial.h
socket.o: $(top_srcdir)/internal/static_assert.h
@@ -1869,24 +1734,14 @@ socket.o: $(top_srcdir)/internal/string.h
socket.o: $(top_srcdir)/internal/thread.h
socket.o: $(top_srcdir)/internal/vm.h
socket.o: $(top_srcdir)/internal/warnings.h
-socket.o: $(top_srcdir)/method.h
-socket.o: $(top_srcdir)/node.h
-socket.o: $(top_srcdir)/ruby_assert.h
-socket.o: $(top_srcdir)/ruby_atomic.h
-socket.o: $(top_srcdir)/rubyparser.h
socket.o: $(top_srcdir)/shape.h
-socket.o: $(top_srcdir)/thread_pthread.h
-socket.o: $(top_srcdir)/vm_core.h
-socket.o: $(top_srcdir)/vm_opts.h
socket.o: constdefs.h
socket.o: rubysocket.h
socket.o: socket.c
socket.o: sockport.h
-socket.o: {$(VPATH)}id.h
sockssocket.o: $(RUBY_EXTCONF_H)
sockssocket.o: $(arch_hdrdir)/ruby/config.h
sockssocket.o: $(hdrdir)/ruby/assert.h
-sockssocket.o: $(hdrdir)/ruby/atomic.h
sockssocket.o: $(hdrdir)/ruby/backward.h
sockssocket.o: $(hdrdir)/ruby/backward/2/assume.h
sockssocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1939,7 +1794,6 @@ sockssocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sockssocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/pure.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2008,6 +1862,7 @@ sockssocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/error.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/eval.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/file.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/gc.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/hash.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/io.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2038,6 +1893,7 @@ sockssocket.o: $(hdrdir)/ruby/internal/memory.h
sockssocket.o: $(hdrdir)/ruby/internal/method.h
sockssocket.o: $(hdrdir)/ruby/internal/module.h
sockssocket.o: $(hdrdir)/ruby/internal/newobj.h
+sockssocket.o: $(hdrdir)/ruby/internal/rgengc.h
sockssocket.o: $(hdrdir)/ruby/internal/scan_args.h
sockssocket.o: $(hdrdir)/ruby/internal/special_consts.h
sockssocket.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2057,19 +1913,12 @@ sockssocket.o: $(hdrdir)/ruby/ruby.h
sockssocket.o: $(hdrdir)/ruby/st.h
sockssocket.o: $(hdrdir)/ruby/subst.h
sockssocket.o: $(hdrdir)/ruby/thread.h
-sockssocket.o: $(hdrdir)/ruby/thread_native.h
sockssocket.o: $(hdrdir)/ruby/util.h
-sockssocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-sockssocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-sockssocket.o: $(top_srcdir)/ccan/list/list.h
-sockssocket.o: $(top_srcdir)/ccan/str/str.h
sockssocket.o: $(top_srcdir)/internal.h
sockssocket.o: $(top_srcdir)/internal/array.h
-sockssocket.o: $(top_srcdir)/internal/basic_operators.h
sockssocket.o: $(top_srcdir)/internal/compilers.h
sockssocket.o: $(top_srcdir)/internal/error.h
sockssocket.o: $(top_srcdir)/internal/gc.h
-sockssocket.o: $(top_srcdir)/internal/imemo.h
sockssocket.o: $(top_srcdir)/internal/io.h
sockssocket.o: $(top_srcdir)/internal/serial.h
sockssocket.o: $(top_srcdir)/internal/static_assert.h
@@ -2077,24 +1926,14 @@ sockssocket.o: $(top_srcdir)/internal/string.h
sockssocket.o: $(top_srcdir)/internal/thread.h
sockssocket.o: $(top_srcdir)/internal/vm.h
sockssocket.o: $(top_srcdir)/internal/warnings.h
-sockssocket.o: $(top_srcdir)/method.h
-sockssocket.o: $(top_srcdir)/node.h
-sockssocket.o: $(top_srcdir)/ruby_assert.h
-sockssocket.o: $(top_srcdir)/ruby_atomic.h
-sockssocket.o: $(top_srcdir)/rubyparser.h
sockssocket.o: $(top_srcdir)/shape.h
-sockssocket.o: $(top_srcdir)/thread_pthread.h
-sockssocket.o: $(top_srcdir)/vm_core.h
-sockssocket.o: $(top_srcdir)/vm_opts.h
sockssocket.o: constdefs.h
sockssocket.o: rubysocket.h
sockssocket.o: sockport.h
sockssocket.o: sockssocket.c
-sockssocket.o: {$(VPATH)}id.h
tcpserver.o: $(RUBY_EXTCONF_H)
tcpserver.o: $(arch_hdrdir)/ruby/config.h
tcpserver.o: $(hdrdir)/ruby/assert.h
-tcpserver.o: $(hdrdir)/ruby/atomic.h
tcpserver.o: $(hdrdir)/ruby/backward.h
tcpserver.o: $(hdrdir)/ruby/backward/2/assume.h
tcpserver.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2147,7 +1986,6 @@ tcpserver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/noinline.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-tcpserver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/pure.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/restrict.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2216,6 +2054,7 @@ tcpserver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/error.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/eval.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/file.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/gc.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/hash.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/io.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2246,6 +2085,7 @@ tcpserver.o: $(hdrdir)/ruby/internal/memory.h
tcpserver.o: $(hdrdir)/ruby/internal/method.h
tcpserver.o: $(hdrdir)/ruby/internal/module.h
tcpserver.o: $(hdrdir)/ruby/internal/newobj.h
+tcpserver.o: $(hdrdir)/ruby/internal/rgengc.h
tcpserver.o: $(hdrdir)/ruby/internal/scan_args.h
tcpserver.o: $(hdrdir)/ruby/internal/special_consts.h
tcpserver.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2265,19 +2105,12 @@ tcpserver.o: $(hdrdir)/ruby/ruby.h
tcpserver.o: $(hdrdir)/ruby/st.h
tcpserver.o: $(hdrdir)/ruby/subst.h
tcpserver.o: $(hdrdir)/ruby/thread.h
-tcpserver.o: $(hdrdir)/ruby/thread_native.h
tcpserver.o: $(hdrdir)/ruby/util.h
-tcpserver.o: $(top_srcdir)/ccan/check_type/check_type.h
-tcpserver.o: $(top_srcdir)/ccan/container_of/container_of.h
-tcpserver.o: $(top_srcdir)/ccan/list/list.h
-tcpserver.o: $(top_srcdir)/ccan/str/str.h
tcpserver.o: $(top_srcdir)/internal.h
tcpserver.o: $(top_srcdir)/internal/array.h
-tcpserver.o: $(top_srcdir)/internal/basic_operators.h
tcpserver.o: $(top_srcdir)/internal/compilers.h
tcpserver.o: $(top_srcdir)/internal/error.h
tcpserver.o: $(top_srcdir)/internal/gc.h
-tcpserver.o: $(top_srcdir)/internal/imemo.h
tcpserver.o: $(top_srcdir)/internal/io.h
tcpserver.o: $(top_srcdir)/internal/serial.h
tcpserver.o: $(top_srcdir)/internal/static_assert.h
@@ -2285,24 +2118,14 @@ tcpserver.o: $(top_srcdir)/internal/string.h
tcpserver.o: $(top_srcdir)/internal/thread.h
tcpserver.o: $(top_srcdir)/internal/vm.h
tcpserver.o: $(top_srcdir)/internal/warnings.h
-tcpserver.o: $(top_srcdir)/method.h
-tcpserver.o: $(top_srcdir)/node.h
-tcpserver.o: $(top_srcdir)/ruby_assert.h
-tcpserver.o: $(top_srcdir)/ruby_atomic.h
-tcpserver.o: $(top_srcdir)/rubyparser.h
tcpserver.o: $(top_srcdir)/shape.h
-tcpserver.o: $(top_srcdir)/thread_pthread.h
-tcpserver.o: $(top_srcdir)/vm_core.h
-tcpserver.o: $(top_srcdir)/vm_opts.h
tcpserver.o: constdefs.h
tcpserver.o: rubysocket.h
tcpserver.o: sockport.h
tcpserver.o: tcpserver.c
-tcpserver.o: {$(VPATH)}id.h
tcpsocket.o: $(RUBY_EXTCONF_H)
tcpsocket.o: $(arch_hdrdir)/ruby/config.h
tcpsocket.o: $(hdrdir)/ruby/assert.h
-tcpsocket.o: $(hdrdir)/ruby/atomic.h
tcpsocket.o: $(hdrdir)/ruby/backward.h
tcpsocket.o: $(hdrdir)/ruby/backward/2/assume.h
tcpsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2355,7 +2178,6 @@ tcpsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-tcpsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2424,6 +2246,7 @@ tcpsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/error.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/io.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2454,6 +2277,7 @@ tcpsocket.o: $(hdrdir)/ruby/internal/memory.h
tcpsocket.o: $(hdrdir)/ruby/internal/method.h
tcpsocket.o: $(hdrdir)/ruby/internal/module.h
tcpsocket.o: $(hdrdir)/ruby/internal/newobj.h
+tcpsocket.o: $(hdrdir)/ruby/internal/rgengc.h
tcpsocket.o: $(hdrdir)/ruby/internal/scan_args.h
tcpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
tcpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2473,19 +2297,12 @@ tcpsocket.o: $(hdrdir)/ruby/ruby.h
tcpsocket.o: $(hdrdir)/ruby/st.h
tcpsocket.o: $(hdrdir)/ruby/subst.h
tcpsocket.o: $(hdrdir)/ruby/thread.h
-tcpsocket.o: $(hdrdir)/ruby/thread_native.h
tcpsocket.o: $(hdrdir)/ruby/util.h
-tcpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-tcpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-tcpsocket.o: $(top_srcdir)/ccan/list/list.h
-tcpsocket.o: $(top_srcdir)/ccan/str/str.h
tcpsocket.o: $(top_srcdir)/internal.h
tcpsocket.o: $(top_srcdir)/internal/array.h
-tcpsocket.o: $(top_srcdir)/internal/basic_operators.h
tcpsocket.o: $(top_srcdir)/internal/compilers.h
tcpsocket.o: $(top_srcdir)/internal/error.h
tcpsocket.o: $(top_srcdir)/internal/gc.h
-tcpsocket.o: $(top_srcdir)/internal/imemo.h
tcpsocket.o: $(top_srcdir)/internal/io.h
tcpsocket.o: $(top_srcdir)/internal/serial.h
tcpsocket.o: $(top_srcdir)/internal/static_assert.h
@@ -2493,24 +2310,14 @@ tcpsocket.o: $(top_srcdir)/internal/string.h
tcpsocket.o: $(top_srcdir)/internal/thread.h
tcpsocket.o: $(top_srcdir)/internal/vm.h
tcpsocket.o: $(top_srcdir)/internal/warnings.h
-tcpsocket.o: $(top_srcdir)/method.h
-tcpsocket.o: $(top_srcdir)/node.h
-tcpsocket.o: $(top_srcdir)/ruby_assert.h
-tcpsocket.o: $(top_srcdir)/ruby_atomic.h
-tcpsocket.o: $(top_srcdir)/rubyparser.h
tcpsocket.o: $(top_srcdir)/shape.h
-tcpsocket.o: $(top_srcdir)/thread_pthread.h
-tcpsocket.o: $(top_srcdir)/vm_core.h
-tcpsocket.o: $(top_srcdir)/vm_opts.h
tcpsocket.o: constdefs.h
tcpsocket.o: rubysocket.h
tcpsocket.o: sockport.h
tcpsocket.o: tcpsocket.c
-tcpsocket.o: {$(VPATH)}id.h
udpsocket.o: $(RUBY_EXTCONF_H)
udpsocket.o: $(arch_hdrdir)/ruby/config.h
udpsocket.o: $(hdrdir)/ruby/assert.h
-udpsocket.o: $(hdrdir)/ruby/atomic.h
udpsocket.o: $(hdrdir)/ruby/backward.h
udpsocket.o: $(hdrdir)/ruby/backward/2/assume.h
udpsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2563,7 +2370,6 @@ udpsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-udpsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2632,6 +2438,7 @@ udpsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/error.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/io.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2662,6 +2469,7 @@ udpsocket.o: $(hdrdir)/ruby/internal/memory.h
udpsocket.o: $(hdrdir)/ruby/internal/method.h
udpsocket.o: $(hdrdir)/ruby/internal/module.h
udpsocket.o: $(hdrdir)/ruby/internal/newobj.h
+udpsocket.o: $(hdrdir)/ruby/internal/rgengc.h
udpsocket.o: $(hdrdir)/ruby/internal/scan_args.h
udpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
udpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2681,19 +2489,12 @@ udpsocket.o: $(hdrdir)/ruby/ruby.h
udpsocket.o: $(hdrdir)/ruby/st.h
udpsocket.o: $(hdrdir)/ruby/subst.h
udpsocket.o: $(hdrdir)/ruby/thread.h
-udpsocket.o: $(hdrdir)/ruby/thread_native.h
udpsocket.o: $(hdrdir)/ruby/util.h
-udpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-udpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-udpsocket.o: $(top_srcdir)/ccan/list/list.h
-udpsocket.o: $(top_srcdir)/ccan/str/str.h
udpsocket.o: $(top_srcdir)/internal.h
udpsocket.o: $(top_srcdir)/internal/array.h
-udpsocket.o: $(top_srcdir)/internal/basic_operators.h
udpsocket.o: $(top_srcdir)/internal/compilers.h
udpsocket.o: $(top_srcdir)/internal/error.h
udpsocket.o: $(top_srcdir)/internal/gc.h
-udpsocket.o: $(top_srcdir)/internal/imemo.h
udpsocket.o: $(top_srcdir)/internal/io.h
udpsocket.o: $(top_srcdir)/internal/serial.h
udpsocket.o: $(top_srcdir)/internal/static_assert.h
@@ -2701,24 +2502,14 @@ udpsocket.o: $(top_srcdir)/internal/string.h
udpsocket.o: $(top_srcdir)/internal/thread.h
udpsocket.o: $(top_srcdir)/internal/vm.h
udpsocket.o: $(top_srcdir)/internal/warnings.h
-udpsocket.o: $(top_srcdir)/method.h
-udpsocket.o: $(top_srcdir)/node.h
-udpsocket.o: $(top_srcdir)/ruby_assert.h
-udpsocket.o: $(top_srcdir)/ruby_atomic.h
-udpsocket.o: $(top_srcdir)/rubyparser.h
udpsocket.o: $(top_srcdir)/shape.h
-udpsocket.o: $(top_srcdir)/thread_pthread.h
-udpsocket.o: $(top_srcdir)/vm_core.h
-udpsocket.o: $(top_srcdir)/vm_opts.h
udpsocket.o: constdefs.h
udpsocket.o: rubysocket.h
udpsocket.o: sockport.h
udpsocket.o: udpsocket.c
-udpsocket.o: {$(VPATH)}id.h
unixserver.o: $(RUBY_EXTCONF_H)
unixserver.o: $(arch_hdrdir)/ruby/config.h
unixserver.o: $(hdrdir)/ruby/assert.h
-unixserver.o: $(hdrdir)/ruby/atomic.h
unixserver.o: $(hdrdir)/ruby/backward.h
unixserver.o: $(hdrdir)/ruby/backward/2/assume.h
unixserver.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2771,7 +2562,6 @@ unixserver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
unixserver.o: $(hdrdir)/ruby/internal/attr/noinline.h
unixserver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
unixserver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-unixserver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
unixserver.o: $(hdrdir)/ruby/internal/attr/pure.h
unixserver.o: $(hdrdir)/ruby/internal/attr/restrict.h
unixserver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2840,6 +2630,7 @@ unixserver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
unixserver.o: $(hdrdir)/ruby/internal/intern/error.h
unixserver.o: $(hdrdir)/ruby/internal/intern/eval.h
unixserver.o: $(hdrdir)/ruby/internal/intern/file.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/gc.h
unixserver.o: $(hdrdir)/ruby/internal/intern/hash.h
unixserver.o: $(hdrdir)/ruby/internal/intern/io.h
unixserver.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2870,6 +2661,7 @@ unixserver.o: $(hdrdir)/ruby/internal/memory.h
unixserver.o: $(hdrdir)/ruby/internal/method.h
unixserver.o: $(hdrdir)/ruby/internal/module.h
unixserver.o: $(hdrdir)/ruby/internal/newobj.h
+unixserver.o: $(hdrdir)/ruby/internal/rgengc.h
unixserver.o: $(hdrdir)/ruby/internal/scan_args.h
unixserver.o: $(hdrdir)/ruby/internal/special_consts.h
unixserver.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -2889,19 +2681,12 @@ unixserver.o: $(hdrdir)/ruby/ruby.h
unixserver.o: $(hdrdir)/ruby/st.h
unixserver.o: $(hdrdir)/ruby/subst.h
unixserver.o: $(hdrdir)/ruby/thread.h
-unixserver.o: $(hdrdir)/ruby/thread_native.h
unixserver.o: $(hdrdir)/ruby/util.h
-unixserver.o: $(top_srcdir)/ccan/check_type/check_type.h
-unixserver.o: $(top_srcdir)/ccan/container_of/container_of.h
-unixserver.o: $(top_srcdir)/ccan/list/list.h
-unixserver.o: $(top_srcdir)/ccan/str/str.h
unixserver.o: $(top_srcdir)/internal.h
unixserver.o: $(top_srcdir)/internal/array.h
-unixserver.o: $(top_srcdir)/internal/basic_operators.h
unixserver.o: $(top_srcdir)/internal/compilers.h
unixserver.o: $(top_srcdir)/internal/error.h
unixserver.o: $(top_srcdir)/internal/gc.h
-unixserver.o: $(top_srcdir)/internal/imemo.h
unixserver.o: $(top_srcdir)/internal/io.h
unixserver.o: $(top_srcdir)/internal/serial.h
unixserver.o: $(top_srcdir)/internal/static_assert.h
@@ -2909,24 +2694,14 @@ unixserver.o: $(top_srcdir)/internal/string.h
unixserver.o: $(top_srcdir)/internal/thread.h
unixserver.o: $(top_srcdir)/internal/vm.h
unixserver.o: $(top_srcdir)/internal/warnings.h
-unixserver.o: $(top_srcdir)/method.h
-unixserver.o: $(top_srcdir)/node.h
-unixserver.o: $(top_srcdir)/ruby_assert.h
-unixserver.o: $(top_srcdir)/ruby_atomic.h
-unixserver.o: $(top_srcdir)/rubyparser.h
unixserver.o: $(top_srcdir)/shape.h
-unixserver.o: $(top_srcdir)/thread_pthread.h
-unixserver.o: $(top_srcdir)/vm_core.h
-unixserver.o: $(top_srcdir)/vm_opts.h
unixserver.o: constdefs.h
unixserver.o: rubysocket.h
unixserver.o: sockport.h
unixserver.o: unixserver.c
-unixserver.o: {$(VPATH)}id.h
unixsocket.o: $(RUBY_EXTCONF_H)
unixsocket.o: $(arch_hdrdir)/ruby/config.h
unixsocket.o: $(hdrdir)/ruby/assert.h
-unixsocket.o: $(hdrdir)/ruby/atomic.h
unixsocket.o: $(hdrdir)/ruby/backward.h
unixsocket.o: $(hdrdir)/ruby/backward/2/assume.h
unixsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2979,7 +2754,6 @@ unixsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-unixsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3048,6 +2822,7 @@ unixsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/error.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/io.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3078,6 +2853,7 @@ unixsocket.o: $(hdrdir)/ruby/internal/memory.h
unixsocket.o: $(hdrdir)/ruby/internal/method.h
unixsocket.o: $(hdrdir)/ruby/internal/module.h
unixsocket.o: $(hdrdir)/ruby/internal/newobj.h
+unixsocket.o: $(hdrdir)/ruby/internal/rgengc.h
unixsocket.o: $(hdrdir)/ruby/internal/scan_args.h
unixsocket.o: $(hdrdir)/ruby/internal/special_consts.h
unixsocket.o: $(hdrdir)/ruby/internal/static_assert.h
@@ -3097,19 +2873,12 @@ unixsocket.o: $(hdrdir)/ruby/ruby.h
unixsocket.o: $(hdrdir)/ruby/st.h
unixsocket.o: $(hdrdir)/ruby/subst.h
unixsocket.o: $(hdrdir)/ruby/thread.h
-unixsocket.o: $(hdrdir)/ruby/thread_native.h
unixsocket.o: $(hdrdir)/ruby/util.h
-unixsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-unixsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-unixsocket.o: $(top_srcdir)/ccan/list/list.h
-unixsocket.o: $(top_srcdir)/ccan/str/str.h
unixsocket.o: $(top_srcdir)/internal.h
unixsocket.o: $(top_srcdir)/internal/array.h
-unixsocket.o: $(top_srcdir)/internal/basic_operators.h
unixsocket.o: $(top_srcdir)/internal/compilers.h
unixsocket.o: $(top_srcdir)/internal/error.h
unixsocket.o: $(top_srcdir)/internal/gc.h
-unixsocket.o: $(top_srcdir)/internal/imemo.h
unixsocket.o: $(top_srcdir)/internal/io.h
unixsocket.o: $(top_srcdir)/internal/serial.h
unixsocket.o: $(top_srcdir)/internal/static_assert.h
@@ -3117,18 +2886,9 @@ unixsocket.o: $(top_srcdir)/internal/string.h
unixsocket.o: $(top_srcdir)/internal/thread.h
unixsocket.o: $(top_srcdir)/internal/vm.h
unixsocket.o: $(top_srcdir)/internal/warnings.h
-unixsocket.o: $(top_srcdir)/method.h
-unixsocket.o: $(top_srcdir)/node.h
-unixsocket.o: $(top_srcdir)/ruby_assert.h
-unixsocket.o: $(top_srcdir)/ruby_atomic.h
-unixsocket.o: $(top_srcdir)/rubyparser.h
unixsocket.o: $(top_srcdir)/shape.h
-unixsocket.o: $(top_srcdir)/thread_pthread.h
-unixsocket.o: $(top_srcdir)/vm_core.h
-unixsocket.o: $(top_srcdir)/vm_opts.h
unixsocket.o: constdefs.h
unixsocket.o: rubysocket.h
unixsocket.o: sockport.h
unixsocket.o: unixsocket.c
-unixsocket.o: {$(VPATH)}id.h
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index 1ca52da366..37ff216560 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -327,8 +327,6 @@ end
net/if_dl.h
arpa/nameser.h
resolv.h
- pthread.h
- sched.h
].each {|h|
if have_header(h, headers)
headers << h
@@ -349,22 +347,10 @@ have_type("struct sockaddr_storage", headers)
have_type("struct addrinfo", headers)
-def check_socklen(headers)
- def (fmt = "none").%(x)
- x || self
- end
- s = checking_for("RSTRING_SOCKLEN", fmt) do
- if try_static_assert("sizeof(socklen_t) >= sizeof(long)", headers)
- "RSTRING_LEN"
- else
- "RSTRING_LENINT"
- end
- end
- $defs << "-DRSTRING_SOCKLEN=(socklen_t)"+s
-end
-
if have_type("socklen_t", headers)
- check_socklen(headers)
+ if try_static_assert("sizeof(socklen_t) >= sizeof(long)", headers)
+ $defs << "-DRSTRING_SOCKLEN=(socklen_t)RSTRING_LEN"
+ end
end
have_type("struct in_pktinfo", headers) {|src|
@@ -701,12 +687,5 @@ SRC
"not needed"
end
end
-
- have_func("pthread_create")
- have_func("pthread_detach")
- have_func("pthread_attr_setaffinity_np")
- have_func("sched_getcpu")
-
- $VPATH << '$(topdir)' << '$(top_srcdir)'
create_makefile("socket")
end
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index bf0d90129f..95a2feb3be 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -219,7 +219,8 @@ freeaddrinfo(struct addrinfo *ai)
do {
next = ai->ai_next;
- free(ai->ai_canonname);
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
/* no need to free(ai->ai_addr) */
free(ai);
} while ((ai = next) != NULL);
diff --git a/ext/socket/init.c b/ext/socket/init.c
index e9dc6f8483..557d4374a5 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -116,7 +116,6 @@ recvfrom_blocking(void *data)
ssize_t ret;
ret = recvfrom(arg->fd, RSTRING_PTR(arg->str), arg->length,
arg->flags, &arg->buf.addr, &arg->alen);
-
if (ret != -1 && len0 < arg->alen)
arg->alen = len0;
@@ -148,18 +147,6 @@ recvfrom_locktmp(VALUE v)
return rb_thread_io_blocking_region(recvfrom_blocking, arg, arg->fd);
}
-int
-rsock_is_dgram(rb_io_t *fptr)
-{
- int socktype;
- socklen_t optlen = (socklen_t)sizeof(socktype);
- int ret = getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen);
- if (ret == -1) {
- rb_sys_fail("getsockopt(SO_TYPE)");
- }
- return socktype == SOCK_DGRAM;
-}
-
VALUE
rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from)
{
@@ -200,9 +187,6 @@ rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from)
slen = (long)rb_str_locktmp_ensure(str, recvfrom_locktmp, (VALUE)&arg);
- if (slen == 0 && !rsock_is_dgram(fptr)) {
- return Qnil;
- }
if (slen >= 0) break;
if (!rb_io_maybe_wait_readable(errno, socket, RUBY_IO_TIMEOUT_DEFAULT))
@@ -275,10 +259,6 @@ rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
if (slen != -1 && len0 < alen)
alen = len0;
- if (slen == 0 && !rsock_is_dgram(fptr)) {
- return Qnil;
- }
-
if (slen < 0) {
int e = errno;
switch (e) {
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index 18585c2181..45b4cad38f 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -10,22 +10,6 @@
#include "rubysocket.h"
-// GETADDRINFO_IMPL == 0 : call getaddrinfo/getnameinfo directly
-// GETADDRINFO_IMPL == 1 : call getaddrinfo/getnameinfo without gvl (but uncancellable)
-// GETADDRINFO_IMPL == 2 : call getaddrinfo/getnameinfo in a dedicated pthread
-// (and if the call is interrupted, the pthread is detached)
-
-#ifndef GETADDRINFO_IMPL
-# ifdef GETADDRINFO_EMU
-# define GETADDRINFO_IMPL 0
-# elif !defined(HAVE_PTHREAD_CREATE) || !defined(HAVE_PTHREAD_DETACH) || defined(__MINGW32__) || defined(__MINGW64__)
-# define GETADDRINFO_IMPL 1
-# else
-# define GETADDRINFO_IMPL 2
-# include "ruby/thread_native.h"
-# endif
-#endif
-
#if defined(INET6) && (defined(LOOKUP_ORDER_HACK_INET) || defined(LOOKUP_ORDER_HACK_INET6))
#define LOOKUP_ORDERS (sizeof(lookup_order_table) / sizeof(lookup_order_table[0]))
static const int lookup_order_table[] = {
@@ -189,6 +173,32 @@ parse_numeric_port(const char *service, int *portp)
}
#endif
+#ifndef GETADDRINFO_EMU
+struct getaddrinfo_arg
+{
+ const char *node;
+ const char *service;
+ const struct addrinfo *hints;
+ struct addrinfo **res;
+};
+
+static void *
+nogvl_getaddrinfo(void *arg)
+{
+ int ret;
+ struct getaddrinfo_arg *ptr = arg;
+ ret = getaddrinfo(ptr->node, ptr->service, ptr->hints, ptr->res);
+#ifdef __linux__
+ /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
+ * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
+ */
+ if (ret == EAI_SYSTEM && errno == ENOENT)
+ ret = EAI_NONAME;
+#endif
+ return (void *)(VALUE)ret;
+}
+#endif
+
static int
numeric_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
@@ -277,8 +287,9 @@ numeric_getaddrinfo(const char *node, const char *service,
void
rb_freeaddrinfo(struct rb_addrinfo *ai)
{
- if (!ai->allocated_by_malloc)
- freeaddrinfo(ai->ai);
+ if (!ai->allocated_by_malloc) {
+ if (ai->ai) freeaddrinfo(ai->ai);
+ }
else {
struct addrinfo *ai1, *ai2;
ai1 = ai->ai;
@@ -292,257 +303,7 @@ rb_freeaddrinfo(struct rb_addrinfo *ai)
xfree(ai);
}
-#if GETADDRINFO_IMPL == 0
-
-static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
-{
- return getaddrinfo(hostp, portp, hints, ai);
-}
-
-#elif GETADDRINFO_IMPL == 1
-
-struct getaddrinfo_arg
-{
- const char *node;
- const char *service;
- const struct addrinfo *hints;
- struct addrinfo **res;
-};
-
-static void *
-nogvl_getaddrinfo(void *arg)
-{
- int ret;
- struct getaddrinfo_arg *ptr = arg;
- ret = getaddrinfo(ptr->node, ptr->service, ptr->hints, ptr->res);
-#ifdef __linux__
- /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
- * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
- */
- if (ret == EAI_SYSTEM && errno == ENOENT)
- ret = EAI_NONAME;
-#endif
- return (void *)(VALUE)ret;
-}
-
-static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
-{
- struct getaddrinfo_arg arg;
- MEMZERO(&arg, struct getaddrinfo_arg, 1);
- arg.node = hostp;
- arg.service = portp;
- arg.hints = hints;
- arg.res = ai;
- return (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
-}
-
-#elif GETADDRINFO_IMPL == 2
-
-struct getaddrinfo_arg
-{
- char *node, *service;
- struct addrinfo hints;
- struct addrinfo *ai;
- int err, refcount, done, cancelled;
- rb_nativethread_lock_t lock;
- rb_nativethread_cond_t cond;
-};
-
-static struct getaddrinfo_arg *
-allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints)
-{
- size_t hostp_offset = sizeof(struct getaddrinfo_arg);
- size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0);
- size_t bufsize = portp_offset + (portp ? strlen(portp) + 1 : 0);
-
- char *buf = malloc(bufsize);
- if (!buf) {
- rb_gc();
- buf = malloc(bufsize);
- if (!buf) return NULL;
- }
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)buf;
-
- if (hostp) {
- arg->node = buf + hostp_offset;
- strcpy(arg->node, hostp);
- }
- else {
- arg->node = NULL;
- }
-
- if (portp) {
- arg->service = buf + portp_offset;
- strcpy(arg->service, portp);
- }
- else {
- arg->service = NULL;
- }
-
- arg->hints = *hints;
- arg->ai = NULL;
-
- arg->refcount = 2;
- arg->done = arg->cancelled = 0;
-
- rb_nativethread_lock_initialize(&arg->lock);
- rb_native_cond_initialize(&arg->cond);
-
- return arg;
-}
-
-static void
-free_getaddrinfo_arg(struct getaddrinfo_arg *arg)
-{
- rb_native_cond_destroy(&arg->cond);
- rb_nativethread_lock_destroy(&arg->lock);
- free(arg);
-}
-
-static void *
-do_getaddrinfo(void *ptr)
-{
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
-
- int err;
- err = getaddrinfo(arg->node, arg->service, &arg->hints, &arg->ai);
-#ifdef __linux__
- /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
- * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
- */
- if (err == EAI_SYSTEM && errno == ENOENT)
- err = EAI_NONAME;
-#endif
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- {
- arg->err = err;
- if (arg->cancelled) {
- freeaddrinfo(arg->ai);
- }
- else {
- arg->done = 1;
- rb_native_cond_signal(&arg->cond);
- }
- if (--arg->refcount == 0) need_free = 1;
- }
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getaddrinfo_arg(arg);
-
- return 0;
-}
-
-static void *
-wait_getaddrinfo(void *ptr)
-{
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- while (!arg->done && !arg->cancelled) {
- rb_native_cond_wait(&arg->cond, &arg->lock);
- }
- rb_nativethread_lock_unlock(&arg->lock);
- return 0;
-}
-
-static void
-cancel_getaddrinfo(void *ptr)
-{
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- {
- arg->cancelled = 1;
- rb_native_cond_signal(&arg->cond);
- }
- rb_nativethread_lock_unlock(&arg->lock);
-}
-
-static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
-{
- int retry;
- struct getaddrinfo_arg *arg;
- int err;
-
-start:
- retry = 0;
-
- arg = allocate_getaddrinfo_arg(hostp, portp, hints);
- if (!arg) {
- return EAI_MEMORY;
- }
-
- pthread_attr_t attr;
- if (pthread_attr_init(&attr) != 0) {
- free_getaddrinfo_arg(arg);
- return EAI_AGAIN;
- }
-#if defined(HAVE_PTHREAD_ATTR_SETAFFINITY_NP) && defined(HAVE_SCHED_GETCPU)
- cpu_set_t tmp_cpu_set;
- CPU_ZERO(&tmp_cpu_set);
- int cpu = sched_getcpu();
- if (cpu < CPU_SETSIZE) {
- CPU_SET(cpu, &tmp_cpu_set);
- pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &tmp_cpu_set);
- }
-#endif
-
- pthread_t th;
- if (pthread_create(&th, &attr, do_getaddrinfo, arg) != 0) {
- free_getaddrinfo_arg(arg);
- return EAI_AGAIN;
- }
- pthread_detach(th);
-
- rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg);
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- {
- if (arg->done) {
- err = arg->err;
- if (err == 0) *ai = arg->ai;
- }
- else if (arg->cancelled) {
- err = EAI_AGAIN;
- }
- else {
- // If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getaddrinfo.
- // In this case, it could be !arg->done && !arg->cancelled.
- arg->cancelled = 1; // to make do_getaddrinfo call freeaddrinfo
- retry = 1;
- }
- if (--arg->refcount == 0) need_free = 1;
- }
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getaddrinfo_arg(arg);
-
- // If the current thread is interrupted by asynchronous exception, the following raises the exception.
- // But if the current thread is interrupted by timer thread, the following returns; we need to manually retry.
- rb_thread_check_ints();
- if (retry) goto start;
-
- return err;
-}
-
-#endif
-
-#if GETADDRINFO_IMPL == 0
-
-int
-rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen, int flags)
-{
- return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
-}
-
-#elif GETADDRINFO_IMPL == 1
-
+#ifndef GETADDRINFO_EMU
struct getnameinfo_arg
{
const struct sockaddr *sa;
@@ -563,11 +324,16 @@ nogvl_getnameinfo(void *arg)
ptr->serv, (socklen_t)ptr->servlen,
ptr->flags);
}
+#endif
+
int
rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen, int flags)
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags)
{
+#ifdef GETADDRINFO_EMU
+ return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+#else
struct getnameinfo_arg arg;
int ret;
arg.sa = sa;
@@ -579,186 +345,9 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
arg.flags = flags;
ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getnameinfo, &arg, RUBY_UBF_IO, 0);
return ret;
-}
-
-#elif GETADDRINFO_IMPL == 2
-
-struct getnameinfo_arg
-{
- struct sockaddr *sa;
- socklen_t salen;
- int flags;
- char *host;
- size_t hostlen;
- char *serv;
- size_t servlen;
- int err, refcount, done, cancelled;
- rb_nativethread_lock_t lock;
- rb_nativethread_cond_t cond;
-};
-
-static struct getnameinfo_arg *
-allocate_getnameinfo_arg(const struct sockaddr *sa, socklen_t salen, size_t hostlen, size_t servlen, int flags)
-{
- size_t sa_offset = sizeof(struct getnameinfo_arg);
- size_t host_offset = sa_offset + salen;
- size_t serv_offset = host_offset + hostlen;
- size_t bufsize = serv_offset + servlen;
-
- char *buf = malloc(bufsize);
- if (!buf) {
- rb_gc();
- buf = malloc(bufsize);
- if (!buf) return NULL;
- }
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)buf;
-
- arg->sa = (struct sockaddr *)(buf + sa_offset);
- memcpy(arg->sa, sa, salen);
- arg->salen = salen;
- arg->host = buf + host_offset;
- arg->hostlen = hostlen;
- arg->serv = buf + serv_offset;
- arg->servlen = servlen;
- arg->flags = flags;
-
- arg->refcount = 2;
- arg->done = arg->cancelled = 0;
-
- rb_nativethread_lock_initialize(&arg->lock);
- rb_native_cond_initialize(&arg->cond);
-
- return arg;
-}
-
-static void
-free_getnameinfo_arg(struct getnameinfo_arg *arg)
-{
- rb_native_cond_destroy(&arg->cond);
- rb_nativethread_lock_destroy(&arg->lock);
-
- free(arg);
-}
-
-static void *
-do_getnameinfo(void *ptr)
-{
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)ptr;
-
- int err;
- err = getnameinfo(arg->sa, arg->salen, arg->host, (socklen_t)arg->hostlen, arg->serv, (socklen_t)arg->servlen, arg->flags);
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- arg->err = err;
- if (!arg->cancelled) {
- arg->done = 1;
- rb_native_cond_signal(&arg->cond);
- }
- if (--arg->refcount == 0) need_free = 1;
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getnameinfo_arg(arg);
-
- return 0;
-}
-
-static void *
-wait_getnameinfo(void *ptr)
-{
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- while (!arg->done && !arg->cancelled) {
- rb_native_cond_wait(&arg->cond, &arg->lock);
- }
- rb_nativethread_lock_unlock(&arg->lock);
- return 0;
-}
-
-static void
-cancel_getnameinfo(void *ptr)
-{
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- arg->cancelled = 1;
- rb_native_cond_signal(&arg->cond);
- rb_nativethread_lock_unlock(&arg->lock);
-}
-
-int
-rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen, int flags)
-{
- int retry;
- struct getnameinfo_arg *arg;
- int err;
-
-start:
- retry = 0;
-
- arg = allocate_getnameinfo_arg(sa, salen, hostlen, servlen, flags);
- if (!arg) {
- return EAI_MEMORY;
- }
-
- pthread_attr_t attr;
- if (pthread_attr_init(&attr) != 0) {
- free_getnameinfo_arg(arg);
- return EAI_AGAIN;
- }
-#if defined(HAVE_PTHREAD_ATTR_SETAFFINITY_NP) && defined(HAVE_SCHED_GETCPU)
- cpu_set_t tmp_cpu_set;
- CPU_ZERO(&tmp_cpu_set);
- int cpu = sched_getcpu();
- if (cpu < CPU_SETSIZE) {
- CPU_SET(cpu, &tmp_cpu_set);
- pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &tmp_cpu_set);
- }
#endif
-
- pthread_t th;
- if (pthread_create(&th, 0, do_getnameinfo, arg) != 0) {
- free_getnameinfo_arg(arg);
- return EAI_AGAIN;
- }
- pthread_detach(th);
-
- rb_thread_call_without_gvl2(wait_getnameinfo, arg, cancel_getnameinfo, arg);
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- if (arg->done) {
- err = arg->err;
- if (err == 0) {
- if (host) memcpy(host, arg->host, hostlen);
- if (serv) memcpy(serv, arg->serv, servlen);
- }
- }
- else if (arg->cancelled) {
- err = EAI_AGAIN;
- }
- else {
- // If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getnameinfo.
- // In this case, it could be !arg->done && !arg->cancelled.
- arg->cancelled = 1;
- retry = 1;
- }
- if (--arg->refcount == 0) need_free = 1;
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getnameinfo_arg(arg);
-
- // If the current thread is interrupted by asynchronous exception, the following raises the exception.
- // But if the current thread is interrupted by timer thread, the following returns; we need to manually retry.
- rb_thread_check_ints();
- if (retry) goto start;
-
- return err;
}
-#endif
-
static void
make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
{
@@ -962,7 +551,17 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
}
if (!resolved) {
- error = rb_getaddrinfo(hostp, portp, hints, &ai);
+#ifdef GETADDRINFO_EMU
+ error = getaddrinfo(hostp, portp, hints, &ai);
+#else
+ struct getaddrinfo_arg arg;
+ MEMZERO(&arg, struct getaddrinfo_arg, 1);
+ arg.node = hostp;
+ arg.service = portp;
+ arg.hints = hints;
+ arg.res = &ai;
+ error = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
+#endif
if (error == 0) {
res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
res->allocated_by_malloc = 0;
@@ -1668,9 +1267,9 @@ rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE r
* RFC 4007: IPv6 Scoped Address Architecture
* draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API
*/
- error = rb_getnameinfo(&sockaddr->addr, socklen,
- hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
- NI_NUMERICHOST|NI_NUMERICSERV);
+ error = getnameinfo(&sockaddr->addr, socklen,
+ hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST|NI_NUMERICSERV);
if (error) {
rsock_raise_socket_error("getnameinfo", error);
}
@@ -2036,9 +1635,9 @@ addrinfo_mdump(VALUE self)
{
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
int error;
- error = rb_getnameinfo(&rai->addr.addr, rai->sockaddr_len,
- hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
- NI_NUMERICHOST|NI_NUMERICSERV);
+ error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
+ hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
+ NI_NUMERICHOST|NI_NUMERICSERV);
if (error) {
rsock_raise_socket_error("getnameinfo", error);
}
@@ -2382,9 +1981,9 @@ addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
if (rai->socktype == SOCK_DGRAM)
flags |= NI_DGRAM;
- error = rb_getnameinfo(&rai->addr.addr, rai->sockaddr_len,
- hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
- flags);
+ error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
+ hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
+ flags);
if (error) {
rsock_raise_socket_error("getnameinfo", error);
}
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 7c5739808d..5f803ba0da 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -459,8 +459,6 @@ VALUE rsock_write_nonblock(VALUE sock, VALUE buf, VALUE ex);
void rsock_make_fd_nonblock(int fd);
-int rsock_is_dgram(rb_io_t *fptr);
-
#if !defined HAVE_INET_NTOP && ! defined _WIN32
const char *inet_ntop(int, const void *, char *, size_t);
#elif defined __MINGW32__
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 74cb0644e6..eb74f7a936 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -1654,7 +1654,8 @@ socket_s_ip_address_list(VALUE self)
finish:
save_errno = errno;
- xfree(lc.lifc_req);
+ if (lc.lifc_buf != NULL)
+ xfree(lc.lifc_req);
if (fd != -1)
close(fd);
errno = save_errno;
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index a8475e3e60..26ab76fc9f 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -540,7 +540,7 @@ unix_peeraddr(VALUE sock)
*
* Creates a pair of sockets connected to each other.
*
- * _type_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
+ * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
*
* _protocol_ should be a protocol defined in the domain.
* 0 is default protocol for the domain.
diff --git a/ext/stringio/depend b/ext/stringio/depend
index ba2b812041..828fc6e842 100644
--- a/ext/stringio/depend
+++ b/ext/stringio/depend
@@ -53,7 +53,6 @@ stringio.o: $(hdrdir)/ruby/internal/attr/noexcept.h
stringio.o: $(hdrdir)/ruby/internal/attr/noinline.h
stringio.o: $(hdrdir)/ruby/internal/attr/nonnull.h
stringio.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-stringio.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
stringio.o: $(hdrdir)/ruby/internal/attr/pure.h
stringio.o: $(hdrdir)/ruby/internal/attr/restrict.h
stringio.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ stringio.o: $(hdrdir)/ruby/internal/intern/enumerator.h
stringio.o: $(hdrdir)/ruby/internal/intern/error.h
stringio.o: $(hdrdir)/ruby/internal/intern/eval.h
stringio.o: $(hdrdir)/ruby/internal/intern/file.h
+stringio.o: $(hdrdir)/ruby/internal/intern/gc.h
stringio.o: $(hdrdir)/ruby/internal/intern/hash.h
stringio.o: $(hdrdir)/ruby/internal/intern/io.h
stringio.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ stringio.o: $(hdrdir)/ruby/internal/memory.h
stringio.o: $(hdrdir)/ruby/internal/method.h
stringio.o: $(hdrdir)/ruby/internal/module.h
stringio.o: $(hdrdir)/ruby/internal/newobj.h
+stringio.o: $(hdrdir)/ruby/internal/rgengc.h
stringio.o: $(hdrdir)/ruby/internal/scan_args.h
stringio.o: $(hdrdir)/ruby/internal/special_consts.h
stringio.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/stringio/extconf.rb b/ext/stringio/extconf.rb
index ad8650dce2..a933159766 100644
--- a/ext/stringio/extconf.rb
+++ b/ext/stringio/extconf.rb
@@ -1,3 +1,4 @@
# frozen_string_literal: false
require 'mkmf'
+have_func("rb_io_extract_modeenc", "ruby/io.h")
create_makefile('stringio')
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index 7eade5bcba..0054766dac 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -12,8 +12,7 @@
**********************************************************************/
-static const char *const
-STRINGIO_VERSION = "3.1.0";
+#define STRINGIO_VERSION "3.0.4"
#include "ruby.h"
#include "ruby/io.h"
@@ -33,6 +32,86 @@ STRINGIO_VERSION = "3.1.0";
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
#endif
+#ifndef HAVE_RB_IO_EXTRACT_MODEENC
+#define rb_io_extract_modeenc strio_extract_modeenc
+static void
+strio_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
+ int *oflags_p, int *fmode_p, struct rb_io_enc_t *convconfig_p)
+{
+ VALUE mode = *vmode_p;
+ VALUE intmode;
+ int fmode;
+ int has_enc = 0, has_vmode = 0;
+
+ convconfig_p->enc = convconfig_p->enc2 = 0;
+
+ vmode_handle:
+ if (NIL_P(mode)) {
+ fmode = FMODE_READABLE;
+ }
+ else if (!NIL_P(intmode = rb_check_to_integer(mode, "to_int"))) {
+ int flags = NUM2INT(intmode);
+ fmode = rb_io_oflags_fmode(flags);
+ }
+ else {
+ const char *m = StringValueCStr(mode), *n, *e;
+ fmode = rb_io_modestr_fmode(m);
+ n = strchr(m, ':');
+ if (n) {
+ long len;
+ char encname[ENCODING_MAXNAMELEN+1];
+ has_enc = 1;
+ if (fmode & FMODE_SETENC_BY_BOM) {
+ n = strchr(n, '|');
+ }
+ e = strchr(++n, ':');
+ len = e ? e - n : (long)strlen(n);
+ if (len > 0 && len <= ENCODING_MAXNAMELEN) {
+ rb_encoding *enc;
+ if (e) {
+ memcpy(encname, n, len);
+ encname[len] = '\0';
+ n = encname;
+ }
+ enc = rb_enc_find(n);
+ if (e)
+ convconfig_p->enc2 = enc;
+ else
+ convconfig_p->enc = enc;
+ }
+ if (e && (len = strlen(++e)) > 0 && len <= ENCODING_MAXNAMELEN) {
+ convconfig_p->enc = rb_enc_find(e);
+ }
+ }
+ }
+
+ if (!NIL_P(opthash)) {
+ rb_encoding *extenc = 0, *intenc = 0;
+ VALUE v;
+ if (!has_vmode) {
+ ID id_mode;
+ CONST_ID(id_mode, "mode");
+ v = rb_hash_aref(opthash, ID2SYM(id_mode));
+ if (!NIL_P(v)) {
+ if (!NIL_P(mode)) {
+ rb_raise(rb_eArgError, "mode specified twice");
+ }
+ has_vmode = 1;
+ mode = v;
+ goto vmode_handle;
+ }
+ }
+
+ if (rb_io_extract_encoding_option(opthash, &extenc, &intenc, &fmode)) {
+ if (has_enc) {
+ rb_raise(rb_eArgError, "encoding specified twice");
+ }
+ }
+ }
+ *fmode_p = fmode;
+}
+#endif
+
struct StringIO {
VALUE string;
rb_encoding *enc;
@@ -92,7 +171,7 @@ static const rb_data_type_t strio_data_type = {
strio_free,
strio_memsize,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#define check_strio(self) ((struct StringIO*)rb_check_typeddata((self), &strio_data_type))
@@ -277,7 +356,7 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
{
VALUE string, vmode, opt;
int oflags;
- rb_io_enc_t convconfig;
+ struct rb_io_enc_t convconfig;
argc = rb_scan_args(argc, argv, "02:", &string, &vmode, &opt);
rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &ptr->flags, &convconfig);
@@ -300,7 +379,7 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
if (ptr->flags & FMODE_TRUNC) {
rb_str_resize(string, 0);
}
- RB_OBJ_WRITE(self, &ptr->string, string);
+ ptr->string = string;
if (argc == 1) {
ptr->enc = rb_enc_get(string);
}
@@ -318,7 +397,7 @@ static VALUE
strio_finalize(VALUE self)
{
struct StringIO *ptr = StringIO(self);
- RB_OBJ_WRITE(self, &ptr->string, Qnil);
+ ptr->string = Qnil;
ptr->flags &= ~FMODE_READWRITE;
return self;
}
@@ -484,8 +563,7 @@ strio_set_string(VALUE self, VALUE string)
ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
ptr->pos = 0;
ptr->lineno = 0;
- RB_OBJ_WRITE(self, &ptr->string, string);
- return string;
+ return ptr->string = string;
}
/*
@@ -604,9 +682,11 @@ strio_to_read(VALUE self)
* eof? -> true or false
*
* Returns +true+ if positioned at end-of-stream, +false+ otherwise;
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:File@Position].
*
* Raises IOError if the stream is not opened for reading.
+ *
+ * StreamIO#eof is an alias for StreamIO#eof?.
*/
static VALUE
strio_eof(VALUE self)
@@ -619,19 +699,15 @@ strio_eof(VALUE self)
static VALUE
strio_copy(VALUE copy, VALUE orig)
{
- struct StringIO *ptr, *old_ptr;
- VALUE old_string = Qundef;
+ struct StringIO *ptr;
orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
if (copy == orig) return copy;
ptr = StringIO(orig);
- old_ptr = check_strio(copy);
- if (old_ptr) {
- old_string = old_ptr->string;
- strio_free(old_ptr);
+ if (check_strio(copy)) {
+ strio_free(DATA_PTR(copy));
}
DATA_PTR(copy) = ptr;
- RB_OBJ_WRITTEN(copy, old_string, ptr->string);
RBASIC(copy)->flags &= ~STRIO_READWRITE;
RBASIC(copy)->flags |= RBASIC(orig)->flags & STRIO_READWRITE;
++ptr->count;
@@ -732,6 +808,8 @@ strio_reopen(int argc, VALUE *argv, VALUE self)
*
* Returns the current position (in bytes);
* see {Position}[rdoc-ref:IO@Position].
+ *
+ * StringIO#tell is an alias for StringIO#pos.
*/
static VALUE
strio_get_pos(VALUE self)
@@ -1143,57 +1221,38 @@ struct getline_arg {
};
static struct getline_arg *
-prepare_getline_args(struct StringIO *ptr, struct getline_arg *arg, int argc, VALUE *argv)
+prepare_getline_args(struct getline_arg *arg, int argc, VALUE *argv)
{
- VALUE rs, lim, opts;
+ VALUE str, lim, opts;
long limit = -1;
int respect_chomp;
- argc = rb_scan_args(argc, argv, "02:", &rs, &lim, &opts);
- respect_chomp = argc == 0 || !NIL_P(rs);
+ argc = rb_scan_args(argc, argv, "02:", &str, &lim, &opts);
+ respect_chomp = argc == 0 || !NIL_P(str);
switch (argc) {
case 0:
- rs = rb_rs;
+ str = rb_rs;
break;
case 1:
- if (!NIL_P(rs) && !RB_TYPE_P(rs, T_STRING)) {
- VALUE tmp = rb_check_string_type(rs);
+ if (!NIL_P(str) && !RB_TYPE_P(str, T_STRING)) {
+ VALUE tmp = rb_check_string_type(str);
if (NIL_P(tmp)) {
- limit = NUM2LONG(rs);
- rs = rb_rs;
+ limit = NUM2LONG(str);
+ str = rb_rs;
}
else {
- rs = tmp;
+ str = tmp;
}
}
break;
case 2:
- if (!NIL_P(rs)) StringValue(rs);
+ if (!NIL_P(str)) StringValue(str);
if (!NIL_P(lim)) limit = NUM2LONG(lim);
break;
}
- if (!NIL_P(rs)) {
- rb_encoding *enc_rs, *enc_io;
- enc_rs = rb_enc_get(rs);
- enc_io = get_enc(ptr);
- if (enc_rs != enc_io &&
- (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
- (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
- if (rs == rb_rs) {
- rs = rb_enc_str_new(0, 0, enc_io);
- rb_str_buf_cat_ascii(rs, "\n");
- rs = rs;
- }
- else {
- rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
- rb_enc_name(enc_io),
- rb_enc_name(enc_rs));
- }
- }
- }
- arg->rs = rs;
+ arg->rs = str;
arg->limit = limit;
arg->chomp = 0;
if (!NIL_P(opts)) {
@@ -1321,15 +1380,15 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
static VALUE
strio_gets(int argc, VALUE *argv, VALUE self)
{
- struct StringIO *ptr = readable(self);
struct getline_arg arg;
VALUE str;
- if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
+ if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
+ struct StringIO *ptr = readable(self);
return rb_enc_str_new(0, 0, get_enc(ptr));
}
- str = strio_getline(&arg, ptr);
+ str = strio_getline(&arg, readable(self));
rb_lastline_set(str);
return str;
}
@@ -1361,21 +1420,23 @@ strio_readline(int argc, VALUE *argv, VALUE self)
* does nothing if already at end-of-file;
* returns +self+.
* See {Line IO}[rdoc-ref:IO@Line+IO].
+ *
+ * StringIO#each is an alias for StringIO#each_line.
*/
static VALUE
strio_each(int argc, VALUE *argv, VALUE self)
{
VALUE line;
- struct StringIO *ptr = readable(self);
struct getline_arg arg;
+ StringIO(self);
RETURN_ENUMERATOR(self, argc, argv);
- if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
+ if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
}
- while (!NIL_P(line = strio_getline(&arg, ptr))) {
+ while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
rb_yield(line);
}
return self;
@@ -1393,15 +1454,15 @@ static VALUE
strio_readlines(int argc, VALUE *argv, VALUE self)
{
VALUE ary, line;
- struct StringIO *ptr = readable(self);
struct getline_arg arg;
- if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
+ StringIO(self);
+ ary = rb_ary_new();
+ if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
}
- ary = rb_ary_new();
- while (!NIL_P(line = strio_getline(&arg, ptr))) {
+ while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
rb_ary_push(ary, line);
}
return ary;
@@ -1604,55 +1665,6 @@ strio_read(int argc, VALUE *argv, VALUE self)
}
/*
- * call-seq:
- * pread(maxlen, offset) -> string
- * pread(maxlen, offset, out_string) -> string
- *
- * See IO#pread.
- */
-static VALUE
-strio_pread(int argc, VALUE *argv, VALUE self)
-{
- VALUE rb_len, rb_offset, rb_buf;
- rb_scan_args(argc, argv, "21", &rb_len, &rb_offset, &rb_buf);
- long len = NUM2LONG(rb_len);
- long offset = NUM2LONG(rb_offset);
-
- if (len < 0) {
- rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
- }
-
- if (len == 0) {
- if (NIL_P(rb_buf)) {
- return rb_str_new("", 0);
- }
- return rb_buf;
- }
-
- if (offset < 0) {
- rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
- }
-
- struct StringIO *ptr = readable(self);
-
- if (offset >= RSTRING_LEN(ptr->string)) {
- rb_eof_error();
- }
-
- if (NIL_P(rb_buf)) {
- return strio_substr(ptr, offset, len, rb_ascii8bit_encoding());
- }
-
- long rest = RSTRING_LEN(ptr->string) - offset;
- if (len > rest) len = rest;
- rb_str_resize(rb_buf, len);
- rb_enc_associate(rb_buf, rb_ascii8bit_encoding());
- MEMCPY(RSTRING_PTR(rb_buf), RSTRING_PTR(ptr->string) + offset, char, len);
- return rb_buf;
-}
-
-
-/*
* call-seq:
* strio.sysread(integer[, outbuf]) -> string
* strio.readpartial(integer[, outbuf]) -> string
@@ -1812,7 +1824,7 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
else {
enc = rb_find_encoding(ext_enc);
if (!enc) {
- rb_io_enc_t convconfig;
+ struct rb_io_enc_t convconfig;
int oflags, fmode;
VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);
@@ -1912,7 +1924,6 @@ Init_stringio(void)
rb_define_method(StringIO, "gets", strio_gets, -1);
rb_define_method(StringIO, "readlines", strio_readlines, -1);
rb_define_method(StringIO, "read", strio_read, -1);
- rb_define_method(StringIO, "pread", strio_pread, -1);
rb_define_method(StringIO, "write", strio_write_m, -1);
rb_define_method(StringIO, "putc", strio_putc, 1);
diff --git a/ext/stringio/stringio.gemspec b/ext/stringio/stringio.gemspec
index 8c950f8ff9..1015d261f5 100644
--- a/ext/stringio/stringio.gemspec
+++ b/ext/stringio/stringio.gemspec
@@ -4,7 +4,7 @@
source_version = ["", "ext/stringio/"].find do |dir|
begin
break File.open(File.join(__dir__, "#{dir}stringio.c")) {|f|
- f.gets("\nSTRINGIO_VERSION ")
+ f.gets("\n#define STRINGIO_VERSION ")
f.gets[/\s*"(.+)"/, 1]
}
rescue Errno::ENOENT
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
s.name = "stringio"
s.version = source_version
+ s.required_rubygems_version = Gem::Requirement.new(">= 2.6")
s.require_paths = ["lib"]
s.authors = ["Nobu Nakada", "Charles Oliver Nutter"]
s.description = "Pseudo `IO` class from/to `String`."
@@ -21,8 +22,7 @@ Gem::Specification.new do |s|
s.files = ["README.md"]
jruby = true if Gem::Platform.new('java') =~ s.platform or RUBY_ENGINE == 'jruby'
if jruby
- s.require_paths = "lib/java"
- s.files += ["lib/java/stringio.rb", "lib/java/stringio.jar"]
+ s.files += ["lib/stringio.rb", "lib/stringio.jar"]
s.platform = "java"
else
s.extensions = ["ext/stringio/extconf.rb"]
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
end
s.homepage = "https://github.com/ruby/stringio"
s.licenses = ["Ruby", "BSD-2-Clause"]
- s.required_ruby_version = ">= 2.7"
+ s.required_ruby_version = ">= 2.5"
s.summary = "Pseudo IO on String"
# s.cert_chain = %w[certs/nobu.pem]
diff --git a/ext/strscan/depend b/ext/strscan/depend
index 8d985b59e8..8fe3cb23d9 100644
--- a/ext/strscan/depend
+++ b/ext/strscan/depend
@@ -52,7 +52,6 @@ strscan.o: $(hdrdir)/ruby/internal/attr/noexcept.h
strscan.o: $(hdrdir)/ruby/internal/attr/noinline.h
strscan.o: $(hdrdir)/ruby/internal/attr/nonnull.h
strscan.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-strscan.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
strscan.o: $(hdrdir)/ruby/internal/attr/pure.h
strscan.o: $(hdrdir)/ruby/internal/attr/restrict.h
strscan.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ strscan.o: $(hdrdir)/ruby/internal/intern/enumerator.h
strscan.o: $(hdrdir)/ruby/internal/intern/error.h
strscan.o: $(hdrdir)/ruby/internal/intern/eval.h
strscan.o: $(hdrdir)/ruby/internal/intern/file.h
+strscan.o: $(hdrdir)/ruby/internal/intern/gc.h
strscan.o: $(hdrdir)/ruby/internal/intern/hash.h
strscan.o: $(hdrdir)/ruby/internal/intern/io.h
strscan.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ strscan.o: $(hdrdir)/ruby/internal/memory.h
strscan.o: $(hdrdir)/ruby/internal/method.h
strscan.o: $(hdrdir)/ruby/internal/module.h
strscan.o: $(hdrdir)/ruby/internal/newobj.h
+strscan.o: $(hdrdir)/ruby/internal/rgengc.h
strscan.o: $(hdrdir)/ruby/internal/scan_args.h
strscan.o: $(hdrdir)/ruby/internal/special_consts.h
strscan.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/strscan/extconf.rb b/ext/strscan/extconf.rb
index bd65606a4e..3c311d2364 100644
--- a/ext/strscan/extconf.rb
+++ b/ext/strscan/extconf.rb
@@ -2,8 +2,8 @@
require 'mkmf'
if RUBY_ENGINE == 'ruby'
$INCFLAGS << " -I$(top_srcdir)" if $extmk
- have_func("onig_region_memsize", "ruby.h")
- have_func("rb_reg_onig_match", "ruby.h")
+ have_func("onig_region_memsize(NULL)")
+ have_func("rb_reg_onig_match", "ruby/re.h")
create_makefile 'strscan'
else
File.write('Makefile', dummy_makefile("").join)
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index a2bf56ce4f..16d669d8a5 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -22,7 +22,7 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
#include <stdbool.h>
-#define STRSCAN_VERSION "3.0.8"
+#define STRSCAN_VERSION "3.0.7"
/* =======================================================================
Data Type Definitions
diff --git a/ext/syslog/depend b/ext/syslog/depend
index ee4ac5f47d..4eea8c3bf9 100644
--- a/ext/syslog/depend
+++ b/ext/syslog/depend
@@ -51,7 +51,6 @@ syslog.o: $(hdrdir)/ruby/internal/attr/noexcept.h
syslog.o: $(hdrdir)/ruby/internal/attr/noinline.h
syslog.o: $(hdrdir)/ruby/internal/attr/nonnull.h
syslog.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-syslog.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
syslog.o: $(hdrdir)/ruby/internal/attr/pure.h
syslog.o: $(hdrdir)/ruby/internal/attr/restrict.h
syslog.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ syslog.o: $(hdrdir)/ruby/internal/intern/enumerator.h
syslog.o: $(hdrdir)/ruby/internal/intern/error.h
syslog.o: $(hdrdir)/ruby/internal/intern/eval.h
syslog.o: $(hdrdir)/ruby/internal/intern/file.h
+syslog.o: $(hdrdir)/ruby/internal/intern/gc.h
syslog.o: $(hdrdir)/ruby/internal/intern/hash.h
syslog.o: $(hdrdir)/ruby/internal/intern/io.h
syslog.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,6 +141,7 @@ syslog.o: $(hdrdir)/ruby/internal/memory.h
syslog.o: $(hdrdir)/ruby/internal/method.h
syslog.o: $(hdrdir)/ruby/internal/module.h
syslog.o: $(hdrdir)/ruby/internal/newobj.h
+syslog.o: $(hdrdir)/ruby/internal/rgengc.h
syslog.o: $(hdrdir)/ruby/internal/scan_args.h
syslog.o: $(hdrdir)/ruby/internal/special_consts.h
syslog.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/syslog/syslog.c b/ext/syslog/syslog.c
index 6a97c15811..8f3674aa8d 100644
--- a/ext/syslog/syslog.c
+++ b/ext/syslog/syslog.c
@@ -12,8 +12,6 @@
#include "ruby/util.h"
#include <syslog.h>
-#define SYSLOG_VERSION "0.1.1"
-
/* Syslog class */
static VALUE mSyslog;
/*
@@ -576,8 +574,6 @@ void Init_syslog(void)
/* Syslog macros */
- rb_define_const(mSyslog, "VERSION", rb_str_new_cstr(SYSLOG_VERSION));
-
rb_define_method(mSyslogMacros, "LOG_MASK", mSyslogMacros_LOG_MASK, 1);
rb_define_method(mSyslogMacros, "LOG_UPTO", mSyslogMacros_LOG_UPTO, 1);
rb_define_singleton_method(mSyslogMacros, "included", mSyslogMacros_included, 1);
diff --git a/ext/syslog/syslog.gemspec b/ext/syslog/syslog.gemspec
index 10a6d1f25c..6aa2e9570d 100644
--- a/ext/syslog/syslog.gemspec
+++ b/ext/syslog/syslog.gemspec
@@ -1,18 +1,13 @@
-source_version = %w[. ext/syslog].find do |dir|
- break $1 if File.foreach(File.join(__dir__, dir, "syslog.c")).any?(/^#define\s+SYSLOG_VERSION\s+"(.+)"/)
-rescue Errno::ENOENT
-end
-
Gem::Specification.new do |spec|
spec.name = "syslog"
- spec.version = source_version
+ spec.version = "0.1.1"
spec.authors = ["Akinori MUSHA"]
spec.email = ["knu@idaemons.org"]
spec.summary = %q{Ruby interface for the POSIX system logging facility.}
spec.description = %q{Ruby interface for the POSIX system logging facility.}
spec.homepage = "https://github.com/ruby/syslog"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.metadata["homepage_uri"] = spec.homepage
diff --git a/ext/win32/lib/win32/registry.rb b/ext/win32/lib/win32/registry.rb
index b5b99ff684..bda8bb012f 100644
--- a/ext/win32/lib/win32/registry.rb
+++ b/ext/win32/lib/win32/registry.rb
@@ -69,7 +69,11 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
WCHAR_NUL = "\0".encode(WCHAR).freeze
WCHAR_CR = "\r".encode(WCHAR).freeze
WCHAR_SIZE = WCHAR_NUL.bytesize
- LOCALE = Encoding.find(Encoding.locale_charmap)
+ begin
+ LOCALE = Encoding.find(Encoding.locale_charmap)
+ rescue ArgumentError
+ LOCALE = Encoding::UTF_8
+ end
class Registry
@@ -740,14 +744,11 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# method returns.
#
def write(name, type, data)
- termsize = 0
case type
when REG_SZ, REG_EXPAND_SZ
- data = data.encode(WCHAR)
- termsize = WCHAR_SIZE
+ data = data.encode(WCHAR) << WCHAR_NUL
when REG_MULTI_SZ
data = data.to_a.map {|s| s.encode(WCHAR)}.join(WCHAR_NUL) << WCHAR_NUL
- termsize = WCHAR_SIZE
when REG_BINARY, REG_NONE
data = data.to_s
when REG_DWORD
@@ -759,7 +760,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
else
raise TypeError, "Unsupported type #{Registry.type2name(type)}"
end
- API.SetValue(@hkey, name, type, data, data.bytesize + termsize)
+ API.SetValue(@hkey, name, type, data, data.bytesize)
end
#
diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c
index a060165a1c..3f083bb12d 100644
--- a/ext/win32ole/win32ole.c
+++ b/ext/win32ole/win32ole.c
@@ -27,7 +27,7 @@
const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}};
#endif
-#define WIN32OLE_VERSION "1.8.10"
+#define WIN32OLE_VERSION "1.8.8"
typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
(REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
diff --git a/ext/win32ole/win32ole.gemspec b/ext/win32ole/win32ole.gemspec
index 9c137a5d70..b6ea8e8a55 100644
--- a/ext/win32ole/win32ole.gemspec
+++ b/ext/win32ole/win32ole.gemspec
@@ -1,16 +1,6 @@
-source_version = ["", "ext/win32ole/"].find do |dir|
- begin
- break File.open(File.join(__dir__, "#{dir}win32ole.c")) {|f|
- f.gets("\n#define WIN32OLE_VERSION ")
- f.gets[/\s*"(.+)"/, 1]
- }
- rescue Errno::ENOENT
- end
-end
-
Gem::Specification.new do |spec|
spec.name = "win32ole"
- spec.version = source_version
+ spec.version = "1.8.9"
spec.authors = ["Masaki Suketa"]
spec.email = ["suke@ruby-lang.org"]
diff --git a/ext/zlib/depend b/ext/zlib/depend
index bdcf6a93e8..15186f8266 100644
--- a/ext/zlib/depend
+++ b/ext/zlib/depend
@@ -53,7 +53,6 @@ zlib.o: $(hdrdir)/ruby/internal/attr/noexcept.h
zlib.o: $(hdrdir)/ruby/internal/attr/noinline.h
zlib.o: $(hdrdir)/ruby/internal/attr/nonnull.h
zlib.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-zlib.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
zlib.o: $(hdrdir)/ruby/internal/attr/pure.h
zlib.o: $(hdrdir)/ruby/internal/attr/restrict.h
zlib.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ zlib.o: $(hdrdir)/ruby/internal/intern/enumerator.h
zlib.o: $(hdrdir)/ruby/internal/intern/error.h
zlib.o: $(hdrdir)/ruby/internal/intern/eval.h
zlib.o: $(hdrdir)/ruby/internal/intern/file.h
+zlib.o: $(hdrdir)/ruby/internal/intern/gc.h
zlib.o: $(hdrdir)/ruby/internal/intern/hash.h
zlib.o: $(hdrdir)/ruby/internal/intern/io.h
zlib.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,6 +152,7 @@ zlib.o: $(hdrdir)/ruby/internal/memory.h
zlib.o: $(hdrdir)/ruby/internal/method.h
zlib.o: $(hdrdir)/ruby/internal/module.h
zlib.o: $(hdrdir)/ruby/internal/newobj.h
+zlib.o: $(hdrdir)/ruby/internal/rgengc.h
zlib.o: $(hdrdir)/ruby/internal/scan_args.h
zlib.o: $(hdrdir)/ruby/internal/special_consts.h
zlib.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/zlib/extconf.rb b/ext/zlib/extconf.rb
index 2b2dbb1a5b..5477f49178 100644
--- a/ext/zlib/extconf.rb
+++ b/ext/zlib/extconf.rb
@@ -11,9 +11,10 @@ require 'rbconfig'
dir_config 'zlib'
libs = $libs
-have_zlib = %w'z libz zlib1 zlib zdll zlibwapi'.any? {|z| have_library(z, 'deflateReset(NULL)', 'zlib.h')}
-
-unless have_zlib
+if %w'z libz zlib1 zlib zdll zlibwapi'.find {|z| have_library(z, 'deflateReset')} and
+ have_header('zlib.h') then
+ have_zlib = true
+else
$libs = libs
unless File.directory?(zsrc = "#{$srcdir}/zlib")
dirs = Dir.open($srcdir) {|z| z.grep(/\Azlib-\d+[.\d]*\z/) {|x|"#{$srcdir}/#{x}"}}
@@ -120,18 +121,12 @@ if have_zlib
$defs << "-DHAVE_CRC32_COMBINE"
$defs << "-DHAVE_ADLER32_COMBINE"
$defs << "-DHAVE_TYPE_Z_CRC_T"
- $defs << "-DHAVE_CRC32_Z"
- $defs << "-DHAVE_ADLER32_Z"
- $defs << "-DHAVE_ZLIB_SIZE_T_FUNCS"
+ $defs << "-DHAVE_TYPE_Z_SIZE_T"
else
have_func('crc32_combine', 'zlib.h')
have_func('adler32_combine', 'zlib.h')
have_type('z_crc_t', 'zlib.h')
- if (have_type('z_size_t', 'zlib.h') &&
- have_func('crc32_z', 'zlib.h') &&
- have_func('adler32_z', 'zlib.h'))
- $defs << "-DHAVE_ZLIB_SIZE_T_FUNCS"
- end
+ have_type('z_size_t', 'zlib.h')
end
create_makefile('zlib') {|conf|
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index dc608ee460..aefdba0ebd 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -25,7 +25,7 @@
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
#endif
-#define RUBY_ZLIB_VERSION "3.1.0"
+#define RUBY_ZLIB_VERSION "3.0.0"
#ifndef RB_PASS_CALLED_KEYWORDS
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
@@ -44,7 +44,7 @@
#endif
#endif
-#if defined(HAVE_ZLIB_SIZE_T_FUNCS)
+#if defined(HAVE_TYPE_Z_SIZE_T)
typedef uLong (*checksum_func)(uLong, const Bytef*, z_size_t);
# define crc32 crc32_z
# define adler32 adler32_z
@@ -388,7 +388,7 @@ rb_zlib_version(VALUE klass)
# define mask32(x) (x)
#endif
-#if SIZEOF_LONG > SIZEOF_INT && !defined(HAVE_ZLIB_SIZE_T_FUNCS)
+#if SIZEOF_LONG > SIZEOF_INT && !defined(HAVE_TYPE_Z_SIZE_T)
static uLong
checksum_long(uLong (*func)(uLong, const Bytef*, uInt), uLong sum, const Bytef *ptr, long len)
{
@@ -923,7 +923,7 @@ zstream_discard_input(struct zstream *z, long len)
z->input = Qnil;
}
else {
- z->input = rb_str_subseq(z->input, len,
+ z->input = rb_str_substr(z->input, len,
RSTRING_LEN(z->input) - len);
}
}
diff --git a/ext/zlib/zlib.gemspec b/ext/zlib/zlib.gemspec
index bb67ea156c..4a5f8f2ee8 100644
--- a/ext/zlib/zlib.gemspec
+++ b/ext/zlib/zlib.gemspec
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
spec.executables = []
spec.require_paths = ["lib"]
spec.extensions = "ext/zlib/extconf.rb"
- spec.required_ruby_version = ">= 2.5.0"
+ spec.required_ruby_version = ">= 2.3.0"
end
diff --git a/file.c b/file.c
index 1b52621928..3a8439ef07 100644
--- a/file.c
+++ b/file.c
@@ -129,7 +129,7 @@ int flock(int, int);
# endif
#else
# define STAT(p, s) stat((p), (s))
-#endif /* _WIN32 */
+#endif
#if defined _WIN32 || defined __APPLE__
# define USE_OSPATH 1
@@ -169,6 +169,7 @@ int flock(int, int);
#include "internal/thread.h"
#include "internal/vm.h"
#include "ruby/encoding.h"
+#include "ruby/io.h"
#include "ruby/thread.h"
#include "ruby/util.h"
@@ -263,7 +264,7 @@ rb_str_encode_ospath(VALUE path)
rb_encoding *utf8 = rb_utf8_encoding();
path = rb_str_conv_enc(path, enc, utf8);
}
-#endif /* USE_OSPATH */
+#endif
return path;
}
@@ -307,7 +308,7 @@ rb_CFString_class_initialize_before_fork(void)
CFRelease(m);
CFRelease(s);
}
-# endif /* HAVE_WORKING_FORK */
+# endif
static VALUE
rb_str_append_normalized_ospath(VALUE str, const char *ptr, long len)
@@ -408,9 +409,9 @@ ignored_char_p(const char *p, const char *e, rb_encoding *enc)
}
return 0;
}
-#else /* !__APPLE__ */
+#else
# define NORMALIZE_UTF8PATH 0
-#endif /* __APPLE__ */
+#endif
#define apply2args(n) (rb_check_arity(argc, n, UNLIMITED_ARGUMENTS), argc-=n)
@@ -492,7 +493,7 @@ stat_memsize(const void *p)
static const rb_data_type_t stat_data_type = {
"stat",
{NULL, RUBY_TYPED_DEFAULT_FREE, stat_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
@@ -963,7 +964,7 @@ typedef struct stat statx_data;
# define stat_birthtime stat_ctime
#else
# undef HAVE_STAT_BIRTHTIME
-#endif /* defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) */
+#endif
/*
* call-seq:
@@ -1188,8 +1189,8 @@ statx(int dirfd, const char *pathname, int flags,
{
return (int)syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf);
}
-# endif /* __linux__ */
-# endif /* HAVE_STATX */
+# endif
+# endif
typedef struct no_gvl_statx_data {
struct statx *stx;
@@ -1288,8 +1289,7 @@ typedef struct statx statx_data;
# define rb_statx(file, st, mask) rb_stat(file, st)
#else
# define statx_has_birthtime(st) 0
-#endif /* !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) && \
- defined(HAVE_STRUCT_STATX_STX_BTIME) */
+#endif
static int
rb_stat(VALUE file, struct stat *st)
@@ -1478,7 +1478,7 @@ rb_group_member(GETGROUPS_T gid)
ALLOCV_END(v);
return rv;
-#endif /* defined(_WIN32) || !defined(HAVE_GETGROUPS) */
+#endif
}
#ifndef S_IXUGO
@@ -1529,9 +1529,9 @@ eaccess(const char *path, int mode)
return -1;
#else
return access(path, mode);
-#endif /* USE_GETEUID */
+#endif
}
-#endif /* HAVE_EACCESS */
+#endif
struct access_arg {
const char *path;
@@ -1773,7 +1773,7 @@ rb_file_blockdev_p(VALUE obj, VALUE fname)
*
* Returns +true+ if +filepath+ points to a character device, +false+ otherwise.
*
- * File.chardev?($stdin) # => true
+ * File.chardev?($stdin) # => true
* File.chardev?('t.txt') # => false
*
*/
@@ -2836,7 +2836,7 @@ utime_failed(struct apply_arg *aa)
}
rb_syserr_fail_path(e, path);
}
-#endif /* UTIME_EINVAL */
+#endif
#if defined(HAVE_UTIMES)
@@ -2860,8 +2860,8 @@ RBIMPL_WARNING_POP()
# define utimensat rb_utimensat()
# else /* __API_AVAILABLE macro does nothing on gcc */
__attribute__((weak)) int utimensat(int, const char *, const struct timespec [2], int);
-# endif /* defined(__has_attribute) && __has_attribute(availability) */
-# endif /* __APPLE__ && < MAC_OS_X_VERSION_13_0 */
+# endif
+# endif
static int
utime_internal(const char *path, void *arg)
@@ -2874,15 +2874,15 @@ utime_internal(const char *path, void *arg)
# if defined(__APPLE__)
const int try_utimensat = utimensat != NULL;
const int try_utimensat_follow = utimensat != NULL;
-# else /* !__APPLE__ */
+# else
# define TRY_UTIMENSAT 1
static int try_utimensat = 1;
-# ifdef AT_SYMLINK_NOFOLLOW
+# ifdef AT_SYMLINK_NOFOLLOW
static int try_utimensat_follow = 1;
-# else
+# else
const int try_utimensat_follow = 0;
-# endif
-# endif /* __APPLE__ */
+# endif
+# endif
int flags = 0;
if (v->follow ? try_utimensat_follow : try_utimensat) {
@@ -2897,15 +2897,15 @@ utime_internal(const char *path, void *arg)
if (result < 0 && errno == ENOSYS) {
# ifdef AT_SYMLINK_NOFOLLOW
try_utimensat_follow = 0;
-# endif /* AT_SYMLINK_NOFOLLOW */
+# endif
if (!v->follow)
try_utimensat = 0;
}
else
-# endif /* TRY_UTIMESAT */
+# endif
return result;
}
-#endif /* defined(HAVE_UTIMENSAT) */
+#endif
if (tsp) {
tvbuf[0].tv_sec = tsp[0].tv_sec;
@@ -2920,7 +2920,7 @@ utime_internal(const char *path, void *arg)
return utimes(path, tvp);
}
-#else /* !defined(HAVE_UTIMES) */
+#else
#if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H
struct utimbuf {
@@ -2942,7 +2942,8 @@ utime_internal(const char *path, void *arg)
}
return utime(path, utp);
}
-#endif /* !defined(HAVE_UTIMES) */
+
+#endif
static VALUE
utime_internal_i(int argc, VALUE *argv, int follow)
@@ -3313,13 +3314,12 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
#endif
#ifndef USE_NTFS
-# if defined _WIN32
-# define USE_NTFS 1
-# else
-# define USE_NTFS 0
-# endif
+#if defined _WIN32
+#define USE_NTFS 1
+#else
+#define USE_NTFS 0
+#endif
#endif
-
#ifndef USE_NTFS_ADS
# if USE_NTFS
# define USE_NTFS_ADS 1
@@ -3333,7 +3333,6 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
#else
#define istrailinggarbage(x) 0
#endif
-
#if USE_NTFS_ADS
# define isADS(x) ((x) == ':')
#else
@@ -3401,8 +3400,8 @@ not_same_drive(VALUE path, int drive)
return has_unc(p);
}
}
-#endif /* _WIN32 */
-#endif /* DOSISH_DRIVE_LETTER */
+#endif
+#endif
static inline char *
skiproot(const char *path, const char *end, rb_encoding *enc)
@@ -3446,7 +3445,7 @@ rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
if (has_drive_letter(path))
return (char *)(path + 2);
#endif
-#endif /* defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) */
+#endif
return (char *)path;
}
@@ -3541,7 +3540,7 @@ ntfs_tail(const char *path, const char *end, rb_encoding *enc)
}
return (char *)path;
}
-#endif /* USE_NTFS */
+#endif
#define BUFCHECK(cond) do {\
bdiff = p - buf;\
@@ -3646,7 +3645,7 @@ rb_home_dir_of(VALUE user, VALUE result)
return result;
}
-#ifndef _WIN32 /* this encompasses rb_file_expand_path_internal */
+#ifndef _WIN32
VALUE
rb_default_home_dir(VALUE result)
{
@@ -3676,7 +3675,7 @@ rb_default_home_dir(VALUE result)
if (NIL_P(login_name)) {
rb_raise(rb_eArgError, "couldn't find login name -- expanding `~'");
}
-# endif /* !defined(HAVE_GETPWUID_R) && !defined(HAVE_GETPWUID) */
+# endif
VALUE pw_dir = rb_getpwdirnam_for_login(login_name);
if (NIL_P(pw_dir)) {
@@ -3691,7 +3690,7 @@ rb_default_home_dir(VALUE result)
rb_str_resize(pw_dir, 0);
return result;
}
-#endif /* defined HAVE_PWD_H */
+#endif
if (!dir) {
rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
}
@@ -3821,7 +3820,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
s += 2;
}
}
-#endif /* DOSISH_DRIVE_LETTER */
+#endif
else if (!rb_is_absolute_path(s)) {
if (!NIL_P(dname)) {
rb_file_expand_path_internal(dname, Qnil, abs_mode, long_name, result);
@@ -3841,7 +3840,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
p = skipprefix(buf, p, enc);
}
else
-#endif /* defined DOSISH || defined __CYGWIN__ */
+#endif
p = chompdirsep(skiproot(buf, p, enc), p, enc);
}
else {
@@ -3894,7 +3893,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
else {
do ++s; while (istrailinggarbage(*s));
}
-#endif /* USE_NTFS */
+#endif
break;
case '/':
#if defined DOSISH || defined __CYGWIN__
@@ -3919,7 +3918,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
}
}
-#endif /* USE_NTFS */
+#endif
break;
case '/':
#if defined DOSISH || defined __CYGWIN__
@@ -3944,7 +3943,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
break;
}
}
-#endif /* __APPLE__ */
+#endif
Inc(s, fend, enc);
break;
}
@@ -3968,8 +3967,8 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
s -= prime_len; /* alternative */
}
}
-# endif /* USE_NTFS_ADS */
-#endif /* USE_NTFS */
+# endif
+#endif
BUFCOPY(b, s-b);
rb_str_set_len(result, p-buf);
}
@@ -3990,7 +3989,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
const int flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
#else
char w32buf[MAXPATHLEN];
-#endif /* HAVE_CYGWIN_CONV_PATH */
+#endif
const char *path;
ssize_t bufsize;
int lnk_added = 0, is_symlink = 0;
@@ -4014,12 +4013,12 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
b = w32buf;
}
}
-#else /* !HAVE_CYGWIN_CONV_PATH */
+#else
bufsize = MAXPATHLEN;
if (cygwin_conv_to_win32_path(path, w32buf) == 0) {
b = w32buf;
}
-#endif /* !HAVE_CYGWIN_CONV_PATH */
+#endif
if (is_symlink && b == w32buf) {
*p = '\\';
strlcat(w32buf, p, bufsize);
@@ -4031,7 +4030,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
lnk_added = 0;
}
*p = '/';
-#endif /* __CYGWIN__ */
+#endif
rb_str_set_len(result, p - buf + strlen(p));
encidx = ENCODING_GET(result);
tmp = result;
@@ -4079,14 +4078,14 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
#endif
}
-#endif /* USE_NTFS */
+#endif
rb_str_set_len(result, p - buf);
rb_enc_check(fname, result);
ENC_CODERANGE_CLEAR(result);
return result;
}
-#endif /* !_WIN32 (this ifdef started above rb_default_home_dir) */
+#endif /* _WIN32 */
#define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, 1)
@@ -4326,7 +4325,7 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE f
rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
}
else
-#endif /* HAVE_READLINK */
+#endif
{
VALUE s = rb_str_dup_frozen(testpath);
rb_hash_aset(loopcheck, s, s);
@@ -4495,7 +4494,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
}
rb_sys_fail_path(unresolved_path);
}
-# endif /* !defined(__LINUX__) && !defined(__APPLE__) */
+# endif
if (origenc && origenc != rb_enc_get(resolved)) {
if (!rb_enc_str_asciionly_p(resolved)) {
@@ -4513,7 +4512,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
RB_GC_GUARD(unresolved_path);
return resolved;
-#else /* !HAVE_REALPATH */
+#else
if (mode == RB_REALPATH_CHECK) {
VALUE arg[3];
arg[0] = basedir;
@@ -4610,7 +4609,7 @@ rmext(const char *p, long l0, long l1, const char *e, long l2, rb_encoding *enc)
if (l1 < l2) return l1;
s = p+l1-l2;
- if (!at_char_boundary(p, s, p+l1, enc)) return 0;
+ if (rb_enc_left_char_head(p, s, p+l1, enc) != s) return 0;
#if CASEFOLD_FILESYSTEM
#define fncomp strncasecmp
#else
@@ -4650,13 +4649,13 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
p++;
f = 0;
}
-#endif /* DOSISH_DRIVE_LETTER */
+#endif
#ifdef DOSISH_UNC
else {
p = "/";
}
-#endif /* DOSISH_UNC */
-#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
+#endif
+#endif
}
else {
if (!(p = strrdirsep(name, end, enc))) {
@@ -4898,7 +4897,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
continue;
#else
e = p; /* get the last dot of the last component */
-#endif /* USE_NTFS */
+#endif
}
#if USE_NTFS
else if (isADS(*p)) {
@@ -4971,7 +4970,7 @@ rb_file_s_extname(VALUE klass, VALUE fname)
*
* Returns the string representation of the path
*
- * File.path(File::NULL) #=> "/dev/null"
+ * File.path("/dev/null") #=> "/dev/null"
* File.path(Pathname.new("/tmp")) #=> "/tmp"
*
*/
@@ -5878,8 +5877,10 @@ rb_stat_wr(VALUE obj)
if ((st->st_mode & (S_IROTH)) == S_IROTH) {
return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
}
+ else {
+ return Qnil;
+ }
#endif
- return Qnil;
}
/*
@@ -5964,13 +5965,15 @@ rb_stat_W(VALUE obj)
static VALUE
rb_stat_ww(VALUE obj)
{
-#ifdef S_IWOTH
+#ifdef S_IROTH
struct stat *st = get_stat(obj);
if ((st->st_mode & (S_IWOTH)) == S_IWOTH) {
return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
}
+ else {
+ return Qnil;
+ }
#endif
- return Qnil;
}
/*
@@ -6086,7 +6089,7 @@ rb_stat_z(VALUE obj)
* the file otherwise.
*
* File.stat("testfile").size? #=> 66
- * File.stat(File::NULL).size? #=> nil
+ * File.stat("/dev/null").size? #=> nil
*
*/
@@ -6369,11 +6372,7 @@ rb_file_load_ok(const char *path)
#endif
0);
int fd = rb_cloexec_open(path, mode, 0);
- if (fd < 0) {
- if (!rb_gc_for_fd(errno)) return 0;
- fd = rb_cloexec_open(path, mode, 0);
- if (fd < 0) return 0;
- }
+ if (fd == -1) return 0;
rb_update_max_fd(fd);
ret = ruby_is_fd_loadable(fd);
(void)close(fd);
@@ -6531,7 +6530,7 @@ const char ruby_null_device[] =
* \Class \File extends module FileTest, supporting such singleton methods
* as <tt>File.exist?</tt>.
*
- * == About the Examples
+ * === About the Examples
*
* Many examples here use these variables:
*
@@ -6539,11 +6538,11 @@ const char ruby_null_device[] =
*
* == Access Modes
*
- * Methods File.new and File.open each create a \File object for a given file path.
+ * \Methods File.new and File.open each create a \File object for a given file path.
*
* === \String Access Modes
*
- * Methods File.new and File.open each may take string argument +mode+, which:
+ * \Methods File.new and File.open each may take string argument +mode+, which:
*
* - Begins with a 1- or 2-character
* {read/write mode}[rdoc-ref:File@Read-2FWrite+Mode].
@@ -7134,6 +7133,7 @@ const char ruby_null_device[] =
*
* Note that file permissions are quite different from the _mode_
* of a file stream (\File object).
+ * See IO@Modes.
*
* In a \File object, the permissions are available thus,
* where method +mode+, despite its name, returns permissions:
@@ -7179,7 +7179,7 @@ const char ruby_null_device[] =
*
* == \File \Constants
*
- * Various constants for use in \File and IO methods
+ * Various constants for use in \File and \IO methods
* may be found in module File::Constants;
* an array of their names is returned by <tt>File::Constants.constants</tt>.
*
@@ -7189,7 +7189,7 @@ const char ruby_null_device[] =
*
* - Inherits from {class IO}[rdoc-ref:IO@What-27s+Here],
* in particular, methods for creating, reading, and writing files
- * - Includes module FileTest,
+ * - Includes {module FileTest}[rdoc-ref:FileTest@What-27s+Here].
* which provides dozens of additional methods.
*
* Here, class \File provides methods that are useful for:
@@ -7234,15 +7234,15 @@ const char ruby_null_device[] =
*
* _Times_
*
- * - ::atime: Returns a Time for the most recent access to the given file.
- * - ::birthtime: Returns a Time for the creation of the given file.
- * - ::ctime: Returns a Time for the metadata change of the given file.
- * - ::mtime: Returns a Time for the most recent data modification to
+ * - ::atime: Returns a \Time for the most recent access to the given file.
+ * - ::birthtime: Returns a \Time for the creation of the given file.
+ * - ::ctime: Returns a \Time for the metadata change of the given file.
+ * - ::mtime: Returns a \Time for the most recent data modification to
* the content of the given file.
- * - #atime: Returns a Time for the most recent access to +self+.
- * - #birthtime: Returns a Time the creation for +self+.
- * - #ctime: Returns a Time for the metadata change of +self+.
- * - #mtime: Returns a Time for the most recent data modification
+ * - #atime: Returns a \Time for the most recent access to +self+.
+ * - #birthtime: Returns a \Time the creation for +self+.
+ * - #ctime: Returns a \Time for the metadata change of +self+.
+ * - #mtime: Returns a \Time for the most recent data modification
* to the content of +self+.
*
* _Types_
@@ -7431,373 +7431,93 @@ Init_File(void)
/*
* Document-module: File::Constants
*
- * \Module +File::Constants+ defines file-related constants.
- *
- * There are two families of constants here:
- *
- * - Those having to do with {file access}[rdoc-ref:File::Constants@File+Access].
- * - Those having to do with {filename globbing}[rdoc-ref:File::Constants@Filename+Globbing+Constants+-28File-3A-3AFNM_-2A-29].
- *
- * \File constants defined for the local process may be retrieved
- * with method File::Constants.constants:
- *
- * File::Constants.constants.take(5)
- * # => [:RDONLY, :WRONLY, :RDWR, :APPEND, :CREAT]
- *
- * == \File Access
- *
- * \File-access constants may be used with optional argument +mode+ in calls
- * to the following methods:
- *
- * - File.new.
- * - File.open.
- * - IO.for_fd.
- * - IO.new.
- * - IO.open.
- * - IO.popen.
- * - IO.reopen.
- * - IO.sysopen.
- * - StringIO.new.
- * - StringIO.open.
- * - StringIO#reopen.
- *
- * === Read/Write Access
- *
- * Read-write access for a stream
- * may be specified by a file-access constant.
- *
- * The constant may be specified as part of a bitwise OR of other such constants.
- *
- * Any combination of the constants in this section may be specified.
- *
- * ==== File::RDONLY
- *
- * Flag File::RDONLY specifies the the stream should be opened for reading only:
- *
- * filepath = '/tmp/t.tmp'
- * f = File.new(filepath, File::RDONLY)
- * f.write('Foo') # Raises IOError (not opened for writing).
- *
- * ==== File::WRONLY
+ * File::Constants provides file-related constants. All possible
+ * file constants are listed in the documentation but they may not all
+ * be present on your platform.
*
- * Flag File::WRONLY specifies that the stream should be opened for writing only:
- *
- * f = File.new(filepath, File::WRONLY)
- * f.read # Raises IOError (not opened for reading).
- *
- * ==== File::RDWR
- *
- * Flag File::RDWR specifies that the stream should be opened
- * for both reading and writing:
- *
- * f = File.new(filepath, File::RDWR)
- * f.write('Foo') # => 3
- * f.rewind # => 0
- * f.read # => "Foo"
- *
- * === \File Positioning
- *
- * ==== File::APPEND
- *
- * Flag File::APPEND specifies that the stream should be opened
- * in append mode.
- *
- * Before each write operation, the position is set to end-of-stream.
- * The modification of the position and the following write operation
- * are performed as a single atomic step.
- *
- * ==== File::TRUNC
- *
- * Flag File::TRUNC specifies that the stream should be truncated
- * at its beginning.
- * If the file exists and is successfully opened for writing,
- * it is to be truncated to position zero;
- * its ctime and mtime are updated.
- *
- * There is no effect on a FIFO special file or a terminal device.
- * The effect on other file types is implementation-defined.
- * The result of using File::TRUNC with File::RDONLY is undefined.
- *
- * === Creating and Preserving
- *
- * ==== File::CREAT
- *
- * Flag File::CREAT specifies that the stream should be created
- * if it does not already exist.
- *
- * If the file exists:
- *
- * - Raise an exception if File::EXCL is also specified.
- * - Otherwise, do nothing.
- *
- * If the file does not exist, then it is created.
- * Upon successful completion, the atime, ctime, and mtime of the file are updated,
- * and the ctime and mtime of the parent directory are updated.
- *
- * ==== File::EXCL
- *
- * Flag File::EXCL specifies that the stream should not already exist;
- * If flags File::CREAT and File::EXCL are both specified
- * and the stream already exists, an exception is raised.
- *
- * The check for the existence and creation of the file is performed as an
- * atomic operation.
- *
- * If both File::EXCL and File::CREAT are specified and the path names a symbolic link,
- * an exception is raised regardless of the contents of the symbolic link.
- *
- * If File::EXCL is specified and File::CREAT is not specified,
- * the result is undefined.
- *
- * === POSIX \File \Constants
- *
- * Some file-access constants are defined only on POSIX-compliant systems;
- * those are:
- *
- * - File::SYNC.
- * - File::DSYNC.
- * - File::RSYNC.
- * - File::DIRECT.
- * - File::NOATIME.
- * - File::NOCTTY.
- * - File::NOFOLLOW.
- * - File::TMPFILE.
- *
- * ==== File::SYNC, File::RSYNC, and File::DSYNC
- *
- * Flag File::SYNC, File::RSYNC, or File::DSYNC
- * specifies synchronization of I/O operations with the underlying file system.
- *
- * These flags are valid only for POSIX-compliant systems.
- *
- * - File::SYNC specifies that all write operations (both data and metadata)
- * are immediately to be flushed to the underlying storage device.
- * This means that the data is written to the storage device,
- * and the file's metadata (e.g., file size, timestamps, permissions)
- * are also synchronized.
- * This guarantees that data is safely stored on the storage medium
- * before returning control to the calling program.
- * This flag can have a significant impact on performance
- * since it requires synchronous writes, which can be slower
- * compared to asynchronous writes.
- *
- * - File::RSYNC specifies that any read operations on the file will not return
- * until all outstanding write operations
- * (those that have been issued but not completed) are also synchronized.
- * This is useful when you want to read the most up-to-date data,
- * which may still be in the process of being written.
- *
- * - File::DSYNC specifies that all _data_ write operations
- * are immediately to be flushed to the underlying storage device;
- * this differs from File::SYNC, which requires that _metadata_
- * also be synchronized.
- *
- * Note that the behavior of these flags may vary slightly
- * depending on the operating system and filesystem being used.
- * Additionally, using these flags can have an impact on performance
- * due to the synchronous nature of the I/O operations,
- * so they should be used judiciously,
- * especially in performance-critical applications.
- *
- * ==== File::NOCTTY
- *
- * Flag File::NOCTTY specifies that if the stream is a terminal device,
- * that device does not become the controlling terminal for the process.
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::DIRECT
- *
- * Flag File::DIRECT requests that cache effects of the I/O to and from the stream
- * be minimized.
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::NOATIME
- *
- * Flag File::NOATIME specifies that act of opening the stream
- * should not modify its access time (atime).
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::NOFOLLOW
- *
- * Flag File::NOFOLLOW specifies that if path is a symbolic link,
- * it should not be followed.
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::TMPFILE
- *
- * Flag File::TMPFILE specifies that the opened stream
- * should be a new temporary file.
- *
- * Defined only for POSIX-compliant systems.
- *
- * === Other File-Access \Constants
- *
- * ==== File::NONBLOCK
- *
- * When possible, the file is opened in nonblocking mode.
- * Neither the open operation nor any subsequent I/O operations on
- * the file will cause the calling process to wait.
- *
- * ==== File::BINARY
- *
- * Flag File::BINARY specifies that the stream is to be accessed in binary mode.
- *
- * ==== File::SHARE_DELETE (Windows Only)
- *
- * Flag File::SHARE_DELETE enables other processes to open the stream
- * with delete access.
- *
- * If the stream is opened for (local) delete access without File::SHARE_DELETE,
- * and another process attempts to open it with delete access,
- * the attempt fails and the stream is not opened for that process.
- *
- * == Locking
- *
- * Four file constants relate to stream locking;
- * see File#flock:
- *
- * ==== File::LOCK_EX
- *
- * Flag File::LOCK_EX specifies an exclusive lock;
- * only one process a a time may lock the stream.
- *
- * ==== File::LOCK_NB
- *
- * Flag File::LOCK_NB specifies non-blocking locking for the stream;
- * may be combined with File::LOCK_EX or File::LOCK_SH.
- *
- * ==== File::LOCK_SH
- *
- * Flag File::LOCK_SH specifies that multiple processes may lock
- * the stream at the same time.
- *
- * ==== File::LOCK_UN
- *
- * Flag File::LOCK_UN specifies that the stream is not to be locked.
- *
- * == Filename Globbing \Constants (File::FNM_*)
- *
- * Filename-globbing constants may be used with optional argument +flags+
- * in calls to the following methods:
- *
- * - Dir.glob.
- * - File.fnmatch.
- * - Pathname#fnmatch.
- * - Pathname.glob.
- * - Pathname#glob.
- *
- * The constants are:
- *
- * ==== File::FNM_CASEFOLD
- *
- * Flag File::FNM_CASEFOLD makes patterns case insensitive
- * for File.fnmatch (but not Dir.glob).
- *
- * ==== File::FNM_DOTMATCH
- *
- * Flag File::FNM_DOTMATCH makes the <tt>'*'</tt> pattern
- * match a filename starting with <tt>'.'</tt>.
- *
- * ==== File::FNM_EXTGLOB
- *
- * Flag File::FNM_EXTGLOB enables pattern <tt>'{_a_,_b_}'</tt>,
- * which matches pattern '_a_' and pattern '_b_';
- * behaves like
- * a {regexp union}[rdoc-ref:Regexp.union]
- * (e.g., <tt>'(?:_a_|_b_)'</tt>):
- *
- * pattern = '{LEGAL,BSDL}'
- * Dir.glob(pattern) # => ["LEGAL", "BSDL"]
- * Pathname.glob(pattern) # => [#<Pathname:LEGAL>, #<Pathname:BSDL>]
- * pathname.glob(pattern) # => [#<Pathname:LEGAL>, #<Pathname:BSDL>]
- *
- * ==== File::FNM_NOESCAPE
- *
- * Flag File::FNM_NOESCAPE disables <tt>'\'</tt> escaping.
- *
- * ==== File::FNM_PATHNAME
- *
- * Flag File::FNM_PATHNAME specifies that patterns <tt>'*'</tt> and <tt>'?'</tt>
- * do not match the directory separator
- * (the value of constant File::SEPARATOR).
- *
- * ==== File::FNM_SHORTNAME (Windows Only)
- *
- * Flag File::FNM_SHORTNAME Allows patterns to match short names if they exist.
- *
- * ==== File::FNM_SYSCASE
- *
- * Flag File::FNM_SYSCASE specifies that case sensitivity
- * is the same as in the underlying operating system;
- * effective for File.fnmatch, but not Dir.glob.
- *
- * == Other \Constants
- *
- * ==== File::NULL
- *
- * Flag File::NULL contains the string value of the null device:
- *
- * - On a Unix-like OS, <tt>'/dev/null'</tt>.
- * - On Windows, <tt>'NUL'</tt>.
+ * If the underlying platform doesn't define a constant the corresponding
+ * Ruby constant is not defined.
*
+ * Your platform documentations (e.g. man open(2)) may describe more
+ * detailed information.
*/
rb_mFConst = rb_define_module_under(rb_cFile, "Constants");
rb_include_module(rb_cIO, rb_mFConst);
+
+ /* open for reading only */
rb_define_const(rb_mFConst, "RDONLY", INT2FIX(O_RDONLY));
+ /* open for writing only */
rb_define_const(rb_mFConst, "WRONLY", INT2FIX(O_WRONLY));
+ /* open for reading and writing */
rb_define_const(rb_mFConst, "RDWR", INT2FIX(O_RDWR));
+ /* append on each write */
rb_define_const(rb_mFConst, "APPEND", INT2FIX(O_APPEND));
+ /* create file if it does not exist */
rb_define_const(rb_mFConst, "CREAT", INT2FIX(O_CREAT));
+ /* error if CREAT and the file exists */
rb_define_const(rb_mFConst, "EXCL", INT2FIX(O_EXCL));
#if defined(O_NDELAY) || defined(O_NONBLOCK)
# ifndef O_NONBLOCK
# define O_NONBLOCK O_NDELAY
# endif
+ /* do not block on open or for data to become available */
rb_define_const(rb_mFConst, "NONBLOCK", INT2FIX(O_NONBLOCK));
#endif
+ /* truncate size to 0 */
rb_define_const(rb_mFConst, "TRUNC", INT2FIX(O_TRUNC));
#ifdef O_NOCTTY
+ /* not to make opened IO the controlling terminal device */
rb_define_const(rb_mFConst, "NOCTTY", INT2FIX(O_NOCTTY));
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
+ /* disable line code conversion */
rb_define_const(rb_mFConst, "BINARY", INT2FIX(O_BINARY));
#ifndef O_SHARE_DELETE
# define O_SHARE_DELETE 0
#endif
+ /* can delete opened file */
rb_define_const(rb_mFConst, "SHARE_DELETE", INT2FIX(O_SHARE_DELETE));
#ifdef O_SYNC
+ /* any write operation perform synchronously */
rb_define_const(rb_mFConst, "SYNC", INT2FIX(O_SYNC));
#endif
#ifdef O_DSYNC
+ /* any write operation perform synchronously except some meta data */
rb_define_const(rb_mFConst, "DSYNC", INT2FIX(O_DSYNC));
#endif
#ifdef O_RSYNC
+ /* any read operation perform synchronously. used with SYNC or DSYNC. */
rb_define_const(rb_mFConst, "RSYNC", INT2FIX(O_RSYNC));
#endif
#ifdef O_NOFOLLOW
+ /* do not follow symlinks */
rb_define_const(rb_mFConst, "NOFOLLOW", INT2FIX(O_NOFOLLOW)); /* FreeBSD, Linux */
#endif
#ifdef O_NOATIME
+ /* do not change atime */
rb_define_const(rb_mFConst, "NOATIME", INT2FIX(O_NOATIME)); /* Linux */
#endif
#ifdef O_DIRECT
+ /* Try to minimize cache effects of the I/O to and from this file. */
rb_define_const(rb_mFConst, "DIRECT", INT2FIX(O_DIRECT));
#endif
#ifdef O_TMPFILE
+ /* Create an unnamed temporary file */
rb_define_const(rb_mFConst, "TMPFILE", INT2FIX(O_TMPFILE));
#endif
+ /* shared lock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_SH", INT2FIX(LOCK_SH));
+ /* exclusive lock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_EX", INT2FIX(LOCK_EX));
+ /* unlock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_UN", INT2FIX(LOCK_UN));
+ /* non-blocking lock. used with LOCK_SH or LOCK_EX. see File#flock */
rb_define_const(rb_mFConst, "LOCK_NB", INT2FIX(LOCK_NB));
+ /* Name of the null device */
rb_define_const(rb_mFConst, "NULL", rb_fstring_cstr(ruby_null_device));
rb_define_global_function("test", rb_f_test, -1);
diff --git a/gc.c b/gc.c
index 7710fec7d4..919d57989a 100644
--- a/gc.c
+++ b/gc.c
@@ -60,15 +60,6 @@
# endif
#endif
-#ifdef HAVE_MALLOC_TRIM
-# include <malloc.h>
-
-# ifdef __EMSCRIPTEN__
-/* malloc_trim is defined in emscripten/emmalloc.h on emscripten. */
-# include <emscripten/emmalloc.h>
-# endif
-#endif
-
#if !defined(PAGE_SIZE) && defined(HAVE_SYS_USER_H)
/* LIST_HEAD conflicts with sys/queue.h on macOS */
# include <sys/user.h>
@@ -104,13 +95,12 @@
#undef LIST_HEAD /* ccan/list conflicts with BSD-origin sys/queue.h. */
#include "constant.h"
-#include "darray.h"
#include "debug_counter.h"
#include "eval_intern.h"
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/class.h"
-#include "internal/compile.h"
#include "internal/complex.h"
#include "internal/cont.h"
#include "internal/error.h"
@@ -129,7 +119,7 @@
#include "internal/thread.h"
#include "internal/variable.h"
#include "internal/warnings.h"
-#include "rjit.h"
+#include "mjit.h"
#include "probes.h"
#include "regint.h"
#include "ruby/debug.h"
@@ -141,6 +131,7 @@
#include "ruby_assert.h"
#include "ruby_atomic.h"
#include "symbol.h"
+#include "transient_heap.h"
#include "vm_core.h"
#include "vm_sync.h"
#include "vm_callinfo.h"
@@ -157,68 +148,6 @@
#define MAP_ANONYMOUS MAP_ANON
#endif
-
-static size_t malloc_offset = 0;
-#if defined(HAVE_MALLOC_USABLE_SIZE)
-static size_t
-gc_compute_malloc_offset(void)
-{
- // Different allocators use different metadata storage strategies which result in different
- // ideal sizes.
- // For instance malloc(64) will waste 8B with glibc, but waste 0B with jemalloc.
- // But malloc(56) will waste 0B with glibc, but waste 8B with jemalloc.
- // So we try allocating 64, 56 and 48 bytes and select the first offset that doesn't
- // waste memory.
- // This was tested on Linux with glibc 2.35 and jemalloc 5, and for both it result in
- // no wasted memory.
- size_t offset = 0;
- for (offset = 0; offset <= 16; offset += 8) {
- size_t allocated = (64 - offset);
- void *test_ptr = malloc(allocated);
- size_t wasted = malloc_usable_size(test_ptr) - allocated;
- free(test_ptr);
-
- if (wasted == 0) {
- return offset;
- }
- }
- return 0;
-}
-#else
-static size_t
-gc_compute_malloc_offset(void)
-{
- // If we don't have malloc_usable_size, we use powers of 2.
- return 0;
-}
-#endif
-
-size_t
-rb_malloc_grow_capa(size_t current, size_t type_size)
-{
- size_t current_capacity = current;
- if (current_capacity < 4) {
- current_capacity = 4;
- }
- current_capacity *= type_size;
-
- // We double the current capacity.
- size_t new_capacity = (current_capacity * 2);
-
- // And round up to the next power of 2 if it's not already one.
- if (rb_popcount64(new_capacity) != 1) {
- new_capacity = (size_t)(1 << (64 - nlz_int64(new_capacity)));
- }
-
- new_capacity -= malloc_offset;
- new_capacity /= type_size;
- if (current > new_capacity) {
- rb_bug("rb_malloc_grow_capa: current_capacity=%zu, new_capacity=%zu, malloc_offset=%zu", current, new_capacity, malloc_offset);
- }
- RUBY_ASSERT(new_capacity > current);
- return new_capacity;
-}
-
static inline struct rbimpl_size_mul_overflow_tag
size_add_overflow(size_t x, size_t y)
{
@@ -362,9 +291,6 @@ rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
#ifndef GC_HEAP_GROWTH_MAX_SLOTS
#define GC_HEAP_GROWTH_MAX_SLOTS 0 /* 0 is disable */
#endif
-#ifndef GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO
-# define GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO 0.01
-#endif
#ifndef GC_HEAP_OLDOBJECT_LIMIT_FACTOR
#define GC_HEAP_OLDOBJECT_LIMIT_FACTOR 2.0
#endif
@@ -399,14 +325,6 @@ rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
#define GC_OLDMALLOC_LIMIT_MAX (128 * 1024 * 1024 /* 128MB */)
#endif
-#ifndef GC_CAN_COMPILE_COMPACTION
-#if defined(__wasi__) /* WebAssembly doesn't support signals */
-# define GC_CAN_COMPILE_COMPACTION 0
-#else
-# define GC_CAN_COMPILE_COMPACTION 1
-#endif
-#endif
-
#ifndef PRINT_MEASURE_LINE
#define PRINT_MEASURE_LINE 0
#endif
@@ -421,7 +339,7 @@ rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
#define TICK_TYPE 1
typedef struct {
- size_t size_pool_init_slots[SIZE_POOL_COUNT];
+ size_t heap_init_slots;
size_t heap_free_slots;
double growth_factor;
size_t growth_max_slots;
@@ -429,7 +347,6 @@ typedef struct {
double heap_free_slots_min_ratio;
double heap_free_slots_goal_ratio;
double heap_free_slots_max_ratio;
- double uncollectible_wb_unprotected_objects_limit_ratio;
double oldobject_limit_factor;
size_t malloc_limit_min;
@@ -444,7 +361,7 @@ typedef struct {
} ruby_gc_params_t;
static ruby_gc_params_t gc_params = {
- { 0 },
+ GC_HEAP_INIT_SLOTS,
GC_HEAP_FREE_SLOTS,
GC_HEAP_GROWTH_FACTOR,
GC_HEAP_GROWTH_MAX_SLOTS,
@@ -452,7 +369,6 @@ static ruby_gc_params_t gc_params = {
GC_HEAP_FREE_SLOTS_MIN_RATIO,
GC_HEAP_FREE_SLOTS_GOAL_RATIO,
GC_HEAP_FREE_SLOTS_MAX_RATIO,
- GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO,
GC_HEAP_OLDOBJECT_LIMIT_FACTOR,
GC_MALLOC_LIMIT_MIN,
@@ -511,6 +427,16 @@ int ruby_rgengc_debug;
// Note: using RUBY_ASSERT_WHEN() extend a macro in expr (info by nobu).
#define GC_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(RGENGC_CHECK_MODE > 0, expr, #expr)
+/* RGENGC_OLD_NEWOBJ_CHECK
+ * 0: disable all assertions
+ * >0: make a OLD object when new object creation.
+ *
+ * Make one OLD object per RGENGC_OLD_NEWOBJ_CHECK WB protected objects creation.
+ */
+#ifndef RGENGC_OLD_NEWOBJ_CHECK
+#define RGENGC_OLD_NEWOBJ_CHECK 0
+#endif
+
/* RGENGC_PROFILE
* 0: disable RGenGC profiling
* 1: enable profiling for basic information
@@ -543,6 +469,9 @@ int ruby_rgengc_debug;
#ifndef GC_PROFILE_DETAIL_MEMORY
#define GC_PROFILE_DETAIL_MEMORY 0
#endif
+#ifndef GC_ENABLE_INCREMENTAL_MARK
+#define GC_ENABLE_INCREMENTAL_MARK USE_RINCGC
+#endif
#ifndef GC_ENABLE_LAZY_SWEEP
#define GC_ENABLE_LAZY_SWEEP 1
#endif
@@ -561,7 +490,7 @@ int ruby_rgengc_debug;
#endif
#ifndef GC_DEBUG_STRESS_TO_CLASS
-#define GC_DEBUG_STRESS_TO_CLASS RUBY_DEBUG
+#define GC_DEBUG_STRESS_TO_CLASS 0
#endif
#ifndef RGENGC_OBJ_INFO
@@ -759,15 +688,15 @@ typedef struct mark_stack {
#define SIZE_POOL_EDEN_HEAP(size_pool) (&(size_pool)->eden_heap)
#define SIZE_POOL_TOMB_HEAP(size_pool) (&(size_pool)->tomb_heap)
-typedef int (*gc_compact_compare_func)(const void *l, const void *r, void *d);
-
typedef struct rb_heap_struct {
struct heap_page *free_pages;
struct ccan_list_head pages;
struct heap_page *sweeping_page; /* iterator for .pages */
struct heap_page *compact_cursor;
uintptr_t compact_cursor_index;
+#if GC_ENABLE_INCREMENTAL_MARK
struct heap_page *pooled_pages;
+#endif
size_t total_pages; /* total page count in a heap */
size_t total_slots; /* total slot count (about total_pages * HEAP_PAGE_OBJ_LIMIT) */
} rb_heap_t;
@@ -781,13 +710,12 @@ typedef struct rb_size_pool_struct {
size_t total_allocated_pages;
size_t total_freed_pages;
size_t force_major_gc_count;
- size_t force_incremental_marking_finish_count;
- size_t total_allocated_objects;
- size_t total_freed_objects;
+#if USE_RVARGC
/* Sweeping statistics */
size_t freed_slots;
size_t empty_slots;
+#endif
rb_heap_t eden_heap;
rb_heap_t tomb_heap;
@@ -818,15 +746,17 @@ typedef struct rb_objspace {
unsigned int dont_incremental : 1;
unsigned int during_gc : 1;
unsigned int during_compacting : 1;
- unsigned int during_reference_updating : 1;
unsigned int gc_stressful: 1;
- unsigned int has_newobj_hook: 1;
+ unsigned int has_hook: 1;
unsigned int during_minor_gc : 1;
+#if GC_ENABLE_INCREMENTAL_MARK
unsigned int during_incremental_marking : 1;
+#endif
unsigned int measure_gc : 1;
} flags;
rb_event_flag_t hook_events;
+ size_t total_allocated_objects;
VALUE next_object_id;
rb_size_pool_t size_pools[SIZE_POOL_COUNT];
@@ -895,14 +825,9 @@ typedef struct rb_objspace {
/* basic statistics */
size_t count;
- uint64_t marking_time_ns;
- struct timespec marking_start_time;
- uint64_t sweeping_time_ns;
- struct timespec sweeping_start_time;
-
- /* Weak references */
- size_t weak_references_count;
- size_t retained_weak_references_count;
+ size_t total_freed_objects;
+ uint64_t total_time_ns;
+ struct timespec start_time;
} profile;
struct gc_list *global_list;
@@ -934,15 +859,14 @@ typedef struct rb_objspace {
size_t moved_up_count_table[T_MASK];
size_t moved_down_count_table[T_MASK];
size_t total_moved;
-
- /* This function will be used, if set, to sort the heap prior to compaction */
- gc_compact_compare_func compare_func;
} rcompactor;
+#if GC_ENABLE_INCREMENTAL_MARK
struct {
size_t pooled_slots;
size_t step_slots;
} rincgc;
+#endif
st_table *id_to_obj_tbl;
st_table *obj_to_id_tbl;
@@ -950,8 +874,6 @@ typedef struct rb_objspace {
#if GC_DEBUG_STRESS_TO_CLASS
VALUE stress_to_class;
#endif
-
- rb_darray(VALUE *) weak_references;
} rb_objspace_t;
@@ -974,7 +896,7 @@ enum {
#define HEAP_PAGE_ALIGN (1 << HEAP_PAGE_ALIGN_LOG)
#define HEAP_PAGE_SIZE HEAP_PAGE_ALIGN
-#if !defined(INCREMENTAL_MARK_STEP_ALLOCATIONS)
+#if GC_ENABLE_INCREMENTAL_MARK && !defined(INCREMENTAL_MARK_STEP_ALLOCATIONS)
# define INCREMENTAL_MARK_STEP_ALLOCATIONS 500
#endif
@@ -1020,19 +942,15 @@ static const bool HEAP_PAGE_ALLOC_USE_MMAP = false;
static bool heap_page_alloc_use_mmap;
#endif
-#define RVALUE_AGE_BIT_COUNT 2
-#define RVALUE_AGE_BIT_MASK (((bits_t)1 << RVALUE_AGE_BIT_COUNT) - 1)
-
struct heap_page {
short slot_size;
short total_slots;
short free_slots;
short final_slots;
- short pinned_slots;
struct {
unsigned int before_sweep : 1;
unsigned int has_remembered_objects : 1;
- unsigned int has_uncollectible_wb_unprotected_objects : 1;
+ unsigned int has_uncollectible_shady_objects : 1;
unsigned int in_tomb : 1;
} flags;
@@ -1049,11 +967,8 @@ struct heap_page {
bits_t uncollectible_bits[HEAP_PAGE_BITMAP_LIMIT];
bits_t marking_bits[HEAP_PAGE_BITMAP_LIMIT];
- bits_t remembered_bits[HEAP_PAGE_BITMAP_LIMIT];
-
/* If set, the object is not movable */
bits_t pinned_bits[HEAP_PAGE_BITMAP_LIMIT];
- bits_t age_bits[HEAP_PAGE_BITMAP_LIMIT * RVALUE_AGE_BIT_COUNT];
};
/*
@@ -1097,43 +1012,9 @@ asan_unlock_freelist(struct heap_page *page)
#define GC_SWEEP_PAGES_FREEABLE_PER_STEP 3
-#define RVALUE_AGE_BITMAP_INDEX(n) (NUM_IN_PAGE(n) / (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT))
-#define RVALUE_AGE_BITMAP_OFFSET(n) ((NUM_IN_PAGE(n) % (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT)) * RVALUE_AGE_BIT_COUNT)
-
-#define RVALUE_OLD_AGE 3
-
-static int
-RVALUE_AGE_GET(VALUE obj)
-{
- bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
- return (int)(age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] >> RVALUE_AGE_BITMAP_OFFSET(obj)) & RVALUE_AGE_BIT_MASK;
-}
-
-static void
-RVALUE_AGE_SET(VALUE obj, int age)
-{
- RUBY_ASSERT(age <= RVALUE_OLD_AGE);
- bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
- // clear the bits
- age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] &= ~(RVALUE_AGE_BIT_MASK << (RVALUE_AGE_BITMAP_OFFSET(obj)));
- // shift the correct value in
- age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] |= ((bits_t)age << RVALUE_AGE_BITMAP_OFFSET(obj));
- if (age == RVALUE_OLD_AGE) {
- RB_FL_SET_RAW(obj, RUBY_FL_PROMOTED);
- }
- else {
- RB_FL_UNSET_RAW(obj, RUBY_FL_PROMOTED);
- }
-}
-
/* Aliases */
#define rb_objspace (*rb_objspace_of(GET_VM()))
#define rb_objspace_of(vm) ((vm)->objspace)
-#define unless_objspace(objspace) \
- rb_objspace_t *objspace; \
- rb_vm_t *unless_objspace_vm = GET_VM(); \
- if (unless_objspace_vm) objspace = unless_objspace_vm->objspace; \
- else /* return; or objspace will be warned uninitialized */
#define ruby_initial_gc_stress gc_params.gc_stress
@@ -1159,10 +1040,8 @@ VALUE *ruby_initial_gc_stress_ptr = &ruby_initial_gc_stress;
#define ruby_gc_stress_mode objspace->gc_stress_mode
#if GC_DEBUG_STRESS_TO_CLASS
#define stress_to_class objspace->stress_to_class
-#define set_stress_to_class(c) (stress_to_class = (c))
#else
-#define stress_to_class (objspace, 0)
-#define set_stress_to_class(c) (objspace, (c))
+#define stress_to_class 0
#endif
#if 0
@@ -1279,43 +1158,32 @@ total_freed_pages(rb_objspace_t *objspace)
return count;
}
-static inline size_t
-total_allocated_objects(rb_objspace_t *objspace)
-{
- size_t count = 0;
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- rb_size_pool_t *size_pool = &size_pools[i];
- count += size_pool->total_allocated_objects;
- }
- return count;
-}
-
-static inline size_t
-total_freed_objects(rb_objspace_t *objspace)
-{
- size_t count = 0;
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- rb_size_pool_t *size_pool = &size_pools[i];
- count += size_pool->total_freed_objects;
- }
- return count;
-}
-
#define gc_mode(objspace) gc_mode_verify((enum gc_mode)(objspace)->flags.mode)
#define gc_mode_set(objspace, mode) ((objspace)->flags.mode = (unsigned int)gc_mode_verify(mode))
#define is_marking(objspace) (gc_mode(objspace) == gc_mode_marking)
#define is_sweeping(objspace) (gc_mode(objspace) == gc_mode_sweeping)
#define is_full_marking(objspace) ((objspace)->flags.during_minor_gc == FALSE)
+#if GC_ENABLE_INCREMENTAL_MARK
#define is_incremental_marking(objspace) ((objspace)->flags.during_incremental_marking != FALSE)
+#else
+#define is_incremental_marking(objspace) FALSE
+#endif
+#if GC_ENABLE_INCREMENTAL_MARK
#define will_be_incremental_marking(objspace) ((objspace)->rgengc.need_major_gc != GPR_FLAG_NONE)
+#else
+#define will_be_incremental_marking(objspace) FALSE
+#endif
+#if GC_ENABLE_INCREMENTAL_MARK
#define GC_INCREMENTAL_SWEEP_SLOT_COUNT 2048
-#define GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT 1024
+#endif
#define is_lazy_sweeping(objspace) (GC_ENABLE_LAZY_SWEEP && has_sweeping_pages(objspace))
#if SIZEOF_LONG == SIZEOF_VOIDP
+# define nonspecial_obj_id(obj) (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG)
# define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
+# define nonspecial_obj_id(obj) LL2NUM((SIGNED_VALUE)(obj) / 2)
# define obj_id_to_ref(objid) (FIXNUM_P(objid) ? \
((objid) ^ FIXNUM_FLAG) : (NUM2PTR(objid) << 1))
#else
@@ -1342,18 +1210,24 @@ VALUE rb_mGC;
int ruby_disable_gc = 0;
int ruby_enable_autocompact = 0;
-void rb_iseq_mark_and_move(rb_iseq_t *iseq, bool referece_updating);
+void rb_iseq_mark(const rb_iseq_t *iseq);
+void rb_iseq_update_references(rb_iseq_t *iseq);
void rb_iseq_free(const rb_iseq_t *iseq);
size_t rb_iseq_memsize(const rb_iseq_t *iseq);
void rb_vm_update_references(void *ptr);
void rb_gcdebug_print_obj_condition(VALUE obj);
+static VALUE define_final0(VALUE obj, VALUE block);
+
NORETURN(static void *gc_vraise(void *ptr));
NORETURN(static void gc_raise(VALUE exc, const char *fmt, ...));
NORETURN(static void negative_size_allocation_error(const char *));
static void init_mark_stack(mark_stack_t *stack);
+
+static int ready_to_gc(rb_objspace_t *objspace);
+
static int garbage_collect(rb_objspace_t *, unsigned int reason);
static int gc_start(rb_objspace_t *objspace, unsigned int reason);
@@ -1361,7 +1235,8 @@ static void gc_rest(rb_objspace_t *objspace);
enum gc_enter_event {
gc_enter_event_start,
- gc_enter_event_continue,
+ gc_enter_event_mark_continue,
+ gc_enter_event_sweep_continue,
gc_enter_event_rest,
gc_enter_event_finalizer,
gc_enter_event_rb_memerror,
@@ -1369,26 +1244,46 @@ enum gc_enter_event {
static inline void gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev);
static inline void gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev);
-static void gc_marking_enter(rb_objspace_t *objspace);
-static void gc_marking_exit(rb_objspace_t *objspace);
-static void gc_sweeping_enter(rb_objspace_t *objspace);
-static void gc_sweeping_exit(rb_objspace_t *objspace);
-static bool gc_marks_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap);
+
+static void gc_marks(rb_objspace_t *objspace, int full_mark);
+static void gc_marks_start(rb_objspace_t *objspace, int full);
+static void gc_marks_finish(rb_objspace_t *objspace);
+static void gc_marks_rest(rb_objspace_t *objspace);
+static void gc_marks_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap);
static void gc_sweep(rb_objspace_t *objspace);
+static void gc_sweep_start(rb_objspace_t *objspace);
+#if USE_RVARGC
static void gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool);
+#endif
+static void gc_sweep_finish(rb_objspace_t *objspace);
+static int gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap);
+static void gc_sweep_rest(rb_objspace_t *objspace);
static void gc_sweep_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap);
static inline void gc_mark(rb_objspace_t *objspace, VALUE ptr);
static inline void gc_pin(rb_objspace_t *objspace, VALUE ptr);
static inline void gc_mark_and_pin(rb_objspace_t *objspace, VALUE ptr);
+static void gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr);
NO_SANITIZE("memory", static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr));
+static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr);
static int gc_mark_stacked_objects_incremental(rb_objspace_t *, size_t count);
+static int gc_mark_stacked_objects_all(rb_objspace_t *);
+static void gc_grey(rb_objspace_t *objspace, VALUE ptr);
+
+static inline int gc_mark_set(rb_objspace_t *objspace, VALUE obj);
NO_SANITIZE("memory", static inline int is_pointer_to_heap(rb_objspace_t *objspace, void *ptr));
+static void push_mark_stack(mark_stack_t *, VALUE);
+static int pop_mark_stack(mark_stack_t *, VALUE *);
+static size_t mark_stack_size(mark_stack_t *stack);
+static void shrink_stack_chunk_cache(mark_stack_t *stack);
+
static size_t obj_memsize_of(VALUE obj, int use_all_types);
static void gc_verify_internal_consistency(rb_objspace_t *objspace);
+static int gc_verify_heap_page(rb_objspace_t *objspace, struct heap_page *page, VALUE obj);
+static int gc_verify_heap_pages(rb_objspace_t *objspace);
static void gc_stress_set(rb_objspace_t *objspace, VALUE flag);
static VALUE gc_disable_no_rest(rb_objspace_t *);
@@ -1466,7 +1361,7 @@ tick(void)
return ((unsigned long long)lo)|( ((unsigned long long)hi)<<32);
}
-#elif defined(__powerpc64__) && (GCC_VERSION_SINCE(4,8,0) || defined(__clang__))
+#elif defined(__powerpc64__) && GCC_VERSION_SINCE(4,8,0)
typedef unsigned long long tick_t;
#define PRItick "llu"
@@ -1600,10 +1495,21 @@ asan_poison_object_restore(VALUE obj, void *ptr)
#define RVALUE_PAGE_UNCOLLECTIBLE(page, obj) MARKED_IN_BITMAP((page)->uncollectible_bits, (obj))
#define RVALUE_PAGE_MARKING(page, obj) MARKED_IN_BITMAP((page)->marking_bits, (obj))
+#define RVALUE_OLD_AGE 3
+#define RVALUE_AGE_SHIFT 5 /* FL_PROMOTED0 bit */
+
+static int rgengc_remembered(rb_objspace_t *objspace, VALUE obj);
+static int rgengc_remembered_sweep(rb_objspace_t *objspace, VALUE obj);
static int rgengc_remember(rb_objspace_t *objspace, VALUE obj);
static void rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap);
static void rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap);
+static inline int
+RVALUE_FLAGS_AGE(VALUE flags)
+{
+ return (int)((flags & (FL_PROMOTED0 | FL_PROMOTED1)) >> RVALUE_AGE_SHIFT);
+}
+
static int
check_rvalue_consistency_force(const VALUE obj, int terminate)
{
@@ -1641,9 +1547,8 @@ check_rvalue_consistency_force(const VALUE obj, int terminate)
const int wb_unprotected_bit = RVALUE_WB_UNPROTECTED_BITMAP(obj) != 0;
const int uncollectible_bit = RVALUE_UNCOLLECTIBLE_BITMAP(obj) != 0;
const int mark_bit = RVALUE_MARK_BITMAP(obj) != 0;
- const int marking_bit = RVALUE_MARKING_BITMAP(obj) != 0;
- const int remembered_bit = MARKED_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj) != 0;
- const int age = RVALUE_AGE_GET((VALUE)obj);
+ const int marking_bit = RVALUE_MARKING_BITMAP(obj) != 0, remembered_bit = marking_bit;
+ const int age = RVALUE_FLAGS_AGE(RBASIC(obj)->flags);
if (GET_HEAP_PAGE(obj)->flags.in_tomb) {
fprintf(stderr, "check_rvalue_consistency: %s is in tomb page.\n", obj_info(obj));
@@ -1776,7 +1681,7 @@ static inline int
RVALUE_REMEMBERED(VALUE obj)
{
check_rvalue_consistency(obj);
- return MARKED_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj) != 0;
+ return RVALUE_MARKING_BITMAP(obj) != 0;
}
static inline int
@@ -1787,20 +1692,34 @@ RVALUE_UNCOLLECTIBLE(VALUE obj)
}
static inline int
+RVALUE_OLD_P_RAW(VALUE obj)
+{
+ const VALUE promoted = FL_PROMOTED0 | FL_PROMOTED1;
+ return (RBASIC(obj)->flags & promoted) == promoted;
+}
+
+static inline int
RVALUE_OLD_P(VALUE obj)
{
- GC_ASSERT(!RB_SPECIAL_CONST_P(obj));
check_rvalue_consistency(obj);
- // Because this will only ever be called on GC controlled objects,
- // we can use the faster _RAW function here
- return RB_OBJ_PROMOTED_RAW(obj);
+ return RVALUE_OLD_P_RAW(obj);
}
+#if RGENGC_CHECK_MODE || GC_DEBUG
+static inline int
+RVALUE_AGE(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_FLAGS_AGE(RBASIC(obj)->flags);
+}
+#endif
+
static inline void
RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
{
MARK_IN_BITMAP(&page->uncollectible_bits[0], obj);
objspace->rgengc.old_objects++;
+ rb_transient_heap_promote(obj);
#if RGENGC_PROFILE >= 2
objspace->profile.total_promoted_count++;
@@ -1815,39 +1734,64 @@ RVALUE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, VALUE obj)
RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(objspace, GET_HEAP_PAGE(obj), obj);
}
+static inline VALUE
+RVALUE_FLAGS_AGE_SET(VALUE flags, int age)
+{
+ flags &= ~(FL_PROMOTED0 | FL_PROMOTED1);
+ flags |= (age << RVALUE_AGE_SHIFT);
+ return flags;
+}
+
/* set age to age+1 */
static inline void
RVALUE_AGE_INC(rb_objspace_t *objspace, VALUE obj)
{
- int age = RVALUE_AGE_GET((VALUE)obj);
+ VALUE flags = RBASIC(obj)->flags;
+ int age = RVALUE_FLAGS_AGE(flags);
if (RGENGC_CHECK_MODE && age == RVALUE_OLD_AGE) {
rb_bug("RVALUE_AGE_INC: can not increment age of OLD object %s.", obj_info(obj));
}
age++;
- RVALUE_AGE_SET(obj, age);
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(flags, age);
if (age == RVALUE_OLD_AGE) {
RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj);
}
+ check_rvalue_consistency(obj);
+}
+
+/* set age to RVALUE_OLD_AGE */
+static inline void
+RVALUE_AGE_SET_OLD(rb_objspace_t *objspace, VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ GC_ASSERT(!RVALUE_OLD_P(obj));
+
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, RVALUE_OLD_AGE);
+ RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj);
check_rvalue_consistency(obj);
}
+/* set age to RVALUE_OLD_AGE - 1 */
static inline void
RVALUE_AGE_SET_CANDIDATE(rb_objspace_t *objspace, VALUE obj)
{
check_rvalue_consistency(obj);
GC_ASSERT(!RVALUE_OLD_P(obj));
- RVALUE_AGE_SET(obj, RVALUE_OLD_AGE - 1);
+
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, RVALUE_OLD_AGE - 1);
+
check_rvalue_consistency(obj);
}
static inline void
-RVALUE_AGE_RESET(VALUE obj)
+RVALUE_DEMOTE_RAW(rb_objspace_t *objspace, VALUE obj)
{
- RVALUE_AGE_SET(obj, 0);
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, 0);
+ CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), obj);
}
static inline void
@@ -1857,11 +1801,10 @@ RVALUE_DEMOTE(rb_objspace_t *objspace, VALUE obj)
GC_ASSERT(RVALUE_OLD_P(obj));
if (!is_incremental_marking(objspace) && RVALUE_REMEMBERED(obj)) {
- CLEAR_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj);
+ CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
}
- CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), obj);
- RVALUE_AGE_RESET(obj);
+ RVALUE_DEMOTE_RAW(objspace, obj);
if (RVALUE_MARKED(obj)) {
objspace->rgengc.old_objects--;
@@ -1870,6 +1813,22 @@ RVALUE_DEMOTE(rb_objspace_t *objspace, VALUE obj)
check_rvalue_consistency(obj);
}
+static inline void
+RVALUE_AGE_RESET_RAW(VALUE obj)
+{
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, 0);
+}
+
+static inline void
+RVALUE_AGE_RESET(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ GC_ASSERT(!RVALUE_OLD_P(obj));
+
+ RVALUE_AGE_RESET_RAW(obj);
+ check_rvalue_consistency(obj);
+}
+
static inline int
RVALUE_BLACK_P(VALUE obj)
{
@@ -1916,8 +1875,6 @@ rb_objspace_alloc(void)
ccan_list_head_init(&SIZE_POOL_TOMB_HEAP(size_pool)->pages);
}
- rb_darray_make_without_gc(&objspace->weak_references, 0);
-
dont_gc_on();
return objspace;
@@ -1933,8 +1890,10 @@ rb_objspace_free(rb_objspace_t *objspace)
if (is_lazy_sweeping(objspace))
rb_bug("lazy sweeping underway when freeing object space");
- free(objspace->profile.records);
- objspace->profile.records = NULL;
+ if (objspace->profile.records) {
+ free(objspace->profile.records);
+ objspace->profile.records = 0;
+ }
if (global_list) {
struct gc_list *list, *next;
@@ -1945,8 +1904,7 @@ rb_objspace_free(rb_objspace_t *objspace)
}
if (heap_pages_sorted) {
size_t i;
- size_t total_heap_pages = heap_allocated_pages;
- for (i = 0; i < total_heap_pages; ++i) {
+ for (i = 0; i < heap_allocated_pages; ++i) {
heap_page_free(objspace, heap_pages_sorted[i]);
}
free(heap_pages_sorted);
@@ -1967,8 +1925,6 @@ rb_objspace_free(rb_objspace_t *objspace)
free_stack_chunks(&objspace->mark_stack);
mark_stack_free_cache(&objspace->mark_stack);
- rb_darray_free_without_gc(objspace->weak_references);
-
free(objspace);
}
@@ -2042,8 +1998,6 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj
page->freelist = p;
asan_lock_freelist(page);
- RVALUE_AGE_RESET(obj);
-
if (RGENGC_CHECK_MODE &&
/* obj should belong to page */
!(page->start <= (uintptr_t)obj &&
@@ -2071,6 +2025,7 @@ heap_add_freepage(rb_heap_t *heap, struct heap_page *page)
asan_lock_freelist(page);
}
+#if GC_ENABLE_INCREMENTAL_MARK
static inline void
heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
{
@@ -2084,6 +2039,7 @@ heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *pa
asan_lock_freelist(page);
}
+#endif
static void
heap_unlink_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
@@ -2136,7 +2092,7 @@ heap_pages_free_unused_pages(rb_objspace_t *objspace)
}
if (has_pages_in_tomb_heap) {
- for (i = j = 0; j < heap_allocated_pages; i++) {
+ for (i = j = 1; j < heap_allocated_pages; i++) {
struct heap_page *page = heap_pages_sorted[i];
if (page->flags.in_tomb && page->free_slots == page->total_slots) {
@@ -2156,11 +2112,6 @@ heap_pages_free_unused_pages(rb_objspace_t *objspace)
GC_ASSERT(himem <= heap_pages_himem);
heap_pages_himem = himem;
- struct heap_page *lopage = heap_pages_sorted[0];
- uintptr_t lomem = (uintptr_t)lopage->start;
- GC_ASSERT(lomem >= heap_pages_lomem);
- heap_pages_lomem = lomem;
-
GC_ASSERT(j == heap_allocated_pages);
}
}
@@ -2372,7 +2323,6 @@ heap_assign_page(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *
heap_add_freepage(heap, page);
}
-#if GC_CAN_COMPILE_COMPACTION
static void
heap_add_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap, size_t add)
{
@@ -2386,26 +2336,6 @@ heap_add_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *he
GC_ASSERT(size_pool->allocatable_pages == 0);
}
-#endif
-
-static size_t
-slots_to_pages_for_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool, size_t slots)
-{
- size_t multiple = size_pool->slot_size / BASE_SLOT_SIZE;
- /* Due to alignment, heap pages may have one less slot. We should
- * ensure there is enough pages to guarantee that we will have at
- * least the required number of slots after allocating all the pages. */
- size_t slots_per_page = (HEAP_PAGE_OBJ_LIMIT / multiple) - 1;
- return CEILDIV(slots, slots_per_page);
-}
-
-static size_t
-minimum_pages_for_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
-{
- size_t size_pool_idx = size_pool - size_pools;
- size_t init_slots = gc_params.size_pool_init_slots[size_pool_idx];
- return slots_to_pages_for_size_pool(objspace, size_pool, init_slots);
-}
static size_t
heap_extend_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, size_t free_slots, size_t total_slots, size_t used)
@@ -2417,7 +2347,8 @@ heap_extend_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, size_t fre
next_used = (size_t)(used * gc_params.growth_factor);
}
else if (total_slots == 0) {
- next_used = minimum_pages_for_size_pool(objspace, size_pool);
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ next_used = (gc_params.heap_init_slots * multiple) / HEAP_PAGE_OBJ_LIMIT;
}
else {
/* Find `f' where free_slots = f * total_slots * goal_ratio
@@ -2472,14 +2403,9 @@ heap_increment(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *he
static void
gc_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
{
- unsigned int lock_lev;
- gc_enter(objspace, gc_enter_event_continue, &lock_lev);
-
/* Continue marking if in incremental marking. */
- if (is_incremental_marking(objspace)) {
- if (gc_marks_continue(objspace, size_pool, heap)) {
- gc_sweep(objspace);
- }
+ if (heap->free_pages == NULL && is_incremental_marking(objspace)) {
+ gc_marks_continue(objspace, size_pool, heap);
}
/* Continue sweeping if in lazy sweeping or the previous incremental
@@ -2487,8 +2413,6 @@ gc_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
if (heap->free_pages == NULL && is_lazy_sweeping(objspace)) {
gc_sweep_continue(objspace, size_pool, heap);
}
-
- gc_exit(objspace, gc_enter_event_continue, &lock_lev);
}
static void
@@ -2544,17 +2468,23 @@ rb_objspace_set_event_hook(const rb_event_flag_t event)
{
rb_objspace_t *objspace = &rb_objspace;
objspace->hook_events = event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK;
- objspace->flags.has_newobj_hook = !!(objspace->hook_events & RUBY_INTERNAL_EVENT_NEWOBJ);
+ objspace->flags.has_hook = (objspace->hook_events != 0);
}
static void
gc_event_hook_body(rb_execution_context_t *ec, rb_objspace_t *objspace, const rb_event_flag_t event, VALUE data)
{
if (UNLIKELY(!ec->cfp)) return;
+ const VALUE *pc = ec->cfp->pc;
+ if (pc && VM_FRAME_RUBYFRAME_P(ec->cfp)) {
+ /* increment PC because source line is calculated with PC-1 */
+ ec->cfp->pc++;
+ }
EXEC_EVENT_HOOK(ec, event, ec->cfp->self, 0, 0, 0, data);
+ ec->cfp->pc = pc;
}
-#define gc_event_newobj_hook_needed_p(objspace) ((objspace)->flags.has_newobj_hook)
+#define gc_event_hook_available_p(objspace) ((objspace)->flags.has_hook)
#define gc_event_hook_needed_p(objspace, event) ((objspace)->hook_events & (event))
#define gc_event_hook_prep(objspace, event, data, prep) do { \
@@ -2577,11 +2507,6 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
p->as.basic.flags = flags;
*((VALUE *)&p->as.basic.klass) = klass;
- int t = flags & RUBY_T_MASK;
- if (t == T_CLASS || t == T_MODULE || t == T_ICLASS) {
- RVALUE_AGE_SET_CANDIDATE(objspace, obj);
- }
-
#if RACTOR_CHECK_MODE
rb_ractor_setup_belonging(obj);
#endif
@@ -2598,7 +2523,13 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
GC_ASSERT(RVALUE_OLD_P(obj) == FALSE);
GC_ASSERT(RVALUE_WB_UNPROTECTED(obj) == FALSE);
- if (RVALUE_REMEMBERED((VALUE)obj)) rb_bug("newobj: %s is remembered.", obj_info(obj));
+ if (flags & FL_PROMOTED1) {
+ if (RVALUE_AGE(obj) != 2) rb_bug("newobj: %s of age (%d) != 2.", obj_info(obj), RVALUE_AGE(obj));
+ }
+ else {
+ if (RVALUE_AGE(obj) > 0) rb_bug("newobj: %s of age (%d) > 0.", obj_info(obj), RVALUE_AGE(obj));
+ }
+ if (rgengc_remembered(objspace, (VALUE)obj)) rb_bug("newobj: %s is remembered.", obj_info(obj));
}
RB_VM_LOCK_LEAVE_NO_BARRIER();
#endif
@@ -2608,6 +2539,9 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
}
+ // TODO: make it atomic, or ractor local
+ objspace->total_allocated_objects++;
+
#if RGENGC_PROFILE
if (wb_protected) {
objspace->profile.total_generated_normal_object_count++;
@@ -2630,6 +2564,24 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
gc_report(5, objspace, "newobj: %s\n", obj_info(obj));
+#if RGENGC_OLD_NEWOBJ_CHECK > 0
+ {
+ static int newobj_cnt = RGENGC_OLD_NEWOBJ_CHECK;
+
+ if (!is_incremental_marking(objspace) &&
+ flags & FL_WB_PROTECTED && /* do not promote WB unprotected objects */
+ ! RB_TYPE_P(obj, T_ARRAY)) { /* array.c assumes that allocated objects are new */
+ if (--newobj_cnt == 0) {
+ newobj_cnt = RGENGC_OLD_NEWOBJ_CHECK;
+
+ gc_mark_set(objspace, obj);
+ RVALUE_AGE_SET_OLD(objspace, obj);
+
+ rb_gc_writebarrier_remember(obj);
+ }
+ }
+ }
+#endif
// RUBY_DEBUG_LOG("obj:%p (%s)", (void *)obj, obj_type_name(obj));
return obj;
}
@@ -2676,6 +2628,7 @@ ractor_cache_allocate_slot(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *ca
rb_ractor_newobj_size_pool_cache_t *size_pool_cache = &cache->size_pool_caches[size_pool_idx];
RVALUE *p = size_pool_cache->freelist;
+#if GC_ENABLE_INCREMENTAL_MARK
if (is_incremental_marking(objspace)) {
// Not allowed to allocate without running an incremental marking step
if (cache->incremental_mark_step_allocated_slots >= INCREMENTAL_MARK_STEP_ALLOCATIONS) {
@@ -2686,12 +2639,17 @@ ractor_cache_allocate_slot(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *ca
cache->incremental_mark_step_allocated_slots++;
}
}
+#endif
if (p) {
VALUE obj = (VALUE)p;
MAYBE_UNUSED(const size_t) stride = size_pool_slot_size(size_pool_idx);
size_pool_cache->freelist = p->as.free.next;
+#if USE_RVARGC
asan_unpoison_memory_region(p, stride, true);
+#else
+ asan_unpoison_object(obj, true);
+#endif
#if RGENGC_CHECK_MODE
GC_ASSERT(rb_gc_obj_slot_size(obj) == stride);
// zero clear
@@ -2761,6 +2719,7 @@ newobj_fill(VALUE obj, VALUE v1, VALUE v2, VALUE v3)
static inline size_t
size_pool_idx_for_size(size_t size)
{
+#if USE_RVARGC
size += RVALUE_OVERHEAD;
size_t slot_count = CEILDIV(size, BASE_SLOT_SIZE);
@@ -2779,6 +2738,10 @@ size_pool_idx_for_size(size_t size)
#endif
return size_pool_idx;
+#else
+ GC_ASSERT(size <= sizeof(RVALUE));
+ return 0;
+#endif
}
static VALUE
@@ -2803,13 +2766,15 @@ newobj_alloc(rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx, boo
{
ASSERT_vm_locking();
+#if GC_ENABLE_INCREMENTAL_MARK
if (is_incremental_marking(objspace)) {
- gc_continue(objspace, size_pool, heap);
+ gc_marks_continue(objspace, size_pool, heap);
cache->incremental_mark_step_allocated_slots = 0;
// Retry allocation after resetting incremental_mark_step_allocated_slots
obj = ractor_cache_allocate_slot(objspace, cache, size_pool_idx);
}
+#endif
if (obj == Qfalse) {
// Get next free page (possibly running GC)
@@ -2828,8 +2793,6 @@ newobj_alloc(rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx, boo
}
}
- size_pool->total_allocated_objects++;
-
return obj;
}
@@ -2864,6 +2827,9 @@ newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_t *
}
obj = newobj_alloc(objspace, cr, size_pool_idx, true);
+#if SHAPE_IN_BASIC_FLAGS
+ flags |= (VALUE)(size_pool_idx) << SHAPE_FLAG_SHIFT;
+#endif
newobj_init(klass, flags, wb_protected, objspace, obj);
gc_event_hook_prep(objspace, RUBY_INTERNAL_EVENT_NEWOBJ, obj, newobj_zero_slot(obj));
@@ -2899,24 +2865,25 @@ newobj_of0(VALUE klass, VALUE flags, int wb_protected, rb_ractor_t *cr, size_t a
RB_DEBUG_COUNTER_INC(obj_newobj);
(void)RB_DEBUG_COUNTER_INC_IF(obj_newobj_wb_unprotected, !wb_protected);
+#if GC_DEBUG_STRESS_TO_CLASS
if (UNLIKELY(stress_to_class)) {
long i, cnt = RARRAY_LEN(stress_to_class);
for (i = 0; i < cnt; ++i) {
if (klass == RARRAY_AREF(stress_to_class, i)) rb_memerror();
}
}
+#endif
size_t size_pool_idx = size_pool_idx_for_size(alloc_size);
- if (SHAPE_IN_BASIC_FLAGS || (flags & RUBY_T_MASK) == T_OBJECT) {
- flags |= (VALUE)size_pool_idx << SHAPE_FLAG_SHIFT;
- }
-
if (!UNLIKELY(during_gc ||
ruby_gc_stressful ||
- gc_event_newobj_hook_needed_p(objspace)) &&
+ gc_event_hook_available_p(objspace)) &&
wb_protected) {
obj = newobj_alloc(objspace, cr, size_pool_idx, false);
+#if SHAPE_IN_BASIC_FLAGS
+ flags |= (VALUE)size_pool_idx << SHAPE_FLAG_SHIFT;
+#endif
newobj_init(klass, flags, wb_protected, objspace, obj);
}
else {
@@ -2931,7 +2898,14 @@ newobj_of0(VALUE klass, VALUE flags, int wb_protected, rb_ractor_t *cr, size_t a
}
static inline VALUE
-newobj_of(rb_ractor_t *cr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, int wb_protected, size_t alloc_size)
+newobj_of(VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, int wb_protected, size_t alloc_size)
+{
+ VALUE obj = newobj_of0(klass, flags, wb_protected, GET_RACTOR(), alloc_size);
+ return newobj_fill(obj, v1, v2, v3);
+}
+
+static inline VALUE
+newobj_of_cr(rb_ractor_t *cr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, int wb_protected, size_t alloc_size)
{
VALUE obj = newobj_of0(klass, flags, wb_protected, cr, alloc_size);
return newobj_fill(obj, v1, v2, v3);
@@ -2941,14 +2915,21 @@ VALUE
rb_wb_unprotected_newobj_of(VALUE klass, VALUE flags, size_t size)
{
GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
- return newobj_of(GET_RACTOR(), klass, flags, 0, 0, 0, FALSE, size);
+ return newobj_of(klass, flags, 0, 0, 0, FALSE, size);
}
VALUE
-rb_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags, size_t size)
+rb_wb_protected_newobj_of(VALUE klass, VALUE flags, size_t size)
{
GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
- return newobj_of(rb_ec_ractor_ptr(ec), klass, flags, 0, 0, 0, TRUE, size);
+ return newobj_of(klass, flags, 0, 0, 0, TRUE, size);
+}
+
+VALUE
+rb_ec_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags, size_t size)
+{
+ GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
+ return newobj_of_cr(rb_ec_ractor_ptr(ec), klass, flags, 0, 0, 0, TRUE, size);
}
/* for compatibility */
@@ -2956,7 +2937,7 @@ rb_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags,
VALUE
rb_newobj(void)
{
- return newobj_of(GET_RACTOR(), 0, T_NONE, 0, 0, 0, FALSE, RVALUE_SIZE);
+ return newobj_of(0, T_NONE, 0, 0, 0, FALSE, RVALUE_SIZE);
}
static size_t
@@ -2972,15 +2953,20 @@ rb_class_instance_allocate_internal(VALUE klass, VALUE flags, bool wb_protected)
GC_ASSERT(flags & ROBJECT_EMBED);
size_t size;
+#if USE_RVARGC
uint32_t index_tbl_num_entries = RCLASS_EXT(klass)->max_iv_count;
size = rb_obj_embedded_size(index_tbl_num_entries);
if (!rb_gc_size_allocatable_p(size)) {
size = sizeof(struct RObject);
}
+#else
+ size = sizeof(struct RObject);
+#endif
- VALUE obj = newobj_of(GET_RACTOR(), klass, flags, 0, 0, 0, wb_protected, size);
- RUBY_ASSERT(rb_shape_get_shape(obj)->type == SHAPE_ROOT);
+ VALUE obj = newobj_of(klass, flags, 0, 0, 0, wb_protected, size);
+ RUBY_ASSERT(rb_shape_get_shape(obj)->type == SHAPE_ROOT ||
+ rb_shape_get_shape(obj)->type == SHAPE_INITIAL_CAPACITY);
// Set the shape to the specific T_OBJECT shape which is always
// SIZE_POOL_COUNT away from the root shape.
@@ -3004,7 +2990,7 @@ rb_newobj_of(VALUE klass, VALUE flags)
return rb_class_instance_allocate_internal(klass, (flags | ROBJECT_EMBED) & ~FL_WB_PROTECTED, flags & FL_WB_PROTECTED);
}
else {
- return newobj_of(GET_RACTOR(), klass, flags & ~FL_WB_PROTECTED, 0, 0, 0, flags & FL_WB_PROTECTED, RVALUE_SIZE);
+ return newobj_of(klass, flags & ~FL_WB_PROTECTED, 0, 0, 0, flags & FL_WB_PROTECTED, RVALUE_SIZE);
}
}
@@ -3044,7 +3030,7 @@ rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0)
{
size_t size = RVALUE_SIZE;
VALUE flags = T_IMEMO | (type << FL_USHIFT);
- return newobj_of(GET_RACTOR(), v0, flags, v1, v2, v3, TRUE, size);
+ return newobj_of(v0, flags, v1, v2, v3, TRUE, size);
}
static VALUE
@@ -3052,7 +3038,7 @@ rb_imemo_tmpbuf_new(VALUE v1, VALUE v2, VALUE v3, VALUE v0)
{
size_t size = sizeof(struct rb_imemo_tmpbuf_struct);
VALUE flags = T_IMEMO | (imemo_tmpbuf << FL_USHIFT);
- return newobj_of(GET_RACTOR(), v0, flags, v1, v2, v3, FALSE, size);
+ return newobj_of(v0, flags, v1, v2, v3, FALSE, size);
}
static VALUE
@@ -3111,7 +3097,7 @@ rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0,
}
#endif
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_class_allocate_instance(VALUE klass)
{
return rb_class_instance_allocate_internal(klass, T_OBJECT | ROBJECT_EMBED, RGENGC_WB_PROTECTED_OBJECT);
@@ -3131,7 +3117,7 @@ rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FU
{
RUBY_ASSERT_ALWAYS(dfree != (RUBY_DATA_FUNC)1);
if (klass) rb_data_object_check(klass);
- return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)dmark, (VALUE)dfree, (VALUE)datap, !dmark, sizeof(struct RTypedData));
+ return newobj_of(klass, T_DATA, (VALUE)dmark, (VALUE)dfree, (VALUE)datap, FALSE, sizeof(struct RTypedData));
}
VALUE
@@ -3142,42 +3128,18 @@ rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_
return obj;
}
-static VALUE
-typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_t *type, size_t size)
-{
- RBIMPL_NONNULL_ARG(type);
- if (klass) rb_data_object_check(klass);
- bool wb_protected = (type->flags & RUBY_FL_WB_PROTECTED) || !type->function.dmark;
- return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)type, 1 | typed_flag, (VALUE)datap, wb_protected, size);
-}
-
VALUE
rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type)
{
- if (UNLIKELY(type->flags & RUBY_TYPED_EMBEDDABLE)) {
- rb_raise(rb_eTypeError, "Cannot wrap an embeddable TypedData");
- }
-
- return typed_data_alloc(klass, 0, datap, type, sizeof(struct RTypedData));
+ RBIMPL_NONNULL_ARG(type);
+ if (klass) rb_data_object_check(klass);
+ return newobj_of(klass, T_DATA, (VALUE)type, (VALUE)1, (VALUE)datap, type->flags & RUBY_FL_WB_PROTECTED, sizeof(struct RTypedData));
}
VALUE
rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type)
{
- if (type->flags & RUBY_TYPED_EMBEDDABLE) {
- if (!(type->flags & RUBY_TYPED_FREE_IMMEDIATELY)) {
- rb_raise(rb_eTypeError, "Embeddable TypedData must be freed immediately");
- }
-
- size_t embed_size = offsetof(struct RTypedData, data) + size;
- if (rb_gc_size_allocatable_p(embed_size)) {
- VALUE obj = typed_data_alloc(klass, TYPED_DATA_EMBEDDED, 0, type, embed_size);
- memset((char *)obj + offsetof(struct RTypedData, data), 0, size);
- return obj;
- }
- }
-
- VALUE obj = typed_data_alloc(klass, 0, NULL, type, sizeof(struct RTypedData));
+ VALUE obj = rb_data_typed_object_wrap(klass, 0, type);
DATA_PTR(obj) = xcalloc(1, size);
return obj;
}
@@ -3185,23 +3147,14 @@ rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type
size_t
rb_objspace_data_type_memsize(VALUE obj)
{
- size_t size = 0;
if (RTYPEDDATA_P(obj)) {
const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
- const void *ptr = RTYPEDDATA_GET_DATA(obj);
-
- if (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_EMBEDDABLE && !RTYPEDDATA_EMBEDDED_P(obj)) {
-#ifdef HAVE_MALLOC_USABLE_SIZE
- size += malloc_usable_size((void *)ptr);
-#endif
- }
-
+ const void *ptr = RTYPEDDATA_DATA(obj);
if (ptr && type->function.dsize) {
- size += type->function.dsize(ptr);
+ return type->function.dsize(ptr);
}
}
-
- return size;
+ return 0;
}
const char *
@@ -3325,8 +3278,6 @@ vm_ccs_free(struct rb_class_cc_entries *ccs, int alive, rb_objspace_t *objspace,
asan_poison_object((VALUE)cc);
}
}
-
- VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
vm_cc_invalidate(cc);
}
ruby_xfree(ccs->entries);
@@ -3464,53 +3415,8 @@ obj_free_object_id(rb_objspace_t *objspace, VALUE obj)
st_delete(objspace->id_to_obj_tbl, &id, NULL);
}
else {
- rb_bug("Object ID seen, but not in mapping table: %s", obj_info(obj));
- }
-}
-
-static bool
-rb_data_free(rb_objspace_t *objspace, VALUE obj)
-{
- void *data = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
- if (data) {
- int free_immediately = false;
- void (*dfree)(void *);
-
- if (RTYPEDDATA_P(obj)) {
- free_immediately = (RANY(obj)->as.typeddata.type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
- dfree = RANY(obj)->as.typeddata.type->function.dfree;
- }
- else {
- dfree = RANY(obj)->as.data.dfree;
- }
-
- if (dfree) {
- if (dfree == RUBY_DEFAULT_FREE) {
- if (!RTYPEDDATA_EMBEDDED_P(obj)) {
- xfree(data);
- RB_DEBUG_COUNTER_INC(obj_data_xfree);
- }
- }
- else if (free_immediately) {
- (*dfree)(data);
- if (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_EMBEDDABLE && !RTYPEDDATA_EMBEDDED_P(obj)) {
- xfree(data);
- }
-
- RB_DEBUG_COUNTER_INC(obj_data_imm_free);
- }
- else {
- make_zombie(objspace, obj, dfree, data);
- RB_DEBUG_COUNTER_INC(obj_data_zombie);
- return FALSE;
- }
- }
- else {
- RB_DEBUG_COUNTER_INC(obj_data_empty);
- }
+ rb_bug("Object ID seen, but not in mapping table: %s\n", obj_info(obj));
}
-
- return true;
}
static int
@@ -3561,6 +3467,9 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
else if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
RB_DEBUG_COUNTER_INC(obj_obj_embed);
}
+ else if (ROBJ_TRANSIENT_P(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_obj_transient);
+ }
else {
xfree(RANY(obj)->as.object.as.heap.ivptr);
RB_DEBUG_COUNTER_INC(obj_obj_ptr);
@@ -3570,13 +3479,9 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
case T_CLASS:
rb_id_table_free(RCLASS_M_TBL(obj));
cc_table_free(objspace, obj, FALSE);
- if (rb_shape_obj_too_complex(obj)) {
- st_free_table((st_table *)RCLASS_IVPTR(obj));
- }
- else if (RCLASS_IVPTR(obj)) {
+ if (RCLASS_IVPTR(obj)) {
xfree(RCLASS_IVPTR(obj));
}
-
if (RCLASS_CONST_TBL(obj)) {
rb_free_const_table(RCLASS_CONST_TBL(obj));
}
@@ -3591,6 +3496,11 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
xfree(RCLASS_SUPERCLASSES(obj));
}
+#if SIZE_POOL_COUNT == 1
+ if (RCLASS_EXT(obj))
+ xfree(RCLASS_EXT(obj));
+#endif
+
(void)RB_DEBUG_COUNTER_INC_IF(obj_module_ptr, BUILTIN_TYPE(obj) == T_MODULE);
(void)RB_DEBUG_COUNTER_INC_IF(obj_class_ptr, BUILTIN_TYPE(obj) == T_CLASS);
break;
@@ -3641,8 +3551,22 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
RB_DEBUG_COUNTER_INC(obj_hash_st);
}
#endif
+ if (/* RHASH_AR_TABLE_P(obj) */ !FL_TEST_RAW(obj, RHASH_ST_TABLE_FLAG)) {
+ struct ar_table_struct *tab = RHASH(obj)->as.ar;
- rb_hash_free(obj);
+ if (tab) {
+ if (RHASH_TRANSIENT_P(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_hash_transient);
+ }
+ else {
+ ruby_xfree(tab);
+ }
+ }
+ }
+ else {
+ GC_ASSERT(RHASH_ST_TABLE_P(obj));
+ st_free_table(RHASH(obj)->as.st);
+ }
break;
case T_REGEXP:
if (RANY(obj)->as.regexp.ptr) {
@@ -3651,11 +3575,46 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
}
break;
case T_DATA:
- if (!rb_data_free(objspace, obj)) return false;
+ if (DATA_PTR(obj)) {
+ int free_immediately = FALSE;
+ void (*dfree)(void *);
+ void *data = DATA_PTR(obj);
+
+ if (RTYPEDDATA_P(obj)) {
+ free_immediately = (RANY(obj)->as.typeddata.type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
+ dfree = RANY(obj)->as.typeddata.type->function.dfree;
+ if (0 && free_immediately == 0) {
+ /* to expose non-free-immediate T_DATA */
+ fprintf(stderr, "not immediate -> %s\n", RANY(obj)->as.typeddata.type->wrap_struct_name);
+ }
+ }
+ else {
+ dfree = RANY(obj)->as.data.dfree;
+ }
+
+ if (dfree) {
+ if (dfree == RUBY_DEFAULT_FREE) {
+ xfree(data);
+ RB_DEBUG_COUNTER_INC(obj_data_xfree);
+ }
+ else if (free_immediately) {
+ (*dfree)(data);
+ RB_DEBUG_COUNTER_INC(obj_data_imm_free);
+ }
+ else {
+ make_zombie(objspace, obj, dfree, data);
+ RB_DEBUG_COUNTER_INC(obj_data_zombie);
+ return FALSE;
+ }
+ }
+ else {
+ RB_DEBUG_COUNTER_INC(obj_data_empty);
+ }
+ }
break;
case T_MATCH:
- {
- rb_matchext_t *rm = RMATCH_EXT(obj);
+ if (RANY(obj)->as.match.rmatch) {
+ struct rmatch *rm = RANY(obj)->as.match.rmatch;
#if USE_DEBUG_COUNTER
if (rm->regs.num_regs >= 8) {
RB_DEBUG_COUNTER_INC(obj_match_ge8);
@@ -3670,6 +3629,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
onig_region_free(&rm->regs, 0);
if (rm->char_offset)
xfree(rm->char_offset);
+ xfree(rm);
RB_DEBUG_COUNTER_INC(obj_match_ptr);
}
@@ -3702,6 +3662,9 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
cc_table_free(objspace, obj, FALSE);
rb_class_remove_from_module_subclasses(obj);
rb_class_remove_from_super_subclasses(obj);
+#if !RCLASS_EXT_EMBEDDED
+ xfree(RCLASS_EXT(obj));
+#endif
RB_DEBUG_COUNTER_INC(obj_iclass_ptr);
break;
@@ -3729,6 +3692,9 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
RANY(obj)->as.rstruct.as.heap.ptr == NULL) {
RB_DEBUG_COUNTER_INC(obj_struct_embed);
}
+ else if (RSTRUCT_TRANSIENT_P(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_struct_transient);
+ }
else {
xfree((void *)RANY(obj)->as.rstruct.as.heap.ptr);
RB_DEBUG_COUNTER_INC(obj_struct_ptr);
@@ -3784,15 +3750,8 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
RB_DEBUG_COUNTER_INC(obj_imemo_parser_strterm);
break;
case imemo_callinfo:
- {
- const struct rb_callinfo * ci = ((const struct rb_callinfo *)obj);
- if (ci->kwarg) {
- ((struct rb_callinfo_kwarg *)ci->kwarg)->references--;
- if (ci->kwarg->references == 0) xfree((void *)ci->kwarg);
- }
- RB_DEBUG_COUNTER_INC(obj_imemo_callinfo);
- break;
- }
+ RB_DEBUG_COUNTER_INC(obj_imemo_callinfo);
+ break;
case imemo_callcache:
RB_DEBUG_COUNTER_INC(obj_imemo_callcache);
break;
@@ -3864,14 +3823,13 @@ Init_heap(void)
objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
#endif
- /* Set size pools allocatable pages. */
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- rb_size_pool_t *size_pool = &size_pools[i];
+ heap_add_pages(objspace, &size_pools[0], SIZE_POOL_EDEN_HEAP(&size_pools[0]), gc_params.heap_init_slots / HEAP_PAGE_OBJ_LIMIT);
- /* Set the default value of size_pool_init_slots. */
- gc_params.size_pool_init_slots[i] = GC_HEAP_INIT_SLOTS;
-
- size_pool->allocatable_pages = minimum_pages_for_size_pool(objspace, size_pool);
+ /* Give other size pools allocatable pages. */
+ for (int i = 1; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ size_pool->allocatable_pages = gc_params.heap_init_slots * multiple / HEAP_PAGE_OBJ_LIMIT;
}
heap_pages_expand_sorted(objspace);
@@ -3918,7 +3876,11 @@ objspace_each_objects_ensure(VALUE arg)
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
struct heap_page **pages = data->pages[i];
- free(pages);
+ /* pages could be NULL if an error was raised during setup (e.g.
+ * malloc failed due to out of memory). */
+ if (pages) {
+ free(pages);
+ }
}
return Qnil;
@@ -4000,16 +3962,14 @@ objspace_each_objects_try(VALUE arg)
*
* This is a sample callback code to iterate liveness objects:
*
- * static int
- * sample_callback(void *vstart, void *vend, int stride, void *data)
- * {
- * VALUE v = (VALUE)vstart;
- * for (; v != (VALUE)vend; v += stride) {
- * if (!rb_objspace_internal_object_p(v)) { // liveness check
- * // do something with live object 'v'
- * }
- * }
- * return 0; // continue to iteration
+ * int
+ * sample_callback(void *vstart, void *vend, int stride, void *data) {
+ * VALUE v = (VALUE)vstart;
+ * for (; v != (VALUE)vend; v += stride) {
+ * if (RBASIC(v)->flags) { // liveness check
+ * // do something with live object 'v'
+ * }
+ * return 0; // continue to iteration
* }
*
* Note: 'vstart' is not a top of heap_page. This point the first
@@ -4227,45 +4187,6 @@ should_be_finalizable(VALUE obj)
rb_check_frozen(obj);
}
-VALUE
-rb_define_finalizer_no_check(VALUE obj, VALUE block)
-{
- rb_objspace_t *objspace = &rb_objspace;
- VALUE table;
- st_data_t data;
-
- RBASIC(obj)->flags |= FL_FINALIZE;
-
- if (st_lookup(finalizer_table, obj, &data)) {
- table = (VALUE)data;
-
- /* avoid duplicate block, table is usually small */
- {
- long len = RARRAY_LEN(table);
- long i;
-
- for (i = 0; i < len; i++) {
- VALUE recv = RARRAY_AREF(table, i);
- if (rb_equal(recv, block)) {
- block = recv;
- goto end;
- }
- }
- }
-
- rb_ary_push(table, block);
- }
- else {
- table = rb_ary_new3(1, block);
- RBASIC_CLEAR_CLASS(table);
- st_add_direct(finalizer_table, obj, table);
- }
- end:
- block = rb_ary_new3(2, INT2FIX(0), block);
- OBJ_FREEZE(block);
- return block;
-}
-
/*
* call-seq:
* ObjectSpace.define_finalizer(obj, aProc=proc())
@@ -4346,7 +4267,46 @@ define_final(int argc, VALUE *argv, VALUE os)
rb_warn("finalizer references object to be finalized");
}
- return rb_define_finalizer_no_check(obj, block);
+ return define_final0(obj, block);
+}
+
+static VALUE
+define_final0(VALUE obj, VALUE block)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE table;
+ st_data_t data;
+
+ RBASIC(obj)->flags |= FL_FINALIZE;
+
+ if (st_lookup(finalizer_table, obj, &data)) {
+ table = (VALUE)data;
+
+ /* avoid duplicate block, table is usually small */
+ {
+ long len = RARRAY_LEN(table);
+ long i;
+
+ for (i = 0; i < len; i++) {
+ VALUE recv = RARRAY_AREF(table, i);
+ if (rb_equal(recv, block)) {
+ block = recv;
+ goto end;
+ }
+ }
+ }
+
+ rb_ary_push(table, block);
+ }
+ else {
+ table = rb_ary_new3(1, block);
+ RBASIC_CLEAR_CLASS(table);
+ st_add_direct(finalizer_table, obj, table);
+ }
+ end:
+ block = rb_ary_new3(2, INT2FIX(0), block);
+ OBJ_FREEZE(block);
+ return block;
}
VALUE
@@ -4354,7 +4314,7 @@ rb_define_finalizer(VALUE obj, VALUE block)
{
should_be_finalizable(obj);
should_be_callable(block);
- return rb_define_finalizer_no_check(obj, block);
+ return define_final0(obj, block);
}
void
@@ -4398,16 +4358,20 @@ run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
VALUE objid;
VALUE final;
rb_control_frame_t *cfp;
+ VALUE *sp;
long finished;
} saved;
+
rb_execution_context_t * volatile ec = GET_EC();
#define RESTORE_FINALIZER() (\
ec->cfp = saved.cfp, \
+ ec->cfp->sp = saved.sp, \
ec->errinfo = saved.errinfo)
saved.errinfo = ec->errinfo;
saved.objid = rb_obj_id(obj);
saved.cfp = ec->cfp;
+ saved.sp = ec->cfp->sp;
saved.finished = 0;
saved.final = Qundef;
@@ -4467,7 +4431,7 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
page->final_slots--;
page->free_slots++;
heap_page_add_freeobj(objspace, page, zombie);
- page->size_pool->total_freed_objects++;
+ objspace->profile.total_freed_objects++;
}
RB_VM_LOCK_LEAVE();
@@ -4589,8 +4553,16 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
if (rb_obj_is_mutex(vp)) break;
if (rb_obj_is_fiber(vp)) break;
if (rb_obj_is_main_ractor(vp)) break;
-
- rb_data_free(objspace, vp);
+ if (RTYPEDDATA_P(vp)) {
+ RDATA(p)->dfree = RANY(p)->as.typeddata.type->function.dfree;
+ }
+ RANY(p)->as.free.flags = 0;
+ if (RANY(p)->as.data.dfree == RUBY_DEFAULT_FREE) {
+ xfree(DATA_PTR(p));
+ }
+ else if (RANY(p)->as.data.dfree) {
+ make_zombie(objspace, vp, RANY(p)->as.data.dfree, RANY(p)->as.data.data);
+ }
break;
case T_FILE:
if (RANY(p)->as.file.fptr) {
@@ -4617,7 +4589,7 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
}
static inline int
-is_swept_object(VALUE ptr)
+is_swept_object(rb_objspace_t *objspace, VALUE ptr)
{
struct heap_page *page = GET_HEAP_PAGE(ptr);
return page->flags.before_sweep ? FALSE : TRUE;
@@ -4628,7 +4600,7 @@ static inline int
is_garbage_object(rb_objspace_t *objspace, VALUE ptr)
{
if (!is_lazy_sweeping(objspace) ||
- is_swept_object(ptr) ||
+ is_swept_object(objspace, ptr) ||
MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(ptr), ptr)) {
return FALSE;
@@ -4659,7 +4631,7 @@ is_live_object(rb_objspace_t *objspace, VALUE ptr)
}
static inline int
-is_markable_object(VALUE obj)
+is_markable_object(rb_objspace_t *objspace, VALUE obj)
{
if (rb_special_const_p(obj)) return FALSE; /* special const is not markable */
check_rvalue_consistency(obj);
@@ -4670,7 +4642,7 @@ int
rb_objspace_markable_object_p(VALUE obj)
{
rb_objspace_t *objspace = &rb_objspace;
- return is_markable_object(obj) && is_live_object(objspace, obj);
+ return is_markable_object(objspace, obj) && is_live_object(objspace, obj);
}
int
@@ -4680,18 +4652,9 @@ rb_objspace_garbage_object_p(VALUE obj)
return is_garbage_object(objspace, obj);
}
-bool
-rb_gc_is_ptr_to_obj(void *ptr)
-{
- rb_objspace_t *objspace = &rb_objspace;
- return is_pointer_to_heap(objspace, ptr);
-}
-
-VALUE
-rb_gc_id2ref_obj_tbl(VALUE objid)
+static VALUE
+id2ref_obj_tbl(rb_objspace_t *objspace, VALUE objid)
{
- rb_objspace_t *objspace = &rb_objspace;
-
VALUE orig;
if (st_lookup(objspace->id_to_obj_tbl, objid, &orig)) {
return orig;
@@ -4748,7 +4711,7 @@ id2ref(VALUE objid)
}
}
- if (!UNDEF_P(orig = rb_gc_id2ref_obj_tbl(objid)) &&
+ if (!UNDEF_P(orig = id2ref_obj_tbl(objspace, objid)) &&
is_live_object(objspace, orig)) {
if (!rb_multi_ractor_p() || rb_ractor_shareable_p(orig)) {
@@ -4822,21 +4785,16 @@ cached_object_id(VALUE obj)
}
static VALUE
-nonspecial_obj_id(VALUE obj)
+nonspecial_obj_id_(VALUE obj)
{
-#if SIZEOF_LONG == SIZEOF_VOIDP
- return (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG);
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
- return LL2NUM((SIGNED_VALUE)(obj) / 2);
-#else
-# error not supported
-#endif
+ return nonspecial_obj_id(obj);
}
+
VALUE
rb_memory_id(VALUE obj)
{
- return rb_find_object_id(obj, nonspecial_obj_id);
+ return rb_find_object_id(obj, nonspecial_obj_id_);
}
/*
@@ -4943,22 +4901,27 @@ obj_memsize_of(VALUE obj, int use_all_types)
break;
case T_MODULE:
case T_CLASS:
- if (RCLASS_M_TBL(obj)) {
- size += rb_id_table_memsize(RCLASS_M_TBL(obj));
- }
- // class IV sizes are allocated as powers of two
- size += SIZEOF_VALUE << bit_length(RCLASS_IV_COUNT(obj));
- if (RCLASS_CVC_TBL(obj)) {
- size += rb_id_table_memsize(RCLASS_CVC_TBL(obj));
- }
- if (RCLASS_EXT(obj)->const_tbl) {
- size += rb_id_table_memsize(RCLASS_EXT(obj)->const_tbl);
- }
- if (RCLASS_CC_TBL(obj)) {
- size += cc_table_memsize(RCLASS_CC_TBL(obj));
- }
- if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
- size += (RCLASS_SUPERCLASS_DEPTH(obj) + 1) * sizeof(VALUE);
+ if (RCLASS_EXT(obj)) {
+ if (RCLASS_M_TBL(obj)) {
+ size += rb_id_table_memsize(RCLASS_M_TBL(obj));
+ }
+ // class IV sizes are allocated as powers of two
+ size += SIZEOF_VALUE << bit_length(RCLASS_IV_COUNT(obj));
+ if (RCLASS_CVC_TBL(obj)) {
+ size += rb_id_table_memsize(RCLASS_CVC_TBL(obj));
+ }
+ if (RCLASS_EXT(obj)->const_tbl) {
+ size += rb_id_table_memsize(RCLASS_EXT(obj)->const_tbl);
+ }
+ if (RCLASS_CC_TBL(obj)) {
+ size += cc_table_memsize(RCLASS_CC_TBL(obj));
+ }
+ if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
+ size += (RCLASS_SUPERCLASS_DEPTH(obj) + 1) * sizeof(VALUE);
+ }
+#if SIZE_POOL_COUNT == 1
+ size += sizeof(rb_classext_t);
+#endif
}
break;
case T_ICLASS:
@@ -4967,7 +4930,7 @@ obj_memsize_of(VALUE obj, int use_all_types)
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
}
}
- if (RCLASS_CC_TBL(obj)) {
+ if (RCLASS_EXT(obj) && RCLASS_CC_TBL(obj)) {
size += cc_table_memsize(RCLASS_CC_TBL(obj));
}
break;
@@ -4978,10 +4941,15 @@ obj_memsize_of(VALUE obj, int use_all_types)
size += rb_ary_memsize(obj);
break;
case T_HASH:
- if (RHASH_ST_TABLE_P(obj)) {
+ if (RHASH_AR_TABLE_P(obj)) {
+ if (RHASH_AR_TABLE(obj) != NULL) {
+ size_t rb_hash_ar_table_size(void);
+ size += rb_hash_ar_table_size();
+ }
+ }
+ else {
VM_ASSERT(RHASH_ST_TABLE(obj) != NULL);
- /* st_table is in the slot */
- size += st_memsize(RHASH_ST_TABLE(obj)) - sizeof(st_table);
+ size += st_memsize(RHASH_ST_TABLE(obj));
}
break;
case T_REGEXP:
@@ -4993,10 +4961,11 @@ obj_memsize_of(VALUE obj, int use_all_types)
if (use_all_types) size += rb_objspace_data_type_memsize(obj);
break;
case T_MATCH:
- {
- rb_matchext_t *rm = RMATCH_EXT(obj);
+ if (RMATCH(obj)->rmatch) {
+ struct rmatch *rm = RMATCH(obj)->rmatch;
size += onig_region_memsize(&rm->regs);
size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
+ size += sizeof(struct rmatch);
}
break;
case T_FILE:
@@ -5215,7 +5184,7 @@ objspace_available_slots(rb_objspace_t *objspace)
static size_t
objspace_live_slots(rb_objspace_t *objspace)
{
- return total_allocated_objects(objspace) - total_freed_objects(objspace) - heap_pages_final_slots;
+ return (objspace->total_allocated_objects - objspace->profile.total_freed_objects) - heap_pages_final_slots;
}
static size_t
@@ -5326,8 +5295,14 @@ gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap)
}
static void gc_update_references(rb_objspace_t * objspace);
-#if GC_CAN_COMPILE_COMPACTION
static void invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page);
+
+#ifndef GC_CAN_COMPILE_COMPACTION
+#if defined(__wasi__) /* WebAssembly doesn't support signals */
+# define GC_CAN_COMPILE_COMPACTION 0
+#else
+# define GC_CAN_COMPILE_COMPACTION 1
+#endif
#endif
#if defined(__MINGW32__) || defined(_WIN32)
@@ -5513,6 +5488,45 @@ install_handlers(void)
#endif
static void
+revert_stack_objects(VALUE stack_obj, void *ctx)
+{
+ rb_objspace_t * objspace = (rb_objspace_t*)ctx;
+
+ if (BUILTIN_TYPE(stack_obj) == T_MOVED) {
+ /* For now we'll revert the whole page if the object made it to the
+ * stack. I think we can change this to move just the one object
+ * back though */
+ invalidate_moved_page(objspace, GET_HEAP_PAGE(stack_obj));
+ }
+}
+
+static void
+revert_machine_stack_references(rb_objspace_t *objspace, VALUE v)
+{
+ if (is_pointer_to_heap(objspace, (void *)v)) {
+ if (BUILTIN_TYPE(v) == T_MOVED) {
+ /* For now we'll revert the whole page if the object made it to the
+ * stack. I think we can change this to move just the one object
+ * back though */
+ invalidate_moved_page(objspace, GET_HEAP_PAGE(v));
+ }
+ }
+}
+
+static void each_machine_stack_value(const rb_execution_context_t *ec, void (*cb)(rb_objspace_t *, VALUE));
+
+static void
+check_stack_for_moved(rb_objspace_t *objspace)
+{
+ rb_execution_context_t *ec = GET_EC();
+ rb_vm_t *vm = rb_ec_vm_ptr(ec);
+ rb_vm_each_stack_value(vm, revert_stack_objects, (void*)objspace);
+ each_machine_stack_value(ec, revert_machine_stack_references);
+}
+
+static void gc_mode_transition(rb_objspace_t *objspace, enum gc_mode mode);
+
+static void
gc_compact_finish(rb_objspace_t *objspace)
{
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
@@ -5523,6 +5537,13 @@ gc_compact_finish(rb_objspace_t *objspace)
uninstall_handlers();
+ /* The mutator is allowed to run during incremental sweeping. T_MOVED
+ * objects can get pushed on the stack and when the compaction process
+ * finishes up, it may remove the read barrier before anything has a
+ * chance to read from the T_MOVED address. To fix this, we scan the stack
+ * then revert any moved objects that made it to the stack. */
+ check_stack_for_moved(objspace);
+
gc_update_references(objspace);
objspace->profile.compact_count++;
@@ -5568,7 +5589,7 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
#if RGENGC_CHECK_MODE
if (!is_full_marking(objspace)) {
if (RVALUE_OLD_P(vp)) rb_bug("page_sweep: %p - old while minor GC.", (void *)p);
- if (RVALUE_REMEMBERED(vp)) rb_bug("page_sweep: %p - remembered.", (void *)p);
+ if (rgengc_remembered_sweep(objspace, vp)) rb_bug("page_sweep: %p - remembered.", (void *)p);
}
#endif
if (obj_free(objspace, vp)) {
@@ -5591,7 +5612,7 @@ gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bit
* The sweep cursor and compact cursor move in
* opposite directions, and when they meet references will
* get updated and "during_compacting" should get disabled */
- rb_bug("T_MOVED shouldn't be seen until compaction is finished");
+ rb_bug("T_MOVED shouldn't be seen until compaction is finished\n");
}
gc_report(3, objspace, "page_sweep: %s is added to freelist\n", obj_info(vp));
ctx->empty_slots++;
@@ -5678,7 +5699,7 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
ctx->freed_slots, ctx->empty_slots, ctx->final_slots);
sweep_page->free_slots += ctx->freed_slots + ctx->empty_slots;
- sweep_page->size_pool->total_freed_objects += ctx->freed_slots;
+ objspace->profile.total_freed_objects += ctx->freed_slots;
if (heap_pages_deferred_final && !finalizing) {
rb_thread_t *th = GET_THREAD();
@@ -5704,6 +5725,23 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
gc_report(2, objspace, "page_sweep: end.\n");
}
+#if !USE_RVARGC
+/* allocate additional minimum page to work */
+static void
+gc_heap_prepare_minimum_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ if (!heap->free_pages && heap_increment(objspace, size_pool, heap) == FALSE) {
+ /* there is no free after page_sweep() */
+ size_pool_allocatable_pages_set(objspace, size_pool, 1);
+ if (!heap_increment(objspace, size_pool, heap)) { /* can't allocate additional free objects */
+ rb_memerror();
+ }
+ }
+ }
+}
+#endif
+
static const char *
gc_mode_name(enum gc_mode mode)
{
@@ -5761,7 +5799,9 @@ gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap)
{
heap->sweeping_page = ccan_list_top(&heap->pages, struct heap_page, page_node);
heap->free_pages = NULL;
+#if GC_ENABLE_INCREMENTAL_MARK
heap->pooled_pages = NULL;
+#endif
if (!objspace->flags.immediate_sweep) {
struct heap_page *page = NULL;
@@ -5774,25 +5814,13 @@ gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap)
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
__attribute__((noinline))
#endif
-
-#if GC_CAN_COMPILE_COMPACTION
-static void gc_sort_heap_by_compare_func(rb_objspace_t *objspace, gc_compact_compare_func compare_func);
-static int compare_pinned_slots(const void *left, const void *right, void *d);
-#endif
-
static void
gc_sweep_start(rb_objspace_t *objspace)
{
gc_mode_transition(objspace, gc_mode_sweeping);
- objspace->rincgc.pooled_slots = 0;
-#if GC_CAN_COMPILE_COMPACTION
- if (objspace->flags.during_compacting) {
- gc_sort_heap_by_compare_func(
- objspace,
- objspace->rcompactor.compare_func ? objspace->rcompactor.compare_func : compare_pinned_slots
- );
- }
+#if GC_ENABLE_INCREMENTAL_MARK
+ objspace->rincgc.pooled_slots = 0;
#endif
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
@@ -5801,12 +5829,14 @@ gc_sweep_start(rb_objspace_t *objspace)
gc_sweep_start_heap(objspace, heap);
+#if USE_RVARGC
/* We should call gc_sweep_finish_size_pool for size pools with no pages. */
if (heap->sweeping_page == NULL) {
GC_ASSERT(heap->total_pages == 0);
GC_ASSERT(heap->total_slots == 0);
gc_sweep_finish_size_pool(objspace, size_pool);
}
+#endif
}
rb_ractor_t *r = NULL;
@@ -5815,6 +5845,7 @@ gc_sweep_start(rb_objspace_t *objspace)
}
}
+#if USE_RVARGC
static void
gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
{
@@ -5823,15 +5854,14 @@ gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
size_t total_pages = heap->total_pages + SIZE_POOL_TOMB_HEAP(size_pool)->total_pages;
size_t swept_slots = size_pool->freed_slots + size_pool->empty_slots;
- size_t init_slots = gc_params.size_pool_init_slots[size_pool - size_pools];
- size_t min_free_slots = (size_t)(MAX(total_slots, init_slots) * gc_params.heap_free_slots_min_ratio);
+ size_t min_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_min_ratio);
/* If we don't have enough slots and we have pages on the tomb heap, move
* pages from the tomb heap to the eden heap. This may prevent page
* creation thrashing (frequently allocating and deallocting pages) and
* GC thrashing (running GC more frequently than required). */
struct heap_page *resurrected_page;
- while (swept_slots < min_free_slots &&
+ while ((swept_slots < min_free_slots || swept_slots < gc_params.heap_init_slots) &&
(resurrected_page = heap_page_resurrect(objspace, size_pool))) {
swept_slots += resurrected_page->free_slots;
@@ -5839,20 +5869,28 @@ gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
heap_add_freepage(heap, resurrected_page);
}
+ /* Some size pools may have very few pages (or even no pages). These size pools
+ * should still have allocatable pages. */
+ if (min_free_slots < gc_params.heap_init_slots && swept_slots < gc_params.heap_init_slots) {
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ size_t extra_slots = gc_params.heap_init_slots - swept_slots;
+ size_t extend_page_count = CEILDIV(extra_slots * multiple, HEAP_PAGE_OBJ_LIMIT);
+ if (extend_page_count > size_pool->allocatable_pages) {
+ size_pool_allocatable_pages_set(objspace, size_pool, extend_page_count);
+ }
+ }
+
if (swept_slots < min_free_slots) {
bool grow_heap = is_full_marking(objspace);
- /* Consider growing or starting a major GC if we are not currently in a
- * major GC and we can't allocate any more pages. */
- if (!is_full_marking(objspace) && size_pool->allocatable_pages == 0) {
- /* The heap is a growth heap if it freed more slots than had empty slots. */
- bool is_growth_heap = size_pool->empty_slots == 0 || size_pool->freed_slots > size_pool->empty_slots;
-
- /* Grow this heap if we haven't run at least RVALUE_OLD_AGE minor
- * GC since the last major GC or if this heap is smaller than the
- * the configured initial size. */
- if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE ||
- total_slots < init_slots) {
+ if (!is_full_marking(objspace)) {
+ /* The heap is a growth heap if it freed more slots than had empty
+ * slots and used up all of its allocatable pages. */
+ bool is_growth_heap = (size_pool->empty_slots == 0 ||
+ size_pool->freed_slots > size_pool->empty_slots) &&
+ size_pool->allocatable_pages == 0;
+
+ if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
grow_heap = TRUE;
}
else if (is_growth_heap) { /* Only growth heaps are allowed to start a major GC. */
@@ -5870,6 +5908,7 @@ gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
}
}
}
+#endif
static void
gc_sweep_finish(rb_objspace_t *objspace)
@@ -5888,9 +5927,11 @@ gc_sweep_finish(rb_objspace_t *objspace)
size_pool->allocatable_pages = tomb_pages;
}
+#if USE_RVARGC
size_pool->freed_slots = 0;
size_pool->empty_slots = 0;
+#if GC_ENABLE_INCREMENTAL_MARK
if (!will_be_incremental_marking(objspace)) {
rb_heap_t *eden_heap = SIZE_POOL_EDEN_HEAP(size_pool);
struct heap_page *end_page = eden_heap->free_pages;
@@ -5904,15 +5945,13 @@ gc_sweep_finish(rb_objspace_t *objspace)
eden_heap->pooled_pages = NULL;
objspace->rincgc.pooled_slots = 0;
}
+#endif
+#endif
}
heap_pages_expand_sorted(objspace);
gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_SWEEP, 0);
gc_mode_transition(objspace, gc_mode_none);
-
-#if RGENGC_CHECK_MODE >= 2
- gc_verify_internal_consistency(objspace);
-#endif
}
static int
@@ -5920,8 +5959,19 @@ gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *hea
{
struct heap_page *sweep_page = heap->sweeping_page;
int unlink_limit = GC_SWEEP_PAGES_FREEABLE_PER_STEP;
+
+#if GC_ENABLE_INCREMENTAL_MARK
int swept_slots = 0;
- int pooled_slots = 0;
+#if USE_RVARGC
+ bool need_pool = TRUE;
+#else
+ int need_pool = will_be_incremental_marking(objspace) ? TRUE : FALSE;
+#endif
+
+ gc_report(2, objspace, "gc_sweep_step (need_pool: %d)\n", need_pool);
+#else
+ gc_report(2, objspace, "gc_sweep_step\n");
+#endif
if (sweep_page == NULL) return FALSE;
@@ -5953,12 +6003,15 @@ gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *hea
heap_add_page(objspace, size_pool, SIZE_POOL_TOMB_HEAP(size_pool), sweep_page);
}
else if (free_slots > 0) {
+#if USE_RVARGC
size_pool->freed_slots += ctx.freed_slots;
size_pool->empty_slots += ctx.empty_slots;
+#endif
- if (pooled_slots < GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT) {
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (need_pool) {
heap_add_poolpage(objspace, heap, sweep_page);
- pooled_slots += free_slots;
+ need_pool = FALSE;
}
else {
heap_add_freepage(heap, sweep_page);
@@ -5967,6 +6020,10 @@ gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *hea
break;
}
}
+#else
+ heap_add_freepage(heap, sweep_page);
+ break;
+#endif
}
else {
sweep_page->free_next = NULL;
@@ -5974,7 +6031,9 @@ gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *hea
} while ((sweep_page = heap->sweeping_page));
if (!heap->sweeping_page) {
+#if USE_RVARGC
gc_sweep_finish_size_pool(objspace, size_pool);
+#endif
if (!has_sweeping_pages(objspace)) {
gc_sweep_finish(objspace);
@@ -6006,11 +6065,13 @@ gc_sweep_continue(rb_objspace_t *objspace, rb_size_pool_t *sweep_size_pool, rb_h
GC_ASSERT(dont_gc_val() == FALSE);
if (!GC_ENABLE_LAZY_SWEEP) return;
- gc_sweeping_enter(objspace);
+ unsigned int lock_lev;
+ gc_enter(objspace, gc_enter_event_sweep_continue, &lock_lev);
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
rb_size_pool_t *size_pool = &size_pools[i];
if (!gc_sweep_step(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool))) {
+#if USE_RVARGC
/* sweep_size_pool requires a free slot but sweeping did not yield any. */
if (size_pool == sweep_size_pool) {
if (size_pool->allocatable_pages > 0) {
@@ -6022,13 +6083,13 @@ gc_sweep_continue(rb_objspace_t *objspace, rb_size_pool_t *sweep_size_pool, rb_h
break;
}
}
+#endif
}
}
- gc_sweeping_exit(objspace);
+ gc_exit(objspace, gc_enter_event_sweep_continue, &lock_lev);
}
-#if GC_CAN_COMPILE_COMPACTION
static void
invalidate_moved_plane(rb_objspace_t *objspace, struct heap_page *page, uintptr_t p, bits_t bitset)
{
@@ -6101,7 +6162,6 @@ invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page)
p += BITS_BITLENGTH * BASE_SLOT_SIZE;
}
}
-#endif
static void
gc_compact_start(rb_objspace_t *objspace)
@@ -6138,8 +6198,6 @@ static void gc_sweep_compact(rb_objspace_t *objspace);
static void
gc_sweep(rb_objspace_t *objspace)
{
- gc_sweeping_enter(objspace);
-
const unsigned int immediate_sweep = objspace->flags.immediate_sweep;
gc_report(1, objspace, "gc_sweep: immediate: %d\n", immediate_sweep);
@@ -6167,7 +6225,10 @@ gc_sweep(rb_objspace_t *objspace)
}
}
- gc_sweeping_exit(objspace);
+#if !USE_RVARGC
+ rb_size_pool_t *size_pool = &size_pools[0];
+ gc_heap_prepare_minimum_pages(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool));
+#endif
}
/* Marking - Marking stack */
@@ -6429,7 +6490,7 @@ stack_check(rb_execution_context_t *ec, int water_mark)
#define STACKFRAME_FOR_CALL_CFUNC 2048
-int
+MJIT_FUNC_EXPORTED int
rb_ec_stack_check(rb_execution_context_t *ec)
{
return stack_check(ec, STACKFRAME_FOR_CALL_CFUNC);
@@ -6469,6 +6530,16 @@ rb_gc_mark_locations(const VALUE *start, const VALUE *end)
gc_mark_locations(&rb_objspace, start, end, gc_mark_maybe);
}
+static void
+gc_mark_values(rb_objspace_t *objspace, long n, const VALUE *values)
+{
+ long i;
+
+ for (i=0; i<n; i++) {
+ gc_mark(objspace, values[i]);
+ }
+}
+
void
rb_gc_mark_values(long n, const VALUE *values)
{
@@ -6476,7 +6547,7 @@ rb_gc_mark_values(long n, const VALUE *values)
rb_objspace_t *objspace = &rb_objspace;
for (i=0; i<n; i++) {
- gc_mark(objspace, values[i]);
+ gc_mark_and_pin(objspace, values[i]);
}
}
@@ -6486,7 +6557,7 @@ gc_mark_stack_values(rb_objspace_t *objspace, long n, const VALUE *values)
long i;
for (i=0; i<n; i++) {
- if (is_markable_object(values[i])) {
+ if (is_markable_object(objspace, values[i])) {
gc_mark_and_pin(objspace, values[i]);
}
}
@@ -6605,6 +6676,14 @@ mark_hash(rb_objspace_t *objspace, VALUE hash)
rb_hash_stlike_foreach(hash, mark_keyvalue, (st_data_t)objspace);
}
+ if (RHASH_AR_TABLE_P(hash)) {
+ if (LIKELY(during_gc) && RHASH_TRANSIENT_P(hash)) {
+ rb_transient_heap_mark(hash, RHASH_AR_TABLE(hash));
+ }
+ }
+ else {
+ VM_ASSERT(!RHASH_TRANSIENT_P(hash));
+ }
gc_mark(objspace, RHASH(hash)->ifnone);
}
@@ -6789,7 +6868,6 @@ each_machine_stack_value(const rb_execution_context_t *ec, void (*cb)(rb_objspac
VALUE *stack_start, *stack_end;
GET_STACK_BOUNDS(stack_start, stack_end, 0);
- RUBY_DEBUG_LOG("ec->th:%u stack_start:%p stack_end:%p", rb_ec_thread_ptr(ec)->serial, stack_start, stack_end);
each_stack_location(objspace, ec, stack_start, stack_end, cb);
}
@@ -6872,7 +6950,7 @@ gc_remember_unprotected(rb_objspace_t *objspace, VALUE obj)
bits_t *uncollectible_bits = &page->uncollectible_bits[0];
if (!MARKED_IN_BITMAP(uncollectible_bits, obj)) {
- page->flags.has_uncollectible_wb_unprotected_objects = TRUE;
+ page->flags.has_uncollectible_shady_objects = TRUE;
MARK_IN_BITMAP(uncollectible_bits, obj);
objspace->rgengc.uncollectible_wb_unprotected_objects++;
@@ -6895,8 +6973,31 @@ rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
const VALUE old_parent = objspace->rgengc.parent_object;
if (old_parent) { /* parent object is old */
- if (RVALUE_WB_UNPROTECTED(obj) || !RVALUE_OLD_P(obj)) {
- rgengc_remember(objspace, old_parent);
+ if (RVALUE_WB_UNPROTECTED(obj)) {
+ if (gc_remember_unprotected(objspace, obj)) {
+ gc_report(2, objspace, "relation: (O->S) %s -> %s\n", obj_info(old_parent), obj_info(obj));
+ }
+ }
+ else {
+ if (!RVALUE_OLD_P(obj)) {
+ if (RVALUE_MARKED(obj)) {
+ /* An object pointed from an OLD object should be OLD. */
+ gc_report(2, objspace, "relation: (O->unmarked Y) %s -> %s\n", obj_info(old_parent), obj_info(obj));
+ RVALUE_AGE_SET_OLD(objspace, obj);
+ if (is_incremental_marking(objspace)) {
+ if (!RVALUE_MARKING(obj)) {
+ gc_grey(objspace, obj);
+ }
+ }
+ else {
+ rgengc_remember(objspace, obj);
+ }
+ }
+ else {
+ gc_report(2, objspace, "relation: (O->Y) %s -> %s\n", obj_info(old_parent), obj_info(obj));
+ RVALUE_AGE_SET_CANDIDATE(objspace, obj);
+ }
+ }
}
}
@@ -6911,9 +7012,11 @@ gc_grey(rb_objspace_t *objspace, VALUE obj)
if (RVALUE_MARKING(obj) == TRUE) rb_bug("gc_grey: %s is marking/remembered.", obj_info(obj));
#endif
+#if GC_ENABLE_INCREMENTAL_MARK
if (is_incremental_marking(objspace)) {
MARK_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
}
+#endif
push_mark_stack(&objspace->mark_stack, obj);
}
@@ -6977,13 +7080,10 @@ gc_mark_ptr(rb_objspace_t *objspace, VALUE obj)
static inline void
gc_pin(rb_objspace_t *objspace, VALUE obj)
{
- GC_ASSERT(is_markable_object(obj));
+ GC_ASSERT(is_markable_object(objspace, obj));
if (UNLIKELY(objspace->flags.during_compacting)) {
if (LIKELY(during_gc)) {
- if (!MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj)) {
- GET_HEAP_PAGE(obj)->pinned_slots++;
- MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
- }
+ MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
}
}
}
@@ -6991,7 +7091,7 @@ gc_pin(rb_objspace_t *objspace, VALUE obj)
static inline void
gc_mark_and_pin(rb_objspace_t *objspace, VALUE obj)
{
- if (!is_markable_object(obj)) return;
+ if (!is_markable_object(objspace, obj)) return;
gc_pin(objspace, obj);
gc_mark_ptr(objspace, obj);
}
@@ -6999,7 +7099,7 @@ gc_mark_and_pin(rb_objspace_t *objspace, VALUE obj)
static inline void
gc_mark(rb_objspace_t *objspace, VALUE obj)
{
- if (!is_markable_object(obj)) return;
+ if (!is_markable_object(objspace, obj)) return;
gc_mark_ptr(objspace, obj);
}
@@ -7015,78 +7115,6 @@ rb_gc_mark(VALUE ptr)
gc_mark_and_pin(&rb_objspace, ptr);
}
-void
-rb_gc_mark_and_move(VALUE *ptr)
-{
- rb_objspace_t *objspace = &rb_objspace;
- if (RB_SPECIAL_CONST_P(*ptr)) return;
-
- if (UNLIKELY(objspace->flags.during_reference_updating)) {
- GC_ASSERT(objspace->flags.during_compacting);
- GC_ASSERT(during_gc);
-
- *ptr = rb_gc_location(*ptr);
- }
- else {
- gc_mark_ptr(objspace, *ptr);
- }
-}
-
-void
-rb_gc_mark_weak(VALUE *ptr)
-{
- rb_objspace_t *objspace = &rb_objspace;
-
- if (UNLIKELY(!during_gc)) return;
-
- VALUE obj = *ptr;
- if (RB_SPECIAL_CONST_P(obj)) return;
-
- GC_ASSERT(objspace->rgengc.parent_object == 0 || FL_TEST(objspace->rgengc.parent_object, FL_WB_PROTECTED));
-
- if (UNLIKELY(RB_TYPE_P(obj, T_NONE))) {
- rp(obj);
- rb_bug("try to mark T_NONE object");
- }
-
- /* If we are in a minor GC and the other object is old, then obj should
- * already be marked and cannot be reclaimed in this GC cycle so we don't
- * need to add it to the weak refences list. */
- if (!is_full_marking(objspace) && RVALUE_OLD_P(obj)) {
- GC_ASSERT(RVALUE_MARKED(obj));
- GC_ASSERT(!objspace->flags.during_compacting);
-
- return;
- }
-
- rgengc_check_relation(objspace, obj);
-
- rb_darray_append_without_gc(&objspace->weak_references, ptr);
-
- objspace->profile.weak_references_count++;
-}
-
-void
-rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr)
-{
- rb_objspace_t *objspace = &rb_objspace;
-
- /* If we're not incremental marking, then the state of the objects can't
- * change so we don't need to do anything. */
- if (!is_incremental_marking(objspace)) return;
- /* If parent_obj has not been marked, then ptr has not yet been marked
- * weak, so we don't need to do anything. */
- if (!RVALUE_MARKED(parent_obj)) return;
-
- VALUE **ptr_ptr;
- rb_darray_foreach(objspace->weak_references, i, ptr_ptr) {
- if (*ptr_ptr == ptr) {
- *ptr_ptr = NULL;
- break;
- }
- }
-}
-
/* CAUTION: THIS FUNCTION ENABLE *ONLY BEFORE* SWEEPING.
* This function is only for GC_END_MARK timing.
*/
@@ -7120,7 +7148,7 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
// just after newobj() can be NULL here.
GC_ASSERT(env->ep[VM_ENV_DATA_INDEX_ENV] == obj);
GC_ASSERT(VM_ENV_ESCAPED_P(env->ep));
- rb_gc_mark_values((long)env->env_size, env->env);
+ gc_mark_values(objspace, (long)env->env_size, env->env);
VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env));
gc_mark(objspace, (VALUE)env->iseq);
@@ -7153,7 +7181,7 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
mark_method_entry(objspace, &RANY(obj)->as.imemo.ment);
return;
case imemo_iseq:
- rb_iseq_mark_and_move((rb_iseq_t *)obj, false);
+ rb_iseq_mark((rb_iseq_t *)obj);
return;
case imemo_tmpbuf:
{
@@ -7167,33 +7195,15 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
rb_ast_mark(&RANY(obj)->as.imemo.ast);
return;
case imemo_parser_strterm:
+ rb_strterm_mark(obj);
return;
case imemo_callinfo:
return;
case imemo_callcache:
- /* cc is callcache.
- *
- * cc->klass (klass) should not be marked because if the klass is
- * free'ed, the cc->klass will be cleared by `vm_cc_invalidate()`.
- *
- * cc->cme (cme) should not be marked because if cc is invalidated
- * when cme is free'ed.
- * - klass marks cme if klass uses cme.
- * - caller classe's ccs->cme marks cc->cme.
- * - if cc is invalidated (klass doesn't refer the cc),
- * cc is invalidated by `vm_cc_invalidate()` and cc->cme is
- * not be accessed.
- * - On the multi-Ractors, cme will be collected with global GC
- * so that it is safe if GC is not interleaving while accessing
- * cc and cme.
- * - However, cc_type_super is not chained from cc so the cc->cme
- * should be marked.
- */
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
- if (vm_cc_super_p(cc)) {
- gc_mark(objspace, (VALUE)cc->cme_);
- }
+ // should not mark klass here
+ gc_mark(objspace, (VALUE)vm_cc_cme(cc));
}
return;
case imemo_constcache:
@@ -7209,39 +7219,6 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
}
}
-static bool
-gc_declarative_marking_p(const rb_data_type_t *type)
-{
- return (type->flags & RUBY_TYPED_DECL_MARKING) != 0;
-}
-
-#define EDGE (VALUE *)((char *)data_struct + offset)
-
-static inline void
-gc_mark_from_offset(rb_objspace_t *objspace, VALUE obj)
-{
- // we are overloading the dmark callback to contain a list of offsets
- size_t *offset_list = (size_t *)RANY(obj)->as.typeddata.type->function.dmark;
- void *data_struct = RANY(obj)->as.typeddata.data;
-
- for (size_t offset = *offset_list; *offset_list != RUBY_REF_END; offset = *offset_list++) {
- rb_gc_mark_movable(*EDGE);
- }
-}
-
-static inline void
-gc_ref_update_from_offset(rb_objspace_t *objspace, VALUE obj)
-{
- // we are overloading the dmark callback to contain a list of offsets
- size_t *offset_list = (size_t *)RANY(obj)->as.typeddata.type->function.dmark;
- void *data_struct = RANY(obj)->as.typeddata.data;
-
- for (size_t offset = *offset_list; *offset_list != RUBY_REF_END; offset = *offset_list++) {
- if (SPECIAL_CONST_P(*EDGE)) continue;
- *EDGE = rb_gc_location(*EDGE);
- }
-}
-
static void mark_cvc_tbl(rb_objspace_t *objspace, VALUE klass);
static void
@@ -7251,7 +7228,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
gc_mark_set_parent(objspace, obj);
if (FL_TEST(obj, FL_EXIVAR)) {
- rb_mark_and_update_generic_ivar(obj);
+ rb_mark_generic_ivar(obj);
}
switch (BUILTIN_TYPE(obj)) {
@@ -7283,29 +7260,19 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
- gc_mark(objspace, RCLASS_ATTACHED_OBJECT(obj));
- }
- // Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
if (RCLASS_SUPER(obj)) {
gc_mark(objspace, RCLASS_SUPER(obj));
}
+ if (!RCLASS_EXT(obj)) break;
mark_m_tbl(objspace, RCLASS_M_TBL(obj));
mark_cvc_tbl(objspace, obj);
cc_table_mark(objspace, obj);
- if (rb_shape_obj_too_complex(obj)) {
- mark_tbl(objspace, (st_table *)RCLASS_IVPTR(obj));
- }
- else {
- for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
- gc_mark(objspace, RCLASS_IVPTR(obj)[i]);
- }
+ for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
+ gc_mark(objspace, RCLASS_IVPTR(obj)[i]);
}
mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
-
- gc_mark(objspace, RCLASS_EXT(obj)->classpath);
break;
case T_ICLASS:
@@ -7315,6 +7282,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
if (RCLASS_SUPER(obj)) {
gc_mark(objspace, RCLASS_SUPER(obj));
}
+ if (!RCLASS_EXT(obj)) break;
if (RCLASS_INCLUDER(obj)) {
gc_mark(objspace, RCLASS_INCLUDER(obj));
@@ -7330,10 +7298,16 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
}
else {
long i, len = RARRAY_LEN(obj);
- const VALUE *ptr = RARRAY_CONST_PTR(obj);
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(obj);
for (i=0; i < len; i++) {
gc_mark(objspace, ptr[i]);
}
+
+ if (LIKELY(during_gc)) {
+ if (!ARY_EMBED_P(obj) && RARRAY_TRANSIENT_P(obj)) {
+ rb_transient_heap_mark(obj, ptr);
+ }
+ }
}
break;
@@ -7349,18 +7323,12 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
case T_DATA:
{
- void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
-
+ void *const ptr = DATA_PTR(obj);
if (ptr) {
- if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(any->as.typeddata.type)) {
- gc_mark_from_offset(objspace, obj);
- }
- else {
- RUBY_DATA_FUNC mark_func = RTYPEDDATA_P(obj) ?
- any->as.typeddata.type->function.dmark :
- any->as.data.dmark;
- if (mark_func) (*mark_func)(ptr);
- }
+ RUBY_DATA_FUNC mark_func = RTYPEDDATA_P(obj) ?
+ any->as.typeddata.type->function.dmark :
+ any->as.data.dmark;
+ if (mark_func) (*mark_func)(ptr);
}
}
break;
@@ -7378,12 +7346,17 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
for (i = 0; i < len; i++) {
gc_mark(objspace, ptr[i]);
}
+
+ if (LIKELY(during_gc) &&
+ ROBJ_TRANSIENT_P(obj)) {
+ rb_transient_heap_mark(obj, ptr);
+ }
}
if (shape) {
VALUE klass = RBASIC_CLASS(obj);
// Increment max_iv_count if applicable, used to determine size pool allocation
- attr_index_t num_of_ivs = shape->next_iv_index;
+ uint32_t num_of_ivs = shape->next_iv_index;
if (RCLASS_EXT(klass)->max_iv_count < num_of_ivs) {
RCLASS_EXT(klass)->max_iv_count = num_of_ivs;
}
@@ -7434,6 +7407,11 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
for (i=0; i<len; i++) {
gc_mark(objspace, ptr[i]);
}
+
+ if (LIKELY(during_gc) &&
+ RSTRUCT_TRANSIENT_P(obj)) {
+ rb_transient_heap_mark(obj, ptr);
+ }
}
break;
@@ -7459,8 +7437,10 @@ gc_mark_stacked_objects(rb_objspace_t *objspace, int incremental, size_t count)
{
mark_stack_t *mstack = &objspace->mark_stack;
VALUE obj;
+#if GC_ENABLE_INCREMENTAL_MARK
size_t marked_slots_at_the_beginning = objspace->marked_slots;
size_t popped_count = 0;
+#endif
while (pop_mark_stack(mstack, &obj)) {
if (UNDEF_P(obj)) continue; /* skip */
@@ -7470,6 +7450,7 @@ gc_mark_stacked_objects(rb_objspace_t *objspace, int incremental, size_t count)
}
gc_mark_children(objspace, obj);
+#if GC_ENABLE_INCREMENTAL_MARK
if (incremental) {
if (RGENGC_CHECK_MODE && !RVALUE_MARKING(obj)) {
rb_bug("gc_mark_stacked_objects: incremental, but marking bit is 0");
@@ -7484,6 +7465,7 @@ gc_mark_stacked_objects(rb_objspace_t *objspace, int incremental, size_t count)
else {
/* just ignore marking bits */
}
+#endif
}
if (RGENGC_CHECK_MODE >= 3) gc_verify_internal_consistency(objspace);
@@ -7909,7 +7891,7 @@ check_children_i(const VALUE child, void *ptr)
if (check_rvalue_consistency_force(child, FALSE) != 0) {
fprintf(stderr, "check_children_i: %s has error (referenced from %s)",
obj_info(child), obj_info(data->parent));
- rb_print_backtrace(stderr); /* C backtrace will help to debug */
+ rb_print_backtrace(); /* C backtrace will help to debug */
data->err_count++;
}
@@ -8017,7 +7999,7 @@ gc_verify_heap_page(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
(void *)page, remembered_old_objects, obj ? obj_info(obj) : "");
}
- if (page->flags.has_uncollectible_wb_unprotected_objects == FALSE && has_remembered_shady == TRUE) {
+ if (page->flags.has_uncollectible_shady_objects == FALSE && has_remembered_shady == TRUE) {
rb_bug("page %p's has_remembered_shady should be false, but there are remembered shady objects. %s",
(void *)page, obj ? obj_info(obj) : "");
}
@@ -8025,11 +8007,11 @@ gc_verify_heap_page(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
if (0) {
/* free_slots may not equal to free_objects */
if (page->free_slots != free_objects) {
- rb_bug("page %p's free_slots should be %d, but %d", (void *)page, page->free_slots, free_objects);
+ rb_bug("page %p's free_slots should be %d, but %d\n", (void *)page, page->free_slots, free_objects);
}
}
if (page->final_slots != zombie_objects) {
- rb_bug("page %p's final_slots should be %d, but %d", (void *)page, page->final_slots, zombie_objects);
+ rb_bug("page %p's final_slots should be %d, but %d\n", (void *)page, page->final_slots, zombie_objects);
}
return remembered_old_objects;
@@ -8129,8 +8111,9 @@ gc_verify_internal_consistency_(rb_objspace_t *objspace)
!finalizing &&
ruby_single_main_ractor != NULL) {
if (objspace_live_slots(objspace) != data.live_object_count) {
- fprintf(stderr, "heap_pages_final_slots: %"PRIdSIZE", total_freed_objects: %"PRIdSIZE"\n",
- heap_pages_final_slots, total_freed_objects(objspace));
+ fprintf(stderr, "heap_pages_final_slots: %"PRIdSIZE", "
+ "objspace->profile.total_freed_objects: %"PRIdSIZE"\n",
+ heap_pages_final_slots, objspace->profile.total_freed_objects);
rb_bug("inconsistent live slot number: expect %"PRIuSIZE", but %"PRIuSIZE".",
objspace_live_slots(objspace), data.live_object_count);
}
@@ -8197,6 +8180,14 @@ rb_gc_verify_internal_consistency(void)
gc_verify_internal_consistency(&rb_objspace);
}
+static VALUE
+gc_verify_transient_heap_internal_consistency(VALUE dmy)
+{
+ rb_transient_heap_verify();
+ return Qnil;
+}
+
+#if GC_ENABLE_INCREMENTAL_MARK
static void
heap_move_pooled_pages_to_free_pages(rb_heap_t *heap)
{
@@ -8215,6 +8206,7 @@ heap_move_pooled_pages_to_free_pages(rb_heap_t *heap)
heap->pooled_pages = NULL;
}
}
+#endif
/* marks */
@@ -8226,6 +8218,7 @@ gc_marks_start(rb_objspace_t *objspace, int full_mark)
gc_mode_transition(objspace, gc_mode_marking);
if (full_mark) {
+#if GC_ENABLE_INCREMENTAL_MARK
size_t incremental_marking_steps = (objspace->rincgc.pooled_slots / INCREMENTAL_MARK_STEP_ALLOCATIONS) + 1;
objspace->rincgc.step_slots = (objspace->marked_slots * 2) / incremental_marking_steps;
@@ -8233,6 +8226,7 @@ gc_marks_start(rb_objspace_t *objspace, int full_mark)
"objspace->rincgc.pooled_page_num: %"PRIdSIZE", "
"objspace->rincgc.step_slots: %"PRIdSIZE", \n",
objspace->marked_slots, objspace->rincgc.pooled_slots, objspace->rincgc.step_slots);
+#endif
objspace->flags.during_minor_gc = FALSE;
if (ruby_enable_autocompact) {
objspace->flags.during_compacting |= TRUE;
@@ -8267,6 +8261,7 @@ gc_marks_start(rb_objspace_t *objspace, int full_mark)
full_mark ? "full" : "minor", mark_stack_size(&objspace->mark_stack));
}
+#if GC_ENABLE_INCREMENTAL_MARK
static inline void
gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bits)
{
@@ -8310,36 +8305,12 @@ gc_marks_wb_unprotected_objects(rb_objspace_t *objspace, rb_heap_t *heap)
gc_mark_stacked_objects_all(objspace);
}
-
-static void
-gc_update_weak_references(rb_objspace_t *objspace)
-{
- size_t retained_weak_references_count = 0;
- VALUE **ptr_ptr;
- rb_darray_foreach(objspace->weak_references, i, ptr_ptr) {
- if (!*ptr_ptr) continue;
-
- VALUE obj = **ptr_ptr;
-
- if (RB_SPECIAL_CONST_P(obj)) continue;
-
- if (!RVALUE_MARKED(obj)) {
- **ptr_ptr = Qundef;
- }
- else {
- retained_weak_references_count++;
- }
- }
-
- objspace->profile.retained_weak_references_count = retained_weak_references_count;
-
- rb_darray_clear(objspace->weak_references);
- rb_darray_resize_capa_without_gc(&objspace->weak_references, retained_weak_references_count);
-}
+#endif
static void
gc_marks_finish(rb_objspace_t *objspace)
{
+#if GC_ENABLE_INCREMENTAL_MARK
/* finish incremental GC */
if (is_incremental_marking(objspace)) {
if (RGENGC_CHECK_MODE && is_mark_stack_empty(&objspace->mark_stack) == 0) {
@@ -8362,13 +8333,19 @@ gc_marks_finish(rb_objspace_t *objspace)
gc_marks_wb_unprotected_objects(objspace, SIZE_POOL_EDEN_HEAP(&size_pools[i]));
}
}
-
- gc_update_weak_references(objspace);
+#endif /* GC_ENABLE_INCREMENTAL_MARK */
#if RGENGC_CHECK_MODE >= 2
gc_verify_internal_consistency(objspace);
#endif
+ if (is_full_marking(objspace)) {
+ /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */
+ const double r = gc_params.oldobject_limit_factor;
+ objspace->rgengc.uncollectible_wb_unprotected_objects_limit = (size_t)(objspace->rgengc.uncollectible_wb_unprotected_objects * r);
+ objspace->rgengc.old_objects_limit = (size_t)(objspace->rgengc.old_objects * r);
+ }
+
#if RGENGC_CHECK_MODE >= 4
during_gc = FALSE;
gc_marks_check(objspace, gc_check_after_marks_i, "after_marks");
@@ -8387,14 +8364,9 @@ gc_marks_finish(rb_objspace_t *objspace)
GC_ASSERT(heap_eden_total_slots(objspace) >= objspace->marked_slots);
- /* Setup freeable slots. */
- size_t total_init_slots = 0;
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- total_init_slots += gc_params.size_pool_init_slots[i] * r_mul;
- }
-
- if (max_free_slots < total_init_slots) {
- max_free_slots = total_init_slots;
+ /* setup free-able page counts */
+ if (max_free_slots < gc_params.heap_init_slots * r_mul) {
+ max_free_slots = gc_params.heap_init_slots * r_mul;
}
if (sweep_slots > max_free_slots) {
@@ -8421,15 +8393,23 @@ gc_marks_finish(rb_objspace_t *objspace)
objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE;
}
}
+
+#if !USE_RVARGC
+ if (full_marking) {
+ /* increment: */
+ gc_report(1, objspace, "gc_marks_finish: heap_set_increment!!\n");
+ rb_size_pool_t *size_pool = &size_pools[0];
+ size_pool_allocatable_pages_set(objspace, size_pool, heap_extend_pages(objspace, size_pool, sweep_slots, total_slots, heap_allocated_pages + heap_allocatable_pages(objspace)));
+
+ heap_increment(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool));
+ }
+#endif
}
if (full_marking) {
/* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */
const double r = gc_params.oldobject_limit_factor;
- objspace->rgengc.uncollectible_wb_unprotected_objects_limit = MAX(
- (size_t)(objspace->rgengc.uncollectible_wb_unprotected_objects * r),
- (size_t)(objspace->rgengc.old_objects * gc_params.uncollectible_wb_unprotected_objects_limit_ratio)
- );
+ objspace->rgengc.uncollectible_wb_unprotected_objects_limit = (size_t)(objspace->rgengc.uncollectible_wb_unprotected_objects * r);
objspace->rgengc.old_objects_limit = (size_t)(objspace->rgengc.old_objects * r);
}
@@ -8450,11 +8430,26 @@ gc_marks_finish(rb_objspace_t *objspace)
objspace->rgengc.need_major_gc ? "major" : "minor");
}
+ rb_transient_heap_finish_marking();
rb_ractor_finish_marking();
gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_MARK, 0);
}
+#if GC_ENABLE_INCREMENTAL_MARK
+static void
+gc_marks_step(rb_objspace_t *objspace, size_t slots)
+{
+ GC_ASSERT(is_marking(objspace));
+
+ if (gc_mark_stacked_objects_incremental(objspace, slots)) {
+ gc_marks_finish(objspace);
+ gc_sweep(objspace);
+ }
+ if (0) fprintf(stderr, "objspace->marked_slots: %"PRIdSIZE"\n", objspace->marked_slots);
+}
+#endif
+
static bool
gc_compact_heap_cursors_met_p(rb_heap_t *heap)
{
@@ -8485,10 +8480,6 @@ gc_compact_destination_pool(rb_objspace_t *objspace, rb_size_pool_t *src_pool, V
obj_size = rb_str_size_as_embedded(src);
break;
- case T_HASH:
- obj_size = sizeof(struct RHash) + (RHASH_ST_TABLE_P(src) ? sizeof(st_table) : sizeof(ar_table));
- break;
-
default:
return src_pool;
}
@@ -8544,7 +8535,7 @@ gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, rb_size_pool_t *size_p
if (dheap->sweeping_page->free_slots > 0) {
heap_add_freepage(dheap, dheap->sweeping_page);
- }
+ };
dheap->sweeping_page = ccan_list_next(&dheap->pages, dheap->sweeping_page, page_node);
if (gc_compact_heap_cursors_met_p(dheap)) {
@@ -8685,9 +8676,11 @@ gc_marks_rest(rb_objspace_t *objspace)
{
gc_report(1, objspace, "gc_marks_rest\n");
+#if GC_ENABLE_INCREMENTAL_MARK
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
SIZE_POOL_EDEN_HEAP(&size_pools[i])->pooled_pages = NULL;
}
+#endif
if (is_incremental_marking(objspace)) {
while (gc_mark_stacked_objects_incremental(objspace, INT_MAX) == FALSE);
@@ -8697,62 +8690,44 @@ gc_marks_rest(rb_objspace_t *objspace)
}
gc_marks_finish(objspace);
-}
-
-static bool
-gc_marks_step(rb_objspace_t *objspace, size_t slots)
-{
- bool marking_finished = false;
-
- GC_ASSERT(is_marking(objspace));
- if (gc_mark_stacked_objects_incremental(objspace, slots)) {
- gc_marks_finish(objspace);
- marking_finished = true;
- }
-
- return marking_finished;
+ /* move to sweep */
+ gc_sweep(objspace);
}
-static bool
+static void
gc_marks_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
{
GC_ASSERT(dont_gc_val() == FALSE);
- bool marking_finished = true;
+#if GC_ENABLE_INCREMENTAL_MARK
- gc_marking_enter(objspace);
+ unsigned int lock_lev;
+ gc_enter(objspace, gc_enter_event_mark_continue, &lock_lev);
if (heap->free_pages) {
gc_report(2, objspace, "gc_marks_continue: has pooled pages");
-
- marking_finished = gc_marks_step(objspace, objspace->rincgc.step_slots);
+ gc_marks_step(objspace, objspace->rincgc.step_slots);
}
else {
gc_report(2, objspace, "gc_marks_continue: no more pooled pages (stack depth: %"PRIdSIZE").\n",
mark_stack_size(&objspace->mark_stack));
- size_pool->force_incremental_marking_finish_count++;
gc_marks_rest(objspace);
}
- gc_marking_exit(objspace);
-
- return marking_finished;
+ gc_exit(objspace, gc_enter_event_mark_continue, &lock_lev);
+#endif
}
-static bool
+static void
gc_marks(rb_objspace_t *objspace, int full_mark)
{
gc_prof_mark_timer_start(objspace);
- gc_marking_enter(objspace);
-
- bool marking_finished = false;
/* setup marking */
gc_marks_start(objspace, full_mark);
if (!is_incremental_marking(objspace)) {
gc_marks_rest(objspace);
- marking_finished = true;
}
#if RGENGC_PROFILE > 0
@@ -8761,11 +8736,7 @@ gc_marks(rb_objspace_t *objspace, int full_mark)
record->old_objects = objspace->rgengc.old_objects;
}
#endif
-
- gc_marking_exit(objspace);
gc_prof_mark_timer_stop(objspace);
-
- return marking_finished;
}
/* RGENGC */
@@ -8803,10 +8774,18 @@ gc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...)
/* bit operations */
static int
+rgengc_remembersetbits_get(rb_objspace_t *objspace, VALUE obj)
+{
+ return RVALUE_REMEMBERED(obj);
+}
+
+static int
rgengc_remembersetbits_set(rb_objspace_t *objspace, VALUE obj)
{
struct heap_page *page = GET_HEAP_PAGE(obj);
- bits_t *bits = &page->remembered_bits[0];
+ bits_t *bits = &page->marking_bits[0];
+
+ GC_ASSERT(!is_incremental_marking(objspace));
if (MARKED_IN_BITMAP(bits, obj)) {
return FALSE;
@@ -8825,7 +8804,7 @@ static int
rgengc_remember(rb_objspace_t *objspace, VALUE obj)
{
gc_report(6, objspace, "rgengc_remember: %s %s\n", obj_info(obj),
- RVALUE_REMEMBERED(obj) ? "was already remembered" : "is remembered now");
+ rgengc_remembersetbits_get(objspace, obj) ? "was already remembered" : "is remembered now");
check_rvalue_consistency(obj);
@@ -8834,7 +8813,7 @@ rgengc_remember(rb_objspace_t *objspace, VALUE obj)
}
#if RGENGC_PROFILE > 0
- if (!RVALUE_REMEMBERED(obj)) {
+ if (!rgengc_remembered(objspace, obj)) {
if (RVALUE_WB_UNPROTECTED(obj) == 0) {
objspace->profile.total_remembered_normal_object_count++;
#if RGENGC_PROFILE >= 2
@@ -8847,6 +8826,21 @@ rgengc_remember(rb_objspace_t *objspace, VALUE obj)
return rgengc_remembersetbits_set(objspace, obj);
}
+static int
+rgengc_remembered_sweep(rb_objspace_t *objspace, VALUE obj)
+{
+ int result = rgengc_remembersetbits_get(objspace, obj);
+ check_rvalue_consistency(obj);
+ return result;
+}
+
+static int
+rgengc_remembered(rb_objspace_t *objspace, VALUE obj)
+{
+ gc_report(6, objspace, "rgengc_remembered: %s\n", obj_info(obj));
+ return rgengc_remembered_sweep(objspace, obj);
+}
+
#ifndef PROFILE_REMEMBERSET_MARK
#define PROFILE_REMEMBERSET_MARK 0
#endif
@@ -8881,20 +8875,20 @@ rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
gc_report(1, objspace, "rgengc_rememberset_mark: start\n");
ccan_list_for_each(&heap->pages, page, page_node) {
- if (page->flags.has_remembered_objects | page->flags.has_uncollectible_wb_unprotected_objects) {
+ if (page->flags.has_remembered_objects | page->flags.has_uncollectible_shady_objects) {
uintptr_t p = page->start;
bits_t bitset, bits[HEAP_PAGE_BITMAP_LIMIT];
- bits_t *remembered_bits = page->remembered_bits;
+ bits_t *marking_bits = page->marking_bits;
bits_t *uncollectible_bits = page->uncollectible_bits;
bits_t *wb_unprotected_bits = page->wb_unprotected_bits;
#if PROFILE_REMEMBERSET_MARK
- if (page->flags.has_remembered_objects && page->flags.has_uncollectible_wb_unprotected_objects) has_both++;
+ if (page->flags.has_remembered_objects && page->flags.has_uncollectible_shady_objects) has_both++;
else if (page->flags.has_remembered_objects) has_old++;
- else if (page->flags.has_uncollectible_wb_unprotected_objects) has_shady++;
+ else if (page->flags.has_uncollectible_shady_objects) has_shady++;
#endif
for (j=0; j<HEAP_PAGE_BITMAP_LIMIT; j++) {
- bits[j] = remembered_bits[j] | (uncollectible_bits[j] & wb_unprotected_bits[j]);
- remembered_bits[j] = 0;
+ bits[j] = marking_bits[j] | (uncollectible_bits[j] & wb_unprotected_bits[j]);
+ marking_bits[j] = 0;
}
page->flags.has_remembered_objects = FALSE;
@@ -8931,9 +8925,8 @@ rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap)
memset(&page->mark_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
memset(&page->uncollectible_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
memset(&page->marking_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
- memset(&page->remembered_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
memset(&page->pinned_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
- page->flags.has_uncollectible_wb_unprotected_objects = FALSE;
+ page->flags.has_uncollectible_shady_objects = FALSE;
page->flags.has_remembered_objects = FALSE;
}
}
@@ -8951,8 +8944,9 @@ gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace)
if (is_incremental_marking(objspace)) rb_bug("gc_writebarrier_generational: called while incremental marking: %s -> %s", obj_info(a), obj_info(b));
}
+#if 1
/* mark `a' and remember (default behavior) */
- if (!RVALUE_REMEMBERED(a)) {
+ if (!rgengc_remembered(objspace, a)) {
RB_VM_LOCK_ENTER_NO_BARRIER();
{
rgengc_remember(objspace, a);
@@ -8960,11 +8954,25 @@ gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace)
RB_VM_LOCK_LEAVE_NO_BARRIER();
gc_report(1, objspace, "gc_writebarrier_generational: %s (remembered) -> %s\n", obj_info(a), obj_info(b));
}
+#else
+ /* mark `b' and remember */
+ MARK_IN_BITMAP(GET_HEAP_MARK_BITS(b), b);
+ if (RVALUE_WB_UNPROTECTED(b)) {
+ gc_remember_unprotected(objspace, b);
+ }
+ else {
+ RVALUE_AGE_SET_OLD(objspace, b);
+ rgengc_remember(objspace, b);
+ }
+
+ gc_report(1, objspace, "gc_writebarrier_generational: %s -> %s (remembered)\n", obj_info(a), obj_info(b));
+#endif
check_rvalue_consistency(a);
check_rvalue_consistency(b);
}
+#if GC_ENABLE_INCREMENTAL_MARK
static void
gc_mark_from(rb_objspace_t *objspace, VALUE obj, VALUE parent)
{
@@ -8990,7 +8998,18 @@ gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace)
}
}
else if (RVALUE_OLD_P(a) && !RVALUE_OLD_P(b)) {
- rgengc_remember(objspace, a);
+ if (!RVALUE_WB_UNPROTECTED(b)) {
+ gc_report(1, objspace, "gc_writebarrier_incremental: [GN] %p -> %s\n", (void *)a, obj_info(b));
+ RVALUE_AGE_SET_OLD(objspace, b);
+
+ if (RVALUE_BLACK_P(b)) {
+ gc_grey(objspace, b);
+ }
+ }
+ else {
+ gc_report(1, objspace, "gc_writebarrier_incremental: [LL] %p -> %s\n", (void *)a, obj_info(b));
+ gc_remember_unprotected(objspace, b);
+ }
}
if (UNLIKELY(objspace->flags.during_compacting)) {
@@ -8998,6 +9017,9 @@ gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace)
}
}
}
+#else
+#define gc_writebarrier_incremental(a, b, objspace)
+#endif
void
rb_gc_writebarrier(VALUE a, VALUE b)
@@ -9047,7 +9069,7 @@ rb_gc_writebarrier_unprotect(VALUE obj)
rb_objspace_t *objspace = &rb_objspace;
gc_report(2, objspace, "rb_gc_writebarrier_unprotect: %s %s\n", obj_info(obj),
- RVALUE_REMEMBERED(obj) ? " (already remembered)" : "");
+ rgengc_remembered(objspace, obj) ? " (already remembered)" : "");
RB_VM_LOCK_ENTER_NO_BARRIER();
{
@@ -9078,7 +9100,7 @@ rb_gc_writebarrier_unprotect(VALUE obj)
/*
* remember `obj' if needed.
*/
-void
+MJIT_FUNC_EXPORTED void
rb_gc_writebarrier_remember(VALUE obj)
{
rb_objspace_t *objspace = &rb_objspace;
@@ -9097,6 +9119,49 @@ rb_gc_writebarrier_remember(VALUE obj)
}
}
+static st_table *rgengc_unprotect_logging_table;
+
+static int
+rgengc_unprotect_logging_exit_func_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ fprintf(stderr, "%s\t%"PRIuVALUE"\n", (char *)key, (VALUE)val);
+ return ST_CONTINUE;
+}
+
+static void
+rgengc_unprotect_logging_exit_func(void)
+{
+ st_foreach(rgengc_unprotect_logging_table, rgengc_unprotect_logging_exit_func_i, 0);
+}
+
+void
+rb_gc_unprotect_logging(void *objptr, const char *filename, int line)
+{
+ VALUE obj = (VALUE)objptr;
+
+ if (rgengc_unprotect_logging_table == 0) {
+ rgengc_unprotect_logging_table = st_init_strtable();
+ atexit(rgengc_unprotect_logging_exit_func);
+ }
+
+ if (RVALUE_WB_UNPROTECTED(obj) == 0) {
+ char buff[0x100];
+ st_data_t cnt = 1;
+ char *ptr = buff;
+
+ snprintf(ptr, 0x100 - 1, "%s|%s:%d", obj_info(obj), filename, line);
+
+ if (st_lookup(rgengc_unprotect_logging_table, (st_data_t)ptr, &cnt)) {
+ cnt++;
+ }
+ else {
+ ptr = (strdup)(buff);
+ if (!ptr) rb_memerror();
+ }
+ st_insert(rgengc_unprotect_logging_table, (st_data_t)ptr, cnt);
+ }
+}
+
void
rb_copy_wb_protected_attribute(VALUE dest, VALUE obj)
{
@@ -9105,7 +9170,7 @@ rb_copy_wb_protected_attribute(VALUE dest, VALUE obj)
if (RVALUE_WB_UNPROTECTED(obj) && !RVALUE_WB_UNPROTECTED(dest)) {
if (!RVALUE_OLD_P(dest)) {
MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(dest), dest);
- RVALUE_AGE_RESET(dest);
+ RVALUE_AGE_RESET_RAW(dest);
}
else {
RVALUE_DEMOTE(objspace, dest);
@@ -9161,7 +9226,9 @@ rb_obj_gc_flags(VALUE obj, ID* flags, size_t max)
void
rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache)
{
+#if GC_ENABLE_INCREMENTAL_MARK
newobj_cache->incremental_mark_step_allocated_slots = 0;
+#endif
for (size_t size_pool_idx = 0; size_pool_idx < SIZE_POOL_COUNT; size_pool_idx++) {
rb_ractor_newobj_size_pool_cache_t *cache = &newobj_cache->size_pool_caches[size_pool_idx];
@@ -9227,9 +9294,9 @@ rb_gc_register_address(VALUE *addr)
*/
RB_GC_GUARD(obj);
if (0 && !SPECIAL_CONST_P(obj)) {
- rb_warn("Object is assigned to registering address already: %"PRIsVALUE,
- rb_obj_class(obj));
- rb_print_backtrace(stderr);
+ rb_warn("Object is assigned to registering address already: %"PRIsVALUE,
+ rb_obj_class(obj));
+ rb_print_backtrace();
}
}
@@ -9396,7 +9463,9 @@ static int
gc_start(rb_objspace_t *objspace, unsigned int reason)
{
unsigned int do_full_mark = !!(reason & GPR_FLAG_FULL_MARK);
+#if GC_ENABLE_INCREMENTAL_MARK
unsigned int immediate_mark = reason & GPR_FLAG_IMMEDIATE_MARK;
+#endif
/* reason may be clobbered, later, so keep set immediate_sweep here */
objspace->flags.immediate_sweep = !!(reason & GPR_FLAG_IMMEDIATE_SWEEP);
@@ -9449,12 +9518,14 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
reason |= GPR_FLAG_MAJOR_BY_FORCE; /* GC by CAPI, METHOD, and so on. */
}
- if (objspace->flags.dont_incremental || immediate_mark) {
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (!GC_ENABLE_INCREMENTAL_MARK || objspace->flags.dont_incremental || immediate_mark) {
objspace->flags.during_incremental_marking = FALSE;
}
else {
objspace->flags.during_incremental_marking = do_full_mark;
}
+#endif
if (!GC_ENABLE_LAZY_SWEEP || objspace->flags.dont_incremental) {
objspace->flags.immediate_sweep = TRUE;
@@ -9489,21 +9560,18 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
objspace->profile.count++;
objspace->profile.latest_gc_info = reason;
- objspace->profile.total_allocated_objects_at_gc_start = total_allocated_objects(objspace);
+ objspace->profile.total_allocated_objects_at_gc_start = objspace->total_allocated_objects;
objspace->profile.heap_used_at_gc_start = heap_allocated_pages;
- objspace->profile.weak_references_count = 0;
- objspace->profile.retained_weak_references_count = 0;
gc_prof_setup_new_record(objspace, reason);
gc_reset_malloc_info(objspace, do_full_mark);
+ rb_transient_heap_start_marking(do_full_mark);
gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_START, 0 /* TODO: pass minor/immediate flag? */);
GC_ASSERT(during_gc);
gc_prof_timer_start(objspace);
{
- if (gc_marks(objspace, do_full_mark)) {
- gc_sweep(objspace);
- }
+ gc_marks(objspace, do_full_mark);
}
gc_prof_timer_stop(objspace);
@@ -9524,19 +9592,11 @@ gc_rest(rb_objspace_t *objspace)
if (RGENGC_CHECK_MODE >= 2) gc_verify_internal_consistency(objspace);
if (is_incremental_marking(objspace)) {
- gc_marking_enter(objspace);
gc_marks_rest(objspace);
- gc_marking_exit(objspace);
-
- gc_sweep(objspace);
}
-
if (is_lazy_sweeping(objspace)) {
- gc_sweeping_enter(objspace);
gc_sweep_rest(objspace);
- gc_sweeping_exit(objspace);
}
-
gc_exit(objspace, gc_enter_event_rest, &lock_lev);
}
}
@@ -9553,7 +9613,9 @@ gc_current_status_fill(rb_objspace_t *objspace, char *buff)
if (is_marking(objspace)) {
buff[i++] = 'M';
if (is_full_marking(objspace)) buff[i++] = 'F';
+#if GC_ENABLE_INCREMENTAL_MARK
if (is_incremental_marking(objspace)) buff[i++] = 'I';
+#endif
}
else if (is_sweeping(objspace)) {
buff[i++] = 'S';
@@ -9625,7 +9687,8 @@ gc_enter_event_cstr(enum gc_enter_event event)
{
switch (event) {
case gc_enter_event_start: return "start";
- case gc_enter_event_continue: return "continue";
+ case gc_enter_event_mark_continue: return "mark_continue";
+ case gc_enter_event_sweep_continue: return "sweep_continue";
case gc_enter_event_rest: return "rest";
case gc_enter_event_finalizer: return "finalizer";
case gc_enter_event_rb_memerror: return "rb_memerror";
@@ -9638,7 +9701,8 @@ gc_enter_count(enum gc_enter_event event)
{
switch (event) {
case gc_enter_event_start: RB_DEBUG_COUNTER_INC(gc_enter_start); break;
- case gc_enter_event_continue: RB_DEBUG_COUNTER_INC(gc_enter_continue); break;
+ case gc_enter_event_mark_continue: RB_DEBUG_COUNTER_INC(gc_enter_mark_continue); break;
+ case gc_enter_event_sweep_continue: RB_DEBUG_COUNTER_INC(gc_enter_sweep_continue); break;
case gc_enter_event_rest: RB_DEBUG_COUNTER_INC(gc_enter_rest); break;
case gc_enter_event_finalizer: RB_DEBUG_COUNTER_INC(gc_enter_finalizer); break;
case gc_enter_event_rb_memerror: /* nothing */ break;
@@ -9649,30 +9713,59 @@ gc_enter_count(enum gc_enter_event event)
#define MEASURE_GC (objspace->flags.measure_gc)
#endif
+static bool
+gc_enter_event_measure_p(rb_objspace_t *objspace, enum gc_enter_event event)
+{
+ if (!MEASURE_GC) return false;
+
+ switch (event) {
+ case gc_enter_event_start:
+ case gc_enter_event_mark_continue:
+ case gc_enter_event_sweep_continue:
+ case gc_enter_event_rest:
+ return true;
+
+ default:
+ // case gc_enter_event_finalizer:
+ // case gc_enter_event_rb_memerror:
+ return false;
+ }
+}
+
static bool current_process_time(struct timespec *ts);
static void
-gc_clock_start(struct timespec *ts)
+gc_enter_clock(rb_objspace_t *objspace, enum gc_enter_event event)
{
- if (!current_process_time(ts)) {
- ts->tv_sec = 0;
- ts->tv_nsec = 0;
+ if (gc_enter_event_measure_p(objspace, event)) {
+ if (!current_process_time(&objspace->profile.start_time)) {
+ objspace->profile.start_time.tv_sec = 0;
+ objspace->profile.start_time.tv_nsec = 0;
+ }
}
}
-static uint64_t
-gc_clock_end(struct timespec *ts)
+static void
+gc_exit_clock(rb_objspace_t *objspace, enum gc_enter_event event)
{
- struct timespec end_time;
+ if (gc_enter_event_measure_p(objspace, event)) {
+ struct timespec end_time;
- if ((ts->tv_sec > 0 || ts->tv_nsec > 0) &&
- current_process_time(&end_time) &&
- end_time.tv_sec >= ts->tv_sec) {
- return (uint64_t)(end_time.tv_sec - ts->tv_sec) * (1000 * 1000 * 1000) +
- (end_time.tv_nsec - ts->tv_nsec);
- }
+ if ((objspace->profile.start_time.tv_sec > 0 ||
+ objspace->profile.start_time.tv_nsec > 0) &&
+ current_process_time(&end_time)) {
- return 0;
+ if (end_time.tv_sec < objspace->profile.start_time.tv_sec) {
+ return; // ignore
+ }
+ else {
+ uint64_t ns =
+ (uint64_t)(end_time.tv_sec - objspace->profile.start_time.tv_sec) * (1000 * 1000 * 1000) +
+ (end_time.tv_nsec - objspace->profile.start_time.tv_nsec);
+ objspace->profile.total_time_ns += ns;
+ }
+ }
+ }
}
static inline void
@@ -9680,12 +9773,14 @@ gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_
{
RB_VM_LOCK_ENTER_LEV(lock_lev);
+ gc_enter_clock(objspace, event);
+
switch (event) {
case gc_enter_event_rest:
if (!is_marking(objspace)) break;
// fall through
case gc_enter_event_start:
- case gc_enter_event_continue:
+ case gc_enter_event_mark_continue:
// stop other ractors
rb_vm_barrier();
break;
@@ -9709,45 +9804,22 @@ gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_l
{
GC_ASSERT(during_gc != 0);
- gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_EXIT, 0); /* TODO: which parameter should be passed? */
+ gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_EXIT, 0); /* TODO: which parameter should be passsed? */
gc_record(objspace, 1, gc_enter_event_cstr(event));
RUBY_DEBUG_LOG("%s (%s)", gc_enter_event_cstr(event), gc_current_status(objspace));
gc_report(1, objspace, "gc_exit: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
during_gc = FALSE;
+ gc_exit_clock(objspace, event);
RB_VM_LOCK_LEAVE_LEV(lock_lev);
-}
-
-static void
-gc_marking_enter(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- gc_clock_start(&objspace->profile.marking_start_time);
-}
-
-static void
-gc_marking_exit(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- objspace->profile.marking_time_ns += gc_clock_end(&objspace->profile.marking_start_time);
-}
-
-static void
-gc_sweeping_enter(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
- gc_clock_start(&objspace->profile.sweeping_start_time);
-}
-
-static void
-gc_sweeping_exit(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- objspace->profile.sweeping_time_ns += gc_clock_end(&objspace->profile.sweeping_start_time);
+#if RGENGC_CHECK_MODE >= 2
+ if (event == gc_enter_event_sweep_continue && gc_mode(objspace) == gc_mode_none) {
+ GC_ASSERT(!during_gc);
+ // sweep finished
+ gc_verify_internal_consistency(objspace);
+ }
+#endif
}
static void *
@@ -9779,31 +9851,6 @@ garbage_collect_with_gvl(rb_objspace_t *objspace, unsigned int reason)
}
}
-static int
-gc_set_candidate_object_i(void *vstart, void *vend, size_t stride, void *data)
-{
- rb_objspace_t *objspace = &rb_objspace;
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- switch (BUILTIN_TYPE(v)) {
- case T_NONE:
- case T_ZOMBIE:
- break;
- case T_STRING:
- // precompute the string coderange. This both save time for when it will be
- // eventually needed, and avoid mutating heap pages after a potential fork.
- rb_enc_str_coderange(v);
- // fall through
- default:
- if (!RVALUE_OLD_P(v) && !RVALUE_WB_UNPROTECTED(v)) {
- RVALUE_AGE_SET_CANDIDATE(objspace, v);
- }
- }
- }
-
- return 0;
-}
-
static VALUE
gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE immediate_mark, VALUE immediate_sweep, VALUE compact)
{
@@ -9831,61 +9878,6 @@ gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE
return Qnil;
}
-static void
-free_empty_pages(void)
-{
- rb_objspace_t *objspace = &rb_objspace;
-
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- /* Move all empty pages to the tomb heap for freeing. */
- rb_size_pool_t *size_pool = &size_pools[i];
- rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
- rb_heap_t *tomb_heap = SIZE_POOL_TOMB_HEAP(size_pool);
-
- size_t freed_pages = 0;
-
- struct heap_page **next_page_ptr = &heap->free_pages;
- struct heap_page *page = heap->free_pages;
- while (page) {
- /* All finalizers should have been ran in gc_start_internal, so there
- * should be no objects that require finalization. */
- GC_ASSERT(page->final_slots == 0);
-
- struct heap_page *next_page = page->free_next;
-
- if (page->free_slots == page->total_slots) {
- heap_unlink_page(objspace, heap, page);
- heap_add_page(objspace, size_pool, tomb_heap, page);
- freed_pages++;
- }
- else {
- *next_page_ptr = page;
- next_page_ptr = &page->free_next;
- }
-
- page = next_page;
- }
-
- *next_page_ptr = NULL;
-
- size_pool_allocatable_pages_set(objspace, size_pool, size_pool->allocatable_pages + freed_pages);
- }
-
- heap_pages_free_unused_pages(objspace);
-}
-
-void
-rb_gc_prepare_heap(void)
-{
- rb_objspace_each_objects(gc_set_candidate_object_i, NULL);
- gc_start_internal(NULL, Qtrue, Qtrue, Qtrue, Qtrue, Qtrue);
- free_empty_pages();
-
-#if defined(HAVE_MALLOC_TRIM) && !defined(RUBY_ALTERNATIVE_MALLOC_HEADER)
- malloc_trim(0);
-#endif
-}
-
static int
gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
{
@@ -9926,9 +9918,9 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
* prevent the objects from being collected. This check prevents
* objects that are keys in the finalizer table from being moved
* without directly pinning them. */
- GC_ASSERT(st_is_member(finalizer_table, obj));
-
- return FALSE;
+ if (st_is_member(finalizer_table, obj)) {
+ return FALSE;
+ }
}
GC_ASSERT(RVALUE_MARKED(obj));
GC_ASSERT(!RVALUE_PINNED(obj));
@@ -9943,13 +9935,24 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
return FALSE;
}
+/* Used in places that could malloc, which can cause the GC to run. We need to
+ * temporarily disable the GC to allow the malloc to happen. */
+#define COULD_MALLOC_REGION_START() \
+ GC_ASSERT(during_gc); \
+ VALUE _already_disabled = rb_gc_disable_no_rest(); \
+ during_gc = false;
+
+#define COULD_MALLOC_REGION_END() \
+ during_gc = true; \
+ if (_already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
+
static VALUE
gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, size_t slot_size)
{
int marked;
int wb_unprotected;
int uncollectible;
- int age;
+ int marking;
RVALUE *dest = (RVALUE *)free;
RVALUE *src = (RVALUE *)scan;
@@ -9958,28 +9961,25 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s
GC_ASSERT(BUILTIN_TYPE(scan) != T_NONE);
GC_ASSERT(!MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(free), free));
- GC_ASSERT(!RVALUE_MARKING((VALUE)src));
-
/* Save off bits for current object. */
marked = rb_objspace_marked_object_p((VALUE)src);
wb_unprotected = RVALUE_WB_UNPROTECTED((VALUE)src);
uncollectible = RVALUE_UNCOLLECTIBLE((VALUE)src);
- bool remembered = RVALUE_REMEMBERED((VALUE)src);
- age = RVALUE_AGE_GET((VALUE)src);
+ marking = RVALUE_MARKING((VALUE)src);
/* Clear bits for eventual T_MOVED */
CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)src), (VALUE)src);
CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS((VALUE)src), (VALUE)src);
CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)src), (VALUE)src);
- CLEAR_IN_BITMAP(GET_HEAP_PAGE((VALUE)src)->remembered_bits, (VALUE)src);
+ CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)src), (VALUE)src);
if (FL_TEST((VALUE)src, FL_EXIVAR)) {
/* Resizing the st table could cause a malloc */
- DURING_GC_COULD_MALLOC_REGION_START();
+ COULD_MALLOC_REGION_START();
{
rb_mv_generic_ivar((VALUE)src, (VALUE)dest);
}
- DURING_GC_COULD_MALLOC_REGION_END();
+ COULD_MALLOC_REGION_END();
}
st_data_t srcid = (st_data_t)src, id;
@@ -9989,12 +9989,12 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s
if (st_lookup(objspace->obj_to_id_tbl, srcid, &id)) {
gc_report(4, objspace, "Moving object with seen id: %p -> %p\n", (void *)src, (void *)dest);
/* Resizing the st table could cause a malloc */
- DURING_GC_COULD_MALLOC_REGION_START();
+ COULD_MALLOC_REGION_START();
{
st_delete(objspace->obj_to_id_tbl, &srcid, 0);
st_insert(objspace->obj_to_id_tbl, (st_data_t)dest, id);
}
- DURING_GC_COULD_MALLOC_REGION_END();
+ COULD_MALLOC_REGION_END();
}
/* Move the object */
@@ -10008,14 +10008,13 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s
}
memset(src, 0, src_slot_size);
- RVALUE_AGE_RESET((VALUE)src);
/* Set bits for object in new location */
- if (remembered) {
- MARK_IN_BITMAP(GET_HEAP_PAGE(dest)->remembered_bits, (VALUE)dest);
+ if (marking) {
+ MARK_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)dest), (VALUE)dest);
}
else {
- CLEAR_IN_BITMAP(GET_HEAP_PAGE(dest)->remembered_bits, (VALUE)dest);
+ CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)dest), (VALUE)dest);
}
if (marked) {
@@ -10039,7 +10038,6 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s
CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)dest), (VALUE)dest);
}
- RVALUE_AGE_SET((VALUE)dest, age);
/* Assign forwarding address */
src->as.moved.flags = T_MOVED;
src->as.moved.dummy = Qundef;
@@ -10051,18 +10049,6 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s
#if GC_CAN_COMPILE_COMPACTION
static int
-compare_pinned_slots(const void *left, const void *right, void *dummy)
-{
- struct heap_page *left_page;
- struct heap_page *right_page;
-
- left_page = *(struct heap_page * const *)left;
- right_page = *(struct heap_page * const *)right;
-
- return left_page->pinned_slots - right_page->pinned_slots;
-}
-
-static int
compare_free_slots(const void *left, const void *right, void *dummy)
{
struct heap_page *left_page;
@@ -10075,7 +10061,7 @@ compare_free_slots(const void *left, const void *right, void *dummy)
}
static void
-gc_sort_heap_by_compare_func(rb_objspace_t *objspace, gc_compact_compare_func compare_func)
+gc_sort_heap_by_empty_slots(rb_objspace_t *objspace)
{
for (int j = 0; j < SIZE_POOL_COUNT; j++) {
rb_size_pool_t *size_pool = &size_pools[j];
@@ -10095,7 +10081,7 @@ gc_sort_heap_by_compare_func(rb_objspace_t *objspace, gc_compact_compare_func co
/* Sort the heap so "filled pages" are first. `heap_add_page` adds to the
* head of the list, so empty pages will end up at the start of the heap */
- ruby_qsort(page_list, total_pages, sizeof(struct heap_page *), compare_func, NULL);
+ ruby_qsort(page_list, total_pages, sizeof(struct heap_page *), compare_free_slots, NULL);
/* Reset the eden heap */
ccan_list_head_init(&SIZE_POOL_EDEN_HEAP(size_pool)->pages);
@@ -10116,10 +10102,13 @@ static void
gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
{
if (ARY_SHARED_P(v)) {
+#if USE_RVARGC
VALUE old_root = RARRAY(v)->as.heap.aux.shared_root;
+#endif
UPDATE_IF_MOVED(objspace, RARRAY(v)->as.heap.aux.shared_root);
+#if USE_RVARGC
VALUE new_root = RARRAY(v)->as.heap.aux.shared_root;
// If the root is embedded and its location has changed
if (ARY_EMBED_P(new_root) && new_root != old_root) {
@@ -10127,22 +10116,25 @@ gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
GC_ASSERT(RARRAY(v)->as.heap.ptr >= RARRAY(old_root)->as.ary);
RARRAY(v)->as.heap.ptr = RARRAY(new_root)->as.ary + offset;
}
+#endif
}
else {
long len = RARRAY_LEN(v);
if (len > 0) {
- VALUE *ptr = (VALUE *)RARRAY_CONST_PTR(v);
+ VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(v);
for (long i = 0; i < len; i++) {
UPDATE_IF_MOVED(objspace, ptr[i]);
}
}
+#if USE_RVARGC
if (rb_gc_obj_slot_size(v) >= rb_ary_size_as_embedded(v)) {
if (rb_ary_embeddable_p(v)) {
rb_ary_make_embedded(v);
}
}
+#endif
}
}
@@ -10156,15 +10148,22 @@ gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
return;
}
+#if USE_RVARGC
size_t slot_size = rb_gc_obj_slot_size(v);
size_t embed_size = rb_obj_embedded_size(ROBJECT_IV_CAPACITY(v));
if (slot_size >= embed_size && !RB_FL_TEST_RAW(v, ROBJECT_EMBED)) {
// Object can be re-embedded
memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * ROBJECT_IV_COUNT(v));
RB_FL_SET_RAW(v, ROBJECT_EMBED);
- xfree(ptr);
+ if (ROBJ_TRANSIENT_P(v)) {
+ ROBJ_TRANSIENT_UNSET(v);
+ }
+ else {
+ xfree(ptr);
+ }
ptr = ROBJECT(v)->as.ary;
}
+#endif
for (uint32_t i = 0; i < ROBJECT_IV_COUNT(v); i++) {
UPDATE_IF_MOVED(objspace, ptr[i]);
@@ -10314,20 +10313,6 @@ gc_update_values(rb_objspace_t *objspace, long n, VALUE *values)
}
}
-void
-rb_gc_update_values(long n, VALUE *values)
-{
- gc_update_values(&rb_objspace, n, values);
-}
-
-static bool
-moved_or_living_object_strictly_p(rb_objspace_t *objspace, VALUE obj)
-{
- return obj &&
- is_pointer_to_heap(objspace, (void *)obj) &&
- (is_live_object(objspace, obj) || BUILTIN_TYPE(obj) == T_MOVED);
-}
-
static void
gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
{
@@ -10367,7 +10352,7 @@ gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
gc_ref_update_method_entry(objspace, &RANY(obj)->as.imemo.ment);
break;
case imemo_iseq:
- rb_iseq_mark_and_move((rb_iseq_t *)obj, true);
+ rb_iseq_update_references((rb_iseq_t *)obj);
break;
case imemo_ast:
rb_ast_update_references((rb_ast_t *)obj);
@@ -10375,18 +10360,17 @@ gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
case imemo_callcache:
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
-
- if (!cc->klass) {
- // already invalidated
- }
- else {
- if (moved_or_living_object_strictly_p(objspace, cc->klass) &&
- moved_or_living_object_strictly_p(objspace, (VALUE)cc->cme_)) {
- UPDATE_IF_MOVED(objspace, cc->klass);
- TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
+ if (cc->klass) {
+ UPDATE_IF_MOVED(objspace, cc->klass);
+ if (!is_live_object(objspace, cc->klass)) {
+ *((VALUE *)(&cc->klass)) = (VALUE)0;
}
- else {
- vm_cc_invalidate(cc);
+ }
+
+ if (cc->cme_) {
+ TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
+ if (!is_live_object(objspace, (VALUE)cc->cme_)) {
+ *((struct rb_callable_method_entry_struct **)(&cc->cme_)) = (struct rb_callable_method_entry_struct *)0;
}
}
}
@@ -10533,13 +10517,12 @@ update_cvc_tbl(rb_objspace_t *objspace, VALUE klass)
static enum rb_id_table_iterator_result
mark_cvc_tbl_i(VALUE cvc_entry, void *data)
{
- rb_objspace_t *objspace = (rb_objspace_t *)data;
struct rb_cvar_class_tbl_entry *entry;
entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
RUBY_ASSERT(entry->cref == 0 || (BUILTIN_TYPE((VALUE)entry->cref) == T_IMEMO && IMEMO_TYPE_P(entry->cref, imemo_cref)));
- gc_mark(objspace, (VALUE) entry->cref);
+ rb_gc_mark((VALUE) entry->cref);
return ID_TABLE_CONTINUE;
}
@@ -10612,20 +10595,13 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
gc_report(4, objspace, "update-refs: %p ->\n", (void *)obj);
- if (FL_TEST(obj, FL_EXIVAR)) {
- rb_mark_and_update_generic_ivar(obj);
- }
-
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
- UPDATE_IF_MOVED(objspace, RCLASS_ATTACHED_OBJECT(obj));
- }
- // Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
if (RCLASS_SUPER((VALUE)obj)) {
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
}
+ if (!RCLASS_EXT(obj)) break;
update_m_tbl(objspace, RCLASS_M_TBL(obj));
update_cc_tbl(objspace, obj);
update_cvc_tbl(objspace, obj);
@@ -10637,8 +10613,6 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
update_class_ext(objspace, RCLASS_EXT(obj));
update_const_tbl(objspace, RCLASS_CONST_TBL(obj));
-
- UPDATE_IF_MOVED(objspace, RCLASS_EXT(obj)->classpath);
break;
case T_ICLASS:
@@ -10649,6 +10623,7 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
if (RCLASS_SUPER((VALUE)obj)) {
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
}
+ if (!RCLASS_EXT(obj)) break;
update_class_ext(objspace, RCLASS_EXT(obj));
update_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
update_cc_tbl(objspace, obj);
@@ -10677,13 +10652,21 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
case T_STRING:
{
+#if USE_RVARGC
+#endif
+
if (STR_SHARED_P(obj)) {
+#if USE_RVARGC
VALUE old_root = any->as.string.as.heap.aux.shared;
+#endif
UPDATE_IF_MOVED(objspace, any->as.string.as.heap.aux.shared);
+#if USE_RVARGC
VALUE new_root = any->as.string.as.heap.aux.shared;
rb_str_update_shared_ary(obj, old_root, new_root);
+#endif
}
+#if USE_RVARGC
/* If, after move the string is not embedded, and can fit in the
* slot it's been placed in, then re-embed it. */
if (rb_gc_obj_slot_size(obj) >= rb_str_size_as_embedded(obj)) {
@@ -10691,18 +10674,16 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
rb_str_make_embedded(obj);
}
}
+#endif
break;
}
case T_DATA:
/* Call the compaction callback, if it exists */
{
- void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
+ void *const ptr = DATA_PTR(obj);
if (ptr) {
- if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(any->as.typeddata.type)) {
- gc_ref_update_from_offset(objspace, obj);
- }
- else if (RTYPEDDATA_P(obj)) {
+ if (RTYPEDDATA_P(obj)) {
RUBY_DATA_FUNC compact_func = any->as.typeddata.type->function.dcompact;
if (compact_func) (*compact_func)(ptr);
}
@@ -10789,7 +10770,7 @@ gc_ref_update(void *vstart, void *vend, size_t stride, rb_objspace_t * objspace,
VALUE v = (VALUE)vstart;
asan_unlock_freelist(page);
asan_lock_freelist(page);
- page->flags.has_uncollectible_wb_unprotected_objects = FALSE;
+ page->flags.has_uncollectible_shady_objects = FALSE;
page->flags.has_remembered_objects = FALSE;
/* For each object on the page */
@@ -10803,9 +10784,9 @@ gc_ref_update(void *vstart, void *vend, size_t stride, rb_objspace_t * objspace,
break;
default:
if (RVALUE_WB_UNPROTECTED(v)) {
- page->flags.has_uncollectible_wb_unprotected_objects = TRUE;
+ page->flags.has_uncollectible_shady_objects = TRUE;
}
- if (RVALUE_REMEMBERED(v)) {
+ if (RVALUE_PAGE_MARKING(page, v)) {
page->flags.has_remembered_objects = TRUE;
}
if (page->flags.before_sweep) {
@@ -10832,8 +10813,6 @@ extern rb_symbols_t ruby_global_symbols;
static void
gc_update_references(rb_objspace_t *objspace)
{
- objspace->flags.during_reference_updating = true;
-
rb_execution_context_t *ec = GET_EC();
rb_vm_t *vm = rb_ec_vm_ptr(ec);
@@ -10858,6 +10837,7 @@ gc_update_references(rb_objspace_t *objspace)
}
}
rb_vm_update_references(vm);
+ rb_transient_heap_update_references();
rb_gc_update_global_tbl();
global_symbols.ids = rb_gc_location(global_symbols.ids);
global_symbols.dsymbol_fstr_hash = rb_gc_location(global_symbols.dsymbol_fstr_hash);
@@ -10865,8 +10845,6 @@ gc_update_references(rb_objspace_t *objspace)
gc_update_table_refs(objspace, objspace->id_to_obj_tbl);
gc_update_table_refs(objspace, global_symbols.str_sym);
gc_update_table_refs(objspace, finalizer_table);
-
- objspace->flags.during_reference_updating = false;
}
#if GC_CAN_COMPILE_COMPACTION
@@ -10927,7 +10905,7 @@ static void
root_obj_check_moved_i(const char *category, VALUE obj, void *data)
{
if (gc_object_moved_p(&rb_objspace, obj)) {
- rb_bug("ROOT %s points to MOVED: %p -> %s", category, (void *)obj, obj_info(rb_gc_location(obj)));
+ rb_bug("ROOT %s points to MOVED: %p -> %s\n", category, (void *)obj, obj_info(rb_gc_location(obj)));
}
}
@@ -10936,7 +10914,7 @@ reachable_object_check_moved_i(VALUE ref, void *data)
{
VALUE parent = (VALUE)data;
if (gc_object_moved_p(&rb_objspace, ref)) {
- rb_bug("Object %s points to MOVED: %p -> %s", obj_info(parent), (void *)ref, obj_info(rb_gc_location(ref)));
+ rb_bug("Object %s points to MOVED: %p -> %s\n", obj_info(parent), (void *)ref, obj_info(rb_gc_location(ref)));
}
}
@@ -11008,6 +10986,7 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do
/* Clear the heap. */
gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qfalse);
+ size_t growth_slots = gc_params.heap_init_slots;
if (RTEST(double_heap)) {
rb_warn("double_heap is deprecated, please use expand_heap instead");
@@ -11023,17 +11002,18 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do
rb_size_pool_t *size_pool = &size_pools[i];
rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
- size_t minimum_pages = 0;
if (RTEST(expand_heap)) {
- minimum_pages = minimum_pages_for_size_pool(objspace, size_pool);
+ size_t required_pages = growth_slots / size_pool->slot_size;
+ heap_add_pages(objspace, size_pool, heap, MAX(required_pages, heap->total_pages));
+ }
+ else {
+ heap_add_pages(objspace, size_pool, heap, heap->total_pages);
}
-
- heap_add_pages(objspace, size_pool, heap, MAX(minimum_pages, heap->total_pages));
}
}
if (RTEST(toward_empty)) {
- objspace->rcompactor.compare_func = compare_free_slots;
+ gc_sort_heap_by_empty_slots(objspace);
}
}
RB_VM_LOCK_LEAVE();
@@ -11043,7 +11023,6 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do
objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, NULL);
objspace_each_objects(objspace, heap_check_moved_i, NULL, TRUE);
- objspace->rcompactor.compare_func = NULL;
return gc_compact_stats(self);
}
#else
@@ -11060,7 +11039,7 @@ rb_gc_start(void)
void
rb_gc(void)
{
- unless_objspace(objspace) { return; }
+ rb_objspace_t *objspace = &rb_objspace;
unsigned int reason = GPR_DEFAULT_REASON;
garbage_collect(objspace, reason);
}
@@ -11068,7 +11047,7 @@ rb_gc(void)
int
rb_during_gc(void)
{
- unless_objspace(objspace) { return FALSE; }
+ rb_objspace_t *objspace = &rb_objspace;
return during_gc;
}
@@ -11111,7 +11090,6 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
#endif
static VALUE sym_newobj, sym_malloc, sym_method, sym_capi;
static VALUE sym_none, sym_marking, sym_sweeping;
- static VALUE sym_weak_references_count, sym_retained_weak_references_count;
VALUE hash = Qnil, key = Qnil;
VALUE major_by, need_major_by;
unsigned int flags = orig_flags ? orig_flags : objspace->profile.latest_gc_info;
@@ -11151,9 +11129,6 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
S(none);
S(marking);
S(sweeping);
-
- S(weak_references_count);
- S(retained_weak_references_count);
#undef S
}
@@ -11204,9 +11179,6 @@ gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned
SET(state, gc_mode(objspace) == gc_mode_none ? sym_none :
gc_mode(objspace) == gc_mode_marking ? sym_marking : sym_sweeping);
}
-
- SET(weak_references_count, LONG2FIX(objspace->profile.weak_references_count));
- SET(retained_weak_references_count, LONG2FIX(objspace->profile.retained_weak_references_count));
#undef SET
if (!NIL_P(key)) {/* matched key should return above */
@@ -11241,8 +11213,6 @@ gc_latest_gc_info(rb_execution_context_t *ec, VALUE self, VALUE arg)
enum gc_stat_sym {
gc_stat_sym_count,
gc_stat_sym_time,
- gc_stat_sym_marking_time,
- gc_stat_sym_sweeping_time,
gc_stat_sym_heap_allocated_pages,
gc_stat_sym_heap_sorted_length,
gc_stat_sym_heap_allocatable_pages,
@@ -11272,7 +11242,6 @@ enum gc_stat_sym {
gc_stat_sym_oldmalloc_increase_bytes,
gc_stat_sym_oldmalloc_increase_bytes_limit,
#endif
- gc_stat_sym_weak_references_count,
#if RGENGC_PROFILE
gc_stat_sym_total_generated_normal_object_count,
gc_stat_sym_total_generated_shady_object_count,
@@ -11293,8 +11262,6 @@ setup_gc_stat_symbols(void)
#define S(s) gc_stat_symbols[gc_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
S(count);
S(time);
- S(marking_time),
- S(sweeping_time),
S(heap_allocated_pages);
S(heap_sorted_length);
S(heap_allocatable_pages);
@@ -11324,7 +11291,6 @@ setup_gc_stat_symbols(void)
S(oldmalloc_increase_bytes);
S(oldmalloc_increase_bytes_limit);
#endif
- S(weak_references_count);
#if RGENGC_PROFILE
S(total_generated_normal_object_count);
S(total_generated_shady_object_count);
@@ -11337,12 +11303,6 @@ setup_gc_stat_symbols(void)
}
}
-static uint64_t
-ns_to_ms(uint64_t ns)
-{
- return ns / (1000 * 1000);
-}
-
static size_t
gc_stat_internal(VALUE hash_or_sym)
{
@@ -11368,9 +11328,7 @@ gc_stat_internal(VALUE hash_or_sym)
rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
SET(count, objspace->profile.count);
- SET(time, (size_t)ns_to_ms(objspace->profile.marking_time_ns + objspace->profile.sweeping_time_ns)); // TODO: UINT64T2NUM
- SET(marking_time, (size_t)ns_to_ms(objspace->profile.marking_time_ns));
- SET(sweeping_time, (size_t)ns_to_ms(objspace->profile.sweeping_time_ns));
+ SET(time, (size_t) (objspace->profile.total_time_ns / (1000 * 1000) /* ns -> ms */)); // TODO: UINT64T2NUM
/* implementation dependent counters */
SET(heap_allocated_pages, heap_allocated_pages);
@@ -11385,8 +11343,8 @@ gc_stat_internal(VALUE hash_or_sym)
SET(heap_tomb_pages, heap_tomb_total_pages(objspace));
SET(total_allocated_pages, total_allocated_pages(objspace));
SET(total_freed_pages, total_freed_pages(objspace));
- SET(total_allocated_objects, total_allocated_objects(objspace));
- SET(total_freed_objects, total_freed_objects(objspace));
+ SET(total_allocated_objects, objspace->total_allocated_objects);
+ SET(total_freed_objects, objspace->profile.total_freed_objects);
SET(malloc_increase_bytes, malloc_increase);
SET(malloc_increase_bytes_limit, malloc_limit);
SET(minor_gc_count, objspace->profile.minor_gc_count);
@@ -11476,9 +11434,6 @@ enum gc_stat_heap_sym {
gc_stat_heap_sym_total_allocated_pages,
gc_stat_heap_sym_total_freed_pages,
gc_stat_heap_sym_force_major_gc_count,
- gc_stat_heap_sym_force_incremental_marking_finish_count,
- gc_stat_heap_sym_total_allocated_objects,
- gc_stat_heap_sym_total_freed_objects,
gc_stat_heap_sym_last
};
@@ -11498,9 +11453,6 @@ setup_gc_stat_heap_symbols(void)
S(total_allocated_pages);
S(total_freed_pages);
S(force_major_gc_count);
- S(force_incremental_marking_finish_count);
- S(total_allocated_objects);
- S(total_freed_objects);
#undef S
}
}
@@ -11544,9 +11496,6 @@ gc_stat_heap_internal(int size_pool_idx, VALUE hash_or_sym)
SET(total_allocated_pages, size_pool->total_allocated_pages);
SET(total_freed_pages, size_pool->total_freed_pages);
SET(force_major_gc_count, size_pool->force_major_gc_count);
- SET(force_incremental_marking_finish_count, size_pool->force_incremental_marking_finish_count);
- SET(total_allocated_objects, size_pool->total_allocated_objects);
- SET(total_freed_objects, size_pool->total_freed_objects);
#undef SET
if (!NIL_P(key)) { /* matched key should return above */
@@ -11830,20 +11779,14 @@ gc_set_initial_pages(rb_objspace_t *objspace)
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
rb_size_pool_t *size_pool = &size_pools[i];
- char env_key[sizeof("RUBY_GC_HEAP_" "_INIT_SLOTS") + DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT)];
- snprintf(env_key, sizeof(env_key), "RUBY_GC_HEAP_%d_INIT_SLOTS", i);
- size_t size_pool_init_slots = gc_params.size_pool_init_slots[i];
- if (get_envparam_size(env_key, &size_pool_init_slots, 0)) {
- gc_params.size_pool_init_slots[i] = size_pool_init_slots;
- }
-
- if (size_pool_init_slots > size_pool->eden_heap.total_slots) {
- size_t slots = size_pool_init_slots - size_pool->eden_heap.total_slots;
- size_pool->allocatable_pages = slots_to_pages_for_size_pool(objspace, size_pool, slots);
+ if (gc_params.heap_init_slots > size_pool->eden_heap.total_slots) {
+ size_t slots = gc_params.heap_init_slots - size_pool->eden_heap.total_slots;
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ size_pool->allocatable_pages = slots * multiple / HEAP_PAGE_OBJ_LIMIT;
}
else {
- /* We already have more slots than size_pool_init_slots allows, so
+ /* We already have more slots than heap_init_slots allows, so
* prevent creating more pages. */
size_pool->allocatable_pages = 0;
}
@@ -11854,6 +11797,8 @@ gc_set_initial_pages(rb_objspace_t *objspace)
/*
* GC tuning environment variables
*
+ * * RUBY_GC_HEAP_INIT_SLOTS
+ * - Initial allocation slots.
* * RUBY_GC_HEAP_FREE_SLOTS
* - Prepare at least this amount of slots after GC.
* - Allocate slots if there are not enough slots.
@@ -11900,7 +11845,10 @@ ruby_gc_set_params(void)
/* ok */
}
- gc_set_initial_pages(objspace);
+ /* RUBY_GC_HEAP_INIT_SLOTS */
+ if (get_envparam_size("RUBY_GC_HEAP_INIT_SLOTS", &gc_params.heap_init_slots, 0)) {
+ gc_set_initial_pages(objspace);
+ }
get_envparam_double("RUBY_GC_HEAP_GROWTH_FACTOR", &gc_params.growth_factor, 1.0, 0.0, FALSE);
get_envparam_size ("RUBY_GC_HEAP_GROWTH_MAX_SLOTS", &gc_params.growth_max_slots, 0);
@@ -11911,7 +11859,6 @@ ruby_gc_set_params(void)
get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO", &gc_params.heap_free_slots_goal_ratio,
gc_params.heap_free_slots_min_ratio, gc_params.heap_free_slots_max_ratio, TRUE);
get_envparam_double("RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR", &gc_params.oldobject_limit_factor, 0.0, 0.0, TRUE);
- get_envparam_double("RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO", &gc_params.uncollectible_wb_unprotected_objects_limit_ratio, 0.0, 0.0, TRUE);
if (get_envparam_size("RUBY_GC_MALLOC_LIMIT", &gc_params.malloc_limit_min, 0)) {
malloc_limit = gc_params.malloc_limit_min;
@@ -11947,7 +11894,7 @@ rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *
{
if (during_gc) rb_bug("rb_objspace_reachable_objects_from() is not supported while during_gc == true");
- if (is_markable_object(obj)) {
+ if (is_markable_object(objspace, obj)) {
rb_ractor_t *cr = GET_RACTOR();
struct gc_mark_func_data_struct mfd = {
.mark_func = func,
@@ -12323,7 +12270,7 @@ malloc_during_gc_p(rb_objspace_t *objspace)
* (since ractors can run while another thread is sweeping) and when we
* have the GVL (since if we don't have the GVL, we'll try to acquire the
* GVL which will block and ensure the other thread finishes GC). */
- return during_gc && !dont_gc_val() && !rb_multi_ractor_p() && ruby_thread_has_gvl_p();
+ return during_gc && !rb_multi_ractor_p() && ruby_thread_has_gvl_p();
}
static inline void *
@@ -12890,8 +12837,7 @@ gc_malloc_allocations(VALUE self)
void
rb_gc_adjust_memory_usage(ssize_t diff)
{
- unless_objspace(objspace) { return; }
-
+ rb_objspace_t *objspace = &rb_objspace;
if (diff > 0) {
objspace_malloc_increase(objspace, 0, diff, 0, MEMOP_TYPE_REALLOC);
}
@@ -12901,6 +12847,573 @@ rb_gc_adjust_memory_usage(ssize_t diff)
}
/*
+ ------------------------------ WeakMap ------------------------------
+*/
+
+struct weakmap {
+ st_table *obj2wmap; /* obj -> [ref,...] */
+ st_table *wmap2obj; /* ref -> obj */
+ VALUE final;
+};
+
+#define WMAP_DELETE_DEAD_OBJECT_IN_MARK 0
+
+#if WMAP_DELETE_DEAD_OBJECT_IN_MARK
+static int
+wmap_mark_map(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+ VALUE obj = (VALUE)val;
+ if (!is_live_object(objspace, obj)) return ST_DELETE;
+ return ST_CONTINUE;
+}
+#endif
+
+static int
+wmap_replace_ref(st_data_t *key, st_data_t *value, st_data_t _argp, int existing)
+{
+ *key = rb_gc_location((VALUE)*key);
+
+ VALUE *values = (VALUE *)*value;
+ VALUE size = values[0];
+
+ for (VALUE index = 1; index <= size; index++) {
+ values[index] = rb_gc_location(values[index]);
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+wmap_foreach_replace(st_data_t key, st_data_t value, st_data_t _argp, int error)
+{
+ if (rb_gc_location((VALUE)key) != (VALUE)key) {
+ return ST_REPLACE;
+ }
+
+ VALUE *values = (VALUE *)value;
+ VALUE size = values[0];
+
+ for (VALUE index = 1; index <= size; index++) {
+ VALUE val = values[index];
+ if (rb_gc_location(val) != val) {
+ return ST_REPLACE;
+ }
+ }
+
+ return ST_CONTINUE;
+}
+
+static void
+wmap_compact(void *ptr)
+{
+ struct weakmap *w = ptr;
+ if (w->wmap2obj) rb_gc_update_tbl_refs(w->wmap2obj);
+ if (w->obj2wmap) st_foreach_with_replace(w->obj2wmap, wmap_foreach_replace, wmap_replace_ref, (st_data_t)NULL);
+ w->final = rb_gc_location(w->final);
+}
+
+static void
+wmap_mark(void *ptr)
+{
+ struct weakmap *w = ptr;
+#if WMAP_DELETE_DEAD_OBJECT_IN_MARK
+ if (w->obj2wmap) st_foreach(w->obj2wmap, wmap_mark_map, (st_data_t)&rb_objspace);
+#endif
+ rb_gc_mark_movable(w->final);
+}
+
+static int
+wmap_free_map(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE *ptr = (VALUE *)val;
+ ruby_sized_xfree(ptr, (ptr[0] + 1) * sizeof(VALUE));
+ return ST_CONTINUE;
+}
+
+static void
+wmap_free(void *ptr)
+{
+ struct weakmap *w = ptr;
+ st_foreach(w->obj2wmap, wmap_free_map, 0);
+ st_free_table(w->obj2wmap);
+ st_free_table(w->wmap2obj);
+ xfree(w);
+}
+
+static int
+wmap_memsize_map(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE *ptr = (VALUE *)val;
+ *(size_t *)arg += (ptr[0] + 1) * sizeof(VALUE);
+ return ST_CONTINUE;
+}
+
+static size_t
+wmap_memsize(const void *ptr)
+{
+ size_t size;
+ const struct weakmap *w = ptr;
+ size = sizeof(*w);
+ size += st_memsize(w->obj2wmap);
+ size += st_memsize(w->wmap2obj);
+ st_foreach(w->obj2wmap, wmap_memsize_map, (st_data_t)&size);
+ return size;
+}
+
+static const rb_data_type_t weakmap_type = {
+ "weakmap",
+ {
+ wmap_mark,
+ wmap_free,
+ wmap_memsize,
+ wmap_compact,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+};
+
+static VALUE wmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self));
+
+static VALUE
+wmap_allocate(VALUE klass)
+{
+ struct weakmap *w;
+ VALUE obj = TypedData_Make_Struct(klass, struct weakmap, &weakmap_type, w);
+ w->obj2wmap = rb_init_identtable();
+ w->wmap2obj = rb_init_identtable();
+ w->final = rb_func_lambda_new(wmap_finalize, obj, 1, 1);
+ return obj;
+}
+
+static int
+wmap_live_p(rb_objspace_t *objspace, VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) return TRUE;
+ /* If is_pointer_to_heap returns false, the page could be in the tomb heap
+ * or have already been freed. */
+ if (!is_pointer_to_heap(objspace, (void *)obj)) return FALSE;
+
+ void *poisoned = asan_unpoison_object_temporary(obj);
+
+ enum ruby_value_type t = BUILTIN_TYPE(obj);
+ int ret = (!(t == T_NONE || t >= T_FIXNUM || t == T_ICLASS) &&
+ is_live_object(objspace, obj));
+
+ if (poisoned) {
+ asan_poison_object(obj);
+ }
+
+ return ret;
+}
+
+static int
+wmap_remove_inverse_ref(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
+{
+ if (!existing) return ST_STOP;
+
+ VALUE old_ref = (VALUE)arg;
+
+ VALUE *values = (VALUE *)*val;
+ VALUE size = values[0];
+
+ if (size == 1) {
+ // fast path, we only had one backref
+ RUBY_ASSERT(values[1] == old_ref);
+ ruby_sized_xfree(values, 2 * sizeof(VALUE));
+ return ST_DELETE;
+ }
+
+ bool found = false;
+ VALUE index = 1;
+ for (; index <= size; index++) {
+ if (values[index] == old_ref) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return ST_STOP;
+
+ if (size > index) {
+ MEMMOVE(&values[index], &values[index + 1], VALUE, size - index);
+ }
+
+ size -= 1;
+ values[0] = size;
+ SIZED_REALLOC_N(values, VALUE, size + 1, size + 2);
+ *val = (st_data_t)values;
+ return ST_CONTINUE;
+}
+
+/* :nodoc: */
+static VALUE
+wmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self))
+{
+ st_data_t orig, wmap, data;
+ VALUE obj, *rids, i, size;
+ struct weakmap *w;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ /* Get reference from object id. */
+ if (UNDEF_P(obj = id2ref_obj_tbl(&rb_objspace, objid))) {
+ rb_bug("wmap_finalize: objid is not found.");
+ }
+
+ /* obj is original referenced object and/or weak reference. */
+ orig = (st_data_t)obj;
+ if (st_delete(w->obj2wmap, &orig, &data)) {
+ rids = (VALUE *)data;
+ size = *rids++;
+ for (i = 0; i < size; ++i) {
+ wmap = (st_data_t)rids[i];
+ st_delete(w->wmap2obj, &wmap, NULL);
+ }
+ ruby_sized_xfree((VALUE *)data, (size + 1) * sizeof(VALUE));
+ }
+
+ wmap = (st_data_t)obj;
+ if (st_delete(w->wmap2obj, &wmap, &orig)) {
+ wmap = (st_data_t)obj;
+ st_update(w->obj2wmap, orig, wmap_remove_inverse_ref, wmap);
+ }
+ return self;
+}
+
+struct wmap_iter_arg {
+ rb_objspace_t *objspace;
+ VALUE value;
+};
+
+static VALUE
+wmap_inspect_append(rb_objspace_t *objspace, VALUE str, VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) {
+ return rb_str_append(str, rb_inspect(obj));
+ }
+ else if (wmap_live_p(objspace, obj)) {
+ return rb_str_append(str, rb_any_to_s(obj));
+ }
+ else {
+ return rb_str_catf(str, "#<collected:%p>", (void*)obj);
+ }
+}
+
+static int
+wmap_inspect_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
+ rb_objspace_t *objspace = argp->objspace;
+ VALUE str = argp->value;
+ VALUE k = (VALUE)key, v = (VALUE)val;
+
+ if (RSTRING_PTR(str)[0] == '#') {
+ rb_str_cat2(str, ", ");
+ }
+ else {
+ rb_str_cat2(str, ": ");
+ RSTRING_PTR(str)[0] = '#';
+ }
+ wmap_inspect_append(objspace, str, k);
+ rb_str_cat2(str, " => ");
+ wmap_inspect_append(objspace, str, v);
+
+ return ST_CONTINUE;
+}
+
+static VALUE
+wmap_inspect(VALUE self)
+{
+ VALUE str;
+ VALUE c = rb_class_name(CLASS_OF(self));
+ struct weakmap *w;
+ struct wmap_iter_arg args;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void *)self);
+ if (w->wmap2obj) {
+ args.objspace = &rb_objspace;
+ args.value = str;
+ st_foreach(w->wmap2obj, wmap_inspect_i, (st_data_t)&args);
+ }
+ RSTRING_PTR(str)[0] = '#';
+ rb_str_cat2(str, ">");
+ return str;
+}
+
+static inline bool
+wmap_live_entry_p(rb_objspace_t *objspace, st_data_t key, st_data_t val)
+{
+ return wmap_live_p(objspace, (VALUE)key) && wmap_live_p(objspace, (VALUE)val);
+}
+
+static int
+wmap_each_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_yield_values(2, (VALUE)key, (VALUE)val);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_each(VALUE self)
+{
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ st_foreach(w->wmap2obj, wmap_each_i, (st_data_t)objspace);
+ return self;
+}
+
+static int
+wmap_each_key_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_yield((VALUE)key);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_each_key(VALUE self)
+{
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ st_foreach(w->wmap2obj, wmap_each_key_i, (st_data_t)objspace);
+ return self;
+}
+
+static int
+wmap_each_value_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_yield((VALUE)val);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_each_value(VALUE self)
+{
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ st_foreach(w->wmap2obj, wmap_each_value_i, (st_data_t)objspace);
+ return self;
+}
+
+static int
+wmap_keys_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
+ rb_objspace_t *objspace = argp->objspace;
+ VALUE ary = argp->value;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_ary_push(ary, (VALUE)key);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_keys(VALUE self)
+{
+ struct weakmap *w;
+ struct wmap_iter_arg args;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ args.objspace = &rb_objspace;
+ args.value = rb_ary_new();
+ st_foreach(w->wmap2obj, wmap_keys_i, (st_data_t)&args);
+ return args.value;
+}
+
+static int
+wmap_values_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
+ rb_objspace_t *objspace = argp->objspace;
+ VALUE ary = argp->value;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_ary_push(ary, (VALUE)val);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over values and objects in a weakly referenced object */
+static VALUE
+wmap_values(VALUE self)
+{
+ struct weakmap *w;
+ struct wmap_iter_arg args;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ args.objspace = &rb_objspace;
+ args.value = rb_ary_new();
+ st_foreach(w->wmap2obj, wmap_values_i, (st_data_t)&args);
+ return args.value;
+}
+
+static int
+wmap_aset_update(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
+{
+ VALUE size, *ptr, *optr;
+ if (existing) {
+ size = (ptr = optr = (VALUE *)*val)[0];
+
+ for (VALUE index = 1; index <= size; index++) {
+ if (ptr[index] == (VALUE)arg) {
+ // The reference was already registered.
+ return ST_STOP;
+ }
+ }
+
+ ++size;
+ SIZED_REALLOC_N(ptr, VALUE, size + 1, size);
+ }
+ else {
+ optr = 0;
+ size = 1;
+ ptr = ruby_xmalloc0(2 * sizeof(VALUE));
+ }
+ ptr[0] = size;
+ ptr[size] = (VALUE)arg;
+ if (ptr == optr) return ST_STOP;
+ *val = (st_data_t)ptr;
+ return ST_CONTINUE;
+}
+
+struct wmap_aset_replace_args {
+ VALUE new_value;
+ VALUE old_value;
+};
+
+static int
+wmap_aset_replace_value(st_data_t *key, st_data_t *val, st_data_t _args, int existing)
+{
+ struct wmap_aset_replace_args *args = (struct wmap_aset_replace_args *)_args;
+
+ if (existing) {
+ args->old_value = *val;
+ }
+ *val = (st_data_t)args->new_value;
+ return ST_CONTINUE;
+}
+
+/* Creates a weak reference from the given key to the given value */
+static VALUE
+wmap_aset(VALUE self, VALUE key, VALUE value)
+{
+ struct weakmap *w;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ if (FL_ABLE(value)) {
+ define_final0(value, w->final);
+ }
+ if (FL_ABLE(key)) {
+ define_final0(key, w->final);
+ }
+
+ struct wmap_aset_replace_args aset_args = {
+ .new_value = value,
+ .old_value = Qundef,
+ };
+ st_update(w->wmap2obj, (st_data_t)key, wmap_aset_replace_value, (st_data_t)&aset_args);
+
+ // If the value is unchanged, we have nothing to do.
+ if (value != aset_args.old_value) {
+ if (!UNDEF_P(aset_args.old_value) && FL_ABLE(aset_args.old_value)) {
+ // That key existed and had an inverse reference, we need to clear the outdated inverse reference.
+ st_update(w->obj2wmap, (st_data_t)aset_args.old_value, wmap_remove_inverse_ref, key);
+ }
+
+ if (FL_ABLE(value)) {
+ // If the value has no finalizer, we don't need to keep the inverse reference
+ st_update(w->obj2wmap, (st_data_t)value, wmap_aset_update, key);
+ }
+ }
+
+ return nonspecial_obj_id(value);
+}
+
+/* Retrieves a weakly referenced object with the given key */
+static VALUE
+wmap_lookup(VALUE self, VALUE key)
+{
+ st_data_t data;
+ VALUE obj;
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+ GC_ASSERT(wmap_live_p(objspace, key));
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ if (!st_lookup(w->wmap2obj, (st_data_t)key, &data)) return Qundef;
+ obj = (VALUE)data;
+ if (!wmap_live_p(objspace, obj)) return Qundef;
+ return obj;
+}
+
+/* Retrieves a weakly referenced object with the given key */
+static VALUE
+wmap_aref(VALUE self, VALUE key)
+{
+ VALUE obj = wmap_lookup(self, key);
+ return !UNDEF_P(obj) ? obj : Qnil;
+}
+
+/* Returns +true+ if +key+ is registered */
+static VALUE
+wmap_has_key(VALUE self, VALUE key)
+{
+ return RBOOL(!UNDEF_P(wmap_lookup(self, key)));
+}
+
+/* Returns the number of referenced objects */
+static VALUE
+wmap_size(VALUE self)
+{
+ struct weakmap *w;
+ st_index_t n;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ n = w->wmap2obj->num_entries;
+#if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
+ return ULONG2NUM(n);
+#else
+ return ULL2NUM(n);
+#endif
+}
+
+/*
------------------------------ GC profiler ------------------------------
*/
@@ -13129,7 +13642,7 @@ gc_prof_set_heap_info(rb_objspace_t *objspace)
{
if (gc_prof_enabled(objspace)) {
gc_profile_record *record = gc_prof_record(objspace);
- size_t live = objspace->profile.total_allocated_objects_at_gc_start - total_freed_objects(objspace);
+ size_t live = objspace->profile.total_allocated_objects_at_gc_start - objspace->profile.total_freed_objects;
size_t total = objspace->profile.heap_used_at_gc_start * HEAP_PAGE_OBJ_LIMIT;
#if GC_PROFILE_MORE_DETAIL
@@ -13161,7 +13674,9 @@ gc_profile_clear(VALUE _)
objspace->profile.size = 0;
objspace->profile.next_index = 0;
objspace->profile.current_record = 0;
- free(p);
+ if (p) {
+ free(p);
+ }
return Qnil;
}
@@ -13625,7 +14140,7 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj
}
}
else {
- const int age = RVALUE_AGE_GET(obj);
+ const int age = RVALUE_FLAGS_AGE(RBASIC(obj)->flags);
if (is_pointer_to_heap(&rb_objspace, (void *)obj)) {
APPEND_F("%p [%d%s%s%s%s%s%s] %s ",
@@ -13689,12 +14204,13 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
RARRAY_LEN(obj));
}
else {
- APPEND_F("[%s%s] len: %ld, capa:%ld ptr:%p",
+ APPEND_F("[%s%s%s] len: %ld, capa:%ld ptr:%p",
C(ARY_EMBED_P(obj), "E"),
C(ARY_SHARED_P(obj), "S"),
+ C(RARRAY_TRANSIENT_P(obj), "T"),
RARRAY_LEN(obj),
ARY_EMBED_P(obj) ? -1L : RARRAY(obj)->as.heap.aux.capa,
- (void *)RARRAY_CONST_PTR(obj));
+ (void *)RARRAY_CONST_PTR_TRANSIENT(obj));
}
break;
case T_STRING: {
@@ -13725,8 +14241,9 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
break;
}
case T_HASH: {
- APPEND_F("[%c] %"PRIdSIZE,
+ APPEND_F("[%c%c] %"PRIdSIZE,
RHASH_AR_TABLE_P(obj) ? 'A' : 'S',
+ RHASH_TRANSIENT_P(obj) ? 'T' : ' ',
RHASH_SIZE(obj));
break;
}
@@ -13738,7 +14255,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
APPEND_F("%s", RSTRING_PTR(class_path));
}
else {
- APPEND_S("(anon)");
+ APPEND_S("(annon)");
}
break;
}
@@ -13916,7 +14433,7 @@ obj_info(VALUE obj)
}
#endif
-const char *
+MJIT_FUNC_EXPORTED const char *
rb_obj_info(VALUE obj)
{
return obj_info(obj);
@@ -13929,7 +14446,7 @@ rb_obj_info_dump(VALUE obj)
fprintf(stderr, "rb_obj_info_dump: %s\n", rb_raw_obj_info(buff, 0x100, obj));
}
-void
+MJIT_FUNC_EXPORTED void
rb_obj_info_dump_loc(VALUE obj, const char *file, int line, const char *func)
{
char buff[0x100];
@@ -13961,14 +14478,14 @@ rb_gcdebug_print_obj_condition(VALUE obj)
fprintf(stderr, "marked? : %s\n", MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) ? "true" : "false");
fprintf(stderr, "pinned? : %s\n", MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj) ? "true" : "false");
- fprintf(stderr, "age? : %d\n", RVALUE_AGE_GET(obj));
+ fprintf(stderr, "age? : %d\n", RVALUE_AGE(obj));
fprintf(stderr, "old? : %s\n", RVALUE_OLD_P(obj) ? "true" : "false");
fprintf(stderr, "WB-protected?: %s\n", RVALUE_WB_UNPROTECTED(obj) ? "false" : "true");
fprintf(stderr, "remembered? : %s\n", RVALUE_REMEMBERED(obj) ? "true" : "false");
if (is_lazy_sweeping(objspace)) {
fprintf(stderr, "lazy sweeping?: true\n");
- fprintf(stderr, "swept?: %s\n", is_swept_object(obj) ? "done" : "not yet");
+ fprintf(stderr, "swept?: %s\n", is_swept_object(objspace, obj) ? "done" : "not yet");
}
else {
fprintf(stderr, "lazy sweeping?: false\n");
@@ -13990,6 +14507,7 @@ rb_gcdebug_sentinel(VALUE obj, const char *name)
#endif /* GC_DEBUG */
+#if GC_DEBUG_STRESS_TO_CLASS
/*
* call-seq:
* GC.add_stress_to_class(class[, ...])
@@ -14003,7 +14521,7 @@ rb_gcdebug_add_stress_to_class(int argc, VALUE *argv, VALUE self)
rb_objspace_t *objspace = &rb_objspace;
if (!stress_to_class) {
- set_stress_to_class(rb_ary_hidden_new(argc));
+ stress_to_class = rb_ary_hidden_new(argc);
}
rb_ary_cat(stress_to_class, argv, argc);
return self;
@@ -14028,11 +14546,12 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
rb_ary_delete_same(stress_to_class, argv[i]);
}
if (RARRAY_LEN(stress_to_class) == 0) {
- set_stress_to_class(0);
+ stress_to_class = 0;
}
}
return Qnil;
}
+#endif
/*
* Document-module: ObjectSpace
@@ -14062,6 +14581,16 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
* Finalizer one on 537763480
*/
+/*
+ * Document-class: ObjectSpace::WeakMap
+ *
+ * An ObjectSpace::WeakMap object holds references to
+ * any objects, but those objects can get garbage collected.
+ *
+ * This class is mostly used internally by WeakRef, please use
+ * +lib/weakref.rb+ for the public interface.
+ */
+
/* Document-class: GC::Profiler
*
* The GC profiler provides access to information on GC runs including time,
@@ -14081,13 +14610,27 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
*/
#include "gc.rbinc"
+/*
+ * call-seq:
+ * GC.using_rvargc? -> true or false
+ *
+ * Returns true if using experimental feature Variable Width Allocation, false
+ * otherwise.
+ */
+static VALUE
+gc_using_rvargc_p(VALUE mod)
+{
+#if USE_RVARGC
+ return Qtrue;
+#else
+ return Qfalse;
+#endif
+}
void
Init_GC(void)
{
#undef rb_intern
- malloc_offset = gc_compute_malloc_offset();
-
VALUE rb_mObjSpace;
VALUE rb_mProfiler;
VALUE gc_constants;
@@ -14104,12 +14647,8 @@ Init_GC(void)
rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_SIZE")), SIZET2NUM(HEAP_PAGE_SIZE));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(SIZE_POOL_COUNT));
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(size_pool_slot_size(SIZE_POOL_COUNT - 1)));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), LONG2FIX(RVALUE_OLD_AGE));
- if (RB_BUG_INSTEAD_OF_RB_MEMERROR+0) {
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RB_BUG_INSTEAD_OF_RB_MEMERROR")), Qtrue);
- }
OBJ_FREEZE(gc_constants);
- /* Internal constants in the garbage collector. */
+ /* internal constants */
rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
@@ -14138,13 +14677,36 @@ Init_GC(void)
rb_define_module_function(rb_mObjSpace, "count_objects", count_objects, -1);
+ {
+ VALUE rb_cWeakMap = rb_define_class_under(rb_mObjSpace, "WeakMap", rb_cObject);
+ rb_define_alloc_func(rb_cWeakMap, wmap_allocate);
+ rb_define_method(rb_cWeakMap, "[]=", wmap_aset, 2);
+ rb_define_method(rb_cWeakMap, "[]", wmap_aref, 1);
+ rb_define_method(rb_cWeakMap, "include?", wmap_has_key, 1);
+ rb_define_method(rb_cWeakMap, "member?", wmap_has_key, 1);
+ rb_define_method(rb_cWeakMap, "key?", wmap_has_key, 1);
+ rb_define_method(rb_cWeakMap, "inspect", wmap_inspect, 0);
+ rb_define_method(rb_cWeakMap, "each", wmap_each, 0);
+ rb_define_method(rb_cWeakMap, "each_pair", wmap_each, 0);
+ rb_define_method(rb_cWeakMap, "each_key", wmap_each_key, 0);
+ rb_define_method(rb_cWeakMap, "each_value", wmap_each_value, 0);
+ rb_define_method(rb_cWeakMap, "keys", wmap_keys, 0);
+ rb_define_method(rb_cWeakMap, "values", wmap_values, 0);
+ rb_define_method(rb_cWeakMap, "size", wmap_size, 0);
+ rb_define_method(rb_cWeakMap, "length", wmap_size, 0);
+ rb_include_module(rb_cWeakMap, rb_mEnumerable);
+ }
+
/* internal methods */
rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency_m, 0);
+ rb_define_singleton_method(rb_mGC, "verify_transient_heap_internal_consistency", gc_verify_transient_heap_internal_consistency, 0);
#if MALLOC_ALLOCATED_SIZE
rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
#endif
+ rb_define_singleton_method(rb_mGC, "using_rvargc?", gc_using_rvargc_p, 0);
+
if (GC_COMPACTION_SUPPORTED) {
rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
@@ -14160,10 +14722,10 @@ Init_GC(void)
rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1);
}
- if (GC_DEBUG_STRESS_TO_CLASS) {
- rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1);
- rb_define_singleton_method(rb_mGC, "remove_stress_to_class", rb_gcdebug_remove_stress_to_class, -1);
- }
+#if GC_DEBUG_STRESS_TO_CLASS
+ rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1);
+ rb_define_singleton_method(rb_mGC, "remove_stress_to_class", rb_gcdebug_remove_stress_to_class, -1);
+#endif
{
VALUE opts;
diff --git a/gc.h b/gc.h
new file mode 100644
index 0000000000..23218c1a9e
--- /dev/null
+++ b/gc.h
@@ -0,0 +1,147 @@
+#ifndef RUBY_GC_H
+#define RUBY_GC_H 1
+#include "ruby/ruby.h"
+
+#if defined(__x86_64__) && !defined(_ILP32) && defined(__GNUC__)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movq\t%%rsp, %0" : "=r" (*(p)))
+#elif defined(__i386) && defined(__GNUC__)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p)))
+#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && !defined(_AIX) && !defined(__APPLE__) // Not Apple is NEEDED to unbreak ppc64 build on Darwin. Don't ask.
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p)))
+#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && defined(_AIX)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr %0,1" : "=r" (*(p)))
+#elif defined(__POWERPC__) && defined(__APPLE__) // Darwin ppc and ppc64
+#define SET_MACHINE_STACK_END(p) __asm__ volatile("mr %0, r1" : "=r" (*(p)))
+#elif defined(__aarch64__) && defined(__GNUC__)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p)))
+#else
+NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
+#define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
+#define USE_CONSERVATIVE_STACK_END
+#endif
+
+#define RB_GC_SAVE_MACHINE_CONTEXT(th) \
+ do { \
+ FLUSH_REGISTER_WINDOWS; \
+ setjmp((th)->ec->machine.regs); \
+ SET_MACHINE_STACK_END(&(th)->ec->machine.stack_end); \
+ } while (0)
+
+/* for GC debug */
+
+#ifndef RUBY_MARK_FREE_DEBUG
+#define RUBY_MARK_FREE_DEBUG 0
+#endif
+
+#if RUBY_MARK_FREE_DEBUG
+extern int ruby_gc_debug_indent;
+
+static inline void
+rb_gc_debug_indent(void)
+{
+ ruby_debug_printf("%*s", ruby_gc_debug_indent, "");
+}
+
+static inline void
+rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
+{
+ if (st == 0) {
+ ruby_gc_debug_indent--;
+ }
+ rb_gc_debug_indent();
+ ruby_debug_printf("%s: %s %s (%p)\n", mode, st ? "->" : "<-", msg, ptr);
+
+ if (st) {
+ ruby_gc_debug_indent++;
+ }
+
+ fflush(stdout);
+}
+
+#define RUBY_MARK_ENTER(msg) rb_gc_debug_body("mark", (msg), 1, ptr)
+#define RUBY_MARK_LEAVE(msg) rb_gc_debug_body("mark", (msg), 0, ptr)
+#define RUBY_FREE_ENTER(msg) rb_gc_debug_body("free", (msg), 1, ptr)
+#define RUBY_FREE_LEAVE(msg) rb_gc_debug_body("free", (msg), 0, ptr)
+#define RUBY_GC_INFO rb_gc_debug_indent(), ruby_debug_printf
+
+#else
+#define RUBY_MARK_ENTER(msg)
+#define RUBY_MARK_LEAVE(msg)
+#define RUBY_FREE_ENTER(msg)
+#define RUBY_FREE_LEAVE(msg)
+#define RUBY_GC_INFO if(0)printf
+#endif
+
+#define RUBY_MARK_MOVABLE_UNLESS_NULL(ptr) do { \
+ VALUE markobj = (ptr); \
+ if (RTEST(markobj)) {rb_gc_mark_movable(markobj);} \
+} while (0)
+#define RUBY_MARK_UNLESS_NULL(ptr) do { \
+ VALUE markobj = (ptr); \
+ if (RTEST(markobj)) {rb_gc_mark(markobj);} \
+} while (0)
+#define RUBY_FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);(ptr)=NULL;}
+
+#if STACK_GROW_DIRECTION > 0
+# define STACK_UPPER(x, a, b) (a)
+#elif STACK_GROW_DIRECTION < 0
+# define STACK_UPPER(x, a, b) (b)
+#else
+RUBY_EXTERN int ruby_stack_grow_direction;
+int ruby_get_stack_grow_direction(volatile VALUE *addr);
+# define stack_growup_p(x) ( \
+ (ruby_stack_grow_direction ? \
+ ruby_stack_grow_direction : \
+ ruby_get_stack_grow_direction(x)) > 0)
+# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? (a) : (b))
+#endif
+
+/*
+ STACK_GROW_DIR_DETECTION is used with STACK_DIR_UPPER.
+
+ On most normal systems, stacks grow from high address to lower address. In
+ this case, STACK_DIR_UPPER(a, b) will return (b), but on exotic systems where
+ the stack grows UP (from low address to high address), it will return (a).
+*/
+
+#if STACK_GROW_DIRECTION
+#define STACK_GROW_DIR_DETECTION
+#define STACK_DIR_UPPER(a,b) STACK_UPPER(0, (a), (b))
+#else
+#define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection
+#define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, (a), (b))
+#endif
+#define IS_STACK_DIR_UPPER() STACK_DIR_UPPER(1,0)
+
+const char *rb_obj_info(VALUE obj);
+const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
+
+struct rb_thread_struct;
+
+size_t rb_size_pool_slot_size(unsigned char pool_id);
+
+RUBY_SYMBOL_EXPORT_BEGIN
+
+/* exports for objspace module */
+size_t rb_objspace_data_type_memsize(VALUE obj);
+void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
+void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *data);
+int rb_objspace_markable_object_p(VALUE obj);
+int rb_objspace_internal_object_p(VALUE obj);
+int rb_objspace_marked_object_p(VALUE obj);
+
+void rb_objspace_each_objects(
+ int (*callback)(void *start, void *end, size_t stride, void *data),
+ void *data);
+
+void rb_objspace_each_objects_without_setup(
+ int (*callback)(void *, void *, size_t, void *),
+ void *data);
+
+size_t rb_gc_obj_slot_size(VALUE obj);
+
+VALUE rb_gc_disable_no_rest(void);
+
+RUBY_SYMBOL_EXPORT_END
+
+#endif /* RUBY_GC_H */
diff --git a/gc.rb b/gc.rb
index c3b104454c..57aeeb9131 100644
--- a/gc.rb
+++ b/gc.rb
@@ -1,6 +1,6 @@
# for gc.c
-# The \GC module provides an interface to Ruby's mark and
+# The GC module provides an interface to Ruby's mark and
# sweep garbage collection mechanism.
#
# Some of the underlying methods are also available via the ObjectSpace
@@ -10,31 +10,26 @@
# GC::Profiler.
module GC
- # Initiates garbage collection, even if manually disabled.
- #
- # The +full_mark+ keyword argument determines whether or not to perform a
- # major garbage collection cycle. When set to +true+, a major garbage
- # collection cycle is ran, meaning all objects are marked. When set to
- # +false+, a minor garbage collection cycle is ran, meaning only young
- # objects are marked.
- #
- # The +immediate_mark+ keyword argument determines whether or not to perform
- # incremental marking. When set to +true+, marking is completed during the
- # call to this method. When set to +false+, marking is performed in steps
- # that is interleaved with future Ruby code execution, so marking might not
- # be completed during this method call. Note that if +full_mark+ is +false+
- # then marking will always be immediate, regardless of the value of
- # +immediate_mark+.
- #
- # The +immedate_sweep+ keyword argument determines whether or not to defer
- # sweeping (using lazy sweep). When set to +true+, sweeping is performed in
- # steps that is interleaved with future Ruby code execution, so sweeping might
- # not be completed during this method call. When set to +false+, sweeping is
- # completed during the call to this method.
- #
- # Note: These keyword arguments are implementation and version dependent. They
- # are not guaranteed to be future-compatible, and may be ignored if the
- # underlying implementation does not support them.
+ # call-seq:
+ # GC.start -> nil
+ # ObjectSpace.garbage_collect -> nil
+ # include GC; garbage_collect -> nil
+ # GC.start(full_mark: true, immediate_sweep: true) -> nil
+ # ObjectSpace.garbage_collect(full_mark: true, immediate_sweep: true) -> nil
+ # include GC; garbage_collect(full_mark: true, immediate_sweep: true) -> nil
+ #
+ # Initiates garbage collection, even if manually disabled.
+ #
+ # This method is defined with keyword arguments that default to true:
+ #
+ # def GC.start(full_mark: true, immediate_sweep: true); end
+ #
+ # Use full_mark: false to perform a minor \GC.
+ # Use immediate_sweep: false to defer sweeping (use lazy sweep).
+ #
+ # Note: These keyword arguments are implementation and version dependent. They
+ # are not guaranteed to be future-compatible, and may be ignored if the
+ # underlying implementation does not support them.
def self.start full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
@@ -123,14 +118,14 @@ module GC
# [time]
# The total time spent in garbage collections (in milliseconds)
# [heap_allocated_pages]
- # The total number of +:heap_eden_pages+ + +:heap_tomb_pages+
+ # The total number of `:heap_eden_pages` + `:heap_tomb_pages`
# [heap_sorted_length]
# The number of pages that can fit into the buffer that holds references to
# all pages
# [heap_allocatable_pages]
# The total number of pages the application could allocate without additional \GC
# [heap_available_slots]
- # The total number of slots in all +:heap_allocated_pages+
+ # The total number of slots in all `:heap_allocated_pages`
# [heap_live_slots]
# The total number of slots which contain live objects
# [heap_free_slots]
@@ -154,7 +149,7 @@ module GC
# [malloc_increase_bytes]
# Amount of memory allocated on the heap for objects. Decreased by any \GC
# [malloc_increase_bytes_limit]
- # When +:malloc_increase_bytes+ crosses this limit, \GC is triggered
+ # When `:malloc_increase_bytes` crosses this limit, \GC is triggered
# [minor_gc_count]
# The total number of minor garbage collections run since process start
# [major_gc_count]
@@ -169,16 +164,16 @@ module GC
# [remembered_wb_unprotected_objects]
# The total number of objects without write barriers
# [remembered_wb_unprotected_objects_limit]
- # When +:remembered_wb_unprotected_objects+ crosses this limit,
+ # When `:remembered_wb_unprotected_objects` crosses this limit,
# major \GC is triggered
# [old_objects]
# Number of live, old objects which have survived at least 3 garbage collections
# [old_objects_limit]
- # When +:old_objects+ crosses this limit, major \GC is triggered
+ # When `:old_objects` crosses this limit, major \GC is triggered
# [oldmalloc_increase_bytes]
# Amount of memory allocated on the heap for objects. Decreased by major \GC
# [oldmalloc_increase_bytes_limit]
- # When +:old_malloc_increase_bytes+ crosses this limit, major \GC is triggered
+ # When `:old_malloc_increase_bytes` crosses this limit, major \GC is triggered
#
# If the optional argument, hash, is given,
# it is overwritten and returned.
@@ -196,18 +191,19 @@ module GC
# GC.stat_heap(heap_name, hash) -> Hash
# GC.stat_heap(heap_name, :key) -> Numeric
#
- # Returns information for heaps in the \GC.
+ # Returns information for memory pools in the \GC.
#
# If the first optional argument, +heap_name+, is passed in and not +nil+, it
- # returns a +Hash+ containing information about the particular heap.
- # Otherwise, it will return a +Hash+ with heap names as keys and
- # a +Hash+ containing information about the heap as values.
+ # returns a +Hash+ containing information about the particular memory pool.
+ # Otherwise, it will return a +Hash+ with memory pool names as keys and
+ # a +Hash+ containing information about the memory pool as values.
#
# If the second optional argument, +hash_or_key+, is given as +Hash+, it will
# be overwritten and returned. This is intended to avoid the probe effect.
#
# If both optional arguments are passed in and the second optional argument is
- # a symbol, it will return a +Numeric+ of the value for the particular heap.
+ # a symbol, it will return a +Numeric+ of the value for the particular memory
+ # pool.
#
# On CRuby, +heap_name+ is of the type +Integer+ but may be of type +String+
# on other implementations.
@@ -218,36 +214,6 @@ module GC
# If the optional argument, hash, is given, it is overwritten and returned.
#
# This method is only expected to work on CRuby.
- #
- # The hash includes the following keys about the internal information in
- # the \GC:
- #
- # [slot_size]
- # The slot size of the heap in bytes.
- # [heap_allocatable_pages]
- # The number of pages that can be allocated without triggering a new
- # garbage collection cycle.
- # [heap_eden_pages]
- # The number of pages in the eden heap.
- # [heap_eden_slots]
- # The total number of slots in all of the pages in the eden heap.
- # [heap_tomb_pages]
- # The number of pages in the tomb heap. The tomb heap only contains pages
- # that do not have any live objects.
- # [heap_tomb_slots]
- # The total number of slots in all of the pages in the tomb heap.
- # [total_allocated_pages]
- # The total number of pages that have been allocated in the heap.
- # [total_freed_pages]
- # The total number of pages that have been freed and released back to the
- # system in the heap.
- # [force_major_gc_count]
- # The number of times major garbage collection cycles this heap has forced
- # to start due to running out of free slots.
- # [force_incremental_marking_finish_count]
- # The number of times this heap has forced incremental marking to complete
- # due to running out of pooled slots.
- #
def self.stat_heap heap_name = nil, hash_or_key = nil
Primitive.gc_stat_heap heap_name, hash_or_key
end
@@ -316,7 +282,7 @@ module GC
# Return measured \GC total time in nano seconds.
def self.total_time
Primitive.cexpr! %{
- ULL2NUM(rb_objspace.profile.marking_time_ns + rb_objspace.profile.sweeping_time_ns)
+ ULL2NUM(rb_objspace.profile.total_time_ns)
}
end
end
diff --git a/gem_prelude.rb b/gem_prelude.rb
index bcd2560fab..f382021ca3 100644
--- a/gem_prelude.rb
+++ b/gem_prelude.rb
@@ -4,8 +4,6 @@ rescue LoadError => e
raise unless e.path == 'rubygems'
warn "`RubyGems' were not loaded."
-else
- require 'bundled_gems'
end if defined?(Gem)
begin
diff --git a/gems/bundled_gems b/gems/bundled_gems
index 25d897a884..d37d869d41 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -1,23 +1,16 @@
-# gem-name version repository-url [revision]
-#
-# - gem-name: gem name to bundle
-# - version: released version to bundle
-# - repository-url: URL from where clone for test
-# - revision: revision in repository-url to test
-# if `revision` is not given, "v"+`version` or `version` will be used.
-minitest 5.20.0 https://github.com/minitest/minitest
+# gem-name version-to-bundle repository-url [optional-commit-hash-to-test-or-defaults-to-v-version]
+minitest 5.25.1 https://github.com/seattlerb/minitest
power_assert 2.0.3 https://github.com/ruby/power_assert
-rake 13.1.0 https://github.com/ruby/rake
-test-unit 3.6.1 https://github.com/test-unit/test-unit
-rexml 3.2.6 https://github.com/ruby/rexml
-rss 0.3.0 https://github.com/ruby/rss
-net-ftp 0.2.0 https://github.com/ruby/net-ftp
-net-imap 0.4.4 https://github.com/ruby/net-imap
+rake 13.0.6 https://github.com/ruby/rake
+test-unit 3.5.7 https://github.com/test-unit/test-unit
+rexml 3.3.9 https://github.com/ruby/rexml
+rss 0.3.1 https://github.com/ruby/rss
+net-ftp 0.2.1 https://github.com/ruby/net-ftp
+net-imap 0.3.9 https://github.com/ruby/net-imap
net-pop 0.1.2 https://github.com/ruby/net-pop
-net-smtp 0.4.0 https://github.com/ruby/net-smtp
+net-smtp 0.3.4 https://github.com/ruby/net-smtp
matrix 0.4.2 https://github.com/ruby/matrix
prime 0.1.2 https://github.com/ruby/prime
-rbs 3.2.2 https://github.com/ruby/rbs 33813a60752624d58dfe5ae770b39bfaf29fbaf1
-typeprof 0.21.8 https://github.com/ruby/typeprof
-debug 1.8.0 https://github.com/ruby/debug 927587afb6aac69b358b86a01f602d207053e8d2
-racc 1.7.3 https://github.com/ruby/racc
+rbs 2.8.2 https://github.com/ruby/rbs
+typeprof 0.21.3 https://github.com/ruby/typeprof
+debug 1.7.1 https://github.com/ruby/debug
diff --git a/gems/lib/envutil.rb b/gems/lib/envutil.rb
new file mode 100644
index 0000000000..d684c22cf2
--- /dev/null
+++ b/gems/lib/envutil.rb
@@ -0,0 +1 @@
+require_relative "../../tool/lib/envutil.rb"
diff --git a/gems/lib/rake/extensiontask.rb b/gems/lib/rake/extensiontask.rb
index aa668935fc..fdbe8d8874 100644
--- a/gems/lib/rake/extensiontask.rb
+++ b/gems/lib/rake/extensiontask.rb
@@ -1,3 +1,5 @@
+require "rake/tasklib" unless defined?(Rake::TaskLib)
+
module Rake
class ExtensionTask < TaskLib
def initialize(...)
diff --git a/hash.c b/hash.c
index 2b4c8d3400..d2dce30624 100644
--- a/hash.c
+++ b/hash.c
@@ -44,33 +44,17 @@
#include "ruby/util.h"
#include "ruby_assert.h"
#include "symbol.h"
+#include "transient_heap.h"
#include "ruby/thread_native.h"
#include "ruby/ractor.h"
#include "vm_sync.h"
-/* Flags of RHash
- *
- * 1: RHASH_PASS_AS_KEYWORDS
- * The hash is flagged as Ruby 2 keywords hash.
- * 2: RHASH_PROC_DEFAULT
- * The hash has a default proc (rather than a default value).
- * 3: RHASH_ST_TABLE_FLAG
- * The hash uses a ST table (rather than an AR table).
- * 4-7: RHASH_AR_TABLE_SIZE_MASK
- * The size of the AR table.
- * 8-11: RHASH_AR_TABLE_BOUND_MASK
- * The bounds of the AR table.
- * 13-19: RHASH_LEV_MASK
- * The iterational level of the hash. Used to prevent modifications
- * to the hash during interation.
- */
-
#ifndef HASH_DEBUG
#define HASH_DEBUG 0
#endif
#if HASH_DEBUG
-#include "internal/gc.h"
+#include "gc.h"
#endif
#define SET_DEFAULT(hash, ifnone) ( \
@@ -122,7 +106,7 @@ rb_hash_set_ifnone(VALUE hash, VALUE ifnone)
return hash;
}
-int
+static int
rb_any_cmp(VALUE a, VALUE b)
{
if (a == b) return 0;
@@ -377,14 +361,19 @@ const struct st_hash_type rb_hashtype_ident = {
rb_ident_hash,
};
+#define RHASH_IDENTHASH_P(hash) (RHASH_TYPE(hash) == &identhash)
+#define RHASH_STRING_KEY_P(hash, key) (!RHASH_IDENTHASH_P(hash) && (rb_obj_class(key) == rb_cString))
+
typedef st_index_t st_hash_t;
/*
* RHASH_AR_TABLE_P(h):
- * RHASH_AR_TABLE points to ar_table.
+ * * as.ar == NULL or
+ * as.ar points ar_table.
+ * * as.ar is allocated by transient heap or xmalloc.
*
* !RHASH_AR_TABLE_P(h):
- * RHASH_ST_TABLE points st_table.
+ * * as.st points st_table.
*/
#define RHASH_AR_TABLE_MAX_BOUND RHASH_AR_TABLE_MAX_SIZE
@@ -392,6 +381,22 @@ typedef st_index_t st_hash_t;
#define RHASH_AR_TABLE_REF(hash, n) (&RHASH_AR_TABLE(hash)->pairs[n])
#define RHASH_AR_CLEARED_HINT 0xff
+typedef struct ar_table_pair_struct {
+ VALUE key;
+ VALUE val;
+} ar_table_pair;
+
+typedef struct ar_table_struct {
+ /* 64bit CPU: 8B * 2 * 8 = 128B */
+ ar_table_pair pairs[RHASH_AR_TABLE_MAX_SIZE];
+} ar_table;
+
+size_t
+rb_hash_ar_table_size(void)
+{
+ return sizeof(ar_table);
+}
+
static inline st_hash_t
ar_do_hash(st_data_t key)
{
@@ -407,13 +412,13 @@ ar_do_hash_hint(st_hash_t hash_value)
static inline ar_hint_t
ar_hint(VALUE hash, unsigned int index)
{
- return RHASH_AR_TABLE(hash)->ar_hint.ary[index];
+ return RHASH(hash)->ar_hint.ary[index];
}
static inline void
ar_hint_set_hint(VALUE hash, unsigned int index, ar_hint_t hint)
{
- RHASH_AR_TABLE(hash)->ar_hint.ary[index] = hint;
+ RHASH(hash)->ar_hint.ary[index] = hint;
}
static inline void
@@ -461,20 +466,14 @@ ar_set_entry(VALUE hash, unsigned int index, st_data_t key, st_data_t val, st_ha
((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
(RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
+#define RHASH_AR_TABLE_BOUND(h) (HASH_ASSERT(RHASH_AR_TABLE_P(h)), \
+ RHASH_AR_TABLE_BOUND_RAW(h))
+
#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s)
#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)
#define HASH_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(HASH_DEBUG, expr, #expr)
-static inline unsigned int
-RHASH_AR_TABLE_BOUND(VALUE h)
-{
- HASH_ASSERT(RHASH_AR_TABLE_P(h));
- const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
- HASH_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
- return bound;
-}
-
#if HASH_DEBUG
#define hash_verify(hash) hash_verify_(hash, __FILE__, __LINE__)
@@ -484,10 +483,10 @@ rb_hash_dump(VALUE hash)
rb_obj_info_dump(hash);
if (RHASH_AR_TABLE_P(hash)) {
- unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
+ unsigned i, n = 0, bound = RHASH_AR_TABLE_BOUND(hash);
fprintf(stderr, " size:%u bound:%u\n",
- RHASH_AR_TABLE_SIZE(hash), bound);
+ RHASH_AR_TABLE_SIZE(hash), RHASH_AR_TABLE_BOUND(hash));
for (i=0; i<bound; i++) {
st_data_t k, v;
@@ -501,6 +500,7 @@ rb_hash_dump(VALUE hash)
rb_raw_obj_info(b1, 0x100, k),
rb_raw_obj_info(b2, 0x100, v),
ar_hint(hash, i));
+ n++;
}
else {
fprintf(stderr, " %d empty\n", i);
@@ -538,6 +538,13 @@ hash_verify_(VALUE hash, const char *file, int line)
HASH_ASSERT(RHASH_AR_TABLE_BOUND_RAW(hash) == 0);
}
+#if USE_TRANSIENT_HEAP
+ if (RHASH_TRANSIENT_P(hash)) {
+ volatile st_data_t MAYBE_UNUSED(key) = RHASH_AR_TABLE_REF(hash, 0)->key; /* read */
+ HASH_ASSERT(RHASH_AR_TABLE(hash) != NULL);
+ HASH_ASSERT(rb_transient_heap_managed_ptr_p(RHASH_AR_TABLE(hash)));
+ }
+#endif
return hash;
}
@@ -546,30 +553,69 @@ hash_verify_(VALUE hash, const char *file, int line)
#endif
static inline int
+RHASH_TABLE_NULL_P(VALUE hash)
+{
+ if (RHASH(hash)->as.ar == NULL) {
+ HASH_ASSERT(RHASH_AR_TABLE_P(hash));
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+static inline int
RHASH_TABLE_EMPTY_P(VALUE hash)
{
return RHASH_SIZE(hash) == 0;
}
-#define RHASH_SET_ST_FLAG(h) FL_SET_RAW(h, RHASH_ST_TABLE_FLAG)
-#define RHASH_UNSET_ST_FLAG(h) FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG)
+int
+rb_hash_ar_table_p(VALUE hash)
+{
+ if (FL_TEST_RAW((hash), RHASH_ST_TABLE_FLAG)) {
+ HASH_ASSERT(RHASH(hash)->as.st != NULL);
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
-static void
-hash_st_table_init(VALUE hash, const struct st_hash_type *type, st_index_t size)
+ar_table *
+rb_hash_ar_table(VALUE hash)
{
- st_init_existing_table_with_size(RHASH_ST_TABLE(hash), type, size);
- RHASH_SET_ST_FLAG(hash);
+ HASH_ASSERT(RHASH_AR_TABLE_P(hash));
+ return RHASH(hash)->as.ar;
+}
+
+st_table *
+rb_hash_st_table(VALUE hash)
+{
+ HASH_ASSERT(!RHASH_AR_TABLE_P(hash));
+ return RHASH(hash)->as.st;
}
void
rb_hash_st_table_set(VALUE hash, st_table *st)
{
HASH_ASSERT(st != NULL);
- RHASH_SET_ST_FLAG(hash);
+ FL_SET_RAW((hash), RHASH_ST_TABLE_FLAG);
+ RHASH(hash)->as.st = st;
+}
- *RHASH_ST_TABLE(hash) = *st;
+static void
+hash_ar_table_set(VALUE hash, ar_table *ar)
+{
+ HASH_ASSERT(RHASH_AR_TABLE_P(hash));
+ HASH_ASSERT((RHASH_TRANSIENT_P(hash) && ar == NULL) ? FALSE : TRUE);
+ RHASH(hash)->as.ar = ar;
+ hash_verify(hash);
}
+#define RHASH_SET_ST_FLAG(h) FL_SET_RAW(h, RHASH_ST_TABLE_FLAG)
+#define RHASH_UNSET_ST_FLAG(h) FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG)
+
static inline void
RHASH_AR_TABLE_BOUND_SET(VALUE h, st_index_t n)
{
@@ -624,7 +670,27 @@ RHASH_AR_TABLE_CLEAR(VALUE h)
RBASIC(h)->flags &= ~RHASH_AR_TABLE_SIZE_MASK;
RBASIC(h)->flags &= ~RHASH_AR_TABLE_BOUND_MASK;
- memset(RHASH_AR_TABLE(h), 0, sizeof(ar_table));
+ hash_ar_table_set(h, NULL);
+}
+
+static ar_table*
+ar_alloc_table(VALUE hash)
+{
+ ar_table *tab = (ar_table*)rb_transient_heap_alloc(hash, sizeof(ar_table));
+
+ if (tab != NULL) {
+ RHASH_SET_TRANSIENT_FLAG(hash);
+ }
+ else {
+ RHASH_UNSET_TRANSIENT_FLAG(hash);
+ tab = (ar_table*)ruby_xmalloc(sizeof(ar_table));
+ }
+
+ RHASH_AR_TABLE_SIZE_SET(hash, 0);
+ RHASH_AR_TABLE_BOUND_SET(hash, 0);
+ hash_ar_table_set(hash, tab);
+
+ return tab;
}
NOINLINE(static int ar_equal(VALUE x, VALUE y));
@@ -639,7 +705,7 @@ static unsigned
ar_find_entry_hint(VALUE hash, ar_hint_t hint, st_data_t key)
{
unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
- const ar_hint_t *hints = RHASH_AR_TABLE(hash)->ar_hint.ary;
+ const ar_hint_t *hints = RHASH(hash)->ar_hint.ary;
/* if table is NULL, then bound also should be 0 */
@@ -686,71 +752,112 @@ ar_find_entry(VALUE hash, st_hash_t hash_value, st_data_t key)
}
static inline void
-hash_ar_free_and_clear_table(VALUE hash)
+ar_free_and_clear_table(VALUE hash)
{
- RHASH_AR_TABLE_CLEAR(hash);
+ ar_table *tab = RHASH_AR_TABLE(hash);
+ if (tab) {
+ if (RHASH_TRANSIENT_P(hash)) {
+ RHASH_UNSET_TRANSIENT_FLAG(hash);
+ }
+ else {
+ ruby_xfree(RHASH_AR_TABLE(hash));
+ }
+ RHASH_AR_TABLE_CLEAR(hash);
+ }
HASH_ASSERT(RHASH_AR_TABLE_SIZE(hash) == 0);
HASH_ASSERT(RHASH_AR_TABLE_BOUND(hash) == 0);
+ HASH_ASSERT(RHASH_TRANSIENT_P(hash) == 0);
}
-static void
-ar_try_convert_table(VALUE hash)
-{
- if (!RHASH_AR_TABLE_P(hash)) return;
+void rb_st_add_direct_with_hash(st_table *tab, st_data_t key, st_data_t value, st_hash_t hash); // st.c
- const unsigned size = RHASH_AR_TABLE_SIZE(hash);
+enum ar_each_key_type {
+ ar_each_key_copy,
+ ar_each_key_cmp,
+ ar_each_key_insert,
+};
- if (size < RHASH_AR_TABLE_MAX_SIZE) {
- return;
+static inline int
+ar_each_key(ar_table *ar, int max, enum ar_each_key_type type, st_data_t *dst_keys, st_table *new_tab, st_hash_t *hashes)
+{
+ for (int i = 0; i < max; i++) {
+ ar_table_pair *pair = &ar->pairs[i];
+
+ switch (type) {
+ case ar_each_key_copy:
+ dst_keys[i] = pair->key;
+ break;
+ case ar_each_key_cmp:
+ if (dst_keys[i] != pair->key) return 1;
+ break;
+ case ar_each_key_insert:
+ if (UNDEF_P(pair->key)) continue; // deleted entry
+ rb_st_add_direct_with_hash(new_tab, pair->key, pair->val, hashes[i]);
+ break;
+ }
}
- st_table tab;
- st_table *new_tab = &tab;
- rb_st_init_existing_table_with_size(new_tab, &objhash, size * 2);
+ return 0;
+}
- for (st_index_t i = 0; i < RHASH_AR_TABLE_MAX_BOUND; i++) {
- ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- st_add_direct(new_tab, pair->key, pair->val);
- }
- hash_ar_free_and_clear_table(hash);
- RHASH_ST_TABLE_SET(hash, new_tab);
-}
static st_table *
ar_force_convert_table(VALUE hash, const char *file, int line)
{
st_table *new_tab;
- st_table tab;
- new_tab = &tab;
if (RHASH_ST_TABLE_P(hash)) {
return RHASH_ST_TABLE(hash);
}
- RUBY_ASSERT(RHASH_AR_TABLE(hash));
- {
- unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
+ if (RHASH_AR_TABLE(hash)) {
+ ar_table *ar = RHASH_AR_TABLE(hash);
+ st_hash_t hashes[RHASH_AR_TABLE_MAX_SIZE];
+ unsigned int bound, size;
- rb_st_init_existing_table_with_size(new_tab, &objhash, RHASH_AR_TABLE_SIZE(hash));
+ // prepare hash values
+ do {
+ st_data_t keys[RHASH_AR_TABLE_MAX_SIZE];
+ bound = RHASH_AR_TABLE_BOUND(hash);
+ size = RHASH_AR_TABLE_SIZE(hash);
+ ar_each_key(ar, bound, ar_each_key_copy, keys, NULL, NULL);
- for (i = 0; i < bound; i++) {
- if (ar_cleared_entry(hash, i)) continue;
+ for (unsigned int i = 0; i < bound; i++) {
+ // do_hash calls #hash method and it can modify hash object
+ hashes[i] = UNDEF_P(keys[i]) ? 0 : ar_do_hash(keys[i]);
+ }
- ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- st_add_direct(new_tab, pair->key, pair->val);
- }
- hash_ar_free_and_clear_table(hash);
- }
+ // check if modified
+ if (UNLIKELY(!RHASH_AR_TABLE_P(hash))) return RHASH_ST_TABLE(hash);
+ if (UNLIKELY(RHASH_AR_TABLE_BOUND(hash) != bound)) continue;
+ if (UNLIKELY(ar_each_key(ar, bound, ar_each_key_cmp, keys, NULL, NULL))) continue;
+ } while (0);
- RHASH_ST_TABLE_SET(hash, new_tab);
- new_tab = RHASH_ST_TABLE(hash);
+ // make st
+ new_tab = st_init_table_with_size(&objhash, size);
+ ar_each_key(ar, bound, ar_each_key_insert, NULL, new_tab, hashes);
+ ar_free_and_clear_table(hash);
+ }
+ else {
+ new_tab = st_init_table(&objhash);
+ }
+ RHASH_ST_TABLE_SET(hash, new_tab);
return new_tab;
}
+static ar_table *
+hash_ar_table(VALUE hash)
+{
+ if (RHASH_TABLE_NULL_P(hash)) {
+ ar_alloc_table(hash);
+ }
+ return RHASH_AR_TABLE(hash);
+}
+
static int
ar_compact_table(VALUE hash)
{
@@ -801,6 +908,7 @@ ar_add_direct_with_hash(VALUE hash, st_data_t key, st_data_t val, st_hash_t hash
else {
if (UNLIKELY(bin >= RHASH_AR_TABLE_MAX_BOUND)) {
bin = ar_compact_table(hash);
+ hash_ar_table(hash);
}
HASH_ASSERT(bin < RHASH_AR_TABLE_MAX_BOUND);
@@ -945,6 +1053,7 @@ ar_update(VALUE hash, st_data_t key,
existing = (bin != RHASH_AR_TABLE_MAX_BOUND) ? TRUE : FALSE;
}
else {
+ hash_ar_table(hash); /* allocate ltbl if needed */
existing = FALSE;
}
@@ -993,6 +1102,8 @@ ar_insert(VALUE hash, st_data_t key, st_data_t value)
return -1;
}
+ hash_ar_table(hash); /* prepare ltbl */
+
bin = ar_find_entry(hash, hash_value, key);
if (bin == RHASH_AR_TABLE_MAX_BOUND) {
if (RHASH_AR_TABLE_SIZE(hash) >= RHASH_AR_TABLE_MAX_SIZE) {
@@ -1000,6 +1111,7 @@ ar_insert(VALUE hash, st_data_t key, st_data_t value)
}
else if (bin >= RHASH_AR_TABLE_MAX_BOUND) {
bin = ar_compact_table(hash);
+ hash_ar_table(hash);
}
HASH_ASSERT(bin < RHASH_AR_TABLE_MAX_BOUND);
@@ -1134,16 +1246,44 @@ static ar_table*
ar_copy(VALUE hash1, VALUE hash2)
{
ar_table *old_tab = RHASH_AR_TABLE(hash2);
- ar_table *new_tab = RHASH_AR_TABLE(hash1);
- *new_tab = *old_tab;
- RHASH_AR_TABLE(hash1)->ar_hint.word = RHASH_AR_TABLE(hash2)->ar_hint.word;
- RHASH_AR_TABLE_BOUND_SET(hash1, RHASH_AR_TABLE_BOUND(hash2));
- RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
+ if (old_tab != NULL) {
+ ar_table *new_tab = RHASH_AR_TABLE(hash1);
+ if (new_tab == NULL) {
+ new_tab = (ar_table*) rb_transient_heap_alloc(hash1, sizeof(ar_table));
+ if (new_tab != NULL) {
+ RHASH_SET_TRANSIENT_FLAG(hash1);
+ }
+ else {
+ RHASH_UNSET_TRANSIENT_FLAG(hash1);
+ new_tab = (ar_table*)ruby_xmalloc(sizeof(ar_table));
+ }
+ }
+ *new_tab = *old_tab;
+ RHASH(hash1)->ar_hint.word = RHASH(hash2)->ar_hint.word;
+ RHASH_AR_TABLE_BOUND_SET(hash1, RHASH_AR_TABLE_BOUND(hash2));
+ RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
+ hash_ar_table_set(hash1, new_tab);
+
+ rb_gc_writebarrier_remember(hash1);
+ return new_tab;
+ }
+ else {
+ RHASH_AR_TABLE_BOUND_SET(hash1, RHASH_AR_TABLE_BOUND(hash2));
+ RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
- rb_gc_writebarrier_remember(hash1);
+ if (RHASH_TRANSIENT_P(hash1)) {
+ RHASH_UNSET_TRANSIENT_FLAG(hash1);
+ }
+ else if (RHASH_AR_TABLE(hash1)) {
+ ruby_xfree(RHASH_AR_TABLE(hash1));
+ }
- return new_tab;
+ hash_ar_table_set(hash1, NULL);
+
+ rb_gc_writebarrier_remember(hash1);
+ return old_tab;
+ }
}
static void
@@ -1159,32 +1299,32 @@ ar_clear(VALUE hash)
}
}
-static void
-hash_st_free(VALUE hash)
-{
- HASH_ASSERT(RHASH_ST_TABLE_P(hash));
-
- st_table *tab = RHASH_ST_TABLE(hash);
-
- free(tab->bins);
- free(tab->entries);
-}
-
-static void
-hash_st_free_and_clear_table(VALUE hash)
-{
- hash_st_free(hash);
-
- RHASH_ST_CLEAR(hash);
-}
-
+#if USE_TRANSIENT_HEAP
void
-rb_hash_free(VALUE hash)
+rb_hash_transient_heap_evacuate(VALUE hash, int promote)
{
- if (RHASH_ST_TABLE_P(hash)) {
- hash_st_free(hash);
+ if (RHASH_TRANSIENT_P(hash)) {
+ ar_table *new_tab;
+ ar_table *old_tab = RHASH_AR_TABLE(hash);
+
+ if (UNLIKELY(old_tab == NULL)) {
+ return;
+ }
+ HASH_ASSERT(old_tab != NULL);
+ if (! promote) {
+ new_tab = rb_transient_heap_alloc(hash, sizeof(ar_table));
+ if (new_tab == NULL) promote = true;
+ }
+ if (promote) {
+ new_tab = ruby_xmalloc(sizeof(ar_table));
+ RHASH_UNSET_TRANSIENT_FLAG(hash);
+ }
+ *new_tab = *old_tab;
+ hash_ar_table_set(hash, new_tab);
}
+ hash_verify(hash);
}
+#endif
typedef int st_foreach_func(st_data_t, st_data_t, st_data_t);
@@ -1423,13 +1563,21 @@ rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
hash_verify(hash);
}
+void rb_st_compact_table(st_table *tab);
+
+static void
+compact_after_delete(VALUE hash)
+{
+ if (RHASH_ITER_LEV(hash) == 0 && RHASH_ST_TABLE_P(hash)) {
+ rb_st_compact_table(RHASH_ST_TABLE(hash));
+ }
+}
+
static VALUE
-hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone, bool st)
+hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone)
{
const VALUE wb = (RGENGC_WB_PROTECTED_HASH ? FL_WB_PROTECTED : 0);
- const size_t size = sizeof(struct RHash) + (st ? sizeof(st_table) : sizeof(ar_table));
-
- NEWOBJ_OF(hash, struct RHash, klass, T_HASH | wb | flags, size, 0);
+ NEWOBJ_OF(hash, struct RHash, klass, T_HASH | wb | flags);
RHASH_SET_IFNONE((VALUE)hash, ifnone);
@@ -1439,8 +1587,7 @@ hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone, bool st)
static VALUE
hash_alloc(VALUE klass)
{
- /* Allocate to be able to fit both st_table and ar_table. */
- return hash_alloc_flags(klass, 0, Qnil, sizeof(st_table) > sizeof(ar_table));
+ return hash_alloc_flags(klass, 0, Qnil);
}
static VALUE
@@ -1466,16 +1613,19 @@ copy_compare_by_id(VALUE hash, VALUE basis)
return hash;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_new_with_size(st_index_t size)
{
- bool st = size > RHASH_AR_TABLE_MAX_SIZE;
- VALUE ret = hash_alloc_flags(rb_cHash, 0, Qnil, st);
-
- if (st) {
- hash_st_table_init(ret, &objhash, size);
+ VALUE ret = rb_hash_new();
+ if (size == 0) {
+ /* do nothing */
+ }
+ else if (size <= RHASH_AR_TABLE_MAX_SIZE) {
+ ar_alloc_table(ret);
+ }
+ else {
+ RHASH_ST_TABLE_SET(ret, st_init_table_with_size(&objhash, size));
}
-
return ret;
}
@@ -1488,32 +1638,11 @@ rb_hash_new_capa(long capa)
static VALUE
hash_copy(VALUE ret, VALUE hash)
{
- if (RHASH_AR_TABLE_P(hash)) {
- if (RHASH_AR_TABLE_P(ret)) {
+ if (!RHASH_EMPTY_P(hash)) {
+ if (RHASH_AR_TABLE_P(hash))
ar_copy(ret, hash);
- }
- else {
- st_table *tab = RHASH_ST_TABLE(ret);
- rb_st_init_existing_table_with_size(tab, &objhash, RHASH_AR_TABLE_SIZE(hash));
-
- int bound = RHASH_AR_TABLE_BOUND(hash);
- for (int i = 0; i < bound; i++) {
- if (ar_cleared_entry(hash, i)) continue;
-
- ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- st_add_direct(tab, pair->key, pair->val);
- RB_OBJ_WRITTEN(ret, Qundef, pair->key);
- RB_OBJ_WRITTEN(ret, Qundef, pair->val);
- }
- }
- }
- else {
- HASH_ASSERT(sizeof(st_table) <= sizeof(ar_table));
-
- RHASH_SET_ST_FLAG(ret);
- st_replace(RHASH_ST_TABLE(ret), RHASH_ST_TABLE(hash));
-
- rb_gc_writebarrier_remember(ret);
+ else if (RHASH_ST_TABLE_P(hash))
+ RHASH_ST_TABLE_SET(ret, st_copy(RHASH_ST_TABLE(hash)));
}
return ret;
}
@@ -1527,7 +1656,7 @@ hash_dup_with_compare_by_id(VALUE hash)
static VALUE
hash_dup(VALUE hash, VALUE klass, VALUE flags)
{
- return hash_copy(hash_alloc_flags(klass, flags, RHASH_IFNONE(hash), !RHASH_EMPTY_P(hash) && RHASH_ST_TABLE_P(hash)),
+ return hash_copy(hash_alloc_flags(klass, flags, RHASH_IFNONE(hash)),
hash);
}
@@ -1542,7 +1671,7 @@ rb_hash_dup(VALUE hash)
return ret;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_resurrect(VALUE hash)
{
VALUE ret = hash_dup(hash, rb_cHash, 0);
@@ -1555,7 +1684,7 @@ rb_hash_modify_check(VALUE hash)
rb_check_frozen(hash);
}
-RUBY_FUNC_EXPORTED struct st_table *
+MJIT_FUNC_EXPORTED struct st_table *
rb_hash_tbl_raw(VALUE hash, const char *file, int line)
{
return ar_force_convert_table(hash, file, line);
@@ -1616,7 +1745,7 @@ rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func,
if (RHASH_AR_TABLE_P(hash)) {
int result = ar_update(hash, key, func, arg);
if (result == -1) {
- ar_try_convert_table(hash);
+ ar_force_convert_table(hash, __FILE__, __LINE__);
}
else {
return result;
@@ -1732,29 +1861,23 @@ set_proc_default(VALUE hash, VALUE proc)
static VALUE
rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
{
- rb_hash_modify(hash);
+ VALUE ifnone;
+ rb_hash_modify(hash);
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
- SET_PROC_DEFAULT(hash, rb_block_proc());
+ ifnone = rb_block_proc();
+ SET_PROC_DEFAULT(hash, ifnone);
}
else {
rb_check_arity(argc, 0, 1);
-
- VALUE options, ifnone;
- rb_scan_args(argc, argv, "01:", &ifnone, &options);
- if (NIL_P(ifnone) && !NIL_P(options)) {
- ifnone = options;
- rb_warn_deprecated_to_remove("3.4", "Calling Hash.new with keyword arguments", "Hash.new({ key: value })");
- }
+ ifnone = argc == 0 ? Qnil : argv[0];
RHASH_SET_IFNONE(hash, ifnone);
}
return hash;
}
-static VALUE rb_hash_to_a(VALUE hash);
-
/*
* call-seq:
* Hash[] -> new_empty_hash
@@ -1774,7 +1897,7 @@ static VALUE rb_hash_to_a(VALUE hash);
* h = {foo: 0, bar: 1, baz: 2}
* Hash[h] # => {:foo=>0, :bar=>1, :baz=>2}
*
- * When the single given argument is an Array of 2-element Arrays,
+ * When the single given argument is an \Array of 2-element Arrays,
* returns a new \Hash object wherein each 2-element array forms a
* key-value entry:
*
@@ -1798,23 +1921,12 @@ rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
if (argc == 1) {
tmp = rb_hash_s_try_convert(Qnil, argv[0]);
if (!NIL_P(tmp)) {
- if (!RHASH_EMPTY_P(tmp) && rb_hash_compare_by_id_p(tmp)) {
- /* hash_copy for non-empty hash will copy compare_by_identity
- flag, but we don't want it copied. Work around by
- converting hash to flattened array and using that. */
- tmp = rb_hash_to_a(tmp);
- }
- else {
- hash = hash_alloc(klass);
- if (!RHASH_EMPTY_P(tmp))
- hash_copy(hash, tmp);
- return hash;
- }
- }
- else {
- tmp = rb_check_array_type(argv[0]);
+ hash = hash_alloc(klass);
+ hash_copy(hash, tmp);
+ return hash;
}
+ tmp = rb_check_array_type(argv[0]);
if (!NIL_P(tmp)) {
long i;
@@ -1852,7 +1964,7 @@ rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
return hash;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_to_hash_type(VALUE hash)
{
return rb_convert_type_with_id(hash, T_HASH, "Hash", idTo_hash);
@@ -1925,12 +2037,9 @@ static VALUE
rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
- VALUE tmp = rb_hash_dup(hash);
- if (RHASH_EMPTY_P(hash) && rb_hash_compare_by_id_p(hash)) {
- rb_hash_compare_by_id(tmp);
- }
- RHASH(tmp)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
- return tmp;
+ hash = rb_hash_dup(hash);
+ RHASH(hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
+ return hash;
}
struct rehash_arg {
@@ -1974,21 +2083,19 @@ rb_hash_rehash(VALUE hash)
rb_hash_modify_check(hash);
if (RHASH_AR_TABLE_P(hash)) {
tmp = hash_alloc(0);
+ ar_alloc_table(tmp);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
-
- hash_ar_free_and_clear_table(hash);
+ ar_free_and_clear_table(hash);
ar_copy(hash, tmp);
+ ar_free_and_clear_table(tmp);
}
else if (RHASH_ST_TABLE_P(hash)) {
st_table *old_tab = RHASH_ST_TABLE(hash);
tmp = hash_alloc(0);
-
- hash_st_table_init(tmp, old_tab->type, old_tab->num_entries);
- tbl = RHASH_ST_TABLE(tmp);
-
+ tbl = st_init_table_with_size(old_tab->type, old_tab->num_entries);
+ RHASH_ST_TABLE_SET(tmp, tbl);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
-
- hash_st_free(hash);
+ st_free_table(old_tab);
RHASH_ST_TABLE_SET(hash, tbl);
RHASH_ST_CLEAR(tmp);
}
@@ -2040,15 +2147,11 @@ hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval)
return ar_lookup(hash, key, pval);
}
else {
- extern st_index_t rb_iseq_cdhash_hash(VALUE);
- RUBY_ASSERT(RHASH_ST_TABLE(hash)->type->hash == rb_any_hash ||
- RHASH_ST_TABLE(hash)->type->hash == rb_ident_hash ||
- RHASH_ST_TABLE(hash)->type->hash == rb_iseq_cdhash_hash);
return st_lookup(RHASH_ST_TABLE(hash), key, pval);
}
}
-int
+MJIT_FUNC_EXPORTED int
rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval)
{
return hash_stlike_lookup(hash, key, pval);
@@ -2298,7 +2401,7 @@ key_i(VALUE key, VALUE value, VALUE arg)
* h.key(0) # => :foo
* h.key(2) # => :bar
*
- * Returns +nil+ if no such value is found.
+ * Returns +nil+ if so such value is found.
*/
static VALUE
@@ -2397,6 +2500,7 @@ rb_hash_delete_m(VALUE hash, VALUE key)
val = rb_hash_delete_entry(hash, key);
if (!UNDEF_P(val)) {
+ compact_after_delete(hash);
return val;
}
else {
@@ -2430,7 +2534,7 @@ shift_i_safe(VALUE key, VALUE value, VALUE arg)
*
* Removes the first hash entry
* (see {Entry Order}[rdoc-ref:Hash@Entry+Order]);
- * returns a 2-element Array containing the removed key and value:
+ * returns a 2-element \Array containing the removed key and value:
* h = {foo: 0, bar: 1, baz: 2}
* h.shift # => [:foo, 0]
* h # => {:bar=>1, :baz=>2}
@@ -2504,7 +2608,7 @@ hash_enum_size(VALUE hash, VALUE args, VALUE eobj)
* h = {foo: 0, bar: 1, baz: 2}
* h.delete_if {|key, value| value > 0 } # => {:foo=>0}
*
- * If no block given, returns a new Enumerator:
+ * If no block given, returns a new \Enumerator:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.delete_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:delete_if>
* e.each { |key, value| value > 0 } # => {:foo=>0}
@@ -2517,6 +2621,7 @@ rb_hash_delete_if(VALUE hash)
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
rb_hash_foreach(hash, delete_if_i, hash);
+ compact_after_delete(hash);
}
return hash;
}
@@ -2533,7 +2638,7 @@ rb_hash_delete_if(VALUE hash)
*
* Returns +nil+ if no entries are removed.
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.reject! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject!>
* e.each {|key, value| key.start_with?('b') } # => {:foo=>0}
@@ -2564,7 +2669,7 @@ rb_hash_reject_bang(VALUE hash)
* h1 = h.reject {|key, value| key.start_with?('b') }
* h1 # => {:foo=>0}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.reject # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject>
* h1 = e.each {|key, value| key.start_with?('b') }
@@ -2580,6 +2685,7 @@ rb_hash_reject(VALUE hash)
result = hash_dup_with_compare_by_id(hash);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(result, delete_if_i, result);
+ compact_after_delete(result);
}
return result;
}
@@ -2639,6 +2745,7 @@ rb_hash_except(int argc, VALUE *argv, VALUE hash)
key = argv[i];
rb_hash_delete(result, key);
}
+ compact_after_delete(result);
return result;
}
@@ -2647,7 +2754,7 @@ rb_hash_except(int argc, VALUE *argv, VALUE hash)
* call-seq:
* hash.values_at(*keys) -> new_array
*
- * Returns a new Array containing values for the given +keys+:
+ * Returns a new \Array containing values for the given +keys+:
* h = {foo: 0, bar: 1, baz: 2}
* h.values_at(:baz, :foo) # => [2, 0]
*
@@ -2673,11 +2780,11 @@ rb_hash_values_at(int argc, VALUE *argv, VALUE hash)
* hash.fetch_values(*keys) -> new_array
* hash.fetch_values(*keys) {|key| ... } -> new_array
*
- * Returns a new Array containing the values associated with the given keys *keys:
+ * Returns a new \Array containing the values associated with the given keys *keys:
* h = {foo: 0, bar: 1, baz: 2}
* h.fetch_values(:baz, :foo) # => [2, 0]
*
- * Returns a new empty Array if no arguments given.
+ * Returns a new empty \Array if no arguments given.
*
* When a block is given, calls the block with each missing key,
* treating the block's return value as the value for that key:
@@ -2715,11 +2822,13 @@ keep_if_i(VALUE key, VALUE value, VALUE hash)
* hash.select {|key, value| ... } -> new_hash
* hash.select -> new_enumerator
*
+ * Hash#filter is an alias for Hash#select.
+ *
* Returns a new \Hash object whose entries are those for which the block returns a truthy value:
* h = {foo: 0, bar: 1, baz: 2}
* h.select {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.select # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select>
* e.each {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
@@ -2734,6 +2843,7 @@ rb_hash_select(VALUE hash)
result = hash_dup_with_compare_by_id(hash);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(result, keep_if_i, result);
+ compact_after_delete(result);
}
return result;
}
@@ -2743,13 +2853,15 @@ rb_hash_select(VALUE hash)
* hash.select! {|key, value| ... } -> self or nil
* hash.select! -> new_enumerator
*
+ * Hash#filter! is an alias for Hash#select!.
+ *
* Returns +self+, whose entries are those for which the block returns a truthy value:
* h = {foo: 0, bar: 1, baz: 2}
* h.select! {|key, value| value < 2 } => {:foo=>0, :bar=>1}
*
* Returns +nil+ if no entries were removed.
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.select! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select!>
* e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
@@ -2780,7 +2892,7 @@ rb_hash_select_bang(VALUE hash)
* h = {foo: 0, bar: 1, baz: 2}
* h.keep_if { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.keep_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:keep_if>
* e.each { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
@@ -2823,6 +2935,7 @@ rb_hash_clear(VALUE hash)
}
else {
st_clear(RHASH_ST_TABLE(hash));
+ compact_after_delete(hash);
}
return hash;
@@ -2863,6 +2976,8 @@ NOINSERT_UPDATE_CALLBACK(hash_aset_str)
* hash[key] = value -> value
* hash.store(key, value)
*
+ * Hash#store is an alias for Hash#[]=.
+
* Associates the given +value+ with the given +key+; returns +value+.
*
* If the given +key+ exists, replaces its value with the given +value+;
@@ -2889,7 +3004,12 @@ rb_hash_aset(VALUE hash, VALUE key, VALUE val)
rb_hash_modify(hash);
- if (RHASH_TYPE(hash) == &identhash || rb_obj_class(key) != rb_cString) {
+ if (RHASH_TABLE_NULL_P(hash)) {
+ if (iter_lev > 0) no_new_key();
+ ar_alloc_table(hash);
+ }
+
+ if (!RHASH_STRING_KEY_P(hash, key)) {
RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val);
}
else {
@@ -2921,13 +3041,19 @@ rb_hash_replace(VALUE hash, VALUE hash2)
COPY_DEFAULT(hash, hash2);
if (RHASH_AR_TABLE_P(hash)) {
- hash_ar_free_and_clear_table(hash);
+ ar_free_and_clear_table(hash);
}
else {
- hash_st_free_and_clear_table(hash);
+ st_free_table(RHASH_ST_TABLE(hash));
+ RHASH_ST_CLEAR(hash);
}
-
hash_copy(hash, hash2);
+ if (RHASH_EMPTY_P(hash2) && RHASH_ST_TABLE_P(hash2)) {
+ /* ident hash */
+ RHASH_ST_TABLE_SET(hash, st_init_table_with_size(RHASH_TYPE(hash2), 0));
+ }
+
+ rb_gc_writebarrier_remember(hash);
return hash;
}
@@ -2938,9 +3064,9 @@ rb_hash_replace(VALUE hash, VALUE hash2)
* hash.size -> integer
*
* Returns the count of entries in +self+:
- *
* {foo: 0, bar: 1, baz: 2}.length # => 3
*
+ * Hash#length is an alias for Hash#size.
*/
VALUE
@@ -2990,7 +3116,7 @@ each_value_i(VALUE key, VALUE value, VALUE _)
* 1
* 2
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.each_value # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_value>
* h1 = e.each {|value| puts value }
@@ -3029,7 +3155,7 @@ each_key_i(VALUE key, VALUE value, VALUE _)
* bar
* baz
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.each_key # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_key>
* h1 = e.each {|key| puts key }
@@ -3071,6 +3197,8 @@ each_pair_i_fast(VALUE key, VALUE value, VALUE _)
* hash.each -> new_enumerator
* hash.each_pair -> new_enumerator
*
+ * Hash#each is an alias for Hash#each_pair.
+
* Calls the given block with each key-value pair; returns +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
@@ -3079,7 +3207,7 @@ each_pair_i_fast(VALUE key, VALUE value, VALUE _)
* bar: 1
* baz: 2
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair>
* h1 = e.each {|key, value| puts "#{key}: #{value}"}
@@ -3162,7 +3290,7 @@ transform_keys_i(VALUE key, VALUE value, VALUE result)
* h1 = h.transform_keys {|key| :bat }
* h1 # => {:bat=>2}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.transform_keys # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_keys>
* h1 = e.each { |key| key.to_s }
@@ -3253,6 +3381,7 @@ rb_hash_transform_keys_bang(int argc, VALUE *argv, VALUE hash)
rb_ary_clear(pairs);
rb_hash_clear(new_keys);
}
+ compact_after_delete(hash);
return hash;
}
@@ -3286,7 +3415,7 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
* h1 = h.transform_values {|value| value * 100}
* h1 # => {:foo=>0, :bar=>100, :baz=>200}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.transform_values # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_values>
* h1 = e.each { |value| value * 100}
@@ -3303,6 +3432,7 @@ rb_hash_transform_values(VALUE hash)
if (!RHASH_EMPTY_P(hash)) {
rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result);
+ compact_after_delete(result);
}
return result;
@@ -3317,7 +3447,7 @@ rb_hash_transform_values(VALUE hash)
* h = {foo: 0, bar: 1, baz: 2}
* h.transform_values! {|value| value * 100} # => {:foo=>0, :bar=>100, :baz=>200}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.transform_values! # => #<Enumerator: {:foo=>0, :bar=>100, :baz=>200}:transform_values!>
* h1 = e.each {|value| value * 100}
@@ -3347,8 +3477,8 @@ to_a_i(VALUE key, VALUE value, VALUE ary)
* call-seq:
* hash.to_a -> new_array
*
- * Returns a new Array of 2-element Array objects;
- * each nested Array contains a key-value pair from +self+:
+ * Returns a new \Array of 2-element \Array objects;
+ * each nested \Array contains a key-value pair from +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.to_a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
*/
@@ -3401,11 +3531,11 @@ inspect_hash(VALUE hash, VALUE dummy, int recur)
* call-seq:
* hash.inspect -> new_string
*
- * Returns a new String containing the hash entries:
-
+ * Returns a new \String containing the hash entries:
* h = {foo: 0, bar: 1, baz: 2}
* h.inspect # => "{:foo=>0, :bar=>1, :baz=>2}"
*
+ * Hash#to_s is an alias for Hash#inspect.
*/
static VALUE
@@ -3473,8 +3603,8 @@ rb_hash_to_h_block(VALUE hash)
*
* When a block is given, returns a new \Hash object
* whose content is based on the block;
- * the block should return a 2-element Array object
- * specifying the key-value pair to be included in the returned Array:
+ * the block should return a 2-element \Array object
+ * specifying the key-value pair to be included in the returned \Array:
* h = {foo: 0, bar: 1, baz: 2}
* h1 = h.to_h {|key, value| [value, key] }
* h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
@@ -3504,12 +3634,12 @@ keys_i(VALUE key, VALUE value, VALUE ary)
* call-seq:
* hash.keys -> new_array
*
- * Returns a new Array containing all keys in +self+:
+ * Returns a new \Array containing all keys in +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.keys # => [:foo, :bar, :baz]
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_keys(VALUE hash)
{
st_index_t size = RHASH_SIZE(hash);
@@ -3518,7 +3648,7 @@ rb_hash_keys(VALUE hash)
if (size == 0) return keys;
if (ST_DATA_COMPATIBLE_P(VALUE)) {
- RARRAY_PTR_USE(keys, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(keys, ptr, {
if (RHASH_AR_TABLE_P(hash)) {
size = ar_keys(hash, ptr, size);
}
@@ -3548,7 +3678,7 @@ values_i(VALUE key, VALUE value, VALUE ary)
* call-seq:
* hash.values -> new_array
*
- * Returns a new Array containing all values in +self+:
+ * Returns a new \Array containing all values in +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.values # => [0, 1, 2]
*/
@@ -3565,14 +3695,14 @@ rb_hash_values(VALUE hash)
if (ST_DATA_COMPATIBLE_P(VALUE)) {
if (RHASH_AR_TABLE_P(hash)) {
rb_gc_writebarrier_remember(values);
- RARRAY_PTR_USE(values, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(values, ptr, {
size = ar_values(hash, ptr, size);
});
}
else if (RHASH_ST_TABLE_P(hash)) {
st_table *table = RHASH_ST_TABLE(hash);
rb_gc_writebarrier_remember(values);
- RARRAY_PTR_USE(values, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(values, ptr, {
size = st_values(table, ptr, size);
});
}
@@ -3592,11 +3722,13 @@ rb_hash_values(VALUE hash)
* hash.has_key?(key) -> true or false
* hash.key?(key) -> true or false
* hash.member?(key) -> true or false
+
+ * Methods #has_key?, #key?, and #member? are aliases for \#include?.
*
* Returns +true+ if +key+ is a key in +self+, otherwise +false+.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
return RBOOL(hash_stlike_lookup(hash, key, NULL));
@@ -3619,6 +3751,8 @@ rb_hash_search_value(VALUE key, VALUE value, VALUE arg)
* hash.has_value?(value) -> true or false
* hash.value?(value) -> true or false
*
+ * Method #value? is an alias for \#has_value?.
+ *
* Returns +true+ if +value+ is a value in +self+, otherwise +false+.
*/
@@ -3780,10 +3914,10 @@ hash_i(VALUE key, VALUE val, VALUE arg)
* call-seq:
* hash.hash -> an_integer
*
- * Returns the Integer hash-code for the hash.
+ * Returns the \Integer hash-code for the hash.
*
* Two \Hash objects have the same hash-code if their content is the same
- * (regardless of order):
+ * (regardless or order):
* h1 = {foo: 0, bar: 1, baz: 2}
* h2 = {baz: 2, bar: 1, foo: 0}
* h2.hash == h1.hash # => true
@@ -3835,18 +3969,9 @@ rb_hash_invert(VALUE hash)
}
static int
-rb_hash_update_callback(st_data_t *key, st_data_t *value, struct update_arg *arg, int existing)
-{
- *value = arg->arg;
- return ST_CONTINUE;
-}
-
-NOINSERT_UPDATE_CALLBACK(rb_hash_update_callback)
-
-static int
rb_hash_update_i(VALUE key, VALUE value, VALUE hash)
{
- RHASH_UPDATE(hash, key, rb_hash_update_callback, value);
+ rb_hash_aset(hash, key, value);
return ST_CONTINUE;
}
@@ -3858,6 +3983,9 @@ rb_hash_update_block_callback(st_data_t *key, st_data_t *value, struct update_ar
if (existing) {
newvalue = (st_data_t)rb_yield_values(3, (VALUE)*key, (VALUE)*value, (VALUE)newvalue);
}
+ else if (RHASH_STRING_KEY_P(arg->hash, *key) && !RB_OBJ_FROZEN(*key)) {
+ *key = rb_hash_key_str(*key);
+ }
*value = newvalue;
return ST_CONTINUE;
}
@@ -3881,6 +4009,8 @@ rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
*
* Each argument in +other_hashes+ must be a \Hash.
*
+ * \Method #update is an alias for \#merge!.
+ *
* With arguments and no block:
* * Returns +self+, after the given hashes are merged into it.
* * The given hashes are merged left to right.
@@ -4087,7 +4217,7 @@ assoc_i(VALUE key, VALUE val, VALUE arg)
* call-seq:
* hash.assoc(key) -> new_array or nil
*
- * If the given +key+ is found, returns a 2-element Array containing that key and its value:
+ * If the given +key+ is found, returns a 2-element \Array containing that key and its value:
* h = {foo: 0, bar: 1, baz: 2}
* h.assoc(:bar) # => [:bar, 1]
*
@@ -4108,7 +4238,7 @@ rb_hash_assoc(VALUE hash, VALUE key)
table = RHASH_ST_TABLE(hash);
orighash = table->type;
- if (orighash != &identhash) {
+ if (!RHASH_IDENTHASH_P(hash)) {
VALUE value;
struct reset_hash_type_arg ensure_arg;
struct st_hash_type assochash;
@@ -4146,7 +4276,7 @@ rassoc_i(VALUE key, VALUE val, VALUE arg)
* call-seq:
* hash.rassoc(value) -> new_array or nil
*
- * Returns a new 2-element Array consisting of the key and value
+ * Returns a new 2-element \Array consisting of the key and value
* of the first-found entry whose value is <tt>==</tt> to value
* (see {Entry Order}[rdoc-ref:Hash@Entry+Order]):
* h = {foo: 0, bar: 1, baz: 1}
@@ -4183,7 +4313,7 @@ flatten_i(VALUE key, VALUE val, VALUE ary)
* hash.flatten -> new_array
* hash.flatten(level) -> new_array
*
- * Returns a new Array object that is a 1-dimensional flattening of +self+.
+ * Returns a new \Array object that is a 1-dimensional flattening of +self+.
*
* ---
*
@@ -4191,7 +4321,7 @@ flatten_i(VALUE key, VALUE val, VALUE ary)
* h = {foo: 0, bar: [:bat, 3], baz: 2}
* h.flatten # => [:foo, 0, :bar, [:bat, 3], :baz, 2]
*
- * Takes the depth of recursive flattening from Integer argument +level+:
+ * Takes the depth of recursive flattening from \Integer argument +level+:
* h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]}
* h.flatten(1) # => [:foo, 0, :bar, [:bat, [:baz, [:bat]]]]
* h.flatten(2) # => [:foo, 0, :bar, :bat, [:baz, [:bat]]]
@@ -4251,6 +4381,15 @@ delete_if_nil(VALUE key, VALUE value, VALUE hash)
return ST_CONTINUE;
}
+static int
+set_if_not_nil(VALUE key, VALUE value, VALUE hash)
+{
+ if (!NIL_P(value)) {
+ rb_hash_aset(hash, key, value);
+ }
+ return ST_CONTINUE;
+}
+
/*
* call-seq:
* hash.compact -> new_hash
@@ -4264,12 +4403,9 @@ delete_if_nil(VALUE key, VALUE value, VALUE hash)
static VALUE
rb_hash_compact(VALUE hash)
{
- VALUE result = rb_hash_dup(hash);
+ VALUE result = rb_hash_new();
if (!RHASH_EMPTY_P(hash)) {
- rb_hash_foreach(result, delete_if_nil, result);
- }
- else if (rb_hash_compare_by_id_p(hash)) {
- result = rb_hash_compare_by_id(result);
+ rb_hash_foreach(hash, set_if_not_nil, result);
}
return result;
}
@@ -4299,6 +4435,8 @@ rb_hash_compact_bang(VALUE hash)
return Qnil;
}
+static st_table *rb_init_identtable_with_size(st_index_t size);
+
/*
* call-seq:
* hash.compare_by_identity -> self
@@ -4340,11 +4478,10 @@ rb_hash_compare_by_id(VALUE hash)
HASH_ASSERT(RHASH_ST_TABLE_P(hash));
tmp = hash_alloc(0);
- hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash));
- identtable = RHASH_ST_TABLE(tmp);
-
+ identtable = rb_init_identtable_with_size(RHASH_SIZE(hash));
+ RHASH_ST_TABLE_SET(tmp, identtable);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
-
+ st_free_table(RHASH_ST_TABLE(hash));
RHASH_ST_TABLE_SET(hash, identtable);
RHASH_ST_CLEAR(tmp);
@@ -4358,17 +4495,17 @@ rb_hash_compare_by_id(VALUE hash)
* Returns +true+ if #compare_by_identity has been called, +false+ otherwise.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_compare_by_id_p(VALUE hash)
{
- return RBOOL(RHASH_ST_TABLE_P(hash) && RHASH_ST_TABLE(hash)->type == &identhash);
+ return RBOOL(RHASH_IDENTHASH_P(hash));
}
VALUE
rb_ident_hash_new(void)
{
VALUE hash = rb_hash_new();
- hash_st_table_init(hash, &identhash, 0);
+ RHASH_ST_TABLE_SET(hash, st_init_table(&identhash));
return hash;
}
@@ -4376,7 +4513,7 @@ VALUE
rb_ident_hash_new_with_size(st_index_t size)
{
VALUE hash = rb_hash_new();
- hash_st_table_init(hash, &identhash, size);
+ RHASH_ST_TABLE_SET(hash, st_init_table_with_size(&identhash, size));
return hash;
}
@@ -4386,6 +4523,12 @@ rb_init_identtable(void)
return st_init_table(&identhash);
}
+static st_table *
+rb_init_identtable_with_size(st_index_t size)
+{
+ return st_init_table_with_size(&identhash, size);
+}
+
static int
any_p_i(VALUE key, VALUE value, VALUE arg)
{
@@ -4428,9 +4571,6 @@ any_p_i_pattern(VALUE key, VALUE value, VALUE arg)
* Returns +true+ if any element satisfies a given criterion;
* +false+ otherwise.
*
- * If +self+ has no element, returns +false+ and argument or block
- * are not used.
- *
* With no argument and no block,
* returns +true+ if +self+ is non-empty; +false+ if empty.
*
@@ -4449,8 +4589,6 @@ any_p_i_pattern(VALUE key, VALUE value, VALUE arg)
* h = {foo: 0, bar: 1, baz: 2}
* h.any? {|key, value| value < 3 } # => true
* h.any? {|key, value| value > 3 } # => false
- *
- * Related: Enumerable#any?
*/
static VALUE
@@ -4628,7 +4766,7 @@ hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, hash))
* call-seq:
* hash.to_proc -> proc
*
- * Returns a Proc object that maps a key to its value:
+ * Returns a \Proc object that maps a key to its value:
* h = {foo: 0, bar: 1, baz: 2}
* proc = h.to_proc
* proc.class # => Proc
@@ -4672,11 +4810,13 @@ rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val)
args[1] = val;
if (RHASH_AR_TABLE_P(hash)) {
+ hash_ar_table(hash);
+
ret = ar_update(hash, (st_data_t)key, add_new_i, (st_data_t)args);
if (ret != -1) {
return ret;
}
- ar_try_convert_table(hash);
+ ar_force_convert_table(hash, __FILE__, __LINE__);
}
tbl = RHASH_TBL_RAW(hash);
return st_update(tbl, (st_data_t)key, add_new_i, (st_data_t)args);
@@ -4710,6 +4850,15 @@ rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
if (argc > 0) {
st_index_t size = argc / 2;
+ if (RHASH_TABLE_NULL_P(hash)) {
+ if (size <= RHASH_AR_TABLE_MAX_SIZE) {
+ hash_ar_table(hash);
+ }
+ else {
+ RHASH_TBL_RAW(hash);
+ }
+ }
+
if (RHASH_AR_TABLE_P(hash) &&
(RHASH_AR_TABLE_SIZE(hash) + size <= RHASH_AR_TABLE_MAX_SIZE)) {
ar_bulk_insert(hash, argc, argv);
@@ -4812,7 +4961,9 @@ has_env_with_lock(const char *name)
static const char TZ_ENV[] = "TZ";
static void *
-get_env_cstr(VALUE str, const char *name)
+get_env_cstr(
+ VALUE str,
+ const char *name)
{
char *var;
rb_encoding *enc = rb_enc_get(str);
@@ -4844,7 +4995,7 @@ env_name(volatile VALUE *s)
static VALUE env_aset(VALUE nm, VALUE val);
static void
-reset_by_modified_env(const char *nam)
+reset_by_modified_env(const char *nam, const char *val)
{
/*
* ENV['TZ'] = nil has a special meaning.
@@ -4853,7 +5004,7 @@ reset_by_modified_env(const char *nam)
* This hack might works only on Linux glibc.
*/
if (ENVMATCH(nam, TZ_ENV)) {
- ruby_reset_timezone();
+ ruby_reset_timezone(val);
}
}
@@ -4861,7 +5012,7 @@ static VALUE
env_delete(VALUE name)
{
const char *nam = env_name(name);
- reset_by_modified_env(nam);
+ reset_by_modified_env(nam, NULL);
VALUE val = getenv_with_lock(nam);
if (!NIL_P(val)) {
@@ -5135,7 +5286,7 @@ ruby_setenv(const char *name, const char *value)
}
ENV_UNLOCK();
- if (ret) rb_sys_fail_sprintf("setenv(%s)", name);
+ if (ret) rb_sys_fail_str(rb_sprintf("setenv(%s)", name));
}
else {
#ifdef VOID_UNSETENV
@@ -5152,7 +5303,7 @@ ruby_setenv(const char *name, const char *value)
}
ENV_UNLOCK();
- if (ret) rb_sys_fail_sprintf("unsetenv(%s)", name);
+ if (ret) rb_sys_fail_str(rb_sprintf("unsetenv(%s)", name));
#endif
}
#elif defined __sun
@@ -5169,7 +5320,7 @@ ruby_setenv(const char *name, const char *value)
mem_size = len + strlen(value) + 2;
mem_ptr = malloc(mem_size);
if (mem_ptr == NULL)
- rb_sys_fail_sprintf("malloc(%"PRIuSIZE")", mem_size);
+ rb_sys_fail_str(rb_sprintf("malloc(%"PRIuSIZE")", mem_size));
snprintf(mem_ptr, mem_size, "%s=%s", name, value);
}
@@ -5195,7 +5346,7 @@ ruby_setenv(const char *name, const char *value)
if (ret) {
free(mem_ptr);
- rb_sys_fail_sprintf("putenv(%s)", name);
+ rb_sys_fail_str(rb_sprintf("putenv(%s)", name));
}
}
#else /* WIN32 */
@@ -5259,6 +5410,8 @@ ruby_unsetenv(const char *name)
* ENV[name] = value -> value
* ENV.store(name, value) -> value
*
+ * ENV.store is an alias for ENV.[]=.
+ *
* Creates, updates, or deletes the named environment variable, returning the value.
* Both +name+ and +value+ may be instances of String.
* See {Valid Names and Values}[rdoc-ref:ENV@Valid+Names+and+Values].
@@ -5319,7 +5472,7 @@ env_aset(VALUE nm, VALUE val)
get_env_ptr(value, val);
ruby_setenv(name, value);
- reset_by_modified_env(name);
+ reset_by_modified_env(name, value);
return val;
}
@@ -5499,7 +5652,7 @@ env_each_value(VALUE ehash)
* ENV.each_pair { |name, value| block } -> ENV
* ENV.each_pair -> an_enumerator
*
- * Yields each environment variable name and its value as a 2-element Array:
+ * Yields each environment variable name and its value as a 2-element \Array:
* h = {}
* ENV.each_pair { |name, value| h[name] = value } # => ENV
* h # => {"bar"=>"1", "foo"=>"0"}
@@ -5635,7 +5788,7 @@ env_delete_if(VALUE ehash)
* Returns +nil+ in the Array for each name that is not an ENV name:
* ENV.values_at('foo', 'bat', 'bar', 'bam') # => ["0", nil, "1", nil]
*
- * Returns an empty Array if no names given.
+ * Returns an empty \Array if no names given.
*
* Raises an exception if any name is invalid.
* See {Invalid Names and Values}[rdoc-ref:ENV@Invalid+Names+and+Values].
@@ -5660,6 +5813,8 @@ env_values_at(int argc, VALUE *argv, VALUE _)
* ENV.filter { |name, value| block } -> hash of name/value pairs
* ENV.filter -> an_enumerator
*
+ * ENV.filter is an alias for ENV.select.
+ *
* Yields each environment variable name and its value as a 2-element Array,
* returning a Hash of the names and values for which the block returns a truthy value:
* ENV.replace('foo' => '0', 'bar' => '1', 'baz' => '2')
@@ -5703,6 +5858,8 @@ env_select(VALUE ehash)
* ENV.filter! { |name, value| block } -> ENV or nil
* ENV.filter! -> an_enumerator
*
+ * ENV.filter! is an alias for ENV.select!.
+ *
* Yields each environment variable name and its value as a 2-element Array,
* deleting each entry for which the block returns +false+ or +nil+,
* and returning ENV if any deletions made, or +nil+ otherwise:
@@ -5870,24 +6027,23 @@ env_to_s(VALUE _)
static VALUE
env_inspect(VALUE _)
{
- VALUE i;
VALUE str = rb_str_buf_new2("{");
+ rb_encoding *enc = env_encoding();
ENV_LOCK();
{
char **env = GET_ENVIRON(environ);
while (*env) {
- char *s = strchr(*env, '=');
+ const char *s = strchr(*env, '=');
if (env != environ) {
rb_str_buf_cat2(str, ", ");
}
if (s) {
- rb_str_buf_cat2(str, "\"");
- rb_str_buf_cat(str, *env, s-*env);
- rb_str_buf_cat2(str, "\"=>");
- i = rb_inspect(rb_str_new2(s+1));
- rb_str_buf_append(str, i);
+ rb_str_buf_append(str, rb_str_inspect(env_enc_str_new(*env, s-*env, enc)));
+ rb_str_buf_cat2(str, "=>");
+ s++;
+ rb_str_buf_append(str, rb_str_inspect(env_enc_str_new(s, strlen(s), enc)));
}
env++;
}
@@ -6013,6 +6169,8 @@ env_empty_p(VALUE _)
* ENV.member?(name) -> true or false
* ENV.key?(name) -> true or false
*
+ * ENV.has_key?, ENV.member?, and ENV.key? are aliases for ENV.include?.
+ *
* Returns +true+ if there is an environment variable with the given +name+:
* ENV.replace('foo' => '0', 'bar' => '1')
* ENV.include?('foo') # => true
@@ -6493,6 +6651,8 @@ env_update_block_i(VALUE key, VALUE val, VALUE _)
* ENV.merge!(*hashes) -> ENV
* ENV.merge!(*hashes) { |name, env_val, hash_val| block } -> ENV
*
+ * ENV.update is an alias for ENV.merge!.
+ *
* Adds to ENV each key/value pair in the given +hash+; returns ENV:
* ENV.replace('foo' => '0', 'bar' => '1')
* ENV.merge!('baz' => '2', 'bat' => '3') # => {"bar"=>"1", "bat"=>"3", "baz"=>"2", "foo"=>"0"}
@@ -6584,8 +6744,8 @@ static const rb_data_type_t env_data_type = {
/*
* A \Hash maps each of its unique keys to a specific value.
*
- * A \Hash has certain similarities to an Array, but:
- * - An Array index is always an Integer.
+ * A \Hash has certain similarities to an \Array, but:
+ * - An \Array index is always an \Integer.
* - A \Hash key can be (almost) any object.
*
* === \Hash \Data Syntax
@@ -6595,14 +6755,14 @@ static const rb_data_type_t env_data_type = {
* h = {:foo => 0, :bar => 1, :baz => 2}
* h # => {:foo=>0, :bar=>1, :baz=>2}
*
- * Alternatively, but only for a \Hash key that's a Symbol,
+ * Alternatively, but only for a \Hash key that's a \Symbol,
* you can use a newer JSON-style syntax,
- * where each bareword becomes a Symbol:
+ * where each bareword becomes a \Symbol:
*
* h = {foo: 0, bar: 1, baz: 2}
* h # => {:foo=>0, :bar=>1, :baz=>2}
*
- * You can also use a String in place of a bareword:
+ * You can also use a \String in place of a bareword:
*
* h = {'foo': 0, 'bar': 1, 'baz': 2}
* h # => {:foo=>0, :bar=>1, :baz=>2}
@@ -6727,7 +6887,7 @@ static const rb_data_type_t env_data_type = {
*
* - Iterative methods such as <tt>each</tt>, <tt>each_key</tt>, <tt>each_pair</tt>, <tt>each_value</tt>.
* - Other order-sensitive methods such as <tt>shift</tt>, <tt>keys</tt>, <tt>values</tt>.
- * - The String returned by method <tt>inspect</tt>.
+ * - The \String returned by method <tt>inspect</tt>.
*
* A new \Hash has its initial ordering per the given entries:
*
@@ -6786,9 +6946,9 @@ static const rb_data_type_t env_data_type = {
* h.include?(a0) # => true
* h[a0] # => 0
*
- * A String key is always safe.
- * That's because an unfrozen String
- * passed as a key will be replaced by a duplicated and frozen String:
+ * A \String key is always safe.
+ * That's because an unfrozen \String
+ * passed as a key will be replaced by a duplicated and frozen \String:
*
* s = 'foo'
* s.frozen? # => false
@@ -6802,9 +6962,9 @@ static const rb_data_type_t env_data_type = {
* Note: this requirement does not apply if the \Hash uses #compare_by_identity since comparison will then
* rely on the keys' object id instead of <code>hash</code> and <code>eql?</code>.
*
- * Object defines basic implementation for <code>hash</code> and <code>eq?</code> that makes each object
+ * \Object defines basic implementation for <code>hash</code> and <code>eq?</code> that makes each object
* a distinct key. Typically, user-defined classes will want to override these methods to provide meaningful
- * behavior, or for example inherit Struct that has useful definitions for these.
+ * behavior, or for example inherit \Struct that has useful definitions for these.
*
* A typical implementation of <code>hash</code> is based on the
* object's data while <code>eql?</code> is usually aliased to the overridden
@@ -6827,7 +6987,7 @@ static const rb_data_type_t env_data_type = {
* alias eql? ==
*
* def hash
- * [self.class, @author, @title].hash
+ * @author.hash ^ @title.hash # XOR
* end
* end
*
@@ -6885,7 +7045,7 @@ static const rb_data_type_t env_data_type = {
*
* To use a mutable object as default, it is recommended to use a default proc
*
- * ==== Default Proc
+ * ==== Default \Proc
*
* When the default proc for a \Hash is set (i.e., not +nil+),
* the default value returned by method #[] is determined by the default proc alone.
@@ -6925,10 +7085,6 @@ static const rb_data_type_t env_data_type = {
*
* Note that setting the default proc will clear the default value and vice versa.
*
- * Be aware that a default proc that modifies the hash is not thread-safe in the
- * sense that multiple threads can call into the default proc concurrently for the
- * same key.
- *
* === What's Here
*
* First, what's elsewhere. \Class \Hash:
@@ -6986,7 +7142,7 @@ static const rb_data_type_t env_data_type = {
* - #<=: Returns whether +self+ is a subset of a given object.
* - #==: Returns whether a given object is equal to +self+.
* - #>: Returns whether +self+ is a proper superset of a given object
- * - #>=: Returns whether +self+ is a superset of a given object.
+ * - #>=: Returns whether +self+ is a proper superset of a given object.
*
* ==== Methods for Fetching
*
@@ -6999,7 +7155,7 @@ static const rb_data_type_t env_data_type = {
* - #key: Returns the key for the first-found entry with a given value.
* - #keys: Returns an array containing all keys in +self+.
* - #rassoc: Returns a 2-element array consisting of the key and value
- * of the first-found entry having a given value.
+ of the first-found entry having a given value.
* - #values: Returns an array containing all values in +self+/
* - #values_at: Returns an array containing values for given keys.
*
@@ -7164,15 +7320,15 @@ Init_Hash(void)
/* Document-class: ENV
*
- * \ENV is a hash-like accessor for environment variables.
+ * ENV is a hash-like accessor for environment variables.
*
* === Interaction with the Operating System
*
- * The \ENV object interacts with the operating system's environment variables:
+ * The ENV object interacts with the operating system's environment variables:
*
- * - When you get the value for a name in \ENV, the value is retrieved from among the current environment variables.
- * - When you create or set a name-value pair in \ENV, the name and value are immediately set in the environment variables.
- * - When you delete a name-value pair in \ENV, it is immediately deleted from the environment variables.
+ * - When you get the value for a name in ENV, the value is retrieved from among the current environment variables.
+ * - When you create or set a name-value pair in ENV, the name and value are immediately set in the environment variables.
+ * - When you delete a name-value pair in ENV, it is immediately deleted from the environment variables.
*
* === Names and Values
*
@@ -7222,24 +7378,24 @@ Init_Hash(void)
*
* === About Ordering
*
- * \ENV enumerates its name/value pairs in the order found
+ * ENV enumerates its name/value pairs in the order found
* in the operating system's environment variables.
- * Therefore the ordering of \ENV content is OS-dependent, and may be indeterminate.
+ * Therefore the ordering of ENV content is OS-dependent, and may be indeterminate.
*
* This will be seen in:
- * - A Hash returned by an \ENV method.
- * - An Enumerator returned by an \ENV method.
+ * - A Hash returned by an ENV method.
+ * - An Enumerator returned by an ENV method.
* - An Array returned by ENV.keys, ENV.values, or ENV.to_a.
* - The String returned by ENV.inspect.
* - The Array returned by ENV.shift.
* - The name returned by ENV.key.
*
* === About the Examples
- * Some methods in \ENV return \ENV itself. Typically, there are many environment variables.
- * It's not useful to display a large \ENV in the examples here,
- * so most example snippets begin by resetting the contents of \ENV:
- * - ENV.replace replaces \ENV with a new collection of entries.
- * - ENV.clear empties \ENV.
+ * Some methods in ENV return ENV itself. Typically, there are many environment variables.
+ * It's not useful to display a large ENV in the examples here,
+ * so most example snippets begin by resetting the contents of ENV:
+ * - ENV.replace replaces ENV with a new collection of entries.
+ * - ENV.clear empties ENV.
*
* == What's Here
*
@@ -7299,8 +7455,8 @@ Init_Hash(void)
* - ::except: Returns a hash of all name/value pairs except those given.
* - ::fetch: Returns the value for the given name.
* - ::inspect: Returns the contents of \ENV as a string.
- * - ::invert: Returns a hash whose keys are the \ENV values,
- and whose values are the corresponding \ENV names.
+ * - ::invert: Returns a hash whose keys are the ENV values,
+ and whose values are the corresponding ENV names.
* - ::keys: Returns an array of all names.
* - ::rassoc: Returns the name and value of the first found entry
* that has the given value.
@@ -7389,7 +7545,7 @@ Init_Hash(void)
rb_undef_method(envtbl_class, "initialize_dup");
/*
- * \ENV is a Hash-like accessor for environment variables.
+ * ENV is a Hash-like accessor for environment variables.
*
* See ENV (the class) for more details.
*/
diff --git a/id_table.c b/id_table.c
index 650721c670..a9a041b955 100644
--- a/id_table.c
+++ b/id_table.c
@@ -92,7 +92,7 @@ rb_id_table_init(struct rb_id_table *tbl, int capa)
return tbl;
}
-struct rb_id_table *
+MJIT_FUNC_EXPORTED struct rb_id_table *
rb_id_table_create(size_t capa)
{
struct rb_id_table *tbl = ALLOC(struct rb_id_table);
@@ -223,7 +223,7 @@ hash_table_show(struct rb_id_table *tbl)
}
#endif
-int
+MJIT_FUNC_EXPORTED int
rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp)
{
id_key_t key = id2key(id);
@@ -253,7 +253,7 @@ rb_id_table_insert_key(struct rb_id_table *tbl, const id_key_t key, const VALUE
return TRUE;
}
-int
+MJIT_FUNC_EXPORTED int
rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val)
{
return rb_id_table_insert_key(tbl, id2key(id), val);
diff --git a/include/ruby/backward/2/attributes.h b/include/ruby/backward/2/attributes.h
index 916d9e9d5b..73acfc9dc0 100644
--- a/include/ruby/backward/2/attributes.h
+++ b/include/ruby/backward/2/attributes.h
@@ -39,7 +39,6 @@
#include "ruby/internal/attr/noinline.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/noreturn.h"
-#include "ruby/internal/attr/packed_struct.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/restrict.h"
#include "ruby/internal/attr/returns_nonnull.h"
@@ -81,8 +80,10 @@
#undef NOINLINE
#define NOINLINE(x) RBIMPL_ATTR_NOINLINE() x
-#undef ALWAYS_INLINE
-#define ALWAYS_INLINE(x) RBIMPL_ATTR_FORCEINLINE() x
+#ifndef MJIT_HEADER
+# undef ALWAYS_INLINE
+# define ALWAYS_INLINE(x) RBIMPL_ATTR_FORCEINLINE() x
+#endif
#undef ERRORFUNC
#define ERRORFUNC(mesg, x) RBIMPL_ATTR_ERROR(mesg) x
@@ -146,14 +147,17 @@
#define NORETURN(x) RBIMPL_ATTR_NORETURN() x
#define NORETURN_STYLE_NEW
-#undef PACKED_STRUCT
-#define PACKED_STRUCT(x) \
- RBIMPL_ATTR_PACKED_STRUCT_BEGIN() x RBIMPL_ATTR_PACKED_STRUCT_END()
+#ifndef PACKED_STRUCT
+# define PACKED_STRUCT(x) x
+#endif
-#undef PACKED_STRUCT_UNALIGNED
-#define PACKED_STRUCT_UNALIGNED(x) \
- RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN() x \
- RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END()
+#ifndef PACKED_STRUCT_UNALIGNED
+# if UNALIGNED_WORD_ACCESS
+# define PACKED_STRUCT_UNALIGNED(x) PACKED_STRUCT(x)
+# else
+# define PACKED_STRUCT_UNALIGNED(x) x
+# endif
+#endif
#undef RB_UNUSED_VAR
#define RB_UNUSED_VAR(x) x RBIMPL_ATTR_MAYBE_UNUSED()
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index e173f16e25..f95acdb17e 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -51,25 +51,6 @@ RBIMPL_ATTR_NONNULL((3))
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
/**
- * Queries mysterious "frame"s of the given range.
- *
- * A per-thread version of rb_profile_frames().
- * Arguments and return values are the same with rb_profile_frames() with the
- * exception of the first argument _thread_, which accepts the Thread to be
- * profiled/queried.
- *
- * @param[in] thread The Ruby Thread to be profiled.
- * @param[in] start Start position (0 means the topmost).
- * @param[in] limit Number objects of `buff`.
- * @param[out] buff Return buffer.
- * @param[out] lines Return buffer.
- * @return Number of objects filled into `buff`.
- * @post `buff` is filled with backtrace pointers.
- * @post `lines` is filled with `__LINE__` of each backtraces.
- */
-int rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines);
-
-/**
* Queries the path of the passed backtrace.
*
* @param[in] frame What rb_profile_frames() returned.
@@ -647,9 +628,9 @@ typedef void (*rb_postponed_job_func_t)(void *arg);
int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data);
/**
- * Identical to rb_postponed_job_register(), except it additionally checks for
- * duplicated registration. In case the passed job is already in the postponed
- * job buffer this function does nothing.
+ * Identical to rb_postponed_job_register_one(), except it additionally checks
+ * for duplicated registration. In case the passed job is already in the
+ * postponed job buffer this function does nothing.
*
* @param[in] flags (Unused) reserved for future extensions.
* @param[in] func Job body.
diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h
index ad3d2d7483..250b39b6df 100644
--- a/include/ruby/fiber/scheduler.h
+++ b/include/ruby/fiber/scheduler.h
@@ -267,10 +267,10 @@ VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv);
* Non-blocking read from the passed IO.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] buffer The buffer to read to.
- * @param[in] length The minimum number of bytes to read.
- * @param[in] offset The offset in the buffer to read from.
+ * @param[out] io An io object to read from.
+ * @param[out] buffer Return buffer.
+ * @param[in] length Requested number of bytes to read.
+ * @param[in] offset The offset in the buffer to read to.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns `[-errno, size]`.
*/
@@ -280,9 +280,9 @@ VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t
* Non-blocking write to the passed IO.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] buffer The buffer to write from.
- * @param[in] length The minimum number of bytes to write.
+ * @param[out] io An io object to write to.
+ * @param[in] buffer What to write.
+ * @param[in] length Number of bytes to write.
* @param[in] offset The offset in the buffer to write from.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns `[-errno, size]`.
@@ -293,10 +293,10 @@ VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_
* Non-blocking read from the passed IO at the specified offset.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] from The offset to read from.
- * @param[in] buffer The buffer to read to.
- * @param[in] length The minimum number of bytes to read.
+ * @param[out] io An io object to read from.
+ * @param[in] from The offset in the given IO to read the data from.
+ * @param[out] buffer The buffer to read the data to.
+ * @param[in] length Requested number of bytes to read.
* @param[in] offset The offset in the buffer to read to.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns.
@@ -307,10 +307,10 @@ VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALU
* Non-blocking write to the passed IO at the specified offset.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] from The offset to write to.
- * @param[in] buffer The buffer to write from.
- * @param[in] length The minimum number of bytes to write.
+ * @param[out] io An io object to write to.
+ * @param[in] from The offset in the given IO to write the data to.
+ * @param[in] buffer The buffer to write the data from.
+ * @param[in] length Number of bytes to write.
* @param[in] offset The offset in the buffer to write from.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns.
@@ -321,55 +321,27 @@ VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VAL
* Non-blocking read from the passed IO using a native buffer.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] base The memory to read to.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to read.
+ * @param[out] io An io object to read from.
+ * @param[out] buffer Return buffer.
+ * @param[in] size Size of the return buffer.
+ * @param[in] length Requested number of bytes to read.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns.
*/
-VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length);
+VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length);
/**
* Non-blocking write to the passed IO using a native buffer.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] base The memory to write from.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to write.
- * @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
- * @return otherwise What `scheduler.io_write` returns.
- */
-VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length);
-
-/**
- * Non-blocking pread from the passed IO using a native buffer.
- *
- * @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] from The offset to read from.
- * @param[in] base The memory to read to.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to read.
- * @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
- * @return otherwise What `scheduler.io_read` returns.
- */
-VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length);
-
-/**
- * Non-blocking pwrite to the passed IO using a native buffer.
- *
- * @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] from The offset to write from.
- * @param[in] base The memory to write from.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to write.
+ * @param[out] io An io object to write to.
+ * @param[in] buffer What to write.
+ * @param[in] size Size of the buffer.
+ * @param[in] length Number of bytes to write.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns.
*/
-VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length);
+VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length);
/**
* Non-blocking close the given IO.
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 48e4cd546e..2480e2e703 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -36,6 +36,7 @@
#include "ruby/internal/intern/error.h"
#include "ruby/internal/intern/eval.h"
#include "ruby/internal/intern/file.h"
+#include "ruby/internal/intern/gc.h"
#include "ruby/internal/intern/hash.h"
#include "ruby/internal/intern/io.h"
#include "ruby/internal/intern/load.h"
diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h
index 8e1bbf3951..44111a0055 100644
--- a/include/ruby/internal/abi.h
+++ b/include/ruby/internal/abi.h
@@ -24,7 +24,7 @@
* In released versions of Ruby, this number is not defined since teeny
* versions of Ruby should guarantee ABI compatibility.
*/
-#define RUBY_ABI_VERSION 0
+#define RUBY_ABI_VERSION 3
/* Windows does not support weak symbols so ruby_abi_version will not exist
* in the shared library. */
diff --git a/include/ruby/internal/anyargs.h b/include/ruby/internal/anyargs.h
index e3e1b6166d..e4c6d155cc 100644
--- a/include/ruby/internal/anyargs.h
+++ b/include/ruby/internal/anyargs.h
@@ -84,12 +84,15 @@
#elif defined(_WIN32) || defined(__CYGWIN__)
# /* Skip due to [Bug #16134] */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! RBIMPL_HAS_ATTRIBUTE(transparent_union)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! defined(HAVE_VA_ARGS_MACRO)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#else
# /** @cond INTERNAL_MACRO */
@@ -348,6 +351,25 @@ RBIMPL_ANYARGS_DECL(rb_define_method, VALUE, const char *)
#endif /* __cplusplus */
+#if defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus)
+/* In C23, K&R style prototypes are gone and so `void foo(ANYARGS)` became
+ * equivalent to `void foo(void)` unlike in earlier versions. This is a problem
+ * for rb_define_* functions since that makes all valid functions one can pass
+ * trip -Wincompatible-pointer-types, which we treat as errors. This is mostly
+ * not a problem for the __builtin_choose_expr path, but outside of that we
+ * need to add a cast for compatibility.
+ */
+#define rb_define_method(klass, mid, func, arity) rb_define_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_method_id(klass, mid, func, arity) rb_define_method_id((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_singleton_method(obj, mid, func, arity) rb_define_singleton_method((obj), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_protected_method(klass, mid, func, arity) rb_define_protected_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_private_method(klass, mid, func, arity) rb_define_private_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_module_function(mod, mid, func, arity) rb_define_module_function((mod), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_global_function(mid, func, arity) rb_define_global_function((mid), (VALUE (*)(ANYARGS))(func), (arity))
+
+#undef RBIMPL_CAST_FN_PTR
+#endif /* defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus) */
+
/**
* This macro is to properly cast a function parameter of *_define_method
* family. It has been around since 1.x era so you can maximise backwards
diff --git a/include/ruby/internal/attr/nonstring.h b/include/ruby/internal/attr/nonstring.h
new file mode 100644
index 0000000000..de26e926d4
--- /dev/null
+++ b/include/ruby/internal/attr/nonstring.h
@@ -0,0 +1,32 @@
+#ifndef RBIMPL_ATTR_NONSTRING_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_ATTR_NONSTRING_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief Defines #RBIMPL_ATTR_NONSTRING.
+ */
+#include "ruby/internal/has/attribute.h"
+
+/** Wraps (or simulates) `__attribute__((nonstring))` */
+#if RBIMPL_HAS_ATTRIBUTE(nonstring)
+# define RBIMPL_ATTR_NONSTRING() __attribute__((nonstring))
+#else
+# define RBIMPL_ATTR_NONSTRING() /* void */
+#endif
+
+#endif /* RBIMPL_ATTR_NONSTRING_H */
diff --git a/include/ruby/internal/attr/packed_struct.h b/include/ruby/internal/attr/packed_struct.h
deleted file mode 100644
index 0678b9acc8..0000000000
--- a/include/ruby/internal/attr/packed_struct.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef RBIMPL_ATTR_PACKED_STRUCT_H /*-*-C++-*-vi:se ft=cpp:*/
-#define RBIMPL_ATTR_PACKED_STRUCT_H
-/**
- * @file
- * @author Ruby developers <ruby-core@ruby-lang.org>
- * @copyright This file is a part of the programming language Ruby.
- * Permission is hereby granted, to either redistribute and/or
- * modify this file, provided that the conditions mentioned in the
- * file COPYING are met. Consult the file for details.
- * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
- * implementation details. Don't take them as canon. They could
- * rapidly appear then vanish. The name (path) of this header file
- * is also an implementation detail. Do not expect it to persist
- * at the place it is now. Developers are free to move it anywhere
- * anytime at will.
- * @note To ruby-core: remember that this header can be possibly
- * recursively included from extension libraries written in C++.
- * Do not expect for instance `__VA_ARGS__` is always available.
- * We assume C99 for ruby itself but we don't assume languages of
- * extension libraries. They could be written in C++98.
- * @brief Defines #RBIMPL_ATTR_PACKED_STRUCT_BEGIN,
- * #RBIMPL_ATTR_PACKED_STRUCT_END,
- * #RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN, and
- * #RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END.
- */
-#include "ruby/internal/config.h"
-
-#ifndef RBIMPL_ATTR_PACKED_STRUCT_BEGIN
-# define RBIMPL_ATTR_PACKED_STRUCT_BEGIN() /* void */
-#endif
-#ifndef RBIMPL_ATTR_PACKED_STRUCT_END
-# define RBIMPL_ATTR_PACKED_STRUCT_END() /* void */
-#endif
-
-#if UNALIGNED_WORD_ACCESS
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN() RBIMPL_ATTR_PACKED_STRUCT_BEGIN()
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END() RBIMPL_ATTR_PACKED_STRUCT_END()
-#else
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN() /* void */
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END() /* void */
-#endif
-
-#endif
diff --git a/include/ruby/internal/config.h b/include/ruby/internal/config.h
index da070f0979..aa63376d7c 100644
--- a/include/ruby/internal/config.h
+++ b/include/ruby/internal/config.h
@@ -148,4 +148,8 @@
# undef RBIMPL_TEST3
#endif /* HAVE_VA_ARGS_MACRO */
+#ifndef USE_RVARGC
+# define USE_RVARGC 1
+#endif
+
#endif /* RBIMPL_CONFIG_H */
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h
index 90690fe794..c3bb40be25 100644
--- a/include/ruby/internal/core/rarray.h
+++ b/include/ruby/internal/core/rarray.h
@@ -29,13 +29,25 @@
#include "ruby/internal/core/rbasic.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/fl_type.h"
-#include "ruby/internal/gc.h"
+#include "ruby/internal/rgengc.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value.h"
#include "ruby/internal/value_type.h"
#include "ruby/assert.h"
/**
+ * @private
+ * @warning Do not touch this macro.
+ * @warning It is an implementation detail.
+ * @warning The value of this macro must match for ruby itself and all
+ * extension libraries, otherwise serious memory corruption shall
+ * occur.
+ */
+#ifndef USE_TRANSIENT_HEAP
+# define USE_TRANSIENT_HEAP 1
+#endif
+
+/**
* Convenient casting macro.
*
* @param obj An object, which is in fact an ::RArray.
@@ -47,9 +59,15 @@
#define RARRAY_EMBED_LEN_MASK RARRAY_EMBED_LEN_MASK
#define RARRAY_EMBED_LEN_MAX RARRAY_EMBED_LEN_MAX
#define RARRAY_EMBED_LEN_SHIFT RARRAY_EMBED_LEN_SHIFT
+#if USE_TRANSIENT_HEAP
+# define RARRAY_TRANSIENT_FLAG RARRAY_TRANSIENT_FLAG
+#else
+# define RARRAY_TRANSIENT_FLAG 0
+#endif
/** @endcond */
#define RARRAY_LEN rb_array_len /**< @alias{rb_array_len} */
#define RARRAY_CONST_PTR rb_array_const_ptr /**< @alias{rb_array_const_ptr} */
+#define RARRAY_CONST_PTR_TRANSIENT rb_array_const_ptr_transient /**< @alias{rb_array_const_ptr_transient} */
/** @cond INTERNAL_MACRO */
#if defined(__fcc__) || defined(__fcc_version) || \
@@ -62,6 +80,7 @@
#define RARRAY_EMBED_LEN RARRAY_EMBED_LEN
#define RARRAY_LENINT RARRAY_LENINT
+#define RARRAY_TRANSIENT_P RARRAY_TRANSIENT_P
#define RARRAY_ASET RARRAY_ASET
#define RARRAY_PTR RARRAY_PTR
/** @endcond */
@@ -111,8 +130,30 @@ enum ruby_rarray_flags {
* 3rd parties must not be aware that there even is more than one way to
* store array elements. It was a bad idea to expose this to them.
*/
+#if USE_RVARGC
RARRAY_EMBED_LEN_MASK = RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | RUBY_FL_USER6 |
RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3
+#else
+ RARRAY_EMBED_LEN_MASK = RUBY_FL_USER4 | RUBY_FL_USER3
+#endif
+
+#if USE_TRANSIENT_HEAP
+ ,
+
+ /**
+ * This flag has something to do with an array's "transiency". A transient
+ * array is an array of young generation (of generational GC), who stores
+ * its elements inside of dedicated memory pages called a transient heap.
+ * Not every young generation share that storage scheme, but elder
+ * generations must no join.
+ *
+ * @internal
+ *
+ * 3rd parties must not be aware that there even is more than one way to
+ * store array elements. It was a bad idea to expose this to them.
+ */
+ RARRAY_TRANSIENT_FLAG = RUBY_FL_USER13
+#endif
};
/**
@@ -122,6 +163,13 @@ enum ruby_rarray_flags {
enum ruby_rarray_consts {
/** Where ::RARRAY_EMBED_LEN_MASK resides. */
RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3
+
+#if !USE_RVARGC
+ ,
+
+ /** Max possible number elements that can be embedded. */
+ RARRAY_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE)
+#endif
};
/** Ruby's array. */
@@ -180,12 +228,16 @@ struct RArray {
* to store its elements. In this case the length is encoded into the
* flags.
*/
+#if USE_RVARGC
/* This is a length 1 array because:
* 1. GCC has a bug that does not optimize C flexible array members
* (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452)
* 2. Zero length arrays are not supported by all compilers
*/
const VALUE ary[1];
+#else
+ const VALUE ary[RARRAY_EMBED_LEN_MAX];
+#endif
} as;
};
@@ -212,6 +264,16 @@ VALUE *rb_ary_ptr_use_start(VALUE ary);
*/
void rb_ary_ptr_use_end(VALUE a);
+#if USE_TRANSIENT_HEAP
+/**
+ * Destructively converts an array of transient backend into ordinal one.
+ *
+ * @param[out] a An object of ::RArray.
+ * @pre `a` must be a transient array.
+ * @post `a` gets out of transient heap, destructively.
+ */
+void rb_ary_detransient(VALUE a);
+#endif
RBIMPL_SYMBOL_EXPORT_END()
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
@@ -284,6 +346,33 @@ RARRAY_LENINT(VALUE ary)
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * Queries if the array is a transient array.
+ *
+ * @param[in] ary Array in question.
+ * @retval true Yes it is.
+ * @retval false No it isn't.
+ * @pre `ary` must be an instance of ::RArray.
+ *
+ * @internal
+ *
+ * @shyouhei doesn't understand the benefit of this function called from
+ * extension libraries.
+ */
+static inline bool
+RARRAY_TRANSIENT_P(VALUE ary)
+{
+ RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
+
+#if USE_TRANSIENT_HEAP
+ return RB_FL_ANY_RAW(ary, RARRAY_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
/**
* @private
*
@@ -294,7 +383,7 @@ RBIMPL_ATTR_PURE_UNLESS_DEBUG()
* @return Its backend storage.
*/
static inline const VALUE *
-rb_array_const_ptr(VALUE a)
+rb_array_const_ptr_transient(VALUE a)
{
RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
@@ -306,21 +395,102 @@ rb_array_const_ptr(VALUE a)
}
}
+#if ! USE_TRANSIENT_HEAP
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+#endif
+/**
+ * @private
+ *
+ * This is an implementation detail of RARRAY_PTR(). People do not use it
+ * directly.
+ *
+ * @param[in] a An object of ::RArray.
+ * @return Its backend storage.
+ * @post `a` is not a transient array.
+ */
+static inline const VALUE *
+rb_array_const_ptr(VALUE a)
+{
+ RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
+
+#if USE_TRANSIENT_HEAP
+ if (RARRAY_TRANSIENT_P(a)) {
+ rb_ary_detransient(a);
+ }
+#endif
+ return rb_array_const_ptr_transient(a);
+}
+
+/**
+ * @private
+ *
+ * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
+ * directly.
+ *
+ * @param[in] a An object of ::RArray.
+ * @param[in] allow_transient Whether `a` can be transient or not.
+ * @return Its backend storage.
+ * @post `a` is not a transient array unless `allow_transient`.
+ */
+static inline VALUE *
+rb_array_ptr_use_start(VALUE a,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int allow_transient)
+{
+ RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
+
+#if USE_TRANSIENT_HEAP
+ if (!allow_transient) {
+ if (RARRAY_TRANSIENT_P(a)) {
+ rb_ary_detransient(a);
+ }
+ }
+#endif
+
+ return rb_ary_ptr_use_start(a);
+}
+
+/**
+ * @private
+ *
+ * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
+ * directly.
+ *
+ * @param[in] a An object of ::RArray.
+ * @param[in] allow_transient Whether `a` can be transient or not.
+ */
+static inline void
+rb_array_ptr_use_end(VALUE a,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int allow_transient)
+{
+ RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
+ rb_ary_ptr_use_end(a);
+}
+
/**
* @private
*
* This is an implementation detail of #RARRAY_PTR_USE. People do not use it
* directly.
*/
-#define RBIMPL_RARRAY_STMT(ary, var, expr) do { \
+#define RBIMPL_RARRAY_STMT(flag, ary, var, expr) do { \
RBIMPL_ASSERT_TYPE((ary), RUBY_T_ARRAY); \
const VALUE rbimpl_ary = (ary); \
- VALUE *var = rb_ary_ptr_use_start(rbimpl_ary); \
+ VALUE *var = rb_array_ptr_use_start(rbimpl_ary, (flag)); \
expr; \
- rb_ary_ptr_use_end(rbimpl_ary); \
+ rb_array_ptr_use_end(rbimpl_ary, (flag)); \
} while (0)
/**
+ * @private
+ *
+ * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
+ * directly.
+ */
+#define RARRAY_PTR_USE_END(a) rb_array_ptr_use_end(a, 0)
+
+/**
* Declares a section of code where raw pointers are used. In case you need to
* touch the raw C array instead of polite CAPIs, then that operation shall be
* wrapped using this macro.
@@ -346,11 +516,21 @@ rb_array_const_ptr(VALUE a)
* them use it... Maybe some transition path can be implemented later.
*/
#define RARRAY_PTR_USE(ary, ptr_name, expr) \
- RBIMPL_RARRAY_STMT(ary, ptr_name, expr)
+ RBIMPL_RARRAY_STMT(0, ary, ptr_name, expr)
+
+/**
+ * Identical to #RARRAY_PTR_USE, except the pointer can be a transient one.
+ *
+ * @param ary An object of ::RArray.
+ * @param ptr_name A variable name which points the C array in `expr`.
+ * @param expr The expression that touches `ptr_name`.
+ */
+#define RARRAY_PTR_USE_TRANSIENT(ary, ptr_name, expr) \
+ RBIMPL_RARRAY_STMT(1, ary, ptr_name, expr)
/**
* Wild use of a C pointer. This function accesses the backend storage
- * directly. This is slower than #RARRAY_PTR_USE. It exercises
+ * directly. This is slower than #RARRAY_PTR_USE_TRANSIENT. It exercises
* extra manoeuvres to protect our generational GC. Use of this function is
* considered archaic. Use a modern way instead.
*
@@ -385,7 +565,7 @@ RARRAY_PTR(VALUE ary)
static inline void
RARRAY_ASET(VALUE ary, long i, VALUE v)
{
- RARRAY_PTR_USE(ary, ptr,
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr,
RB_OBJ_WRITE(ary, &ptr[i], v));
}
@@ -400,6 +580,6 @@ RARRAY_ASET(VALUE ary, long i, VALUE v)
* remains as it is due to that. If we could warn such usages we can set a
* transition path, but currently no way is found to do so.
*/
-#define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i]
+#define RARRAY_AREF(a, i) RARRAY_CONST_PTR_TRANSIENT(a)[i]
#endif /* RBIMPL_RARRAY_H */
diff --git a/include/ruby/internal/core/rfile.h b/include/ruby/internal/core/rfile.h
index a0eb8cb833..f8dddde9e5 100644
--- a/include/ruby/internal/core/rfile.h
+++ b/include/ruby/internal/core/rfile.h
@@ -25,7 +25,7 @@
/* rb_io_t is in ruby/io.h. The header file has historically not been included
* into ruby/ruby.h. We follow that tradition. */
-struct rb_io;
+struct rb_io_t;
/**
* Ruby's File and IO. Ruby's IO are not just file descriptors. They have
@@ -38,7 +38,7 @@ struct RFile {
struct RBasic basic;
/** IO's specific fields. */
- struct rb_io *fptr;
+ struct rb_io_t *fptr;
};
/**
diff --git a/include/ruby/internal/core/rhash.h b/include/ruby/internal/core/rhash.h
index 897c570794..61d2c15d87 100644
--- a/include/ruby/internal/core/rhash.h
+++ b/include/ruby/internal/core/rhash.h
@@ -54,6 +54,19 @@
*
* @internal
*
+ * Declaration of rb_hash_iter_lev() is at include/ruby/backward.h.
+ */
+#define RHASH_ITER_LEV(h) rb_hash_iter_lev(h)
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ *
+ * @internal
+ *
* Declaration of rb_hash_ifnone() is at include/ruby/backward.h.
*/
#define RHASH_IFNONE(h) rb_hash_ifnone(h)
diff --git a/include/ruby/internal/core/rmatch.h b/include/ruby/internal/core/rmatch.h
index a528c2999e..2d2fd897f5 100644
--- a/include/ruby/internal/core/rmatch.h
+++ b/include/ruby/internal/core/rmatch.h
@@ -68,7 +68,7 @@ struct rmatch_offset {
};
/** Represents a match. */
-struct rb_matchext_struct {
+struct rmatch {
/**
* "Registers" of a match. This is a quasi-opaque struct that holds
* execution result of a match. Roughly resembles `&~`.
@@ -82,8 +82,6 @@ struct rb_matchext_struct {
int char_offset_num_allocated;
};
-typedef struct rb_matchext_struct rb_matchext_t;
-
/**
* Regular expression execution context. When a regular expression "matches"
* to a string, it generates capture groups etc. This struct holds that info.
@@ -104,13 +102,16 @@ struct RMatch {
VALUE str;
/**
+ * The result of this match.
+ */
+ struct rmatch *rmatch;
+
+ /**
* The expression of this match.
*/
VALUE regexp; /* RRegexp */
};
-#define RMATCH_EXT(m) ((rb_matchext_t *)((char *)(m) + sizeof(struct RMatch)))
-
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
@@ -138,7 +139,8 @@ static inline struct re_registers *
RMATCH_REGS(VALUE match)
{
RBIMPL_ASSERT_TYPE(match, RUBY_T_MATCH);
- return &RMATCH_EXT(match)->regs;
+ RBIMPL_ASSERT_OR_ASSUME(RMATCH(match)->rmatch != NULL);
+ return &RMATCH(match)->rmatch->regs;
}
#endif /* RBIMPL_RMATCH_H */
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h
index c2bcae6306..b1c2e1b0a9 100644
--- a/include/ruby/internal/core/robject.h
+++ b/include/ruby/internal/core/robject.h
@@ -74,6 +74,17 @@ enum ruby_robject_flags {
ROBJECT_EMBED = RUBY_FL_USER1
};
+#if !USE_RVARGC
+/**
+ * This is an enum because GDB wants it (rather than a macro). People need not
+ * bother.
+ */
+enum ruby_robject_consts {
+ /** Max possible number of instance variables that can be embedded. */
+ ROBJECT_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE)
+};
+#endif
+
struct st_table;
/**
@@ -107,6 +118,7 @@ struct RObject {
struct rb_id_table *iv_index_tbl;
} heap;
+#if USE_RVARGC
/* Embedded instance variables. When an object is small enough, it
* uses this area to store the instance variables.
*
@@ -116,9 +128,23 @@ struct RObject {
* 2. Zero length arrays are not supported by all compilers
*/
VALUE ary[1];
+#else
+ /**
+ * Embedded instance variables. When an object is small enough, it
+ * uses this area to store the instance variables.
+ */
+ VALUE ary[ROBJECT_EMBED_LEN_MAX];
+#endif
} as;
};
+/* Offsets for YJIT */
+#ifndef __cplusplus
+static const int32_t ROBJECT_OFFSET_AS_HEAP_IVPTR = offsetof(struct RObject, as.heap.ivptr);
+static const int32_t ROBJECT_OFFSET_AS_HEAP_IV_INDEX_TBL = offsetof(struct RObject, as.heap.iv_index_tbl);
+static const int32_t ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary);
+#endif
+
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h
index 0bca74e688..e394ab7dca 100644
--- a/include/ruby/internal/core/rstring.h
+++ b/include/ruby/internal/core/rstring.h
@@ -42,7 +42,13 @@
/** @cond INTERNAL_MACRO */
#define RSTRING_NOEMBED RSTRING_NOEMBED
+#if !USE_RVARGC
+#define RSTRING_EMBED_LEN_MASK RSTRING_EMBED_LEN_MASK
+#define RSTRING_EMBED_LEN_SHIFT RSTRING_EMBED_LEN_SHIFT
+#define RSTRING_EMBED_LEN_MAX RSTRING_EMBED_LEN_MAX
+#endif
#define RSTRING_FSTR RSTRING_FSTR
+#define RSTRING_EMBED_LEN RSTRING_EMBED_LEN
#define RSTRING_LEN RSTRING_LEN
#define RSTRING_LENINT RSTRING_LENINT
#define RSTRING_PTR RSTRING_PTR
@@ -156,6 +162,21 @@ enum ruby_rstring_flags {
*/
RSTRING_NOEMBED = RUBY_FL_USER1,
+#if !USE_RVARGC
+ /**
+ * When a string employs embedded strategy (see ::RSTRING_NOEMBED), these
+ * bits are used to store the number of bytes actually filled into
+ * ::RString::ary.
+ *
+ * @internal
+ *
+ * 3rd parties must not be aware that there even is more than one way to
+ * store a string. Might better be hidden.
+ */
+ RSTRING_EMBED_LEN_MASK = RUBY_FL_USER2 | RUBY_FL_USER3 | RUBY_FL_USER4 |
+ RUBY_FL_USER5 | RUBY_FL_USER6,
+#endif
+
/* Actually, string encodings are also encoded into the flags, using
* remaining bits.*/
@@ -181,6 +202,20 @@ enum ruby_rstring_flags {
RSTRING_FSTR = RUBY_FL_USER17
};
+#if !USE_RVARGC
+/**
+ * This is an enum because GDB wants it (rather than a macro). People need not
+ * bother.
+ */
+enum ruby_rstring_consts {
+ /** Where ::RSTRING_EMBED_LEN_MASK resides. */
+ RSTRING_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 2,
+
+ /** Max possible number of characters that can be embedded. */
+ RSTRING_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(char) - 1
+};
+#endif
+
/**
* Ruby's String. A string in ruby conceptually has these information:
*
@@ -198,13 +233,6 @@ struct RString {
/** Basic part, including flags and class. */
struct RBasic basic;
- /**
- * Length of the string, not including terminating NUL character.
- *
- * @note This is in bytes.
- */
- long len;
-
/** String's specific fields. */
union {
@@ -213,6 +241,14 @@ struct RString {
* pattern.
*/
struct {
+
+ /**
+ * Length of the string, not including terminating NUL character.
+ *
+ * @note This is in bytes.
+ */
+ long len;
+
/**
* Pointer to the contents of the string. In the old days each
* string had dedicated memory regions. That is no longer true
@@ -243,12 +279,24 @@ struct RString {
/** Embedded contents. */
struct {
+#if USE_RVARGC
+ long len;
/* This is a length 1 array because:
* 1. GCC has a bug that does not optimize C flexible array members
* (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452)
* 2. Zero length arrays are not supported by all compilers
*/
char ary[1];
+#else
+ /**
+ * When a string is short enough, it uses this area to store the
+ * contents themselves. This was impractical in the 20th century,
+ * but these days 64 bit machines can typically hold 24 bytes here.
+ * Could be sufficiently large. In this case the length is encoded
+ * into the flags.
+ */
+ char ary[RSTRING_EMBED_LEN_MAX + 1];
+#endif
} embed;
} as;
};
@@ -361,12 +409,31 @@ RBIMPL_ATTR_ARTIFICIAL()
*
* @param[in] str String in question.
* @return Its length, in bytes.
- * @pre `str` must be an instance of ::RString.
+ * @pre `str` must be an instance of ::RString, and must has its
+ * ::RSTRING_NOEMBED flag off.
+ *
+ * @internal
+ *
+ * This was a macro before. It was inevitable to be public, since macros are
+ * global constructs. But should it be forever? Now that it is a function,
+ * @shyouhei thinks it could just be eliminated, hidden into implementation
+ * details.
*/
static inline long
-RSTRING_LEN(VALUE str)
+RSTRING_EMBED_LEN(VALUE str)
{
- return RSTRING(str)->len;
+ RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING);
+ RBIMPL_ASSERT_OR_ASSUME(! RB_FL_ANY_RAW(str, RSTRING_NOEMBED));
+
+#if USE_RVARGC
+ long f = RSTRING(str)->as.embed.len;
+ return f;
+#else
+ VALUE f = RBASIC(str)->flags;
+ f &= RSTRING_EMBED_LEN_MASK;
+ f >>= RSTRING_EMBED_LEN_SHIFT;
+ return RBIMPL_CAST((long)f);
+#endif
}
RBIMPL_WARNING_PUSH()
@@ -396,7 +463,7 @@ rbimpl_rstring_getmem(VALUE str)
else {
/* Expecting compilers to optimize this on-stack struct away. */
struct RString retval;
- retval.len = RSTRING_LEN(str);
+ retval.as.heap.len = RSTRING_EMBED_LEN(str);
retval.as.heap.ptr = RSTRING(str)->as.embed.ary;
return retval;
}
@@ -404,6 +471,21 @@ rbimpl_rstring_getmem(VALUE str)
RBIMPL_WARNING_POP()
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * Queries the length of the string.
+ *
+ * @param[in] str String in question.
+ * @return Its length, in bytes.
+ * @pre `str` must be an instance of ::RString.
+ */
+static inline long
+RSTRING_LEN(VALUE str)
+{
+ return rbimpl_rstring_getmem(str).as.heap.len;
+}
+
RBIMPL_ATTR_ARTIFICIAL()
/**
* Queries the contents pointer of the string.
@@ -417,9 +499,13 @@ RSTRING_PTR(VALUE str)
{
char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr;
- if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) {
+ if (RB_UNLIKELY(! ptr)) {
/* :BEWARE: @shyouhei thinks that currently, there are rooms for this
- * function to return NULL. Better check here for maximum safety.
+ * function to return NULL. In the 20th century that was a pointless
+ * concern. However struct RString can hold fake strings nowadays. It
+ * seems no check against NULL are exercised around handling of them
+ * (one of such usages is located in marshal.c, which scares
+ * @shyouhei). Better check here for maximum safety.
*
* Also, this is not rb_warn() because RSTRING_PTR() can be called
* during GC (see what obj_info() does). rb_warn() needs to allocate
@@ -443,12 +529,12 @@ RSTRING_END(VALUE str)
{
struct RString buf = rbimpl_rstring_getmem(str);
- if (RUBY_DEBUG && RB_UNLIKELY(! buf.as.heap.ptr)) {
+ if (RB_UNLIKELY(! buf.as.heap.ptr)) {
/* Ditto. */
rb_debug_rstring_null_ptr("RSTRING_END");
}
- return &buf.as.heap.ptr[buf.len];
+ return &buf.as.heap.ptr[buf.as.heap.len];
}
RBIMPL_ATTR_ARTIFICIAL()
@@ -482,7 +568,7 @@ RSTRING_LENINT(VALUE str)
__extension__ ({ \
struct RString rbimpl_str = rbimpl_rstring_getmem(str); \
(ptrvar) = rbimpl_str.as.heap.ptr; \
- (lenvar) = rbimpl_str.len; \
+ (lenvar) = rbimpl_str.as.heap.len; \
})
#else
# define RSTRING_GETMEM(str, ptrvar, lenvar) \
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h
index 6c19576c20..bbf208867d 100644
--- a/include/ruby/internal/core/rtypeddata.h
+++ b/include/ruby/internal/core/rtypeddata.h
@@ -114,8 +114,6 @@
#define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1
/** @endcond */
-#define TYPED_DATA_EMBEDDED 2
-
/**
* @private
*
@@ -139,8 +137,6 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FREE_IMMEDIATELY = 1,
- RUBY_TYPED_EMBEDDABLE = 2,
-
/**
* This flag has something to do with Ractor. Multiple Ractors run without
* protecting each other. Sharing an object among Ractors is basically
@@ -177,16 +173,10 @@ rbimpl_typeddata_flags {
RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
/**
- * This flag no longer in use
+ * This flag is mysterious. It seems nobody is currently using it. The
+ * intention of this flag is also unclear. We need further investigations.
*/
- RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6,
-
- /**
- * This flag determines whether marking and compaction should be carried out
- * using the dmark/dcompact callback functions or whether we should mark
- * declaratively using a list of references defined inside the data struct we're wrapping
- */
- RUBY_TYPED_DECL_MARKING = RUBY_FL_USER2
+ RUBY_TYPED_PROMOTED1 = RUBY_FL_PROMOTED1 /* THIS FLAG DEPENDS ON Ruby version */
};
/**
@@ -357,14 +347,16 @@ struct RTypedData {
* data. This roughly resembles a Ruby level class (apart from method
* definition etc.)
*/
- const rb_data_type_t *const type;
+ const rb_data_type_t *type;
/**
* This has to be always 1.
*
* @internal
+ *
+ * Why, then, this is not a const ::VALUE?
*/
- const VALUE typed_flag;
+ VALUE typed_flag;
/** Pointer to the actual C level struct that you want to wrap. */
void *data;
@@ -464,7 +456,7 @@ RBIMPL_SYMBOL_EXPORT_END()
*/
#define TypedData_Make_Struct0(result, klass, type, size, data_type, sval) \
VALUE result = rb_data_typed_object_zalloc(klass, size, data_type); \
- (sval) = (type *)RTYPEDDATA_GET_DATA(result); \
+ (sval) = RBIMPL_CAST((type *)RTYPEDDATA_DATA(result)); \
RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
/**
@@ -515,36 +507,6 @@ RBIMPL_SYMBOL_EXPORT_END()
#define TypedData_Get_Struct(obj,type,data_type,sval) \
((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type))))
-static inline bool
-RTYPEDDATA_EMBEDDED_P(VALUE obj)
-{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) {
- Check_Type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(false);
- }
-#endif
-
- return RTYPEDDATA(obj)->typed_flag & TYPED_DATA_EMBEDDED;
-}
-
-static inline void *
-RTYPEDDATA_GET_DATA(VALUE obj)
-{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) {
- Check_Type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(false);
- }
-#endif
-
- /* We reuse the data pointer in embedded TypedData. We can't use offsetof
- * since RTypedData a non-POD type in C++. */
- const size_t embedded_typed_data_size = sizeof(struct RTypedData) - sizeof(void *);
-
- return RTYPEDDATA_EMBEDDED_P(obj) ? (char *)obj + embedded_typed_data_size : RTYPEDDATA(obj)->data;
-}
-
RBIMPL_ATTR_PURE()
RBIMPL_ATTR_ARTIFICIAL()
/**
@@ -561,8 +523,7 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline bool
rbimpl_rtypeddata_p(VALUE obj)
{
- VALUE typed_flag = RTYPEDDATA(obj)->typed_flag;
- return typed_flag != 0 && typed_flag <= 3;
+ return RTYPEDDATA(obj)->typed_flag == 1;
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
diff --git a/include/ruby/internal/dllexport.h b/include/ruby/internal/dllexport.h
index 71026e7100..08a262209d 100644
--- a/include/ruby/internal/dllexport.h
+++ b/include/ruby/internal/dllexport.h
@@ -37,7 +37,9 @@
* ```
*/
#undef RUBY_EXTERN
-#if defined(RUBY_EXPORT)
+#if defined(MJIT_HEADER) && defined(_WIN32)
+# define RUBY_EXTERN extern __declspec(dllimport)
+#elif defined(RUBY_EXPORT)
# define RUBY_EXTERN extern
#elif defined(_WIN32)
# define RUBY_EXTERN extern __declspec(dllimport)
@@ -57,6 +59,36 @@
# define RUBY_FUNC_EXPORTED /* void */
#endif
+/**
+ * @cond INTERNAL_MACRO
+ *
+ * These MJIT related macros are placed here because translate_mjit_header can
+ * need them. Extension libraries should not touch.
+ */
+
+/* These macros are used for functions which are exported only for MJIT
+ and NOT ensured to be exported in future versions. */
+
+#if ! defined(MJIT_HEADER)
+# define MJIT_FUNC_EXPORTED RUBY_FUNC_EXPORTED
+#elif ! RBIMPL_COMPILER_IS(MSVC)
+# define MJIT_FUNC_EXPORTED RUBY_FUNC_EXPORTED
+#else
+# define MJIT_FUNC_EXPORTED static
+#endif
+
+#define MJIT_SYMBOL_EXPORT_BEGIN RUBY_SYMBOL_EXPORT_BEGIN
+#define MJIT_SYMBOL_EXPORT_END RUBY_SYMBOL_EXPORT_END
+
+/* On mswin, MJIT header transformation can't be used since cl.exe can't output
+ preprocessed output preserving macros. So this `MJIT_STATIC` is needed
+ to force non-static function to static on MJIT header to avoid symbol conflict. */
+#ifdef MJIT_HEADER
+# define MJIT_STATIC static
+#else
+# define MJIT_STATIC
+#endif
+
/** @endcond */
/** Shortcut macro equivalent to `RUBY_SYMBOL_EXPORT_BEGIN extern "C" {`.
diff --git a/include/ruby/internal/encoding/encoding.h b/include/ruby/internal/encoding/encoding.h
index dc3e0151f0..4748ca806b 100644
--- a/include/ruby/internal/encoding/encoding.h
+++ b/include/ruby/internal/encoding/encoding.h
@@ -139,6 +139,23 @@ RBIMPL_ATTR_NOALIAS()
int rb_char_to_option_kcode(int c, int *option, int *kcode);
/**
+ * Creates a new encoding, using the passed one as a template.
+ *
+ * @param[in] name Name of the creating encoding.
+ * @param[in] src Template.
+ * @exception rb_eArgError Duplicated or malformed `name`.
+ * @return Replicated new encoding's index.
+ * @post Encoding named `name` is created as a copy of `src`, whose index
+ * is the return value.
+ *
+ * @internal
+ *
+ * `name` can be `NULL`, but that just raises an exception. OTOH it seems no
+ * sanity check is done against `src`...?
+ */
+int rb_enc_replicate(const char *name, rb_encoding *src);
+
+/**
* Creates a new "dummy" encoding. Roughly speaking, an encoding is dummy when
* it is stateful. Notable example of dummy encoding are those defined in
* ISO/IEC 2022
diff --git a/include/ruby/internal/encoding/string.h b/include/ruby/internal/encoding/string.h
index 2b9dfe4f31..6ed7ca1c90 100644
--- a/include/ruby/internal/encoding/string.h
+++ b/include/ruby/internal/encoding/string.h
@@ -30,7 +30,7 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
- * Identical to rb_str_new(), except it additionally takes an encoding.
+ * Identical to rb_enc_str_new(), except it additionally takes an encoding.
*
* @param[in] ptr A memory region of `len` bytes length.
* @param[in] len Length of `ptr`, in bytes, not including the
diff --git a/include/ruby/internal/error.h b/include/ruby/internal/error.h
index cd37f4461a..49e2276cb9 100644
--- a/include/ruby/internal/error.h
+++ b/include/ruby/internal/error.h
@@ -50,19 +50,7 @@ typedef enum {
/** Warning is for experimental features. */
RB_WARN_CATEGORY_EXPERIMENTAL,
- /** Warning is for performance issues (not enabled by -w). */
- RB_WARN_CATEGORY_PERFORMANCE,
-
- RB_WARN_CATEGORY_DEFAULT_BITS = (
- (1U << RB_WARN_CATEGORY_DEPRECATED) |
- (1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
- 0),
-
- RB_WARN_CATEGORY_ALL_BITS = (
- (1U << RB_WARN_CATEGORY_DEPRECATED) |
- (1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
- (1U << RB_WARN_CATEGORY_PERFORMANCE) |
- 0)
+ RB_WARN_CATEGORY_ALL_BITS = 0x6 /* no RB_WARN_CATEGORY_NONE bit */
} rb_warning_category_t;
/** for rb_readwrite_sys_fail first argument */
@@ -481,7 +469,7 @@ VALUE *rb_ruby_debug_ptr(void);
*/
#define ruby_debug (*rb_ruby_debug_ptr())
-/* reports if $VERBOSE is true */
+/* reports if `-W' specified */
RBIMPL_ATTR_NONNULL((1))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
/**
@@ -496,8 +484,7 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
* default, the method just emits its passed contents to ::rb_stderr using
* rb_io_write().
*
- * @note This function is affected by the value of $VERBOSE, it does
- * nothing unless $VERBOSE is true.
+ * @note This function is affected by the `-W` flag.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*
* @internal
@@ -522,7 +509,7 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
* Issues a compile-time warning that happens at `__file__:__line__`. Purpose
* of this function being exposed to CAPI is unclear.
*
- * @note This function is affected by the value of $VERBOSE.
+ * @note This function is affected by the `-W` flag.
* @param[in] file The path corresponding to Ruby level `__FILE__`.
* @param[in] line The number corresponding to Ruby level `__LINE__`.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
@@ -535,20 +522,19 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
* Identical to rb_sys_fail(), except it does not raise an exception to render
* a warning instead.
*
- * @note This function is affected by the value of $VERBOSE.
+ * @note This function is affected by the `-W` flag.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*/
void rb_sys_warning(const char *fmt, ...);
-/* reports if $VERBOSE is not nil (so if it is true or false) */
+/* reports always */
RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NONNULL((1))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
/**
- * Identical to rb_warning(), except it reports unless $VERBOSE is nil.
+ * Identical to rb_warning(), except it reports always regardless of runtime
+ * `-W` flag.
*
- * @note This function is affected by the value of $VERBOSE, it does
- * nothing if $VERBOSE is nil.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*/
void rb_warn(const char *fmt, ...);
@@ -557,7 +543,8 @@ RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NONNULL((2))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
/**
- * Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
+ * Identical to rb_category_warning(), except it reports always regardless of
+ * runtime `-W` flag.
*
* @param[in] cat Category e.g. deprecated.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
@@ -567,7 +554,8 @@ void rb_category_warn(rb_warning_category_t cat, const char *fmt, ...);
RBIMPL_ATTR_NONNULL((1, 3))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
/**
- * Identical to rb_compile_warning(), except it reports unless $VERBOSE is nil.
+ * Identical to rb_compile_warning(), except it reports always regardless of
+ * runtime `-W` flag.
*
* @param[in] file The path corresponding to Ruby level `__FILE__`.
* @param[in] line The number corresponding to Ruby level `__LINE__`.
diff --git a/include/ruby/internal/event.h b/include/ruby/internal/event.h
index 1d194ed618..04b137a193 100644
--- a/include/ruby/internal/event.h
+++ b/include/ruby/internal/event.h
@@ -23,10 +23,6 @@
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
/* These macros are not enums because they are wider than int.*/
/**
@@ -58,7 +54,6 @@
#define RUBY_EVENT_THREAD_END 0x0800 /**< Encountered an end of a thread. */
#define RUBY_EVENT_FIBER_SWITCH 0x1000 /**< Encountered a `Fiber#yield`. */
#define RUBY_EVENT_SCRIPT_COMPILED 0x2000 /**< Encountered an `eval`. */
-#define RUBY_EVENT_RESCUE 0x4000 /**< Encountered a `rescue` statement. */
#define RUBY_EVENT_TRACEPOINT_ALL 0xffff /**< Bitmask of extended events. */
/** @} */
diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h
index f7f5abdd9b..7383426b23 100644
--- a/include/ruby/internal/fl_type.h
+++ b/include/ruby/internal/fl_type.h
@@ -57,7 +57,8 @@
#define FL_SINGLETON RBIMPL_CAST((VALUE)RUBY_FL_SINGLETON) /**< @old{RUBY_FL_SINGLETON} */
#define FL_WB_PROTECTED RBIMPL_CAST((VALUE)RUBY_FL_WB_PROTECTED) /**< @old{RUBY_FL_WB_PROTECTED} */
-#define FL_PROMOTED RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED) /**< @old{RUBY_FL_PROMOTED} */
+#define FL_PROMOTED0 RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED0) /**< @old{RUBY_FL_PROMOTED0} */
+#define FL_PROMOTED1 RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED1) /**< @old{RUBY_FL_PROMOTED1} */
#define FL_FINALIZE RBIMPL_CAST((VALUE)RUBY_FL_FINALIZE) /**< @old{RUBY_FL_FINALIZE} */
#define FL_TAINT RBIMPL_CAST((VALUE)RUBY_FL_TAINT) /**< @old{RUBY_FL_TAINT} */
#define FL_SHAREABLE RBIMPL_CAST((VALUE)RUBY_FL_SHAREABLE) /**< @old{RUBY_FL_SHAREABLE} */
@@ -110,6 +111,13 @@
#define RB_OBJ_FREEZE_RAW RB_OBJ_FREEZE_RAW
#define RB_OBJ_FROZEN RB_OBJ_FROZEN
#define RB_OBJ_FROZEN_RAW RB_OBJ_FROZEN_RAW
+#define RB_OBJ_INFECT RB_OBJ_INFECT
+#define RB_OBJ_INFECT_RAW RB_OBJ_INFECT_RAW
+#define RB_OBJ_TAINT RB_OBJ_TAINT
+#define RB_OBJ_TAINTABLE RB_OBJ_TAINTABLE
+#define RB_OBJ_TAINTED RB_OBJ_TAINTED
+#define RB_OBJ_TAINTED_RAW RB_OBJ_TAINTED_RAW
+#define RB_OBJ_TAINT_RAW RB_OBJ_TAINT_RAW
#define RB_OBJ_UNTRUST RB_OBJ_TAINT
#define RB_OBJ_UNTRUSTED RB_OBJ_TAINTED
/** @endcond */
@@ -199,15 +207,12 @@ ruby_fl_type {
RUBY_FL_WB_PROTECTED = (1<<5),
/**
- * Ruby objects are "generational". There are young objects & old objects.
- * Young objects are prone to die & monitored relatively extensively by the
- * garbage collector. Old objects tend to live longer & are monitored less
- * frequently. When an object survives a GC, its age is incremented. When
- * age is equal to RVALUE_OLD_AGE, the object becomes Old. This flag is set
- * when an object becomes old, and is used by the write barrier to check if
- * an old object should be considered for marking more frequently - as old
- * objects that have references added between major GCs need to be remarked
- * to prevent the referred object being mistakenly swept.
+ * This flag has something to do with our garbage collector. These days
+ * ruby objects are "generational". There are those who are young and
+ * those who are old. Young objects are prone to die; monitored relatively
+ * extensively by the garbage collector. OTOH old objects tend to live
+ * longer. They are relatively rarely considered. This flag is set when a
+ * object experienced promotion i.e. survived a garbage collection.
*
* @internal
*
@@ -215,14 +220,41 @@ ruby_fl_type {
* 3rd parties. It must be an implementation detail that they should never
* know. Might better be hidden.
*/
- RUBY_FL_PROMOTED = (1<<5),
+ RUBY_FL_PROMOTED0 = (1<<5),
/**
- * This flag is no longer in use
+ * This flag has something to do with our garbage collector. These days
+ * ruby objects are "generational". There are those who are young and
+ * those who are old. Young objects are prone to die; monitored relatively
+ * extensively by the garbage collector. OTOH old objects tend to live
+ * longer. They are relatively rarely considered. This flag is set when a
+ * object experienced two promotions i.e. survived garbage collections
+ * twice.
*
* @internal
+ *
+ * But honestly, @shyouhei doesn't think this flag should be visible from
+ * 3rd parties. It must be an implementation detail that they should never
+ * know. Might better be hidden.
+ */
+ RUBY_FL_PROMOTED1 = (1<<6),
+
+ /**
+ * This flag has something to do with our garbage collector. These days
+ * ruby objects are "generational". There are those who are young and
+ * those who are old. Young objects are prone to die; monitored relatively
+ * extensively by the garbage collector. OTOH old objects tend to live
+ * longer. They are relatively rarely considered. This flag is set when a
+ * object experienced promotions i.e. survived more than one garbage
+ * collections.
+ *
+ * @internal
+ *
+ * But honestly, @shyouhei doesn't think this flag should be visible from
+ * 3rd parties. It must be an implementation detail that they should never
+ * know. Might better be hidden.
*/
- RUBY_FL_UNUSED6 = (1<<6),
+ RUBY_FL_PROMOTED = RUBY_FL_PROMOTED0 | RUBY_FL_PROMOTED1,
/**
* This flag has something to do with finalisers. A ruby object can have
@@ -251,7 +283,7 @@ ruby_fl_type {
# pragma deprecated(RUBY_FL_TAINT)
#endif
- = 0,
+ = (1<<8),
/**
* This flag has something to do with Ractor. Multiple Ractors run without
@@ -278,7 +310,7 @@ ruby_fl_type {
# pragma deprecated(RUBY_FL_UNTRUSTED)
#endif
- = 0,
+ = (1<<8),
/**
* This flag has something to do with object IDs. Unlike in the old days,
@@ -755,7 +787,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline bool
RB_OBJ_TAINTABLE(VALUE obj)
{
- (void)obj;
return false;
}
@@ -773,7 +804,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline VALUE
RB_OBJ_TAINTED_RAW(VALUE obj)
{
- (void)obj;
return false;
}
@@ -791,7 +821,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline bool
RB_OBJ_TAINTED(VALUE obj)
{
- (void)obj;
return false;
}
@@ -807,7 +836,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_TAINT_RAW(VALUE obj)
{
- (void)obj;
return;
}
@@ -823,7 +851,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_TAINT(VALUE obj)
{
- (void)obj;
return;
}
@@ -840,8 +867,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_INFECT_RAW(VALUE dst, VALUE src)
{
- (void)dst;
- (void)src;
return;
}
@@ -858,8 +883,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_INFECT(VALUE dst, VALUE src)
{
- (void)dst;
- (void)src;
return;
}
diff --git a/include/ruby/internal/gc.h b/include/ruby/internal/gc.h
index 2a5180671c..054e4b0f9c 100644
--- a/include/ruby/internal/gc.h
+++ b/include/ruby/internal/gc.h
@@ -20,384 +20,11 @@
* extension libraries. They could be written in C++98.
* @brief Registering values to the GC.
*/
-#include "ruby/internal/config.h"
-
-#ifdef STDC_HEADERS
-# include <stddef.h> /* size_t */
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h> /* ssize_t */
-#endif
-
-#include "ruby/assert.h"
-#include "ruby/internal/attr/cold.h"
-#include "ruby/internal/attr/nonnull.h"
-#include "ruby/internal/attr/noreturn.h"
-#include "ruby/internal/attr/artificial.h"
-#include "ruby/internal/attr/maybe_unused.h"
-#include "ruby/internal/attr/pure.h"
#include "ruby/internal/dllexport.h"
-#include "ruby/internal/special_consts.h"
-#include "ruby/internal/stdbool.h"
#include "ruby/internal/value.h"
RBIMPL_SYMBOL_EXPORT_BEGIN()
-#define REF_EDGE(s, p) (offsetof(struct s, p))
-#define REFS_LIST_PTR(l) ((RUBY_DATA_FUNC)l)
-#define RUBY_REF_END SIZE_MAX
-#define RUBY_REFERENCES_START(t) static size_t t[] = {
-#define RUBY_REFERENCES_END RUBY_REF_END, };
-
-/* gc.c */
-
-RBIMPL_ATTR_COLD()
-RBIMPL_ATTR_NORETURN()
-/**
- * Triggers out-of-memory error. If possible it raises ::rb_eNoMemError. But
- * because we are running out of memory that is not always doable. This
- * function tries hard to show something, but ultimately can die silently.
- *
- * @exception rb_eNoMemError Raises it if possible.
- */
-void rb_memerror(void);
-
-RBIMPL_ATTR_PURE()
-/**
- * Queries if the GC is busy.
- *
- * @retval 0 It isn't.
- * @retval 1 It is.
- */
-int rb_during_gc(void);
-
-RBIMPL_ATTR_NONNULL((1))
-/**
- * Marks objects between the two pointers. This is one of the GC utility
- * functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @pre Continuous memory region from `start` to `end` shall be fully
- * addressable.
- * @param[out] start Pointer to an array of objects.
- * @param[out] end Pointer that terminates the array of objects.
- * @post Objects from `start` (included) to `end` (excluded) are marked.
- *
- * @internal
- *
- * `end` can be NULL... But that just results in no-op.
- */
-void rb_gc_mark_locations(const VALUE *start, const VALUE *end);
-
-/**
- * Identical to rb_mark_hash(), except it marks only values of the table and
- * leave their associated keys unmarked. This is one of the GC utility
- * functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @warning Of course it can break GC. Leave it unused if unsure.
- * @param[in] tbl A table to mark.
- * @post Values stored in `tbl` are marked.
- */
-void rb_mark_tbl(struct st_table *tbl);
-
-/**
- * Identical to rb_mark_tbl(), except it marks objects using
- * rb_gc_mark_movable(). This is one of the GC utility functions that you can
- * call when you design your own ::rb_data_type_struct::dmark.
- *
- * @warning Of course it can break GC. Leave it unused if unsure.
- * @param[in] tbl A table to mark.
- * @post Values stored in `tbl` are marked.
- */
-void rb_mark_tbl_no_pin(struct st_table *tbl);
-
-/**
- * Identical to rb_mark_hash(), except it marks only keys of the table and
- * leave their associated values unmarked. This is one of the GC utility
- * functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @warning Of course it can break GC. Leave it unused if unsure.
- * @param[in] tbl A table to mark.
- * @post Keys stored in `tbl` are marked.
- */
-void rb_mark_set(struct st_table *tbl);
-
-/**
- * Marks keys and values associated inside of the given table. This is one of
- * the GC utility functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @param[in] tbl A table to mark.
- * @post Objects stored in `tbl` are marked.
- */
-void rb_mark_hash(struct st_table *tbl);
-
-/**
- * Updates references inside of tables. After you marked values using
- * rb_mark_tbl_no_pin(), the objects inside of the table could of course be
- * moved. This function is to fixup those references. You can call this from
- * your ::rb_data_type_struct::dcompact.
- *
- * @param[out] ptr A table that potentially includes moved references.
- * @post Moved references, if any, are corrected.
- */
-void rb_gc_update_tbl_refs(st_table *ptr);
-
-/**
- * Identical to rb_gc_mark(), except it allows the passed value be a
- * non-object. For instance pointers to different type of memory regions are
- * allowed here. Such values are silently ignored. This is one of the GC
- * utility functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @param[out] obj A possible object.
- * @post `obj` is marked, if possible.
- */
-void rb_gc_mark_maybe(VALUE obj);
-
-/**
- * Marks an object. This is one of the GC utility functions that you can call
- * when you design your own ::rb_data_type_struct::dmark.
- *
- * @param[out] obj Arbitrary Ruby object.
- * @post `obj` is marked.
- */
-void rb_gc_mark(VALUE obj);
-
-/**
- * Maybe this is the only function provided for C extensions to control the
- * pinning of objects, so let us describe it in detail. These days Ruby's GC
- * is copying. As far as an object's physical address is guaranteed unused, it
- * can move around the object space. Our GC engine rearranges these objects
- * after it reclaims unreachable objects from our object space, so that the
- * space is compact (improves memory locality). This is called the
- * "compaction" phase, and works well most of the time... as far as there are
- * no C extensions. C extensions complicate the scenario because Ruby core
- * cannot detect any use of the physical address of an object inside of C
- * functions. In order to prevent memory corruptions, objects observable from
- * C extensions are "pinned"; they stick to where they are born until they die,
- * just in case any C extensions touch their raw pointers. This variant of
- * scheme is called "Mostly-Copying" garbage collector. Authors of C
- * extensions, however, can extremely carefully write them to become
- * compaction-aware. To do so avoid referring to a Ruby object from inside of
- * your struct in the first place. But if that is not possible, use this
- * function from your ::rb_data_type_struct::dmark then. This way objects
- * marked using it are considered movable. If you chose this way you have to
- * manually fix up locations of such moved pointers using rb_gc_location().
- *
- * @see Bartlett, Joel F., "Compacting Garbage Collection with Ambiguous
- * Roots", ACM SIGPLAN Lisp Pointers Volume 1 Issue 6 pp. 3-12,
- * April-May-June, 1988. https://doi.org/10.1145/1317224.1317225
- *
- * @param[in] obj Object that is movable.
- * @post Values stored in `tbl` are marked.
- */
-void rb_gc_mark_movable(VALUE obj);
-
-/**
- * Finds a new "location" of an object. An object can be moved on compaction.
- * This function projects its new abode, or just returns the passed object if
- * not moved. This is one of the GC utility functions that you can call when
- * you design your own ::rb_data_type_struct::dcompact.
- *
- * @param[in] obj An object, possibly already moved to somewhere else.
- * @return An object, which holds the current contents of former `obj`.
- */
-VALUE rb_gc_location(VALUE obj);
-
-/**
- * Asserts that the passed object is no longer needed. Such objects are
- * reclaimed sooner or later so this function is not mandatory. But sometimes
- * you can know from your application knowledge that an object is surely dead
- * at some point. Calling this as a hint can be a polite way.
- *
- * @param[out] obj Object, dead.
- * @pre `obj` have never been passed to this function before.
- * @post `obj` could be invalidated.
- * @warning It is a failure to pass an object multiple times to this
- * function.
- * @deprecated This is now a no-op function.
- */
-RBIMPL_ATTR_DEPRECATED(("this is now a no-op function"))
-void rb_gc_force_recycle(VALUE obj);
-
-/**
- * Triggers a GC process. This was the only GC entry point that we had at the
- * beginning. Over time our GC evolved. Now what this function does is just a
- * very simplified variation of the entire GC algorithms. A series of
- * procedures kicked by this API is called a "full" GC.
- *
- * - It immediately scans the entire object space to sort the dead.
- * - It immediately reclaims any single dead bodies to reuse later.
- *
- * It is worth noting that the procedures above do not include evaluations of
- * finalisers. They run later.
- *
- * @internal
- *
- * Finalisers are deferred until we can handle interrupts. See
- * `rb_postponed_job_flush` in vm_trace.c.
- *
- * Of course there are GC that are not "full". For instance this one and the
- * GC which runs when we are running out of memory are different. See
- * `gc_profile_record_flag` defined in gc.c for the kinds of GC.
- *
- * In spite of the name this is not what everything that a GC can trigger. As
- * of writing it seems this function does not trigger compaction. But this
- * might change in future.
- */
-void rb_gc(void);
-
-/**
- * Copy&paste an object's finaliser to another. This is one of the GC utility
- * functions that you can call when you design your own `initialize_copy`,
- * `initialize_dup`, `initialize_clone`.
- *
- * @param[out] dst Destination object.
- * @param[in] src Source object.
- * @post `dst` and `src` share the same finaliser.
- *
- * @internal
- *
- * But isn't it easier for you to call super, and let `Object#initialize_copy`
- * call this function instead?
- */
-void rb_gc_copy_finalizer(VALUE dst, VALUE src);
-
-/**
- * (Re-) enables GC. This makes sense only after you called rb_gc_disable().
- *
- * @retval RUBY_Qtrue GC was disabled before.
- * @retval RUBY_Qfalse GC was enabled before.
- * @post GC is enabled.
- *
- * @internal
- *
- * This is one of such exceptional functions that does not raise both Ruby
- * exceptions and C++ exceptions.
- */
-VALUE rb_gc_enable(void);
-
-/**
- * Disables GC. This prevents automatic GC runs when the process is running
- * out of memory. Such situations shall result in rb_memerror(). However this
- * does not prevent users from manually invoking rb_gc(). That should work.
- * People abused this by disabling GC at the beginning of an event loop,
- * process events without GC overheads, then manually force reclaiming garbage
- * at the bottom of the loop. However because our GC is now much smarter than
- * just calling rb_gc(), this technique is proven to be sub-optimal these days.
- * It is believed that there is currently practically no needs of this
- * function.
- *
- * @retval RUBY_Qtrue GC was disabled before.
- * @retval RUBY_Qfalse GC was enabled before.
- * @post GC is disabled.
- */
-VALUE rb_gc_disable(void);
-
-/**
- * Identical to rb_gc(), except the return value.
- *
- * @return Always returns ::RUBY_Qnil.
- */
-VALUE rb_gc_start(void);
-
-/**
- * Assigns a finaliser for an object. Each objects can have objects (typically
- * blocks) that run immediately after that object dies. They are called
- * finalisers of an object. This function associates a finaliser object with a
- * target object.
- *
- * @note Note that finalisers run _after_ the object they finalise dies. You
- * cannot for instance call its methods.
- * @note If your finaliser references the object it finalises that object
- * loses any chance to become a garbage; effectively leaks memory until
- * the end of the process.
- *
- * @param[in] obj Target to finalise.
- * @param[in] block Something `call`able.
- * @exception rb_eRuntimeError Somehow `obj` cannot have finalisers.
- * @exception rb_eFrozenError `obj` is frozen.
- * @exception rb_eArgError `block` doesn't respond to `call`.
- * @return The passed `block`.
- * @post `block` runs after `obj` dies.
- */
-VALUE rb_define_finalizer(VALUE obj, VALUE block);
-
-/**
- * Modifies the object so that it has no finalisers at all. This function is
- * mainly provided for symmetry. No practical usages can be thought of.
- *
- * @param[out] obj Object to clear its finalisers.
- * @exception rb_eFrozenError `obj` is frozen.
- * @return The passed `obj`.
- * @post `obj` has no finalisers.
- * @note There is no way to undefine a specific part of many finalisers
- * that `obj` could have. All you can do is to clear them all.
- */
-VALUE rb_undefine_finalizer(VALUE obj);
-
-/**
- * Identical to rb_gc_stat(), with "count" parameter.
- *
- * @return Lifetime total number of runs of GC.
- */
-size_t rb_gc_count(void);
-
-/**
- * Obtains various GC related profiles. The parameter can be either a Symbol
- * or a Hash. If a Hash is passed, it is filled with everything currently
- * available. If a Symbol is passed just that portion is returned.
- *
- * Possible variations of keys you can pass here change from version to
- * version. You can get the list of known keys by passing an empty hash and
- * let it be filled.
- *
- * @param[in,out] key_or_buf A Symbol, or a Hash.
- * @exception rb_eTypeError Neither Symbol nor Hash.
- * @exception rb_eFrozenError Frozen hash is passed.
- * @return In case a Hash is passed it returns 0. Otherwise the
- * profile value associated with the given key is returned.
- * @post In case a Hash is passed it is filled with values.
- */
-size_t rb_gc_stat(VALUE key_or_buf);
-
-/**
- * Obtains various info regarding the most recent GC run. This includes for
- * instance the reason of the GC. The parameter can be either a Symbol or a
- * Hash. If a Hash is passed, it is filled with everything currently
- * available. If a Symbol is passed just that portion is returned.
- *
- * Possible variations of keys you can pass here change from version to
- * version. You can get the list of known keys by passing an empty hash and
- * let it be filled.
- *
- * @param[in,out] key_or_buf A Symbol, or a Hash.
- * @exception rb_eTypeError Neither Symbol nor Hash.
- * @exception rb_eFrozenError Frozen hash is passed.
- * @return In case a Hash is passed it returns that hash. Otherwise
- * the profile value associated with the given key is returned.
- * @post In case a Hash is passed it is filled with values.
- */
-VALUE rb_gc_latest_gc_info(VALUE key_or_buf);
-
-/**
- * Informs that there are external memory usages. Our GC runs when we are
- * running out of memory. The amount of memory, however, can increase/decrease
- * behind-the-scene. For instance DLLs can allocate memories using `mmap(2)`
- * etc, which are opaque to us. Registering such external allocations using
- * this function enables proper detection of how much memories an object used
- * as a whole. That will trigger GCs more often than it would otherwise. You
- * can also pass negative numbers here, to indicate that such external
- * allocations are gone.
- *
- * @param[in] diff Amount of memory increased(+)/decreased(-).
- */
-void rb_gc_adjust_memory_usage(ssize_t diff);
-
/**
* Inform the garbage collector that the global or static variable pointed by
* `valptr` stores a live Ruby object that should not be moved. Note that
@@ -432,410 +59,4 @@ void rb_gc_register_mark_object(VALUE object);
RBIMPL_SYMBOL_EXPORT_END()
-/**
- * @private
- *
- * @deprecated This macro once was a thing in the old days, but makes no sense
- * any longer today. Exists here for backwards compatibility
- * only. You can safely forget about it.
- */
-#undef USE_RGENGC
-#define USE_RGENGC 1
-
-/**
- * @deprecated This macro seems broken. Setting this to anything other than
- * zero just doesn't compile. We need to KonMari.
- */
-#ifndef USE_RGENGC_LOGGING_WB_UNPROTECT
-# define USE_RGENGC_LOGGING_WB_UNPROTECT 0
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RArray. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_ARRAY
-# define RGENGC_WB_PROTECTED_ARRAY 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RHash. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_HASH
-# define RGENGC_WB_PROTECTED_HASH 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RStruct. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_STRUCT
-# define RGENGC_WB_PROTECTED_STRUCT 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RString. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_STRING
-# define RGENGC_WB_PROTECTED_STRING 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RObject. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_OBJECT
-# define RGENGC_WB_PROTECTED_OBJECT 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RRegexp. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_REGEXP
-# define RGENGC_WB_PROTECTED_REGEXP 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RMatch. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_MATCH
-# define RGENGC_WB_PROTECTED_MATCH 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RClass. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_CLASS
-# define RGENGC_WB_PROTECTED_CLASS 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RFloat. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_FLOAT
-# define RGENGC_WB_PROTECTED_FLOAT 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RComplex. It has to be set at the time ruby itself compiles.
- * Makes no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_COMPLEX
-# define RGENGC_WB_PROTECTED_COMPLEX 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RRational. It has to be set at the time ruby itself compiles.
- * Makes no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_RATIONAL
-# define RGENGC_WB_PROTECTED_RATIONAL 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RBignum. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_BIGNUM
-# define RGENGC_WB_PROTECTED_BIGNUM 1
-#endif
-
-/**
- * @private
- *
- * @deprecated This macro once was a thing in the old days, but makes no sense
- * any longer today. Exists here for backwards compatibility
- * only. You can safely forget about it.
- *
- * @internal
- *
- * @shyouhei doesn't think anybody uses this right now.
- */
-#ifndef RGENGC_WB_PROTECTED_NODE_CREF
-# define RGENGC_WB_PROTECTED_NODE_CREF 1
-#endif
-
-/**
- * @defgroup rgengc Write barrier (WB) interfaces:
- *
- * @note The following core interfaces can be changed in the future. Please
- * catch up if you want to insert WB into C-extensions correctly.
- *
- * @{
- */
-
-/**
- * Declaration of a "back" pointer. This is a write barrier for new reference
- * from "old" generation to "young" generation. It writes `young` into
- * `*slot`, which is a pointer inside of `old`.
- *
- * @param[in] old An old object.
- * @param[in] slot A pointer inside of `old`.
- * @param[out] young A young object.
- */
-#define RB_OBJ_WRITE(old, slot, young) \
- RBIMPL_CAST(rb_obj_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young), __FILE__, __LINE__))
-
-/**
- * Identical to #RB_OBJ_WRITE(), except it doesn't write any values, but only a
- * WB declaration. `oldv` is replaced value with `b` (not used in current
- * Ruby).
- *
- * @param[in] old An old object.
- * @param[in] oldv An object previously stored inside of `old`.
- * @param[out] young A young object.
- */
-#define RB_OBJ_WRITTEN(old, oldv, young) \
- RBIMPL_CAST(rb_obj_written((VALUE)(old), (VALUE)(oldv), (VALUE)(young), __FILE__, __LINE__))
-/** @} */
-
-#define OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW /**< @old{RB_OBJ_PROMOTED_RAW} */
-#define OBJ_PROMOTED RB_OBJ_PROMOTED /**< @old{RB_OBJ_PROMOTED} */
-#define OBJ_WB_UNPROTECT RB_OBJ_WB_UNPROTECT /**< @old{RB_OBJ_WB_UNPROTECT} */
-
-/**
- * Asserts that the passed object is not fenced by write barriers. Objects of
- * such property do not contribute to generational GCs. They are scanned
- * always.
- *
- * @param[out] x An object that would not be protected by the barrier.
- */
-#define RB_OBJ_WB_UNPROTECT(x) rb_obj_wb_unprotect(x, __FILE__, __LINE__)
-
-/**
- * Identical to #RB_OBJ_WB_UNPROTECT(), except it can also assert that the
- * given object is of given type.
- *
- * @param[in] type One of `ARRAY`, `STRING`, etc.
- * @param[out] obj An object of `type` that would not be protected.
- *
- * @internal
- *
- * @shyouhei doesn't understand why this has to be visible from extensions.
- */
-#define RB_OBJ_WB_UNPROTECT_FOR(type, obj) \
- (RGENGC_WB_PROTECTED_##type ? OBJ_WB_UNPROTECT(obj) : obj)
-
-/**
- * @private
- *
- * This is an implementation detail of rb_obj_wb_unprotect(). People don't use
- * it directly.
- */
-#define RGENGC_LOGGING_WB_UNPROTECT rb_gc_unprotect_logging
-
-/** @cond INTERNAL_MACRO */
-#define RB_OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW
-#define RB_OBJ_PROMOTED RB_OBJ_PROMOTED
-/** @endcond */
-
-RBIMPL_SYMBOL_EXPORT_BEGIN()
-/**
- * This is the implementation of #RB_OBJ_WRITE(). People don't use it
- * directly.
- *
- * @param[in] old An object that points to `young`.
- * @param[out] young An object that is referenced from `old`.
- */
-void rb_gc_writebarrier(VALUE old, VALUE young);
-
-/**
- * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
- * directly.
- *
- * @param[out] obj An object that does not participate in WB.
- */
-void rb_gc_writebarrier_unprotect(VALUE obj);
-
-#if USE_RGENGC_LOGGING_WB_UNPROTECT
-/**
- * @private
- *
- * This is the implementation of #RGENGC_LOGGING_WB_UNPROTECT(). People
- * don't use it directly.
- *
- * @param[in] objptr Don't know why this is a pointer to void but in
- * reality this is a pointer to an object that is about
- * to be un-protected.
- * @param[in] filename Pass C's `__FILE__` here.
- * @param[in] line Pass C's `__LINE__` here.
- */
-void rb_gc_unprotect_logging(void *objptr, const char *filename, int line);
-#endif
-
-RBIMPL_SYMBOL_EXPORT_END()
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * This is the implementation of #RB_OBJ_PROMOTED(). People don't use it
- * directly.
- *
- * @param[in] obj An object to query.
- * @retval true The object is "promoted".
- * @retval false The object is young. Have not experienced GC at all.
- */
-static inline bool
-RB_OBJ_PROMOTED_RAW(VALUE obj)
-{
- RBIMPL_ASSERT_OR_ASSUME(RB_FL_ABLE(obj));
- return RB_FL_ANY_RAW(obj, RUBY_FL_PROMOTED);
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * Tests if the object is "promoted" -- that is, whether the object experienced
- * one or more GC marks.
- *
- * @param[in] obj An object to query.
- * @retval true The object is "promoted".
- * @retval false The object is young. Have not experienced GC at all.
- * @note Hello, is anyone actively calling this function? @shyouhei have
- * never seen any actual usages outside of the GC implementation
- * itself.
- */
-static inline bool
-RB_OBJ_PROMOTED(VALUE obj)
-{
- if (! RB_FL_ABLE(obj)) {
- return false;
- }
- else {
- return RB_OBJ_PROMOTED_RAW(obj);
- }
-}
-
-/**
- * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
- * directly.
- *
- * @param[out] x An object that does not participate in WB.
- * @param[in] filename C's `__FILE__` of the caller function.
- * @param[in] line C's `__LINE__` of the caller function.
- * @return x
- */
-static inline VALUE
-rb_obj_wb_unprotect(
- VALUE x,
- RBIMPL_ATTR_MAYBE_UNUSED()
- const char *filename,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int line)
-{
-#if USE_RGENGC_LOGGING_WB_UNPROTECT
- RGENGC_LOGGING_WB_UNPROTECT(RBIMPL_CAST((void *)x), filename, line);
-#endif
- rb_gc_writebarrier_unprotect(x);
- return x;
-}
-
-/**
- * @private
- *
- * This is the implementation of #RB_OBJ_WRITTEN(). People don't use it
- * directly.
- *
- * @param[in] a An old object.
- * @param[in] oldv An object previously stored inside of `old`.
- * @param[out] b A young object.
- * @param[in] filename C's `__FILE__` of the caller function.
- * @param[in] line C's `__LINE__` of the caller function.
- * @return a
- */
-static inline VALUE
-rb_obj_written(
- VALUE a,
- RBIMPL_ATTR_MAYBE_UNUSED()
- VALUE oldv,
- VALUE b,
- RBIMPL_ATTR_MAYBE_UNUSED()
- const char *filename,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int line)
-{
-#if USE_RGENGC_LOGGING_WB_UNPROTECT
- RGENGC_LOGGING_OBJ_WRITTEN(a, oldv, b, filename, line);
-#endif
-
- if (!RB_SPECIAL_CONST_P(b)) {
- rb_gc_writebarrier(a, b);
- }
-
- return a;
-}
-
-/**
- * @private
- *
- * This is the implementation of #RB_OBJ_WRITE(). People don't use it
- * directly.
- *
- * @param[in] a An old object.
- * @param[in] slot A pointer inside of `old`.
- * @param[out] b A young object.
- * @param[in] filename C's `__FILE__` of the caller function.
- * @param[in] line C's `__LINE__` of the caller function.
- * @return a
- */
-static inline VALUE
-rb_obj_write(
- VALUE a, VALUE *slot, VALUE b,
- RBIMPL_ATTR_MAYBE_UNUSED()
- const char *filename,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int line)
-{
-#ifdef RGENGC_LOGGING_WRITE
- RGENGC_LOGGING_WRITE(a, slot, b, filename, line);
-#endif
-
- *slot = b;
-
- rb_obj_written(a, RUBY_Qundef /* ignore `oldv' now */, b, filename, line);
- return a;
-}
-
#endif /* RBIMPL_GC_H */
diff --git a/include/ruby/internal/has/c_attribute.h b/include/ruby/internal/has/c_attribute.h
index 69b0f402cd..c5c48867bf 100644
--- a/include/ruby/internal/has/c_attribute.h
+++ b/include/ruby/internal/has/c_attribute.h
@@ -21,23 +21,11 @@
* @brief Defines #RBIMPL_HAS_C_ATTRIBUTE.
*/
-#include "ruby/internal/has/extension.h"
-#include "ruby/internal/has/warning.h"
-
/** Wraps (or simulates) `__has_c_attribute`. */
#if defined(__cplusplus)
# /* Makes no sense. */
# define RBIMPL_HAS_C_ATTRIBUTE(_) 0
-#elif RBIMPL_HAS_EXTENSION(c_attributes)
-# /* Hmm. It seems Clang 17 has this macro defined even when -std=c99 mode,
-# * _and_ fails to compile complaining that attributes are C2X feature. We
-# * need to work around this nonsense. */
-# define RBIMPL_HAS_C_ATTRIBUTE(_) __has_c_attribute(_)
-
-#elif RBIMPL_HAS_WARNING("-Wc2x-extensions")
-# define RBIMPL_HAS_C_ATTRIBUTE(_) 0
-
#elif defined(__has_c_attribute)
# define RBIMPL_HAS_C_ATTRIBUTE(_) __has_c_attribute(_)
diff --git a/include/ruby/internal/intern/bignum.h b/include/ruby/internal/intern/bignum.h
index 4ba48264fa..43d68018de 100644
--- a/include/ruby/internal/intern/bignum.h
+++ b/include/ruby/internal/intern/bignum.h
@@ -793,7 +793,7 @@ size_t rb_absint_size(VALUE val, int *nlz_bits_ret);
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
* @retval (size_t)-1 Overflowed.
* @retval otherwise
- * `((val_numbits * CHAR_BIT + word_numbits - 1) / word_numbits)`,
+ `((val_numbits * CHAR_BIT + word_numbits - 1) / word_numbits)`,
* where val_numbits is the number of bits of `abs(val)`.
* @post If `nlz_bits_ret` is not `NULL` and there is no overflow,
* `(return_value * word_numbits - val_numbits)` is stored in
diff --git a/include/ruby/internal/intern/error.h b/include/ruby/internal/intern/error.h
index bf8daadd3e..9c153cbac5 100644
--- a/include/ruby/internal/intern/error.h
+++ b/include/ruby/internal/intern/error.h
@@ -235,7 +235,7 @@ RBIMPL_ATTR_NORETURN()
* @param[in] max Maximum allowed `argc`.
* @exception rb_eArgError Always.
*/
-void rb_error_arity(int argc, int min, int max);
+MJIT_STATIC void rb_error_arity(int argc, int min, int max);
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/include/ruby/internal/intern/gc.h b/include/ruby/internal/intern/gc.h
new file mode 100644
index 0000000000..2ee1d257db
--- /dev/null
+++ b/include/ruby/internal/intern/gc.h
@@ -0,0 +1,392 @@
+#ifndef RBIMPL_INTERN_GC_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_INTERN_GC_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief Public APIs related to ::rb_mGC.
+ */
+#include "ruby/internal/config.h"
+
+#ifdef STDC_HEADERS
+# include <stddef.h> /* size_t */
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* ssize_t */
+#endif
+
+#include "ruby/internal/attr/cold.h"
+#include "ruby/internal/attr/noreturn.h"
+#include "ruby/internal/attr/nonnull.h"
+#include "ruby/internal/attr/pure.h"
+#include "ruby/internal/dllexport.h"
+#include "ruby/internal/value.h"
+
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+
+/* gc.c */
+
+RBIMPL_ATTR_COLD()
+RBIMPL_ATTR_NORETURN()
+/**
+ * Triggers out-of-memory error. If possible it raises ::rb_eNoMemError. But
+ * because we are running out of memory that is not always doable. This
+ * function tries hard to show something, but ultimately can die silently.
+ *
+ * @exception rb_eNoMemError Raises it if possible.
+ */
+void rb_memerror(void);
+
+RBIMPL_ATTR_PURE()
+/**
+ * Queries if the GC is busy.
+ *
+ * @retval 0 It isn't.
+ * @retval 1 It is.
+ */
+int rb_during_gc(void);
+
+RBIMPL_ATTR_NONNULL((1))
+/**
+ * Marks objects between the two pointers. This is one of the GC utility
+ * functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @pre Continuous memory region from `start` to `end` shall be fully
+ * addressable.
+ * @param[out] start Pointer to an array of objects.
+ * @param[out] end Pointer that terminates the array of objects.
+ * @post Objects from `start` (included) to `end` (excluded) are marked.
+ *
+ * @internal
+ *
+ * `end` can be NULL... But that just results in no-op.
+ */
+void rb_gc_mark_locations(const VALUE *start, const VALUE *end);
+
+/**
+ * Identical to rb_mark_hash(), except it marks only values of the table and
+ * leave their associated keys unmarked. This is one of the GC utility
+ * functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @warning Of course it can break GC. Leave it unused if unsure.
+ * @param[in] tbl A table to mark.
+ * @post Values stored in `tbl` are marked.
+ */
+void rb_mark_tbl(struct st_table *tbl);
+
+/**
+ * Identical to rb_mark_tbl(), except it marks objects using
+ * rb_gc_mark_movable(). This is one of the GC utility functions that you can
+ * call when you design your own ::rb_data_type_struct::dmark.
+ *
+ * @warning Of course it can break GC. Leave it unused if unsure.
+ * @param[in] tbl A table to mark.
+ * @post Values stored in `tbl` are marked.
+ */
+void rb_mark_tbl_no_pin(struct st_table *tbl);
+
+/**
+ * Identical to rb_mark_hash(), except it marks only keys of the table and
+ * leave their associated values unmarked. This is one of the GC utility
+ * functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @warning Of course it can break GC. Leave it unused if unsure.
+ * @param[in] tbl A table to mark.
+ * @post Keys stored in `tbl` are marked.
+ */
+void rb_mark_set(struct st_table *tbl);
+
+/**
+ * Marks keys and values associated inside of the given table. This is one of
+ * the GC utility functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @param[in] tbl A table to mark.
+ * @post Objects stored in `tbl` are marked.
+ */
+void rb_mark_hash(struct st_table *tbl);
+
+/**
+ * Updates references inside of tables. After you marked values using
+ * rb_mark_tbl_no_pin(), the objects inside of the table could of course be
+ * moved. This function is to fixup those references. You can call this from
+ * your ::rb_data_type_struct::dcompact.
+ *
+ * @param[out] ptr A table that potentially includes moved references.
+ * @post Moved references, if any, are corrected.
+ */
+void rb_gc_update_tbl_refs(st_table *ptr);
+
+/**
+ * Identical to rb_gc_mark(), except it allows the passed value be a
+ * non-object. For instance pointers to different type of memory regions are
+ * allowed here. Such values are silently ignored. This is one of the GC
+ * utility functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @param[out] obj A possible object.
+ * @post `obj` is marked, if possible.
+ */
+void rb_gc_mark_maybe(VALUE obj);
+
+/**
+ * Marks an object. This is one of the GC utility functions that you can call
+ * when you design your own ::rb_data_type_struct::dmark.
+ *
+ * @param[out] obj Arbitrary Ruby object.
+ * @post `obj` is marked.
+ */
+void rb_gc_mark(VALUE obj);
+
+/**
+ * Maybe this is the only function provided for C extensions to control the
+ * pinning of objects, so let us describe it in detail. These days Ruby's GC
+ * is copying. As far as an object's physical address is guaranteed unused, it
+ * can move around the object space. Our GC engine rearranges these objects
+ * after it reclaims unreachable objects from our object space, so that the
+ * space is compact (improves memory locality). This is called the
+ * "compaction" phase, and works well most of the time... as far as there are
+ * no C extensions. C extensions complicate the scenario because Ruby core
+ * cannot detect any use of the physical address of an object inside of C
+ * functions. In order to prevent memory corruptions, objects observable from
+ * C extensions are "pinned"; they stick to where they are born until they die,
+ * just in case any C extensions touch their raw pointers. This variant of
+ * scheme is called "Mostly-Copying" garbage collector. Authors of C
+ * extensions, however, can extremely carefully write them to become
+ * compaction-aware. To do so avoid referring to a Ruby object from inside of
+ * your struct in the first place. But if that is not possible, use this
+ * function from your ::rb_data_type_struct::dmark then. This way objects
+ * marked using it are considered movable. If you chose this way you have to
+ * manually fix up locations of such moved pointers using rb_gc_location().
+ *
+ * @see Bartlett, Joel F., "Compacting Garbage Collection with Ambiguous
+ * Roots", ACM SIGPLAN Lisp Pointers Volume 1 Issue 6 pp. 3-12,
+ * April-May-June, 1988. https://doi.org/10.1145/1317224.1317225
+ *
+ * @param[in] obj Object that is movable.
+ * @post Values stored in `tbl` are marked.
+ */
+void rb_gc_mark_movable(VALUE obj);
+
+/**
+ * Finds a new "location" of an object. An object can be moved on compaction.
+ * This function projects its new abode, or just returns the passed object if
+ * not moved. This is one of the GC utility functions that you can call when
+ * you design your own ::rb_data_type_struct::dcompact.
+ *
+ * @param[in] obj An object, possibly already moved to somewhere else.
+ * @return An object, which holds the current contents of former `obj`.
+ */
+VALUE rb_gc_location(VALUE obj);
+
+/**
+ * Asserts that the passed object is no longer needed. Such objects are
+ * reclaimed sooner or later so this function is not mandatory. But sometimes
+ * you can know from your application knowledge that an object is surely dead
+ * at some point. Calling this as a hint can be a polite way.
+ *
+ * @param[out] obj Object, dead.
+ * @pre `obj` have never been passed to this function before.
+ * @post `obj` could be invalidated.
+ * @warning It is a failure to pass an object multiple times to this
+ * function.
+ * @deprecated This is now a no-op function.
+ */
+RBIMPL_ATTR_DEPRECATED(("this is now a no-op function"))
+void rb_gc_force_recycle(VALUE obj);
+
+/**
+ * Triggers a GC process. This was the only GC entry point that we had at the
+ * beginning. Over time our GC evolved. Now what this function does is just a
+ * very simplified variation of the entire GC algorithms. A series of
+ * procedures kicked by this API is called a "full" GC.
+ *
+ * - It immediately scans the entire object space to sort the dead.
+ * - It immediately reclaims any single dead bodies to reuse later.
+ *
+ * It is worth noting that the procedures above do not include evaluations of
+ * finalisers. They run later.
+ *
+ * @internal
+ *
+ * Finalisers are deferred until we can handle interrupts. See
+ * `rb_postponed_job_flush` in vm_trace.c.
+ *
+ * Of course there are GC that are not "full". For instance this one and the
+ * GC which runs when we are running out of memory are different. See
+ * `gc_profile_record_flag` defined in gc.c for the kinds of GC.
+ *
+ * In spite of the name this is not what everything that a GC can trigger. As
+ * of writing it seems this function does not trigger compaction. But this
+ * might change in future.
+ */
+void rb_gc(void);
+
+/**
+ * Copy&paste an object's finaliser to another. This is one of the GC utility
+ * functions that you can call when you design your own `initialize_copy`,
+ * `initialize_dup`, `initialize_clone`.
+ *
+ * @param[out] dst Destination object.
+ * @param[in] src Source object.
+ * @post `dst` and `src` share the same finaliser.
+ *
+ * @internal
+ *
+ * But isn't it easier for you to call super, and let `Object#initialize_copy`
+ * call this function instead?
+ */
+void rb_gc_copy_finalizer(VALUE dst, VALUE src);
+
+/**
+ * (Re-) enables GC. This makes sense only after you called rb_gc_disable().
+ *
+ * @retval RUBY_Qtrue GC was disabled before.
+ * @retval RUBY_Qfalse GC was enabled before.
+ * @post GC is enabled.
+ *
+ * @internal
+ *
+ * This is one of such exceptional functions that does not raise both Ruby
+ * exceptions and C++ exceptions.
+ */
+VALUE rb_gc_enable(void);
+
+/**
+ * Disables GC. This prevents automatic GC runs when the process is running
+ * out of memory. Such situations shall result in rb_memerror(). However this
+ * does not prevent users from manually invoking rb_gc(). That should work.
+ * People abused this by disabling GC at the beginning of an event loop,
+ * process events without GC overheads, then manually force reclaiming garbage
+ * at the bottom of the loop. However because our GC is now much smarter than
+ * just calling rb_gc(), this technique is proven to be sub-optimal these days.
+ * It is believed that there is currently practically no needs of this
+ * function.
+ *
+ * @retval RUBY_Qtrue GC was disabled before.
+ * @retval RUBY_Qfalse GC was enabled before.
+ * @post GC is disabled.
+ */
+VALUE rb_gc_disable(void);
+
+/**
+ * Identical to rb_gc(), except the return value.
+ *
+ * @return Always returns ::RUBY_Qnil.
+ */
+VALUE rb_gc_start(void);
+
+/**
+ * Assigns a finaliser for an object. Each objects can have objects (typically
+ * blocks) that run immediately after that object dies. They are called
+ * finalisers of an object. This function associates a finaliser object with a
+ * target object.
+ *
+ * @note Note that finalisers run _after_ the object they finalise dies. You
+ * cannot for instance call its methods.
+ * @note If your finaliser references the object it finalises that object
+ * loses any chance to become a garbage; effectively leaks memory until
+ * the end of the process.
+ *
+ * @param[in] obj Target to finalise.
+ * @param[in] block Something `call`able.
+ * @exception rb_eRuntimeError Somehow `obj` cannot have finalisers.
+ * @exception rb_eFrozenError `obj` is frozen.
+ * @exception rb_eArgError `block` doesn't respond to `call`.
+ * @return The passed `block`.
+ * @post `block` runs after `obj` dies.
+ */
+VALUE rb_define_finalizer(VALUE obj, VALUE block);
+
+/**
+ * Modifies the object so that it has no finalisers at all. This function is
+ * mainly provided for symmetry. No practical usages can be thought of.
+ *
+ * @param[out] obj Object to clear its finalisers.
+ * @exception rb_eFrozenError `obj` is frozen.
+ * @return The passed `obj`.
+ * @post `obj` has no finalisers.
+ * @note There is no way to undefine a specific part of many finalisers
+ * that `obj` could have. All you can do is to clear them all.
+ */
+VALUE rb_undefine_finalizer(VALUE obj);
+
+/**
+ * Identical to rb_gc_stat(), with "count" parameter.
+ *
+ * @return Lifetime total number of runs of GC.
+ */
+size_t rb_gc_count(void);
+
+/**
+ * Obtains various GC related profiles. The parameter can be either a Symbol
+ * or a Hash. If a Hash is passed, it is filled with everything currently
+ * available. If a Symbol is passed just that portion is returned.
+ *
+ * Possible variations of keys you can pass here change from version to
+ * version. You can get the list of known keys by passing an empty hash and
+ * let it be filled.
+ *
+ * @param[in,out] key_or_buf A Symbol, or a Hash.
+ * @exception rb_eTypeError Neither Symbol nor Hash.
+ * @exception rb_eFrozenError Frozen hash is passed.
+ * @return In case a Hash is passed it returns 0. Otherwise the
+ * profile value associated with the given key is returned.
+ * @post In case a Hash is passed it is filled with values.
+ */
+size_t rb_gc_stat(VALUE key_or_buf);
+
+/**
+ * Obtains various info regarding the most recent GC run. This includes for
+ * instance the reason of the GC. The parameter can be either a Symbol or a
+ * Hash. If a Hash is passed, it is filled with everything currently
+ * available. If a Symbol is passed just that portion is returned.
+ *
+ * Possible variations of keys you can pass here change from version to
+ * version. You can get the list of known keys by passing an empty hash and
+ * let it be filled.
+ *
+ * @param[in,out] key_or_buf A Symbol, or a Hash.
+ * @exception rb_eTypeError Neither Symbol nor Hash.
+ * @exception rb_eFrozenError Frozen hash is passed.
+ * @return In case a Hash is passed it returns that hash. Otherwise
+ * the profile value associated with the given key is returned.
+ * @post In case a Hash is passed it is filled with values.
+ */
+VALUE rb_gc_latest_gc_info(VALUE key_or_buf);
+
+/**
+ * Informs that there are external memory usages. Our GC runs when we are
+ * running out of memory. The amount of memory, however, can increase/decrease
+ * behind-the-scene. For instance DLLs can allocate memories using `mmap(2)`
+ * etc, which are opaque to us. Registering such external allocations using
+ * this function enables proper detection of how much memories an object used
+ * as a whole. That will trigger GCs more often than it would otherwise. You
+ * can also pass negative numbers here, to indicate that such external
+ * allocations are gone.
+ *
+ * @param[in] diff Amount of memory increased(+)/decreased(-).
+ */
+void rb_gc_adjust_memory_usage(ssize_t diff);
+
+RBIMPL_SYMBOL_EXPORT_END()
+
+#endif /* RBIMPL_INTERN_GC_H */
diff --git a/include/ruby/internal/intern/process.h b/include/ruby/internal/intern/process.h
index 5dcf85e80c..7a7b24ed4b 100644
--- a/include/ruby/internal/intern/process.h
+++ b/include/ruby/internal/intern/process.h
@@ -31,15 +31,6 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
/* process.c */
/**
- * Wait for the specified process to terminate, reap it, and return its status.
- *
- * @param[in] pid The process ID to wait for.
- * @param[in] flags The flags to pass to waitpid(2).
- * @return VALUE An instance of Process::Status.
- */
-VALUE rb_process_status_wait(rb_pid_t pid, int flags);
-
-/**
* Sets the "last status", or the `$?`.
*
* @param[in] status The termination status, as defined in `waitpid(3posix)`.
diff --git a/include/ruby/internal/intern/re.h b/include/ruby/internal/intern/re.h
index 4dd58b469b..31f5593275 100644
--- a/include/ruby/internal/intern/re.h
+++ b/include/ruby/internal/intern/re.h
@@ -87,6 +87,11 @@ void rb_match_busy(VALUE md);
* @retval RUBY_Qfalse There is a `n`-th capture and is empty.
* @retval RUBY_Qtrue There is a `n`-th capture that has something.
*
+ * @internal
+ *
+ * @shyouhei wonders: why there are both rb_reg_match_defined() and
+ * rb_match_nth_defined, which are largely the same things, but do not share
+ * their implementations at all?
*/
VALUE rb_reg_nth_defined(int n, VALUE md);
diff --git a/include/ruby/internal/intern/signal.h b/include/ruby/internal/intern/signal.h
index e5b6d6c3d5..84f7558404 100644
--- a/include/ruby/internal/intern/signal.h
+++ b/include/ruby/internal/intern/signal.h
@@ -113,6 +113,12 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_f_kill(int argc, const VALUE *argv);
+/* This must be private, @shyouhei guesses. */
+#ifdef POSIX_SIGNAL
+#define posix_signal ruby_posix_signal
+void (*posix_signal(int, void (*)(int)))(int);
+#endif
+
RBIMPL_ATTR_PURE()
/**
* Queries the name of the signal. It returns for instance `"KILL"` for
diff --git a/include/ruby/internal/intern/struct.h b/include/ruby/internal/intern/struct.h
index 4510508d77..312cf444e2 100644
--- a/include/ruby/internal/intern/struct.h
+++ b/include/ruby/internal/intern/struct.h
@@ -46,10 +46,10 @@ VALUE rb_struct_new(VALUE klass, ...);
*
* @param[in] name Name of the class.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `name` is not a constant name.
* @exception rb_eTypeError `name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post Global toplevel constant `name` is defined.
* @note `name` is allowed to be a null pointer. This function creates
@@ -70,10 +70,10 @@ RBIMPL_ATTR_NONNULL((2))
* @param[out] space Namespace that the defining class shall reside.
* @param[in] name Name of the class.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `name` is not a constant name.
* @exception rb_eTypeError `name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post `name` is a constant under `space`.
* @note In contrast to rb_struct_define(), it doesn't make any sense to
@@ -164,10 +164,10 @@ VALUE rb_struct_alloc_noinit(VALUE klass);
* @param[in] super Superclass of the defining class.
* @param[in] func Must be 0 for extension libraries.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `name` is not a constant name.
* @exception rb_eTypeError `name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post Global toplevel constant `name` is defined.
* @note `name` is allowed to be a null pointer. This function creates
@@ -187,10 +187,10 @@ RBIMPL_ATTR_NONNULL((2))
* @param[in] super Superclass of the defining class.
* @param[in] alloc Must be 0 for extension libraries.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `class_name` is not a constant name.
* @exception rb_eTypeError `class_name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post `class_name` is a constant under `outer`.
* @note In contrast to rb_struct_define_without_accessor(), it doesn't
@@ -198,20 +198,6 @@ RBIMPL_ATTR_NONNULL((2))
*/
VALUE rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, ...);
-/**
- * Defines an anonymous data class.
- *
- * @endinternal
- *
- * @param[in] super Superclass of the defining class. Must be a
- * descendant of ::rb_cData, or 0 as ::rb_cData.
- * @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
- * @exception rb_eArgError Duplicated field name.
- * @return The defined class.
- */
-VALUE rb_data_define(VALUE super, ...);
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_STRUCT_H */
diff --git a/include/ruby/internal/newobj.h b/include/ruby/internal/newobj.h
index ba1d7cbe59..a8a5557a25 100644
--- a/include/ruby/internal/newobj.h
+++ b/include/ruby/internal/newobj.h
@@ -172,8 +172,6 @@ RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#clone works."))
static inline void
rb_clone_setup(VALUE clone, VALUE obj)
{
- (void)clone;
- (void)obj;
return;
}
@@ -191,8 +189,6 @@ RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#dup works."))
static inline void
rb_dup_setup(VALUE dup, VALUE obj)
{
- (void)dup;
- (void)obj;
return;
}
diff --git a/include/ruby/internal/rgengc.h b/include/ruby/internal/rgengc.h
new file mode 100644
index 0000000000..7ea04442f6
--- /dev/null
+++ b/include/ruby/internal/rgengc.h
@@ -0,0 +1,443 @@
+#ifndef RBIMPL_RGENGC_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_RGENGC_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief RGENGC write-barrier APIs.
+ * @see Sasada, K., "Gradual write-barrier insertion into a Ruby
+ * interpreter", in proceedings of the 2019 ACM SIGPLAN
+ * International Symposium on Memory Management (ISMM 2019), pp
+ * 115-121, 2019. https://doi.org/10.1145/3315573.3329986
+ */
+#include "ruby/internal/attr/artificial.h"
+#include "ruby/internal/attr/maybe_unused.h"
+#include "ruby/internal/attr/pure.h"
+#include "ruby/internal/dllexport.h"
+#include "ruby/internal/special_consts.h"
+#include "ruby/internal/stdbool.h"
+#include "ruby/internal/value.h"
+#include "ruby/assert.h"
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ */
+#undef USE_RGENGC
+#define USE_RGENGC 1
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable incremental GC feature. It
+ * has to be set at the time ruby itself compiles. Makes no sense for 3rd
+ * parties. It is safe for them to set this though; that just doesn't change
+ * anything.
+ */
+#ifndef USE_RINCGC
+# define USE_RINCGC 1
+#endif
+
+/**
+ * @deprecated This macro seems broken. Setting this to anything other than
+ * zero just doesn't compile. We need to KonMari.
+ */
+#ifndef USE_RGENGC_LOGGING_WB_UNPROTECT
+# define USE_RGENGC_LOGGING_WB_UNPROTECT 0
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RArray. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_ARRAY
+# define RGENGC_WB_PROTECTED_ARRAY 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RHash. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_HASH
+# define RGENGC_WB_PROTECTED_HASH 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RStruct. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_STRUCT
+# define RGENGC_WB_PROTECTED_STRUCT 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RString. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_STRING
+# define RGENGC_WB_PROTECTED_STRING 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RObject. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_OBJECT
+# define RGENGC_WB_PROTECTED_OBJECT 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RRegexp. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_REGEXP
+# define RGENGC_WB_PROTECTED_REGEXP 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RClass. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_CLASS
+# define RGENGC_WB_PROTECTED_CLASS 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RFloat. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_FLOAT
+# define RGENGC_WB_PROTECTED_FLOAT 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RComplex. It has to be set at the time ruby itself compiles.
+ * Makes no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_COMPLEX
+# define RGENGC_WB_PROTECTED_COMPLEX 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RRational. It has to be set at the time ruby itself compiles.
+ * Makes no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_RATIONAL
+# define RGENGC_WB_PROTECTED_RATIONAL 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RBignum. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_BIGNUM
+# define RGENGC_WB_PROTECTED_BIGNUM 1
+#endif
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ *
+ * @internal
+ *
+ * @shyouhei doesn't think anybody uses this right now.
+ */
+#ifndef RGENGC_WB_PROTECTED_NODE_CREF
+# define RGENGC_WB_PROTECTED_NODE_CREF 1
+#endif
+
+/**
+ * @defgroup rgengc Write barrier (WB) interfaces:
+ *
+ * @note The following core interfaces can be changed in the future. Please
+ * catch up if you want to insert WB into C-extensions correctly.
+ *
+ * @{
+ */
+
+/**
+ * Declaration of a "back" pointer. This is a write barrier for new reference
+ * from "old" generation to "young" generation. It writes `young` into
+ * `*slot`, which is a pointer inside of `old`.
+ *
+ * @param[in] old An old object.
+ * @param[in] slot A pointer inside of `old`.
+ * @param[out] young A young object.
+ */
+#define RB_OBJ_WRITE(old, slot, young) \
+ RBIMPL_CAST(rb_obj_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young), __FILE__, __LINE__))
+
+/**
+ * Identical to #RB_OBJ_WRITE(), except it doesn't write any values, but only a
+ * WB declaration. `oldv` is replaced value with `b` (not used in current
+ * Ruby).
+ *
+ * @param[in] old An old object.
+ * @param[in] oldv An object previously stored inside of `old`.
+ * @param[out] young A young object.
+ */
+#define RB_OBJ_WRITTEN(old, oldv, young) \
+ RBIMPL_CAST(rb_obj_written((VALUE)(old), (VALUE)(oldv), (VALUE)(young), __FILE__, __LINE__))
+/** @} */
+
+#define OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW /**< @old{RB_OBJ_PROMOTED_RAW} */
+#define OBJ_PROMOTED RB_OBJ_PROMOTED /**< @old{RB_OBJ_PROMOTED} */
+#define OBJ_WB_UNPROTECT RB_OBJ_WB_UNPROTECT /**< @old{RB_OBJ_WB_UNPROTECT} */
+
+/**
+ * Asserts that the passed object is not fenced by write barriers. Objects of
+ * such property do not contribute to generational GCs. They are scanned
+ * always.
+ *
+ * @param[out] x An object that would not be protected by the barrier.
+ */
+#define RB_OBJ_WB_UNPROTECT(x) rb_obj_wb_unprotect(x, __FILE__, __LINE__)
+
+/**
+ * Identical to #RB_OBJ_WB_UNPROTECT(), except it can also assert that the
+ * given object is of given type.
+ *
+ * @param[in] type One of `ARRAY`, `STRING`, etc.
+ * @param[out] obj An object of `type` that would not be protected.
+ *
+ * @internal
+ *
+ * @shyouhei doesn't understand why this has to be visible from extensions.
+ */
+#define RB_OBJ_WB_UNPROTECT_FOR(type, obj) \
+ (RGENGC_WB_PROTECTED_##type ? OBJ_WB_UNPROTECT(obj) : obj)
+
+/**
+ * @private
+ *
+ * This is an implementation detail of rb_obj_wb_unprotect(). People don't use
+ * it directly.
+ */
+#define RGENGC_LOGGING_WB_UNPROTECT rb_gc_unprotect_logging
+
+/** @cond INTERNAL_MACRO */
+#define RB_OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW
+#define RB_OBJ_PROMOTED RB_OBJ_PROMOTED
+/** @endcond */
+
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+/**
+ * This is the implementation of #RB_OBJ_WRITE(). People don't use it
+ * directly.
+ *
+ * @param[in] old An object that points to `young`.
+ * @param[out] young An object that is referenced from `old`.
+ */
+void rb_gc_writebarrier(VALUE old, VALUE young);
+
+/**
+ * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
+ * directly.
+ *
+ * @param[out] obj An object that does not participate in WB.
+ */
+void rb_gc_writebarrier_unprotect(VALUE obj);
+
+#if USE_RGENGC_LOGGING_WB_UNPROTECT
+/**
+ * @private
+ *
+ * This is the implementation of #RGENGC_LOGGING_WB_UNPROTECT(). People
+ * don't use it directly.
+ *
+ * @param[in] objptr Don't know why this is a pointer to void but in
+ * reality this is a pointer to an object that is about
+ * to be un-protected.
+ * @param[in] filename Pass C's `__FILE__` here.
+ * @param[in] line Pass C's `__LINE__` here.
+ */
+void rb_gc_unprotect_logging(void *objptr, const char *filename, int line);
+#endif
+
+RBIMPL_SYMBOL_EXPORT_END()
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * This is the implementation of #RB_OBJ_PROMOTED(). People don't use it
+ * directly.
+ *
+ * @param[in] obj An object to query.
+ * @retval true The object is "promoted".
+ * @retval false The object is young. Have not experienced GC at all.
+ */
+static inline bool
+RB_OBJ_PROMOTED_RAW(VALUE obj)
+{
+ RBIMPL_ASSERT_OR_ASSUME(RB_FL_ABLE(obj));
+ return RB_FL_ANY_RAW(obj, RUBY_FL_PROMOTED);
+}
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * Tests if the object is "promoted" -- that is, whether the object experienced
+ * one or more GC marks.
+ *
+ * @param[in] obj An object to query.
+ * @retval true The object is "promoted".
+ * @retval false The object is young. Have not experienced GC at all.
+ * @note Hello, is anyone actively calling this function? @shyouhei have
+ * never seen any actual usages outside of the GC implementation
+ * itself.
+ */
+static inline bool
+RB_OBJ_PROMOTED(VALUE obj)
+{
+ if (! RB_FL_ABLE(obj)) {
+ return false;
+ }
+ else {
+ return RB_OBJ_PROMOTED_RAW(obj);
+ }
+}
+
+/**
+ * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
+ * directly.
+ *
+ * @param[out] x An object that does not participate in WB.
+ * @param[in] filename C's `__FILE__` of the caller function.
+ * @param[in] line C's `__LINE__` of the caller function.
+ * @return x
+ */
+static inline VALUE
+rb_obj_wb_unprotect(
+ VALUE x,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ const char *filename,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int line)
+{
+#if USE_RGENGC_LOGGING_WB_UNPROTECT
+ RGENGC_LOGGING_WB_UNPROTECT(RBIMPL_CAST((void *)x), filename, line);
+#endif
+ rb_gc_writebarrier_unprotect(x);
+ return x;
+}
+
+/**
+ * @private
+ *
+ * This is the implementation of #RB_OBJ_WRITTEN(). People don't use it
+ * directly.
+ *
+ * @param[in] a An old object.
+ * @param[in] oldv An object previously stored inside of `old`.
+ * @param[out] b A young object.
+ * @param[in] filename C's `__FILE__` of the caller function.
+ * @param[in] line C's `__LINE__` of the caller function.
+ * @return a
+ */
+static inline VALUE
+rb_obj_written(
+ VALUE a,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ VALUE oldv,
+ VALUE b,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ const char *filename,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int line)
+{
+#if USE_RGENGC_LOGGING_WB_UNPROTECT
+ RGENGC_LOGGING_OBJ_WRITTEN(a, oldv, b, filename, line);
+#endif
+
+ if (!RB_SPECIAL_CONST_P(b)) {
+ rb_gc_writebarrier(a, b);
+ }
+
+ return a;
+}
+
+/**
+ * @private
+ *
+ * This is the implementation of #RB_OBJ_WRITE(). People don't use it
+ * directly.
+ *
+ * @param[in] a An old object.
+ * @param[in] slot A pointer inside of `old`.
+ * @param[out] b A young object.
+ * @param[in] filename C's `__FILE__` of the caller function.
+ * @param[in] line C's `__LINE__` of the caller function.
+ * @return a
+ */
+static inline VALUE
+rb_obj_write(
+ VALUE a, VALUE *slot, VALUE b,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ const char *filename,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int line)
+{
+#ifdef RGENGC_LOGGING_WRITE
+ RGENGC_LOGGING_WRITE(a, slot, b, filename, line);
+#endif
+
+ *slot = b;
+
+ rb_obj_written(a, RUBY_Qundef /* ignore `oldv' now */, b, filename, line);
+ return a;
+}
+
+#endif /* RBIMPL_RGENGC_H */
diff --git a/include/ruby/io.h b/include/ruby/io.h
index e9dfeda5b1..88029b1bb9 100644
--- a/include/ruby/io.h
+++ b/include/ruby/io.h
@@ -49,11 +49,11 @@
/** @endcond */
#include "ruby/internal/attr/const.h"
-#include "ruby/internal/attr/packed_struct.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
+#include "ruby/backward/2/attributes.h" /* PACKED_STRUCT_UNALIGNED */
// IO#wait, IO#wait_readable, IO#wait_writable, IO#wait_priority are defined by this implementation.
#define RUBY_IO_WAIT_METHODS
@@ -78,20 +78,17 @@ RUBY_EXTERN VALUE rb_eIOTimeoutError;
*
* This is visible from extension libraries because `io/wait` wants it.
*/
-enum rb_io_event {
+typedef enum {
RUBY_IO_READABLE = RB_WAITFD_IN, /**< `IO::READABLE` */
RUBY_IO_WRITABLE = RB_WAITFD_OUT, /**< `IO::WRITABLE` */
RUBY_IO_PRIORITY = RB_WAITFD_PRI, /**< `IO::PRIORITY` */
-};
-
-typedef enum rb_io_event rb_io_event_t;
+} rb_io_event_t;
/**
* IO buffers. This is an implementation detail of ::rb_io_t::wbuf and
* ::rb_io_t::rbuf. People don't manipulate it directly.
*/
-RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
-struct rb_io_internal_buffer {
+PACKED_STRUCT_UNALIGNED(struct rb_io_buffer_t {
/** Pointer to the underlying memory region, of at least `capa` bytes. */
char *ptr; /* off + len <= capa */
@@ -104,10 +101,10 @@ struct rb_io_internal_buffer {
/** Designed capacity of the buffer. */
int capa;
-} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
+});
/** @alias{rb_io_buffer_t} */
-typedef struct rb_io_internal_buffer rb_io_buffer_t;
+typedef struct rb_io_buffer_t rb_io_buffer_t;
/** Decomposed encoding flags (e.g. `"enc:enc2""`). */
/*
@@ -116,7 +113,7 @@ typedef struct rb_io_internal_buffer rb_io_buffer_t;
* e1 NULL force_encoding(e1) convert str.encoding to e1
* e1 e2 convert from e2 to e1 convert str.encoding to e2
*/
-struct rb_io_encoding {
+struct rb_io_enc_t {
/** Internal encoding. */
rb_encoding *enc;
/** External encoding. */
@@ -137,51 +134,40 @@ struct rb_io_encoding {
VALUE ecopts;
};
-#ifndef HAVE_RB_IO_T
-#define HAVE_RB_IO_T 1
/** Ruby's IO, metadata and buffers. */
-struct rb_io {
+typedef struct rb_io_t {
+
/** The IO's Ruby level counterpart. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE self;
/** stdio ptr for read/write, if available. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
FILE *stdio_file;
/** file descriptor. */
- RBIMPL_ATTR_DEPRECATED(("rb_io_descriptor"))
int fd;
/** mode flags: FMODE_XXXs */
- RBIMPL_ATTR_DEPRECATED(("rb_io_mode"))
int mode;
/** child's pid (for pipes) */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_pid_t pid;
/** number of lines read */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
int lineno;
/** pathname for file */
- RBIMPL_ATTR_DEPRECATED(("rb_io_path"))
VALUE pathv;
/** finalize proc */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
- void (*finalize)(struct rb_io*,int);
+ void (*finalize)(struct rb_io_t*,int);
/** Write buffer. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_io_buffer_t wbuf;
/**
* (Byte) read buffer. Note also that there is a field called
* ::rb_io_t::cbuf, which also concerns read IO.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_io_buffer_t rbuf;
/**
@@ -189,25 +175,20 @@ struct rb_io {
*
* @see rb_io_set_write_io()
*/
- RBIMPL_ATTR_DEPRECATED(("rb_io_get_write_io"))
VALUE tied_io_for_writing;
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
- struct rb_io_encoding encs; /**< Decomposed encoding flags. */
+ struct rb_io_enc_t encs; /**< Decomposed encoding flags. */
/** Encoding converter used when reading from this IO. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_econv_t *readconv;
/**
* rb_io_ungetc() destination. This buffer is read before checking
* ::rb_io_t::rbuf
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_io_buffer_t cbuf;
/** Encoding converter used when writing to this IO. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_econv_t *writeconv;
/**
@@ -216,25 +197,21 @@ struct rb_io {
* conversion from encoding X to encoding Y does not exist, Ruby finds an
* encoding Z that bridges the two, so that X to Z to Y conversion happens.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE writeconv_asciicompat;
/** Whether ::rb_io_t::writeconv is already set up. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
int writeconv_initialized;
/**
* Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before
* initialising ::rb_io_t::writeconv.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
int writeconv_pre_ecflags;
/**
* Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising
* ::rb_io_t::writeconv.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE writeconv_pre_ecopts;
/**
@@ -244,21 +221,25 @@ struct rb_io {
*
* This of course doesn't help inter-process IO interleaves, though.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE write_lock;
/**
* The timeout associated with this IO when performing blocking operations.
*/
- RBIMPL_ATTR_DEPRECATED(("rb_io_timeout/rb_io_set_timeout"))
VALUE timeout;
-};
-#endif
-
-typedef struct rb_io rb_io_t;
+} rb_io_t;
/** @alias{rb_io_enc_t} */
-typedef struct rb_io_encoding rb_io_enc_t;
+typedef struct rb_io_enc_t rb_io_enc_t;
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ */
+#define HAVE_RB_IO_T 1
/**
* @name Possible flags for ::rb_io_t::mode
@@ -349,16 +330,7 @@ typedef struct rb_io_encoding rb_io_enc_t;
* Setting this one and #FMODE_BINMODE at the same time is a contradiction.
*/
#define FMODE_TEXTMODE 0x00001000
-/**
- * This flag means that an IO object is wrapping an "external" file descriptor,
- * which is owned by something outside the Ruby interpreter (usually a C extension).
- * Ruby will not close this file when the IO object is garbage collected.
- * If this flag is set, then IO#autoclose? is false, and vice-versa.
- *
- * This flag was previously called FMODE_PREP internally.
- */
-#define FMODE_EXTERNAL 0x00010000
-
+/* #define FMODE_PREP 0x00010000 */
/* #define FMODE_SIGNAL_ON_EPIPE 0x00020000 */
/**
@@ -373,18 +345,6 @@ typedef struct rb_io_encoding rb_io_enc_t;
/** @} */
/**
- * Allocate a new IO object, with the given file descriptor.
- */
-VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding);
-
-/**
- * Returns whether or not the underlying IO is closed.
- *
- * @return Whether the underlying IO is closed.
- */
-VALUE rb_io_closed_p(VALUE io);
-
-/**
* Queries the underlying IO pointer.
*
* @param[in] obj An IO object.
@@ -454,14 +414,14 @@ rb_io_t *rb_io_make_open_file(VALUE obj);
* like this:
*
* ```CXX
- * typedef struct rb_io {
+ * typedef struct rb_io_t {
* FILE *f; // stdio ptr for read/write
* FILE *f2; // additional ptr for rw pipes
* int mode; // mode flags
* int pid; // child's pid (for pipes)
* int lineno; // number of lines read
* char *path; // pathname for file
- * void (*finalize) _((struct rb_io*,int)); // finalize proc
+ * void (*finalize) _((struct rb_io_t*,int)); // finalize proc
* } rb_io_t;
*```
*
@@ -743,12 +703,6 @@ VALUE rb_io_set_write_io(VALUE io, VALUE w);
void rb_io_set_nonblock(rb_io_t *fptr);
/**
- * Returns the path for the given IO.
- *
- */
-VALUE rb_io_path(VALUE io);
-
-/**
* Returns an integer representing the numeric file descriptor for
* <em>io</em>.
*
@@ -758,12 +712,6 @@ VALUE rb_io_path(VALUE io);
int rb_io_descriptor(VALUE io);
/**
- * Get the mode of the IO.
- *
- */
-int rb_io_mode(VALUE io);
-
-/**
* This function breaks down the option hash that `IO#initialize` takes into
* components. This is an implementation detail of rb_io_extract_modeenc()
* today. People prefer that API instead.
diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h
index f2ab8f1195..e4b855d8e7 100644
--- a/include/ruby/io/buffer.h
+++ b/include/ruby/io/buffer.h
@@ -56,14 +56,10 @@ enum rb_io_buffer_endian {
RB_IO_BUFFER_LITTLE_ENDIAN = 4,
RB_IO_BUFFER_BIG_ENDIAN = 8,
-#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
-#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#if defined(WORDS_BIGENDIAN)
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN,
-#elif defined(REG_DWORD) && REG_DWORD == REG_DWORD_LITTLE_ENDIAN
+#else
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
-#elif defined(REG_DWORD) && REG_DWORD == REG_DWORD_BIG_ENDIAN
- RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN,
#endif
RB_IO_BUFFER_NETWORK_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN
@@ -75,9 +71,7 @@ VALUE rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer
VALUE rb_io_buffer_lock(VALUE self);
VALUE rb_io_buffer_unlock(VALUE self);
int rb_io_buffer_try_unlock(VALUE self);
-
VALUE rb_io_buffer_free(VALUE self);
-VALUE rb_io_buffer_free_locked(VALUE self);
int rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size);
void rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size);
diff --git a/include/ruby/memory_view.h b/include/ruby/memory_view.h
index 42309d5afc..1ddca2d46f 100644
--- a/include/ruby/memory_view.h
+++ b/include/ruby/memory_view.h
@@ -47,10 +47,10 @@ typedef struct {
char format;
/** :FIXME: what is a "native" size is unclear. */
- bool native_size_p;
+ unsigned native_size_p: 1;
/** Endian of the component */
- bool little_endian_p;
+ unsigned little_endian_p: 1;
/** The component's offset. */
size_t offset;
diff --git a/include/ruby/onigmo.h b/include/ruby/onigmo.h
index d233336316..8d7c601703 100644
--- a/include/ruby/onigmo.h
+++ b/include/ruby/onigmo.h
@@ -744,6 +744,8 @@ typedef struct {
typedef struct {
int lower;
int upper;
+ long base_num;
+ long inner_num;
} OnigRepeatRange;
typedef void (*OnigWarnFunc)(const char* s);
@@ -844,8 +846,6 @@ void onig_free(OnigRegex);
ONIG_EXTERN
void onig_free_body(OnigRegex);
ONIG_EXTERN
-int onig_reg_copy(OnigRegex* reg, OnigRegex orig_reg);
-ONIG_EXTERN
OnigPosition onig_scan(OnigRegex reg, const OnigUChar* str, const OnigUChar* end, OnigRegion* region, OnigOptionType option, int (*scan_callback)(OnigPosition, OnigPosition, OnigRegion*, void*), void* callback_arg);
ONIG_EXTERN
OnigPosition onig_search(OnigRegex, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegion* region, OnigOptionType option);
diff --git a/include/ruby/re.h b/include/ruby/re.h
index f86d6f26cf..3892d6e7f2 100644
--- a/include/ruby/re.h
+++ b/include/ruby/re.h
@@ -18,7 +18,6 @@
#include <stdio.h>
-#include "ruby/onigmo.h"
#include "ruby/regex.h"
#include "ruby/internal/core/rmatch.h"
#include "ruby/internal/dllexport.h"
@@ -127,30 +126,6 @@ VALUE rb_reg_quote(VALUE str);
regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
/**
- * Runs a regular expression match using function `match`. Performs preparation,
- * error handling, and memory cleanup.
- *
- * @param[in] re Target regular expression.
- * @param[in] str What `re` is about to run on.
- * @param[in] match The function to run to match `str` against `re`.
- * @param[in] args Pointer to arguments to pass into `match`.
- * @param[out] regs Registers on a successful match.
- * @exception rb_eArgError `re` does not fit for `str`.
- * @exception rb_eEncCompatError `re` and `str` are incompatible.
- * @exception rb_eRegexpError `re` is malformed.
- * @return Match position on a successful match, `ONIG_MISMATCH` otherwise.
- *
- * @internal
- *
- * The type `regex_t *` is defined in `<ruby/onigmo.h>`, _and_
- * _conflicts_ with POSIX's `<regex.h>`. We can no longer save the situation
- * at this point. Just don't mix the two.
- */
-OnigPosition rb_reg_onig_match(VALUE re, VALUE str,
- OnigPosition (*match)(regex_t *reg, VALUE str, struct re_registers *regs, void *args),
- void *args, struct re_registers *regs);
-
-/**
* Duplicates a match data. This is roughly the same as `onig_region_copy()`,
* except it tries to GC when there is not enough memory.
*
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 91e24bcebd..444940ca3a 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -43,6 +43,7 @@
#include "ruby/internal/method.h"
#include "ruby/internal/module.h"
#include "ruby/internal/newobj.h"
+#include "ruby/internal/rgengc.h"
#include "ruby/internal/scan_args.h"
#include "ruby/internal/special_consts.h"
#include "ruby/internal/symbol.h"
@@ -97,10 +98,8 @@ VALUE rb_get_path(VALUE obj);
VALUE rb_get_path_no_checksafe(VALUE);
/**
- * This macro actually does the same thing as #FilePathValue now. The "String"
- * part indicates that this is for when a string is treated like a pathname,
- * rather than the actual pathname on the file systems. For examples:
- * `Dir.fnmatch?`, `File.join`, `File.basename`, etc.
+ * @deprecated This macro is an alias of #FilePathValue now. The part that did
+ * "String" was deleted. It remains here because of no harm.
*/
#define FilePathStringValue(v) ((v) = rb_get_path(v))
@@ -272,24 +271,6 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 0)
*/
int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap);
-// TODO: doc
-
-#include <errno.h>
-
-int rb_errno(void);
-void rb_errno_set(int);
-int *rb_errno_ptr(void);
-
-static inline int *
-rb_orig_errno_ptr(void)
-{
- return &errno;
-}
-
-#define rb_orig_errno errno
-#undef errno
-#define errno (*rb_errno_ptr())
-
/** @cond INTERNAL_MACRO */
#if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments")
# /* Skip it; clang -pedantic doesn't like the following */
diff --git a/include/ruby/st.h b/include/ruby/st.h
index ba69c066c9..f35ab43603 100644
--- a/include/ruby/st.h
+++ b/include/ruby/st.h
@@ -104,8 +104,6 @@ st_table *rb_st_init_table(const struct st_hash_type *);
#define st_init_table rb_st_init_table
st_table *rb_st_init_table_with_size(const struct st_hash_type *, st_index_t);
#define st_init_table_with_size rb_st_init_table_with_size
-st_table *rb_st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type, st_index_t size);
-#define st_init_existing_table_with_size rb_st_init_existing_table_with_size
st_table *rb_st_init_numtable(void);
#define st_init_numtable rb_st_init_numtable
st_table *rb_st_init_numtable_with_size(st_index_t);
@@ -162,8 +160,6 @@ void rb_st_cleanup_safe(st_table *, st_data_t);
#define st_cleanup_safe rb_st_cleanup_safe
void rb_st_clear(st_table *);
#define st_clear rb_st_clear
-st_table *rb_st_replace(st_table *new_tab, st_table *old_tab);
-#define st_replace rb_st_replace
st_table *rb_st_copy(st_table *);
#define st_copy rb_st_copy
CONSTFUNC(int rb_st_numcmp(st_data_t, st_data_t));
diff --git a/include/ruby/thread.h b/include/ruby/thread.h
index d6a543af91..0b5b1ca0f3 100644
--- a/include/ruby/thread.h
+++ b/include/ruby/thread.h
@@ -190,41 +190,11 @@ void *rb_nogvl(void *(*func)(void *), void *data1,
*/
#define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_
-/**
- * Triggered when a new thread is started.
- *
- * @note The callback will be called *without* the GVL held.
- */
-#define RUBY_INTERNAL_THREAD_EVENT_STARTED 1 << 0
-
-/**
-* Triggered when a thread attempt to acquire the GVL.
-*
-* @note The callback will be called *without* the GVL held.
-*/
+#define RUBY_INTERNAL_THREAD_EVENT_STARTED 1 << 0 /** thread started */
#define RUBY_INTERNAL_THREAD_EVENT_READY 1 << 1 /** acquiring GVL */
-
-/**
- * Triggered when a thread successfuly acquired the GVL.
- *
- * @note The callback will be called *with* the GVL held.
- */
#define RUBY_INTERNAL_THREAD_EVENT_RESUMED 1 << 2 /** acquired GVL */
-
-/**
- * Triggered when a thread released the GVL.
- *
- * @note The callback will be called *without* the GVL held.
- */
#define RUBY_INTERNAL_THREAD_EVENT_SUSPENDED 1 << 3 /** released GVL */
-
-/**
- * Triggered when a thread exits.
- *
- * @note The callback will be called *without* the GVL held.
- */
#define RUBY_INTERNAL_THREAD_EVENT_EXITED 1 << 4 /** thread terminated */
-
#define RUBY_INTERNAL_THREAD_EVENT_MASK 0xff /** All Thread events */
typedef void rb_internal_thread_event_data_t; // for future extension.
@@ -242,8 +212,6 @@ typedef struct rb_internal_thread_event_hook rb_internal_thread_event_hook_t;
* @param[in] data Passed as-is to `func`.
* @return An opaque pointer to the hook, to unregister it later.
* @note This functionality is a noop on Windows.
- * @note The callback will be called without the GVL held, except for the
- * RESUMED event.
* @warning This function MUST not be called from a thread event callback.
*/
rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook(
diff --git a/include/ruby/thread_native.h b/include/ruby/thread_native.h
index 8217a67514..c23b15e133 100644
--- a/include/ruby/thread_native.h
+++ b/include/ruby/thread_native.h
@@ -28,11 +28,6 @@ typedef union rb_thread_lock_union {
CRITICAL_SECTION crit;
} rb_nativethread_lock_t;
-struct rb_thread_cond_struct {
- struct cond_event_entry *next;
- struct cond_event_entry *prev;
-};
-
typedef struct rb_thread_cond_struct rb_nativethread_cond_t;
#elif defined(HAVE_PTHREAD_H)
diff --git a/include/ruby/util.h b/include/ruby/util.h
index ee11bc940a..e8727a3200 100644
--- a/include/ruby/util.h
+++ b/include/ruby/util.h
@@ -36,15 +36,6 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
/** an approximation of ceil(n * log10(2)), up to 65536 at least */
#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
-/** an approximation of decimal representation size for n-bytes */
-#define DECIMAL_SIZE_OF_BYTES(n) DECIMAL_SIZE_OF_BITS((n) * CHAR_BIT)
-
-/**
- * An approximation of decimal representation size. `expr` may be a
- * type name
- */
-#define DECIMAL_SIZE_OF(expr) DECIMAL_SIZE_OF_BYTES(sizeof(expr))
-
/**
* Character to number mapping like `'a'` -> `10`, `'b'` -> `11` etc. For
* punctuation etc., the value is -1. "36" terminology comes from the fact
diff --git a/include/ruby/version.h b/include/ruby/version.h
index 08c0aadb07..18b3abc8d7 100644
--- a/include/ruby/version.h
+++ b/include/ruby/version.h
@@ -67,7 +67,7 @@
* Minor version. As of writing this version changes annually. Greater
* version doesn't mean "better"; they just mean years passed.
*/
-#define RUBY_API_VERSION_MINOR 3
+#define RUBY_API_VERSION_MINOR 2
/**
* Teeny version. This digit is kind of reserved these days. Kept 0 for the
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index dfb56f4182..18de3a17d8 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -125,8 +125,15 @@ typedef unsigned int uintptr_t;
#define O_SHARE_DELETE 0x20000000 /* for rb_w32_open(), rb_w32_wopen() */
typedef int clockid_t;
+#if defined(__MINGW32__)
+#undef CLOCK_PROCESS_CPUTIME_ID
+#undef CLOCK_THREAD_CPUTIME_ID
+#undef CLOCK_REALTIME_COARSE
+#endif
+#if defined(HAVE_CLOCK_GETTIME) && !defined(CLOCK_REALTIME)
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
+#endif
#undef utime
#undef lseek
@@ -147,10 +154,8 @@ typedef int clockid_t;
#define open rb_w32_uopen
#define close(h) rb_w32_close(h)
#define fclose(f) rb_w32_fclose(f)
-#define read(f, b, s) rb_w32_read(f, b, s)
-#define write(f, b, s) rb_w32_write(f, b, s)
-#define pread(f, b, s, o) rb_w32_pread(f, b, s, o)
-#define pwrite(f, b, s, o) rb_w32_pwrite(f, b, s, o)
+#define read(f, b, s) rb_w32_read(f, b, s)
+#define write(f, b, s) rb_w32_write(f, b, s)
#define getpid() rb_w32_getpid()
#undef HAVE_GETPPID
#define HAVE_GETPPID 1
@@ -718,8 +723,6 @@ int rb_w32_fclose(FILE*);
int rb_w32_pipe(int[2]);
ssize_t rb_w32_read(int, void *, size_t);
ssize_t rb_w32_write(int, const void *, size_t);
-ssize_t rb_w32_pread(int, void *, size_t, rb_off_t offset);
-ssize_t rb_w32_pwrite(int, const void *, size_t, rb_off_t offset);
rb_off_t rb_w32_lseek(int, rb_off_t, int);
int rb_w32_uutime(const char *, const struct utimbuf *);
int rb_w32_uutimes(const char *, const struct timeval *);
diff --git a/inits.c b/inits.c
index 46530bb6d0..e809b56cc9 100644
--- a/inits.c
+++ b/inits.c
@@ -22,7 +22,11 @@ rb_call_inits(void)
{
CALL(default_shapes);
CALL(Thread_Mutex);
+#if USE_TRANSIENT_HEAP
+ CALL(TransientHeap);
+#endif
CALL(vm_postponed_job);
+ CALL(Method);
CALL(RandomSeedCore);
CALL(encodings);
CALL(sym);
@@ -58,7 +62,6 @@ rb_call_inits(void)
CALL(Binding);
CALL(Math);
CALL(GC);
- CALL(WeakMap);
CALL(Enumerator);
CALL(Ractor);
CALL(VM);
@@ -76,7 +79,6 @@ rb_call_inits(void)
CALL(ast);
CALL(gc_stress);
CALL(shape);
- CALL(Prism);
// enable builtin loading
CALL(builtin);
@@ -103,9 +105,9 @@ rb_call_builtin_inits(void)
BUILTIN(yjit);
BUILTIN(nilclass);
BUILTIN(marshal);
-#if USE_RJIT
- BUILTIN(rjit_c);
- BUILTIN(rjit);
+#if USE_MJIT
+ BUILTIN(mjit);
+ BUILTIN(mjit_c);
#endif
Init_builtin_prelude();
}
diff --git a/insns.def b/insns.def
index b784d7c043..9f5ee7095a 100644
--- a/insns.def
+++ b/insns.def
@@ -260,7 +260,20 @@ opt_getconstant_path
(VALUE val)
// attr bool leaf = false; /* may autoload or raise */
{
- val = rb_vm_opt_getconstant_path(ec, GET_CFP(), ic);
+ const ID *segments = ic->segments;
+ struct iseq_inline_constant_cache_entry *ice = ic->entry;
+ if (ice && vm_ic_hit_p(ice, GET_EP())) {
+ val = ice->value;
+
+ VM_ASSERT(val == vm_get_ev_const_chain(ec, segments));
+ } else {
+ ruby_vm_constant_cache_misses++;
+ val = vm_get_ev_const_chain(ec, segments);
+ vm_ic_track_const_chain(GET_CFP(), ic, segments);
+ // Because leaf=false, we need to undo the PC increment to get the address to this instruction
+ // INSN_ATTR(width) == 2
+ vm_ic_update(GET_ISEQ(), ic, val, GET_EP(), GET_PC() - 2);
+ }
}
/* Get constant variable id. If klass is Qnil and allow_nil is Qtrue, constants
@@ -688,20 +701,6 @@ defined
}
}
-/* defined?(@foo) */
-DEFINE_INSN
-definedivar
-(ID id, IVC ic, VALUE pushval)
-()
-(VALUE val)
-// attr bool leaf = false;
-{
- val = Qnil;
- if (vm_getivar(GET_SELF(), id, GET_ISEQ(), ic, NULL, FALSE, Qundef) != Qundef) {
- val = pushval;
- }
-}
-
/* check `target' matches `pattern'.
`flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern.
VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy.
@@ -800,7 +799,6 @@ send
{
VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
- JIT_EXEC(ec, val);
if (val == Qundef) {
RESTORE_REGS();
@@ -820,7 +818,6 @@ opt_send_without_block
{
VALUE bh = VM_BLOCK_HANDLER_NONE;
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
- JIT_EXEC(ec, val);
if (val == Qundef) {
RESTORE_REGS();
@@ -886,8 +883,8 @@ opt_str_uminus
}
DEFINE_INSN
-opt_newarray_send
-(rb_num_t num, ID method)
+opt_newarray_max
+(rb_num_t num)
(...)
(VALUE val)
/* This instruction typically has no funcalls. But it compares array
@@ -896,21 +893,20 @@ opt_newarray_send
* cannot but mark it being not leaf. */
// attr bool leaf = false; /* has rb_funcall() */
// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
-// attr rb_snum_t comptime_sp_inc = 1 - (rb_snum_t)num;
-{
- switch(method) {
- case idHash:
- val = vm_opt_newarray_hash(ec, num, STACK_ADDR_FROM_TOP(num));
- break;
- case idMin:
- val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
- break;
- case idMax:
- val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
- break;
- default:
- rb_bug("unreachable");
- }
+{
+ val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
+}
+
+DEFINE_INSN
+opt_newarray_min
+(rb_num_t num)
+(...)
+(VALUE val)
+/* Same discussion as opt_newarray_max. */
+// attr bool leaf = false; /* has rb_funcall() */
+// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
+{
+ val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
}
/* super(args) # args.size => num */
@@ -924,7 +920,6 @@ invokesuper
{
VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
- JIT_EXEC(ec, val);
if (val == Qundef) {
RESTORE_REGS();
@@ -944,7 +939,6 @@ invokeblock
{
VALUE bh = VM_BLOCK_HANDLER_NONE;
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
- JIT_EXEC(ec, val);
if (val == Qundef) {
RESTORE_REGS();
@@ -1351,8 +1345,10 @@ opt_aset_with
val = tmp;
}
else {
+#ifndef MJIT_HEADER
TOPN(0) = rb_str_resurrect(key);
PUSH(val);
+#endif
CALL_SIMPLE_METHOD();
}
}
@@ -1369,7 +1365,9 @@ opt_aref_with
val = vm_opt_aref_with(recv, key);
if (val == Qundef) {
+#ifndef MJIT_HEADER
PUSH(rb_str_resurrect(key));
+#endif
CALL_SIMPLE_METHOD();
}
}
@@ -1459,6 +1457,27 @@ opt_regexpmatch2
}
}
+/* call native compiled method */
+DEFINE_INSN_IF(SUPPORT_CALL_C_FUNCTION)
+opt_call_c_function
+(rb_insn_func_t funcptr)
+()
+()
+// attr bool leaf = false; /* anything can happen inside */
+// attr bool handles_sp = true;
+{
+ reg_cfp = (funcptr)(ec, reg_cfp);
+
+ if (reg_cfp == 0) {
+ VALUE err = ec->errinfo;
+ ec->errinfo = Qnil;
+ THROW_EXCEPTION(err);
+ }
+
+ RESTORE_REGS();
+ NEXT_INSN();
+}
+
/* call specific function with args */
DEFINE_INSN
invokebuiltin
diff --git a/internal.h b/internal.h
index c66e057f60..b63af50616 100644
--- a/internal.h
+++ b/internal.h
@@ -43,6 +43,7 @@
/* internal/gc.h */
#undef NEWOBJ_OF
#undef RB_NEWOBJ_OF
+#undef RB_OBJ_WRITE
/* internal/hash.h */
#undef RHASH_IFNONE
diff --git a/internal/array.h b/internal/array.h
index 39f6fcbea6..a0d16dec3f 100644
--- a/internal/array.h
+++ b/internal/array.h
@@ -23,7 +23,6 @@
#define RARRAY_PTR_IN_USE_FLAG FL_USER14
/* array.c */
-VALUE rb_ary_hash_values(long len, const VALUE *elements);
VALUE rb_ary_last(int, const VALUE *, VALUE);
void rb_ary_set_len(VALUE, long);
void rb_ary_delete_same(VALUE, VALUE);
@@ -40,7 +39,10 @@ VALUE rb_ary_diff(VALUE ary1, VALUE ary2);
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
static inline bool ARY_PTR_USING_P(VALUE ary);
+static inline void RARY_TRANSIENT_SET(VALUE ary);
+static inline void RARY_TRANSIENT_UNSET(VALUE ary);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ary_tmp_new_from_values(VALUE, long, const VALUE *);
VALUE rb_check_to_array(VALUE ary);
VALUE rb_ary_behead(VALUE, long);
@@ -48,13 +50,14 @@ VALUE rb_ary_aref1(VALUE ary, VALUE i);
struct rb_execution_context_struct;
VALUE rb_ec_ary_new_from_values(struct rb_execution_context_struct *ec, long n, const VALUE *elts);
+MJIT_SYMBOL_EXPORT_END
// YJIT needs this function to never allocate and never raise
static inline VALUE
rb_ary_entry_internal(VALUE ary, long offset)
{
long len = RARRAY_LEN(ary);
- const VALUE *ptr = RARRAY_CONST_PTR(ary);
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
if (len == 0) return Qnil;
if (offset < 0) {
offset += len;
@@ -116,6 +119,22 @@ ARY_SHARED_ROOT_REFCNT(VALUE ary)
return RARRAY(ary)->as.heap.aux.capa;
}
+static inline void
+RARY_TRANSIENT_SET(VALUE ary)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+RARY_TRANSIENT_UNSET(VALUE ary)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+#endif
+}
+
#undef rb_ary_new_from_args
#if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments")
# /* Skip it; clang -pedantic doesn't like the following */
@@ -136,16 +155,9 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline VALUE
RARRAY_AREF(VALUE ary, long i)
{
- VALUE val;
RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
- RBIMPL_WARNING_PUSH();
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 13
- RBIMPL_WARNING_IGNORED(-Warray-bounds);
-#endif
- val = RARRAY_CONST_PTR(ary)[i];
- RBIMPL_WARNING_POP();
- return val;
+ return RARRAY_CONST_PTR_TRANSIENT(ary)[i];
}
#endif /* INTERNAL_ARRAY_H */
diff --git a/internal/basic_operators.h b/internal/basic_operators.h
index a59403631e..2cd9f50073 100644
--- a/internal/basic_operators.h
+++ b/internal/basic_operators.h
@@ -31,7 +31,6 @@ enum ruby_basic_operators {
BOP_UMINUS,
BOP_MAX,
BOP_MIN,
- BOP_HASH,
BOP_CALL,
BOP_AND,
BOP_OR,
@@ -41,7 +40,9 @@ enum ruby_basic_operators {
BOP_LAST_
};
+MJIT_SYMBOL_EXPORT_BEGIN
RUBY_EXTERN short ruby_vm_redefined_flag[BOP_LAST_];
+MJIT_SYMBOL_EXPORT_END
/* optimize insn */
#define INTEGER_REDEFINED_OP_FLAG (1 << 0)
diff --git a/internal/bignum.h b/internal/bignum.h
index db8d3aee83..5cd35ede8a 100644
--- a/internal/bignum.h
+++ b/internal/bignum.h
@@ -163,9 +163,11 @@ VALUE rb_str2big_gmp(VALUE arg, int base, int badcheck);
VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
#if defined(HAVE_INT128_T)
VALUE rb_int128t2big(int128_t n);
#endif
+MJIT_SYMBOL_EXPORT_END
/* sign: positive:1, negative:0 */
static inline bool
diff --git a/internal/bits.h b/internal/bits.h
index 1fe98fa430..2602ff7a31 100644
--- a/internal/bits.h
+++ b/internal/bits.h
@@ -34,7 +34,8 @@
# include <stdlib.h> /* for _byteswap_uint64 */
#endif
-#if defined(HAVE_X86INTRIN_H)
+#if defined(HAVE_X86INTRIN_H) && ! defined(MJIT_HEADER)
+# /* Rule out MJIT_HEADER, which does not interface well with <immintrin.h> */
# include <x86intrin.h> /* for _lzcnt_u64 */
#elif MSC_VERSION_SINCE(1310)
# include <intrin.h> /* for the following intrinsics */
@@ -118,16 +119,12 @@
MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
#endif
-#if defined(MUL_OVERFLOW_P) && defined(USE___BUILTIN_MUL_OVERFLOW_LONG_LONG)
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
-#else
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
-#endif
-
#ifdef MUL_OVERFLOW_P
+# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_P(a, b)
#else
+# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
#endif
@@ -238,7 +235,7 @@ nlz_int32(uint32_t x)
* safety. */
return (unsigned int)__lzcnt(x);
-#elif defined(__x86_64__) && defined(__LZCNT__)
+#elif defined(__x86_64__) && defined(__LZCNT__) && ! defined(MJIT_HEADER)
return (unsigned int)_lzcnt_u32(x);
#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
@@ -267,7 +264,7 @@ nlz_int64(uint64_t x)
#if defined(_MSC_VER) && defined(__AVX2__)
return (unsigned int)__lzcnt64(x);
-#elif defined(__x86_64__) && defined(__LZCNT__)
+#elif defined(__x86_64__) && defined(__LZCNT__) && ! defined(MJIT_HEADER)
return (unsigned int)_lzcnt_u64(x);
#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
@@ -398,9 +395,9 @@ rb_popcount32(uint32_t x)
#else
x = (x & 0x55555555) + (x >> 1 & 0x55555555);
x = (x & 0x33333333) + (x >> 2 & 0x33333333);
- x = (x & 0x07070707) + (x >> 4 & 0x07070707);
- x = (x & 0x000f000f) + (x >> 8 & 0x000f000f);
- x = (x & 0x0000001f) + (x >>16 & 0x0000001f);
+ x = (x & 0x0f0f0f0f) + (x >> 4 & 0x0f0f0f0f);
+ x = (x & 0x001f001f) + (x >> 8 & 0x001f001f);
+ x = (x & 0x0000003f) + (x >>16 & 0x0000003f);
return (unsigned int)x;
#endif
@@ -428,9 +425,9 @@ rb_popcount64(uint64_t x)
x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555);
x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
x = (x & 0x0707070707070707) + (x >> 4 & 0x0707070707070707);
- x = (x & 0x000f000f000f000f) + (x >> 8 & 0x000f000f000f000f);
- x = (x & 0x0000001f0000001f) + (x >>16 & 0x0000001f0000001f);
- x = (x & 0x000000000000003f) + (x >>32 & 0x000000000000003f);
+ x = (x & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f);
+ x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f);
+ x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f);
return (unsigned int)x;
#endif
@@ -453,7 +450,7 @@ rb_popcount_intptr(uintptr_t x)
static inline int
ntz_int32(uint32_t x)
{
-#if defined(__x86_64__) && defined(__BMI__)
+#if defined(__x86_64__) && defined(__BMI__) && ! defined(MJIT_HEADER)
return (unsigned)_tzcnt_u32(x);
#elif MSC_VERSION_SINCE(1400)
@@ -475,7 +472,7 @@ ntz_int32(uint32_t x)
static inline int
ntz_int64(uint64_t x)
{
-#if defined(__x86_64__) && defined(__BMI__)
+#if defined(__x86_64__) && defined(__BMI__) && ! defined(MJIT_HEADER)
return (unsigned)_tzcnt_u64(x);
#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
diff --git a/internal/class.h b/internal/class.h
index b055f07317..63917e867f 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -8,11 +8,9 @@
* file COPYING are met. Consult the file for details.
* @brief Internal header for Class.
*/
-#include "id.h"
#include "id_table.h" /* for struct rb_id_table */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "internal/serial.h" /* for rb_serial_t */
-#include "internal/static_assert.h"
-#include "internal/variable.h" /* for rb_class_ivar_set */
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/intern.h" /* for rb_alloc_func_t */
#include "ruby/ruby.h" /* for struct RBasic */
@@ -30,7 +28,6 @@ struct rb_subclass_entry {
struct rb_subclass_entry *next;
struct rb_subclass_entry *prev;
};
-typedef struct rb_subclass_entry rb_subclass_entry_t;
struct rb_cvar_class_tbl_entry {
uint32_t index;
@@ -57,40 +54,32 @@ struct rb_classext_struct {
struct rb_subclass_entry *module_subclass_entry;
const VALUE origin_;
const VALUE refined_class;
- union {
- struct {
- rb_alloc_func_t allocator;
- } class;
- struct {
- VALUE attached_object;
- } singleton_class;
- } as;
+ rb_alloc_func_t allocator;
const VALUE includer;
- attr_index_t max_iv_count;
- unsigned char variation_count;
- bool permanent_classpath : 1;
- bool cloned : 1;
- VALUE classpath;
+ uint32_t max_iv_count;
+ uint32_t variation_count;
+#if !SHAPE_IN_BASIC_FLAGS
+ shape_id_t shape_id;
+#endif
};
-typedef struct rb_classext_struct rb_classext_t;
-
-STATIC_ASSERT(shape_max_variations, SHAPE_MAX_VARIATIONS < (1 << (sizeof(((rb_classext_t *)0)->variation_count) * CHAR_BIT)));
struct RClass {
struct RBasic basic;
VALUE super;
struct rb_id_table *m_tbl;
+#if SIZE_POOL_COUNT == 1
+ struct rb_classext_struct *ptr;
+#endif
};
-// Assert that classes can be embedded in size_pools[2] (which has 160B slot size)
-STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass) + sizeof(rb_classext_t) <= 4 * RVALUE_SIZE);
-
-struct RClass_and_rb_classext_t {
- struct RClass rclass;
- rb_classext_t classext;
-};
+typedef struct rb_subclass_entry rb_subclass_entry_t;
+typedef struct rb_classext_struct rb_classext_t;
-#define RCLASS_EXT(c) (&((struct RClass_and_rb_classext_t*)(c))->classext)
+#if RCLASS_EXT_EMBEDDED
+# define RCLASS_EXT(c) ((rb_classext_t *)((char *)(c) + sizeof(struct RClass)))
+#else
+# define RCLASS_EXT(c) (RCLASS(c)->ptr)
+#endif
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
#define RCLASS_IVPTR(c) (RCLASS_EXT(c)->iv_ptr)
@@ -102,12 +91,13 @@ struct RClass_and_rb_classext_t {
#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer)
#define RCLASS_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->subclass_entry)
#define RCLASS_MODULE_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->module_subclass_entry)
+#define RCLASS_ALLOCATOR(c) (RCLASS_EXT(c)->allocator)
#define RCLASS_SUBCLASSES(c) (RCLASS_EXT(c)->subclasses)
#define RCLASS_SUPERCLASS_DEPTH(c) (RCLASS_EXT(c)->superclass_depth)
#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT(c)->superclasses)
-#define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT(c)->as.singleton_class.attached_object)
#define RICLASS_IS_ORIGIN FL_USER0
+#define RCLASS_CLONED FL_USER1
#define RCLASS_SUPERCLASSES_INCLUDE_SELF FL_USER2
#define RICLASS_ORIGIN_SHARED_MTBL FL_USER3
@@ -129,6 +119,7 @@ void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE);
void rb_class_detach_subclasses(VALUE);
void rb_class_detach_module_subclasses(VALUE);
void rb_class_remove_from_module_subclasses(VALUE);
+VALUE rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super);
VALUE rb_obj_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj);
@@ -145,24 +136,10 @@ static inline VALUE RCLASS_SUPER(VALUE klass);
static inline VALUE RCLASS_SET_SUPER(VALUE klass, VALUE super);
static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);
-
-static inline rb_alloc_func_t
-RCLASS_ALLOCATOR(VALUE klass)
-{
- if (FL_TEST_RAW(klass, FL_SINGLETON)) {
- return 0;
- }
- return RCLASS_EXT(klass)->as.class.allocator;
-}
-
-static inline void
-RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator)
-{
- assert(!FL_TEST(klass, FL_SINGLETON));
- RCLASS_EXT(klass)->as.class.allocator = allocator;
-}
+MJIT_SYMBOL_EXPORT_END
static inline void
RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
@@ -207,24 +184,4 @@ RCLASS_SET_SUPER(VALUE klass, VALUE super)
return super;
}
-static inline void
-RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
-{
- assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
- assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
-
- RB_OBJ_WRITE(klass, &(RCLASS_EXT(klass)->classpath), classpath);
- RCLASS_EXT(klass)->permanent_classpath = permanent;
-}
-
-static inline VALUE
-RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object)
-{
- assert(BUILTIN_TYPE(klass) == T_CLASS);
- assert(FL_TEST_RAW(klass, FL_SINGLETON));
-
- RB_OBJ_WRITE(klass, &RCLASS_EXT(klass)->as.singleton_class.attached_object, attached_object);
- return attached_object;
-}
-
#endif /* INTERNAL_CLASS_H */
diff --git a/internal/cmdlineopt.h b/internal/cmdlineopt.h
index e79b993345..bf52f1214b 100644
--- a/internal/cmdlineopt.h
+++ b/internal/cmdlineopt.h
@@ -1,7 +1,7 @@
#ifndef INTERNAL_CMDLINEOPT_H /*-*-C-*-vi:se ft=c:*/
#define INTERNAL_CMDLINEOPT_H
-#include "rjit.h"
+#include "mjit.h"
#include "yjit.h"
typedef struct {
@@ -23,15 +23,11 @@ typedef struct ruby_cmdline_options {
ruby_features_t features;
ruby_features_t warn;
unsigned int dump;
- long backtrace_length_limit;
-#if USE_RJIT
- struct rb_rjit_options rjit;
+#if USE_MJIT
+ struct mjit_options mjit;
#endif
- const char *crash_report;
-
- signed int sflag: 2;
- unsigned int xflag: 1;
+ int sflag, xflag;
unsigned int warning: 1;
unsigned int verbose: 1;
unsigned int do_loop: 1;
diff --git a/internal/compile.h b/internal/compile.h
index 2ece5396f6..d32c2233c9 100644
--- a/internal/compile.h
+++ b/internal/compile.h
@@ -17,7 +17,6 @@ struct rb_iseq_struct; /* in vm_core.h */
/* compile.c */
int rb_dvar_defined(ID, const struct rb_iseq_struct *);
int rb_local_defined(ID, const struct rb_iseq_struct *);
-int rb_insn_len(VALUE insn);
const char *rb_insns_name(int i);
VALUE rb_insns_name_array(void);
int rb_iseq_cdhash_cmp(VALUE val, VALUE lit);
@@ -28,7 +27,9 @@ int rb_vm_insn_addr2insn(const void *);
int rb_vm_insn_decode(const VALUE encoded);
extern bool ruby_vm_keep_script_lines;
+MJIT_SYMBOL_EXPORT_BEGIN
/* iseq.c (export) */
rb_event_flag_t rb_iseq_event_flags(const struct rb_iseq_struct *iseq, size_t pos);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_COMPILE_H */
diff --git a/internal/error.h b/internal/error.h
index 5fee468929..11601858f4 100644
--- a/internal/error.h
+++ b/internal/error.h
@@ -29,37 +29,15 @@
#define rb_raise_static(e, m) \
rb_raise_cstr_i((e), rb_str_new_static((m), rb_strlen_lit(m)))
#ifdef RUBY_FUNCTION_NAME_STRING
+# define rb_sys_fail_path(path) rb_sys_fail_path_in(RUBY_FUNCTION_NAME_STRING, path)
# define rb_syserr_fail_path(err, path) rb_syserr_fail_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path))
# define rb_syserr_new_path(err, path) rb_syserr_new_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path))
#else
+# define rb_sys_fail_path(path) rb_sys_fail_str(path)
# define rb_syserr_fail_path(err, path) rb_syserr_fail_str((err), (path))
# define rb_syserr_new_path(err, path) rb_syserr_new_str((err), (path))
#endif
-#define rb_sys_fail(mesg) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail(errno_to_fail, (mesg)); \
-} while (0)
-
-#define rb_sys_fail_str(mesg) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail_str(errno_to_fail, (mesg)); \
-} while (0)
-
-#define rb_sys_fail_path(path) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail_path(errno_to_fail, (path)); \
-} while (0)
-
-#define rb_sys_fail_sprintf(...) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail_str(errno_to_fail, rb_sprintf("" __VA_ARGS__)); \
-} while (0)
-
/* error.c */
extern long rb_backtrace_length_limit;
extern VALUE rb_eEAGAIN;
diff --git a/internal/eval.h b/internal/eval.h
index 73bb656d96..e594d8516d 100644
--- a/internal/eval.h
+++ b/internal/eval.h
@@ -21,6 +21,7 @@ extern ID ruby_static_id_status;
VALUE rb_refinement_module_get_refined_class(VALUE module);
void rb_class_modify_check(VALUE);
NORETURN(VALUE rb_f_raise(int argc, VALUE *argv));
+VALUE rb_top_main_class(const char *method);
/* eval_error.c */
VALUE rb_get_backtrace(VALUE info);
diff --git a/internal/gc.h b/internal/gc.h
index 188497b007..e54a5dce9d 100644
--- a/internal/gc.h
+++ b/internal/gc.h
@@ -14,116 +14,6 @@
#include "internal/compilers.h" /* for __has_attribute */
#include "ruby/ruby.h" /* for rb_event_flag_t */
-#include "vm_core.h" /* for GET_EC() */
-
-#if defined(__x86_64__) && !defined(_ILP32) && defined(__GNUC__)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movq\t%%rsp, %0" : "=r" (*(p)))
-#elif defined(__i386) && defined(__GNUC__)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p)))
-#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && !defined(_AIX) && !defined(__APPLE__) // Not Apple is NEEDED to unbreak ppc64 build on Darwin. Don't ask.
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p)))
-#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && defined(_AIX)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr %0,1" : "=r" (*(p)))
-#elif defined(__POWERPC__) && defined(__APPLE__) // Darwin ppc and ppc64
-#define SET_MACHINE_STACK_END(p) __asm__ volatile("mr %0, r1" : "=r" (*(p)))
-#elif defined(__aarch64__) && defined(__GNUC__)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p)))
-#else
-NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
-#define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
-#define USE_CONSERVATIVE_STACK_END
-#endif
-
-/* for GC debug */
-
-#ifndef RUBY_MARK_FREE_DEBUG
-#define RUBY_MARK_FREE_DEBUG 0
-#endif
-
-#if RUBY_MARK_FREE_DEBUG
-extern int ruby_gc_debug_indent;
-
-static inline void
-rb_gc_debug_indent(void)
-{
- ruby_debug_printf("%*s", ruby_gc_debug_indent, "");
-}
-
-static inline void
-rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
-{
- if (st == 0) {
- ruby_gc_debug_indent--;
- }
- rb_gc_debug_indent();
- ruby_debug_printf("%s: %s %s (%p)\n", mode, st ? "->" : "<-", msg, ptr);
-
- if (st) {
- ruby_gc_debug_indent++;
- }
-
- fflush(stdout);
-}
-
-#define RUBY_MARK_ENTER(msg) rb_gc_debug_body("mark", (msg), 1, ptr)
-#define RUBY_MARK_LEAVE(msg) rb_gc_debug_body("mark", (msg), 0, ptr)
-#define RUBY_FREE_ENTER(msg) rb_gc_debug_body("free", (msg), 1, ptr)
-#define RUBY_FREE_LEAVE(msg) rb_gc_debug_body("free", (msg), 0, ptr)
-#define RUBY_GC_INFO rb_gc_debug_indent(), ruby_debug_printf
-
-#else
-#define RUBY_MARK_ENTER(msg)
-#define RUBY_MARK_LEAVE(msg)
-#define RUBY_FREE_ENTER(msg)
-#define RUBY_FREE_LEAVE(msg)
-#define RUBY_GC_INFO if(0)printf
-#endif
-
-#define RUBY_MARK_MOVABLE_UNLESS_NULL(ptr) do { \
- VALUE markobj = (ptr); \
- if (RTEST(markobj)) {rb_gc_mark_movable(markobj);} \
-} while (0)
-#define RUBY_MARK_UNLESS_NULL(ptr) do { \
- VALUE markobj = (ptr); \
- if (RTEST(markobj)) {rb_gc_mark(markobj);} \
-} while (0)
-#define RUBY_FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);(ptr)=NULL;}
-
-#if STACK_GROW_DIRECTION > 0
-# define STACK_UPPER(x, a, b) (a)
-#elif STACK_GROW_DIRECTION < 0
-# define STACK_UPPER(x, a, b) (b)
-#else
-RUBY_EXTERN int ruby_stack_grow_direction;
-int ruby_get_stack_grow_direction(volatile VALUE *addr);
-# define stack_growup_p(x) ( \
- (ruby_stack_grow_direction ? \
- ruby_stack_grow_direction : \
- ruby_get_stack_grow_direction(x)) > 0)
-# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? (a) : (b))
-#endif
-
-/*
- STACK_GROW_DIR_DETECTION is used with STACK_DIR_UPPER.
-
- On most normal systems, stacks grow from high address to lower address. In
- this case, STACK_DIR_UPPER(a, b) will return (b), but on exotic systems where
- the stack grows UP (from low address to high address), it will return (a).
-*/
-
-#if STACK_GROW_DIRECTION
-#define STACK_GROW_DIR_DETECTION
-#define STACK_DIR_UPPER(a,b) STACK_UPPER(0, (a), (b))
-#else
-#define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection
-#define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, (a), (b))
-#endif
-#define IS_STACK_DIR_UPPER() STACK_DIR_UPPER(1,0)
-
-const char *rb_obj_info(VALUE obj);
-const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
-
-size_t rb_size_pool_slot_size(unsigned char pool_id);
struct rb_execution_context_struct; /* in vm_core.h */
struct rb_objspace; /* in vm_core.h */
@@ -131,22 +21,28 @@ struct rb_objspace; /* in vm_core.h */
#ifdef NEWOBJ_OF
# undef NEWOBJ_OF
# undef RB_NEWOBJ_OF
+# undef RB_OBJ_WRITE
#endif
-#define NEWOBJ_OF_0(var, T, c, f, s, ec) \
- T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
- rb_wb_protected_newobj_of(GET_EC(), (c), (f) & ~FL_WB_PROTECTED, s) : \
- rb_wb_unprotected_newobj_of((c), (f), s))
-#define NEWOBJ_OF_ec(var, T, c, f, s, ec) \
- T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
- rb_wb_protected_newobj_of((ec), (c), (f) & ~FL_WB_PROTECTED, s) : \
- rb_wb_unprotected_newobj_of((c), (f), s))
+#define RVALUE_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]))
+
+#define RB_RVARGC_NEWOBJ_OF(var, T, c, f, s) \
+ T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
+ rb_wb_protected_newobj_of((c), (f) & ~FL_WB_PROTECTED, s) : \
+ rb_wb_unprotected_newobj_of((c), (f), s))
+
+#define RB_RVARGC_EC_NEWOBJ_OF(ec, var, T, c, f, s) \
+ T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
+ rb_ec_wb_protected_newobj_of((ec), (c), (f) & ~FL_WB_PROTECTED, s) : \
+ rb_wb_unprotected_newobj_of((c), (f), s))
-#define NEWOBJ_OF(var, T, c, f, s, ec) \
- NEWOBJ_OF_HELPER(ec)(var, T, c, f, s, ec)
+/* optimized version of NEWOBJ() */
+#define RB_NEWOBJ_OF(var, T, c, f) RB_RVARGC_NEWOBJ_OF(var, T, c, f, RVALUE_SIZE)
-#define NEWOBJ_OF_HELPER(ec) NEWOBJ_OF_ ## ec
+#define RB_EC_NEWOBJ_OF(ec, var, T, c, f) RB_RVARGC_EC_NEWOBJ_OF(ec, var, T, c, f, RVALUE_SIZE)
+#define NEWOBJ_OF(var, T, c, f) RB_NEWOBJ_OF((var), T, (c), (f))
+#define RVARGC_NEWOBJ_OF(var, T, c, f, s) RB_RVARGC_NEWOBJ_OF((var), T, (c), (f), (s))
#define RB_OBJ_GC_FLAGS_MAX 6 /* used in ext/objspace */
#ifndef USE_UNALIGNED_MEMBER_ACCESS
@@ -164,41 +60,22 @@ struct rb_objspace; /* in vm_core.h */
COMPILER_WARNING_POP; \
unaligned_member_access_result; \
})
-
-# define UNALIGNED_MEMBER_PTR(ptr, mem) __extension__({ \
- COMPILER_WARNING_PUSH; \
- COMPILER_WARNING_IGNORED(-Waddress-of-packed-member); \
- const volatile void *unaligned_member_ptr_result = &(ptr)->mem; \
- COMPILER_WARNING_POP; \
- (__typeof__((ptr)->mem) *)unaligned_member_ptr_result; \
-})
-#endif
-
-#ifndef UNALIGNED_MEMBER_PTR
-# define UNALIGNED_MEMBER_PTR(ptr, mem) UNALIGNED_MEMBER_ACCESS(&(ptr)->mem)
#endif
-#define RB_OBJ_WRITE_UNALIGNED(old, slot, young) do { \
- VALUE *_slot = UNALIGNED_MEMBER_ACCESS(slot); \
- RB_OBJ_WRITE(old, _slot, young); \
-} while (0)
+#define UNALIGNED_MEMBER_PTR(ptr, mem) UNALIGNED_MEMBER_ACCESS(&(ptr)->mem)
+#define RB_OBJ_WRITE(a, slot, b) \
+ rb_obj_write((VALUE)(a), UNALIGNED_MEMBER_ACCESS((VALUE *)(slot)), \
+ (VALUE)(b), __FILE__, __LINE__)
// We use SIZE_POOL_COUNT number of shape IDs for transitions out of different size pools
-// The next available shape ID will be the SPECIAL_CONST_SHAPE_ID
-#ifndef SIZE_POOL_COUNT
+// The next available shapd ID will be the SPECIAL_CONST_SHAPE_ID
+#if USE_RVARGC && (SIZEOF_UINT64_T == SIZEOF_VALUE)
# define SIZE_POOL_COUNT 5
+#else
+# define SIZE_POOL_COUNT 1
#endif
-/* Used in places that could malloc during, which can cause the GC to run. We
- * need to temporarily disable the GC to allow the malloc to happen.
- * Allocating memory during GC is a bad idea, so use this only when absolutely
- * necessary. */
-#define DURING_GC_COULD_MALLOC_REGION_START() \
- assert(rb_during_gc()); \
- VALUE _already_disabled = rb_gc_disable_no_rest()
-
-#define DURING_GC_COULD_MALLOC_REGION_END() \
- if (_already_disabled == Qfalse) rb_gc_enable()
+#define RCLASS_EXT_EMBEDDED (SIZE_POOL_COUNT > 1)
typedef struct ractor_newobj_size_pool_cache {
struct RVALUE *freelist;
@@ -215,7 +92,6 @@ extern VALUE *ruby_initial_gc_stress_ptr;
extern int ruby_disable_gc;
RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size);
void ruby_mimfree(void *ptr);
-void rb_gc_prepare_heap(void);
void rb_objspace_set_event_hook(const rb_event_flag_t event);
VALUE rb_objspace_gc_enable(struct rb_objspace *);
VALUE rb_objspace_gc_disable(struct rb_objspace *);
@@ -227,7 +103,6 @@ __attribute__((__alloc_align__(1)))
RUBY_ATTR_MALLOC void *rb_aligned_malloc(size_t, size_t) RUBY_ATTR_ALLOC_SIZE((2));
size_t rb_size_mul_or_raise(size_t, size_t, VALUE); /* used in compile.c */
size_t rb_size_mul_add_or_raise(size_t, size_t, size_t, VALUE); /* used in iseq.h */
-size_t rb_malloc_grow_capa(size_t current_capacity, size_t type_size);
RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add(size_t, size_t, size_t);
RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add(size_t, size_t, size_t);
void *rb_xrealloc_mul_add(const void *, size_t, size_t, size_t);
@@ -241,61 +116,28 @@ void rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache);
size_t rb_gc_obj_slot_size(VALUE obj);
bool rb_gc_size_allocatable_p(size_t size);
int rb_objspace_garbage_object_p(VALUE obj);
-bool rb_gc_is_ptr_to_obj(void *ptr);
-VALUE rb_gc_id2ref_obj_tbl(VALUE objid);
-VALUE rb_define_finalizer_no_check(VALUE obj, VALUE block);
-
-void rb_gc_mark_and_move(VALUE *ptr);
-
-void rb_gc_mark_weak(VALUE *ptr);
-void rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr);
-
-#define rb_gc_mark_and_move_ptr(ptr) do { \
- VALUE _obj = (VALUE)*(ptr); \
- rb_gc_mark_and_move(&_obj); \
- if (_obj != (VALUE)*(ptr)) *(ptr) = (void *)_obj; \
-} while (0)
RUBY_SYMBOL_EXPORT_BEGIN
-/* exports for objspace module */
-size_t rb_objspace_data_type_memsize(VALUE obj);
-void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
-void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *data);
-int rb_objspace_markable_object_p(VALUE obj);
-int rb_objspace_internal_object_p(VALUE obj);
-int rb_objspace_marked_object_p(VALUE obj);
-
-void rb_objspace_each_objects(
- int (*callback)(void *start, void *end, size_t stride, void *data),
- void *data);
-
-void rb_objspace_each_objects_without_setup(
- int (*callback)(void *, void *, size_t, void *),
- void *data);
-
-size_t rb_gc_obj_slot_size(VALUE obj);
-
-VALUE rb_gc_disable_no_rest(void);
-
-
/* gc.c (export) */
const char *rb_objspace_data_type_name(VALUE obj);
-VALUE rb_wb_protected_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, size_t);
+VALUE rb_wb_protected_newobj_of(VALUE, VALUE, size_t);
VALUE rb_wb_unprotected_newobj_of(VALUE, VALUE, size_t);
+VALUE rb_ec_wb_protected_newobj_of(struct rb_execution_context_struct *ec, VALUE klass, VALUE flags, size_t);
size_t rb_obj_memsize_of(VALUE);
void rb_gc_verify_internal_consistency(void);
size_t rb_obj_gc_flags(VALUE, ID[], size_t);
void rb_gc_mark_values(long n, const VALUE *values);
void rb_gc_mark_vm_stack_values(long n, const VALUE *values);
-void rb_gc_update_values(long n, VALUE *values);
void *ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2));
void *ruby_sized_xrealloc2(void *ptr, size_t new_count, size_t element_size, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3));
void ruby_sized_xfree(void *x, size_t size);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_ec_stack_check(struct rb_execution_context_struct *ec);
void rb_gc_writebarrier_remember(VALUE obj);
const char *rb_obj_info(VALUE obj);
+MJIT_SYMBOL_EXPORT_END
#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32)
@@ -319,12 +161,6 @@ ruby_sized_xfree_inlined(void *ptr, size_t size)
# define SIZED_REALLOC_N(x, y, z, w) REALLOC_N(x, y, z)
-static inline void *
-ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count)
-{
- return ruby_xrealloc2(ptr, new_count, element_size);
-}
-
#else
static inline void *
@@ -348,12 +184,6 @@ ruby_sized_xfree_inlined(void *ptr, size_t size)
# define SIZED_REALLOC_N(v, T, m, n) \
((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n)))
-static inline void *
-ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count)
-{
- return ruby_sized_xrealloc2(ptr, new_count, element_size, old_count);
-}
-
#endif /* HAVE_MALLOC_USABLE_SIZE */
#define ruby_sized_xrealloc ruby_sized_xrealloc_inlined
diff --git a/internal/hash.h b/internal/hash.h
index fe859cb716..64832c9610 100644
--- a/internal/hash.h
+++ b/internal/hash.h
@@ -28,6 +28,10 @@ enum ruby_rhash_flags {
RHASH_AR_TABLE_BOUND_MASK = (FL_USER8|FL_USER9|FL_USER10|FL_USER11), /* FL 8..11 */
RHASH_AR_TABLE_BOUND_SHIFT = (FL_USHIFT+8),
+#if USE_TRANSIENT_HEAP
+ RHASH_TRANSIENT_FLAG = FL_USER12, /* FL 12 */
+#endif
+
// we can not put it in "enum" because it can exceed "int" range.
#define RHASH_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \
FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19)
@@ -36,23 +40,17 @@ enum ruby_rhash_flags {
RHASH_LEV_MAX = 127, /* 7 bits */
};
-typedef struct ar_table_pair_struct {
- VALUE key;
- VALUE val;
-} ar_table_pair;
-
-typedef struct ar_table_struct {
+struct RHash {
+ struct RBasic basic;
+ union {
+ st_table *st;
+ struct ar_table_struct *ar; /* possibly 0 */
+ } as;
+ const VALUE ifnone;
union {
ar_hint_t ary[RHASH_AR_TABLE_MAX_SIZE];
VALUE word;
} ar_hint;
- /* 64bit CPU: 8B * 2 * 8 = 128B */
- ar_table_pair pairs[RHASH_AR_TABLE_MAX_SIZE];
-} ar_table;
-
-struct RHash {
- struct RBasic basic;
- const VALUE ifnone;
};
#define RHASH(obj) ((struct RHash *)(obj))
@@ -76,7 +74,6 @@ VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
long rb_dbl_long_hash(double d);
st_table *rb_init_identtable(void);
st_index_t rb_any_hash(VALUE a);
-int rb_any_cmp(VALUE a, VALUE b);
VALUE rb_to_hash_type(VALUE obj);
VALUE rb_hash_key_str(VALUE);
VALUE rb_hash_values(VALUE hash);
@@ -86,8 +83,8 @@ VALUE rb_hash_set_pair(VALUE hash, VALUE pair);
int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg);
int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg);
+extern st_table *rb_hash_st_table(VALUE hash);
VALUE rb_ident_hash_new_with_size(st_index_t size);
-void rb_hash_free(VALUE hash);
static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h);
static inline VALUE RHASH_IFNONE(VALUE h);
@@ -99,6 +96,9 @@ static inline struct ar_table_struct *RHASH_AR_TABLE(VALUE h);
static inline st_table *RHASH_ST_TABLE(VALUE h);
static inline size_t RHASH_ST_SIZE(VALUE h);
static inline void RHASH_ST_CLEAR(VALUE h);
+static inline bool RHASH_TRANSIENT_P(VALUE h);
+static inline void RHASH_SET_TRANSIENT_FLAG(VALUE h);
+static inline void RHASH_UNSET_TRANSIENT_FLAG(VALUE h);
RUBY_SYMBOL_EXPORT_BEGIN
/* hash.c (export) */
@@ -107,6 +107,7 @@ VALUE rb_ident_hash_new(void);
int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_hash_new_with_size(st_index_t size);
VALUE rb_hash_resurrect(VALUE hash);
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
@@ -116,29 +117,54 @@ VALUE rb_hash_compare_by_id_p(VALUE hash);
st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line);
#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__)
+MJIT_SYMBOL_EXPORT_END
VALUE rb_hash_compare_by_id(VALUE hash);
+#if 0 /* for debug */
+
+static inline bool
+RHASH_AR_TABLE_P(VALUE h)
+{
+ extern int rb_hash_ar_table_p(VALUE hash);
+ return rb_hash_ar_table_p(h)
+}
+
+static inline struct ar_table_struct *
+RHASH_AR_TABLE(VALUE h)
+{
+ extern struct ar_table_struct *rb_hash_ar_table(VALUE hash);
+ return rb_hash_ar_table(h)
+}
+
+static inline st_table *
+RHASH_ST_TABLE(VALUE h)
+{
+ return rb_hash_st_table(h)
+}
+
+#else
+
static inline bool
RHASH_AR_TABLE_P(VALUE h)
{
return ! FL_TEST_RAW(h, RHASH_ST_TABLE_FLAG);
}
-RBIMPL_ATTR_RETURNS_NONNULL()
static inline struct ar_table_struct *
RHASH_AR_TABLE(VALUE h)
{
- return (struct ar_table_struct *)((uintptr_t)h + sizeof(struct RHash));
+ return RHASH(h)->as.ar;
}
-RBIMPL_ATTR_RETURNS_NONNULL()
static inline st_table *
RHASH_ST_TABLE(VALUE h)
{
- return (st_table *)((uintptr_t)h + sizeof(struct RHash));
+ return RHASH(h)->as.st;
}
+#endif
+
static inline VALUE
RHASH_IFNONE(VALUE h)
{
@@ -177,7 +203,8 @@ RHASH_ST_SIZE(VALUE h)
static inline void
RHASH_ST_CLEAR(VALUE h)
{
- memset(RHASH_ST_TABLE(h), 0, sizeof(st_table));
+ FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG);
+ RHASH(h)->as.ar = NULL;
}
static inline unsigned
@@ -188,4 +215,30 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h)
return (unsigned)ret;
}
+static inline bool
+RHASH_TRANSIENT_P(VALUE h)
+{
+#if USE_TRANSIENT_HEAP
+ return FL_TEST_RAW(h, RHASH_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+static inline void
+RHASH_SET_TRANSIENT_FLAG(VALUE h)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(h, RHASH_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+RHASH_UNSET_TRANSIENT_FLAG(VALUE h)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(h, RHASH_TRANSIENT_FLAG);
+#endif
+}
+
#endif /* INTERNAL_HASH_H */
diff --git a/internal/imemo.h b/internal/imemo.h
index 65335285ab..91b524e0a6 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -11,6 +11,7 @@
#include "ruby/internal/config.h"
#include <stddef.h> /* for size_t */
#include "internal/array.h" /* for rb_ary_hidden_new_fill */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for rb_block_call_func_t */
@@ -82,7 +83,7 @@ struct vm_ifunc_argc {
/*! IFUNC (Internal FUNCtion) */
struct vm_ifunc {
VALUE flags;
- VALUE *svar_lep;
+ VALUE reserved;
rb_block_call_func_t func;
const void *data;
struct vm_ifunc_argc argc;
@@ -129,6 +130,7 @@ struct MEMO {
typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
rb_imemo_tmpbuf_t *rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt);
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
+void rb_strterm_mark(VALUE obj);
static inline enum imemo_type imemo_type(VALUE imemo);
static inline int imemo_type_p(VALUE imemo, enum imemo_type imemo_type);
static inline bool imemo_throw_data_p(VALUE imemo);
diff --git a/internal/io.h b/internal/io.h
index f16d9efc9c..b5f15499d7 100644
--- a/internal/io.h
+++ b/internal/io.h
@@ -9,107 +9,8 @@
* @brief Internal header for IO.
*/
#include "ruby/ruby.h" /* for VALUE */
-
-#define HAVE_RB_IO_T
-struct rb_io;
-
#include "ruby/io.h" /* for rb_io_t */
-/** Ruby's IO, metadata and buffers. */
-struct rb_io {
-
- /** The IO's Ruby level counterpart. */
- VALUE self;
-
- /** stdio ptr for read/write, if available. */
- FILE *stdio_file;
-
- /** file descriptor. */
- int fd;
-
- /** mode flags: FMODE_XXXs */
- int mode;
-
- /** child's pid (for pipes) */
- rb_pid_t pid;
-
- /** number of lines read */
- int lineno;
-
- /** pathname for file */
- VALUE pathv;
-
- /** finalize proc */
- void (*finalize)(struct rb_io*,int);
-
- /** Write buffer. */
- rb_io_buffer_t wbuf;
-
- /**
- * (Byte) read buffer. Note also that there is a field called
- * ::rb_io_t::cbuf, which also concerns read IO.
- */
- rb_io_buffer_t rbuf;
-
- /**
- * Duplex IO object, if set.
- *
- * @see rb_io_set_write_io()
- */
- VALUE tied_io_for_writing;
-
- struct rb_io_encoding encs; /**< Decomposed encoding flags. */
-
- /** Encoding converter used when reading from this IO. */
- rb_econv_t *readconv;
-
- /**
- * rb_io_ungetc() destination. This buffer is read before checking
- * ::rb_io_t::rbuf
- */
- rb_io_buffer_t cbuf;
-
- /** Encoding converter used when writing to this IO. */
- rb_econv_t *writeconv;
-
- /**
- * This is, when set, an instance of ::rb_cString which holds the "common"
- * encoding. Write conversion can convert strings twice... In case
- * conversion from encoding X to encoding Y does not exist, Ruby finds an
- * encoding Z that bridges the two, so that X to Z to Y conversion happens.
- */
- VALUE writeconv_asciicompat;
-
- /** Whether ::rb_io_t::writeconv is already set up. */
- int writeconv_initialized;
-
- /**
- * Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before
- * initialising ::rb_io_t::writeconv.
- */
- int writeconv_pre_ecflags;
-
- /**
- * Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising
- * ::rb_io_t::writeconv.
- */
- VALUE writeconv_pre_ecopts;
-
- /**
- * This is a Ruby level mutex. It avoids multiple threads to write to an
- * IO at once; helps for instance rb_io_puts() to ensure newlines right
- * next to its arguments.
- *
- * This of course doesn't help inter-process IO interleaves, though.
- */
- VALUE write_lock;
-
- /**
- * The timeout associated with this IO when performing blocking operations.
- */
- VALUE timeout;
-};
-
/* io.c */
void ruby_set_inplace_mode(const char *);
void rb_stdio_set_default_encoding(void);
diff --git a/internal/numeric.h b/internal/numeric.h
index f7b8d0ad2d..89bc54b307 100644
--- a/internal/numeric.h
+++ b/internal/numeric.h
@@ -111,6 +111,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
/* numeric.c (export) */
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_flo_div_flo(VALUE x, VALUE y);
double ruby_float_mod(double x, double y);
VALUE rb_float_equal(VALUE x, VALUE y);
@@ -124,6 +125,7 @@ VALUE rb_int_abs(VALUE num);
VALUE rb_int_bit_length(VALUE num);
VALUE rb_int_uminus(VALUE num);
VALUE rb_int_comp(VALUE num);
+MJIT_SYMBOL_EXPORT_END
static inline bool
INT_POSITIVE_P(VALUE num)
diff --git a/internal/object.h b/internal/object.h
index 58e989562a..7b54e13dd2 100644
--- a/internal/object.h
+++ b/internal/object.h
@@ -27,6 +27,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
int rb_opts_exception_p(VALUE opts, int default_value);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
CONSTFUNC(VALUE rb_obj_equal(VALUE obj1, VALUE obj2));
CONSTFUNC(VALUE rb_obj_not(VALUE obj));
VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
@@ -35,6 +36,7 @@ VALUE rb_false(VALUE obj);
VALUE rb_convert_type_with_id(VALUE v, int t, const char* nam, ID mid);
VALUE rb_obj_size(VALUE self, VALUE args, VALUE obj);
VALUE rb_get_freeze_opt(int argc, VALUE *argv);
+MJIT_SYMBOL_EXPORT_END
static inline void
RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass)
diff --git a/internal/parse.h b/internal/parse.h
index bd6d295be1..f242c384ad 100644
--- a/internal/parse.h
+++ b/internal/parse.h
@@ -8,101 +8,18 @@
* file COPYING are met. Consult the file for details.
* @brief Internal header for the parser.
*/
-#include <limits.h>
-#include "rubyparser.h"
-#include "internal/static_assert.h"
-
-#ifdef UNIVERSAL_PARSER
-#define rb_encoding void
-#endif
-
+#include "ruby/ruby.h" /* for VALUE */
struct rb_iseq_struct; /* in vm_core.h */
-#define STRTERM_HEREDOC IMEMO_FL_USER0
-
-/* structs for managing terminator of string literal and heredocment */
-typedef struct rb_strterm_literal_struct {
- long nest;
- int func; /* STR_FUNC_* (e.g., STR_FUNC_ESCAPE and STR_FUNC_EXPAND) */
- int paren; /* '(' of `%q(...)` */
- int term; /* ')' of `%q(...)` */
-} rb_strterm_literal_t;
-
-typedef struct rb_strterm_heredoc_struct {
- VALUE lastline; /* the string of line that contains `<<"END"` */
- long offset; /* the column of END in `<<"END"` */
- int sourceline; /* lineno of the line that contains `<<"END"` */
- unsigned length; /* the length of END in `<<"END"` */
- uint8_t quote;
- uint8_t func;
-} rb_strterm_heredoc_t;
-
-#define HERETERM_LENGTH_MAX UINT_MAX
-
-typedef struct rb_strterm_struct {
- VALUE flags;
- union {
- rb_strterm_literal_t literal;
- rb_strterm_heredoc_t heredoc;
- } u;
-} rb_strterm_t;
-
/* parse.y */
-void rb_ruby_parser_mark(void *ptr);
-size_t rb_ruby_parser_memsize(const void *ptr);
-
-void rb_ruby_parser_set_options(rb_parser_t *p, int print, int loop, int chomp, int split);
-rb_parser_t *rb_ruby_parser_set_context(rb_parser_t *p, const struct rb_iseq_struct *base, int main);
-void rb_ruby_parser_set_script_lines(rb_parser_t *p, VALUE lines_array);
-void rb_ruby_parser_error_tolerant(rb_parser_t *p);
-rb_ast_t* rb_ruby_parser_compile_file_path(rb_parser_t *p, VALUE fname, VALUE file, int start);
-void rb_ruby_parser_keep_tokens(rb_parser_t *p);
-rb_ast_t* rb_ruby_parser_compile_generic(rb_parser_t *p, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start);
-rb_ast_t* rb_ruby_parser_compile_string_path(rb_parser_t *p, VALUE f, VALUE s, int line);
+VALUE rb_parser_set_yydebug(VALUE, VALUE);
+void *rb_parser_load_file(VALUE parser, VALUE name);
+void rb_parser_keep_script_lines(VALUE vparser);
+void rb_parser_error_tolerant(VALUE vparser);
+void rb_parser_keep_tokens(VALUE vparser);
RUBY_SYMBOL_EXPORT_BEGIN
-
-VALUE rb_ruby_parser_encoding(rb_parser_t *p);
-int rb_ruby_parser_end_seen_p(rb_parser_t *p);
-int rb_ruby_parser_set_yydebug(rb_parser_t *p, int flag);
-
+VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int);
RUBY_SYMBOL_EXPORT_END
-int rb_reg_named_capture_assign_iter_impl(struct parser_params *p, const char *s, long len, rb_encoding *enc, NODE **succ_block, const rb_code_location_t *loc);
-
-#ifdef RIPPER
-void ripper_parser_mark(void *ptr);
-void ripper_parser_free(void *ptr);
-size_t ripper_parser_memsize(const void *ptr);
-void ripper_error(struct parser_params *p);
-VALUE ripper_value(struct parser_params *p);
-int rb_ruby_parser_get_yydebug(rb_parser_t *p);
-void rb_ruby_parser_set_value(rb_parser_t *p, VALUE value);
-int rb_ruby_parser_error_p(rb_parser_t *p);
-VALUE rb_ruby_parser_debug_output(rb_parser_t *p);
-void rb_ruby_parser_set_debug_output(rb_parser_t *p, VALUE output);
-VALUE rb_ruby_parser_parsing_thread(rb_parser_t *p);
-void rb_ruby_parser_set_parsing_thread(rb_parser_t *p, VALUE parsing_thread);
-void rb_ruby_parser_ripper_initialize(rb_parser_t *p, VALUE (*gets)(struct parser_params*,VALUE), VALUE input, VALUE sourcefile_string, const char *sourcefile, int sourceline);
-VALUE rb_ruby_parser_result(rb_parser_t *p);
-rb_encoding *rb_ruby_parser_enc(rb_parser_t *p);
-VALUE rb_ruby_parser_ruby_sourcefile_string(rb_parser_t *p);
-int rb_ruby_parser_ruby_sourceline(rb_parser_t *p);
-int rb_ruby_parser_lex_state(rb_parser_t *p);
-void rb_ruby_ripper_parse0(rb_parser_t *p);
-int rb_ruby_ripper_dedent_string(rb_parser_t *p, VALUE string, int width);
-VALUE rb_ruby_ripper_lex_get_str(rb_parser_t *p, VALUE s);
-int rb_ruby_ripper_initialized_p(rb_parser_t *p);
-void rb_ruby_ripper_parser_initialize(rb_parser_t *p);
-long rb_ruby_ripper_column(rb_parser_t *p);
-long rb_ruby_ripper_token_len(rb_parser_t *p);
-VALUE rb_ruby_ripper_lex_lastline(rb_parser_t *p);
-VALUE rb_ruby_ripper_lex_state_name(struct parser_params *p, int state);
-struct parser_params *rb_ruby_ripper_parser_allocate(void);
-#endif
-
-#ifdef UNIVERSAL_PARSER
-#undef rb_encoding
-#endif
-
#endif /* INTERNAL_PARSE_H */
diff --git a/internal/proc.h b/internal/proc.h
index c75f15b283..2416c31e14 100644
--- a/internal/proc.h
+++ b/internal/proc.h
@@ -22,9 +22,11 @@ int rb_block_min_max_arity(int *max);
VALUE rb_block_to_s(VALUE self, const struct rb_block *block, const char *additional_info);
VALUE rb_callable_receiver(VALUE);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_func_proc_new(rb_block_call_func_t func, VALUE val);
VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc);
VALUE rb_iseq_location(const struct rb_iseq_struct *iseq);
VALUE rb_sym_to_proc(VALUE sym);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_PROC_H */
diff --git a/internal/process.h b/internal/process.h
index fd4994cb4b..ceadfdcbbb 100644
--- a/internal/process.h
+++ b/internal/process.h
@@ -20,8 +20,8 @@
#endif
#include "ruby/ruby.h" /* for VALUE */
-#include "internal/compilers.h" /* for __has_warning */
#include "internal/imemo.h" /* for RB_IMEMO_TMPBUF_PTR */
+#include "internal/warnings.h" /* for COMPILER_WARNING_PUSH */
#define RB_MAX_GROUPS (65536)
@@ -121,4 +121,17 @@ ARGVSTR2ARGC(VALUE argv_str)
return i - 1;
}
+#ifdef HAVE_WORKING_FORK
+COMPILER_WARNING_PUSH
+#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
+COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
+#endif
+static inline rb_pid_t
+rb_fork(void)
+{
+ return fork();
+}
+COMPILER_WARNING_POP
+#endif
+
#endif /* INTERNAL_PROCESS_H */
diff --git a/internal/range.h b/internal/range.h
index 2394937bf8..8daba0ecab 100644
--- a/internal/range.h
+++ b/internal/range.h
@@ -24,13 +24,13 @@ RANGE_BEG(VALUE r)
static inline VALUE
RANGE_END(VALUE r)
{
- return RSTRUCT_GET(r, 1);
+ return RSTRUCT(r)->as.ary[1];
}
static inline VALUE
RANGE_EXCL(VALUE r)
{
- return RSTRUCT_GET(r, 2);
+ return RSTRUCT(r)->as.ary[2];
}
VALUE
diff --git a/internal/rational.h b/internal/rational.h
index f11fab4583..61ddbf089a 100644
--- a/internal/rational.h
+++ b/internal/rational.h
@@ -10,6 +10,7 @@
*/
#include "ruby/internal/config.h" /* for HAVE_LIBGMP */
#include "ruby/ruby.h" /* for struct RBasic */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "internal/numeric.h" /* for INT_POSITIVE_P */
#include "ruby_assert.h" /* for assert */
diff --git a/internal/re.h b/internal/re.h
index 3e20114665..8b31b3d8a5 100644
--- a/internal/re.h
+++ b/internal/re.h
@@ -22,7 +22,9 @@ VALUE rb_reg_equal(VALUE re1, VALUE re2);
void rb_backref_set_string(VALUE string, long pos, long len);
void rb_match_unbusy(VALUE);
int rb_match_count(VALUE match);
+int rb_match_nth_defined(int nth, VALUE match);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_reg_new_ary(VALUE ary, int options);
-VALUE rb_reg_last_defined(VALUE match);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_RE_H */
diff --git a/internal/ruby_parser.h b/internal/ruby_parser.h
deleted file mode 100644
index 6beb2808ab..0000000000
--- a/internal/ruby_parser.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef INTERNAL_RUBY_PARSE_H
-#define INTERNAL_RUBY_PARSE_H
-
-#include "internal.h"
-#include "internal/imemo.h"
-#include "rubyparser.h"
-#include "vm.h"
-
-RUBY_SYMBOL_EXPORT_BEGIN
-#ifdef UNIVERSAL_PARSER
-void rb_parser_config_initialize(rb_parser_config_t *config);
-#endif
-VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int);
-VALUE rb_parser_new(void);
-rb_ast_t *rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line);
-RUBY_SYMBOL_EXPORT_END
-
-VALUE rb_parser_end_seen_p(VALUE);
-VALUE rb_parser_encoding(VALUE);
-VALUE rb_parser_set_yydebug(VALUE, VALUE);
-void rb_parser_set_options(VALUE, int, int, int, int);
-void *rb_parser_load_file(VALUE parser, VALUE name);
-void rb_parser_set_script_lines(VALUE vparser, VALUE lines_array);
-void rb_parser_error_tolerant(VALUE vparser);
-void rb_parser_keep_tokens(VALUE vparser);
-
-rb_ast_t *rb_parser_compile_string(VALUE, const char*, VALUE, int);
-rb_ast_t *rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE input, int line);
-rb_ast_t *rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int line);
-
-enum lex_state_bits {
- EXPR_BEG_bit, /* ignore newline, +/- is a sign. */
- EXPR_END_bit, /* newline significant, +/- is an operator. */
- EXPR_ENDARG_bit, /* ditto, and unbound braces. */
- EXPR_ENDFN_bit, /* ditto, and unbound braces. */
- EXPR_ARG_bit, /* newline significant, +/- is an operator. */
- EXPR_CMDARG_bit, /* newline significant, +/- is an operator. */
- EXPR_MID_bit, /* newline significant, +/- is an operator. */
- EXPR_FNAME_bit, /* ignore newline, no reserved words. */
- EXPR_DOT_bit, /* right after `.', `&.' or `::', no reserved words. */
- EXPR_CLASS_bit, /* immediate after `class', no here document. */
- EXPR_LABEL_bit, /* flag bit, label is allowed. */
- EXPR_LABELED_bit, /* flag bit, just after a label. */
- EXPR_FITEM_bit, /* symbol literal as FNAME. */
- EXPR_MAX_STATE
-};
-/* examine combinations */
-enum lex_state_e {
-#define DEF_EXPR(n) EXPR_##n = (1 << EXPR_##n##_bit)
- DEF_EXPR(BEG),
- DEF_EXPR(END),
- DEF_EXPR(ENDARG),
- DEF_EXPR(ENDFN),
- DEF_EXPR(ARG),
- DEF_EXPR(CMDARG),
- DEF_EXPR(MID),
- DEF_EXPR(FNAME),
- DEF_EXPR(DOT),
- DEF_EXPR(CLASS),
- DEF_EXPR(LABEL),
- DEF_EXPR(LABELED),
- DEF_EXPR(FITEM),
- EXPR_VALUE = EXPR_BEG,
- EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS),
- EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG),
- EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN),
- EXPR_NONE = 0
-};
-#endif /* INTERNAL_RUBY_PARSE_H */
diff --git a/internal/sanitizers.h b/internal/sanitizers.h
index 7b7d166c74..6e2d81137f 100644
--- a/internal/sanitizers.h
+++ b/internal/sanitizers.h
@@ -89,6 +89,8 @@
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
#endif
+#ifndef MJIT_HEADER
+
/*!
* This function asserts that a (continuous) memory region from ptr to size
* being "poisoned". Both read / write access to such memory region are
@@ -183,4 +185,6 @@ asan_unpoison_object(VALUE obj, bool newobj_p)
asan_unpoison_memory_region(ptr, SIZEOF_VALUE, newobj_p);
}
+#endif /* MJIT_HEADER */
+
#endif /* INTERNAL_SANITIZERS_H */
diff --git a/internal/signal.h b/internal/signal.h
index 660cd95f78..86fb54e949 100644
--- a/internal/signal.h
+++ b/internal/signal.h
@@ -13,10 +13,6 @@
extern int ruby_enable_coredump;
int rb_get_next_signal(void);
-#ifdef POSIX_SIGNAL
-void (*ruby_posix_signal(int, void (*)(int)))(int);
-#endif
-
RUBY_SYMBOL_EXPORT_BEGIN
/* signal.c (export) */
int rb_grantpt(int fd);
diff --git a/internal/string.h b/internal/string.h
index abb0a536ad..12edbff2b1 100644
--- a/internal/string.h
+++ b/internal/string.h
@@ -67,6 +67,7 @@ bool rb_str_reembeddable_p(VALUE);
void rb_str_update_shared_ary(VALUE str, VALUE old_root, VALUE new_root);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_fstring_new(const char *ptr, long len);
VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
VALUE rb_str_opt_plus(VALUE x, VALUE y);
@@ -77,6 +78,7 @@ VALUE rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE
struct rb_execution_context_struct;
VALUE rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str);
+MJIT_SYMBOL_EXPORT_END
#define rb_fstring_lit(str) rb_fstring_new((str), rb_strlen_lit(str))
#define rb_fstring_literal(str) rb_fstring_lit(str)
@@ -119,21 +121,6 @@ is_broken_string(VALUE str)
return rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN;
}
-static inline bool
-at_char_boundary(const char *s, const char *p, const char *e, rb_encoding *enc)
-{
- return rb_enc_left_char_head(s, p, e, enc) == p;
-}
-
-static inline bool
-at_char_right_boundary(const char *s, const char *p, const char *e, rb_encoding *enc)
-{
- RUBY_ASSERT(s <= p);
- RUBY_ASSERT(p <= e);
-
- return rb_enc_right_char_head(s, p, e, enc) == p;
-}
-
/* expect tail call optimization */
// YJIT needs this function to never allocate and never raise
static inline VALUE
diff --git a/internal/struct.h b/internal/struct.h
index 6da5bad10a..8acc00ec3c 100644
--- a/internal/struct.h
+++ b/internal/struct.h
@@ -9,12 +9,14 @@
* @brief Internal header for Struct.
*/
#include "ruby/internal/stdbool.h" /* for bool */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "ruby/ruby.h" /* for struct RBasic */
enum {
- RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 |
- RUBY_FL_USER3 | RUBY_FL_USER2 | RUBY_FL_USER1,
+ RSTRUCT_EMBED_LEN_MAX = RVALUE_EMBED_LEN_MAX,
+ RSTRUCT_EMBED_LEN_MASK = (RUBY_FL_USER2|RUBY_FL_USER1),
RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1),
+ RSTRUCT_TRANSIENT_FLAG = FL_USER3,
};
struct RStruct {
@@ -24,12 +26,7 @@ struct RStruct {
long len;
const VALUE *ptr;
} heap;
- /* This is a length 1 array because:
- * 1. GCC has a bug that does not optimize C flexible array members
- * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452)
- * 2. Zero length arrays are not supported by all compilers
- */
- const VALUE ary[1];
+ const VALUE ary[RSTRUCT_EMBED_LEN_MAX];
} as;
};
@@ -60,6 +57,9 @@ VALUE rb_struct_init_copy(VALUE copy, VALUE s);
VALUE rb_struct_lookup(VALUE s, VALUE idx);
VALUE rb_struct_s_keyword_init(VALUE klass);
static inline const VALUE *rb_struct_const_heap_ptr(VALUE st);
+static inline bool RSTRUCT_TRANSIENT_P(VALUE st);
+static inline void RSTRUCT_TRANSIENT_SET(VALUE st);
+static inline void RSTRUCT_TRANSIENT_UNSET(VALUE st);
static inline long RSTRUCT_EMBED_LEN(VALUE st);
static inline long RSTRUCT_LEN(VALUE st);
static inline int RSTRUCT_LENINT(VALUE st);
@@ -67,6 +67,32 @@ static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st);
static inline void RSTRUCT_SET(VALUE st, long k, VALUE v);
static inline VALUE RSTRUCT_GET(VALUE st, long k);
+static inline bool
+RSTRUCT_TRANSIENT_P(VALUE st)
+{
+#if USE_TRANSIENT_HEAP
+ return FL_TEST_RAW(st, RSTRUCT_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+static inline void
+RSTRUCT_TRANSIENT_SET(VALUE st)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(st, RSTRUCT_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+RSTRUCT_TRANSIENT_UNSET(VALUE st)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(st, RSTRUCT_TRANSIENT_FLAG);
+#endif
+}
+
static inline long
RSTRUCT_EMBED_LEN(VALUE st)
{
@@ -120,7 +146,7 @@ RSTRUCT_GET(VALUE st, long k)
static inline const VALUE *
rb_struct_const_heap_ptr(VALUE st)
{
- assert(!FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK));
+ /* TODO: check embed on debug mode */
return RSTRUCT(st)->as.heap.ptr;
}
diff --git a/internal/thread.h b/internal/thread.h
index 647d1c40c5..c3e54de683 100644
--- a/internal/thread.h
+++ b/internal/thread.h
@@ -10,17 +10,9 @@
*/
#include "ruby/ruby.h" /* for VALUE */
#include "ruby/intern.h" /* for rb_blocking_function_t */
-#include "ccan/list/list.h" /* for list in rb_io_close_wait_list */
struct rb_thread_struct; /* in vm_core.h */
-#define RB_VM_SAVE_MACHINE_CONTEXT(th) \
- do { \
- FLUSH_REGISTER_WINDOWS; \
- setjmp((th)->ec->machine.regs); \
- SET_MACHINE_STACK_END(&(th)->ec->machine.stack_end); \
- } while (0)
-
/* thread.c */
#define COVERAGE_INDEX_LINES 0
#define COVERAGE_INDEX_BRANCHES 1
@@ -30,10 +22,6 @@ struct rb_thread_struct; /* in vm_core.h */
#define COVERAGE_TARGET_ONESHOT_LINES 8
#define COVERAGE_TARGET_EVAL 16
-#define RUBY_FATAL_THREAD_KILLED INT2FIX(0)
-#define RUBY_FATAL_THREAD_TERMINATED INT2FIX(1)
-#define RUBY_FATAL_FIBER_KILLED RB_INT2FIX(2)
-
VALUE rb_obj_is_mutex(VALUE obj);
VALUE rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg);
void rb_thread_execute_interrupts(VALUE th);
@@ -50,18 +38,9 @@ void rb_mutex_allow_trap(VALUE self, int val);
VALUE rb_uninterruptible(VALUE (*b_proc)(VALUE), VALUE data);
VALUE rb_mutex_owned_p(VALUE self);
VALUE rb_exec_recursive_outer_mid(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h, ID mid);
-void ruby_mn_threads_params(void);
int rb_thread_wait_for_single_fd(int fd, int events, struct timeval * timeout);
-struct rb_io_close_wait_list {
- struct ccan_list_head pending_fd_users;
- VALUE closing_thread;
- VALUE wakeup_mutex;
-};
-int rb_notify_fd_close(int fd, struct rb_io_close_wait_list *busy);
-void rb_notify_fd_close_wait(struct rb_io_close_wait_list *busy);
-
RUBY_SYMBOL_EXPORT_BEGIN
/* Temporary. This API will be removed (renamed). */
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd);
@@ -70,6 +49,8 @@ VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, in
int ruby_thread_has_gvl_p(void); /* for ext/fiddle/closure.c */
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_threadptr_execute_interrupts(struct rb_thread_struct *th, int blocking_timing);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_THREAD_H */
diff --git a/internal/time.h b/internal/time.h
index a3bf0587ec..e21b3574f6 100644
--- a/internal/time.h
+++ b/internal/time.h
@@ -28,7 +28,10 @@ struct timeval rb_time_timeval(VALUE);
RUBY_SYMBOL_EXPORT_BEGIN
/* time.c (export) */
void ruby_reset_leap_second_info(void);
-void ruby_reset_timezone(void);
+#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY
+RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
+#endif
+void ruby_reset_timezone(const char *);
RUBY_SYMBOL_EXPORT_END
#endif /* INTERNAL_TIME_H */
diff --git a/internal/variable.h b/internal/variable.h
index e7e24d2a15..6dec6a6759 100644
--- a/internal/variable.h
+++ b/internal/variable.h
@@ -15,6 +15,10 @@
#include "ruby/ruby.h" /* for VALUE */
#include "shape.h" /* for rb_shape_t */
+/* global variable */
+
+#define ROBJECT_TRANSIENT_FLAG FL_USER2
+
/* variable.c */
void rb_gc_mark_global_tbl(void);
void rb_gc_update_global_tbl(void);
@@ -28,43 +32,59 @@ rb_gvar_getter_t *rb_gvar_getter_function_of(ID);
rb_gvar_setter_t *rb_gvar_setter_function_of(ID);
void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_);
void rb_gvar_ractor_local(const char *name);
-
-/**
- * Sets the name of a module.
- *
- * Non-permanently named classes can have a temporary name assigned (or
- * cleared). In that case the name will be used for `#inspect` and `#to_s`, and
- * nested classes/modules will be named with the temporary name as a prefix.
- *
- * After the module is assigned to a constant, the temporary name will be
- * discarded, and the name will be computed based on the nesting.
- *
- * @param[in] mod An instance of ::rb_cModule.
- * @param[in] name An instance of ::rb_cString.
- * @retval mod
- */
-VALUE rb_mod_set_temporary_name(VALUE, VALUE);
+static inline bool ROBJ_TRANSIENT_P(VALUE obj);
+static inline void ROBJ_TRANSIENT_SET(VALUE obj);
+static inline void ROBJ_TRANSIENT_UNSET(VALUE obj);
struct gen_ivtbl;
int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl);
int rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg);
-void rb_evict_ivars_to_hash(VALUE obj, rb_shape_t * shape);
RUBY_SYMBOL_EXPORT_BEGIN
/* variable.c (export) */
-void rb_mark_and_update_generic_ivar(VALUE);
+void rb_mark_generic_ivar(VALUE);
void rb_mv_generic_ivar(VALUE src, VALUE dst);
VALUE rb_const_missing(VALUE klass, VALUE name);
int rb_class_ivar_set(VALUE klass, ID vid, VALUE value);
void rb_iv_tbl_copy(VALUE dst, VALUE src);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
VALUE rb_gvar_get(ID);
VALUE rb_gvar_set(ID, VALUE);
VALUE rb_gvar_defined(ID);
void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID);
+rb_shape_t * rb_grow_iv_list(VALUE obj);
void rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize);
+struct gen_ivtbl *rb_ensure_generic_iv_list_size(VALUE obj, rb_shape_t *shape, uint32_t newsize);
attr_index_t rb_obj_ivar_set(VALUE obj, ID id, VALUE val);
+MJIT_SYMBOL_EXPORT_END
+
+static inline bool
+ROBJ_TRANSIENT_P(VALUE obj)
+{
+#if USE_TRANSIENT_HEAP
+ return FL_TEST_RAW(obj, ROBJECT_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+static inline void
+ROBJ_TRANSIENT_SET(VALUE obj)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(obj, ROBJECT_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+ROBJ_TRANSIENT_UNSET(VALUE obj)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(obj, ROBJECT_TRANSIENT_FLAG);
+#endif
+}
#endif /* INTERNAL_VARIABLE_H */
diff --git a/internal/vm.h b/internal/vm.h
index d10c14eb4d..cf245c6579 100644
--- a/internal/vm.h
+++ b/internal/vm.h
@@ -50,15 +50,17 @@ PUREFUNC(VALUE rb_vm_top_self(void));
const void **rb_vm_get_insns_address_table(void);
VALUE rb_source_location(int *pline);
const char *rb_source_location_cstr(int *pline);
-void rb_vm_pop_cfunc_frame(void);
+MJIT_STATIC void rb_vm_pop_cfunc_frame(void);
int rb_vm_add_root_module(VALUE module);
void rb_vm_check_redefinition_by_prepend(VALUE klass);
int rb_vm_check_optimizable_mid(VALUE mid);
VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements);
-VALUE ruby_vm_special_exception_copy(VALUE);
+MJIT_STATIC VALUE ruby_vm_special_exception_copy(VALUE);
PUREFUNC(st_table *rb_vm_fstring_table(void));
-void rb_lastline_set_up(VALUE val, unsigned int up);
+MJIT_SYMBOL_EXPORT_BEGIN
+VALUE vm_exec(struct rb_execution_context_struct *, bool); /* used in JIT-ed code */
+MJIT_SYMBOL_EXPORT_END
/* vm_eval.c */
VALUE rb_current_realfilepath(void);
@@ -78,26 +80,25 @@ VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
VALUE data2);
void rb_check_stack_overflow(void);
-#if USE_YJIT
-/* vm_exec.c */
-extern uint64_t rb_vm_insns_count;
-#endif
-
/* vm_insnhelper.c */
VALUE rb_equal_opt(VALUE obj1, VALUE obj2);
VALUE rb_eql_opt(VALUE obj1, VALUE obj2);
struct rb_iseq_struct;
+MJIT_SYMBOL_EXPORT_BEGIN
const struct rb_callcache *rb_vm_search_method_slowpath(const struct rb_callinfo *ci, VALUE klass);
+MJIT_SYMBOL_EXPORT_END
/* vm_method.c */
struct rb_execution_context_struct;
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv);
+MJIT_SYMBOL_EXPORT_END
void rb_clear_constant_cache(void);
/* vm_dump.c */
-void rb_print_backtrace(FILE *);
+void rb_print_backtrace(void);
/* vm_backtrace.c */
VALUE rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval);
@@ -105,7 +106,7 @@ VALUE rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
VALUE rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec);
VALUE rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec);
VALUE rb_make_backtrace(void);
-void rb_backtrace_print_as_bugreport(FILE*);
+void rb_backtrace_print_as_bugreport(void);
int rb_backtrace_p(VALUE obj);
VALUE rb_backtrace_to_str_ary(VALUE obj);
VALUE rb_backtrace_to_location_ary(VALUE obj);
@@ -114,8 +115,10 @@ int rb_frame_info_p(VALUE obj);
int rb_get_node_id_from_frame_info(VALUE obj);
const struct rb_iseq_struct *rb_get_iseq_from_frame_info(VALUE obj);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
void rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self);
+MJIT_SYMBOL_EXPORT_END
#define RUBY_DTRACE_CREATE_HOOK(name, arg) \
RUBY_DTRACE_HOOK(name##_CREATE, arg)
diff --git a/io.c b/io.c
index 7ded212804..99ec59da29 100644
--- a/io.c
+++ b/io.c
@@ -16,6 +16,11 @@
#include "ruby/fiber/scheduler.h"
#include "ruby/io/buffer.h"
+#ifdef _WIN32
+# include "ruby/ruby.h"
+# include "ruby/io.h"
+#endif
+
#include <ctype.h>
#include <errno.h>
#include <stddef.h>
@@ -170,7 +175,6 @@ off_t __syscall(quad_t number, ...);
#define open rb_w32_uopen
#undef rename
#define rename(f, t) rb_w32_urename((f), (t))
-#include "win32/file.h"
#endif
VALUE rb_cIO;
@@ -217,7 +221,7 @@ struct argf {
long lineno;
VALUE argv;
VALUE inplace;
- struct rb_io_encoding encs;
+ struct rb_io_enc_t encs;
int8_t init_p, next_p, binmode;
};
@@ -521,6 +525,7 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd)
static int io_fflush(rb_io_t *);
static rb_io_t *flush_before_seek(rb_io_t *fptr);
+#define FMODE_PREP (1<<16)
#define FMODE_SIGNAL_ON_EPIPE (1<<17)
#define fptr_signal_on_epipe(fptr) \
@@ -847,12 +852,9 @@ rb_io_timeout(VALUE self)
* timeout = duration -> duration
* timeout = nil -> nil
*
- * Sets the internal timeout to the specified duration or nil. The timeout
+ * Set the internal timeout to the specified duration or nil. The timeout
* applies to all blocking operations where possible.
*
- * When the operation performs longer than the timeout set, IO::TimeoutError
- * is raised.
- *
* This affects the following methods (but is not limited to): #gets, #puts,
* #read, #write, #wait_readable and #wait_writable. This also affects
* blocking socket operations like Socket#accept and Socket#connect.
@@ -1064,24 +1066,20 @@ rb_gc_for_fd(int err)
return 0;
}
-/* try `expr` upto twice while it returns false and `errno`
- * is to GC. Each `errno`s are available as `first_errno` and
- * `retried_errno` respectively */
-#define TRY_WITH_GC(expr) \
- for (int first_errno, retried_errno = 0, retried = 0; \
- (!retried && \
- !(expr) && \
- (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
- (retried_errno = errno, 1)); \
- (void)retried_errno, retried = 1)
-
static int
ruby_dup(int orig)
{
- int fd = -1;
+ int fd;
- TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
- rb_syserr_fail(first_errno, 0);
+ fd = rb_cloexec_dup(orig);
+ if (fd < 0) {
+ int e = errno;
+ if (rb_gc_for_fd(e)) {
+ fd = rb_cloexec_dup(orig);
+ }
+ if (fd < 0) {
+ rb_syserr_fail(e, 0);
+ }
}
rb_update_max_fd(fd);
return fd;
@@ -1090,7 +1088,7 @@ ruby_dup(int orig)
static VALUE
io_alloc(VALUE klass)
{
- NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
+ NEWOBJ_OF(io, struct RFile, klass, T_FILE);
io->fptr = 0;
@@ -1462,7 +1460,7 @@ rb_io_wait(VALUE io, VALUE events, VALUE timeout)
static VALUE
io_from_fd(int fd)
{
- return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
+ return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
}
static int
@@ -1795,13 +1793,11 @@ io_binwrite_string(VALUE arg)
// Write as much as possible:
ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
- // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
- // should try again.
if (result == 0) {
- errno = EWOULDBLOCK;
+ // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
+ // should try again immediately.
}
-
- if (result > 0) {
+ else if (result > 0) {
if ((size_t)result == remaining) break;
ptr += result;
remaining -= result;
@@ -1838,7 +1834,7 @@ io_allocate_write_buffer(rb_io_t *fptr, int sync)
static inline int
io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
{
- // If the requested operation was synchronous and the output mode is synchronous or a TTY:
+ // If the requested operation was synchronous and the output mode is synchronus or a TTY:
if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
return 1;
@@ -2391,6 +2387,9 @@ rb_io_flush(VALUE io)
* f.close
*
* Related: IO#pos=, IO#seek.
+ *
+ * IO#pos is an alias for IO#tell.
+ *
*/
static VALUE
@@ -2658,6 +2657,9 @@ io_fillbuf(rb_io_t *fptr)
* Note that this method reads data to the input byte buffer. So
* IO#sysread may not behave as you intend with IO#eof?, unless you
* call IO#rewind first (which is not available for some streams).
+ *
+ * IO#eof? is an alias for IO#eof.
+ *
*/
VALUE
@@ -2848,6 +2850,8 @@ rb_io_fdatasync(VALUE io)
* File.open('t.txt').fileno # => 10
* f.close
*
+ * IO#to_i is an alias for IO#fileno.
+ *
*/
static VALUE
@@ -2870,23 +2874,8 @@ rb_io_descriptor(VALUE io)
return fptr->fd;
}
else {
- VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
- if (!UNDEF_P(fileno)) {
- return RB_NUM2INT(fileno);
- }
+ return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
}
-
- rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
-
- UNREACHABLE_RETURN(-1);
-}
-
-int
-rb_io_mode(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->mode;
}
/*
@@ -2935,7 +2924,7 @@ rb_io_pid(VALUE io)
* File.open("testfile") {|f| f.path} # => "testfile"
*/
-VALUE
+static VALUE
rb_io_path(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;
@@ -3276,10 +3265,9 @@ io_setstrbuf(VALUE *str, long len)
}
else {
VALUE s = StringValue(*str);
- rb_str_modify(s);
-
long clen = RSTRING_LEN(s);
if (clen >= len) {
+ rb_str_modify(s);
return FALSE;
}
len -= clen;
@@ -3817,8 +3805,33 @@ rscheck(const char *rsptr, long rslen, VALUE rs)
rb_raise(rb_eRuntimeError, "rs modified");
}
+static const char *
+search_delim(const char *p, long len, int delim, rb_encoding *enc)
+{
+ if (rb_enc_mbminlen(enc) == 1) {
+ p = memchr(p, delim, len);
+ if (p) return p + 1;
+ }
+ else {
+ const char *end = p + len;
+ while (p < end) {
+ int r = rb_enc_precise_mbclen(p, end, enc);
+ if (!MBCLEN_CHARFOUND_P(r)) {
+ p += rb_enc_mbminlen(enc);
+ continue;
+ }
+ int n = MBCLEN_CHARFOUND_LEN(r);
+ if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
+ return p + n;
+ }
+ p += n;
+ }
+ }
+ return NULL;
+}
+
static int
-appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
+appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
{
VALUE str = *strp;
long limit = *lp;
@@ -3833,9 +3846,9 @@ appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
p = READ_CHAR_PENDING_PTR(fptr);
if (0 < limit && limit < searchlen)
searchlen = (int)limit;
- e = memchr(p, delim, searchlen);
+ e = search_delim(p, searchlen, delim, enc);
if (e) {
- int len = (int)(e-p+1);
+ int len = (int)(e-p);
if (NIL_P(str))
*strp = str = rb_str_new(p, len);
else
@@ -3875,8 +3888,8 @@ appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
long last;
if (limit > 0 && pending > limit) pending = limit;
- e = memchr(p, delim, pending);
- if (e) pending = e - p + 1;
+ e = search_delim(p, pending, delim, enc);
+ if (e) pending = e - p;
if (!NIL_P(str)) {
last = RSTRING_LEN(str);
rb_str_resize(str, last + pending);
@@ -4136,16 +4149,26 @@ rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
rsptr = RSTRING_PTR(rs);
rslen = RSTRING_LEN(rs);
}
+ newline = '\n';
+ }
+ else if (rb_enc_mbminlen(enc) == 1) {
+ rsptr = RSTRING_PTR(rs);
+ newline = (unsigned char)rsptr[rslen - 1];
}
else {
+ rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
rsptr = RSTRING_PTR(rs);
+ const char *e = rsptr + rslen;
+ const char *last = rb_enc_prev_char(rsptr, e, e, enc);
+ int n;
+ newline = rb_enc_codepoint_len(last, e, &n, enc);
+ if (last + n != e) rb_raise(rb_eArgError, "broken separator");
}
- newline = (unsigned char)rsptr[rslen - 1];
- chomp_cr = chomp && rslen == 1 && newline == '\n';
+ chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
}
/* MS - Optimization */
- while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
+ while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
const char *s, *p, *pp, *e;
if (c == newline) {
@@ -4153,7 +4176,8 @@ rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
s = RSTRING_PTR(str);
e = RSTRING_END(str);
p = e - rslen;
- if (!at_char_boundary(s, p, e, enc)) continue;
+ pp = rb_enc_left_char_head(s, p, e, enc);
+ if (pp != p) continue;
if (!rspara) rscheck(rsptr, rslen, rs);
if (memcmp(p, rsptr, rslen) == 0) {
if (chomp) {
@@ -4166,8 +4190,8 @@ rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
if (limit == 0) {
s = RSTRING_PTR(str);
p = RSTRING_END(str);
- pp = rb_enc_left_char_head(s, p-1, p, enc);
- if (extra_limit &&
+ pp = rb_enc_prev_char(s, p, p, enc);
+ if (extra_limit && pp &&
MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
/* relax the limit while incomplete character.
* extra_limit limits the relax length */
@@ -4365,28 +4389,22 @@ rb_io_set_lineno(VALUE io, VALUE lineno)
return lineno;
}
-/* :nodoc: */
+/*
+ * call-seq:
+ * readline(sep = $/, chomp: false) -> string
+ * readline(limit, chomp: false) -> string
+ * readline(sep, limit, chomp: false) -> string
+ *
+ * Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
+ *
+ * Optional keyword argument +chomp+ specifies whether line separators
+ * are to be omitted.
+ */
+
static VALUE
-io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
+rb_io_readline(int argc, VALUE *argv, VALUE io)
{
- if (NIL_P(lim)) {
- // If sep is specified, but it's not a string and not nil, then assume
- // it's the limit (it should be an integer)
- if (!NIL_P(sep) && NIL_P(rb_check_string_type(sep))) {
- // If the user has specified a non-nil / non-string value
- // for the separator, we assume it's the limit and set the
- // separator to default: rb_rs.
- lim = sep;
- sep = rb_rs;
- }
- }
-
- if (!NIL_P(sep)) {
- StringValue(sep);
- }
-
- VALUE line = rb_io_getline_1(sep, NIL_P(lim) ? -1L : NUM2LONG(lim), RTEST(chomp), io);
- rb_lastline_set_up(line, 1);
+ VALUE line = rb_io_gets_m(argc, argv, io);
if (NIL_P(line)) {
rb_eof_error();
@@ -4591,6 +4609,9 @@ io_readlines(const struct getline_arg *arg, VALUE io)
* "Fifth line"
*
* Returns an Enumerator if no block is given.
+ *
+ * IO#each is an alias for IO#each_line.
+ *
*/
static VALUE
@@ -5214,6 +5235,8 @@ rb_io_ungetc(VALUE io, VALUE c)
* f = File.new('/dev/tty').isatty #=> true
* f.close
*
+ * IO#tty? is an alias for IO#isatty.
+ *
*/
static VALUE
@@ -5274,7 +5297,7 @@ rb_io_close_on_exec_p(VALUE io)
*
* Sets a close-on-exec flag.
*
- * f = File.open(File::NULL)
+ * f = open("/dev/null")
* f.close_on_exec = true
* system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
* f.closed? #=> false
@@ -5325,7 +5348,7 @@ rb_io_set_close_on_exec(VALUE io, VALUE arg)
#define rb_io_set_close_on_exec rb_f_notimplement
#endif
-#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
+#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
static VALUE
@@ -5444,7 +5467,7 @@ static void clear_codeconv(rb_io_t *fptr);
static void
fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
- struct rb_io_close_wait_list *busy)
+ struct ccan_list_head *busy)
{
VALUE error = Qnil;
int fd = fptr->fd;
@@ -5475,7 +5498,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
int done = 0;
- if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
+ if (IS_PREP_STDIO(fptr) || fd <= 2) {
// Need to keep FILE objects of stdin, stdout and stderr, so we are done:
done = 1;
}
@@ -5487,7 +5510,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
// Ensure waiting_fd users do not hit EBADF.
if (busy) {
// Wait for them to exit before we call close().
- rb_notify_fd_close_wait(busy);
+ do rb_thread_schedule(); while (!ccan_list_empty(busy));
}
// Disable for now.
@@ -5589,9 +5612,12 @@ clear_codeconv(rb_io_t *fptr)
clear_writeconv(fptr);
}
-static void
-rb_io_fptr_cleanup_all(rb_io_t *fptr)
+void
+rb_io_fptr_finalize_internal(void *ptr)
{
+ rb_io_t *fptr = ptr;
+
+ if (!ptr) return;
fptr->pathv = Qnil;
if (0 <= fptr->fd)
rb_io_fptr_cleanup(fptr, TRUE);
@@ -5599,14 +5625,7 @@ rb_io_fptr_cleanup_all(rb_io_t *fptr)
free_io_buffer(&fptr->rbuf);
free_io_buffer(&fptr->wbuf);
clear_codeconv(fptr);
-}
-
-void
-rb_io_fptr_finalize_internal(void *ptr)
-{
- if (!ptr) return;
- rb_io_fptr_cleanup_all(ptr);
- free(ptr);
+ free(fptr);
}
#undef rb_io_fptr_finalize
@@ -5642,14 +5661,16 @@ rb_io_memsize(const rb_io_t *fptr)
# define KEEPGVL FALSE
#endif
+int rb_notify_fd_close(int fd, struct ccan_list_head *);
static rb_io_t *
io_close_fptr(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
rb_io_t *write_fptr;
- struct rb_io_close_wait_list busy;
+ struct ccan_list_head busy;
+ ccan_list_head_init(&busy);
write_io = GetWriteIO(io);
if (io != write_io) {
write_fptr = RFILE(write_io)->fptr;
@@ -5786,8 +5807,10 @@ io_close(VALUE io)
*
* Related: IO#close_read, IO#close_write, IO#close.
*/
-VALUE
-rb_io_closed_p(VALUE io)
+
+
+static VALUE
+rb_io_closed(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
@@ -6085,37 +6108,28 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io)
return str;
}
+#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
struct prdwr_internal_arg {
- VALUE io;
int fd;
void *buf;
size_t count;
rb_off_t offset;
};
+#endif /* HAVE_PREAD || HAVE_PWRITE */
+#if defined(HAVE_PREAD)
static VALUE
-internal_pread_func(void *_arg)
+internal_pread_func(void *arg)
{
- struct prdwr_internal_arg *arg = _arg;
-
- return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
+ struct prdwr_internal_arg *p = arg;
+ return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
}
static VALUE
-pread_internal_call(VALUE _arg)
+pread_internal_call(VALUE arg)
{
- struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
-
- VALUE scheduler = rb_fiber_scheduler_current();
- if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
-
- if (!UNDEF_P(result)) {
- return rb_fiber_scheduler_io_result_apply(result);
- }
- }
-
- return rb_thread_io_blocking_region(internal_pread_func, arg, arg->fd);
+ struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
+ return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
}
/*
@@ -6152,7 +6166,7 @@ rb_io_pread(int argc, VALUE *argv, VALUE io)
VALUE len, offset, str;
rb_io_t *fptr;
ssize_t n;
- struct prdwr_internal_arg arg = {.io = io};
+ struct prdwr_internal_arg arg;
int shrinkable;
rb_scan_args(argc, argv, "21", &len, &offset, &str);
@@ -6182,21 +6196,15 @@ rb_io_pread(int argc, VALUE *argv, VALUE io)
return str;
}
+#else
+# define rb_io_pread rb_f_notimplement
+#endif /* HAVE_PREAD */
+#if defined(HAVE_PWRITE)
static VALUE
-internal_pwrite_func(void *_arg)
+internal_pwrite_func(void *ptr)
{
- struct prdwr_internal_arg *arg = _arg;
-
- VALUE scheduler = rb_fiber_scheduler_current();
- if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
-
- if (!UNDEF_P(result)) {
- return rb_fiber_scheduler_io_result_apply(result);
- }
- }
-
+ struct prdwr_internal_arg *arg = ptr;
return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
}
@@ -6231,7 +6239,7 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
{
rb_io_t *fptr;
ssize_t n;
- struct prdwr_internal_arg arg = {.io = io};
+ struct prdwr_internal_arg arg;
VALUE tmp;
if (!RB_TYPE_P(str, T_STRING))
@@ -6254,6 +6262,9 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
return SSIZET2NUM(n);
}
+#else
+# define rb_io_pwrite rb_f_notimplement
+#endif /* HAVE_PWRITE */
VALUE
rb_io_binmode(VALUE io)
@@ -6738,6 +6749,8 @@ rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2
return extracted;
}
+typedef struct rb_io_enc_t convconfig_t;
+
static void
validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
{
@@ -6796,7 +6809,7 @@ extract_binmode(VALUE opthash, int *fmode)
void
rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
- int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
+ int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
{
VALUE vmode;
int oflags, fmode;
@@ -6967,7 +6980,7 @@ rb_sysopen_internal(struct sysopen_struct *data)
static int
rb_sysopen(VALUE fname, int oflags, mode_t perm)
{
- int fd = -1;
+ int fd;
struct sysopen_struct data;
data.fname = rb_str_encode_ospath(fname);
@@ -6975,14 +6988,21 @@ rb_sysopen(VALUE fname, int oflags, mode_t perm)
data.oflags = oflags;
data.perm = perm;
- TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
- rb_syserr_fail_path(first_errno, fname);
+ fd = rb_sysopen_internal(&data);
+ if (fd < 0) {
+ int e = errno;
+ if (rb_gc_for_fd(e)) {
+ fd = rb_sysopen_internal(&data);
+ }
+ if (fd < 0) {
+ rb_syserr_fail_path(e, fname);
+ }
}
return fd;
}
-static inline FILE *
-fdopen_internal(int fd, const char *modestr)
+FILE *
+rb_fdopen(int fd, const char *modestr)
{
FILE *file;
@@ -6991,22 +7011,26 @@ fdopen_internal(int fd, const char *modestr)
#endif
file = fdopen(fd, modestr);
if (!file) {
+ int e = errno;
+#if defined(__sun)
+ if (e == 0) {
+ rb_gc();
+ errno = 0;
+ file = fdopen(fd, modestr);
+ }
+ else
+#endif
+ if (rb_gc_for_fd(e)) {
+ file = fdopen(fd, modestr);
+ }
+ if (!file) {
#ifdef _WIN32
- if (errno == 0) errno = EINVAL;
+ if (e == 0) e = EINVAL;
#elif defined(__sun)
- if (errno == 0) errno = EMFILE;
+ if (e == 0) e = EMFILE;
#endif
- }
- return file;
-}
-
-FILE *
-rb_fdopen(int fd, const char *modestr)
-{
- FILE *file = 0;
-
- TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
- rb_syserr_fail(first_errno, 0);
+ rb_syserr_fail(e, 0);
+ }
}
/* xxx: should be _IONBF? A buffer in FILE may have trouble. */
@@ -7113,11 +7137,11 @@ io_set_encoding_by_bom(VALUE io)
static VALUE
rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
- const struct rb_io_encoding *convconfig, mode_t perm)
+ const convconfig_t *convconfig, mode_t perm)
{
VALUE pathv;
rb_io_t *fptr;
- struct rb_io_encoding cc;
+ convconfig_t cc;
if (!convconfig) {
/* Set to default encodings */
rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
@@ -7151,7 +7175,7 @@ rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
{
int fmode = rb_io_modestr_fmode(modestr);
const char *p = strchr(modestr, ':');
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
if (p) {
parse_mode_enc(p+1, rb_usascii_encoding(),
@@ -7259,7 +7283,7 @@ static void
fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
{
#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
- void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
+ void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
if (old_finalize == orig->finalize) return;
#endif
@@ -7297,7 +7321,12 @@ int
rb_pipe(int *pipes)
{
int ret;
- TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
+ ret = rb_cloexec_pipe(pipes);
+ if (ret < 0) {
+ if (rb_gc_for_fd(errno)) {
+ ret = rb_cloexec_pipe(pipes);
+ }
+ }
if (ret == 0) {
rb_update_max_fd(pipes[0]);
rb_update_max_fd(pipes[1]);
@@ -7459,7 +7488,7 @@ char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
#ifndef __EMSCRIPTEN__
static VALUE
pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
- const struct rb_io_encoding *convconfig)
+ const convconfig_t *convconfig)
{
struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
@@ -7688,7 +7717,7 @@ pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
#else
static VALUE
pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
- const struct rb_io_encoding *convconfig)
+ const convconfig_t *convconfig)
{
rb_raise(rb_eNotImpError, "popen() is not available");
}
@@ -7710,7 +7739,7 @@ is_popen_fork(VALUE prog)
static VALUE
pipe_open_s(VALUE prog, const char *modestr, int fmode,
- const struct rb_io_encoding *convconfig)
+ const convconfig_t *convconfig)
{
int argc = 1;
VALUE *argv = &prog;
@@ -7919,7 +7948,7 @@ rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
const char *modestr;
VALUE tmp, execarg_obj = Qnil;
int oflags, fmode;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
tmp = rb_check_array_type(pname);
if (!NIL_P(tmp)) {
@@ -7956,7 +7985,7 @@ popen_finish(VALUE port, VALUE klass)
if (NIL_P(port)) {
/* child */
if (rb_block_given_p()) {
- rb_yield(Qnil);
+ rb_protect(rb_yield, Qnil, NULL);
rb_io_flush(rb_ractor_stdout());
rb_io_flush(rb_ractor_stderr());
_exit(0);
@@ -7970,64 +7999,10 @@ popen_finish(VALUE port, VALUE klass)
return port;
}
-#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
-struct popen_writer_arg {
- char *const *argv;
- struct popen_arg popen;
-};
-
-static int
-exec_popen_writer(void *arg, char *errmsg, size_t buflen)
-{
- struct popen_writer_arg *pw = arg;
- pw->popen.modef = FMODE_WRITABLE;
- popen_redirect(&pw->popen);
- execv(pw->argv[0], pw->argv);
- strlcpy(errmsg, strerror(errno), buflen);
- return -1;
-}
-#endif
-
-FILE *
-ruby_popen_writer(char *const *argv, rb_pid_t *pid)
-{
-#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
-# ifdef HAVE_WORKING_FORK
- struct popen_writer_arg pw;
- int *const write_pair = pw.popen.pair;
-# else
- int write_pair[2];
-# endif
-
- int result = rb_cloexec_pipe(write_pair);
- *pid = -1;
- if (result == 0) {
-# ifdef HAVE_WORKING_FORK
- pw.argv = argv;
- int status;
- char errmsg[80] = {'\0'};
- *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
-# else
- *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
- const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
-# endif
- close(write_pair[0]);
- if (*pid < 0) {
- close(write_pair[1]);
- fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
- }
- else {
- return fdopen(write_pair[1], "w");
- }
- }
-#endif
- return NULL;
-}
-
static void
rb_scan_open_args(int argc, const VALUE *argv,
VALUE *fname_p, int *oflags_p, int *fmode_p,
- struct rb_io_encoding *convconfig_p, mode_t *perm_p)
+ convconfig_t *convconfig_p, mode_t *perm_p)
{
VALUE opt, fname, vmode, vperm;
int oflags, fmode;
@@ -8051,7 +8026,7 @@ rb_open_file(int argc, const VALUE *argv, VALUE io)
{
VALUE fname;
int oflags, fmode;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
mode_t perm;
rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
@@ -8067,11 +8042,11 @@ rb_open_file(int argc, const VALUE *argv, VALUE io)
* File.open(path, mode = 'r', perm = 0666, **opts) -> file
* File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
*
- * Creates a new File object, via File.new with the given arguments.
+ * Creates a new \File object, via File.new with the given arguments.
*
- * With no block given, returns the File object.
+ * With no block given, returns the \File object.
*
- * With a block given, calls the block with the File object
+ * With a block given, calls the block with the \File object
* and returns the block's value.
*
*/
@@ -8169,10 +8144,20 @@ check_pipe_command(VALUE filename_or_command)
* open(path, mode = 'r', perm = 0666, **opts) -> io or nil
* open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
*
- * Creates an IO object connected to the given file.
+ * Creates an IO object connected to the given stream, file, or subprocess.
*
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ * Required string argument +path+ determines which of the following occurs:
+ *
+ * - The file at the specified +path+ is opened.
+ * - The process forks.
+ * - A subprocess is created.
+ *
+ * Each of these is detailed below.
+ *
+ * <b>File Opened</b>
+
+ * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>),
+ * a file stream is opened with <tt>File.open(path, mode, perm, **opts)</tt>.
*
* With no block given, file stream is returned:
*
@@ -8189,6 +8174,67 @@ check_pipe_command(VALUE filename_or_command)
*
* See File.open for details.
*
+ * <b>Process Forked</b>
+ *
+ * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks
+ * and the child process is connected to the parent.
+ *
+ * With no block given:
+ *
+ * io = open('|-')
+ * if io
+ * $stderr.puts "In parent, child pid is #{io.pid}."
+ * else
+ * $stderr.puts "In child, pid is #{$$}."
+ * end
+ *
+ * Output:
+ *
+ * In parent, child pid is 27903.
+ * In child, pid is 27903.
+ *
+ * With a block given:
+ *
+ * open('|-') do |io|
+ * if io
+ * $stderr.puts "In parent, child pid is #{io.pid}."
+ * else
+ * $stderr.puts "In child, pid is #{$$}."
+ * end
+ * end
+ *
+ * Output:
+ *
+ * In parent, child pid is 28427.
+ * In child, pid is 28427.
+ *
+ * <b>Subprocess Created</b>
+ *
+ * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>),
+ * a new subprocess runs the command; its open stream is returned.
+ * Note that the command may be processed by shell if it contains
+ * shell metacharacters.
+ *
+ * With no block given:
+ *
+ * io = open('|echo "Hi!"') # => #<IO:fd 12>
+ * print io.gets
+ * io.close
+ *
+ * Output:
+ *
+ * "Hi!"
+ *
+ * With a block given, calls the block with the stream, then closes the stream:
+ *
+ * open('|echo "Hi!"') do |io|
+ * print io.gets
+ * end
+ *
+ * Output:
+ *
+ * "Hi!"
+ *
*/
static VALUE
@@ -8211,8 +8257,6 @@ rb_f_open(int argc, VALUE *argv, VALUE _)
else {
VALUE cmd = check_pipe_command(tmp);
if (!NIL_P(cmd)) {
- // TODO: when removed in 4.0, update command_injection.rdoc
- rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
argv[0] = cmd;
return rb_io_s_popen(argc, argv, rb_cIO);
}
@@ -8230,13 +8274,13 @@ rb_f_open(int argc, VALUE *argv, VALUE _)
return rb_io_s_open(argc, argv, rb_cFile);
}
-static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
+static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
static VALUE
rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
{
int oflags, fmode;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
mode_t perm;
rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
@@ -8246,12 +8290,10 @@ rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
static VALUE
rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
- const struct rb_io_encoding *convconfig, mode_t perm)
+ const convconfig_t *convconfig, mode_t perm)
{
VALUE cmd;
if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
- // TODO: when removed in 4.0, update command_injection.rdoc
- rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
}
else {
@@ -8272,7 +8314,7 @@ io_reopen(VALUE io, VALUE nfile)
GetOpenFile(nfile, orig);
if (fptr == orig) return io;
- if (RUBY_IO_EXTERNAL_P(fptr)) {
+ if (IS_PREP_STDIO(fptr)) {
if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
(fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
(fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
@@ -8298,17 +8340,17 @@ io_reopen(VALUE io, VALUE nfile)
}
/* copy rb_io_t structure */
- fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
+ fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
fptr->pid = orig->pid;
fptr->lineno = orig->lineno;
if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
- else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
+ else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
fptr_copy_finalizer(fptr, orig);
fd = fptr->fd;
fd2 = orig->fd;
if (fd != fd2) {
- if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
+ if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
/* need to keep FILE objects of stdin, stdout and stderr */
if (rb_cloexec_dup2(fd2, fd) < 0)
rb_sys_fail_path(orig->pathv);
@@ -8413,10 +8455,10 @@ rb_io_reopen(int argc, VALUE *argv, VALUE file)
if (!NIL_P(nmode) || !NIL_P(opt)) {
int fmode;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
- if (RUBY_IO_EXTERNAL_P(fptr) &&
+ if (IS_PREP_STDIO(fptr) &&
((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
(fptr->mode & FMODE_READWRITE)) {
rb_raise(rb_eArgError,
@@ -8495,7 +8537,7 @@ rb_io_init_copy(VALUE dest, VALUE io)
rb_io_flush(io);
/* copy rb_io_t structure */
- fptr->mode = orig->mode & ~FMODE_EXTERNAL;
+ fptr->mode = orig->mode & ~FMODE_PREP;
fptr->encs = orig->encs;
fptr->pid = orig->pid;
fptr->lineno = orig->lineno;
@@ -8859,9 +8901,9 @@ io_puts_ary(VALUE ary, VALUE out, int recur)
*
* Treatment for each object:
*
- * - String: writes the string.
+ * - \String: writes the string.
* - Neither string nor array: writes <tt>object.to_s</tt>.
- * - Array: writes each element of the array; arrays may be nested.
+ * - \Array: writes each element of the array; arrays may be nested.
*
* To keep these examples brief, we define this helper method:
*
@@ -9017,10 +9059,6 @@ rb_p_result(int argc, const VALUE *argv)
* 0..4
* [0..4, 0..4, 0..4]
*
- * Kernel#p is designed for debugging purposes.
- * Ruby implementations may define Kernel#p to be uninterruptible
- * in whole or in part.
- * On CRuby, Kernel#p's writing of data is uninterruptible.
*/
static VALUE
@@ -9174,78 +9212,26 @@ stderr_getter(ID id, VALUE *ptr)
}
static VALUE
-allocate_and_open_new_file(VALUE klass)
-{
- VALUE self = io_alloc(klass);
- rb_io_make_open_file(self);
- return self;
-}
-
-VALUE
-rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
-{
- int state;
- VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
- if (state) {
- /* if we raised an exception allocating an IO object, but the caller
- intended to transfer ownership of this FD to us, close the fd before
- raising the exception. Otherwise, we would leak a FD - the caller
- expects GC to close the file, but we never got around to assigning
- it to a rb_io. */
- if (!(mode & FMODE_EXTERNAL)) {
- maygvl_close(descriptor, 0);
- }
- rb_jump_tag(state);
- }
-
-
- rb_io_t *io = RFILE(self)->fptr;
- io->self = self;
- io->fd = descriptor;
- io->mode = mode;
-
- /* At this point, Ruby fully owns the descriptor, and will close it when
- the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
- in the rest of this method. */
-
- if (NIL_P(path)) {
- io->pathv = Qnil;
- }
- else {
- StringValue(path);
- io->pathv = rb_str_new_frozen(path);
- }
-
- io->timeout = timeout;
-
- if (encoding) {
- io->encs = *encoding;
- }
-
- rb_update_max_fd(descriptor);
-
- return self;
-}
-
-static VALUE
prep_io(int fd, int fmode, VALUE klass, const char *path)
{
- VALUE path_value = Qnil;
- if (path) {
- path_value = rb_obj_freeze(rb_str_new_cstr(path));
- }
-
- VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, NULL);
- rb_io_t*io = RFILE(self)->fptr;
+ rb_io_t *fp;
+ VALUE io = io_alloc(klass);
- if (!io_check_tty(io)) {
+ MakeOpenFile(io, fp);
+ fp->self = io;
+ fp->fd = fd;
+ fp->mode = fmode;
+ fp->timeout = Qnil;
+ if (!io_check_tty(fp)) {
#ifdef __CYGWIN__
- io->mode |= FMODE_BINMODE;
+ fp->mode |= FMODE_BINMODE;
setmode(fd, O_BINARY);
#endif
}
+ if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
+ rb_update_max_fd(fd);
- return self;
+ return io;
}
VALUE
@@ -9261,7 +9247,7 @@ static VALUE
prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
{
rb_io_t *fptr;
- VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
+ VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
GetOpenFile(io, fptr);
fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
@@ -9305,7 +9291,7 @@ rb_io_stdio_file(rb_io_t *fptr)
}
static inline void
-rb_io_buffer_init(struct rb_io_internal_buffer *buf)
+rb_io_buffer_init(rb_io_buffer_t *buf)
{
buf->ptr = NULL;
buf->off = 0;
@@ -9408,7 +9394,7 @@ rb_io_initialize(int argc, VALUE *argv, VALUE io)
VALUE fnum, vmode;
rb_io_t *fp;
int fd, fmode, oflags = O_RDONLY;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
VALUE opt;
#if defined(HAVE_FCNTL) && defined(F_GETFL)
int ofmode;
@@ -9445,7 +9431,7 @@ rb_io_initialize(int argc, VALUE *argv, VALUE io)
if (!NIL_P(opt)) {
if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
- fmode |= FMODE_EXTERNAL;
+ fmode |= FMODE_PREP;
}
path = rb_hash_aref(opt, RB_ID2SYM(idPath));
@@ -9524,9 +9510,9 @@ rb_io_set_encoding_by_bom(VALUE io)
* File.new(path, mode = 'r', perm = 0666, **opts) -> file
*
* Opens the file at the given +path+ according to the given +mode+;
- * creates and returns a new File object for that file.
+ * creates and returns a new \File object for that file.
*
- * The new File object is buffered mode (or non-sync mode), unless
+ * The new \File object is buffered mode (or non-sync mode), unless
* +filename+ is a tty.
* See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
*
@@ -9614,7 +9600,7 @@ rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
* ios.autoclose? -> true or false
*
* Returns +true+ if the underlying file descriptor of _ios_ will be
- * closed at its finalization or at calling #close, otherwise +false+.
+ * closed automatically at its finalization, otherwise +false+.
*/
static VALUE
@@ -9622,7 +9608,7 @@ rb_io_autoclose_p(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;
rb_io_check_closed(fptr);
- return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
+ return RBOOL(!(fptr->mode & FMODE_PREP));
}
/*
@@ -9631,14 +9617,14 @@ rb_io_autoclose_p(VALUE io)
*
* Sets auto-close flag.
*
- * f = File.open(File::NULL)
- * IO.for_fd(f.fileno).close
- * f.gets # raises Errno::EBADF
+ * f = open("/dev/null")
+ * IO.for_fd(f.fileno)
+ * # ...
+ * f.gets # may cause Errno::EBADF
*
- * f = File.open(File::NULL)
- * g = IO.for_fd(f.fileno)
- * g.autoclose = false
- * g.close
+ * f = open("/dev/null")
+ * IO.for_fd(f.fileno).autoclose = false
+ * # ...
* f.gets # won't cause Errno::EBADF
*/
@@ -9648,9 +9634,9 @@ rb_io_set_autoclose(VALUE io, VALUE autoclose)
rb_io_t *fptr;
GetOpenFile(io, fptr);
if (!RTEST(autoclose))
- fptr->mode |= FMODE_EXTERNAL;
+ fptr->mode |= FMODE_PREP;
else
- fptr->mode &= ~FMODE_EXTERNAL;
+ fptr->mode &= ~FMODE_PREP;
return autoclose;
}
@@ -9783,7 +9769,7 @@ wait_mode_sym(VALUE mode)
rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
}
-static inline enum rb_io_event
+static inline rb_io_event_t
io_event_from_value(VALUE value)
{
int events = RB_NUM2INT(value);
@@ -9814,7 +9800,7 @@ static VALUE
io_wait(int argc, VALUE *argv, VALUE io)
{
VALUE timeout = Qundef;
- enum rb_io_event events = 0;
+ rb_io_event_t events = 0;
int return_io = 0;
// The documented signature for this method is actually incorrect.
@@ -10542,7 +10528,8 @@ rb_f_backquote(VALUE obj, VALUE str)
GetOpenFile(port, fptr);
result = read_all(fptr, remain_size(fptr), Qnil);
rb_io_close(port);
- rb_io_fptr_cleanup_all(fptr);
+ RFILE(port)->fptr = NULL;
+ rb_io_fptr_finalize(fptr);
RB_GC_GUARD(port);
return result;
@@ -11443,7 +11430,7 @@ rb_fcntl(VALUE io, VALUE req, VALUE arg)
* a file-oriented I/O stream. Arguments and results are platform
* dependent.
*
- * If +argument+ is a number, its value is passed directly;
+ * If +argument is a number, its value is passed directly;
* if it is a string, it is interpreted as a binary sequence of bytes.
* (Array#pack might be a useful way to build this string.)
*
@@ -11631,11 +11618,6 @@ io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
enc2 = NULL;
}
}
- if (enc2 == rb_ascii8bit_encoding()) {
- /* If external is ASCII-8BIT, no transcoding */
- enc = enc2;
- enc2 = NULL;
- }
SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
}
@@ -11696,9 +11678,9 @@ pipe_pair_close(VALUE rw)
* IO.pipe(**opts) -> [read_io, write_io]
* IO.pipe(enc, **opts) -> [read_io, write_io]
* IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
- * IO.pipe(**opts) {|read_io, write_io| ...} -> object
- * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
- * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
+ * IO.pipe(**opts) {|read_io, write_io] ...} -> object
+ * IO.pipe(enc, **opts) {|read_io, write_io] ...} -> object
+ * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io] ...} -> object
*
* Creates a pair of pipe endpoints, +read_io+ and +write_io+,
* connected to each other.
@@ -11909,6 +11891,9 @@ io_s_foreach(VALUE v)
* IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
* IO.foreach(path, limit, **opts) {|line| block } -> nil
* IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
+ * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil
+ * IO.foreach(command, limit, **opts) {|line| block } -> nil
+ * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil
* IO.foreach(...) -> an_enumerator
*
* Calls the block with each successive line read from the stream.
@@ -11917,7 +11902,16 @@ io_s_foreach(VALUE v)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string that is one of the following:
+ *
+ * - Path: if +self+ is a subclass of \IO (\File, for example),
+ * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>),
+ * the string is the path to a file.
+ * - Command: if +self+ is the class \IO,
+ * and if the string starts with the pipe character,
+ * the rest of the string is a command to be executed as a subprocess.
+ * This usage has potential security vulnerabilities if called with untrusted input;
+ * see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
* With only argument +path+ given, parses lines from the file at the given +path+,
* as determined by the default line separator,
@@ -11978,7 +11972,7 @@ io_s_foreach(VALUE v)
*
* - {Open Options}[rdoc-ref:IO@Open+Options].
* - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
- * - {Line Options}[rdoc-ref:IO@Line+IO].
+ * - {Line Options}[rdoc-ref:IO@Line+Options].
*
* Returns an Enumerator if no block is given.
*
@@ -12011,6 +12005,9 @@ io_s_readlines(VALUE v)
/*
* call-seq:
+ * IO.readlines(command, sep = $/, **opts) -> array
+ * IO.readlines(command, limit, **opts) -> array
+ * IO.readlines(command, sep, limit, **opts) -> array
* IO.readlines(path, sep = $/, **opts) -> array
* IO.readlines(path, limit, **opts) -> array
* IO.readlines(path, sep, limit, **opts) -> array
@@ -12021,7 +12018,19 @@ io_s_readlines(VALUE v)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string;
+ * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
+ *
+ * - If so (and if +self+ is \IO),
+ * the rest of the string is a command to be executed as a subprocess.
+ * - Otherwise, the string is the path to a file.
+ *
+ * With only argument +command+ given, executes the command in a shell,
+ * parses its $stdout into lines, as determined by the default line separator,
+ * and returns those lines in an array:
+ *
+ * IO.readlines('| cat t.txt')
+ * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
*
* With only argument +path+ given, parses lines from the file at the given +path+,
* as determined by the default line separator,
@@ -12030,6 +12039,8 @@ io_s_readlines(VALUE v)
* IO.readlines('t.txt')
* # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
*
+ * For both forms, command and path, the remaining arguments are the same.
+ *
* With argument +sep+ given, parses lines as determined by that line separator
* (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
*
@@ -12059,7 +12070,7 @@ io_s_readlines(VALUE v)
*
* - {Open Options}[rdoc-ref:IO@Open+Options].
* - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
- * - {Line Options}[rdoc-ref:IO@Line+IO].
+ * - {Line Options}[rdoc-ref:IO@Line+Options].
*
*/
@@ -12102,6 +12113,7 @@ seek_before_access(VALUE argp)
/*
* call-seq:
+ * IO.read(command, length = nil, offset = 0, **opts) -> string or nil
* IO.read(path, length = nil, offset = 0, **opts) -> string or nil
*
* Opens the stream, reads and returns some or all of its content,
@@ -12111,7 +12123,18 @@ seek_before_access(VALUE argp)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string;
+ * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
+ *
+ * - If so (and if +self+ is \IO),
+ * the rest of the string is a command to be executed as a subprocess.
+ * - Otherwise, the string is the path to a file.
+ *
+ * With only argument +command+ given, executes the command in a shell,
+ * returns its entire $stdout:
+ *
+ * IO.read('| cat t.txt')
+ * # => "First line\nSecond line\n\nThird line\nFourth line\n"
*
* With only argument +path+ given, reads in text mode and returns the entire content
* of the file at the given path:
@@ -12123,6 +12146,8 @@ seek_before_access(VALUE argp)
* unread when encountering certain special bytes. Consider using
* IO.binread if all bytes in the file should be read.
*
+ * For both forms, command and path, the remaining arguments are the same.
+ *
* With argument +length+, returns +length+ bytes if available:
*
* IO.read('t.txt', 7) # => "First l"
@@ -12146,13 +12171,9 @@ static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
VALUE opt, offset;
- long off;
struct foreach_arg arg;
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
- if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
- rb_raise(rb_eArgError, "negative offset %ld given", off);
- }
open_key_args(io, argc, argv, opt, &arg);
if (NIL_P(arg.io)) return Qnil;
if (!NIL_P(offset)) {
@@ -12173,6 +12194,7 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
+ * IO.binread(command, length = nil, offset = 0) -> string or nil
* IO.binread(path, length = nil, offset = 0) -> string or nil
*
* Behaves like IO.read, except that the stream is opened in binary mode
@@ -12196,7 +12218,7 @@ rb_io_s_binread(int argc, VALUE *argv, VALUE io)
|O_BINARY
#endif
};
- struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
+ convconfig_t convconfig = {NULL, NULL, 0, Qnil};
rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
FilePathValue(argv[0]);
@@ -12277,6 +12299,7 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
/*
* call-seq:
+ * IO.write(command, data, **opts) -> integer
* IO.write(path, data, offset = 0, **opts) -> integer
*
* Opens the stream, writes the given +data+ to it,
@@ -12286,9 +12309,25 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string;
+ * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
*
- * With only argument +path+ given, writes the given +data+ to the file at that path:
+ * - If so (and if +self+ is \IO),
+ * the rest of the string is a command to be executed as a subprocess.
+ * - Otherwise, the string is the path to a file.
+ *
+ * With argument +command+ given, executes the command in a shell,
+ * passes +data+ through standard input, writes its output to $stdout,
+ * and returns the length of the given +data+:
+ *
+ * IO.write('| cat', 'Hello World!') # => 12
+ *
+ * Output:
+ *
+ * Hello World!
+ *
+ * With argument +path+ given, writes the given +data+ to the file
+ * at that path:
*
* IO.write('t.tmp', 'abc') # => 3
* File.read('t.tmp') # => "abc"
@@ -12327,6 +12366,7 @@ rb_io_s_write(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
+ * IO.binwrite(command, string, offset = 0) -> integer
* IO.binwrite(path, string, offset = 0) -> integer
*
* Behaves like IO.write, except that the stream is opened in binary mode
@@ -12883,7 +12923,12 @@ maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf,
ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
}
else {
+#ifdef HAVE_PREAD
ss = pread(stp->src_fptr->fd, buf, len, offset);
+#else
+ stp->notimp = "pread";
+ return -1;
+#endif
}
if (ss == 0) {
return 0;
@@ -13050,6 +13095,7 @@ copy_stream_fallback_body(VALUE arg)
while (1) {
long numwrote;
long l;
+ rb_str_make_independent(buf);
if (stp->copy_length < (rb_off_t)0) {
l = buflen;
}
@@ -13393,12 +13439,10 @@ rb_io_internal_encoding(VALUE io)
*
* See {Encodings}[rdoc-ref:File@Encodings].
*
- * Argument +ext_enc+, if given, must be an Encoding object
- * or a String with the encoding name;
+ * Argument +ext_enc+, if given, must be an Encoding object;
* it is assigned as the encoding for the stream.
*
- * Argument +int_enc+, if given, must be an Encoding object
- * or a String with the encoding name;
+ * Argument +int_enc+, if given, must be an Encoding object;
* it is assigned as the encoding for the internal string.
*
* Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
@@ -13406,10 +13450,6 @@ rb_io_internal_encoding(VALUE io)
* corresponding Encoding objects are assigned as the external
* and internal encodings for the stream.
*
- * If the external encoding of a string is binary/ASCII-8BIT,
- * the internal encoding of the string is set to nil, since no
- * transcoding is needed.
- *
* Optional keyword arguments +enc_opts+ specify
* {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
*
@@ -14417,7 +14457,7 @@ argf_closed(VALUE argf)
{
next_argv();
ARGF_FORWARD(0, 0);
- return rb_io_closed_p(ARGF.current_file);
+ return rb_io_closed(ARGF.current_file);
}
/*
@@ -14696,16 +14736,11 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* ARGV.replace ["file2", "file3"]
* ARGF.read # Returns the contents of file2 and file3
*
- * If +ARGV+ is empty, ARGF acts as if it contained <tt>"-"</tt> that
- * makes ARGF read from STDIN, i.e. the data piped or typed to your
- * script. For example:
+ * If +ARGV+ is empty, ARGF acts as if it contained STDIN, i.e. the data
+ * piped to your script. For example:
*
* $ echo "glark" | ruby -e 'p ARGF.read'
* "glark\n"
- *
- * $ echo Glark > file1
- * $ echo "glark" | ruby -e 'p ARGF.read' -- - file1
- * "glark\nGlark\n"
*/
/*
@@ -14723,7 +14758,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* ARGF is not itself a subclass of \IO.
*
* \Class StringIO provides an IO-like stream that handles a String.
- * StringIO is not itself a subclass of \IO.
+ * \StringIO is not itself a subclass of \IO.
*
* Important objects based on \IO include:
*
@@ -14741,7 +14776,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* - Kernel#open: Returns a new \IO object connected to a given source:
* stream, file, or subprocess.
*
- * Like a File stream, an \IO stream has:
+ * Like a \File stream, an \IO stream has:
*
* - A read/write mode, which may be read-only, write-only, or read/write;
* see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
@@ -14777,7 +14812,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* that determine how a new stream is to be opened:
*
* - +:mode+: Stream mode.
- * - +:flags+: Integer file open flags;
+ * - +:flags+: \Integer file open flags;
* If +mode+ is also given, the two are bitwise-ORed.
* - +:external_encoding+: External encoding for the stream.
* - +:internal_encoding+: Internal encoding for the stream.
@@ -14792,7 +14827,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* #path method.
*
* Also available are the options offered in String#encode,
- * which may control conversion between external and internal encoding.
+ * which may control conversion between external internal encoding.
*
* == Basic \IO
*
@@ -15067,7 +15102,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* # => 41
* f.close
*
- * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
+ * - When a stream is read, <tt>#.</tt> is set to the line number for that stream:
*
* f0 = File.new('t.txt')
* f1 = File.new('t.dat')
@@ -15316,7 +15351,6 @@ Init_IO(void)
rb_cIO = rb_define_class("IO", rb_cObject);
rb_include_module(rb_cIO, rb_mEnumerable);
- /* Can be raised by IO operations when IO#timeout= is set. */
rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
@@ -15434,6 +15468,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "read", io_read, -1);
rb_define_method(rb_cIO, "write", io_write_m, -1);
rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
+ rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
@@ -15468,7 +15503,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
- rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
+ rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
diff --git a/io.rb b/io.rb
index 549c5e62bd..40873ea4fd 100644
--- a/io.rb
+++ b/io.rb
@@ -120,17 +120,4 @@ class IO
def write_nonblock(buf, exception: true)
Primitive.io_write_nonblock(buf, exception)
end
-
- # call-seq:
- # readline(sep = $/, chomp: false) -> string
- # readline(limit, chomp: false) -> string
- # readline(sep, limit, chomp: false) -> string
- #
- # Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
- #
- # Optional keyword argument +chomp+ specifies whether line separators
- # are to be omitted.
- def readline(sep = $/, limit = nil, chomp: false)
- Primitive.io_readline(sep, limit, chomp)
- end
end
diff --git a/io_buffer.c b/io_buffer.c
index 942ab268ae..87b51c0b8c 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -518,35 +518,6 @@ rb_io_buffer_type_for(VALUE klass, VALUE string)
}
}
-/*
- * call-seq:
- * IO::Buffer.string(length) {|io_buffer| ... read/write io_buffer ...} -> string
- *
- * Creates a new string of the given length and yields a IO::Buffer instance
- * to the block which uses the string as a source. The block is expected to
- * write to the buffer and the string will be returned.
- *
- * IO::Buffer.string(4) do |buffer|
- * buffer.set_string("Ruby")
- * end
- * # => "Ruby"
- */
-VALUE
-rb_io_buffer_type_string(VALUE klass, VALUE length)
-{
- VALUE string = rb_str_new(NULL, RB_NUM2LONG(length));
-
- struct io_buffer_for_yield_instance_arguments arguments = {
- .klass = klass,
- .string = string,
- .instance = Qnil,
- };
-
- rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments);
-
- return string;
-}
-
VALUE
rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags)
{
@@ -1245,17 +1216,6 @@ rb_io_buffer_free(VALUE self)
return self;
}
-VALUE rb_io_buffer_free_locked(VALUE self)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- io_buffer_unlock(buffer);
- io_buffer_free(buffer);
-
- return self;
-}
-
// Validate that access to the buffer is within bounds, assuming you want to
// access length bytes from the specified offset.
static inline void
@@ -1276,6 +1236,7 @@ rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_
struct rb_io_buffer *slice = NULL;
TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, slice);
+ slice->flags |= (buffer->flags & RB_IO_BUFFER_READONLY);
slice->base = (char*)buffer->base + offset;
slice->size = length;
@@ -1379,7 +1340,8 @@ rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size)
static inline void
io_buffer_get_bytes_for_writing(struct rb_io_buffer *buffer, void **base, size_t *size)
{
- if (buffer->flags & RB_IO_BUFFER_READONLY) {
+ if (buffer->flags & RB_IO_BUFFER_READONLY ||
+ (!NIL_P(buffer->source) && OBJ_FROZEN(buffer->source))) {
rb_raise(rb_eIOBufferAccessError, "Buffer is not writable!");
}
@@ -2258,8 +2220,8 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
* call-seq:
* copy(source, [offset, [length, [source_offset]]]) -> size
*
- * Efficiently copy from a source IO::Buffer into the buffer, at +offset+
- * using +memcpy+. For copying String instances, see #set_string.
+ * Efficiently copy buffer from a source IO::Buffer into the buffer,
+ * at +offset+ using +memcpy+. For copying String instances, see #set_string.
*
* buffer = IO::Buffer.new(32)
* # =>
@@ -2540,12 +2502,13 @@ io_buffer_blocking_region(struct rb_io_buffer *buffer, rb_blocking_function_t *f
}
struct io_buffer_read_internal_argument {
- // The file descriptor to read from:
int descriptor;
+
// The base pointer to read from:
char *base;
// The size of the buffer:
size_t size;
+
// The minimum number of bytes to read:
size_t length;
};
@@ -2628,8 +2591,6 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset)
* If +offset+ is not given, it defaults to zero, i.e. the beginning of the
* buffer.
*
- * Example:
- *
* IO::Buffer.for('test') do |buffer|
* p buffer
* # =>
@@ -2656,45 +2617,35 @@ io_buffer_read(int argc, VALUE *argv, VALUE self)
}
struct io_buffer_pread_internal_argument {
- // The file descriptor to read from:
int descriptor;
- // The base pointer to read from:
- char *base;
- // The size of the buffer:
+ void *base;
size_t size;
- // The minimum number of bytes to read:
- size_t length;
- // The offset to read from:
off_t offset;
};
static VALUE
io_buffer_pread_internal(void *_argument)
{
- size_t total = 0;
struct io_buffer_pread_internal_argument *argument = _argument;
- while (true) {
- ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
+#if defined(HAVE_PREAD)
+ ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
+#else
+ // This emulation is not thread safe.
+ rb_off_t offset = lseek(argument->descriptor, 0, SEEK_CUR);
+ if (offset == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (result < 0) {
- return rb_fiber_scheduler_io_result(result, errno);
- }
- else if (result == 0) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
- else {
- total += result;
+ if (lseek(argument->descriptor, argument->offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (total >= argument->length) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
+ ssize_t result = read(argument->descriptor, argument->base, argument->size);
- argument->base = argument->base + result;
- argument->size = argument->size - result;
- argument->offset = argument->offset + result;
- }
- }
+ if (lseek(argument->descriptor, offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
+#endif
+
+ return rb_fiber_scheduler_io_result(result, errno);
}
VALUE
@@ -2720,14 +2671,16 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
size_t size;
io_buffer_get_bytes_for_writing(buffer, &base, &size);
- base = (unsigned char*)base + offset;
- size = size - offset;
-
struct io_buffer_pread_internal_argument argument = {
.descriptor = descriptor,
- .base = base,
- .size = size,
- .length = length,
+
+ // Move the base pointer to the offset:
+ .base = (unsigned char*)base + offset,
+
+ // And the size to the length of buffer we want to read:
+ .size = length,
+
+ // From the offset in the file we want to read from:
.offset = from,
};
@@ -2735,19 +2688,13 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
}
/*
- * call-seq: pread(io, from, [length, [offset]]) -> read length or -errno
+ * call-seq: pread(io, from, length, [offset]) -> read length or -errno
*
- * Read at least +length+ bytes from the +io+ starting at the specified +from+
- * position, into the buffer starting at +offset+. If an error occurs,
- * return <tt>-errno</tt>.
- *
- * If +length+ is not given or +nil+, it defaults to the size of the buffer
- * minus the offset, i.e. the entire buffer.
+ * Read at most +length+ bytes from +io+ into the buffer, starting at
+ * +from+, and put it in buffer starting from specified +offset+.
+ * If an error occurs, return <tt>-errno</tt>.
*
- * If +length+ is zero, exactly one <tt>pread</tt> operation will occur.
- *
- * If +offset+ is not given, it defaults to zero, i.e. the beginning of the
- * buffer.
+ * If +offset+ is not given, put it at the beginning of the buffer.
*
* Example:
*
@@ -2781,12 +2728,13 @@ io_buffer_pread(int argc, VALUE *argv, VALUE self)
}
struct io_buffer_write_internal_argument {
- // The file descriptor to write to:
int descriptor;
+
// The base pointer to write from:
const char *base;
// The size of the buffer:
size_t size;
+
// The minimum length to write:
size_t length;
};
@@ -2869,8 +2817,6 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset)
* If +offset+ is not given, it defaults to zero, i.e. the beginning of the
* buffer.
*
- * Example:
- *
* out = File.open('output.txt', 'wb')
* IO::Buffer.for('1234567').write(out, 3)
*
@@ -2888,46 +2834,37 @@ io_buffer_write(int argc, VALUE *argv, VALUE self)
return rb_io_buffer_write(self, io, length, offset);
}
+
struct io_buffer_pwrite_internal_argument {
- // The file descriptor to write to:
int descriptor;
- // The base pointer to write from:
- const char *base;
- // The size of the buffer:
+ const void *base;
size_t size;
- // The minimum length to write:
- size_t length;
- // The offset to write to:
off_t offset;
};
static VALUE
io_buffer_pwrite_internal(void *_argument)
{
- size_t total = 0;
struct io_buffer_pwrite_internal_argument *argument = _argument;
- while (true) {
- ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
+#if defined(HAVE_PWRITE)
+ ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
+#else
+ // This emulation is not thread safe.
+ rb_off_t offset = lseek(argument->descriptor, 0, SEEK_CUR);
+ if (offset == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (result < 0) {
- return rb_fiber_scheduler_io_result(result, errno);
- }
- else if (result == 0) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
- else {
- total += result;
+ if (lseek(argument->descriptor, argument->offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (total >= argument->length) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
+ ssize_t result = write(argument->descriptor, argument->base, argument->size);
- argument->base = argument->base + result;
- argument->size = argument->size - result;
- argument->offset = argument->offset + result;
- }
- }
+ if (lseek(argument->descriptor, offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
+#endif
+
+ return rb_fiber_scheduler_io_result(result, errno);
}
VALUE
@@ -2953,20 +2890,14 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
size_t size;
io_buffer_get_bytes_for_reading(buffer, &base, &size);
- base = (unsigned char*)base + offset;
- size = size - offset;
-
struct io_buffer_pwrite_internal_argument argument = {
.descriptor = descriptor,
// Move the base pointer to the offset:
- .base = base,
+ .base = (unsigned char *)base + offset,
// And the size to the length of buffer we want to read:
- .size = size,
-
- // And the length of the buffer we want to write:
- .length = length,
+ .size = length,
// And the offset in the file we want to write from:
.offset = from,
@@ -2976,24 +2907,14 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
}
/*
- * call-seq: pwrite(io, from, [length, [offset]]) -> written length or -errno
+ * call-seq: pwrite(io, from, length, [offset]) -> written length or -errno
*
- * Write at least +length+ bytes from the buffer starting at +offset+, into
- * the +io+ starting at the specified +from+ position. If an error occurs,
- * return <tt>-errno</tt>.
+ * Writes +length+ bytes from buffer into +io+, starting at
+ * +offset+ in the buffer. If an error occurs, return <tt>-errno</tt>.
*
- * If +length+ is not given or +nil+, it defaults to the size of the buffer
- * minus the offset, i.e. the entire buffer.
- *
- * If +length+ is zero, exactly one <tt>pwrite</tt> operation will occur.
- *
- * If +offset+ is not given, it defaults to zero, i.e. the beginning of the
- * buffer.
- *
- * If the +from+ position is beyond the end of the file, the gap will be
- * filled with null (0 value) bytes.
- *
- * Example:
+ * If +offset+ is not given, the bytes are taken from the beginning of the
+ * buffer. If the +offset+ is given and is beyond the end of the file, the
+ * gap will be filled with null (0 value) bytes.
*
* out = File.open('output.txt', File::RDWR) # open for read/write, no truncation
* IO::Buffer.for('1234567').pwrite(out, 2, 3, 1)
@@ -3467,7 +3388,6 @@ Init_IO_Buffer(void)
rb_define_alloc_func(rb_cIOBuffer, rb_io_buffer_type_allocate);
rb_define_singleton_method(rb_cIOBuffer, "for", rb_io_buffer_type_for, 1);
- rb_define_singleton_method(rb_cIOBuffer, "string", rb_io_buffer_type_string, 1);
#ifdef _WIN32
SYSTEM_INFO info;
diff --git a/iseq.c b/iseq.c
index 0b58b51b48..d17ce486c5 100644
--- a/iseq.c
+++ b/iseq.c
@@ -19,6 +19,7 @@
#endif
#include "eval_intern.h"
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/bits.h"
@@ -26,15 +27,14 @@
#include "internal/compile.h"
#include "internal/error.h"
#include "internal/file.h"
-#include "internal/gc.h"
#include "internal/hash.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
#include "internal/sanitizers.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "iseq.h"
-#include "rjit.h"
+#include "mjit.h"
#include "ruby/util.h"
#include "vm_core.h"
#include "vm_callinfo.h"
@@ -43,7 +43,6 @@
#include "builtin.h"
#include "insns.inc"
#include "insns_info.inc"
-#include "prism_compile.h"
VALUE rb_cISeq;
static VALUE iseqw_new(const rb_iseq_t *iseq);
@@ -114,7 +113,9 @@ remove_from_constant_cache(ID id, IC ic)
st_table *ics = (st_table *)lookup_result;
st_delete(ics, &ic_data, NULL);
- if (ics->num_entries == 0) {
+ if (ics->num_entries == 0 &&
+ // See comment in vm_track_constant_cache on why we need this check
+ id != vm->inserting_constant_cache_id) {
rb_id_table_delete(vm->constant_cache, id);
st_free_table(ics);
}
@@ -165,17 +166,15 @@ rb_iseq_free(const rb_iseq_t *iseq)
if (iseq && ISEQ_BODY(iseq)) {
iseq_clear_ic_references(iseq);
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- rb_rjit_free_iseq(iseq); /* Notify RJIT */
+ mjit_free_iseq(iseq); /* Notify MJIT */
#if USE_YJIT
rb_yjit_iseq_free(body->yjit_payload);
- RUBY_ASSERT(rb_yjit_live_iseq_count > 0);
- rb_yjit_live_iseq_count--;
#endif
ruby_xfree((void *)body->iseq_encoded);
ruby_xfree((void *)body->insns_info.body);
- ruby_xfree((void *)body->insns_info.positions);
+ if (body->insns_info.positions) ruby_xfree((void *)body->insns_info.positions);
#if VM_INSN_INFO_TABLE_IMPL == 2
- ruby_xfree(body->insns_info.succ_index_table);
+ if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
#endif
if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl))
ruby_xfree((void *)body->local_table);
@@ -213,7 +212,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
typedef VALUE iseq_value_itr_t(void *ctx, VALUE obj);
static inline void
-iseq_scan_bits(unsigned int page, iseq_bits_t bits, VALUE *code, VALUE *original_iseq)
+iseq_scan_bits(unsigned int page, iseq_bits_t bits, VALUE *code, iseq_value_itr_t *func, void *data)
{
unsigned int offset;
unsigned int page_offset = (page * ISEQ_MBITS_BITLENGTH);
@@ -221,17 +220,20 @@ iseq_scan_bits(unsigned int page, iseq_bits_t bits, VALUE *code, VALUE *original
while (bits) {
offset = ntz_intptr(bits);
VALUE op = code[page_offset + offset];
- rb_gc_mark_and_move(&code[page_offset + offset]);
- VALUE newop = code[page_offset + offset];
- if (original_iseq && newop != op) {
- original_iseq[page_offset + offset] = newop;
+ VALUE newop = func(data, op);
+ if (newop != op) {
+ code[page_offset + offset] = newop;
+ if (data) {
+ VALUE *original_iseq = (VALUE *)data;
+ original_iseq[page_offset + offset] = newop;
+ }
}
bits &= bits - 1; // Reset Lowest Set Bit (BLSR)
}
}
static void
-rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
+rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
{
unsigned int size;
VALUE *code;
@@ -252,7 +254,10 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
if (icvarc->entry) {
RUBY_ASSERT(!RB_TYPE_P(icvarc->entry->class_value, T_NONE));
- rb_gc_mark_and_move(&icvarc->entry->class_value);
+ VALUE nv = func(data, icvarc->entry->class_value);
+ if (icvarc->entry->class_value != nv) {
+ icvarc->entry->class_value = nv;
+ }
}
}
@@ -260,7 +265,10 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
for (unsigned int i = 0; i < body->ise_size; i++, is_entries++) {
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)is_entries;
if (is->once.value) {
- rb_gc_mark_and_move(&is->once.value);
+ VALUE nv = func(data, is->once.value);
+ if (is->once.value != nv) {
+ is->once.value = nv;
+ }
}
}
@@ -268,7 +276,10 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
for (unsigned int i = 0; i < body->ic_size; i++, is_entries++) {
IC ic = (IC)is_entries;
if (ic->entry) {
- rb_gc_mark_and_move_ptr(&ic->entry);
+ VALUE nv = func(data, (VALUE)ic->entry);
+ if ((VALUE)ic->entry != nv) {
+ ic->entry = (void *)nv;
+ }
}
}
}
@@ -276,134 +287,197 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
// Embedded VALUEs
if (body->mark_bits.list) {
if (ISEQ_MBITS_BUFLEN(size) == 1) {
- iseq_scan_bits(0, body->mark_bits.single, code, original_iseq);
+ iseq_scan_bits(0, body->mark_bits.single, code, func, data);
}
else {
if (body->mark_bits.list) {
for (unsigned int i = 0; i < ISEQ_MBITS_BUFLEN(size); i++) {
iseq_bits_t bits = body->mark_bits.list[i];
- iseq_scan_bits(i, bits, code, original_iseq);
+ iseq_scan_bits(i, bits, code, func, data);
}
}
}
}
}
-static bool
-cc_is_active(const struct rb_callcache *cc, bool reference_updating)
+static VALUE
+update_each_insn_value(void *ctx, VALUE obj)
{
- if (cc) {
- if (reference_updating) {
- cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
+ return rb_gc_location(obj);
+}
+
+void
+rb_iseq_update_references(rb_iseq_t *iseq)
+{
+ if (ISEQ_BODY(iseq)) {
+ struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+
+ body->variable.coverage = rb_gc_location(body->variable.coverage);
+ body->variable.pc2branchindex = rb_gc_location(body->variable.pc2branchindex);
+ body->variable.script_lines = rb_gc_location(body->variable.script_lines);
+ body->location.label = rb_gc_location(body->location.label);
+ body->location.base_label = rb_gc_location(body->location.base_label);
+ body->location.pathobj = rb_gc_location(body->location.pathobj);
+ if (body->local_iseq) {
+ body->local_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->local_iseq);
+ }
+ if (body->parent_iseq) {
+ body->parent_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->parent_iseq);
+ }
+ if (body->mandatory_only_iseq) {
+ body->mandatory_only_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->mandatory_only_iseq);
}
+ if (body->call_data) {
+ for (unsigned int i=0; i<body->ci_size; i++) {
+ struct rb_call_data *cds = body->call_data;
+ if (!SPECIAL_CONST_P((VALUE)cds[i].ci)) {
+ cds[i].ci = (struct rb_callinfo *)rb_gc_location((VALUE)cds[i].ci);
+ }
+ cds[i].cc = (struct rb_callcache *)rb_gc_location((VALUE)cds[i].cc);
+ }
+ }
+ VALUE *original_iseq = ISEQ_ORIGINAL_ISEQ(iseq);
+ rb_iseq_each_value(iseq, update_each_insn_value, (void *)original_iseq);
+
+ if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
+ int i, j;
- if (vm_cc_markable(cc)) {
- if (cc->klass) { // cc is not invalidated
- const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
- if (reference_updating) {
- cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cme);
+ i = body->param.keyword->required_num;
+
+ for (j = 0; i < body->param.keyword->num; i++, j++) {
+ VALUE obj = body->param.keyword->default_values[j];
+ if (!UNDEF_P(obj)) {
+ body->param.keyword->default_values[j] = rb_gc_location(obj);
}
- if (!METHOD_ENTRY_INVALIDATED(cme)) {
- return true;
+ }
+ }
+
+ if (body->catch_table) {
+ struct iseq_catch_table *table = body->catch_table;
+ unsigned int i;
+ for (i = 0; i < table->size; i++) {
+ struct iseq_catch_table_entry *entry;
+ entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
+ if (entry->iseq) {
+ entry->iseq = (rb_iseq_t *)rb_gc_location((VALUE)entry->iseq);
}
}
}
+#if USE_MJIT
+ mjit_update_references(iseq);
+#endif
+#if USE_YJIT
+ rb_yjit_iseq_update_references(body->yjit_payload);
+#endif
}
- return false;
+}
+
+static VALUE
+each_insn_value(void *ctx, VALUE obj)
+{
+ rb_gc_mark_movable(obj);
+ return obj;
}
void
-rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
+rb_iseq_mark(const rb_iseq_t *iseq)
{
RUBY_MARK_ENTER("iseq");
- rb_gc_mark_and_move(&iseq->wrapper);
+ RUBY_MARK_UNLESS_NULL(iseq->wrapper);
if (ISEQ_BODY(iseq)) {
- struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+ const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- rb_iseq_mark_and_move_each_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
+ rb_iseq_each_value(iseq, each_insn_value, NULL);
- rb_gc_mark_and_move(&body->variable.coverage);
- rb_gc_mark_and_move(&body->variable.pc2branchindex);
- rb_gc_mark_and_move(&body->variable.script_lines);
- rb_gc_mark_and_move(&body->location.label);
- rb_gc_mark_and_move(&body->location.base_label);
- rb_gc_mark_and_move(&body->location.pathobj);
- if (body->local_iseq) rb_gc_mark_and_move_ptr(&body->local_iseq);
- if (body->parent_iseq) rb_gc_mark_and_move_ptr(&body->parent_iseq);
- if (body->mandatory_only_iseq) rb_gc_mark_and_move_ptr(&body->mandatory_only_iseq);
+ rb_gc_mark_movable(body->variable.coverage);
+ rb_gc_mark_movable(body->variable.pc2branchindex);
+ rb_gc_mark_movable(body->variable.script_lines);
+ rb_gc_mark_movable(body->location.label);
+ rb_gc_mark_movable(body->location.base_label);
+ rb_gc_mark_movable(body->location.pathobj);
+ RUBY_MARK_MOVABLE_UNLESS_NULL((VALUE)body->mandatory_only_iseq);
+ RUBY_MARK_MOVABLE_UNLESS_NULL((VALUE)body->parent_iseq);
if (body->call_data) {
- for (unsigned int i = 0; i < body->ci_size; i++) {
- struct rb_call_data *cds = body->call_data;
-
- if (cds[i].ci) rb_gc_mark_and_move_ptr(&cds[i].ci);
+ struct rb_call_data *cds = (struct rb_call_data *)body->call_data;
+ for (unsigned int i=0; i<body->ci_size; i++) {
+ const struct rb_callinfo *ci = cds[i].ci;
+ const struct rb_callcache *cc = cds[i].cc;
- if (cc_is_active(cds[i].cc, reference_updating)) {
- rb_gc_mark_and_move_ptr(&cds[i].cc);
+ if (vm_ci_markable(ci)) {
+ rb_gc_mark_movable((VALUE)ci);
}
- else {
- cds[i].cc = rb_vm_empty_cc();
+
+ if (cc) {
+ VM_ASSERT((cc->flags & VM_CALLCACHE_ON_STACK) == 0);
+
+ if (vm_cc_markable(cc)) {
+ if (!vm_cc_invalidated_p(cc)) {
+ rb_gc_mark_movable((VALUE)cc);
+ }
+ else {
+ cds[i].cc = rb_vm_empty_cc();
+ }
+ }
}
}
}
if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
+ int i, j;
+
+ i = keyword->required_num;
- for (int j = 0, i = keyword->required_num; i < keyword->num; i++, j++) {
- rb_gc_mark_and_move(&keyword->default_values[j]);
+ for (j = 0; i < keyword->num; i++, j++) {
+ VALUE obj = keyword->default_values[j];
+ if (!SPECIAL_CONST_P(obj)) {
+ rb_gc_mark_movable(obj);
+ }
}
}
if (body->catch_table) {
- struct iseq_catch_table *table = body->catch_table;
-
- for (unsigned int i = 0; i < table->size; i++) {
- struct iseq_catch_table_entry *entry;
+ const struct iseq_catch_table *table = body->catch_table;
+ unsigned int i;
+ for (i = 0; i < table->size; i++) {
+ const struct iseq_catch_table_entry *entry;
entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
if (entry->iseq) {
- rb_gc_mark_and_move_ptr(&entry->iseq);
+ rb_gc_mark_movable((VALUE)entry->iseq);
}
}
}
- if (reference_updating) {
-#if USE_RJIT
- rb_rjit_iseq_update_references(body);
-#endif
-#if USE_YJIT
- rb_yjit_iseq_update_references(body->yjit_payload);
-#endif
- }
- else {
-#if USE_RJIT
- rb_rjit_iseq_mark(body->rjit_blocks);
+#if USE_MJIT
+ mjit_mark_cc_entries(body);
#endif
#if USE_YJIT
- rb_yjit_iseq_mark(body->yjit_payload);
+ rb_yjit_iseq_mark(body->yjit_payload);
#endif
- }
}
if (FL_TEST_RAW((VALUE)iseq, ISEQ_NOT_LOADED_YET)) {
- rb_gc_mark_and_move(&iseq->aux.loader.obj);
+ rb_gc_mark(iseq->aux.loader.obj);
}
else if (FL_TEST_RAW((VALUE)iseq, ISEQ_USE_COMPILE_DATA)) {
const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
- rb_iseq_mark_and_move_insn_storage(compile_data->insn.storage_head);
+ rb_iseq_mark_insn_storage(compile_data->insn.storage_head);
- rb_gc_mark_and_move((VALUE *)&compile_data->err_info);
- rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary);
+ RUBY_MARK_UNLESS_NULL(compile_data->err_info);
+ if (RTEST(compile_data->catch_table_ary)) {
+ rb_gc_mark(compile_data->catch_table_ary);
+ }
+ VM_ASSERT(compile_data != NULL);
}
else {
/* executable */
VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
-
if (iseq->aux.exec.local_hooks) {
- rb_hook_list_mark_and_update(iseq->aux.exec.local_hooks);
+ rb_hook_list_mark(iseq->aux.exec.local_hooks);
}
}
@@ -523,6 +597,19 @@ rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
rb_iseq_pathobj_new(path, realpath));
}
+// Make a dummy iseq for a dummy frame that exposes a path for profilers to inspect
+rb_iseq_t *
+rb_iseq_alloc_with_dummy_path(VALUE fname)
+{
+ rb_iseq_t *dummy_iseq = iseq_alloc();
+
+ ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP;
+ RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname);
+ RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname);
+
+ return dummy_iseq;
+}
+
static rb_iseq_location_t *
iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id)
{
@@ -720,6 +807,7 @@ static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
+ OPT_STACK_CACHING, /* int stack_caching; */
OPT_FROZEN_STRING_LITERAL,
OPT_DEBUG_FROZEN_STRING_LITERAL,
TRUE, /* coverage_enabled */
@@ -736,7 +824,7 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
else if (flag == Qfalse) { (o)->mem = 0; } \
}
#define SET_COMPILE_OPTION_NUM(o, h, mem) \
- { VALUE num = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
+ { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
}
SET_COMPILE_OPTION(option, opt, inline_const_cache);
@@ -745,6 +833,7 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
SET_COMPILE_OPTION(option, opt, specialized_instruction);
SET_COMPILE_OPTION(option, opt, operands_unification);
SET_COMPILE_OPTION(option, opt, instructions_unification);
+ SET_COMPILE_OPTION(option, opt, stack_caching);
SET_COMPILE_OPTION(option, opt, frozen_string_literal);
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
SET_COMPILE_OPTION(option, opt, coverage_enabled);
@@ -753,15 +842,11 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
#undef SET_COMPILE_OPTION_NUM
}
-static rb_compile_option_t *
-set_compile_option_from_ast(rb_compile_option_t *option, const rb_ast_body_t *ast)
+static void
+rb_iseq_make_compile_option(rb_compile_option_t *option, VALUE opt)
{
-#define SET_COMPILE_OPTION(o, a, mem) \
- ((a)->mem < 0 ? 0 : ((o)->mem = (a)->mem > 0))
- SET_COMPILE_OPTION(option, ast, frozen_string_literal);
- SET_COMPILE_OPTION(option, ast, coverage_enabled);
-#undef SET_COMPILE_OPTION
- return option;
+ Check_Type(opt, T_HASH);
+ set_compile_option_from_hash(option, opt);
}
static void
@@ -802,6 +887,7 @@ make_compile_option_value(rb_compile_option_t *option)
SET_COMPILE_OPTION(option, opt, specialized_instruction);
SET_COMPILE_OPTION(option, opt, operands_unification);
SET_COMPILE_OPTION(option, opt, instructions_unification);
+ SET_COMPILE_OPTION(option, opt, stack_caching);
SET_COMPILE_OPTION(option, opt, frozen_string_literal);
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
SET_COMPILE_OPTION(option, opt, coverage_enabled);
@@ -856,7 +942,7 @@ iseq_new_setup_coverage(VALUE path, const rb_ast_body_t *ast, int line_offset)
VALUE coverages = rb_get_coverages();
if (RTEST(coverages)) {
- iseq_setup_coverage(coverages, path, ast, line_offset);
+ iseq_setup_coverage(coverages, path, ast, 0);
}
}
@@ -917,11 +1003,13 @@ rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE rea
rb_iseq_t *iseq = iseq_alloc();
rb_compile_option_t new_opt;
- if (!option) option = &COMPILE_OPTION_DEFAULT;
- if (ast) {
+ if (option) {
new_opt = *option;
- option = set_compile_option_from_ast(&new_opt, ast);
}
+ else {
+ new_opt = COMPILE_OPTION_DEFAULT;
+ }
+ if (ast && ast->compile_option) rb_iseq_make_compile_option(&new_opt, ast->compile_option);
VALUE script_lines = Qnil;
@@ -933,7 +1021,7 @@ rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE rea
}
prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1,
- parent, isolated_depth, type, script_lines, option);
+ parent, isolated_depth, type, script_lines, &new_opt);
rb_iseq_compile_node(iseq, node);
finish_iseq_build(iseq);
@@ -941,45 +1029,6 @@ rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE rea
return iseq_translate(iseq);
}
-VALUE rb_iseq_compile_prism_node(rb_iseq_t * iseq, pm_scope_node_t *scope_node, pm_parser_t *parser);
-
-rb_iseq_t *
-pm_iseq_new_with_opt(pm_scope_node_t *scope_node, pm_parser_t *parser, VALUE name, VALUE path, VALUE realpath,
- int first_lineno, const rb_iseq_t *parent, int isolated_depth,
- enum rb_iseq_type type, const rb_compile_option_t *option)
-{
- rb_iseq_t *iseq = iseq_alloc();
- VALUE script_lines = Qnil;
- rb_code_location_t code_loc;
-
- if (!option) option = &COMPILE_OPTION_DEFAULT;
-
- pm_line_column_t start_line_col = pm_newline_list_line_column(&parser->newline_list, scope_node->base.location.start);
- pm_line_column_t end_line_col = pm_newline_list_line_column(&parser->newline_list, scope_node->base.location.end);
-
- code_loc = (rb_code_location_t) {
- .beg_pos = {
- .lineno = (int) start_line_col.line,
- .column = (int) start_line_col.column
- },
- .end_pos = {
- .lineno = (int) end_line_col.line,
- .column = (int) end_line_col.column
- },
- };
-
- // TODO: node_id
- int node_id = -1;
- prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_loc, node_id,
- parent, isolated_depth, type, script_lines, option);
-
- rb_iseq_compile_prism_node(iseq, scope_node, parser);
-
- finish_iseq_build(iseq);
-
- return iseq_translate(iseq);
-}
-
rb_iseq_t *
rb_iseq_new_with_callback(
const struct rb_iseq_new_with_callback_callback_func * ifunc,
@@ -1161,7 +1210,6 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
const rb_iseq_t *outer_scope = rb_iseq_new(NULL, name, name, Qnil, 0, ISEQ_TYPE_TOP);
VALUE outer_scope_v = (VALUE)outer_scope;
rb_parser_set_context(parser, outer_scope, FALSE);
- rb_parser_set_script_lines(parser, RBOOL(ruby_vm_keep_script_lines));
RB_GC_GUARD(outer_scope_v);
ast = (*parse)(parser, file, src, ln);
}
@@ -1334,8 +1382,8 @@ rb_iseqw_new(const rb_iseq_t *iseq)
* InstructionSequence.compile(source[, file[, path[, line[, options]]]]) -> iseq
* InstructionSequence.new(source[, file[, path[, line[, options]]]]) -> iseq
*
- * Takes +source+, which can be a string of Ruby code, or an open +File+ object.
- * that contains Ruby source code.
+ * Takes +source+, a String of Ruby code and compiles it to an
+ * InstructionSequence.
*
* Optionally takes +file+, +path+, and +line+ which describe the file path,
* real path and first line number of the ruby code in +source+ which are
@@ -1357,10 +1405,6 @@ rb_iseqw_new(const rb_iseq_t *iseq)
* RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
* #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
*
- * file = File.open("test.rb")
- * RubyVM::InstructionSequence.compile(file)
- * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
- *
* path = File.expand_path("test.rb")
* RubyVM::InstructionSequence.compile(File.read(path), path, path)
* #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
@@ -1369,7 +1413,7 @@ rb_iseqw_new(const rb_iseq_t *iseq)
static VALUE
iseqw_s_compile(int argc, VALUE *argv, VALUE self)
{
- VALUE src, file = Qnil, path = Qnil, line = Qnil, opt = Qnil;
+ VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
int i;
i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
@@ -1391,71 +1435,6 @@ iseqw_s_compile(int argc, VALUE *argv, VALUE self)
return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, opt));
}
-static VALUE
-iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
-{
- VALUE src, file = Qnil, path = Qnil, line = Qnil, opt = Qnil;
- int i;
-
- i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
- if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
- switch (i) {
- case 5: opt = argv[--i];
- case 4: line = argv[--i];
- case 3: path = argv[--i];
- case 2: file = argv[--i];
- }
-
- if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
- if (NIL_P(path)) path = file;
- if (NIL_P(line)) line = INT2FIX(1);
-
- Check_Type(path, T_STRING);
- Check_Type(file, T_STRING);
-
- rb_iseq_t *iseq = iseq_alloc();
- int start_line = NUM2INT(line);
-
- pm_options_t options = { 0 };
- pm_options_filepath_set(&options, RSTRING_PTR(file));
- pm_options_line_set(&options, start_line);
-
- pm_parser_t parser;
- pm_parser_init(&parser, (const uint8_t *) RSTRING_PTR(src), RSTRING_LEN(src), &options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_line_column_t start_loc = pm_newline_list_line_column(&parser.newline_list, node->location.start);
- pm_line_column_t end_loc = pm_newline_list_line_column(&parser.newline_list, node->location.end);
-
- rb_code_location_t node_location;
- node_location.beg_pos.lineno = (int) start_loc.line;
- node_location.beg_pos.column = (int) start_loc.column;
- node_location.end_pos.lineno = (int) end_loc.line;
- node_location.end_pos.column = (int) end_loc.column;
-
- int node_id = 0;
- rb_iseq_t *parent = NULL;
- enum rb_iseq_type iseq_type = ISEQ_TYPE_TOP;
- rb_compile_option_t option;
-
- make_compile_option(&option, opt);
-
- VALUE name = rb_fstring_lit("<compiled>");
- prepare_iseq_build(iseq, name, file, path, start_line, &node_location, node_id,
- parent, 0, (enum rb_iseq_type)iseq_type, Qnil, &option);
-
- pm_scope_node_t scope_node;
- pm_scope_node_init(node, &scope_node, NULL, &parser);
- rb_iseq_compile_prism_node(iseq, &scope_node, &parser);
-
- finish_iseq_build(iseq);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-
- return iseqw_new(iseq);
-}
-
/*
* call-seq:
* InstructionSequence.compile_file(file[, options]) -> iseq
@@ -1544,6 +1523,7 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
* * +:operands_unification+
* * +:peephole_optimization+
* * +:specialized_instruction+
+ * * +:stack_caching+
* * +:tailcall_optimization+
*
* Additionally, +:debug_level+ can be set to an integer.
@@ -1607,7 +1587,11 @@ rb_iseqw_to_iseq(VALUE iseqw)
static VALUE
iseqw_eval(VALUE self)
{
- return rb_iseq_eval(iseqw_check(self));
+ const rb_iseq_t *iseq = iseqw_check(self);
+ if (0 == ISEQ_BODY(iseq)->iseq_size) {
+ rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence");
+ }
+ return rb_iseq_eval(iseq);
}
/*
@@ -2029,7 +2013,7 @@ rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos)
}
#endif
-rb_event_flag_t
+MJIT_FUNC_EXPORTED rb_event_flag_t
rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
{
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
@@ -2225,6 +2209,7 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
CALL_FLAG(FCALL);
CALL_FLAG(VCALL);
CALL_FLAG(ARGS_SIMPLE);
+ CALL_FLAG(BLOCKISEQ);
CALL_FLAG(TAILCALL);
CALL_FLAG(SUPER);
CALL_FLAG(ZSUPER);
@@ -2328,7 +2313,7 @@ rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
{
rb_event_flag_t events = rb_iseq_event_flags(iseq, pos);
if (events) {
- str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s%s]",
+ str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s]",
events & RUBY_EVENT_LINE ? "Li" : "",
events & RUBY_EVENT_CLASS ? "Cl" : "",
events & RUBY_EVENT_END ? "En" : "",
@@ -2338,7 +2323,6 @@ rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
events & RUBY_EVENT_C_RETURN ? "Cr" : "",
events & RUBY_EVENT_B_CALL ? "Bc" : "",
events & RUBY_EVENT_B_RETURN ? "Br" : "",
- events & RUBY_EVENT_RESCUE ? "Rs" : "",
events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "",
events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "");
}
@@ -2428,6 +2412,7 @@ rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent)
rb_str_cat2(str, "== disasm: ");
rb_str_append(str, iseq_inspect(iseq));
+ rb_str_catf(str, " (catch: %s)", body->catch_except_p ? "true" : "false");
if ((l = RSTRING_LEN(str) - indent_len) < header_minlen) {
rb_str_modify_expand(str, header_minlen - l);
memset(RSTRING_END(str), '=', header_minlen - l);
@@ -2683,7 +2668,6 @@ push_event_info(const rb_iseq_t *iseq, rb_event_flag_t events, int line, VALUE a
C(RUBY_EVENT_END, "end", INT2FIX(line));
C(RUBY_EVENT_RETURN, "return", INT2FIX(line));
C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
- C(RUBY_EVENT_RESCUE, "rescue", INT2FIX(line));
#undef C
}
@@ -2827,6 +2811,17 @@ iseqw_s_disasm(VALUE klass, VALUE body)
return NIL_P(iseqw) ? Qnil : rb_iseq_disasm(iseqw_check(iseqw));
}
+const char *
+ruby_node_name(int node)
+{
+ switch (node) {
+#include "node_name.inc"
+ default:
+ rb_bug("unknown node: %d", node);
+ return 0;
+ }
+}
+
static VALUE
register_label(struct st_table *table, unsigned long idx)
{
@@ -3201,7 +3196,6 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN);
- CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT
prev_insn_info = info;
}
@@ -3396,7 +3390,7 @@ rb_vm_encoded_insn_data_table_init(void)
const void * const *table = rb_vm_get_insns_address_table();
#define INSN_CODE(insn) ((VALUE)table[insn])
#else
-#define INSN_CODE(insn) (insn)
+#define INSN_CODE(insn) ((VALUE)(insn))
#endif
st_data_t insn;
encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2);
@@ -3661,32 +3655,9 @@ rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
}
}
+bool rb_vm_call_ivar_attrset_p(const vm_call_handler ch);
void rb_vm_cc_general(const struct rb_callcache *cc);
-static bool
-clear_attr_cc(VALUE v)
-{
- if (imemo_type_p(v, imemo_callcache) && vm_cc_ivar_p((const struct rb_callcache *)v)) {
- rb_vm_cc_general((struct rb_callcache *)v);
- return true;
- }
- else {
- return false;
- }
-}
-
-static bool
-clear_bf_cc(VALUE v)
-{
- if (imemo_type_p(v, imemo_callcache) && vm_cc_bf_p((const struct rb_callcache *)v)) {
- rb_vm_cc_general((struct rb_callcache *)v);
- return true;
- }
- else {
- return false;
- }
-}
-
static int
clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
{
@@ -3694,35 +3665,20 @@ clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
for (; v != (VALUE)vend; v += stride) {
void *ptr = asan_poisoned_object_p(v);
asan_unpoison_object(v, false);
- clear_attr_cc(v);
- asan_poison_object_if(ptr, v);
- }
- return 0;
-}
-void
-rb_clear_attr_ccs(void)
-{
- rb_objspace_each_objects(clear_attr_ccs_i, NULL);
-}
+ if (imemo_type_p(v, imemo_callcache) && rb_vm_call_ivar_attrset_p(((const struct rb_callcache *)v)->call_)) {
+ rb_vm_cc_general((struct rb_callcache *)v);
+ }
-static int
-clear_bf_ccs_i(void *vstart, void *vend, size_t stride, void *data)
-{
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- void *ptr = asan_poisoned_object_p(v);
- asan_unpoison_object(v, false);
- clear_bf_cc(v);
asan_poison_object_if(ptr, v);
}
return 0;
}
void
-rb_clear_bf_ccs(void)
+rb_clear_attr_ccs(void)
{
- rb_objspace_each_objects(clear_bf_ccs_i, NULL);
+ rb_objspace_each_objects(clear_attr_ccs_i, NULL);
}
static int
@@ -3738,9 +3694,8 @@ trace_set_i(void *vstart, void *vend, size_t stride, void *data)
if (rb_obj_is_iseq(v)) {
rb_iseq_trace_set(rb_iseq_check((rb_iseq_t *)v), turnon_events);
}
- else if (clear_attr_cc(v)) {
- }
- else if (clear_bf_cc(v)) {
+ else if (imemo_type_p(v, imemo_callcache) && rb_vm_call_ivar_attrset_p(((const struct rb_callcache *)v)->call_)) {
+ rb_vm_cc_general((struct rb_callcache *)v);
}
asan_poison_object_if(ptr, v);
@@ -3955,7 +3910,7 @@ succ_index_lookup(const struct succ_index_table *sd, int x)
* call-seq:
* iseq.script_lines -> array or nil
*
- * It returns recorded script lines if it is available.
+ * It returns recorded script lines if it is availalble.
* The script lines are not limited to the iseq range, but
* are entire lines of the source file.
*
@@ -4028,7 +3983,6 @@ Init_ISeq(void)
(void)iseq_s_load;
rb_define_singleton_method(rb_cISeq, "compile", iseqw_s_compile, -1);
- rb_define_singleton_method(rb_cISeq, "compile_prism", iseqw_s_compile_prism, -1);
rb_define_singleton_method(rb_cISeq, "new", iseqw_s_compile, -1);
rb_define_singleton_method(rb_cISeq, "compile_file", iseqw_s_compile_file, -1);
rb_define_singleton_method(rb_cISeq, "compile_option", iseqw_s_compile_option_get, 0);
diff --git a/iseq.h b/iseq.h
index 1ad07e9065..2f83e7336d 100644
--- a/iseq.h
+++ b/iseq.h
@@ -11,7 +11,6 @@
**********************************************************************/
#include "internal/gc.h"
-#include "shape.h"
#include "vm_core.h"
RUBY_EXTERN const int ruby_api_version[];
@@ -83,10 +82,9 @@ ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size)
RUBY_EVENT_CALL | \
RUBY_EVENT_RETURN| \
RUBY_EVENT_C_CALL| \
- RUBY_EVENT_C_RETURN | \
- RUBY_EVENT_B_CALL | \
- RUBY_EVENT_B_RETURN | \
- RUBY_EVENT_RESCUE | \
+ RUBY_EVENT_C_RETURN| \
+ RUBY_EVENT_B_CALL| \
+ RUBY_EVENT_B_RETURN| \
RUBY_EVENT_COVERAGE_LINE| \
RUBY_EVENT_COVERAGE_BRANCH)
@@ -116,6 +114,7 @@ struct iseq_compile_data {
struct iseq_compile_data_storage *storage_current;
} insn;
bool in_rescue;
+ bool in_masgn;
int loopval_popped; /* used by NODE_BREAK */
int last_line;
int label_no;
@@ -127,7 +126,6 @@ struct iseq_compile_data {
struct rb_id_table *ivar_cache_table;
const struct rb_builtin_function *builtin_function_table;
const NODE *root_node;
- bool catch_except_p; // If a frame of this ISeq may catch exception, set true.
#if OPT_SUPPORT_JOKE
st_table *labels_table;
#endif
@@ -189,7 +187,7 @@ VALUE *rb_iseq_original_iseq(const rb_iseq_t *iseq);
void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc,
VALUE locals, VALUE args,
VALUE exception, VALUE body);
-void rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *arena);
+void rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *arena);
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc);
@@ -227,6 +225,7 @@ struct rb_compile_option_struct {
unsigned int specialized_instruction: 1;
unsigned int operands_unification: 1;
unsigned int instructions_unification: 1;
+ unsigned int stack_caching: 1;
unsigned int frozen_string_literal: 1;
unsigned int debug_frozen_string_literal: 1;
unsigned int coverage_enabled: 1;
@@ -272,11 +271,10 @@ struct iseq_catch_table_entry {
unsigned int sp;
};
-RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
-struct iseq_catch_table {
+PACKED_STRUCT_UNALIGNED(struct iseq_catch_table {
unsigned int size;
struct iseq_catch_table_entry entries[FLEX_ARY_LEN];
-} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
+});
static inline int
iseq_catch_table_bytes(int n)
@@ -327,8 +325,6 @@ VALUE rb_iseq_defined_string(enum defined_type type);
/* vm.c */
VALUE rb_iseq_local_variables(const rb_iseq_t *iseq);
-attr_index_t rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq);
-
RUBY_SYMBOL_EXPORT_END
#endif /* RUBY_ISEQ_H */
diff --git a/kernel.rb b/kernel.rb
index c6b3e44000..9cc58bc1d9 100644
--- a/kernel.rb
+++ b/kernel.rb
@@ -16,7 +16,7 @@ module Kernel
#++
#
def class
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_obj_class(self)'
end
@@ -65,7 +65,7 @@ module Kernel
#++
#
def frozen?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_obj_frozen_p(self)'
end
@@ -117,17 +117,8 @@ module Kernel
# # does not meet condition, drop value
# 2.then.detect(&:odd?) # => nil
#
- # Good usage for +then+ is value piping in method chains:
- #
- # require 'open-uri'
- # require 'json'
- #
- # construct_url(arguments).
- # then {|url| URI(url).read }.
- # then {|response| JSON.parse(response) }
- #
def then
- unless block_given?
+ unless Primitive.block_given_p
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
end
yield(self)
@@ -141,8 +132,17 @@ module Kernel
#
# "my string".yield_self {|s| s.upcase } #=> "MY STRING"
#
+ # Good usage for +then+ is value piping in method chains:
+ #
+ # require 'open-uri'
+ # require 'json'
+ #
+ # construct_url(arguments).
+ # then {|url| URI(url).read }.
+ # then {|response| JSON.parse(response) }
+ #
def yield_self
- unless block_given?
+ unless Primitive.block_given_p
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
end
yield(self)
@@ -150,47 +150,6 @@ module Kernel
module_function
- # call-seq:
- # loop { block }
- # loop -> an_enumerator
- #
- # Repeatedly executes the block.
- #
- # If no block is given, an enumerator is returned instead.
- #
- # loop do
- # print "Input: "
- # line = gets
- # break if !line or line =~ /^q/i
- # # ...
- # end
- #
- # StopIteration raised in the block breaks the loop. In this case,
- # loop returns the "result" value stored in the exception.
- #
- # enum = Enumerator.new { |y|
- # y << "one"
- # y << "two"
- # :ok
- # }
- #
- # result = loop {
- # puts enum.next
- # } #=> :ok
- def loop
- unless block_given?
- return enum_for(:loop) { Float::INFINITY }
- end
-
- begin
- while true
- yield
- end
- rescue StopIteration => e
- e.result
- end
- end
-
#
# call-seq:
# Float(arg, exception: true) -> float or nil
@@ -216,97 +175,4 @@ module Kernel
Primitive.rb_f_float(arg, exception)
end
end
-
- # call-seq:
- # Integer(object, base = 0, exception: true) -> integer or nil
- #
- # Returns an integer converted from +object+.
- #
- # Tries to convert +object+ to an integer
- # using +to_int+ first and +to_i+ second;
- # see below for exceptions.
- #
- # With a non-zero +base+, +object+ must be a string or convertible
- # to a string.
- #
- # ==== numeric objects
- #
- # With integer argument +object+ given, returns +object+:
- #
- # Integer(1) # => 1
- # Integer(-1) # => -1
- #
- # With floating-point argument +object+ given,
- # returns +object+ truncated to an integer:
- #
- # Integer(1.9) # => 1 # Rounds toward zero.
- # Integer(-1.9) # => -1 # Rounds toward zero.
- #
- # ==== string objects
- #
- # With string argument +object+ and zero +base+ given,
- # returns +object+ converted to an integer in base 10:
- #
- # Integer('100') # => 100
- # Integer('-100') # => -100
- #
- # With +base+ zero, string +object+ may contain leading characters
- # to specify the actual base (radix indicator):
- #
- # Integer('0100') # => 64 # Leading '0' specifies base 8.
- # Integer('0b100') # => 4 # Leading '0b', specifies base 2.
- # Integer('0x100') # => 256 # Leading '0x' specifies base 16.
- #
- # With a positive +base+ (in range 2..36) given, returns +object+
- # converted to an integer in the given base:
- #
- # Integer('100', 2) # => 4
- # Integer('100', 8) # => 64
- # Integer('-100', 16) # => -256
- #
- # With a negative +base+ (in range -36..-2) given, returns +object+
- # converted to an integer in the radix indicator if exists or
- # +-base+:
- #
- # Integer('0x100', -2) # => 256
- # Integer('100', -2) # => 4
- # Integer('0b100', -8) # => 4
- # Integer('100', -8) # => 64
- # Integer('0o100', -10) # => 64
- # Integer('100', -10) # => 100
- #
- # +base+ -1 is equal the -10 case.
- #
- # When converting strings, surrounding whitespace and embedded underscores
- # are allowed and ignored:
- #
- # Integer(' 100 ') # => 100
- # Integer('-1_0_0', 16) # => -256
- #
- # ==== other classes
- #
- # Examples with +object+ of various other classes:
- #
- # Integer(Rational(9, 10)) # => 0 # Rounds toward zero.
- # Integer(Complex(2, 0)) # => 2 # Imaginary part must be zero.
- # Integer(Time.now) # => 1650974042
- #
- # ==== keywords
- #
- # With optional keyword argument +exception+ given as +true+ (the default):
- #
- # - Raises TypeError if +object+ does not respond to +to_int+ or +to_i+.
- # - Raises TypeError if +object+ is +nil+.
- # - Raise ArgumentError if +object+ is an invalid string.
- #
- # With +exception+ given as +false+, an exception of any kind is suppressed
- # and +nil+ is returned.
-
- def Integer(arg, base = 0, exception: true)
- if Primitive.mandatory_only?
- Primitive.rb_f_integer1(arg)
- else
- Primitive.rb_f_integer(arg, base, exception);
- end
- end
end
diff --git a/lib/English.gemspec b/lib/English.gemspec
index 5f4eb420c2..a08542bcda 100644
--- a/lib/English.gemspec
+++ b/lib/English.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "english"
- spec.version = "0.8.0"
+ spec.version = "0.7.2"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.require_paths = ["lib"]
end
diff --git a/lib/English.rb b/lib/English.rb
index 03fe721991..ec90ff10cd 100644
--- a/lib/English.rb
+++ b/lib/English.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
# Include the English library file in a Ruby script, and you can
-# reference the global variables such as <code>$_</code> using less
+# reference the global variables such as <tt>$_</tt> using less
# cryptic names, listed below.
#
# Without 'English':
@@ -39,6 +39,7 @@
# $PROCESS_ID:: $$
# $CHILD_STATUS:: $?
# $LAST_MATCH_INFO:: $~
+# $IGNORECASE:: $=
# $ARGV:: $*
# $MATCH:: $&
# $PREMATCH:: $`
@@ -55,73 +56,87 @@ alias $ERROR_INFO $!
alias $ERROR_POSITION $@
# The default separator pattern used by String#split. May be set from
-# the command line using the <code>-F</code> flag.
+# the command line using the <tt>-F</tt> flag.
alias $FS $;
+
+# The default separator pattern used by String#split. May be set from
+# the command line using the <tt>-F</tt> flag.
alias $FIELD_SEPARATOR $;
# The separator string output between the parameters to methods such
# as Kernel#print and Array#join. Defaults to +nil+, which adds no
# text.
+alias $OFS $,
# The separator string output between the parameters to methods such
# as Kernel#print and Array#join. Defaults to +nil+, which adds no
# text.
-alias $OFS $,
alias $OUTPUT_FIELD_SEPARATOR $,
# The input record separator (newline by default). This is the value
# that routines such as Kernel#gets use to determine record
# boundaries. If set to +nil+, +gets+ will read the entire file.
alias $RS $/
+
+# The input record separator (newline by default). This is the value
+# that routines such as Kernel#gets use to determine record
+# boundaries. If set to +nil+, +gets+ will read the entire file.
alias $INPUT_RECORD_SEPARATOR $/
# The string appended to the output of every call to methods such as
# Kernel#print and IO#write. The default value is +nil+.
alias $ORS $\
+
+# The string appended to the output of every call to methods such as
+# Kernel#print and IO#write. The default value is +nil+.
alias $OUTPUT_RECORD_SEPARATOR $\
# The number of the last line read from the current input file.
-alias $NR $.
alias $INPUT_LINE_NUMBER $.
+# The number of the last line read from the current input file.
+alias $NR $.
+
# The last line read by Kernel#gets or
# Kernel#readline. Many string-related functions in the
-# Kernel module operate on <code>$_</code> by default. The variable is
+# Kernel module operate on <tt>$_</tt> by default. The variable is
# local to the current scope. Thread local.
alias $LAST_READ_LINE $_
# The destination of output for Kernel#print
# and Kernel#printf. The default value is
-# <code>$stdout</code>.
+# <tt>$stdout</tt>.
alias $DEFAULT_OUTPUT $>
# An object that provides access to the concatenation
# of the contents of all the files
-# given as command-line arguments, or <code>$stdin</code>
+# given as command-line arguments, or <tt>$stdin</tt>
# (in the case where there are no
-# arguments). <code>$<</code> supports methods similar to a
+# arguments). <tt>$<</tt> supports methods similar to a
# File object:
# +inmode+, +close+,
-# <code>closed?</code>, +each+,
-# <code>each_byte</code>, <code>each_line</code>,
-# +eof+, <code>eof?</code>, +file+,
+# <tt>closed?</tt>, +each+,
+# <tt>each_byte</tt>, <tt>each_line</tt>,
+# +eof+, <tt>eof?</tt>, +file+,
# +filename+, +fileno+,
# +getc+, +gets+, +lineno+,
-# <code>lineno=</code>, +path+,
-# +pos+, <code>pos=</code>,
+# <tt>lineno=</tt>, +path+,
+# +pos+, <tt>pos=</tt>,
# +read+, +readchar+,
# +readline+, +readlines+,
# +rewind+, +seek+, +skip+,
-# +tell+, <code>to_a</code>, <code>to_i</code>,
-# <code>to_io</code>, <code>to_s</code>, along with the
+# +tell+, <tt>to_a</tt>, <tt>to_i</tt>,
+# <tt>to_io</tt>, <tt>to_s</tt>, along with the
# methods in Enumerable. The method +file+
# returns a File object for the file currently
-# being read. This may change as <code>$<</code> reads
+# being read. This may change as <tt>$<</tt> reads
# through the files on the command line. Read only.
alias $DEFAULT_INPUT $<
# The process number of the program being executed. Read only.
alias $PID $$
+
+# The process number of the program being executed. Read only.
alias $PROCESS_ID $$
# The exit status of the last child process to terminate. Read
@@ -129,13 +144,16 @@ alias $PROCESS_ID $$
alias $CHILD_STATUS $?
# A +MatchData+ object that encapsulates the results of a successful
-# pattern match. The variables <code>$&</code>, <code>$`</code>, <code>$'</code>,
-# and <code>$1</code> to <code>$9</code> are all derived from
-# <code>$~</code>. Assigning to <code>$~</code> changes the values of these
+# pattern match. The variables <tt>$&</tt>, <tt>$`</tt>, <tt>$'</tt>,
+# and <tt>$1</tt> to <tt>$9</tt> are all derived from
+# <tt>$~</tt>. Assigning to <tt>$~</tt> changes the values of these
# derived variables. This variable is local to the current
# scope.
alias $LAST_MATCH_INFO $~
+# This variable is no longer effective. Deprecated.
+alias $IGNORECASE $=
+
# An array of strings containing the command-line
# options from the invocation of the program. Options
# used by the Ruby interpreter will have been
@@ -158,7 +176,7 @@ alias $PREMATCH $`
alias $POSTMATCH $'
# The contents of the highest-numbered group matched in the last
-# successful pattern match. Thus, in <code>"cat" =~ /(c|a)(t|z)/</code>,
-# <code>$+</code> will be set to "t". This variable is local to the
+# successful pattern match. Thus, in <tt>"cat" =~ /(c|a)(t|z)/</tt>,
+# <tt>$+</tt> will be set to "t". This variable is local to the
# current scope. Read only.
alias $LAST_PAREN_MATCH $+
diff --git a/lib/abbrev.gemspec b/lib/abbrev.gemspec
index 50c500bbc7..c28b960c8c 100644
--- a/lib/abbrev.gemspec
+++ b/lib/abbrev.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "abbrev"
+ spec.version = "0.1.1"
spec.authors = ["Akinori MUSHA"]
spec.email = ["knu@idaemons.org"]
diff --git a/lib/abbrev.rb b/lib/abbrev.rb
index ee86f06874..2af01d2eae 100644
--- a/lib/abbrev.rb
+++ b/lib/abbrev.rb
@@ -47,7 +47,6 @@
# "w" => "winter" }
module Abbrev
- VERSION = "0.1.1"
# Given a set of strings, calculate the set of unambiguous abbreviations for
# those strings, and return a hash where the keys are all the possible
diff --git a/lib/base64.gemspec b/lib/base64.gemspec
index c013b7c1c2..daa0b7fa14 100644
--- a/lib/base64.gemspec
+++ b/lib/base64.gemspec
@@ -1,20 +1,13 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "base64"
+ spec.version = "0.1.1"
spec.authors = ["Yusuke Endoh"]
spec.email = ["mame@ruby-lang.org"]
spec.summary = %q{Support for encoding and decoding binary data using a Base64 representation.}
spec.description = %q{Support for encoding and decoding binary data using a Base64 representation.}
spec.homepage = "https://github.com/ruby/base64"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.metadata["homepage_uri"] = spec.homepage
diff --git a/lib/base64.rb b/lib/base64.rb
index cd2ecc18ea..693aa1f519 100644
--- a/lib/base64.rb
+++ b/lib/base64.rb
@@ -1,330 +1,85 @@
# frozen_string_literal: true
#
-# \Module \Base64 provides methods for:
+# = base64.rb: methods for base64-encoding and -decoding strings
#
-# - Encoding a binary string (containing non-ASCII characters)
-# as a string of printable ASCII characters.
-# - Decoding such an encoded string.
-#
-# \Base64 is commonly used in contexts where binary data
-# is not allowed or supported:
-#
-# - Images in HTML or CSS files, or in URLs.
-# - Email attachments.
-#
-# A \Base64-encoded string is about one-third larger that its source.
-# See the {Wikipedia article}[https://en.wikipedia.org/wiki/Base64]
-# for more information.
-#
-# This module provides three pairs of encode/decode methods.
-# Your choices among these methods should depend on:
-#
-# - Which character set is to be used for encoding and decoding.
-# - Whether "padding" is to be used.
-# - Whether encoded strings are to contain newlines.
-#
-# Note: Examples on this page assume that the including program has executed:
-#
-# require 'base64'
-#
-# == Encoding Character Sets
-#
-# A \Base64-encoded string consists only of characters from a 64-character set:
-#
-# - <tt>('A'..'Z')</tt>.
-# - <tt>('a'..'z')</tt>.
-# - <tt>('0'..'9')</tt>.
-# - <tt>=</tt>, the 'padding' character.
-# - Either:
-# - <tt>%w[+ /]</tt>:
-# {RFC-2045-compliant}[https://datatracker.ietf.org/doc/html/rfc2045];
-# _not_ safe for URLs.
-# - <tt>%w[- _]</tt>:
-# {RFC-4648-compliant}[https://datatracker.ietf.org/doc/html/rfc4648];
-# safe for URLs.
-#
-# If you are working with \Base64-encoded strings that will come from
-# or be put into URLs, you should choose this encoder-decoder pair
-# of RFC-4648-compliant methods:
-#
-# - Base64.urlsafe_encode64 and Base64.urlsafe_decode64.
-#
-# Otherwise, you may choose any of the pairs in this module,
-# including the pair above, or the RFC-2045-compliant pairs:
-#
-# - Base64.encode64 and Base64.decode64.
-# - Base64.strict_encode64 and Base64.strict_decode64.
-#
-# == Padding
-#
-# \Base64-encoding changes a triplet of input bytes
-# into a quartet of output characters.
-#
-# <b>Padding in Encode Methods</b>
-#
-# Padding -- extending an encoded string with zero, one, or two trailing
-# <tt>=</tt> characters -- is performed by methods Base64.encode64,
-# Base64.strict_encode64, and, by default, Base64.urlsafe_encode64:
-#
-# Base64.encode64('s') # => "cw==\n"
-# Base64.strict_encode64('s') # => "cw=="
-# Base64.urlsafe_encode64('s') # => "cw=="
-# Base64.urlsafe_encode64('s', padding: false) # => "cw"
-#
-# When padding is performed, the encoded string is always of length <em>4n</em>,
-# where +n+ is a non-negative integer:
-#
-# - Input bytes of length <em>3n</em> generate unpadded output characters
-# of length <em>4n</em>:
-#
-# # n = 1: 3 bytes => 4 characters.
-# Base64.strict_encode64('123') # => "MDEy"
-# # n = 2: 6 bytes => 8 characters.
-# Base64.strict_encode64('123456') # => "MDEyMzQ1"
-#
-# - Input bytes of length <em>3n+1</em> generate padded output characters
-# of length <em>4(n+1)</em>, with two padding characters at the end:
-#
-# # n = 1: 4 bytes => 8 characters.
-# Base64.strict_encode64('1234') # => "MDEyMw=="
-# # n = 2: 7 bytes => 12 characters.
-# Base64.strict_encode64('1234567') # => "MDEyMzQ1Ng=="
-#
-# - Input bytes of length <em>3n+2</em> generate padded output characters
-# of length <em>4(n+1)</em>, with one padding character at the end:
-#
-# # n = 1: 5 bytes => 8 characters.
-# Base64.strict_encode64('12345') # => "MDEyMzQ="
-# # n = 2: 8 bytes => 12 characters.
-# Base64.strict_encode64('12345678') # => "MDEyMzQ1Njc="
-#
-# When padding is suppressed, for a positive integer <em>n</em>:
-#
-# - Input bytes of length <em>3n</em> generate unpadded output characters
-# of length <em>4n</em>:
-#
-# # n = 1: 3 bytes => 4 characters.
-# Base64.urlsafe_encode64('123', padding: false) # => "MDEy"
-# # n = 2: 6 bytes => 8 characters.
-# Base64.urlsafe_encode64('123456', padding: false) # => "MDEyMzQ1"
-#
-# - Input bytes of length <em>3n+1</em> generate unpadded output characters
-# of length <em>4n+2</em>, with two padding characters at the end:
-#
-# # n = 1: 4 bytes => 6 characters.
-# Base64.urlsafe_encode64('1234', padding: false) # => "MDEyMw"
-# # n = 2: 7 bytes => 10 characters.
-# Base64.urlsafe_encode64('1234567', padding: false) # => "MDEyMzQ1Ng"
-#
-# - Input bytes of length <em>3n+2</em> generate unpadded output characters
-# of length <em>4n+3</em>, with one padding character at the end:
-#
-# # n = 1: 5 bytes => 7 characters.
-# Base64.urlsafe_encode64('12345', padding: false) # => "MDEyMzQ"
-# # m = 2: 8 bytes => 11 characters.
-# Base64.urlsafe_encode64('12345678', padding: false) # => "MDEyMzQ1Njc"
-#
-# <b>Padding in Decode Methods</b>
-#
-# All of the \Base64 decode methods support (but do not require) padding.
-#
-# \Method Base64.decode64 does not check the size of the padding:
-#
-# Base64.decode64("MDEyMzQ1Njc") # => "01234567"
-# Base64.decode64("MDEyMzQ1Njc=") # => "01234567"
-# Base64.decode64("MDEyMzQ1Njc==") # => "01234567"
-#
-# \Method Base64.strict_decode64 strictly enforces padding size:
-#
-# Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError
-# Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567"
-# Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError
-#
-# \Method Base64.urlsafe_decode64 allows padding in +str+,
-# which if present, must be correct:
-# see {Padding}[Base64.html#module-Base64-label-Padding], above:
-#
-# Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567"
-# Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567"
-# Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError.
-#
-# == Newlines
-#
-# An encoded string returned by Base64.encode64 or Base64.urlsafe_encode64
-# has an embedded newline character
-# after each 60-character sequence, and, if non-empty, at the end:
-#
-# # No newline if empty.
-# encoded = Base64.encode64("\x00" * 0)
-# encoded.index("\n") # => nil
-#
-# # Newline at end of short output.
-# encoded = Base64.encode64("\x00" * 1)
-# encoded.size # => 4
-# encoded.index("\n") # => 4
+
+# The Base64 module provides for the encoding (#encode64, #strict_encode64,
+# #urlsafe_encode64) and decoding (#decode64, #strict_decode64,
+# #urlsafe_decode64) of binary data using a Base64 representation.
#
-# # Newline at end of longer output.
-# encoded = Base64.encode64("\x00" * 45)
-# encoded.size # => 60
-# encoded.index("\n") # => 60
+# == Example
#
-# # Newlines embedded and at end of still longer output.
-# encoded = Base64.encode64("\x00" * 46)
-# encoded.size # => 65
-# encoded.rindex("\n") # => 65
-# encoded.split("\n").map {|s| s.size } # => [60, 4]
+# A simple encoding and decoding.
#
-# The string to be encoded may itself contain newlines,
-# which are encoded as \Base64:
+# require "base64"
#
-# # Base64.encode64("\n\n\n") # => "CgoK\n"
-# s = "This is line 1\nThis is line 2\n"
-# Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n"
+# enc = Base64.encode64('Send reinforcements')
+# # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n"
+# plain = Base64.decode64(enc)
+# # -> "Send reinforcements"
#
-module Base64
-
- VERSION = "0.2.0"
+# The purpose of using base64 to encode data is that it translates any
+# binary data into purely printable characters.
+module Base64
module_function
- # Returns a string containing the RFC-2045-compliant \Base64-encoding of +bin+.
- #
- # Per RFC 2045, the returned string may contain the URL-unsafe characters
- # <tt>+</tt> or <tt>/</tt>;
- # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
- #
- # Base64.encode64("\xFB\xEF\xBE") # => "++++\n"
- # Base64.encode64("\xFF\xFF\xFF") # => "////\n"
+ # Returns the Base64-encoded version of +bin+.
+ # This method complies with RFC 2045.
+ # Line feeds are added to every 60 encoded characters.
#
- # The returned string may include padding;
- # see {Padding}[Base64.html#module-Base64-label-Padding] above.
+ # require 'base64'
+ # Base64.encode64("Now is the time for all good coders\nto learn Ruby")
#
- # Base64.encode64('*') # => "Kg==\n"
- #
- # The returned string ends with a newline character, and if sufficiently long
- # will have one or more embedded newline characters;
- # see {Newlines}[Base64.html#module-Base64-label-Newlines] above:
- #
- # Base64.encode64('*') # => "Kg==\n"
- # Base64.encode64('*' * 46)
- # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq\nKg==\n"
- #
- # The string to be encoded may itself contain newlines,
- # which will be encoded as ordinary \Base64:
- #
- # Base64.encode64("\n\n\n") # => "CgoK\n"
- # s = "This is line 1\nThis is line 2\n"
- # Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n"
+ # <i>Generates:</i>
#
+ # Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g
+ # UnVieQ==
def encode64(bin)
[bin].pack("m")
end
- # Returns a string containing the decoding of an RFC-2045-compliant
- # \Base64-encoded string +str+:
- #
- # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n"
- # Base64.decode64(s) # => "This is line 1\nThis is line 2\n"
- #
- # Non-\Base64 characters in +str+ are ignored;
- # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
- # these include newline characters and characters <tt>-</tt> and <tt>/</tt>:
- #
- # Base64.decode64("\x00\n-_") # => ""
- #
- # Padding in +str+ (even if incorrect) is ignored:
- #
- # Base64.decode64("MDEyMzQ1Njc") # => "01234567"
- # Base64.decode64("MDEyMzQ1Njc=") # => "01234567"
- # Base64.decode64("MDEyMzQ1Njc==") # => "01234567"
- #
+ # Returns the Base64-decoded version of +str+.
+ # This method complies with RFC 2045.
+ # Characters outside the base alphabet are ignored.
+ #
+ # require 'base64'
+ # str = 'VGhpcyBpcyBsaW5lIG9uZQpUaGlzIG' +
+ # 'lzIGxpbmUgdHdvClRoaXMgaXMgbGlu' +
+ # 'ZSB0aHJlZQpBbmQgc28gb24uLi4K'
+ # puts Base64.decode64(str)
+ #
+ # <i>Generates:</i>
+ #
+ # This is line one
+ # This is line two
+ # This is line three
+ # And so on...
def decode64(str)
str.unpack1("m")
end
- # Returns a string containing the RFC-2045-compliant \Base64-encoding of +bin+.
- #
- # Per RFC 2045, the returned string may contain the URL-unsafe characters
- # <tt>+</tt> or <tt>/</tt>;
- # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
- #
- # Base64.strict_encode64("\xFB\xEF\xBE") # => "++++\n"
- # Base64.strict_encode64("\xFF\xFF\xFF") # => "////\n"
- #
- # The returned string may include padding;
- # see {Padding}[Base64.html#module-Base64-label-Padding] above.
- #
- # Base64.strict_encode64('*') # => "Kg==\n"
- #
- # The returned string will have no newline characters, regardless of its length;
- # see {Newlines}[Base64.html#module-Base64-label-Newlines] above:
- #
- # Base64.strict_encode64('*') # => "Kg=="
- # Base64.strict_encode64('*' * 46)
- # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg=="
- #
- # The string to be encoded may itself contain newlines,
- # which will be encoded as ordinary \Base64:
- #
- # Base64.strict_encode64("\n\n\n") # => "CgoK"
- # s = "This is line 1\nThis is line 2\n"
- # Base64.strict_encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK"
- #
+ # Returns the Base64-encoded version of +bin+.
+ # This method complies with RFC 4648.
+ # No line feeds are added.
def strict_encode64(bin)
[bin].pack("m0")
end
- # Returns a string containing the decoding of an RFC-2045-compliant
- # \Base64-encoded string +str+:
- #
- # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK"
- # Base64.strict_decode64(s) # => "This is line 1\nThis is line 2\n"
- #
- # Non-\Base64 characters in +str+ not allowed;
- # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
- # these include newline characters and characters <tt>-</tt> and <tt>/</tt>:
- #
- # Base64.strict_decode64("\n") # Raises ArgumentError
- # Base64.strict_decode64('-') # Raises ArgumentError
- # Base64.strict_decode64('_') # Raises ArgumentError
- #
- # Padding in +str+, if present, must be correct:
- #
- # Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError
- # Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567"
- # Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError
- #
+ # Returns the Base64-decoded version of +str+.
+ # This method complies with RFC 4648.
+ # ArgumentError is raised if +str+ is incorrectly padded or contains
+ # non-alphabet characters. Note that CR or LF are also rejected.
def strict_decode64(str)
str.unpack1("m0")
end
- # Returns the RFC-4648-compliant \Base64-encoding of +bin+.
- #
- # Per RFC 4648, the returned string will not contain the URL-unsafe characters
- # <tt>+</tt> or <tt>/</tt>,
- # but instead may contain the URL-safe characters
- # <tt>-</tt> and <tt>_</tt>;
- # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
- #
- # Base64.urlsafe_encode64("\xFB\xEF\xBE") # => "----"
- # Base64.urlsafe_encode64("\xFF\xFF\xFF") # => "____"
- #
- # By default, the returned string may have padding;
- # see {Padding}[Base64.html#module-Base64-label-Padding], above:
- #
- # Base64.urlsafe_encode64('*') # => "Kg=="
- #
- # Optionally, you can suppress padding:
- #
- # Base64.urlsafe_encode64('*', padding: false) # => "Kg"
- #
- # The returned string will have no newline characters, regardless of its length;
- # see {Newlines}[Base64.html#module-Base64-label-Newlines] above:
- #
- # Base64.urlsafe_encode64('*') # => "Kg=="
- # Base64.urlsafe_encode64('*' * 46)
- # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg=="
- #
+ # Returns the Base64-encoded version of +bin+.
+ # This method complies with ``Base 64 Encoding with URL and Filename Safe
+ # Alphabet'' in RFC 4648.
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
+ # Note that the result can still contain '='.
+ # You can remove the padding by setting +padding+ as false.
def urlsafe_encode64(bin, padding: true)
str = strict_encode64(bin)
str.chomp!("==") or str.chomp!("=") unless padding
@@ -332,22 +87,14 @@ module Base64
str
end
- # Returns the decoding of an RFC-4648-compliant \Base64-encoded string +str+:
- #
- # +str+ may not contain non-Base64 characters;
- # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
- #
- # Base64.urlsafe_decode64('+') # Raises ArgumentError.
- # Base64.urlsafe_decode64('/') # Raises ArgumentError.
- # Base64.urlsafe_decode64("\n") # Raises ArgumentError.
- #
- # Padding in +str+, if present, must be correct:
- # see {Padding}[Base64.html#module-Base64-label-Padding], above:
- #
- # Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567"
- # Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567"
- # Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError.
- #
+ # Returns the Base64-decoded version of +str+.
+ # This method complies with ``Base 64 Encoding with URL and Filename Safe
+ # Alphabet'' in RFC 4648.
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
+ #
+ # The padding character is optional.
+ # This method accepts both correctly-padded and unpadded input.
+ # Note that it still rejects incorrectly-padded input.
def urlsafe_decode64(str)
# NOTE: RFC 4648 does say nothing about unpadded input, but says that
# "the excess pad characters MAY also be ignored", so it is inferred that
diff --git a/lib/benchmark.gemspec b/lib/benchmark.gemspec
deleted file mode 100644
index d6e98db805..0000000000
--- a/lib/benchmark.gemspec
+++ /dev/null
@@ -1,30 +0,0 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{a performance benchmarking library}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/benchmark"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = []
- spec.require_paths = ["lib"]
-end
diff --git a/lib/benchmark.rb b/lib/benchmark.rb
index 9f43255e42..79c782e262 100644
--- a/lib/benchmark.rb
+++ b/lib/benchmark.rb
@@ -121,8 +121,6 @@
module Benchmark
- VERSION = "0.3.0"
-
BENCHMARK_VERSION = "2002-04-25" # :nodoc:
# Invokes the block with a Benchmark::Report object, which
diff --git a/lib/benchmark/benchmark.gemspec b/lib/benchmark/benchmark.gemspec
new file mode 100644
index 0000000000..58b47d95e1
--- /dev/null
+++ b/lib/benchmark/benchmark.gemspec
@@ -0,0 +1,29 @@
+begin
+ require_relative "lib/benchmark/version"
+rescue LoadError # Fallback to load version file in ruby core repository
+ require_relative "version"
+end
+
+Gem::Specification.new do |spec|
+ spec.name = "benchmark"
+ spec.version = Benchmark::VERSION
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{a performance benchmarking library}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/benchmark"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = []
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/benchmark/version.rb b/lib/benchmark/version.rb
new file mode 100644
index 0000000000..645966fd80
--- /dev/null
+++ b/lib/benchmark/version.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+module Benchmark
+ VERSION = "0.2.1"
+end
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb
deleted file mode 100644
index ceb546f580..0000000000
--- a/lib/bundled_gems.rb
+++ /dev/null
@@ -1,134 +0,0 @@
-module Gem::BUNDLED_GEMS
- SINCE = {
- "rexml" => "3.0.0",
- "rss" => "3.0.0",
- "webrick" => "3.0.0",
- "matrix" => "3.1.0",
- "net-ftp" => "3.1.0",
- "net-imap" => "3.1.0",
- "net-pop" => "3.1.0",
- "net-smtp" => "3.1.0",
- "prime" => "3.1.0",
- "abbrev" => "3.4.0",
- "base64" => "3.4.0",
- "bigdecimal" => "3.4.0",
- "csv" => "3.4.0",
- "drb" => "3.4.0",
- "getoptlong" => "3.4.0",
- "mutex_m" => "3.4.0",
- "nkf" => "3.4.0",
- "observer" => "3.4.0",
- "racc" => "3.4.0",
- "resolv-replace" => "3.4.0",
- "rinda" => "3.4.0",
- "syslog" => "3.4.0",
- }.freeze
-
- EXACT = {
- "abbrev" => true,
- "base64" => true,
- "bigdecimal" => true,
- "csv" => true,
- "drb" => true,
- "getoptlong" => true,
- "mutex_m" => true,
- "nkf" => true, "kconv" => "nkf",
- "observer" => true,
- "resolv-replace" => true,
- "rinda" => true,
- "syslog" => true,
- }.freeze
-
- PREFIXED = {
- "bigdecimal" => true,
- "csv" => true,
- "drb" => true,
- "rinda" => true,
- "syslog" => true,
- }.freeze
-
- WARNED = {} # unfrozen
-
- conf = ::RbConfig::CONFIG
- LIBDIR = (conf["rubylibdir"] + "/").freeze
- ARCHDIR = (conf["rubyarchdir"] + "/").freeze
- dlext = [conf["DLEXT"], "so"].uniq
- DLEXT = /\.#{Regexp.union(dlext)}\z/
- LIBEXT = /\.#{Regexp.union("rb", *dlext)}\z/
-
- def self.find_gem(path)
- if !path
- return
- elsif path.start_with?(ARCHDIR)
- n = path.delete_prefix(ARCHDIR).sub(DLEXT, "")
- elsif path.start_with?(LIBDIR)
- n = path.delete_prefix(LIBDIR).chomp(".rb")
- else
- return
- end
- EXACT[n] or PREFIXED[n = n[%r[\A[^/]+(?=/)]]] && n
- end
-
- def self.warning?(name, specs: nil)
- name = File.path(name) # name can be a feature name or a file path with String or Pathname
- return if specs.to_a.map(&:name).include?(name.sub(LIBEXT, ""))
- name = name.tr("/", "-")
- _t, path = $:.resolve_feature_path(name)
- return unless gem = find_gem(path)
- caller = caller_locations(3, 3).find {|c| c&.absolute_path}
- return if find_gem(caller&.absolute_path)
- name = name.sub(LIBEXT, "") # assume "foo.rb"/"foo.so" belongs to "foo" gem
- return if WARNED[name]
- WARNED[name] = true
- if gem == true
- gem = name
- elsif gem
- return if WARNED[gem]
- WARNED[gem] = true
- "#{name} is found in #{gem}"
- else
- return
- end + build_message(gem)
- end
-
- def self.build_message(gem)
- msg = " which #{RUBY_VERSION < SINCE[gem] ? "will no longer be" : "is not"} part of the default gems since Ruby #{SINCE[gem]}."
-
- if defined?(Bundler)
- msg += " Add #{gem} to your Gemfile or gemspec."
- # We detect the gem name from caller_locations. We need to skip 2 frames like:
- # lib/ruby/3.3.0+0/bundled_gems.rb:90:in `warning?'",
- # lib/ruby/3.3.0+0/bundler/rubygems_integration.rb:247:in `block (2 levels) in replace_require'",
- location = caller_locations(3,3)[0]&.path
- if File.file?(location) && !location.start_with?(Gem::BUNDLED_GEMS::LIBDIR)
- caller_gem = nil
- Gem.path.each do |path|
- if location =~ %r{#{path}/gems/([\w\-\.]+)}
- caller_gem = $1
- break
- end
- end
- if caller_gem
- msg += " Also contact author of #{caller_gem} to add #{gem} into its gemspec."
- end
- end
- else
- msg += " Install #{gem} from RubyGems."
- end
-
- msg
- end
-
- freeze
-end
-
-# for RubyGems without Bundler environment.
-# If loading library is not part of the default gems and the bundled gems, warn it.
-class LoadError
- def message
- if !defined?(Bundler) && Gem::BUNDLED_GEMS::SINCE[path] && !Gem::BUNDLED_GEMS::WARNED[path]
- warn path + Gem::BUNDLED_GEMS.build_message(path)
- end
- super
- end
-end
diff --git a/lib/bundler.rb b/lib/bundler.rb
index bc28b24e2e..f83268e9cd 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -39,7 +39,6 @@ module Bundler
environment_preserver.replace_with_backup
SUDO_MUTEX = Thread::Mutex.new
- autoload :Checksum, File.expand_path("bundler/checksum", __dir__)
autoload :Definition, File.expand_path("bundler/definition", __dir__)
autoload :Dependency, File.expand_path("bundler/dependency", __dir__)
autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__)
@@ -331,6 +330,14 @@ module Bundler
def rm_rf(path)
FileUtils.remove_entry_secure(path) if path && File.exist?(path)
+ rescue ArgumentError
+ message = <<EOF
+It is a security vulnerability to allow your home directory to be world-writable, and bundler cannot continue.
+You should probably consider fixing this issue by running `chmod o-w ~` on *nix.
+Please refer to https://ruby-doc.org/stdlib-3.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details.
+EOF
+ File.world_writable?(path) ? Bundler.ui.warn(message) : raise
+ raise PathError, "Please fix the world-writable issue with your #{path} directory"
end
def settings
@@ -508,16 +515,7 @@ module Bundler
end
def safe_load_marshal(data)
- if Gem.respond_to?(:load_safe_marshal)
- Gem.load_safe_marshal
- begin
- Gem::SafeMarshal.safe_load(data)
- rescue Gem::SafeMarshal::Reader::Error, Gem::SafeMarshal::Visitors::ToRuby::Error => e
- raise MarshalError, "#{e.class}: #{e.message}"
- end
- else
- load_marshal(data, :marshal_proc => SafeMarshal.proc)
- end
+ load_marshal(data, :marshal_proc => SafeMarshal.proc)
end
def load_gemspec(file, validate = false)
diff --git a/lib/bundler/build_metadata.rb b/lib/bundler/build_metadata.rb
index 29fa833588..8bffb2fae7 100644
--- a/lib/bundler/build_metadata.rb
+++ b/lib/bundler/build_metadata.rb
@@ -29,7 +29,7 @@ module Bundler
# commit instance variable then we can't determine its commits SHA.
git_dir = File.expand_path("../../../.git", __dir__)
if File.directory?(git_dir)
- return @git_commit_sha = IO.popen(%w[git rev-parse --short HEAD], { :chdir => git_dir }, &:read).strip.freeze
+ return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze }
end
@git_commit_sha ||= "unknown"
diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb
deleted file mode 100644
index f8fd386569..0000000000
--- a/lib/bundler/checksum.rb
+++ /dev/null
@@ -1,235 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class Checksum
- ALGO_SEPARATOR = "="
- DEFAULT_ALGORITHM = "sha256"
- private_constant :DEFAULT_ALGORITHM
- DEFAULT_BLOCK_SIZE = 16_384
- private_constant :DEFAULT_BLOCK_SIZE
-
- class << self
- def from_gem(io, pathname, algo = DEFAULT_ALGORITHM)
- digest = Bundler::SharedHelpers.digest(algo.upcase).new
- buf = String.new(:capacity => DEFAULT_BLOCK_SIZE)
- digest << io.readpartial(DEFAULT_BLOCK_SIZE, buf) until io.eof?
- Checksum.new(algo, digest.hexdigest!, Source.new(:gem, pathname))
- end
-
- def from_api(digest, source_uri, algo = DEFAULT_ALGORITHM)
- Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:api, source_uri))
- end
-
- def from_lock(lock_checksum, lockfile_location)
- algo, digest = lock_checksum.strip.split(ALGO_SEPARATOR, 2)
- Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:lock, lockfile_location))
- end
-
- def to_hexdigest(digest, algo = DEFAULT_ALGORITHM)
- return digest unless algo == DEFAULT_ALGORITHM
- return digest if digest.match?(/\A[0-9a-f]{64}\z/i)
- if digest.match?(%r{\A[-0-9a-z_+/]{43}={0,2}\z}i)
- digest = digest.tr("-_", "+/") # fix urlsafe base64
- # transform to hex. Use unpack1 when we drop older rubies
- return digest.unpack("m0").first.unpack("H*").first
- end
- raise ArgumentError, "#{digest.inspect} is not a valid SHA256 hex or base64 digest"
- end
- end
-
- attr_reader :algo, :digest, :sources
-
- def initialize(algo, digest, source)
- @algo = algo
- @digest = digest
- @sources = [source]
- end
-
- def ==(other)
- match?(other) && other.sources == sources
- end
-
- alias_method :eql?, :==
-
- def match?(other)
- other.is_a?(self.class) && other.digest == digest && other.algo == algo
- end
-
- def hash
- digest.hash
- end
-
- def to_s
- "#{to_lock} (from #{sources.first}#{", ..." if sources.size > 1})"
- end
-
- def to_lock
- "#{algo}#{ALGO_SEPARATOR}#{digest}"
- end
-
- def merge!(other)
- return nil unless match?(other)
- @sources.concat(other.sources).uniq!
- self
- end
-
- def formatted_sources
- sources.join("\n and ").concat("\n")
- end
-
- def removable?
- sources.all?(&:removable?)
- end
-
- def removal_instructions
- msg = +""
- i = 1
- sources.each do |source|
- msg << " #{i}. #{source.removal}\n"
- i += 1
- end
- msg << " #{i}. run `bundle install`\n"
- end
-
- def inspect
- abbr = "#{algo}#{ALGO_SEPARATOR}#{digest[0, 8]}"
- from = "from #{sources.join(" and ")}"
- "#<#{self.class}:#{object_id} #{abbr} #{from}>"
- end
-
- class Source
- attr_reader :type, :location
-
- def initialize(type, location)
- @type = type
- @location = location
- end
-
- def removable?
- type == :lock || type == :gem
- end
-
- def ==(other)
- other.is_a?(self.class) && other.type == type && other.location == location
- end
-
- # phrased so that the usual string format is grammatically correct
- # rake (10.3.2) sha256=abc123 from #{to_s}
- def to_s
- case type
- when :lock
- "the lockfile CHECKSUMS at #{location}"
- when :gem
- "the gem at #{location}"
- when :api
- "the API at #{location}"
- else
- "#{location} (#{type})"
- end
- end
-
- # A full sentence describing how to remove the checksum
- def removal
- case type
- when :lock
- "remove the matching checksum in #{location}"
- when :gem
- "remove the gem at #{location}"
- when :api
- "checksums from #{location} cannot be locally modified, you may need to update your sources"
- else
- "remove #{location} (#{type})"
- end
- end
- end
-
- class Store
- attr_reader :store
- protected :store
-
- def initialize
- @store = {}
- end
-
- def initialize_copy(other)
- @store = {}
- other.store.each do |name_tuple, checksums|
- store[name_tuple] = checksums.dup
- end
- end
-
- def inspect
- "#<#{self.class}:#{object_id} size=#{store.size}>"
- end
-
- def fetch(spec, algo = DEFAULT_ALGORITHM)
- store[spec.name_tuple]&.fetch(algo, nil)
- end
-
- # Replace when the new checksum is from the same source.
- # The primary purpose of this registering checksums from gems where there are
- # duplicates of the same gem (according to full_name) in the index.
- # In particular, this is when 2 gems have two similar platforms, e.g.
- # "darwin20" and "darwin-20", both of which resolve to darwin-20.
- # In the Index, the later gem replaces the former, so we do that here.
- #
- # However, if the new checksum is from a different source, we register like normal.
- # This ensures a mismatch error where there are multiple top level sources
- # that contain the same gem with different checksums.
- def replace(spec, checksum)
- return if Bundler.settings[:disable_checksum_validation]
- return unless checksum
-
- name_tuple = spec.name_tuple
- checksums = (store[name_tuple] ||= {})
- existing = checksums[checksum.algo]
-
- # we assume only one source because this is used while building the index
- if !existing || existing.sources.first == checksum.sources.first
- checksums[checksum.algo] = checksum
- else
- register_checksum(name_tuple, checksum)
- end
- end
-
- def register(spec, checksum)
- return if Bundler.settings[:disable_checksum_validation]
- return unless checksum
- register_checksum(spec.name_tuple, checksum)
- end
-
- def merge!(other)
- other.store.each do |name_tuple, checksums|
- checksums.each do |_algo, checksum|
- register_checksum(name_tuple, checksum)
- end
- end
- end
-
- def to_lock(spec)
- name_tuple = spec.name_tuple
- if checksums = store[name_tuple]
- "#{name_tuple.lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}"
- else
- name_tuple.lock_name
- end
- end
-
- private
-
- def register_checksum(name_tuple, checksum)
- return unless checksum
- checksums = (store[name_tuple] ||= {})
- existing = checksums[checksum.algo]
-
- if !existing
- checksums[checksum.algo] = checksum
- elsif existing.merge!(checksum)
- checksum
- else
- raise ChecksumMismatchError.new(name_tuple, existing, checksum)
- end
- end
- end
- end
-end
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index dd91038d64..a3eb494db2 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -771,7 +771,7 @@ module Bundler
def self.deprecated_ext_value?(arguments)
index = arguments.index("--ext")
- next_argument = arguments[index + 1]
+ next_argument = arguments[index+1]
# it is ok when --ext is followed with valid extension value
# for example `bundle gem hello --ext c`
diff --git a/lib/bundler/cli/check.rb b/lib/bundler/cli/check.rb
index 85c49f510a..cc1f37f0c3 100644
--- a/lib/bundler/cli/check.rb
+++ b/lib/bundler/cli/check.rb
@@ -29,7 +29,7 @@ module Bundler
Bundler.ui.warn "Install missing gems with `bundle install`"
exit 1
elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle?
- Bundler.ui.error "This bundle has been frozen, but there is no #{SharedHelpers.relative_lockfile_path} present"
+ Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present"
exit 1
else
Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"]
diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb
index fb064ed702..7f1200f4a0 100644
--- a/lib/bundler/cli/gem.rb
+++ b/lib/bundler/cli/gem.rb
@@ -137,13 +137,10 @@ module Bundler
case config[:ci]
when "github"
templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml")
- config[:ci_config_path] = ".github "
when "gitlab"
templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml")
- config[:ci_config_path] = ".gitlab-ci.yml "
when "circle"
templates.merge!("circleci/config.yml.tt" => ".circleci/config.yml")
- config[:ci_config_path] = ".circleci "
end
if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?",
@@ -236,7 +233,9 @@ module Bundler
end
if use_git
- IO.popen(%w[git add .], { :chdir => target }, &:read)
+ Dir.chdir(target) do
+ `git add .`
+ end
end
# Open gemspec in editor
@@ -349,7 +348,7 @@ module Bundler
Bundler.ui.confirm "Do you want to add a code linter and formatter to your gem? " \
"Supported Linters:\n" \
"* RuboCop: https://rubocop.org\n" \
- "* Standard: https://github.com/standardrb/standard\n" \
+ "* Standard: https://github.com/testdouble/standard\n" \
"\n"
Bundler.ui.info hint_text("linter")
diff --git a/lib/bundler/cli/info.rb b/lib/bundler/cli/info.rb
index 3facde1947..36c7a58f12 100644
--- a/lib/bundler/cli/info.rb
+++ b/lib/bundler/cli/info.rb
@@ -33,7 +33,7 @@ module Bundler
def default_gem_spec(gem_name)
return unless Gem::Specification.respond_to?(:find_all_by_name)
gem_spec = Gem::Specification.find_all_by_name(gem_name).last
- gem_spec if gem_spec&.default_gem?
+ return gem_spec if gem_spec&.default_gem?
end
def spec_not_found(gem_name)
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index f7228db623..c71bcf159f 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -28,8 +28,8 @@ module Bundler
flag = "--deployment flag" if options[:deployment]
flag ||= "--frozen flag" if options[:frozen]
flag ||= "deployment setting"
- raise ProductionError, "The #{flag} requires a lockfile. Please make " \
- "sure you have checked your #{SharedHelpers.relative_lockfile_path} into version control " \
+ raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \
+ "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \
"before deploying."
end
diff --git a/lib/bundler/cli/issue.rb b/lib/bundler/cli/issue.rb
index 5f2924c4bd..b891ecb1d2 100644
--- a/lib/bundler/cli/issue.rb
+++ b/lib/bundler/cli/issue.rb
@@ -5,7 +5,7 @@ require "rbconfig"
module Bundler
class CLI::Issue
def run
- Bundler.ui.info <<~EOS
+ Bundler.ui.info <<-EOS.gsub(/^ {8}/, "")
Did you find an issue with Bundler? Before filing a new issue,
be sure to check out these resources:
diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb
index a03a5bae35..cb3ed27138 100644
--- a/lib/bundler/cli/lock.rb
+++ b/lib/bundler/cli/lock.rb
@@ -32,39 +32,36 @@ module Bundler
elsif update && bundler
update = { :bundler => bundler }
end
+ definition = Bundler.definition(update)
- Bundler.settings.temporary(:frozen => false) do
- definition = Bundler.definition(update)
+ Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update]
- Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update]
-
- options["remove-platform"].each do |platform|
- definition.remove_platform(platform)
- end
+ options["remove-platform"].each do |platform|
+ definition.remove_platform(platform)
+ end
- options["add-platform"].each do |platform_string|
- platform = Gem::Platform.new(platform_string)
- if platform.to_s == "unknown"
- Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \
- "and adding it will likely lead to resolution errors"
- end
- definition.add_platform(platform)
+ options["add-platform"].each do |platform_string|
+ platform = Gem::Platform.new(platform_string)
+ if platform.to_s == "unknown"
+ Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \
+ "and adding it will likely lead to resolution errors"
end
+ definition.add_platform(platform)
+ end
- if definition.platforms.empty?
- raise InvalidOption, "Removing all platforms from the bundle is not allowed"
- end
+ if definition.platforms.empty?
+ raise InvalidOption, "Removing all platforms from the bundle is not allowed"
+ end
- definition.resolve_remotely! unless options[:local]
+ definition.resolve_remotely! unless options[:local]
- if print
- puts definition.to_lock
- else
- file = options[:lockfile]
- file = file ? File.expand_path(file) : Bundler.default_lockfile
- puts "Writing lockfile to #{file}"
- definition.lock(file)
- end
+ if print
+ puts definition.to_lock
+ else
+ file = options[:lockfile]
+ file = file ? File.expand_path(file) : Bundler.default_lockfile
+ puts "Writing lockfile to #{file}"
+ definition.lock(file)
end
Bundler.ui.level = previous_ui_level
diff --git a/lib/bundler/cli/open.rb b/lib/bundler/cli/open.rb
index 87c1c3b1db..8522ec92d6 100644
--- a/lib/bundler/cli/open.rb
+++ b/lib/bundler/cli/open.rb
@@ -18,11 +18,13 @@ module Bundler
Bundler.ui.info "Unable to open #{name} because it's a default gem, so the directory it would normally be installed to does not exist."
else
root_path = spec.full_gem_path
- require "shellwords"
- command = Shellwords.split(editor) << File.join([root_path, path].compact)
- Bundler.with_original_env do
- system(*command, { :chdir => root_path })
- end || Bundler.ui.info("Could not run '#{command.join(" ")}'")
+ Dir.chdir(root_path) do
+ require "shellwords"
+ command = Shellwords.split(editor) << File.join([root_path, path].compact)
+ Bundler.with_original_env do
+ system(*command)
+ end || Bundler.ui.info("Could not run '#{command.join(" ")}'")
+ end
end
end
end
diff --git a/lib/bundler/cli/show.rb b/lib/bundler/cli/show.rb
index 59b0af42e1..2df13db1fa 100644
--- a/lib/bundler/cli/show.rb
+++ b/lib/bundler/cli/show.rb
@@ -40,8 +40,8 @@ module Bundler
desc = " * #{s.name} (#{s.version}#{s.git_version})"
if @verbose
latest = latest_specs.find {|l| l.name == s.name }
- Bundler.ui.info <<~END
- #{desc.lstrip}
+ Bundler.ui.info <<-END.gsub(/^ +/, "")
+ #{desc}
\tSummary: #{s.summary || "No description available."}
\tHomepage: #{s.homepage || "No website available."}
\tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"}
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index 22dd1a78dd..b49182655b 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -63,7 +63,6 @@ module Bundler
opts = options.dup
opts["update"] = true
opts["local"] = options[:local]
- opts["force"] = options[:redownload]
Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
diff --git a/lib/bundler/compact_index_client/cache.rb b/lib/bundler/compact_index_client/cache.rb
index b5607c8751..0b43581c11 100644
--- a/lib/bundler/compact_index_client/cache.rb
+++ b/lib/bundler/compact_index_client/cache.rb
@@ -32,11 +32,11 @@ module Bundler
name, versions_string, info_checksum = line.split(" ", 3)
info_checksums_by_name[name] = info_checksum || ""
versions_string.split(",").each do |version|
- delete = version.delete_prefix!("-")
- version = version.split("-", 2).unshift(name)
- if delete
+ if version.start_with?("-")
+ version = version[1..-1].split("-", 2).unshift(name)
versions_by_name[name].delete(version)
else
+ version = version.split("-", 2).unshift(name)
versions_by_name[name] << version
end
end
diff --git a/lib/bundler/compact_index_client/gem_parser.rb b/lib/bundler/compact_index_client/gem_parser.rb
index 60a1817607..e7bf4c6001 100644
--- a/lib/bundler/compact_index_client/gem_parser.rb
+++ b/lib/bundler/compact_index_client/gem_parser.rb
@@ -6,15 +6,12 @@ module Bundler
GemParser = Gem::Resolver::APISet::GemParser
else
class GemParser
- EMPTY_ARRAY = [].freeze
- private_constant :EMPTY_ARRAY
-
def parse(line)
version_and_platform, rest = line.split(" ", 2)
version, platform = version_and_platform.split("-", 2)
- dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
- dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
- requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
+ dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
+ dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
+ requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
[version, platform, dependencies, requirements]
end
@@ -23,7 +20,6 @@ module Bundler
def parse_dependency(string)
dependency = string.split(":")
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
- dependency[0] = -dependency[0]
dependency
end
end
diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb
index 3b75d5c129..0f7bf9bb50 100644
--- a/lib/bundler/compact_index_client/updater.rb
+++ b/lib/bundler/compact_index_client/updater.rb
@@ -95,12 +95,7 @@ module Bundler
# because we need to preserve \n line endings on windows when calculating
# the checksum
SharedHelpers.filesystem_access(path, :read) do
- File.open(path, "rb") do |f|
- digest = SharedHelpers.digest(:MD5).new
- buf = String.new(:capacity => 16_384, :encoding => Encoding::BINARY)
- digest << buf while f.read(16_384, buf)
- digest.hexdigest
- end
+ SharedHelpers.digest(:MD5).hexdigest(File.read(path))
end
end
diff --git a/lib/bundler/constants.rb b/lib/bundler/constants.rb
index de9698b577..8dd8a53815 100644
--- a/lib/bundler/constants.rb
+++ b/lib/bundler/constants.rb
@@ -3,5 +3,5 @@
module Bundler
WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- NULL = File::NULL
+ NULL = WINDOWS ? "NUL" : "/dev/null"
end
diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb
index 1d2d8ff2fb..f009b07ad7 100644
--- a/lib/bundler/current_ruby.rb
+++ b/lib/bundler/current_ruby.rb
@@ -71,10 +71,26 @@ module Bundler
def windows?
Gem.win_platform?
end
- alias_method :mswin?, :windows?
- alias_method :mswin64?, :windows?
- alias_method :mingw?, :windows?
- alias_method :x64_mingw?, :windows?
+
+ def mswin?
+ # For backwards compatibility
+ windows?
+
+ # TODO: This should correctly be:
+ # windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin32" && Bundler.local_platform.cpu == "x86"
+ end
+
+ def mswin64?
+ windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64"
+ end
+
+ def mingw?
+ windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64"
+ end
+
+ def x64_mingw?
+ Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os.start_with?("mingw") && Bundler.local_platform.cpu == "x64"
+ end
(KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version|
trimmed_version = version.tr(".", "")
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 761185ff21..564530a98c 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -149,7 +149,7 @@ module Bundler
@dependency_changes = converge_dependencies
@local_changes = converge_locals
- check_lockfile
+ @missing_lockfile_dep = check_missing_lockfile_dep
end
def gem_version_promoter
@@ -405,13 +405,13 @@ module Bundler
msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
- msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n"
+ msg << "\n\nRun `bundle install` elsewhere and add the updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control.\n"
unless explicit_flag
suggested_command = unless Bundler.settings.locations("frozen").keys.include?(:env)
"bundle config set frozen false"
end
- msg << "If this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} " \
+ msg << "If this is a development machine, remove the #{Bundler.default_gemfile.relative_path_from(SharedHelpers.pwd)} " \
"freeze by running `#{suggested_command}`." if suggested_command
end
@@ -452,8 +452,8 @@ module Bundler
return if current_platform_locked?
raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
- "but your local platform is #{local_platform}. " \
- "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again."
+ "but your local platform is #{Bundler.local_platform}. " \
+ "Add the current platform to the lockfile with\n`bundle lock --add-platform #{Bundler.local_platform}` and try again."
end
def add_platform(platform)
@@ -478,7 +478,7 @@ module Bundler
private :sources
def nothing_changed?
- !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@missing_lockfile_dep && !@unlocking_bundler && !@invalid_lockfile_dep
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@missing_lockfile_dep && !@unlocking_bundler
end
def no_resolve_needed?
@@ -509,7 +509,7 @@ module Bundler
def resolution_packages
@resolution_packages ||= begin
last_resolve = converge_locked_specs
- remove_invalid_platforms!(current_dependencies)
+ remove_ruby_from_platforms_if_necessary!(current_dependencies)
packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, :locked_specs => @originally_locked_specs, :unlock => @unlock[:gems], :prerelease => gem_version_promoter.pre?)
additional_base_requirements_for_resolve(packages, last_resolve)
end
@@ -600,7 +600,7 @@ module Bundler
def current_platform_locked?
@platforms.any? do |bundle_platform|
- MatchPlatform.platforms_match?(bundle_platform, local_platform)
+ MatchPlatform.platforms_match?(bundle_platform, Bundler.local_platform)
end
end
@@ -630,7 +630,6 @@ module Bundler
[@local_changes, "the gemspecs for git local gems changed"],
[@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
[@unlocking_bundler, "an update to the version of Bundler itself was requested"],
- [@invalid_lockfile_dep, "your lock file has an invalid dependency \"#{@invalid_lockfile_dep}\""],
].select(&:first).map(&:last).join(", ")
end
@@ -657,7 +656,8 @@ module Bundler
locked_index = Index.new
locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
- !locked_index.subset?(source.specs)
+ # order here matters, since Index#== is checking source.specs.include?(locked_index)
+ locked_index != source.specs
rescue PathError, GitError => e
Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})"
false
@@ -684,38 +684,24 @@ module Bundler
!sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
end
- def check_lockfile
- @invalid_lockfile_dep = nil
- @missing_lockfile_dep = nil
+ def check_missing_lockfile_dep
+ all_locked_specs = @locked_specs.map(&:name) << "bundler"
- locked_names = @locked_specs.map(&:name)
- missing = []
- invalid = []
-
- @locked_specs.each do |s|
- s.dependencies.each do |dep|
- next if dep.name == "bundler"
-
- missing << s unless locked_names.include?(dep.name)
- invalid << s if @locked_specs.none? {|spec| dep.matches_spec?(spec) }
- end
+ missing = @locked_specs.select do |s|
+ s.dependencies.any? {|dep| !all_locked_specs.include?(dep.name) }
end
if missing.any?
@locked_specs.delete(missing)
- @missing_lockfile_dep = missing.first.name
- elsif !@dependency_changes
- @missing_lockfile_dep = current_dependencies.find do |d|
- @locked_specs[d.name].empty? && d.name != "bundler"
- end&.name
+ return missing.first.name
end
- if invalid.any?
- @locked_specs.delete(invalid)
+ return if @dependency_changes
- @invalid_lockfile_dep = invalid.first.name
- end
+ current_dependencies.find do |d|
+ @locked_specs[d.name].empty? && d.name != "bundler"
+ end&.name
end
def converge_paths
@@ -749,11 +735,6 @@ module Bundler
changes = sources.replace_sources!(@locked_sources)
sources.all_sources.each do |source|
- # has to be done separately, because we want to keep the locked checksum
- # store for a source, even when doing a full update
- if @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source && !s.equal?(source) }
- source.checksum_store.merge!(locked_source.checksum_store)
- end
# If the source is unlockable and the current command allows an unlock of
# the source (for example, you are doing a `bundle update <foo>` of a git-pinned
# gem), unlock it. For git sources, this means to unlock the revision, which
@@ -885,7 +866,7 @@ module Bundler
def metadata_dependencies
@metadata_dependencies ||= [
- Dependency.new("Ruby\0", Bundler::RubyVersion.system.gem_version),
+ Dependency.new("Ruby\0", Gem.ruby_version),
Dependency.new("RubyGems\0", Gem::VERSION),
]
end
@@ -960,19 +941,17 @@ module Bundler
resolution_packages
end
- def remove_invalid_platforms!(dependencies)
- return if Bundler.frozen_bundle?
-
- platforms.each do |platform|
- next if local_platform == platform ||
- (@new_platform && platforms.last == platform) ||
+ def remove_ruby_from_platforms_if_necessary!(dependencies)
+ return if Bundler.frozen_bundle? ||
+ Bundler.local_platform == Gem::Platform::RUBY ||
+ !platforms.include?(Gem::Platform::RUBY) ||
+ (@new_platform && platforms.last == Gem::Platform::RUBY) ||
@path_changes ||
@dependency_changes ||
- !@originally_locked_specs.incomplete_for_platform?(dependencies, platform)
+ !@originally_locked_specs.incomplete_ruby_specs?(dependencies)
- remove_platform(platform)
- add_current_platform if platform == Gem::Platform::RUBY
- end
+ remove_platform(Gem::Platform::RUBY)
+ add_current_platform
end
def source_map
diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb
index 21a4564dcc..5f17943629 100644
--- a/lib/bundler/dependency.rb
+++ b/lib/bundler/dependency.rb
@@ -17,8 +17,7 @@ module Bundler
:truffleruby => [Gem::Platform::RUBY],
:jruby => [Gem::Platform::JAVA, [18, 19]],
:windows => [Gem::Platform::WINDOWS, ALL_RUBY_VERSIONS],
- # deprecated
- :mswin => [Gem::Platform::MSWIN, ALL_RUBY_VERSIONS],
+ :mswin => [Gem::Platform::MSWIN, ALL_RUBY_VERSIONS],
:mswin64 => [Gem::Platform::MSWIN64, ALL_RUBY_VERSIONS - [18]],
:mingw => [Gem::Platform::MINGW, ALL_RUBY_VERSIONS],
:x64_mingw => [Gem::Platform::X64_MINGW, ALL_RUBY_VERSIONS - [18, 19]],
diff --git a/lib/bundler/digest.rb b/lib/bundler/digest.rb
index 148e9f7788..f11f5edd38 100644
--- a/lib/bundler/digest.rb
+++ b/lib/bundler/digest.rb
@@ -26,7 +26,7 @@ module Bundler
end
a, b, c, d, e = *words
(16..79).each do |i|
- w[i] = SHA1_MASK & rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1)
+ w[i] = SHA1_MASK & rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1)
end
0.upto(79) do |i|
case i
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index b639918f70..863544b1f9 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -94,7 +94,7 @@ module Bundler
def _local_specification
return unless @loaded_from && File.exist?(local_specification_path)
- eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec|
+ eval(File.read(local_specification_path)).tap do |spec|
spec.loaded_from = @loaded_from
end
end
@@ -125,12 +125,7 @@ module Bundler
next unless v
case k.to_s
when "checksum"
- next if Bundler.settings[:disable_checksum_validation]
- begin
- @checksum = Checksum.from_api(v.last, @spec_fetcher.uri)
- rescue ArgumentError => e
- raise ArgumentError, "Invalid checksum for #{full_name}: #{e.message}"
- end
+ @checksum = v.last
when "rubygems"
@required_rubygems_version = Gem::Requirement.new(v)
when "ruby"
diff --git a/lib/bundler/env.rb b/lib/bundler/env.rb
index f6cb198e38..7b1152930e 100644
--- a/lib/bundler/env.rb
+++ b/lib/bundler/env.rb
@@ -40,11 +40,11 @@ module Bundler
out << "\n## Gemfile\n"
gemfiles.each do |gemfile|
- out << "\n### #{SharedHelpers.relative_path_to(gemfile)}\n\n"
+ out << "\n### #{Pathname.new(gemfile).relative_path_from(SharedHelpers.pwd)}\n\n"
out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n"
end
- out << "\n### #{SharedHelpers.relative_path_to(Bundler.default_lockfile)}\n\n"
+ out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n"
out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n"
end
@@ -69,7 +69,9 @@ module Bundler
end
def self.ruby_version
- "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{Gem::Platform.local}]"
+ str = String.new(RUBY_VERSION)
+ str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+ str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{Gem::Platform.local}]"
end
def self.git_version
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index eec72b1692..5839fc6a73 100644
--- a/lib/bundler/errors.rb
+++ b/lib/bundler/errors.rb
@@ -52,49 +52,6 @@ module Bundler
class GemfileEvalError < GemfileError; end
class MarshalError < StandardError; end
- class ChecksumMismatchError < SecurityError
- def initialize(name_tuple, existing, checksum)
- @name_tuple = name_tuple
- @existing = existing
- @checksum = checksum
- end
-
- def message
- <<~MESSAGE
- Bundler found mismatched checksums. This is a potential security risk.
- #{@name_tuple.lock_name} #{@existing.to_lock}
- from #{@existing.sources.join("\n and ")}
- #{@name_tuple.lock_name} #{@checksum.to_lock}
- from #{@checksum.sources.join("\n and ")}
-
- #{mismatch_resolution_instructions}
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- MESSAGE
- end
-
- def mismatch_resolution_instructions
- removable, remote = [@existing, @checksum].partition(&:removable?)
- case removable.size
- when 0
- msg = +"Mismatched checksums each have an authoritative source:\n"
- msg << " 1. #{@existing.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n"
- msg << " 2. #{@checksum.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n"
- msg << "You may need to alter your Gemfile sources to resolve this issue.\n"
- when 1
- msg = +"If you trust #{remote.first.sources.first}, to resolve this issue you can:\n"
- msg << removable.first.removal_instructions
- when 2
- msg = +"To resolve this issue you can either:\n"
- msg << @checksum.removal_instructions
- msg << "or if you are sure that the new checksum from #{@checksum.sources.first} is correct:\n"
- msg << @existing.removal_instructions
- end
- end
-
- status_code(37)
- end
-
class PermissionError < BundlerError
def initialize(path, permission_type = :write)
@path = path
@@ -215,19 +172,4 @@ module Bundler
status_code(36)
end
-
- class InsecureInstallPathError < BundlerError
- def initialize(path)
- @path = path
- end
-
- def message
- "The installation path is insecure. Bundler cannot continue.\n" \
- "#{@path} is world-writable (without sticky bit).\n" \
- "Bundler cannot safely replace gems in world-writeable directories due to potential vulnerabilities.\n" \
- "Please change the permissions of this directory or choose a different install path."
- end
-
- status_code(38)
- end
end
diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb
index e5384c5679..2119799f68 100644
--- a/lib/bundler/fetcher.rb
+++ b/lib/bundler/fetcher.rb
@@ -9,7 +9,6 @@ require "rubygems/request"
module Bundler
# Handles all the fetching with the rubygems server
class Fetcher
- autoload :Base, File.expand_path("fetcher/base", __dir__)
autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__)
autoload :Downloader, File.expand_path("fetcher/downloader", __dir__)
autoload :Dependency, File.expand_path("fetcher/dependency", __dir__)
@@ -81,7 +80,7 @@ module Bundler
:HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity,
:HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
FAIL_ERRORS = begin
- fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError]
+ fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError]
fail_errors << Gem::Requirement::BadRequirementError
fail_errors.concat(NET_ERRORS.map {|e| Net.const_get(e) })
end.freeze
@@ -111,7 +110,7 @@ module Bundler
spec_file_name = "#{spec.join "-"}.gemspec"
uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
- spec = if uri.scheme == "file"
+ if uri.scheme == "file"
path = Bundler.rubygems.correct_for_windows_path(uri.path)
Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
elsif cached_spec_path = gemspec_cached_path(spec_file_name)
@@ -119,8 +118,6 @@ module Bundler
else
Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
end
- raise MarshalError, "is #{spec.inspect}" unless spec.is_a?(Gem::Specification)
- spec
rescue MarshalError
raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \
"Your network or your gem server is probably having issues right now."
@@ -137,11 +134,20 @@ module Bundler
def specs(gem_names, source)
index = Bundler::Index.new
- fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata|
+ if Bundler::Fetcher.disable_endpoint
+ @use_api = false
+ specs = fetchers.last.specs(gem_names)
+ else
+ specs = []
+ @fetchers = fetchers.drop_while do |f|
+ !f.available? || (f.api_fetcher? && !gem_names) || !specs = f.specs(gem_names)
+ end
+ @use_api = false if fetchers.none?(&:api_fetcher?)
+ end
+
+ specs.each do |name, version, platform, dependencies, metadata|
spec = if dependencies
- EndpointSpecification.new(name, version, platform, self, dependencies, metadata).tap do |es|
- source.checksum_store.replace(es, es.checksum)
- end
+ EndpointSpecification.new(name, version, platform, self, dependencies, metadata)
else
RemoteSpecification.new(name, version, platform, self)
end
@@ -152,10 +158,22 @@ module Bundler
index
rescue CertificateFailureError
- Bundler.ui.info "" if gem_names && api_fetcher? # newline after dots
+ Bundler.ui.info "" if gem_names && use_api # newline after dots
raise
end
+ def use_api
+ return @use_api if defined?(@use_api)
+
+ fetchers.shift until fetchers.first.available?
+
+ @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
+ false
+ else
+ fetchers.first.api_fetcher?
+ end
+ end
+
def user_agent
@user_agent ||= begin
ruby = Bundler::RubyVersion.system
@@ -191,6 +209,10 @@ module Bundler
end
end
+ def fetchers
+ @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) }
+ end
+
def http_proxy
return unless uri = connection.proxy_uri
uri.to_s
@@ -200,36 +222,9 @@ module Bundler
"#<#{self.class}:0x#{object_id} uri=#{uri}>"
end
- def api_fetcher?
- fetchers.first.api_fetcher?
- end
-
private
- def available_fetchers
- if Bundler::Fetcher.disable_endpoint
- [Index]
- elsif remote_uri.scheme == "file"
- Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
- [Index]
- else
- [CompactIndex, Dependency, Index]
- end
- end
-
- def fetchers
- @fetchers ||= available_fetchers.map {|f| f.new(downloader, @remote, uri) }.drop_while {|f| !f.available? }
- end
-
- def fetch_specs(gem_names)
- fetchers.reject!(&:api_fetcher?) unless gem_names
- fetchers.reject! do |f|
- specs = f.specs(gem_names)
- return specs if specs
- true
- end
- []
- end
+ FETCHERS = [CompactIndex, Dependency, Index].freeze
def cis
env_cis = {
diff --git a/lib/bundler/fetcher/base.rb b/lib/bundler/fetcher/base.rb
index 99c6343c9a..62cc75add8 100644
--- a/lib/bundler/fetcher/base.rb
+++ b/lib/bundler/fetcher/base.rb
@@ -38,9 +38,9 @@ module Bundler
private
- def log_specs(&block)
+ def log_specs(debug_msg)
if Bundler.ui.debug?
- Bundler.ui.debug yield
+ Bundler.ui.debug debug_msg
else
Bundler.ui.info ".", false
end
diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb
index dc30443e27..8d30dec471 100644
--- a/lib/bundler/fetcher/compact_index.rb
+++ b/lib/bundler/fetcher/compact_index.rb
@@ -35,7 +35,7 @@ module Bundler
remaining_gems = gem_names.dup
until remaining_gems.empty?
- log_specs { "Looking up gems #{remaining_gems.inspect}" }
+ log_specs "Looking up gems #{remaining_gems.inspect}"
deps = begin
parallel_compact_index_client.dependencies(remaining_gems)
@@ -44,7 +44,7 @@ module Bundler
@bundle_worker = nil # reset it. Not sure if necessary
serial_compact_index_client.dependencies(remaining_gems)
end
- next_gems = deps.flat_map {|d| d[3].flat_map(&:first) }.uniq
+ next_gems = deps.map {|d| d[3].map(&:first).flatten(1) }.flatten(1).uniq
deps.each {|dep| gem_info << dep }
complete_gems.concat(deps.map(&:first)).uniq!
remaining_gems = next_gems - complete_gems
@@ -60,6 +60,10 @@ module Bundler
Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API")
return nil
end
+ if fetch_uri.scheme == "file"
+ Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
+ return false
+ end
# Read info file checksums out of /versions, so we can know if gems are up to date
compact_index_client.update_and_parse_checksums!
rescue CompactIndexClient::Updater::MisMatchedChecksumError => e
diff --git a/lib/bundler/fetcher/dependency.rb b/lib/bundler/fetcher/dependency.rb
index 0b807c9a4b..18b606abb6 100644
--- a/lib/bundler/fetcher/dependency.rb
+++ b/lib/bundler/fetcher/dependency.rb
@@ -24,7 +24,7 @@ module Bundler
def specs(gem_names, full_dependency_list = [], last_spec_list = [])
query_list = gem_names.uniq - full_dependency_list
- log_specs { "Query List: #{query_list.inspect}" }
+ log_specs "Query List: #{query_list.inspect}"
return last_spec_list if query_list.empty?
diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb
index b66a046d37..39afe8a071 100644
--- a/lib/bundler/friendly_errors.rb
+++ b/lib/bundler/friendly_errors.rb
@@ -61,7 +61,7 @@ module Bundler
end
def request_issue_report_for(e)
- Bundler.ui.error <<~EOS, nil, nil
+ Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, nil
--- ERROR REPORT TEMPLATE -------------------------------------------------------
```
@@ -75,7 +75,7 @@ module Bundler
Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue."
- Bundler.ui.error <<~EOS, nil, :yellow
+ Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, :yellow
First, try this link to see if there are any existing issue reports for this error:
#{issues_url(e)}
@@ -93,7 +93,7 @@ module Bundler
end
def serialized_exception_for(e)
- <<~EOS
+ <<-EOS.gsub(/^ {8}/, "")
#{e.class}: #{e.message}
#{e.backtrace&.join("\n ")&.chomp}
EOS
diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb
index f0d5ce135a..2e6d788f9c 100644
--- a/lib/bundler/gem_helpers.rb
+++ b/lib/bundler/gem_helpers.rb
@@ -48,13 +48,6 @@ module Bundler
end
module_function :select_best_platform_match
- def force_ruby_platform(specs)
- matching = specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
-
- sort_best_platform_match(matching, Gem::Platform::RUBY)
- end
- module_function :force_ruby_platform
-
def sort_best_platform_match(matching, platform)
exact = matching.select {|spec| spec.platform == platform }
return exact if exact.any?
diff --git a/lib/bundler/gem_version_promoter.rb b/lib/bundler/gem_version_promoter.rb
index c7eacd1930..d281f46eeb 100644
--- a/lib/bundler/gem_version_promoter.rb
+++ b/lib/bundler/gem_version_promoter.rb
@@ -101,7 +101,7 @@ module Bundler
next 1 if b_pre && !a_pre
end
- if major? || locked_version.nil?
+ if major?
a <=> b
elsif either_version_older_than_locked?(a, b, locked_version)
a <=> b
@@ -117,7 +117,7 @@ module Bundler
end
def either_version_older_than_locked?(a, b, locked_version)
- a.version < locked_version || b.version < locked_version
+ locked_version && (a.version < locked_version || b.version < locked_version)
end
def segments_do_not_match?(a, b, level)
diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb
index df46facc88..b8c599f63a 100644
--- a/lib/bundler/index.rb
+++ b/lib/bundler/index.rb
@@ -10,8 +10,8 @@ module Bundler
i
end
- attr_reader :specs, :duplicates, :sources
- protected :specs, :duplicates
+ attr_reader :specs, :all_specs, :sources
+ protected :specs, :all_specs
RUBY = "ruby"
NULL = "\0"
@@ -19,21 +19,21 @@ module Bundler
def initialize
@sources = []
@cache = {}
- @specs = {}
- @duplicates = {}
+ @specs = Hash.new {|h, k| h[k] = {} }
+ @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
end
def initialize_copy(o)
@sources = o.sources.dup
@cache = {}
- @specs = {}
- @duplicates = {}
+ @specs = Hash.new {|h, k| h[k] = {} }
+ @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
o.specs.each do |name, hash|
@specs[name] = hash.dup
end
- o.duplicates.each do |name, array|
- @duplicates[name] = array.dup
+ o.all_specs.each do |name, array|
+ @all_specs[name] = array.dup
end
end
@@ -46,11 +46,12 @@ module Bundler
true
end
- def search_all(name, &blk)
- return enum_for(:search_all, name) unless blk
- specs_by_name(name).each(&blk)
- @duplicates[name]&.each(&blk)
- @sources.each {|source| source.search_all(name, &blk) }
+ def search_all(name)
+ all_matches = local_search(name) + @all_specs[name]
+ @sources.each do |source|
+ all_matches.concat(source.search_all(name))
+ end
+ all_matches
end
# Search this index's specs, and any source indexes that this index knows
@@ -60,14 +61,11 @@ module Bundler
return results unless @sources.any?
@sources.each do |source|
- results = safe_concat(results, source.search(query))
+ results.concat(source.search(query))
end
- results.uniq!(&:full_name) unless results.empty? # avoid modifying frozen EMPTY_SEARCH
- results
+ results.uniq(&:full_name)
end
- alias_method :[], :search
-
def local_search(query)
case query
when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query)
@@ -78,10 +76,12 @@ module Bundler
end
end
- def add(spec)
- (@specs[spec.name] ||= {}).store(spec.full_name, spec)
+ alias_method :[], :search
+
+ def <<(spec)
+ @specs[spec.name][spec.full_name] = spec
+ spec
end
- alias_method :<<, :add
def each(&blk)
return enum_for(:each) unless blk
@@ -115,25 +115,15 @@ module Bundler
names.uniq
end
- # Combines indexes proritizing existing specs, like `Hash#reverse_merge!`
- # Duplicate specs found in `other` are stored in `@duplicates`.
- def use(other)
+ def use(other, override_dupes = false)
return unless other
- other.each do |spec|
- exist?(spec) ? add_duplicate(spec) : add(spec)
- end
- self
- end
-
- # Combines indexes proritizing specs from `other`, like `Hash#merge!`
- # Duplicate specs found in `self` are saved in `@duplicates`.
- def merge!(other)
- return unless other
- other.each do |spec|
- if existing = find_by_spec(spec)
- add_duplicate(existing)
+ other.each do |s|
+ if (dupes = search_by_spec(s)) && !dupes.empty?
+ # safe to << since it's a new array when it has contents
+ @all_specs[s.name] = dupes << s
+ next unless override_dupes
end
- add spec
+ self << s
end
self
end
@@ -145,7 +135,8 @@ module Bundler
end
# Whether all the specs in self are in other
- def subset?(other)
+ # TODO: rename to #include?
+ def ==(other)
all? do |spec|
other_spec = other[spec].first
other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source
@@ -166,40 +157,19 @@ module Bundler
private
- def safe_concat(a, b)
- return a if b.empty?
- return b if a.empty?
- a.concat(b)
- end
-
- def add_duplicate(spec)
- (@duplicates[spec.name] ||= []) << spec
- end
-
def specs_by_name_and_version(name, version)
- results = @specs[name]&.values
- return EMPTY_SEARCH unless results
- results.select! {|spec| spec.version == version }
- results
+ specs_by_name(name).select {|spec| spec.version == version }
end
def specs_by_name(name)
- @specs[name]&.values || EMPTY_SEARCH
+ @specs[name].values
end
EMPTY_SEARCH = [].freeze
def search_by_spec(spec)
- spec = find_by_spec(spec)
+ spec = @specs[spec.name][spec.full_name]
spec ? [spec] : EMPTY_SEARCH
end
-
- def find_by_spec(spec)
- @specs[spec.name]&.fetch(spec.full_name, nil)
- end
-
- def exist?(spec)
- @specs[spec.name]&.key?(spec.full_name)
- end
end
end
diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb
index a738992068..cb644a7f69 100644
--- a/lib/bundler/injector.rb
+++ b/lib/bundler/injector.rb
@@ -86,7 +86,7 @@ module Bundler
segments = version.segments
seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2
- prerelease_suffix = version.to_s.delete_prefix(version.release.to_s) if version.prerelease?
+ prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease?
"#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
end
diff --git a/lib/bundler/installer/gem_installer.rb b/lib/bundler/installer/gem_installer.rb
index b6065c24d0..9a013eea4d 100644
--- a/lib/bundler/installer/gem_installer.rb
+++ b/lib/bundler/installer/gem_installer.rb
@@ -16,13 +16,13 @@ module Bundler
post_install_message = install
Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
generate_executable_stubs
- [true, post_install_message]
- rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError, Bundler::InsecureInstallPathError
+ return true, post_install_message
+ rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError
raise
rescue Errno::ENOSPC
- [false, out_of_space_message]
- rescue Bundler::BundlerError, Gem::InstallError => e
- [false, specific_failure_message(e)]
+ return false, out_of_space_message
+ rescue Bundler::BundlerError, Gem::InstallError, Bundler::APIResponseInvalidDependenciesError => e
+ return false, specific_failure_message(e)
end
private
diff --git a/lib/bundler/installer/parallel_installer.rb b/lib/bundler/installer/parallel_installer.rb
index 11a90b36cb..83a381f592 100644
--- a/lib/bundler/installer/parallel_installer.rb
+++ b/lib/bundler/installer/parallel_installer.rb
@@ -91,12 +91,38 @@ module Bundler
install_serially
end
+ check_for_unmet_dependencies
+
handle_error if failed_specs.any?
@specs
ensure
worker_pool&.stop
end
+ def check_for_unmet_dependencies
+ unmet_dependencies = @specs.map do |s|
+ [
+ s,
+ s.dependencies.reject {|dep| @specs.any? {|spec| dep.matches_spec?(spec.spec) } },
+ ]
+ end.reject {|a| a.last.empty? }
+ return if unmet_dependencies.empty?
+
+ warning = []
+ warning << "Your lockfile doesn't include a valid resolution."
+ warning << "You can fix this by regenerating your lockfile or manually editing the bad locked gems to a version that satisfies all dependencies."
+ warning << "The unmet dependencies are:"
+
+ unmet_dependencies.each do |spec, unmet_spec_dependencies|
+ unmet_spec_dependencies.each do |unmet_spec_dependency|
+ found = @specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }
+ warning << "* #{unmet_spec_dependency}, dependency of #{spec.full_name}, unsatisfied by #{found.full_name}"
+ end
+ end
+
+ Bundler.ui.warn(warning.join("\n"))
+ end
+
private
def failed_specs
diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb
index 2cdada44d6..2a8c9a432d 100644
--- a/lib/bundler/installer/standalone.rb
+++ b/lib/bundler/installer/standalone.rb
@@ -12,7 +12,6 @@ module Bundler
end
File.open File.join(bundler_path, "setup.rb"), "w" do |file|
file.puts "require 'rbconfig'"
- file.puts prevent_gem_activation
file.puts define_path_helpers
file.puts reverse_rubygems_kernel_mixin
paths.each do |path|
@@ -56,26 +55,13 @@ module Bundler
if spec.source.instance_of?(Source::Path) && spec.source.path.absolute?
full_path
else
- SharedHelpers.relative_path_to(full_path, :from => Bundler.root.join(bundler_path))
+ Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s
end
rescue TypeError
error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
raise Gem::InvalidSpecificationException.new(error_message)
end
- def prevent_gem_activation
- <<~'END'
- module Kernel
- remove_method(:gem) if private_method_defined?(:gem)
-
- def gem(*)
- end
-
- private :gem
- end
- END
- end
-
def define_path_helpers
<<~'END'
unless defined?(Gem)
@@ -101,7 +87,8 @@ module Bundler
if Gem.respond_to?(:discover_gems_on_require=)
Gem.discover_gems_on_require = false
else
- [::Kernel.singleton_class, ::Kernel].each do |k|
+ kernel = (class << ::Kernel; self; end)
+ [kernel, ::Kernel].each do |k|
if k.private_method_defined?(:gem_original_require)
private_require = k.private_method_defined?(:require)
k.send(:remove_method, :require)
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index 4a5a7d3f66..c9b161dc0e 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -27,14 +27,6 @@ module Bundler
end
end
- def lock_name
- @lock_name ||= name_tuple.lock_name
- end
-
- def name_tuple
- Gem::NameTuple.new(@name, @version, @platform)
- end
-
def ==(other)
full_name == other.full_name
end
@@ -69,7 +61,12 @@ module Bundler
def to_lock
out = String.new
- out << " #{lock_name}\n"
+
+ if platform == Gem::Platform::RUBY
+ out << " #{name} (#{version})\n"
+ else
+ out << " #{name} (#{version}-#{platform})\n"
+ end
dependencies.sort_by(&:to_s).uniq.each do |dep|
next if dep.type == :development
@@ -125,7 +122,11 @@ module Bundler
end
def to_s
- lock_name
+ @to_s ||= if platform == Gem::Platform::RUBY
+ "#{name} (#{version})"
+ else
+ "#{name} (#{version}-#{platform})"
+ end
end
def git_version
@@ -133,10 +134,6 @@ module Bundler
" #{source.revision[0..6]}"
end
- def force_ruby_platform!
- @force_ruby_platform = true
- end
-
private
def use_exact_resolved_specifications?
diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb
index 4d2a968d7e..f7ba51b3e6 100644
--- a/lib/bundler/lockfile_generator.rb
+++ b/lib/bundler/lockfile_generator.rb
@@ -19,7 +19,6 @@ module Bundler
add_sources
add_platforms
add_dependencies
- add_checksums
add_locked_ruby_version
add_bundled_with
@@ -66,13 +65,6 @@ module Bundler
end
end
- def add_checksums
- checksums = definition.resolve.map do |spec|
- spec.source.checksum_store.to_lock(spec)
- end
- add_section("CHECKSUMS", checksums)
- end
-
def add_locked_ruby_version
return unless locked_ruby_version = definition.locked_ruby_version
add_section("RUBY VERSION", locked_ruby_version.to_s)
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index 2f00da7ea9..7360a36752 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -2,33 +2,10 @@
module Bundler
class LockfileParser
- class Position
- attr_reader :line, :column
- def initialize(line, column)
- @line = line
- @column = column
- end
-
- def advance!(string)
- lines = string.count("\n")
- if lines > 0
- @line += lines
- @column = string.length - string.rindex("\n")
- else
- @column += string.length
- end
- end
-
- def to_s
- "#{line}:#{column}"
- end
- end
-
- attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version, :checksums
+ attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version
BUNDLED = "BUNDLED WITH"
DEPENDENCIES = "DEPENDENCIES"
- CHECKSUMS = "CHECKSUMS"
PLATFORMS = "PLATFORMS"
RUBY = "RUBY VERSION"
GIT = "GIT"
@@ -44,18 +21,15 @@ module Bundler
Gem::Version.create("1.10") => [BUNDLED].freeze,
Gem::Version.create("1.12") => [RUBY].freeze,
Gem::Version.create("1.13") => [PLUGIN].freeze,
- Gem::Version.create("2.5.0") => [CHECKSUMS].freeze,
}.freeze
- KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten!.freeze
+ KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze
ENVIRONMENT_VERSION_SECTIONS = [BUNDLED, RUBY].freeze
deprecate_constant(:ENVIRONMENT_VERSION_SECTIONS)
def self.sections_in_lockfile(lockfile_contents)
- sections = lockfile_contents.scan(/^\w[\w ]*$/)
- sections.uniq!
- sections
+ lockfile_contents.scan(/^\w[\w ]*$/).uniq
end
def self.unknown_sections_in_lockfile(lockfile_contents)
@@ -64,7 +38,7 @@ module Bundler
def self.sections_to_ignore(base_version = nil)
base_version &&= base_version.release
- base_version ||= Gem::Version.create("1.0")
+ base_version ||= Gem::Version.create("1.0".dup)
attributes = []
SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced|
next if version <= base_version
@@ -87,50 +61,37 @@ module Bundler
@platforms = []
@sources = []
@dependencies = {}
- @parse_method = nil
+ @state = nil
@specs = {}
- @lockfile_path = begin
- SharedHelpers.relative_lockfile_path
- rescue GemfileNotFound
- "Gemfile.lock"
- end
- @pos = Position.new(1, 1)
if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
- raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \
- "Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock."
+ raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \
+ "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock."
end
- lockfile.split(/((?:\r?\n)+)/) do |line|
- # split alternates between the line and the following whitespace
- next @pos.advance!(line) if line.match?(/^\s*$/)
-
+ lockfile.split(/(?:\r?\n)+/).each do |line|
if SOURCE.include?(line)
- @parse_method = :parse_source
+ @state = :source
parse_source(line)
elsif line == DEPENDENCIES
- @parse_method = :parse_dependency
- elsif line == CHECKSUMS
- @parse_method = :parse_checksum
+ @state = :dependency
elsif line == PLATFORMS
- @parse_method = :parse_platform
+ @state = :platform
elsif line == RUBY
- @parse_method = :parse_ruby
+ @state = :ruby
elsif line == BUNDLED
- @parse_method = :parse_bundled_with
+ @state = :bundled_with
elsif /^[^\s]/.match?(line)
- @parse_method = nil
- elsif @parse_method
- send(@parse_method, line)
+ @state = nil
+ elsif @state
+ send("parse_#{@state}", line)
end
- @pos.advance!(line)
end
- @specs = @specs.values.sort_by!(&:full_name)
+ @specs = @specs.values.sort_by(&:full_name)
rescue ArgumentError => e
Bundler.ui.debug(e)
- raise LockfileError, "Your lockfile is unreadable. Run `rm #{@lockfile_path}` " \
- "and then `bundle install` to generate a new lockfile. The error occurred while " \
- "evaluating #{@lockfile_path}:#{@pos}"
+ raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \
+ "and then `bundle install` to generate a new lockfile."
end
def may_include_redundant_platform_specific_gems?
@@ -149,9 +110,21 @@ module Bundler
def parse_source(line)
case line
when SPECS
- return unless TYPES.key?(@type)
- @current_source = TYPES[@type].from_lock(@opts)
- @sources << @current_source
+ case @type
+ when PATH
+ @current_source = TYPES[@type].from_lock(@opts)
+ @sources << @current_source
+ when GIT
+ @current_source = TYPES[@type].from_lock(@opts)
+ @sources << @current_source
+ when GEM
+ @opts["remotes"] = Array(@opts.delete("remote")).reverse
+ @current_source = TYPES[@type].from_lock(@opts)
+ @sources << @current_source
+ when PLUGIN
+ @current_source = Plugin.source_from_lock(@opts)
+ @sources << @current_source
+ end
when OPTIONS
value = $2
value = true if value == "true"
@@ -181,7 +154,6 @@ module Bundler
(?:#{space}\(([^-]*) # Space, followed by version
(?:-(.*))?\))? # Optional platform
(!)? # Optional pinned marker
- (?:#{space}([^ ]+))? # Optional checksum
$ # Line end
/xo.freeze
@@ -189,11 +161,11 @@ module Bundler
return unless line =~ NAME_VERSION
spaces = $1
return unless spaces.size == 2
- name = -$2
+ name = $2
version = $3
pinned = $5
- version = version.split(",").each(&:strip!) if version
+ version = version.split(",").map(&:strip) if version
dep = Bundler::Dependency.new(name, version)
@@ -214,41 +186,14 @@ module Bundler
@dependencies[dep.name] = dep
end
- def parse_checksum(line)
+ def parse_spec(line)
return unless line =~ NAME_VERSION
-
spaces = $1
- return unless spaces.size == 2
- checksums = $6
- return unless checksums
name = $2
version = $3
platform = $4
- version = Gem::Version.new(version)
- platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
- full_name = Gem::NameTuple.new(name, version, platform).full_name
- # Don't raise exception if there's a checksum for a gem that's not in the lockfile,
- # we prefer to heal invalid lockfiles
- return unless spec = @specs[full_name]
-
- checksums.split(",") do |lock_checksum|
- column = line.index(lock_checksum) + 1
- checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}")
- spec.source.checksum_store.register(spec, checksum)
- end
- end
-
- def parse_spec(line)
- return unless line =~ NAME_VERSION
- spaces = $1
- name = -$2
- version = $3
-
if spaces.size == 4
- # only load platform for non-dependency (spec) line
- platform = $4
-
version = Gem::Version.new(version)
platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
@current_spec = LazySpecification.new(name, version, platform)
@@ -257,7 +202,7 @@ module Bundler
@specs[@current_spec.full_name] = @current_spec
elsif spaces.size == 6
- version = version.split(",").each(&:strip!) if version
+ version = version.split(",").map(&:strip) if version
dep = Gem::Dependency.new(name, version)
@current_spec.dependencies << dep
end
@@ -268,14 +213,13 @@ module Bundler
end
def parse_bundled_with(line)
- line.strip!
+ line = line.strip
return unless Gem::Version.correct?(line)
@bundler_version = Gem::Version.create(line)
end
def parse_ruby(line)
- line.strip!
- @ruby_version = line
+ @ruby_version = line.strip
end
end
end
diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1
index 17f03fc290..8549855b0d 100644
--- a/lib/bundler/man/bundle-add.1
+++ b/lib/bundler/man/bundle-add.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-ADD" "1" "October 2023" "" ""
+.TH "BUNDLE\-ADD" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1
index 00cbda104a..40c338916a 100644
--- a/lib/bundler/man/bundle-binstubs.1
+++ b/lib/bundler/man/bundle-binstubs.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-BINSTUBS" "1" "October 2023" "" ""
+.TH "BUNDLE\-BINSTUBS" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1
index 14250e589a..69b1e1e3dd 100644
--- a/lib/bundler/man/bundle-cache.1
+++ b/lib/bundler/man/bundle-cache.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-CACHE" "1" "October 2023" "" ""
+.TH "BUNDLE\-CACHE" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1
index cb70661591..748a37e7d1 100644
--- a/lib/bundler/man/bundle-check.1
+++ b/lib/bundler/man/bundle-check.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-CHECK" "1" "October 2023" "" ""
+.TH "BUNDLE\-CHECK" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1
index 76450a35dc..af8f13cd89 100644
--- a/lib/bundler/man/bundle-clean.1
+++ b/lib/bundler/man/bundle-clean.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-CLEAN" "1" "October 2023" "" ""
+.TH "BUNDLE\-CLEAN" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1
index 34654301b2..4442f33105 100644
--- a/lib/bundler/man/bundle-config.1
+++ b/lib/bundler/man/bundle-config.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-CONFIG" "1" "October 2023" "" ""
+.TH "BUNDLE\-CONFIG" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options
@@ -296,9 +296,6 @@ The following is a list of all configuration keys and their purpose\. You can le
\fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\.
.
.IP "\(bu" 4
-\fBversion\fR (\fBBUNDLE_VERSION\fR): The version of Bundler to use when running under Bundler environment\. Defaults to \fBlockfile\fR\. You can also specify \fBsystem\fR or \fBx\.y\.z\fR\. \fBlockfile\fR will use the Bundler version specified in the \fBGemfile\.lock\fR, \fBsystem\fR will use the system version of Bundler, and \fBx\.y\.z\fR will use the specified version of Bundler\.
-.
-.IP "\(bu" 4
\fBwith\fR (\fBBUNDLE_WITH\fR): A \fB:\fR\-separated list of groups whose gems bundler should install\.
.
.IP "\(bu" 4
diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn
index b935329b4e..adc273ec62 100644
--- a/lib/bundler/man/bundle-config.1.ronn
+++ b/lib/bundler/man/bundle-config.1.ronn
@@ -274,12 +274,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
and disallow passing no options to `bundle update`.
* `user_agent` (`BUNDLE_USER_AGENT`):
The custom user agent fragment Bundler includes in API requests.
-* `version` (`BUNDLE_VERSION`):
- The version of Bundler to use when running under Bundler environment.
- Defaults to `lockfile`. You can also specify `system` or `x.y.z`.
- `lockfile` will use the Bundler version specified in the `Gemfile.lock`,
- `system` will use the system version of Bundler, and `x.y.z` will use
- the specified version of Bundler.
* `with` (`BUNDLE_WITH`):
A `:`-separated list of groups whose gems bundler should install.
* `without` (`BUNDLE_WITHOUT`):
diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1
index a223558c68..24fff46cec 100644
--- a/lib/bundler/man/bundle-console.1
+++ b/lib/bundler/man/bundle-console.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-CONSOLE" "1" "October 2023" "" ""
+.TH "BUNDLE\-CONSOLE" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-console\fR \- Deprecated way to open an IRB session with the bundle pre\-loaded
diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1
index 143d9b700f..57da8216cb 100644
--- a/lib/bundler/man/bundle-doctor.1
+++ b/lib/bundler/man/bundle-doctor.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-DOCTOR" "1" "October 2023" "" ""
+.TH "BUNDLE\-DOCTOR" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems
diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1
index 91454985f2..852788db7a 100644
--- a/lib/bundler/man/bundle-exec.1
+++ b/lib/bundler/man/bundle-exec.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-EXEC" "1" "October 2023" "" ""
+.TH "BUNDLE\-EXEC" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle
@@ -22,7 +22,7 @@ Note that \fBbundle exec\fR does not require that an executable is available on
.
.TP
\fB\-\-keep\-file\-descriptors\fR
-Passes all file descriptors to the new processes\. Default is true from bundler version 2\.2\.26\. Setting it to false is now deprecated\.
+Exec in Ruby 2\.0 began discarding non\-standard file descriptors\. When this flag is passed, exec will revert to the 1\.9 behaviour of passing all file descriptors to the new process\.
.
.SH "BUNDLE INSTALL \-\-BINSTUBS"
If you use the \fB\-\-binstubs\fR flag in bundle install(1) \fIbundle\-install\.1\.html\fR, Bundler will automatically create a directory (which defaults to \fBapp_root/bin\fR) containing all of the executables available from gems in the bundle\.
diff --git a/lib/bundler/man/bundle-exec.1.ronn b/lib/bundler/man/bundle-exec.1.ronn
index 9d5b559f26..05948095e2 100644
--- a/lib/bundler/man/bundle-exec.1.ronn
+++ b/lib/bundler/man/bundle-exec.1.ronn
@@ -21,8 +21,9 @@ available on your shell's `$PATH`.
## OPTIONS
* `--keep-file-descriptors`:
- Passes all file descriptors to the new processes. Default is true from
- bundler version 2.2.26. Setting it to false is now deprecated.
+ Exec in Ruby 2.0 began discarding non-standard file descriptors. When this
+ flag is passed, exec will revert to the 1.9 behaviour of passing all file
+ descriptors to the new process.
## BUNDLE INSTALL --BINSTUBS
diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1
index 825c46fd47..8339b727ce 100644
--- a/lib/bundler/man/bundle-gem.1
+++ b/lib/bundler/man/bundle-gem.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-GEM" "1" "October 2023" "" ""
+.TH "BUNDLE\-GEM" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem
diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1
index 26309a2e68..9787c2d49f 100644
--- a/lib/bundler/man/bundle-help.1
+++ b/lib/bundler/man/bundle-help.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-HELP" "1" "October 2023" "" ""
+.TH "BUNDLE\-HELP" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-help\fR \- Displays detailed help for each subcommand
diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1
index d6049aa667..2cced71520 100644
--- a/lib/bundler/man/bundle-info.1
+++ b/lib/bundler/man/bundle-info.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-INFO" "1" "October 2023" "" ""
+.TH "BUNDLE\-INFO" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-info\fR \- Show information for the given gem in your bundle
diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1
index 3514ae40e1..c7a9a155b5 100644
--- a/lib/bundler/man/bundle-init.1
+++ b/lib/bundler/man/bundle-init.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-INIT" "1" "October 2023" "" ""
+.TH "BUNDLE\-INIT" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-init\fR \- Generates a Gemfile into the current working directory
diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1
index 21fb8734fe..9e25c29085 100644
--- a/lib/bundler/man/bundle-inject.1
+++ b/lib/bundler/man/bundle-inject.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-INJECT" "1" "October 2023" "" ""
+.TH "BUNDLE\-INJECT" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile
diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1
index 70dccc6078..337683af06 100644
--- a/lib/bundler/man/bundle-install.1
+++ b/lib/bundler/man/bundle-install.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-INSTALL" "1" "October 2023" "" ""
+.TH "BUNDLE\-INSTALL" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile
diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1
index f66755b19a..1680e6007a 100644
--- a/lib/bundler/man/bundle-list.1
+++ b/lib/bundler/man/bundle-list.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-LIST" "1" "October 2023" "" ""
+.TH "BUNDLE\-LIST" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle
diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1
index 783e97f9f2..8722c44b3d 100644
--- a/lib/bundler/man/bundle-lock.1
+++ b/lib/bundler/man/bundle-lock.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-LOCK" "1" "October 2023" "" ""
+.TH "BUNDLE\-LOCK" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing
diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1
index 8fb26f9862..3513f0d09b 100644
--- a/lib/bundler/man/bundle-open.1
+++ b/lib/bundler/man/bundle-open.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-OPEN" "1" "October 2023" "" ""
+.TH "BUNDLE\-OPEN" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle
diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1
index a8afc5cc74..129ff00f58 100644
--- a/lib/bundler/man/bundle-outdated.1
+++ b/lib/bundler/man/bundle-outdated.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-OUTDATED" "1" "October 2023" "" ""
+.TH "BUNDLE\-OUTDATED" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available
diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1
index 6c0451ebac..5021c46b4c 100644
--- a/lib/bundler/man/bundle-platform.1
+++ b/lib/bundler/man/bundle-platform.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-PLATFORM" "1" "October 2023" "" ""
+.TH "BUNDLE\-PLATFORM" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-platform\fR \- Displays platform compatibility information
diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1
index e295c30622..ec30e1d0fd 100644
--- a/lib/bundler/man/bundle-plugin.1
+++ b/lib/bundler/man/bundle-plugin.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-PLUGIN" "1" "October 2023" "" ""
+.TH "BUNDLE\-PLUGIN" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-plugin\fR \- Manage Bundler plugins
@@ -26,37 +26,37 @@ You can install, uninstall, and list plugin(s) with this command to extend funct
.SS "install"
Install the given plugin(s)\.
.
-.TP
-\fBbundle plugin install bundler\-graph\fR
-Install bundler\-graph gem from globally configured sources (defaults to RubyGems\.org)\. The global source, specified in source in Gemfile is ignored\.
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph\fR: Install bundler\-graph gem from RubyGems\.org\. The global source, specified in source in Gemfile is ignored\.
.
-.TP
-\fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR
-Install bundler\-graph gem from example\.com\. The global source, specified in source in Gemfile is not considered\.
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR: Install bundler\-graph gem from example\.com\. The global source, specified in source in Gemfile is not considered\.
.
-.TP
-\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR
-You can specify the version of the gem via \fB\-\-version\fR\.
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR: You can specify the version of the gem via \fB\-\-version\fR\.
.
-.TP
-\fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR
-Install bundler\-graph gem from Git repository\. \fB\-\-git\fR can be replaced with \fB\-\-local\-git\fR\. You cannot use both \fB\-\-git\fR and \fB\-\-local\-git\fR\. You can use standard Git URLs like:
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR: Install bundler\-graph gem from Git repository\. \fB\-\-git\fR can be replaced with \fB\-\-local\-git\fR\. You cannot use both \fB\-\-git\fR and \fB\-\-local\-git\fR\. You can use standard Git URLs like:
.
-.IP
+.IP "\(bu" 4
\fBssh://[user@]host\.xz[:port]/path/to/repo\.git\fR
.
-.br
+.IP "\(bu" 4
\fBhttp[s]://host\.xz[:port]/path/to/repo\.git\fR
.
-.br
+.IP "\(bu" 4
\fB/path/to/repo\fR
.
-.br
+.IP "\(bu" 4
\fBfile:///path/to/repo\fR
.
+.IP "" 0
+.
.IP
When you specify \fB\-\-git\fR/\fB\-\-local\-git\fR, you can use \fB\-\-branch\fR or \fB\-\-ref\fR to specify any branch, tag, or commit hash (revision) to use\. When you specify both, only the latter is used\.
.
+.IP "" 0
+.
.SS "uninstall"
Uninstall the plugin(s) specified in PLUGINS\.
.
diff --git a/lib/bundler/man/bundle-plugin.1.ronn b/lib/bundler/man/bundle-plugin.1.ronn
index a11df4c162..4f234eeba7 100644
--- a/lib/bundler/man/bundle-plugin.1.ronn
+++ b/lib/bundler/man/bundle-plugin.1.ronn
@@ -20,7 +20,7 @@ You can install, uninstall, and list plugin(s) with this command to extend funct
Install the given plugin(s).
* `bundle plugin install bundler-graph`:
- Install bundler-graph gem from globally configured sources (defaults to RubyGems.org). The global source, specified in source in Gemfile is ignored.
+ Install bundler-graph gem from RubyGems.org. The global source, specified in source in Gemfile is ignored.
* `bundle plugin install bundler-graph --source https://example.com`:
Install bundler-graph gem from example.com. The global source, specified in source in Gemfile is not considered.
@@ -31,10 +31,10 @@ Install the given plugin(s).
* `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph`:
Install bundler-graph gem from Git repository. `--git` can be replaced with `--local-git`. You cannot use both `--git` and `--local-git`. You can use standard Git URLs like:
- `ssh://[user@]host.xz[:port]/path/to/repo.git`<br>
- `http[s]://host.xz[:port]/path/to/repo.git`<br>
- `/path/to/repo`<br>
- `file:///path/to/repo`
+ * `ssh://[user@]host.xz[:port]/path/to/repo.git`
+ * `http[s]://host.xz[:port]/path/to/repo.git`
+ * `/path/to/repo`
+ * `file:///path/to/repo`
When you specify `--git`/`--local-git`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use. When you specify both, only the latter is used.
diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1
index 6422ea9517..af81c48d2b 100644
--- a/lib/bundler/man/bundle-pristine.1
+++ b/lib/bundler/man/bundle-pristine.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-PRISTINE" "1" "October 2023" "" ""
+.TH "BUNDLE\-PRISTINE" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition
diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1
index ebfb17ffb1..d86cf134bd 100644
--- a/lib/bundler/man/bundle-remove.1
+++ b/lib/bundler/man/bundle-remove.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-REMOVE" "1" "October 2023" "" ""
+.TH "BUNDLE\-REMOVE" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile
diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1
index ac64aee6b6..aa91176bf2 100644
--- a/lib/bundler/man/bundle-show.1
+++ b/lib/bundler/man/bundle-show.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-SHOW" "1" "October 2023" "" ""
+.TH "BUNDLE\-SHOW" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem
diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1
index 37a289ddf9..e4e10ad23b 100644
--- a/lib/bundler/man/bundle-update.1
+++ b/lib/bundler/man/bundle-update.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-UPDATE" "1" "October 2023" "" ""
+.TH "BUNDLE\-UPDATE" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-update\fR \- Update your gems to the latest available versions
diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1
index ab29c24763..5e3ed44600 100644
--- a/lib/bundler/man/bundle-version.1
+++ b/lib/bundler/man/bundle-version.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-VERSION" "1" "October 2023" "" ""
+.TH "BUNDLE\-VERSION" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-version\fR \- Prints Bundler version information
diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1
index 3ae31a0fba..d5330ec754 100644
--- a/lib/bundler/man/bundle-viz.1
+++ b/lib/bundler/man/bundle-viz.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE\-VIZ" "1" "October 2023" "" ""
+.TH "BUNDLE\-VIZ" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile
diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1
index d89a8cb1ee..99c65a72b5 100644
--- a/lib/bundler/man/bundle.1
+++ b/lib/bundler/man/bundle.1
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "BUNDLE" "1" "October 2023" "" ""
+.TH "BUNDLE" "1" "August 2023" "" ""
.
.SH "NAME"
\fBbundle\fR \- Ruby Dependency Management
diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5
index 4480bb625a..352fa0f545 100644
--- a/lib/bundler/man/gemfile.5
+++ b/lib/bundler/man/gemfile.5
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "GEMFILE" "5" "October 2023" "" ""
+.TH "GEMFILE" "5" "August 2023" "" ""
.
.SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
@@ -98,17 +98,6 @@ ruby file: "\.ruby\-version"
.
.IP "" 0
.
-.P
-The version file should conform to any of the following formats:
-.
-.IP "\(bu" 4
-\fB3\.1\.2\fR (\.ruby\-version)
-.
-.IP "\(bu" 4
-\fBruby 3\.1\.2\fR (\.tool\-versions, read: https://asdf\-vm\.com/manage/configuration\.html#tool\-versions)
-.
-.IP "" 0
-.
.SS "ENGINE"
Each application \fImay\fR specify a Ruby engine\. If an engine is specified, an engine version \fImust\fR also be specified\.
.
@@ -342,14 +331,6 @@ gem "nokogiri", platforms: [:windows_31, :jruby]
.P
All operations involving groups (\fBbundle install\fR \fIbundle\-install\.1\.html\fR, \fBBundler\.setup\fR, \fBBundler\.require\fR) behave exactly the same as if any groups not matching the current platform were explicitly excluded\.
.
-.P
-The following platform values are deprecated and should be replaced with \fBwindows\fR:
-.
-.IP "\(bu" 4
-\fBmswin\fR, \fBmswin64\fR, \fBmingw32\fR, \fBx64_mingw\fR
-.
-.IP "" 0
-.
.SS "FORCE_RUBY_PLATFORM"
If you always want the pure ruby variant of a gem to be chosen over platform specific variants, you can use the \fBforce_ruby_platform\fR option:
.
diff --git a/lib/bundler/man/gemfile.5.ronn b/lib/bundler/man/gemfile.5.ronn
index e8a1f8b79e..6749c33f59 100644
--- a/lib/bundler/man/gemfile.5.ronn
+++ b/lib/bundler/man/gemfile.5.ronn
@@ -74,11 +74,6 @@ you can use the `file` option instead.
ruby file: ".ruby-version"
-The version file should conform to any of the following formats:
-
- - `3.1.2` (.ruby-version)
- - `ruby 3.1.2` (.tool-versions, read: https://asdf-vm.com/manage/configuration.html#tool-versions)
-
### ENGINE
Each application _may_ specify a Ruby engine. If an engine is specified, an
@@ -238,10 +233,6 @@ All operations involving groups ([`bundle install`](bundle-install.1.html), `Bun
`Bundler.require`) behave exactly the same as if any groups not
matching the current platform were explicitly excluded.
-The following platform values are deprecated and should be replaced with `windows`:
-
- * `mswin`, `mswin64`, `mingw32`, `x64_mingw`
-
### FORCE_RUBY_PLATFORM
If you always want the pure ruby variant of a gem to be chosen over platform
diff --git a/lib/bundler/match_platform.rb b/lib/bundler/match_platform.rb
index ece9fb8679..7f7e8227f9 100644
--- a/lib/bundler/match_platform.rb
+++ b/lib/bundler/match_platform.rb
@@ -12,7 +12,7 @@ module Bundler
def self.platforms_match?(gemspec_platform, local_platform)
return true if gemspec_platform.nil?
- return true if gemspec_platform == Gem::Platform::RUBY
+ return true if Gem::Platform::RUBY == gemspec_platform
return true if local_platform == gemspec_platform
gemspec_platform = Gem::Platform.new(gemspec_platform)
return true if gemspec_platform === local_platform
diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb
index e3f698ec43..f3caff8963 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -62,8 +62,7 @@ module Bundler
if names.any?
names.each do |name|
if index.installed?(name)
- path = index.plugin_path(name).to_s
- Bundler.rm_rf(path) if index.installed_in_plugin_root?(name)
+ Bundler.rm_rf(index.plugin_path(name))
index.unregister_plugin(name)
Bundler.ui.info "Uninstalled plugin #{name}"
else
@@ -198,7 +197,7 @@ module Bundler
# @param [Hash] The options that are present in the lock file
# @return [API::Source] the instance of the class that handles the source
# type passed in locked_opts
- def from_lock(locked_opts)
+ def source_from_lock(locked_opts)
src = source(locked_opts["type"])
src.new(locked_opts.merge("uri" => locked_opts["remote"]))
@@ -228,7 +227,7 @@ module Bundler
plugins = index.hook_plugins(event)
return unless plugins.any?
- plugins.each {|name| load_plugin(name) }
+ (plugins - @loaded_plugin_names).each {|name| load_plugin(name) }
@hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) }
end
@@ -240,11 +239,6 @@ module Bundler
Index.new.installed?(plugin)
end
- # @return [true, false] whether the plugin is loaded
- def loaded?(plugin)
- @loaded_plugin_names.include?(plugin)
- end
-
# Post installation processing and registering with index
#
# @param [Array<String>] plugins list to be installed
@@ -335,7 +329,6 @@ module Bundler
# @param [String] name of the plugin
def load_plugin(name)
return unless name && !name.empty?
- return if loaded?(name)
# Need to ensure before this that plugin root where the rest of gems
# are installed to be on load path to support plugin deps. Currently not
diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb
index 57d4eb64ad..67c45bd204 100644
--- a/lib/bundler/plugin/api/source.rb
+++ b/lib/bundler/plugin/api/source.rb
@@ -39,7 +39,7 @@ module Bundler
# is present to be compatible with `Definition` and is used by
# rubygems source.
module Source
- attr_reader :uri, :options, :name, :checksum_store
+ attr_reader :uri, :options, :name
attr_accessor :dependency_names
def initialize(opts)
@@ -48,7 +48,6 @@ module Bundler
@uri = opts["uri"]
@type = opts["type"]
@name = opts["name"] || "#{@type} at #{@uri}"
- @checksum_store = Checksum::Store.new
end
# This is used by the default `spec` method to constructs the
diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb
index c2ab8f90da..a2d5eaa38a 100644
--- a/lib/bundler/plugin/index.rb
+++ b/lib/bundler/plugin/index.rb
@@ -136,14 +136,6 @@ module Bundler
@hooks[event] || []
end
- # This plugin is installed inside the .bundle/plugin directory,
- # and thus is managed solely by Bundler
- def installed_in_plugin_root?(name)
- return false unless (path = installed?(name))
-
- path.start_with?("#{Plugin.root}/")
- end
-
private
# Reads the index file from the directory and initializes the instance
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index 9ec39d5a35..2ad35bc931 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -37,17 +37,9 @@ module Bundler
root_version = Resolver::Candidate.new(0)
@all_specs = Hash.new do |specs, name|
- source = source_for(name)
- matches = source.specs.search(name)
-
- # Don't bother to check for circular deps when no dependency API are
- # available, since it's too slow to be usable. That edge case won't work
- # but resolution other than that should work fine and reasonably fast.
- if source.respond_to?(:dependency_api_available?) && source.dependency_api_available?
- matches = filter_invalid_self_dependencies(matches, name)
- end
-
- specs[name] = matches.sort_by {|s| [s.version, s.platform.to_s] }
+ specs[name] = source_for(name).specs.search(name).reject do |s|
+ s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) } # ignore versions that depend on themselves incorrectly
+ end.sort_by {|s| [s.version, s.platform.to_s] }
end
@sorted_versions = Hash.new do |candidates, package|
@@ -131,7 +123,7 @@ module Bundler
if base_requirements[name]
names_to_unlock << name
- elsif package.ignores_prereleases? && @all_specs[name].any? {|s| s.version.prerelease? }
+ elsif package.ignores_prereleases?
names_to_allow_prereleases_for << name
end
@@ -248,22 +240,8 @@ module Bundler
results = filter_matching_specs(results, locked_requirement) if locked_requirement
versions = results.group_by(&:version).reduce([]) do |groups, (version, specs)|
- platform_specs = package.platforms.map {|platform| select_best_platform_match(specs, platform) }
-
- # If package is a top-level dependency,
- # candidate is only valid if there are matching versions for all resolution platforms.
- #
- # If package is not a top-level deependency,
- # then it's not necessary that it has matching versions for all platforms, since it may have been introduced only as
- # a dependency for a platform specific variant, so it will only need to have a valid version for that platform.
- #
- if package.top_level?
- next groups if platform_specs.any?(&:empty?)
- else
- next groups if platform_specs.all?(&:empty?)
- end
-
- platform_specs.flatten!
+ platform_specs = package.platforms.flat_map {|platform| select_best_platform_match(specs, platform) }
+ next groups if platform_specs.empty?
ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY)
groups << Resolver::Candidate.new(version, :specs => ruby_specs) if ruby_specs.any?
@@ -309,21 +287,15 @@ module Bundler
end
specs_matching_requirement = filter_matching_specs(specs, package.dependency.requirement)
- not_found_message = if specs_matching_requirement.any?
+ if specs_matching_requirement.any?
specs = specs_matching_requirement
matching_part = requirement_label
platforms = package.platforms
-
- if platforms.size == 1
- "Could not find gem '#{requirement_label}' with platform '#{platforms.first}'"
- else
- "Could not find gems matching '#{requirement_label}' valid for all resolution platforms (#{platforms.join(", ")})"
- end
- else
- "Could not find gem '#{requirement_label}'"
+ platform_label = platforms.size == 1 ? "platform '#{platforms.first}" : "platforms '#{platforms.join("', '")}"
+ requirement_label = "#{requirement_label}' with #{platform_label}"
end
- message = String.new("#{not_found_message} in #{source}#{cache_message}.\n")
+ message = String.new("Could not find gem '#{requirement_label}' in #{source}#{cache_message}.\n")
if specs.any?
message << "\n#{other_specs_matching_message(specs, matching_part)}"
@@ -346,13 +318,6 @@ module Bundler
specs.reject {|s| s.version.prerelease? }
end
- # Ignore versions that depend on themselves incorrectly
- def filter_invalid_self_dependencies(specs, name)
- specs.reject do |s|
- s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) }
- end
- end
-
def requirement_satisfied_by?(requirement, spec)
requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec)
end
diff --git a/lib/bundler/resolver/package.rb b/lib/bundler/resolver/package.rb
index 0461328683..7499a75006 100644
--- a/lib/bundler/resolver/package.rb
+++ b/lib/bundler/resolver/package.rb
@@ -21,7 +21,6 @@ module Bundler
@locked_version = locked_specs[name].first&.version
@unlock = unlock
@dependency = dependency || Dependency.new(name, @locked_version)
- @top_level = !dependency.nil?
@prerelease = @dependency.prerelease? || @locked_version&.prerelease? || prerelease ? :consider_first : :ignore
end
@@ -33,10 +32,6 @@ module Bundler
false
end
- def top_level?
- @top_level
- end
-
def meta?
@name.end_with?("\0")
end
diff --git a/lib/bundler/retry.rb b/lib/bundler/retry.rb
index b95c42c361..2415ade200 100644
--- a/lib/bundler/retry.rb
+++ b/lib/bundler/retry.rb
@@ -56,7 +56,7 @@ module Bundler
def keep_trying?
return true if current_run.zero?
return false if last_attempt?
- true if @failed
+ return true if @failed
end
def last_attempt?
diff --git a/lib/bundler/ruby_dsl.rb b/lib/bundler/ruby_dsl.rb
index 95151898ff..d054969e8d 100644
--- a/lib/bundler/ruby_dsl.rb
+++ b/lib/bundler/ruby_dsl.rb
@@ -10,8 +10,8 @@ module Bundler
raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
if options[:file]
- raise GemfileError, "Do not pass version argument when using :file option" unless ruby_version.empty?
- ruby_version << normalize_ruby_file(options[:file])
+ raise GemfileError, "Cannot specify version when using the file option" if ruby_version.any?
+ ruby_version << Bundler.read_file(options[:file]).strip
end
if options[:engine] == "ruby" && options[:engine_version] &&
@@ -20,26 +20,5 @@ module Bundler
end
@ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])
end
-
- # Support the various file formats found in .ruby-version files.
- #
- # 3.2.2
- # ruby-3.2.2
- #
- # Also supports .tool-versions files for asdf. Lines not starting with "ruby" are ignored.
- #
- # ruby 2.5.1 # comment is ignored
- # ruby 2.5.1# close comment and extra spaces doesn't confuse
- #
- # Intentionally does not support `3.2.1@gemset` since rvm recommends using .ruby-gemset instead
- def normalize_ruby_file(filename)
- file_content = Bundler.read_file(Bundler.root.join(filename))
- # match "ruby-3.2.2" or "ruby 3.2.2" capturing version string up to the first space or comment
- if /^ruby(-|\s+)([^\s#]+)/.match(file_content)
- $2
- else
- file_content.strip
- end
- end
end
end
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index 52868b5fb8..b5396abb6e 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -23,7 +23,7 @@ module Bundler
# specified must match the version.
@versions = Array(versions).map do |v|
- op, v = Gem::Requirement.parse(normalize_version(v))
+ op, v = Gem::Requirement.parse(v)
op == "=" ? v.to_s : "#{op} #{v}"
end
@@ -112,13 +112,6 @@ module Bundler
private
- # Ruby's official preview version format uses a `-`: Example: 3.3.0-preview2
- # However, RubyGems recognizes preview version format with a `.`: Example: 3.3.0.preview2
- # Returns version string after replacing `-` with `.`
- def normalize_version(version)
- version.tr("-", ".")
- end
-
def matches?(requirements, version)
# Handles RUBY_PATCHLEVEL of -1 for instances like ruby-head
return requirements == version if requirements.to_s == "-1" || version.to_s == "-1"
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index 0296fc543d..8981612706 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -76,24 +76,6 @@ module Gem
end
end
- alias_method :rg_missing_extensions?, :missing_extensions?
- def missing_extensions?
- # When we use this methods with local gemspec, we don't handle
- # build status of extension correctly. So We need to find extension
- # files in require_paths.
- # TODO: Gem::Specification couldn't access extension name from extconf.rb
- # so we find them with heuristic way. We should improve it.
- if source.respond_to?(:root)
- return false if raw_require_paths.any? do |path|
- ext_dir = File.join(full_gem_path, path)
- File.exist?(File.join(ext_dir, "#{name}.#{RbConfig::CONFIG["DLEXT"]}")) ||
- !Dir.glob(File.join(ext_dir, name, "*.#{RbConfig::CONFIG["DLEXT"]}")).empty?
- end
- end
-
- rg_missing_extensions?
- end
-
remove_method :gem_dir if instance_methods(false).include?(:gem_dir)
def gem_dir
full_gem_path
@@ -338,7 +320,7 @@ module Gem
end
# On universal Rubies, resolve the "universal" arch to the real CPU arch, without changing the extension directory.
- class BasicSpecification
+ class Specification
if /^universal\.(?<arch>.*?)-/ =~ (CROSS_COMPILING || RUBY_PLATFORM)
local_platform = Platform.local
if local_platform.cpu == "universal"
@@ -351,34 +333,14 @@ module Gem
end
def extensions_dir
- @extensions_dir ||=
- Gem.default_ext_dir_for(base_dir) || File.join(base_dir, "extensions", ORIGINAL_LOCAL_PLATFORM, Gem.extension_api_version)
+ Gem.default_ext_dir_for(base_dir) ||
+ File.join(base_dir, "extensions", ORIGINAL_LOCAL_PLATFORM,
+ Gem.extension_api_version)
end
end
end
end
- require "rubygems/name_tuple"
-
- class NameTuple
- def self.new(name, version, platform="ruby")
- if Gem::Platform === platform
- super(name, version, platform.to_s)
- else
- super
- end
- end
-
- def lock_name
- @lock_name ||=
- if platform == Gem::Platform::RUBY
- "#{name} (#{version})"
- else
- "#{name} (#{version}-#{platform})"
- end
- end
- end
-
require "rubygems/util"
Util.singleton_class.module_eval do
diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb
index d04ef62e8e..38035a00ac 100644
--- a/lib/bundler/rubygems_gem_installer.rb
+++ b/lib/bundler/rubygems_gem_installer.rb
@@ -45,14 +45,6 @@ module Bundler
spec
end
- def pre_install_checks
- super
- rescue Gem::FilePermissionError
- # Ignore permission checks in RubyGems. Instead, go on, and try to write
- # for real. We properly handle permission errors when they happen.
- nil
- end
-
def generate_plugins
return unless Gem::Installer.instance_methods(false).include?(:generate_plugins)
@@ -68,6 +60,10 @@ module Bundler
end
end
+ def pre_install_checks
+ super && validate_bundler_checksum(options[:bundler_expected_checksum])
+ end
+
def build_extensions
extension_cache_path = options[:bundler_extension_cache_path]
extension_dir = spec.extension_dir
@@ -102,18 +98,6 @@ module Bundler
end
end
- def gem_checksum
- return nil if Bundler.settings[:disable_checksum_validation]
- return nil unless source = @package.instance_variable_get(:@gem)
- return nil unless source.respond_to?(:with_read_io)
-
- source.with_read_io do |io|
- Checksum.from_gem(io, source.path)
- ensure
- io.rewind
- end
- end
-
private
def prepare_extension_build(extension_dir)
@@ -124,21 +108,64 @@ module Bundler
end
def strict_rm_rf(dir)
- return unless File.exist?(dir)
+ Bundler.rm_rf dir
+ rescue StandardError => e
+ raise unless File.exist?(dir)
+
+ raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`")
+ end
- parent = File.dirname(dir)
- parent_st = File.stat(parent)
+ def validate_bundler_checksum(checksum)
+ return true if Bundler.settings[:disable_checksum_validation]
+ return true unless checksum
+ return true unless source = @package.instance_variable_get(:@gem)
+ return true unless source.respond_to?(:with_read_io)
+ digest = source.with_read_io do |io|
+ digest = SharedHelpers.digest(:SHA256).new
+ digest << io.read(16_384) until io.eof?
+ io.rewind
+ send(checksum_type(checksum), digest)
+ end
+ unless digest == checksum
+ raise SecurityError, <<-MESSAGE
+ Bundler cannot continue installing #{spec.name} (#{spec.version}).
+ The checksum for the downloaded `#{spec.full_name}.gem` does not match \
+ the checksum given by the server. This means the contents of the downloaded \
+ gem is different from what was uploaded to the server, and could be a potential security issue.
+
+ To resolve this issue:
+ 1. delete the downloaded gem located at: `#{spec.gem_dir}/#{spec.full_name}.gem`
+ 2. run `bundle install`
+
+ If you wish to continue installing the downloaded gem, and are certain it does not pose a \
+ security issue despite the mismatching checksum, do the following:
+ 1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification
+ 2. run `bundle install`
+
+ (More info: The expected SHA256 checksum was #{checksum.inspect}, but the \
+ checksum for the downloaded gem was #{digest.inspect}.)
+ MESSAGE
+ end
+ true
+ end
- if parent_st.world_writable? && !parent_st.sticky?
- raise InsecureInstallPathError.new(parent)
+ def checksum_type(checksum)
+ case checksum.length
+ when 64 then :hexdigest!
+ when 44 then :base64digest!
+ else raise InstallError, "The given checksum for #{spec.full_name} (#{checksum.inspect}) is not a valid SHA256 hexdigest nor base64digest"
end
+ end
- begin
- FileUtils.remove_entry_secure(dir)
- rescue StandardError => e
- raise unless File.exist?(dir)
+ def hexdigest!(digest)
+ digest.hexdigest!
+ end
- raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`")
+ def base64digest!(digest)
+ if digest.respond_to?(:base64digest!)
+ digest.base64digest!
+ else
+ [digest.digest!].pack("m0")
end
end
end
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index f420934ceb..d8b7886af7 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -91,9 +91,9 @@ module Bundler
def spec_matches_for_glob(spec, glob)
return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob)
- spec.load_paths.flat_map do |lp|
+ spec.load_paths.map do |lp|
Dir["#{lp}/#{glob}#{suffix_pattern}"]
- end
+ end.flatten(1)
end
def stub_set_spec(stub, spec)
@@ -230,7 +230,8 @@ module Bundler
if Gem.respond_to?(:discover_gems_on_require=)
Gem.discover_gems_on_require = false
else
- [::Kernel.singleton_class, ::Kernel].each do |k|
+ kernel = (class << ::Kernel; self; end)
+ [kernel, ::Kernel].each do |k|
if k.private_method_defined?(:gem_original_require)
redefine_method(k, :require, k.instance_method(:gem_original_require))
end
@@ -238,29 +239,13 @@ module Bundler
end
end
- def replace_require(specs)
- return if [::Kernel.singleton_class, ::Kernel].any? {|klass| klass.respond_to?(:no_warning_require) }
-
- [::Kernel.singleton_class, ::Kernel].each do |kernel_class|
- kernel_class.send(:alias_method, :no_warning_require, :require)
- kernel_class.send(:define_method, :require) do |name|
- if message = ::Gem::BUNDLED_GEMS.warning?(name, specs: specs) # rubocop:disable Style/HashSyntax
- warn message, :uplevel => 1
- end
- kernel_class.send(:no_warning_require, name)
- end
- if kernel_class == ::Kernel
- kernel_class.send(:private, :require)
- else
- kernel_class.send(:public, :require)
- end
- end
- end
-
def replace_gem(specs, specs_by_name)
+ reverse_rubygems_kernel_mixin
+
executables = nil
- [::Kernel.singleton_class, ::Kernel].each do |kernel_class|
+ kernel = (class << ::Kernel; self; end)
+ [kernel, ::Kernel].each do |kernel_class|
redefine_method(kernel_class, :gem) do |dep, *reqs|
if executables&.include?(File.basename(caller.first.split(":").first))
break
@@ -373,11 +358,6 @@ module Bundler
def replace_entrypoints(specs)
specs_by_name = add_default_gems_to(specs)
- if defined?(::Gem::BUNDLED_GEMS)
- replace_require(specs)
- else
- reverse_rubygems_kernel_mixin
- end
replace_gem(specs, specs_by_name)
stub_rubygems(specs)
replace_bin_path(specs_by_name)
@@ -473,9 +453,7 @@ module Bundler
fetcher = gem_remote_fetcher
fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri
string = fetcher.fetch_path(path)
- specs = Bundler.safe_load_marshal(string)
- raise MarshalError, "Specs #{name} from #{remote} is expected to be an Array but was unexpected class #{specs.class}" unless specs.is_a?(Array)
- specs
+ Bundler.safe_load_marshal(string)
rescue Gem::RemoteFetcher::FetchError
# it's okay for prerelease to fail
raise unless name == "prerelease_specs"
@@ -521,7 +499,8 @@ module Bundler
def gem_remote_fetcher
require "rubygems/remote_fetcher"
- Gem::RemoteFetcher.fetcher
+ proxy = Gem.configuration[:http_proxy]
+ Gem::RemoteFetcher.new(proxy)
end
def build(spec, skip_validation = false)
diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb
index 1925a266d9..827f3f9222 100644
--- a/lib/bundler/self_manager.rb
+++ b/lib/bundler/self_manager.rb
@@ -9,23 +9,17 @@ module Bundler
def restart_with_locked_bundler_if_needed
return unless needs_switching? && installed?
- restart_with(restart_version)
+ restart_with(lockfile_version)
end
def install_locked_bundler_and_restart_with_it_if_needed
return unless needs_switching?
- if restart_version == lockfile_version
- Bundler.ui.info \
- "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \
- "Installing Bundler #{lockfile_version} and restarting using that version."
- else
- Bundler.ui.info \
- "Bundler #{current_version} is running, but your configuration was #{restart_version}. " \
- "Installing Bundler #{restart_version} and restarting using that version."
- end
+ Bundler.ui.info \
+ "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \
+ "Installing Bundler #{lockfile_version} and restarting using that version."
- install_and_restart_with(restart_version)
+ install_and_restart_with(lockfile_version)
end
def update_bundler_and_restart_with_it_if_needed(target)
@@ -85,8 +79,7 @@ module Bundler
autoswitching_applies? &&
released?(lockfile_version) &&
!running?(lockfile_version) &&
- !updating? &&
- Bundler.settings[:version] != "system"
+ !updating?
end
def autoswitching_applies?
@@ -158,7 +151,7 @@ module Bundler
def installed?
Bundler.configure
- Bundler.rubygems.find_bundler(restart_version.to_s)
+ Bundler.rubygems.find_bundler(lockfile_version.to_s)
end
def current_version
@@ -170,17 +163,6 @@ module Bundler
parsed_version = Bundler::LockfileParser.bundled_with
@lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil
- rescue ArgumentError
- @lockfile_version = nil
- end
-
- def restart_version
- return @restart_version if defined?(@restart_version)
- # BUNDLE_VERSION=x.y.z
- @restart_version = Gem::Version.new(Bundler.settings[:version])
- rescue ArgumentError
- # BUNDLE_VERSION=lockfile
- @restart_version = lockfile_version
end
end
end
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index d14ce40dc4..0af2236a45 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -74,7 +74,6 @@ module Bundler
shebang
system_bindir
trust-policy
- version
].freeze
DEFAULT_CONFIG = {
@@ -84,32 +83,19 @@ module Bundler
"BUNDLE_REDIRECT" => 5,
"BUNDLE_RETRY" => 3,
"BUNDLE_TIMEOUT" => 10,
- "BUNDLE_VERSION" => "lockfile",
}.freeze
def initialize(root = nil)
@root = root
@local_config = load_config(local_config_file)
-
- @env_config = ENV.to_h
- @env_config.select! {|key, _value| key.start_with?("BUNDLE_") }
- @env_config.delete("BUNDLE_")
-
+ @env_config = ENV.to_h.select {|key, _value| key =~ /\ABUNDLE_.+/ }
@global_config = load_config(global_config_file)
@temporary = {}
-
- @key_cache = {}
end
def [](name)
key = key_for(name)
-
- value = nil
- configs.each do |_, config|
- value = config[key]
- next if value.nil?
- break
- end
+ value = configs.values.map {|config| config[key] }.compact.first
converted_value(value, name)
end
@@ -152,22 +138,17 @@ module Bundler
end
def all
- keys = @temporary.keys.union(@global_config.keys, @local_config.keys, @env_config.keys)
+ keys = @temporary.keys | @global_config.keys | @local_config.keys | @env_config.keys
- keys.map! do |key|
- key = key.delete_prefix("BUNDLE_")
- key.gsub!("___", "-")
- key.gsub!("__", ".")
- key.downcase!
- key
- end.sort!
- keys
+ keys.map do |key|
+ key.sub(/^BUNDLE_/, "").gsub(/___/, "-").gsub(/__/, ".").downcase
+ end.sort
end
def local_overrides
repos = {}
all.each do |k|
- repos[k.delete_prefix("local.")] = self[k] if k.start_with?("local.")
+ repos[$'] = self[k] if k =~ /^local\./
end
repos
end
@@ -314,13 +295,13 @@ module Bundler
end
def key_for(key)
- @key_cache[key] ||= self.class.key_for(key)
+ self.class.key_for(key)
end
private
def configs
- @configs ||= {
+ {
:temporary => @temporary,
:local => @local_config,
:env => @env_config,
@@ -346,20 +327,16 @@ module Bundler
end
def is_bool(name)
- name = self.class.key_to_s(name)
- BOOL_KEYS.include?(name) || BOOL_KEYS.include?(parent_setting_for(name))
+ BOOL_KEYS.include?(name.to_s) || BOOL_KEYS.include?(parent_setting_for(name.to_s))
end
def is_string(name)
- name = self.class.key_to_s(name)
- STRING_KEYS.include?(name) || name.start_with?("local.") || name.start_with?("mirror.") || name.start_with?("build.")
+ STRING_KEYS.include?(name.to_s) || name.to_s.start_with?("local.") || name.to_s.start_with?("mirror.") || name.to_s.start_with?("build.")
end
def to_bool(value)
case value
- when String
- value.match?(/\A(false|f|no|n|0|)\z/i) ? false : true
- when nil, false
+ when nil, /\A(false|f|no|n|0|)\z/i, false
false
else
true
@@ -367,11 +344,11 @@ module Bundler
end
def is_num(key)
- NUMBER_KEYS.include?(self.class.key_to_s(key))
+ NUMBER_KEYS.include?(key.to_s)
end
def is_array(key)
- ARRAY_KEYS.include?(self.class.key_to_s(key))
+ ARRAY_KEYS.include?(key.to_s)
end
def is_credential(key)
@@ -394,7 +371,7 @@ module Bundler
end
def set_key(raw_key, value, hash, file)
- raw_key = self.class.key_to_s(raw_key)
+ raw_key = raw_key.to_s
value = array_to_s(value) if is_array(raw_key)
key = key_for(raw_key)
@@ -409,13 +386,12 @@ module Bundler
return unless file
SharedHelpers.filesystem_access(file) do |p|
FileUtils.mkdir_p(p.dirname)
- p.open("w") {|f| f.write(serializer_class.dump(hash)) }
+ require_relative "yaml_serializer"
+ p.open("w") {|f| f.write(YAMLSerializer.dump(hash)) }
end
end
def converted_value(value, key)
- key = self.class.key_to_s(key)
-
if is_array(key)
to_array(value)
elsif value.nil?
@@ -473,31 +449,24 @@ module Bundler
SharedHelpers.filesystem_access(config_file, :read) do |file|
valid_file = file.exist? && !file.size.zero?
return {} unless valid_file
- serializer_class.load(file.read).inject({}) do |config, (k, v)|
+ require_relative "yaml_serializer"
+ YAMLSerializer.load(file.read).inject({}) do |config, (k, v)|
+ new_k = k
+
if k.include?("-")
Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \
"This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \
"Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)."
- # string hash keys are frozen
- k = k.gsub("-", "___")
+ new_k = k.gsub("-", "___")
end
- config[k] = v
+ config[new_k] = v
config
end
end
end
- def serializer_class
- require "rubygems/yaml_serializer"
- Gem::YAMLSerializer
- rescue LoadError
- # TODO: Remove this when RubyGems 3.4 is EOL
- require_relative "yaml_serializer"
- YAMLSerializer
- end
-
PER_URI_OPTIONS = %w[
fallback_timeout
].freeze
@@ -513,11 +482,8 @@ module Bundler
def self.key_for(key)
key = normalize_uri(key).to_s if key.is_a?(String) && key.start_with?("http", "mirror.http")
- key = key_to_s(key).gsub(".", "__")
- key.gsub!("-", "___")
- key.upcase!
-
- key.prepend("BUNDLE_")
+ key = key.to_s.gsub(".", "__").gsub("-", "___").upcase
+ "BUNDLE_#{key}"
end
# TODO: duplicates Rubygems#normalize_uri
@@ -537,34 +503,5 @@ module Bundler
end
"#{prefix}#{uri}#{suffix}"
end
-
- # This is a hot method, so avoid respond_to? checks on every invocation
- if :read.respond_to?(:name)
- def self.key_to_s(key)
- case key
- when String
- key
- when Symbol
- key.name
- when Bundler::URI::HTTP
- key.to_s
- else
- raise ArgumentError, "Invalid key: #{key.inspect}"
- end
- end
- else
- def self.key_to_s(key)
- case key
- when String
- key
- when Symbol
- key.to_s
- when Bundler::URI::HTTP
- key.to_s
- else
- raise ArgumentError, "Invalid key: #{key.inspect}"
- end
- end
- end
end
end
diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb
index 5196243949..d1d4e1d07a 100644
--- a/lib/bundler/shared_helpers.rb
+++ b/lib/bundler/shared_helpers.rb
@@ -197,21 +197,6 @@ module Bundler
filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } }
end
- def relative_gemfile_path
- relative_path_to(Bundler.default_gemfile)
- end
-
- def relative_lockfile_path
- relative_path_to(Bundler.default_lockfile)
- end
-
- def relative_path_to(destination, from: pwd)
- Pathname.new(destination).relative_path_from(from).to_s
- rescue ArgumentError
- # on Windows, if source and destination are on different drivers, there's no relative path from one to the other
- destination
- end
-
private
def validate_bundle_path
@@ -312,7 +297,7 @@ module Bundler
def set_rubyopt
rubyopt = [ENV["RUBYOPT"]].compact
setup_require = "-r#{File.expand_path("setup", __dir__)}"
- return if !rubyopt.empty? && rubyopt.first =~ /#{Regexp.escape(setup_require)}/
+ return if !rubyopt.empty? && rubyopt.first =~ /#{setup_require}/
rubyopt.unshift setup_require
Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ")
end
diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb
index 115dbd1378..f7f5ea7865 100644
--- a/lib/bundler/source.rb
+++ b/lib/bundler/source.rb
@@ -11,8 +11,6 @@ module Bundler
attr_accessor :dependency_names
- attr_reader :checksum_store
-
def unmet_deps
specs.unmet_dependency_names
end
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index 24d871bd11..adbce5fce4 100644
--- a/lib/bundler/source/git.rb
+++ b/lib/bundler/source/git.rb
@@ -11,7 +11,6 @@ module Bundler
def initialize(options)
@options = options
- @checksum_store = Checksum::Store.new
@glob = options["glob"] || DEFAULT_GLOB
@allow_cached = false
diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb
index 0b507abc76..fdb738e52e 100644
--- a/lib/bundler/source/git/git_proxy.rb
+++ b/lib/bundler/source/git/git_proxy.rb
@@ -43,13 +43,6 @@ module Bundler
end
end
- class AmbiguousGitReference < GitError
- def initialize(options)
- msg = "Specification of branch or ref with tag is ambiguous. You specified #{options.inspect}"
- super msg
- end
- end
-
# The GitProxy is responsible to interact with git repositories.
# All actions required by the Git source is encapsulated in this
# object.
@@ -60,15 +53,10 @@ module Bundler
def initialize(path, uri, options = {}, revision = nil, git = nil)
@path = path
@uri = uri
- @tag = options["tag"]
@branch = options["branch"]
+ @tag = options["tag"]
@ref = options["ref"]
- if @tag
- raise AmbiguousGitReference.new(options) if @branch || @ref
- @explicit_ref = @tag
- else
- @explicit_ref = @ref || @branch
- end
+ @explicit_ref = branch || tag || ref
@revision = revision
@git = git
@commit_ref = nil
@@ -130,12 +118,7 @@ module Bundler
end
end
- ref = @commit_ref || (locked_to_full_sha? && @revision)
- if ref
- git "config", "uploadpack.allowAnySHA1InWant", "true", :dir => path.to_s if @commit_ref.nil? && needs_allow_any_sha1_in_want?
-
- git "fetch", "--force", "--quiet", *extra_fetch_args(ref), :dir => destination
- end
+ git "fetch", "--force", "--quiet", *extra_fetch_args, :dir => destination if @commit_ref
git "reset", "--hard", @revision, :dir => destination
@@ -179,7 +162,8 @@ module Bundler
_, err, status = capture(command, nil)
return extra_ref if status.success?
- if err.include?("Could not find remote branch")
+ if err.include?("Could not find remote branch") || # git up to 2.49
+ err.include?("Remote branch #{branch_option} not found") # git 2.49 or higher
raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri)
else
raise GitCommandError.new(command_with_no_credentials, path, err)
@@ -248,19 +232,11 @@ module Bundler
end
def not_pinned?
- branch || tag || ref.nil?
+ branch_option || ref.nil?
end
def pinned_to_full_sha?
- full_sha_revision?(ref)
- end
-
- def locked_to_full_sha?
- full_sha_revision?(@revision)
- end
-
- def full_sha_revision?(ref)
- ref&.match?(/\A\h{40}\z/)
+ ref =~ /\A\h{40}\z/
end
def git_null(*command, dir: nil)
@@ -414,7 +390,7 @@ module Bundler
# anyways.
return args if @revision
- args += ["--branch", branch || tag] if branch || tag
+ args += ["--branch", branch_option] if branch_option
args
end
@@ -424,12 +400,16 @@ module Bundler
["--depth", depth.to_s]
end
- def extra_fetch_args(ref)
+ def extra_fetch_args
extra_args = [path.to_s, *depth_args]
- extra_args.push(ref)
+ extra_args.push(@commit_ref)
extra_args
end
+ def branch_option
+ branch || tag
+ end
+
def full_clone?
depth.nil?
end
@@ -438,10 +418,6 @@ module Bundler
@supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5")
end
- def needs_allow_any_sha1_in_want?
- @needs_allow_any_sha1_in_want ||= Gem::Version.new(version) <= Gem::Version.new("2.13.7")
- end
-
def supports_fetching_unreachable_refs?
@supports_fetching_unreachable_refs ||= Gem::Version.new(version) >= Gem::Version.new("2.5.0")
end
diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb
index 4d27761365..593da6d1a7 100644
--- a/lib/bundler/source/metadata.rb
+++ b/lib/bundler/source/metadata.rb
@@ -5,27 +5,27 @@ module Bundler
class Metadata < Source
def specs
@specs ||= Index.build do |idx|
- idx << Gem::Specification.new("Ruby\0", Bundler::RubyVersion.system.gem_version)
+ idx << Gem::Specification.new("Ruby\0", Gem.ruby_version)
idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s|
s.required_rubygems_version = Gem::Requirement.default
end
- if local_spec = Gem.loaded_specs["bundler"]
+ idx << Gem::Specification.new do |s|
+ s.name = "bundler"
+ s.version = VERSION
+ s.license = "MIT"
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["bundler team"]
+ s.bindir = "exe"
+ s.homepage = "https://bundler.io"
+ s.summary = "The best way to manage your application's dependencies"
+ s.executables = %w[bundle]
+ # can't point to the actual gemspec or else the require paths will be wrong
+ s.loaded_from = __dir__
+ end
+
+ if local_spec = Bundler.rubygems.find_bundler(VERSION)
idx << local_spec
- else
- idx << Gem::Specification.new do |s|
- s.name = "bundler"
- s.version = VERSION
- s.license = "MIT"
- s.platform = Gem::Platform::RUBY
- s.authors = ["bundler team"]
- s.bindir = "exe"
- s.homepage = "https://bundler.io"
- s.summary = "The best way to manage your application's dependencies"
- s.executables = %w[bundle]
- # can't point to the actual gemspec or else the require paths will be wrong
- s.loaded_from = __dir__
- end
end
idx.each {|s| s.source = self }
diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index cdf871250a..bdfcf8274a 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -14,7 +14,6 @@ module Bundler
DEFAULT_GLOB = "{,*,*/*}.gemspec"
def initialize(options)
- @checksum_store = Checksum::Store.new
@options = options.dup
@glob = options["glob"] || DEFAULT_GLOB
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 6d6f36e298..af57acbbc2 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -19,7 +19,6 @@ module Bundler
@allow_remote = false
@allow_cached = false
@allow_local = options["allow_local"] || false
- @checksum_store = Checksum::Store.new
Array(options["remotes"]).reverse_each {|r| add_remote(r) }
end
@@ -89,7 +88,6 @@ module Bundler
end
def self.from_lock(options)
- options["remotes"] = Array(options.delete("remote")).reverse
new(options)
end
@@ -130,12 +128,12 @@ module Bundler
def specs
@specs ||= begin
# remote_specs usually generates a way larger Index than the other
- # sources, and large_idx.merge! small_idx is way faster than
- # small_idx.merge! large_idx.
- index = @allow_remote ? remote_specs.dup : Index.new
- index.merge!(cached_specs) if @allow_cached || @allow_remote
- index.merge!(installed_specs) if @allow_local
- index
+ # sources, and large_idx.use small_idx is way faster than
+ # small_idx.use large_idx.
+ idx = @allow_remote ? remote_specs.dup : Index.new
+ idx.use(cached_specs, :override_dupes) if @allow_cached || @allow_remote
+ idx.use(installed_specs, :override_dupes) if @allow_local
+ idx
end
end
@@ -178,6 +176,7 @@ module Bundler
:wrappers => true,
:env_shebang => true,
:build_args => options[:build_args],
+ :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum,
:bundler_extension_cache_path => extension_cache_path(spec)
)
@@ -196,8 +195,6 @@ module Bundler
spec.__swap__(s)
end
- spec.source.checksum_store.register(spec, installer.gem_checksum)
-
message = "Installing #{version_message(spec, options[:previous_spec])}"
message += " with native extensions" if spec.extensions.any?
Bundler.ui.confirm message
@@ -240,7 +237,7 @@ module Bundler
end
def spec_names
- if dependency_api_available?
+ if @allow_remote && dependency_api_available?
remote_specs.spec_names
else
[]
@@ -248,7 +245,7 @@ module Bundler
end
def unmet_deps
- if dependency_api_available?
+ if @allow_remote && dependency_api_available?
remote_specs.unmet_dependency_names
else
[]
@@ -263,6 +260,7 @@ module Bundler
end
def double_check_for(unmet_dependency_names)
+ return unless @allow_remote
return unless dependency_api_available?
unmet_dependency_names = unmet_dependency_names.call
@@ -277,9 +275,7 @@ module Bundler
Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}"
- fetch_names(api_fetchers, unmet_dependency_names, remote_specs)
-
- specs.use remote_specs
+ fetch_names(api_fetchers, unmet_dependency_names, specs, false)
end
def dependency_names_to_double_check
@@ -383,7 +379,7 @@ module Bundler
def cached_specs
@cached_specs ||= begin
- idx = Index.new
+ idx = @allow_local ? installed_specs.dup : Index.new
Dir["#{cache_path}/*.gem"].each do |gemfile|
s ||= Bundler.rubygems.spec_from_gem(gemfile)
@@ -396,30 +392,35 @@ module Bundler
end
def api_fetchers
- fetchers.select(&:api_fetcher?)
+ fetchers.select {|f| f.use_api && f.fetchers.first.api_fetcher? }
end
def remote_specs
@remote_specs ||= Index.build do |idx|
index_fetchers = fetchers - api_fetchers
- if index_fetchers.empty?
- fetch_names(api_fetchers, dependency_names, idx)
- else
- fetch_names(fetchers, nil, idx)
- end
+ # gather lists from non-api sites
+ fetch_names(index_fetchers, nil, idx, false)
+
+ # legacy multi-remote sources need special logic to figure out
+ # dependency names and that logic can be very costly if one remote
+ # uses the dependency API but others don't. So use full indexes
+ # consistently in that particular case.
+ allow_api = !multiple_remotes?
+
+ fetch_names(api_fetchers, allow_api && dependency_names, idx, false)
end
end
- def fetch_names(fetchers, dependency_names, index)
+ def fetch_names(fetchers, dependency_names, index, override_dupes)
fetchers.each do |f|
if dependency_names
Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug?
- index.use f.specs_with_retry(dependency_names, self)
+ index.use f.specs_with_retry(dependency_names, self), override_dupes
Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
else
Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}"
- index.use f.specs_with_retry(nil, self)
+ index.use f.specs_with_retry(nil, self), override_dupes
end
end
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index cb8f0fd1b2..21630e3a3e 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -100,12 +100,12 @@ module Bundler
end
end
- def incomplete_for_platform?(deps, platform)
+ def incomplete_ruby_specs?(deps)
return false if @specs.empty?
@incomplete_specs = []
- self.for(deps, true, [platform])
+ self.for(deps, true, [Gem::Platform::RUBY])
@incomplete_specs.any?
end
@@ -200,11 +200,8 @@ module Bundler
def specs_for_dependency(dep, platform)
specs_for_name = lookup[dep.name]
- matching_specs = if dep.force_ruby_platform
- GemHelpers.force_ruby_platform(specs_for_name)
- else
- GemHelpers.select_best_platform_match(specs_for_name, platform || Bundler.local_platform)
- end
+ target_platform = dep.force_ruby_platform ? Gem::Platform::RUBY : (platform || Bundler.local_platform)
+ matching_specs = GemHelpers.select_best_platform_match(specs_for_name, target_platform)
matching_specs.map!(&:materialize_for_installation).compact! if platform.nil?
matching_specs
end
diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb
index da830cf8d4..88a4257fa4 100644
--- a/lib/bundler/stub_specification.rb
+++ b/lib/bundler/stub_specification.rb
@@ -9,7 +9,6 @@ module Bundler
spec
end
- attr_reader :checksum
attr_accessor :stub, :ignored
def source=(source)
@@ -17,8 +16,7 @@ module Bundler
# Stub has no concept of source, which means that extension_dir may be wrong
# This is the case for git-based gems. So, instead manually assign the extension dir
return unless source.respond_to?(:extension_dir_name)
- unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-")
- path = File.join(stub.extensions_dir, unique_extension_dir)
+ path = File.join(stub.extensions_dir, source.extension_dir_name)
stub.extension_dir = File.expand_path(path)
end
@@ -58,7 +56,7 @@ module Bundler
end
def gem_build_complete_path
- stub.gem_build_complete_path
+ File.join(extension_dir, "gem.build_complete")
end
def default_gem?
@@ -110,7 +108,6 @@ module Bundler
end
rs.source = source
- rs.base_dir = stub.base_dir
rs
end
diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt
index 5bf36378e8..20eaac8a62 100644
--- a/lib/bundler/templates/newgem/README.md.tt
+++ b/lib/bundler/templates/newgem/README.md.tt
@@ -6,15 +6,15 @@ Welcome to your new gem! In this directory, you'll find the files you need to be
## Installation
-TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
+TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
Install the gem and add to the application's Gemfile by executing:
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
If bundler is not being used to manage dependencies, install the gem by executing:
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
## Usage
diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt
index 77f8a02530..b5a5c4e392 100644
--- a/lib/bundler/templates/newgem/Rakefile.tt
+++ b/lib/bundler/templates/newgem/Rakefile.tt
@@ -46,9 +46,7 @@ require "rb_sys/extensiontask"
task build: :compile
-GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec")
-
-RbSys::ExtensionTask.new(<%= config[:name].inspect %>, GEMSPEC) do |ext|
+RbSys::ExtensionTask.new(<%= config[:name].inspect %>) do |ext|
ext.lib_dir = "lib/<%= config[:namespaced_path] %>"
end
<% else -%>
@@ -56,9 +54,7 @@ require "rake/extensiontask"
task build: :compile
-GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec")
-
-Rake::ExtensionTask.new("<%= config[:underscored_name] %>", GEMSPEC) do |ext|
+Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext|
ext.lib_dir = "lib/<%= config[:namespaced_path] %>"
end
<% end -%>
diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
index 32b39558d8..be58dd8156 100644
--- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt
+++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
@@ -17,7 +17,7 @@ jobs:
- '<%= RUBY_VERSION %>'
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v3
<%- if config[:ext] == 'rust' -%>
- name: Set up Ruby & Rust
uses: oxidize-rb/actions/setup-ruby-and-rust@v1
diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt
index 51f19a5be9..bb76680379 100644
--- a/lib/bundler/templates/newgem/newgem.gemspec.tt
+++ b/lib/bundler/templates/newgem/newgem.gemspec.tt
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
spec.files = Dir.chdir(__dir__) do
`git ls-files -z`.split("\x0").reject do |f|
(File.expand_path(f) == __FILE__) ||
- f.start_with?(*%w[bin/ test/ spec/ features/ .git <%= config[:ci_config_path] %>appveyor Gemfile])
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
end
end
spec.bindir = "exe"
diff --git a/lib/bundler/templates/newgem/standard.yml.tt b/lib/bundler/templates/newgem/standard.yml.tt
index a0696cd2e9..934b0b2c37 100644
--- a/lib/bundler/templates/newgem/standard.yml.tt
+++ b/lib/bundler/templates/newgem/standard.yml.tt
@@ -1,3 +1,3 @@
# For available configuration options, see:
-# https://github.com/standardrb/standard
+# https://github.com/testdouble/standard
ruby_version: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %>
diff --git a/lib/bundler/ui/shell.rb b/lib/bundler/ui/shell.rb
index a9053f2852..4139585c47 100644
--- a/lib/bundler/ui/shell.rb
+++ b/lib/bundler/ui/shell.rb
@@ -147,7 +147,7 @@ module Bundler
spaces ? text.gsub(/#{spaces}/, "") : text
end
- def word_wrap(text, line_width = Thor::Terminal.terminal_width)
+ def word_wrap(text, line_width = @shell.terminal_width)
strip_leading_spaces(text).split("\n").collect do |line|
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
end * "\n"
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
index bd53ee757e..a4e1c5a750 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
@@ -174,7 +174,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
##
# The version of Bundler::Persistent::Net::HTTP::Persistent you are using
- VERSION = '4.0.2'
+ VERSION = '4.0.1'
##
# Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb
index 40f61aacea..a57a5d1352 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb
@@ -25,7 +25,6 @@ class Bundler::Persistent::Net::HTTP::Persistent::Connection # :nodoc:
ensure
reset
end
- alias_method :close, :finish
def reset
@last_use = Bundler::Persistent::Net::HTTP::Persistent::EPOCH
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb
index 736027863c..9dfa6ffdb1 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb
@@ -11,32 +11,20 @@ class Bundler::Persistent::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool
end
def checkin net_http_args
- if net_http_args.is_a?(Hash) && net_http_args.size == 1 && net_http_args[:force]
- # Bundler::ConnectionPool 2.4+ calls `checkin(force: true)` after fork.
- # When this happens, we should remove all connections from Thread.current
- if stacks = Thread.current[@key]
- stacks.each do |http_args, connections|
- connections.each do |conn|
- @available.push conn, connection_args: http_args
- end
- connections.clear
- end
- end
- else
- stack = Thread.current[@key][net_http_args] ||= []
+ stack = Thread.current[@key][net_http_args] ||= []
- raise Bundler::ConnectionPool::Error, 'no connections are checked out' if
- stack.empty?
+ raise Bundler::ConnectionPool::Error, 'no connections are checked out' if
+ stack.empty?
- conn = stack.pop
+ conn = stack.pop
- if stack.empty?
- @available.push conn, connection_args: net_http_args
+ if stack.empty?
+ @available.push conn, connection_args: net_http_args
- Thread.current[@key].delete(net_http_args)
- Thread.current[@key] = nil if Thread.current[@key].empty?
- end
+ Thread.current[@key].delete(net_http_args)
+ Thread.current[@key] = nil if Thread.current[@key].empty?
end
+
nil
end
diff --git a/lib/bundler/vendor/thor/lib/thor.rb b/lib/bundler/vendor/thor/lib/thor.rb
index 627722164f..0794dbb522 100644
--- a/lib/bundler/vendor/thor/lib/thor.rb
+++ b/lib/bundler/vendor/thor/lib/thor.rb
@@ -65,15 +65,8 @@ class Bundler::Thor
# Defines the long description of the next command.
#
- # Long description is by default indented, line-wrapped and repeated whitespace merged.
- # In order to print long description verbatim, with indentation and spacing exactly
- # as found in the code, use the +wrap+ option
- #
- # long_desc 'your very long description', wrap: false
- #
# ==== Parameters
# long description<String>
- # options<Hash>
#
def long_desc(long_description, options = {})
if options[:for]
@@ -81,7 +74,6 @@ class Bundler::Thor
command.long_description = long_description if long_description
else
@long_desc = long_description
- @long_desc_wrap = options[:wrap] != false
end
end
@@ -141,7 +133,7 @@ class Bundler::Thor
# # magic
# end
#
- # method_option :foo, :for => :previous_command
+ # method_option :foo => :bar, :for => :previous_command
#
# def next_command
# # magic
@@ -161,9 +153,6 @@ class Bundler::Thor
# :hide - If you want to hide this option from the help.
#
def method_option(name, options = {})
- unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
- raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
- end
scope = if options[:for]
find_and_refresh_command(options[:for]).options
else
@@ -174,81 +163,6 @@ class Bundler::Thor
end
alias_method :option, :method_option
- # Adds and declares option group for exclusive options in the
- # block and arguments. You can declare options as the outside of the block.
- #
- # If :for is given as option, it allows you to change the options from
- # a previous defined command.
- #
- # ==== Parameters
- # Array[Bundler::Thor::Option.name]
- # options<Hash>:: :for is applied for previous defined command.
- #
- # ==== Examples
- #
- # exclusive do
- # option :one
- # option :two
- # end
- #
- # Or
- #
- # option :one
- # option :two
- # exclusive :one, :two
- #
- # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
- # will be raised.
- #
- def method_exclusive(*args, &block)
- register_options_relation_for(:method_options,
- :method_exclusive_option_names, *args, &block)
- end
- alias_method :exclusive, :method_exclusive
-
- # Adds and declares option group for required at least one of options in the
- # block of arguments. You can declare options as the outside of the block.
- #
- # If :for is given as option, it allows you to change the options from
- # a previous defined command.
- #
- # ==== Parameters
- # Array[Bundler::Thor::Option.name]
- # options<Hash>:: :for is applied for previous defined command.
- #
- # ==== Examples
- #
- # at_least_one do
- # option :one
- # option :two
- # end
- #
- # Or
- #
- # option :one
- # option :two
- # at_least_one :one, :two
- #
- # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
- # will be raised.
- #
- # You can use at_least_one and exclusive at the same time.
- #
- # exclusive do
- # at_least_one do
- # option :one
- # option :two
- # end
- # end
- #
- # Then it is required either only one of "--one" or "--two".
- #
- def method_at_least_one(*args, &block)
- register_options_relation_for(:method_options,
- :method_at_least_one_option_names, *args, &block)
- end
- alias_method :at_least_one, :method_at_least_one
-
# Prints help information for the given command.
#
# ==== Parameters
@@ -264,16 +178,9 @@ class Bundler::Thor
shell.say " #{banner(command).split("\n").join("\n ")}"
shell.say
class_options_help(shell, nil => command.options.values)
- print_exclusive_options(shell, command)
- print_at_least_one_required_options(shell, command)
-
if command.long_description
shell.say "Description:"
- if command.wrap_long_description
- shell.print_wrapped(command.long_description, indent: 2)
- else
- shell.say command.long_description
- end
+ shell.print_wrapped(command.long_description, :indent => 2)
else
shell.say command.description
end
@@ -290,7 +197,7 @@ class Bundler::Thor
Bundler::Thor::Util.thor_classes_in(self).each do |klass|
list += klass.printable_commands(false)
end
- sort_commands!(list)
+ list.sort! { |a, b| a[0] <=> b[0] }
if defined?(@package_name) && @package_name
shell.say "#{@package_name} commands:"
@@ -298,11 +205,9 @@ class Bundler::Thor
shell.say "Commands:"
end
- shell.print_table(list, indent: 2, truncate: true)
+ shell.print_table(list, :indent => 2, :truncate => true)
shell.say
class_options_help(shell)
- print_exclusive_options(shell)
- print_at_least_one_required_options(shell)
end
# Returns commands ready to be printed.
@@ -333,7 +238,7 @@ class Bundler::Thor
define_method(subcommand) do |*args|
args, opts = Bundler::Thor::Arguments.split(args)
- invoke_args = [args, opts, {invoked_via_subcommand: true, class_options: options}]
+ invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}]
invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h")
invoke subcommand_class, *invoke_args
end
@@ -441,24 +346,6 @@ class Bundler::Thor
protected
- # Returns this class exclusive options array set.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def method_exclusive_option_names #:nodoc:
- @method_exclusive_option_names ||= []
- end
-
- # Returns this class at least one of required options array set.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def method_at_least_one_option_names #:nodoc:
- @method_at_least_one_option_names ||= []
- end
-
def stop_on_unknown_option #:nodoc:
@stop_on_unknown_option ||= []
end
@@ -468,30 +355,8 @@ class Bundler::Thor
@disable_required_check ||= [:help]
end
- def print_exclusive_options(shell, command = nil) # :nodoc:
- opts = []
- opts = command.method_exclusive_option_names unless command.nil?
- opts += class_exclusive_option_names
- unless opts.empty?
- shell.say "Exclusive Options:"
- shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
- shell.say
- end
- end
-
- def print_at_least_one_required_options(shell, command = nil) # :nodoc:
- opts = []
- opts = command.method_at_least_one_option_names unless command.nil?
- opts += class_at_least_one_option_names
- unless opts.empty?
- shell.say "Required At Least One:"
- shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
- shell.say
- end
- end
-
# The method responsible for dispatching given the args.
- def dispatch(meth, given_args, given_opts, config) #:nodoc:
+ def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
meth ||= retrieve_command_name(given_args)
command = all_commands[normalize_command_name(meth)]
@@ -550,16 +415,12 @@ class Bundler::Thor
@usage ||= nil
@desc ||= nil
@long_desc ||= nil
- @long_desc_wrap ||= nil
@hide ||= nil
if @usage && @desc
base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command
- relations = {exclusive_option_names: method_exclusive_option_names,
- at_least_one_option_names: method_at_least_one_option_names}
- commands[meth] = base_class.new(meth, @desc, @long_desc, @long_desc_wrap, @usage, method_options, relations)
- @usage, @desc, @long_desc, @long_desc_wrap, @method_options, @hide = nil
- @method_exclusive_option_names, @method_at_least_one_option_names = nil
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
+ @usage, @desc, @long_desc, @method_options, @hide = nil
true
elsif all_commands[meth] || meth == "method_missing"
true
@@ -634,14 +495,6 @@ class Bundler::Thor
"
end
alias_method :subtask_help, :subcommand_help
-
- # Sort the commands, lexicographically by default.
- #
- # Can be overridden in the subclass to change the display order of the
- # commands.
- def sort_commands!(list)
- list.sort! { |a, b| a[0] <=> b[0] }
- end
end
include Bundler::Thor::Base
diff --git a/lib/bundler/vendor/thor/lib/thor/actions.rb b/lib/bundler/vendor/thor/lib/thor/actions.rb
index ca58182691..de9b3b4c86 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions.rb
@@ -46,17 +46,17 @@ class Bundler::Thor
# Add runtime options that help actions execution.
#
def add_runtime_options!
- class_option :force, type: :boolean, aliases: "-f", group: :runtime,
- desc: "Overwrite files that already exist"
+ class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
+ :desc => "Overwrite files that already exist"
- class_option :pretend, type: :boolean, aliases: "-p", group: :runtime,
- desc: "Run but do not make any changes"
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
+ :desc => "Run but do not make any changes"
- class_option :quiet, type: :boolean, aliases: "-q", group: :runtime,
- desc: "Suppress status output"
+ class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
+ :desc => "Suppress status output"
- class_option :skip, type: :boolean, aliases: "-s", group: :runtime,
- desc: "Skip files that already exist"
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
+ :desc => "Skip files that already exist"
end
end
@@ -113,9 +113,9 @@ class Bundler::Thor
#
def relative_to_original_destination_root(path, remove_dot = true)
root = @destination_stack[0]
- if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ""].include?(path[root.size..root.size])
+ if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ''].include?(path[root.size..root.size])
path = path.dup
- path[0...root.size] = "."
+ path[0...root.size] = '.'
remove_dot ? (path[2..-1] || "") : path
else
path
@@ -175,7 +175,7 @@ class Bundler::Thor
shell.padding += 1 if verbose
@destination_stack.push File.expand_path(dir, destination_root)
- # If the directory doesn't exist and we're not pretending
+ # If the directory doesnt exist and we're not pretending
if !File.exist?(destination_root) && !pretend
require "fileutils"
FileUtils.mkdir_p(destination_root)
@@ -225,7 +225,7 @@ class Bundler::Thor
require "open-uri"
URI.open(path, "Accept" => "application/x-thor-template", &:read)
else
- File.open(path, &:read)
+ open(path, &:read)
end
instance_eval(contents, path)
@@ -284,7 +284,7 @@ class Bundler::Thor
#
def run_ruby_script(command, config = {})
return unless behavior == :invoke
- run command, config.merge(with: Bundler::Thor::Util.ruby_command)
+ run command, config.merge(:with => Bundler::Thor::Util.ruby_command)
end
# Run a thor command. A hash of options can be given and it's converted to
@@ -315,7 +315,7 @@ class Bundler::Thor
args.push Bundler::Thor::Options.to_switches(config)
command = args.join(" ").strip
- run command, with: :thor, verbose: verbose, pretend: pretend, capture: capture
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
end
protected
@@ -323,7 +323,7 @@ class Bundler::Thor
# Allow current root to be shared between invocations.
#
def _shared_configuration #:nodoc:
- super.merge!(destination_root: destination_root)
+ super.merge!(:destination_root => destination_root)
end
def _cleanup_options_and_set(options, key) #:nodoc:
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb b/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
index 6724835b01..330fc08cae 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
@@ -43,8 +43,7 @@ class Bundler::Thor
# Boolean:: true if it is identical, false otherwise.
#
def identical?
- # binread uses ASCII-8BIT, so to avoid false negatives, the string must use the same
- exists? && File.binread(destination) == String.new(render).force_encoding("ASCII-8BIT")
+ exists? && File.binread(destination) == render
end
# Holds the content to be added to the file.
@@ -61,7 +60,7 @@ class Bundler::Thor
invoke_with_conflict_check do
require "fileutils"
FileUtils.mkdir_p(File.dirname(destination))
- File.open(destination, "wb", config[:perm]) { |f| f.write render }
+ File.open(destination, "wb") { |f| f.write render }
end
given_destination
end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/directory.rb b/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
index 2f9687c0a5..d37327a139 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
@@ -58,7 +58,7 @@ class Bundler::Thor
def initialize(base, source, destination = nil, config = {}, &block)
@source = File.expand_path(Dir[Util.escape_globs(base.find_in_source_paths(source.to_s))].first)
@block = block
- super(base, destination, {recursive: true}.merge(config))
+ super(base, destination, {:recursive => true}.merge(config))
end
def invoke!
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb b/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
index c0bca78525..284d92c19a 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
@@ -33,7 +33,7 @@ class Bundler::Thor
#
def initialize(base, destination, config = {})
@base = base
- @config = {verbose: true}.merge(config)
+ @config = {:verbose => true}.merge(config)
self.destination = destination
end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
index 80a0255996..bf2a737c84 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
@@ -66,15 +66,12 @@ class Bundler::Thor
# ==== Parameters
# source<String>:: the address of the given content.
# destination<String>:: the relative path to the destination root.
- # config<Hash>:: give :verbose => false to not log the status, and
- # :http_headers => <Hash> to add headers to an http request.
+ # config<Hash>:: give :verbose => false to not log the status.
#
# ==== Examples
#
# get "http://gist.github.com/103208", "doc/README"
#
- # get "http://gist.github.com/103208", "doc/README", :http_headers => {"Content-Type" => "application/json"}
- #
# get "http://gist.github.com/103208" do |content|
# content.split("\n").first
# end
@@ -85,10 +82,10 @@ class Bundler::Thor
render = if source =~ %r{^https?\://}
require "open-uri"
- URI.send(:open, source, config.fetch(:http_headers, {})) { |input| input.binmode.read }
+ URI.send(:open, source) { |input| input.binmode.read }
else
source = File.expand_path(find_in_source_paths(source.to_s))
- File.open(source) { |input| input.binmode.read }
+ open(source) { |input| input.binmode.read }
end
destination ||= if block_given?
@@ -123,7 +120,12 @@ class Bundler::Thor
context = config.delete(:context) || instance_eval("binding")
create_file destination, nil, config do
- capturable_erb = CapturableERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer")
+ match = ERB.version.match(/(\d+\.\d+\.\d+)/)
+ capturable_erb = if match && match[1] >= "2.2.0" # Ruby 2.6+
+ CapturableERB.new(::File.binread(source), :trim_mode => "-", :eoutvar => "@output_buffer")
+ else
+ CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer")
+ end
content = capturable_erb.tap do |erb|
erb.filename = source
end.result(context)
@@ -250,7 +252,7 @@ class Bundler::Thor
# flag<Regexp|String>:: the regexp or string to be replaced
# replacement<String>:: the replacement, can be also given as a block
# config<Hash>:: give :verbose => false to not log the status, and
- # :force => true, to force the replacement regardless of runner behavior.
+ # :force => true, to force the replacement regardles of runner behavior.
#
# ==== Example
#
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
index 70526e615f..bf013307f1 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
@@ -21,7 +21,7 @@ class Bundler::Thor
# gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
# end
#
- WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
+ WARNINGS = { unchanged_no_flag: 'File unchanged! The supplied flag value not found!' }
def insert_into_file(destination, *args, &block)
data = block_given? ? block : args.shift
@@ -37,7 +37,7 @@ class Bundler::Thor
attr_reader :replacement, :flag, :behavior
def initialize(base, destination, data, config)
- super(base, destination, {verbose: true}.merge(config))
+ super(base, destination, {:verbose => true}.merge(config))
@behavior, @flag = if @config.key?(:after)
[:after, @config.delete(:after)]
@@ -59,8 +59,6 @@ class Bundler::Thor
if exists?
if replace!(/#{flag}/, content, config[:force])
say_status(:invoke)
- elsif replacement_present?
- say_status(:unchanged, color: :blue)
else
say_status(:unchanged, warning: WARNINGS[:unchanged_no_flag], color: :red)
end
@@ -98,8 +96,6 @@ class Bundler::Thor
end
elsif warning
warning
- elsif behavior == :unchanged
- :unchanged
else
:subtract
end
@@ -107,18 +103,11 @@ class Bundler::Thor
super(status, (color || config[:verbose]))
end
- def content
- @content ||= File.read(destination)
- end
-
- def replacement_present?
- content.include?(replacement)
- end
-
# Adds the content to the file.
#
def replace!(regexp, string, force)
- if force || !replacement_present?
+ content = File.read(destination)
+ if force || !content.include?(replacement)
success = content.gsub!(regexp, string)
File.open(destination, "wb") { |file| file.write(content) } unless pretend?
diff --git a/lib/bundler/vendor/thor/lib/thor/base.rb b/lib/bundler/vendor/thor/lib/thor/base.rb
index b156899c1e..8487f9590a 100644
--- a/lib/bundler/vendor/thor/lib/thor/base.rb
+++ b/lib/bundler/vendor/thor/lib/thor/base.rb
@@ -24,9 +24,9 @@ class Bundler::Thor
class << self
def deprecation_warning(message) #:nodoc:
- unless ENV["THOR_SILENCE_DEPRECATION"]
+ unless ENV['THOR_SILENCE_DEPRECATION']
warn "Deprecation warning: #{message}\n" +
- "You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION."
+ 'You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.'
end
end
end
@@ -60,7 +60,6 @@ class Bundler::Thor
command_options = config.delete(:command_options) # hook for start
parse_options = parse_options.merge(command_options) if command_options
-
if local_options.is_a?(Array)
array_options = local_options
hash_options = {}
@@ -74,24 +73,9 @@ class Bundler::Thor
# Let Bundler::Thor::Options parse the options first, so it can remove
# declared options from the array. This will leave us with
# a list of arguments that weren't declared.
- current_command = config[:current_command]
- stop_on_unknown = self.class.stop_on_unknown_option? current_command
-
- # Give a relation of options.
- # After parsing, Bundler::Thor::Options check whether right relations are kept
- relations = if current_command.nil?
- {exclusive_option_names: [], at_least_one_option_names: []}
- else
- current_command.options_relation
- end
-
- self.class.class_exclusive_option_names.map { |n| relations[:exclusive_option_names] << n }
- self.class.class_at_least_one_option_names.map { |n| relations[:at_least_one_option_names] << n }
-
- disable_required_check = self.class.disable_required_check? current_command
-
- opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check, relations)
-
+ stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
+ disable_required_check = self.class.disable_required_check? config[:current_command]
+ opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check)
self.options = opts.parse(array_options)
self.options = config[:class_options].merge(options) if config[:class_options]
@@ -326,92 +310,9 @@ class Bundler::Thor
# :hide:: -- If you want to hide this option from the help.
#
def class_option(name, options = {})
- unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
- raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
- end
build_option(name, options, class_options)
end
- # Adds and declares option group for exclusive options in the
- # block and arguments. You can declare options as the outside of the block.
- #
- # ==== Parameters
- # Array[Bundler::Thor::Option.name]
- #
- # ==== Examples
- #
- # class_exclusive do
- # class_option :one
- # class_option :two
- # end
- #
- # Or
- #
- # class_option :one
- # class_option :two
- # class_exclusive :one, :two
- #
- # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
- # will be raised.
- #
- def class_exclusive(*args, &block)
- register_options_relation_for(:class_options,
- :class_exclusive_option_names, *args, &block)
- end
-
- # Adds and declares option group for required at least one of options in the
- # block and arguments. You can declare options as the outside of the block.
- #
- # ==== Examples
- #
- # class_at_least_one do
- # class_option :one
- # class_option :two
- # end
- #
- # Or
- #
- # class_option :one
- # class_option :two
- # class_at_least_one :one, :two
- #
- # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
- # will be raised.
- #
- # You can use class_at_least_one and class_exclusive at the same time.
- #
- # class_exclusive do
- # class_at_least_one do
- # class_option :one
- # class_option :two
- # end
- # end
- #
- # Then it is required either only one of "--one" or "--two".
- #
- def class_at_least_one(*args, &block)
- register_options_relation_for(:class_options,
- :class_at_least_one_option_names, *args, &block)
- end
-
- # Returns this class exclusive options array set, looking up in the ancestors chain.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def class_exclusive_option_names
- @class_exclusive_option_names ||= from_superclass(:class_exclusive_option_names, [])
- end
-
- # Returns this class at least one of required options array set, looking up in the ancestors chain.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def class_at_least_one_option_names
- @class_at_least_one_option_names ||= from_superclass(:class_at_least_one_option_names, [])
- end
-
# Removes a previous defined argument. If :undefine is given, undefine
# accessors as well.
#
@@ -605,7 +506,7 @@ class Bundler::Thor
#
def public_command(*names)
names.each do |name|
- class_eval "def #{name}(*); super end", __FILE__, __LINE__
+ class_eval "def #{name}(*); super end"
end
end
alias_method :public_task, :public_command
@@ -657,19 +558,20 @@ class Bundler::Thor
return if options.empty?
list = []
- padding = options.map { |o| o.aliases_for_usage.size }.max.to_i
+ padding = options.map { |o| o.aliases.size }.max.to_i * 4
+
options.each do |option|
next if option.hide
item = [option.usage(padding)]
item.push(option.description ? "# #{option.description}" : "")
list << item
- list << ["", "# Default: #{option.print_default}"] if option.show_default?
- list << ["", "# Possible values: #{option.enum_to_s}"] if option.enum
+ list << ["", "# Default: #{option.default}"] if option.show_default?
+ list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum
end
shell.say(group_name ? "#{group_name} options:" : "Options:")
- shell.print_table(list, indent: 2)
+ shell.print_table(list, :indent => 2)
shell.say ""
end
@@ -686,7 +588,7 @@ class Bundler::Thor
# options<Hash>:: Described in both class_option and method_option.
# scope<Hash>:: Options hash that is being built up
def build_option(name, options, scope) #:nodoc:
- scope[name] = Bundler::Thor::Option.new(name, {check_default_type: check_default_type}.merge!(options))
+ scope[name] = Bundler::Thor::Option.new(name, {:check_default_type => check_default_type}.merge!(options))
end
# Receives a hash of options, parse them and add to the scope. This is a
@@ -708,7 +610,7 @@ class Bundler::Thor
def find_and_refresh_command(name) #:nodoc:
if commands[name.to_s]
commands[name.to_s]
- elsif command = all_commands[name.to_s] # rubocop:disable Lint/AssignmentInCondition
+ elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition
commands[name.to_s] = command.clone
else
raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
@@ -716,7 +618,7 @@ class Bundler::Thor
end
alias_method :find_and_refresh_task, :find_and_refresh_command
- # Every time someone inherits from a Bundler::Thor class, register the klass
+ # Everytime someone inherits from a Bundler::Thor class, register the klass
# and file into baseclass.
def inherited(klass)
super(klass)
@@ -792,34 +694,6 @@ class Bundler::Thor
def dispatch(command, given_args, given_opts, config) #:nodoc:
raise NotImplementedError
end
-
- # Register a relation of options for target(method_option/class_option)
- # by args and block.
- def register_options_relation_for(target, relation, *args, &block) # :nodoc:
- opt = args.pop if args.last.is_a? Hash
- opt ||= {}
- names = args.map{ |arg| arg.to_s }
- names += built_option_names(target, opt, &block) if block_given?
- command_scope_member(relation, opt) << names
- end
-
- # Get target(method_options or class_options) options
- # of before and after by block evaluation.
- def built_option_names(target, opt = {}, &block) # :nodoc:
- before = command_scope_member(target, opt).map{ |k,v| v.name }
- instance_eval(&block)
- after = command_scope_member(target, opt).map{ |k,v| v.name }
- after - before
- end
-
- # Get command scope member by name.
- def command_scope_member(name, options = {}) # :nodoc:
- if options[:for]
- find_and_refresh_command(options[:for]).send(name)
- else
- send(name)
- end
- end
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/command.rb b/lib/bundler/vendor/thor/lib/thor/command.rb
index 68c8fffedb..040c971c0c 100644
--- a/lib/bundler/vendor/thor/lib/thor/command.rb
+++ b/lib/bundler/vendor/thor/lib/thor/command.rb
@@ -1,15 +1,14 @@
class Bundler::Thor
- class Command < Struct.new(:name, :description, :long_description, :wrap_long_description, :usage, :options, :options_relation, :ancestor_name)
+ class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name)
FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
- def initialize(name, description, long_description, wrap_long_description, usage, options = nil, options_relation = nil)
- super(name.to_s, description, long_description, wrap_long_description, usage, options || {}, options_relation || {})
+ def initialize(name, description, long_description, usage, options = nil)
+ super(name.to_s, description, long_description, usage, options || {})
end
def initialize_copy(other) #:nodoc:
super(other)
self.options = other.options.dup if other.options
- self.options_relation = other.options_relation.dup if other.options_relation
end
def hidden?
@@ -63,14 +62,6 @@ class Bundler::Thor
end.join("\n")
end
- def method_exclusive_option_names #:nodoc:
- self.options_relation[:exclusive_option_names] || []
- end
-
- def method_at_least_one_option_names #:nodoc:
- self.options_relation[:at_least_one_option_names] || []
- end
-
protected
# Add usage with required arguments
@@ -136,7 +127,7 @@ class Bundler::Thor
# A dynamic command that handles method missing scenarios.
class DynamicCommand < Command
def initialize(name, options = nil)
- super(name.to_s, "A dynamically-generated command", name.to_s, nil, name.to_s, options)
+ super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options)
end
def run(instance, args = [])
diff --git a/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb b/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
index b16a98f782..3c4483e5dd 100644
--- a/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
+++ b/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
@@ -38,10 +38,6 @@ class Bundler::Thor
super(convert_key(key), *args)
end
- def slice(*keys)
- super(*keys.map{ |key| convert_key(key) })
- end
-
def key?(key)
super(convert_key(key))
end
diff --git a/lib/bundler/vendor/thor/lib/thor/error.rb b/lib/bundler/vendor/thor/lib/thor/error.rb
index 928646e501..03f2ce85bb 100644
--- a/lib/bundler/vendor/thor/lib/thor/error.rb
+++ b/lib/bundler/vendor/thor/lib/thor/error.rb
@@ -1,15 +1,18 @@
class Bundler::Thor
Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName
- Module.new do
- def to_s
- super + DidYouMean.formatter.message_for(corrections)
- end
-
- def corrections
- @corrections ||= self.class.const_get(:SpellChecker).new(self).corrections
- end
- end
- end
+ # In order to support versions of Ruby that don't have keyword
+ # arguments, we need our own spell checker class that doesn't take key
+ # words. Even though this code wouldn't be hit because of the check
+ # above, it's still necessary because the interpreter would otherwise be
+ # unable to parse the file.
+ class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc:
+ def initialize(dictionary)
+ @dictionary = dictionary
+ end
+ end
+
+ DidYouMean::Correctable
+ end
# Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those
# errors have their backtrace suppressed and are nicely shown to the user.
@@ -34,7 +37,7 @@ class Bundler::Thor
end
def spell_checker
- DidYouMean::SpellChecker.new(dictionary: error.all_commands)
+ NoKwargSpellChecker.new(error.all_commands)
end
end
@@ -76,7 +79,7 @@ class Bundler::Thor
end
def spell_checker
- @spell_checker ||= DidYouMean::SpellChecker.new(dictionary: error.switches)
+ @spell_checker ||= NoKwargSpellChecker.new(error.switches)
end
end
@@ -98,9 +101,15 @@ class Bundler::Thor
class MalformattedArgumentError < InvocationError
end
- class ExclusiveArgumentError < InvocationError
- end
-
- class AtLeastOneRequiredArgumentError < InvocationError
+ if Correctable
+ if DidYouMean.respond_to?(:correct_error)
+ DidYouMean.correct_error(Bundler::Thor::UndefinedCommandError, UndefinedCommandError::SpellChecker)
+ DidYouMean.correct_error(Bundler::Thor::UnknownArgumentError, UnknownArgumentError::SpellChecker)
+ else
+ DidYouMean::SPELL_CHECKERS.merge!(
+ 'Bundler::Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker,
+ 'Bundler::Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker
+ )
+ end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/group.rb b/lib/bundler/vendor/thor/lib/thor/group.rb
index 7ea11e8f93..7861d05345 100644
--- a/lib/bundler/vendor/thor/lib/thor/group.rb
+++ b/lib/bundler/vendor/thor/lib/thor/group.rb
@@ -169,7 +169,7 @@ class Bundler::Thor::Group
# options are added to group_options hash. Options that already exists
# in base_options are not added twice.
#
- def get_options_from_invocations(group_options, base_options) #:nodoc:
+ def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength
invocations.each do |name, from_option|
value = if from_option
option = class_options[name]
diff --git a/lib/bundler/vendor/thor/lib/thor/invocation.rb b/lib/bundler/vendor/thor/lib/thor/invocation.rb
index 5ce74710ba..248a466f8e 100644
--- a/lib/bundler/vendor/thor/lib/thor/invocation.rb
+++ b/lib/bundler/vendor/thor/lib/thor/invocation.rb
@@ -143,7 +143,7 @@ class Bundler::Thor
# Configuration values that are shared between invocations.
def _shared_configuration #:nodoc:
- {invocations: @_invocations}
+ {:invocations => @_invocations}
end
# This method simply retrieves the class and command to be invoked.
diff --git a/lib/bundler/vendor/thor/lib/thor/nested_context.rb b/lib/bundler/vendor/thor/lib/thor/nested_context.rb
index 7d60cb1c12..fd36b9d43f 100644
--- a/lib/bundler/vendor/thor/lib/thor/nested_context.rb
+++ b/lib/bundler/vendor/thor/lib/thor/nested_context.rb
@@ -13,10 +13,10 @@ class Bundler::Thor
end
def entered?
- @depth.positive?
+ @depth > 0
end
- private
+ private
def push
@depth += 1
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/argument.rb b/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
index b9e94e4669..dfe7398583 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
@@ -24,17 +24,6 @@ class Bundler::Thor
validate! # Trigger specific validations
end
- def print_default
- if @type == :array and @default.is_a?(Array)
- @default.map { |x|
- p = x.gsub('"','\\"')
- "\"#{p}\""
- }.join(" ")
- else
- @default
- end
- end
-
def usage
required? ? banner : "[#{banner}]"
end
@@ -52,19 +41,11 @@ class Bundler::Thor
end
end
- def enum_to_s
- if enum.respond_to? :join
- enum.join(", ")
- else
- "#{enum.first}..#{enum.last}"
- end
- end
-
protected
def validate!
raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil?
- raise ArgumentError, "An argument cannot have an enum other than an enumerable." if @enum && !@enum.is_a?(Enumerable)
+ raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array)
end
def valid_type?(type)
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
index b6f9c9a37a..3a5d82cf29 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
@@ -1,5 +1,5 @@
class Bundler::Thor
- class Arguments #:nodoc:
+ class Arguments #:nodoc: # rubocop:disable ClassLength
NUMERIC = /[-+]?(\d*\.\d+|\d+)/
# Receives an array of args and returns two arrays, one with arguments
@@ -30,7 +30,11 @@ class Bundler::Thor
arguments.each do |argument|
if !argument.default.nil?
- @assigns[argument.human_name] = argument.default.dup
+ begin
+ @assigns[argument.human_name] = argument.default.dup
+ rescue TypeError # Compatibility shim for un-dup-able Fixnum in Ruby < 2.4
+ @assigns[argument.human_name] = argument.default
+ end
elsif argument.required?
@non_assigned_required << argument
end
@@ -117,18 +121,8 @@ class Bundler::Thor
#
def parse_array(name)
return shift if peek.is_a?(Array)
-
array = []
-
- while current_is_value?
- value = shift
-
- if !value.empty?
- validate_enum_value!(name, value, "Expected all values of '%s' to be one of %s; got %s")
- end
-
- array << value
- end
+ array << shift while current_is_value?
array
end
@@ -144,9 +138,11 @@ class Bundler::Thor
end
value = $&.index(".") ? shift.to_f : shift.to_i
-
- validate_enum_value!(name, value, "Expected '%s' to be one of %s; got %s")
-
+ if @switches.is_a?(Hash) && switch = @switches[name]
+ if switch.enum && !switch.enum.include?(value)
+ raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
+ end
+ end
value
end
@@ -160,27 +156,15 @@ class Bundler::Thor
nil
else
value = shift
-
- validate_enum_value!(name, value, "Expected '%s' to be one of %s; got %s")
-
+ if @switches.is_a?(Hash) && switch = @switches[name]
+ if switch.enum && !switch.enum.include?(value)
+ raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
+ end
+ end
value
end
end
- # Raises an error if the switch is an enum and the values aren't included on it.
- #
- def validate_enum_value!(name, value, message)
- return unless @switches.is_a?(Hash)
-
- switch = @switches[name]
-
- return unless switch
-
- if switch.enum && !switch.enum.include?(value)
- raise MalformattedArgumentError, message % [name, switch.enum_to_s, value]
- end
- end
-
# Raises an error if @non_assigned_required array is not empty.
#
def check_requirement!
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/option.rb b/lib/bundler/vendor/thor/lib/thor/parser/option.rb
index c6af4e1e87..5a5af6f888 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/option.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/option.rb
@@ -11,7 +11,7 @@ class Bundler::Thor
super
@lazy_default = options[:lazy_default]
@group = options[:group].to_s.capitalize if options[:group]
- @aliases = normalize_aliases(options[:aliases])
+ @aliases = Array(options[:aliases])
@hide = options[:hide]
end
@@ -58,7 +58,7 @@ class Bundler::Thor
default = nil
if VALID_TYPES.include?(value)
value
- elsif required = (value == :required) # rubocop:disable Lint/AssignmentInCondition
+ elsif required = (value == :required) # rubocop:disable AssignmentInCondition
:string
end
when TrueClass, FalseClass
@@ -69,7 +69,7 @@ class Bundler::Thor
value.class.name.downcase.to_sym
end
- new(name.to_s, required: required, type: type, default: default, aliases: aliases)
+ new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases)
end
def switch_name
@@ -90,26 +90,13 @@ class Bundler::Thor
sample = "[#{sample}]".dup unless required?
if boolean?
- sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.match(/\Ano[\-_]/)
+ sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-")
end
- aliases_for_usage.ljust(padding) + sample
- end
-
- def aliases_for_usage
if aliases.empty?
- ""
- else
- "#{aliases.join(', ')}, "
- end
- end
-
- def show_default?
- case default
- when TrueClass, FalseClass
- true
+ (" " * padding) << sample
else
- super
+ "#{aliases.join(', ')}, #{sample}"
end
end
@@ -151,8 +138,8 @@ class Bundler::Thor
raise ArgumentError, err
elsif @check_default_type == nil
Bundler::Thor.deprecation_warning "#{err}.\n" +
- "This will be rejected in the future unless you explicitly pass the options `check_default_type: false`" +
- " or call `allow_incompatible_default_type!` in your code"
+ 'This will be rejected in the future unless you explicitly pass the options `check_default_type: false`' +
+ ' or call `allow_incompatible_default_type!` in your code'
end
end
end
@@ -168,11 +155,5 @@ class Bundler::Thor
def dasherize(str)
(str.length > 1 ? "--" : "-") + str.tr("_", "-")
end
-
- private
-
- def normalize_aliases(aliases)
- Array(aliases).map { |short| short.to_s.sub(/^(?!\-)/, "-") }
- end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/options.rb b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
index 978e76b132..5bd97aba6f 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/options.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
@@ -1,5 +1,5 @@
class Bundler::Thor
- class Options < Arguments #:nodoc:
+ class Options < Arguments #:nodoc: # rubocop:disable ClassLength
LONG_RE = /^(--\w+(?:-\w+)*)$/
SHORT_RE = /^(-[a-z])$/i
EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
@@ -29,10 +29,8 @@ class Bundler::Thor
#
# If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
# an unknown option or a regular argument.
- def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false, relations = {})
+ def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false)
@stop_on_unknown = stop_on_unknown
- @exclusives = (relations[:exclusive_option_names] || []).select{|array| !array.empty?}
- @at_least_ones = (relations[:at_least_one_option_names] || []).select{|array| !array.empty?}
@disable_required_check = disable_required_check
options = hash_options.values
super(options)
@@ -52,7 +50,8 @@ class Bundler::Thor
options.each do |option|
@switches[option.switch_name] = option
- option.aliases.each do |name|
+ option.aliases.each do |short|
+ name = short.to_s.sub(/^(?!\-)/, "-")
@shorts[name] ||= option.switch_name
end
end
@@ -86,7 +85,7 @@ class Bundler::Thor
super(arg)
end
- def parse(args) # rubocop:disable Metrics/MethodLength
+ def parse(args) # rubocop:disable MethodLength
@pile = args.dup
@is_treated_as_value = false
@parsing_options = true
@@ -133,38 +132,12 @@ class Bundler::Thor
end
check_requirement! unless @disable_required_check
- check_exclusive!
- check_at_least_one!
assigns = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
assigns.freeze
assigns
end
- def check_exclusive!
- opts = @assigns.keys
- # When option A and B are exclusive, if A and B are given at the same time,
- # the diffrence of argument array size will decrease.
- found = @exclusives.find{ |ex| (ex - opts).size < ex.size - 1 }
- if found
- names = names_to_switch_names(found & opts).map{|n| "'#{n}'"}
- class_name = self.class.name.split("::").last.downcase
- fail ExclusiveArgumentError, "Found exclusive #{class_name} #{names.join(", ")}"
- end
- end
-
- def check_at_least_one!
- opts = @assigns.keys
- # When at least one is required of the options A and B,
- # if the both options were not given, none? would be true.
- found = @at_least_ones.find{ |one_reqs| one_reqs.none?{ |o| opts.include? o} }
- if found
- names = names_to_switch_names(found).map{|n| "'#{n}'"}
- class_name = self.class.name.split("::").last.downcase
- fail AtLeastOneRequiredArgumentError, "Not found at least one of required #{class_name} #{names.join(", ")}"
- end
- end
-
def check_unknown!
to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra
@@ -175,17 +148,6 @@ class Bundler::Thor
protected
- # Option names changes to swith name or human name
- def names_to_switch_names(names = [])
- @switches.map do |_, o|
- if names.include? o.name
- o.respond_to?(:switch_name) ? o.switch_name : o.human_name
- else
- nil
- end
- end.compact
- end
-
def assign_result!(option, result)
if option.repeatable && option.type == :hash
(@assigns[option.human_name] ||= {}).merge!(result)
@@ -232,7 +194,7 @@ class Bundler::Thor
end
def switch_option(arg)
- if match = no_or_skip?(arg) # rubocop:disable Lint/AssignmentInCondition
+ if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition
@switches[arg] || @switches["--#{match}"]
else
@switches[arg]
diff --git a/lib/bundler/vendor/thor/lib/thor/rake_compat.rb b/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
index c6a4653fc1..f8f86372cc 100644
--- a/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
+++ b/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
@@ -41,7 +41,7 @@ instance_eval do
def task(*)
task = super
- if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable Lint/AssignmentInCondition
+ if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
non_namespaced_name = task.name.split(":").last
description = non_namespaced_name
@@ -59,7 +59,7 @@ instance_eval do
end
def namespace(name)
- if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable Lint/AssignmentInCondition
+ if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
const_name = Bundler::Thor::Util.camel_case(name.to_s).to_sym
klass.const_set(const_name, Class.new(Bundler::Thor))
new_klass = klass.const_get(const_name)
diff --git a/lib/bundler/vendor/thor/lib/thor/runner.rb b/lib/bundler/vendor/thor/lib/thor/runner.rb
index c7cc873131..54c5525093 100644
--- a/lib/bundler/vendor/thor/lib/thor/runner.rb
+++ b/lib/bundler/vendor/thor/lib/thor/runner.rb
@@ -2,10 +2,12 @@ require_relative "../thor"
require_relative "group"
require "yaml"
-require "digest/sha2"
+require "digest/md5"
require "pathname"
-class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
+class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength
+ autoload :OpenURI, "open-uri"
+
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
def self.banner(command, all = false, subcommand = false)
@@ -23,7 +25,7 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
initialize_thorfiles(meth)
klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth)
self.class.handle_no_command_error(command, false) if klass.nil?
- klass.start(["-h", command].compact, shell: shell)
+ klass.start(["-h", command].compact, :shell => shell)
else
super
end
@@ -38,42 +40,30 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth)
self.class.handle_no_command_error(command, false) if klass.nil?
args.unshift(command) if command
- klass.start(args, shell: shell)
+ klass.start(args, :shell => shell)
end
desc "install NAME", "Install an optionally named Bundler::Thor file into your system commands"
- method_options as: :string, relative: :boolean, force: :boolean
- def install(name) # rubocop:disable Metrics/MethodLength
+ method_options :as => :string, :relative => :boolean, :force => :boolean
+ def install(name) # rubocop:disable MethodLength
initialize_thorfiles
- is_uri = name =~ %r{^https?\://}
-
- if is_uri
- base = name
- package = :file
- require "open-uri"
- begin
- contents = URI.open(name, &:read)
- rescue OpenURI::HTTPError
- raise Error, "Error opening URI '#{name}'"
- end
- else
- # If a directory name is provided as the argument, look for a 'main.thor'
- # command in said directory.
- begin
- if File.directory?(File.expand_path(name))
- base = File.join(name, "main.thor")
- package = :directory
- contents = File.open(base, &:read)
- else
- base = name
- package = :file
- require "open-uri"
- contents = URI.open(name, &:read)
- end
- rescue Errno::ENOENT
- raise Error, "Error opening file '#{name}'"
+ # If a directory name is provided as the argument, look for a 'main.thor'
+ # command in said directory.
+ begin
+ if File.directory?(File.expand_path(name))
+ base = File.join(name, "main.thor")
+ package = :directory
+ contents = open(base, &:read)
+ else
+ base = name
+ package = :file
+ contents = open(name, &:read)
end
+ rescue OpenURI::HTTPError
+ raise Error, "Error opening URI '#{name}'"
+ rescue Errno::ENOENT
+ raise Error, "Error opening file '#{name}'"
end
say "Your Thorfile contains:"
@@ -94,16 +84,16 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
as = basename if as.empty?
end
- location = if options[:relative] || is_uri
+ location = if options[:relative] || name =~ %r{^https?://}
name
else
File.expand_path(name)
end
thor_yaml[as] = {
- filename: Digest::SHA256.hexdigest(name + as),
- location: location,
- namespaces: Bundler::Thor::Util.namespaces_in_content(contents, base)
+ :filename => Digest::MD5.hexdigest(name + as),
+ :location => location,
+ :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base)
}
save_yaml(thor_yaml)
@@ -164,14 +154,14 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
end
desc "installed", "List the installed Bundler::Thor modules and commands"
- method_options internal: :boolean
+ method_options :internal => :boolean
def installed
initialize_thorfiles(nil, true)
display_klasses(true, options["internal"])
end
desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
- method_options substring: :boolean, group: :string, all: :boolean, debug: :boolean
+ method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
def list(search = "")
initialize_thorfiles
@@ -313,7 +303,7 @@ private
say shell.set_color(namespace, :blue, true)
say "-" * namespace.size
- print_table(list, truncate: true)
+ print_table(list, :truncate => true)
say
end
alias_method :display_tasks, :display_commands
diff --git a/lib/bundler/vendor/thor/lib/thor/shell.rb b/lib/bundler/vendor/thor/lib/thor/shell.rb
index 265f3ba046..a4137d1bde 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell.rb
@@ -75,7 +75,7 @@ class Bundler::Thor
# Allow shell to be shared between invocations.
#
def _shared_configuration #:nodoc:
- super.merge!(shell: shell)
+ super.merge!(:shell => shell)
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
index dc3179e5f3..ef97d52ae7 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
@@ -1,10 +1,8 @@
-require_relative "column_printer"
-require_relative "table_printer"
-require_relative "wrapped_printer"
-
class Bundler::Thor
module Shell
class Basic
+ DEFAULT_TERMINAL_WIDTH = 80
+
attr_accessor :base
attr_reader :padding
@@ -147,14 +145,14 @@ class Bundler::Thor
# "yes".
#
def yes?(statement, color = nil)
- !!(ask(statement, color, add_to_history: false) =~ is?(:yes))
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:yes))
end
# Make a question the to user and returns true if the user replies "n" or
# "no".
#
def no?(statement, color = nil)
- !!(ask(statement, color, add_to_history: false) =~ is?(:no))
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:no))
end
# Prints values in columns
@@ -163,8 +161,16 @@ class Bundler::Thor
# Array[String, String, ...]
#
def print_in_columns(array)
- printer = ColumnPrinter.new(stdout)
- printer.print(array)
+ return if array.empty?
+ colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
+ array.each_with_index do |value, index|
+ # Don't output trailing spaces when printing the last column
+ if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
+ stdout.puts value
+ else
+ stdout.printf("%-#{colwidth}s", value)
+ end
+ end
end
# Prints a table.
@@ -175,11 +181,58 @@ class Bundler::Thor
# ==== Options
# indent<Integer>:: Indent the first column by indent value.
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
- # borders<Boolean>:: Adds ascii borders.
#
- def print_table(array, options = {}) # rubocop:disable Metrics/MethodLength
- printer = TablePrinter.new(stdout, options)
- printer.print(array)
+ def print_table(array, options = {}) # rubocop:disable MethodLength
+ return if array.empty?
+
+ formats = []
+ indent = options[:indent].to_i
+ colwidth = options[:colwidth]
+ options[:truncate] = terminal_width if options[:truncate] == true
+
+ formats << "%-#{colwidth + 2}s".dup if colwidth
+ start = colwidth ? 1 : 0
+
+ colcount = array.max { |a, b| a.size <=> b.size }.size
+
+ maximas = []
+
+ start.upto(colcount - 1) do |index|
+ maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
+ maximas << maxima
+ formats << if index == colcount - 1
+ # Don't output 2 trailing spaces when printing the last column
+ "%-s".dup
+ else
+ "%-#{maxima + 2}s".dup
+ end
+ end
+
+ formats[0] = formats[0].insert(0, " " * indent)
+ formats << "%s"
+
+ array.each do |row|
+ sentence = "".dup
+
+ row.each_with_index do |column, index|
+ maxima = maximas[index]
+
+ f = if column.is_a?(Numeric)
+ if index == row.size - 1
+ # Don't output 2 trailing spaces when printing the last column
+ "%#{maxima}s"
+ else
+ "%#{maxima}s "
+ end
+ else
+ formats[index]
+ end
+ sentence << f % column.to_s
+ end
+
+ sentence = truncate(sentence, options[:truncate]) if options[:truncate]
+ stdout.puts sentence
+ end
end
# Prints a long string, word-wrapping the text to the current width of the
@@ -192,8 +245,33 @@ class Bundler::Thor
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
#
def print_wrapped(message, options = {})
- printer = WrappedPrinter.new(stdout, options)
- printer.print(message)
+ indent = options[:indent] || 0
+ width = terminal_width - indent
+ paras = message.split("\n\n")
+
+ paras.map! do |unwrapped|
+ words = unwrapped.split(" ")
+ counter = words.first.length
+ words.inject do |memo, word|
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
+ counter = 0 if word.include? "\n"
+ if (counter + word.length + 1) < width
+ memo = "#{memo} #{word}"
+ counter += (word.length + 1)
+ else
+ memo = "#{memo}\n#{word}"
+ counter = word.length
+ end
+ memo
+ end
+ end.compact!
+
+ paras.each do |para|
+ para.split("\n").each do |line|
+ stdout.puts line.insert(0, " " * indent)
+ end
+ stdout.puts unless para == paras.last
+ end
end
# Deals with file collision and returns true if the file should be
@@ -211,7 +289,7 @@ class Bundler::Thor
loop do
answer = ask(
%[Overwrite #{destination}? (enter "h" for help) #{options}],
- add_to_history: false
+ :add_to_history => false
)
case answer
@@ -238,11 +316,24 @@ class Bundler::Thor
say "Please specify merge tool to `THOR_MERGE` env."
else
- say file_collision_help(block_given?)
+ say file_collision_help
end
end
end
+ # This code was copied from Rake, available under MIT-LICENSE
+ # Copyright (c) 2003, 2004 Jim Weirich
+ def terminal_width
+ result = if ENV["THOR_COLUMNS"]
+ ENV["THOR_COLUMNS"].to_i
+ else
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
+ end
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
+ rescue
+ DEFAULT_TERMINAL_WIDTH
+ end
+
# Called if something goes wrong during the execution. This is used by Bundler::Thor
# internally and should not be used inside your scripts. If something went
# wrong, you can always raise an exception. If you raise a Bundler::Thor::Error, it
@@ -293,21 +384,16 @@ class Bundler::Thor
end
end
- def file_collision_help(block_given) #:nodoc:
- help = <<-HELP
+ def file_collision_help #:nodoc:
+ <<-HELP
Y - yes, overwrite
n - no, do not overwrite
a - all, overwrite this and all others
q - quit, abort
- h - help, show this help
- HELP
- if block_given
- help << <<-HELP
d - diff, show the differences between the old and the new
+ h - help, show this help
m - merge, run merge tool
- HELP
- end
- help
+ HELP
end
def show_diff(destination, content) #:nodoc:
@@ -325,8 +411,46 @@ class Bundler::Thor
mute? || (base && base.options[:quiet])
end
+ # Calculate the dynamic width of the terminal
+ def dynamic_width
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
+ end
+
+ def dynamic_width_stty
+ `stty size 2>/dev/null`.split[1].to_i
+ end
+
+ def dynamic_width_tput
+ `tput cols 2>/dev/null`.to_i
+ end
+
def unix?
- Terminal.unix?
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
+ end
+
+ def truncate(string, width)
+ as_unicode do
+ chars = string.chars.to_a
+ if chars.length <= width
+ chars.join
+ else
+ chars[0, width - 3].join + "..."
+ end
+ end
+ end
+
+ if "".respond_to?(:encode)
+ def as_unicode
+ yield
+ end
+ else
+ def as_unicode
+ old = $KCODE
+ $KCODE = "U"
+ yield
+ ensure
+ $KCODE = old
+ end
end
def ask_simply(statement, color, options)
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/color.rb b/lib/bundler/vendor/thor/lib/thor/shell/color.rb
index 6a9176331c..dc167ed3cc 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/color.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/color.rb
@@ -1,5 +1,4 @@
require_relative "basic"
-require_relative "lcs_diff"
class Bundler::Thor
module Shell
@@ -7,8 +6,6 @@ class Bundler::Thor
# Bundler::Thor::Shell::Basic to see all available methods.
#
class Color < Basic
- include LCSDiff
-
# Embed in a String to clear all previous ANSI sequences.
CLEAR = "\e[0m"
# The start of an ANSI bold sequence.
@@ -108,7 +105,52 @@ class Bundler::Thor
end
def are_colors_disabled?
- !ENV["NO_COLOR"].nil? && !ENV["NO_COLOR"].empty?
+ !ENV['NO_COLOR'].nil?
+ end
+
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
+ # available.
+ #
+ def show_diff(destination, content) #:nodoc:
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
+ actual = File.binread(destination).to_s.split("\n")
+ content = content.to_s.split("\n")
+
+ Diff::LCS.sdiff(actual, content).each do |diff|
+ output_diff_line(diff)
+ end
+ else
+ super
+ end
+ end
+
+ def output_diff_line(diff) #:nodoc:
+ case diff.action
+ when "-"
+ say "- #{diff.old_element.chomp}", :red, true
+ when "+"
+ say "+ #{diff.new_element.chomp}", :green, true
+ when "!"
+ say "- #{diff.old_element.chomp}", :red, true
+ say "+ #{diff.new_element.chomp}", :green, true
+ else
+ say " #{diff.old_element.chomp}", nil, true
+ end
+ end
+
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
+ # for diff.
+ #
+ def diff_lcs_loaded? #:nodoc:
+ return true if defined?(Diff::LCS)
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
+
+ @diff_lcs_loaded = begin
+ require "diff/lcs"
+ true
+ rescue LoadError
+ false
+ end
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb b/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb
deleted file mode 100644
index 56a9e6181b..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative "terminal"
-
-class Bundler::Thor
- module Shell
- class ColumnPrinter
- attr_reader :stdout, :options
-
- def initialize(stdout, options = {})
- @stdout = stdout
- @options = options
- @indent = options[:indent].to_i
- end
-
- def print(array)
- return if array.empty?
- colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
- array.each_with_index do |value, index|
- # Don't output trailing spaces when printing the last column
- if ((((index + 1) % (Terminal.terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
- stdout.puts value
- else
- stdout.printf("%-#{colwidth}s", value)
- end
- end
- end
- end
- end
-end
-
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/html.rb b/lib/bundler/vendor/thor/lib/thor/shell/html.rb
index 6091485acb..77a6d13a23 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/html.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/html.rb
@@ -1,5 +1,4 @@
require_relative "basic"
-require_relative "lcs_diff"
class Bundler::Thor
module Shell
@@ -7,8 +6,6 @@ class Bundler::Thor
# Bundler::Thor::Shell::Basic to see all available methods.
#
class HTML < Basic
- include LCSDiff
-
# The start of an HTML bold sequence.
BOLD = "font-weight: bold"
@@ -79,6 +76,51 @@ class Bundler::Thor
def can_display_colors?
true
end
+
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
+ # available.
+ #
+ def show_diff(destination, content) #:nodoc:
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
+ actual = File.binread(destination).to_s.split("\n")
+ content = content.to_s.split("\n")
+
+ Diff::LCS.sdiff(actual, content).each do |diff|
+ output_diff_line(diff)
+ end
+ else
+ super
+ end
+ end
+
+ def output_diff_line(diff) #:nodoc:
+ case diff.action
+ when "-"
+ say "- #{diff.old_element.chomp}", :red, true
+ when "+"
+ say "+ #{diff.new_element.chomp}", :green, true
+ when "!"
+ say "- #{diff.old_element.chomp}", :red, true
+ say "+ #{diff.new_element.chomp}", :green, true
+ else
+ say " #{diff.old_element.chomp}", nil, true
+ end
+ end
+
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
+ # for diff.
+ #
+ def diff_lcs_loaded? #:nodoc:
+ return true if defined?(Diff::LCS)
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
+
+ @diff_lcs_loaded = begin
+ require "diff/lcs"
+ true
+ rescue LoadError
+ false
+ end
+ end
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb b/lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb
deleted file mode 100644
index 81268a9f02..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-module LCSDiff
-protected
-
- # Overwrite show_diff to show diff with colors if Diff::LCS is
- # available.
- def show_diff(destination, content) #:nodoc:
- if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
- actual = File.binread(destination).to_s.split("\n")
- content = content.to_s.split("\n")
-
- Diff::LCS.sdiff(actual, content).each do |diff|
- output_diff_line(diff)
- end
- else
- super
- end
- end
-
-private
-
- def output_diff_line(diff) #:nodoc:
- case diff.action
- when "-"
- say "- #{diff.old_element.chomp}", :red, true
- when "+"
- say "+ #{diff.new_element.chomp}", :green, true
- when "!"
- say "- #{diff.old_element.chomp}", :red, true
- say "+ #{diff.new_element.chomp}", :green, true
- else
- say " #{diff.old_element.chomp}", nil, true
- end
- end
-
- # Check if Diff::LCS is loaded. If it is, use it to create pretty output
- # for diff.
- def diff_lcs_loaded? #:nodoc:
- return true if defined?(Diff::LCS)
- return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
-
- @diff_lcs_loaded = begin
- require "diff/lcs"
- true
- rescue LoadError
- false
- end
- end
-
-end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb b/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb
deleted file mode 100644
index 525f9ce5bb..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb
+++ /dev/null
@@ -1,134 +0,0 @@
-require_relative "column_printer"
-require_relative "terminal"
-
-class Bundler::Thor
- module Shell
- class TablePrinter < ColumnPrinter
- BORDER_SEPARATOR = :separator
-
- def initialize(stdout, options = {})
- super
- @formats = []
- @maximas = []
- @colwidth = options[:colwidth]
- @truncate = options[:truncate] == true ? Terminal.terminal_width : options[:truncate]
- @padding = 1
- end
-
- def print(array)
- return if array.empty?
-
- prepare(array)
-
- print_border_separator if options[:borders]
-
- array.each do |row|
- if options[:borders] && row == BORDER_SEPARATOR
- print_border_separator
- next
- end
-
- sentence = "".dup
-
- row.each_with_index do |column, index|
- sentence << format_cell(column, row.size, index)
- end
-
- sentence = truncate(sentence)
- sentence << "|" if options[:borders]
- stdout.puts indentation + sentence
-
- end
- print_border_separator if options[:borders]
- end
-
- private
-
- def prepare(array)
- array = array.reject{|row| row == BORDER_SEPARATOR }
-
- @formats << "%-#{@colwidth + 2}s".dup if @colwidth
- start = @colwidth ? 1 : 0
-
- colcount = array.max { |a, b| a.size <=> b.size }.size
-
- start.upto(colcount - 1) do |index|
- maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
-
- @maximas << maxima
- @formats << if options[:borders]
- "%-#{maxima}s".dup
- elsif index == colcount - 1
- # Don't output 2 trailing spaces when printing the last column
- "%-s".dup
- else
- "%-#{maxima + 2}s".dup
- end
- end
-
- @formats << "%s"
- end
-
- def format_cell(column, row_size, index)
- maxima = @maximas[index]
-
- f = if column.is_a?(Numeric)
- if options[:borders]
- # With borders we handle padding separately
- "%#{maxima}s"
- elsif index == row_size - 1
- # Don't output 2 trailing spaces when printing the last column
- "%#{maxima}s"
- else
- "%#{maxima}s "
- end
- else
- @formats[index]
- end
-
- cell = "".dup
- cell << "|" + " " * @padding if options[:borders]
- cell << f % column.to_s
- cell << " " * @padding if options[:borders]
- cell
- end
-
- def print_border_separator
- separator = @maximas.map do |maxima|
- "+" + "-" * (maxima + 2 * @padding)
- end
- stdout.puts indentation + separator.join + "+"
- end
-
- def truncate(string)
- return string unless @truncate
- as_unicode do
- chars = string.chars.to_a
- if chars.length <= @truncate
- chars.join
- else
- chars[0, @truncate - 3 - @indent].join + "..."
- end
- end
- end
-
- def indentation
- " " * @indent
- end
-
- if "".respond_to?(:encode)
- def as_unicode
- yield
- end
- else
- def as_unicode
- old = $KCODE # rubocop:disable Style/GlobalVars
- $KCODE = "U" # rubocop:disable Style/GlobalVars
- yield
- ensure
- $KCODE = old # rubocop:disable Style/GlobalVars
- end
- end
- end
- end
-end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb b/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb
deleted file mode 100644
index 2c60684308..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-class Bundler::Thor
- module Shell
- module Terminal
- DEFAULT_TERMINAL_WIDTH = 80
-
- class << self
- # This code was copied from Rake, available under MIT-LICENSE
- # Copyright (c) 2003, 2004 Jim Weirich
- def terminal_width
- result = if ENV["THOR_COLUMNS"]
- ENV["THOR_COLUMNS"].to_i
- else
- unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
- end
- result < 10 ? DEFAULT_TERMINAL_WIDTH : result
- rescue
- DEFAULT_TERMINAL_WIDTH
- end
-
- def unix?
- RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
- end
-
- private
-
- # Calculate the dynamic width of the terminal
- def dynamic_width
- @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
- end
-
- def dynamic_width_stty
- `stty size 2>/dev/null`.split[1].to_i
- end
-
- def dynamic_width_tput
- `tput cols 2>/dev/null`.to_i
- end
-
- end
- end
- end
-end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb b/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb
deleted file mode 100644
index ba88e952db..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative "column_printer"
-require_relative "terminal"
-
-class Bundler::Thor
- module Shell
- class WrappedPrinter < ColumnPrinter
- def print(message)
- width = Terminal.terminal_width - @indent
- paras = message.split("\n\n")
-
- paras.map! do |unwrapped|
- words = unwrapped.split(" ")
- counter = words.first.length
- words.inject do |memo, word|
- word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
- counter = 0 if word.include? "\n"
- if (counter + word.length + 1) < width
- memo = "#{memo} #{word}"
- counter += (word.length + 1)
- else
- memo = "#{memo}\n#{word}"
- counter = word.length
- end
- memo
- end
- end.compact!
-
- paras.each do |para|
- para.split("\n").each do |line|
- stdout.puts line.insert(0, " " * @indent)
- end
- stdout.puts unless para == paras.last
- end
- end
- end
- end
-end
-
diff --git a/lib/bundler/vendor/thor/lib/thor/util.rb b/lib/bundler/vendor/thor/lib/thor/util.rb
index 68916daf2e..d2572a4249 100644
--- a/lib/bundler/vendor/thor/lib/thor/util.rb
+++ b/lib/bundler/vendor/thor/lib/thor/util.rb
@@ -90,7 +90,7 @@ class Bundler::Thor
def snake_case(str)
return str.downcase if str =~ /^[A-Z_]+$/
str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/
- Regexp.last_match(-1).downcase
+ $+.downcase
end
# Receives a string and convert it to camel case. camel_case returns CamelCase.
@@ -130,10 +130,9 @@ class Bundler::Thor
#
def find_class_and_command_by_namespace(namespace, fallback = true)
if namespace.include?(":") # look for a namespaced command
- *pieces, command = namespace.split(":")
- namespace = pieces.join(":")
- namespace = "default" if namespace.empty?
- klass = Bundler::Thor::Base.subclasses.detect { |thor| thor.namespace == namespace && thor.commands.keys.include?(command) }
+ pieces = namespace.split(":")
+ command = pieces.pop
+ klass = Bundler::Thor::Util.find_by_namespace(pieces.join(":"))
end
unless klass # look for a Bundler::Thor::Group with the right name
klass = Bundler::Thor::Util.find_by_namespace(namespace)
@@ -151,7 +150,7 @@ class Bundler::Thor
# inside the sandbox to avoid namespacing conflicts.
#
def load_thorfile(path, content = nil, debug = false)
- content ||= File.read(path)
+ content ||= File.binread(path)
begin
Bundler::Thor::Sandbox.class_eval(content, path)
@@ -190,7 +189,7 @@ class Bundler::Thor
# Returns the root where thor files are located, depending on the OS.
#
def thor_root
- File.join(user_home, ".thor").tr("\\", "/")
+ File.join(user_home, ".thor").tr('\\', "/")
end
# Returns the files in the thor root. On Windows thor_root will be something
@@ -237,7 +236,7 @@ class Bundler::Thor
# symlink points to 'ruby_install_name'
ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
end
- rescue NotImplementedError # rubocop:disable Lint/HandleExceptions
+ rescue NotImplementedError # rubocop:disable HandleExceptions
# just ignore on windows
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/version.rb b/lib/bundler/vendor/thor/lib/thor/version.rb
index 1fb00017ed..48a4788b3b 100644
--- a/lib/bundler/vendor/thor/lib/thor/version.rb
+++ b/lib/bundler/vendor/thor/lib/thor/version.rb
@@ -1,3 +1,3 @@
class Bundler::Thor
- VERSION = "1.3.0"
+ VERSION = "1.2.1"
end
diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb
index 7c03d8687f..8ef7be935b 100644
--- a/lib/bundler/version.rb
+++ b/lib/bundler/version.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
module Bundler
- VERSION = "2.5.0.dev".freeze
+ VERSION = "2.4.19".freeze
def self.bundler_major_version
@bundler_major_version ||= VERSION.split(".").first.to_i
diff --git a/lib/bundler/yaml_serializer.rb b/lib/bundler/yaml_serializer.rb
index aebbea7de2..d5ecbd4aef 100644
--- a/lib/bundler/yaml_serializer.rb
+++ b/lib/bundler/yaml_serializer.rb
@@ -17,11 +17,7 @@ module Bundler
if v.is_a?(Hash)
yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines
elsif v.is_a?(Array) # Expected to be array of strings
- if v.empty?
- yaml << " []\n"
- else
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
- end
+ yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
else
yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
end
@@ -58,8 +54,8 @@ module Bundler
str.split(/\r?\n/).each do |line|
if match = HASH_REGEX.match(line)
indent, key, quote, val = match.captures
- convert_to_backward_compatible_key!(key)
- depth = indent.size / 2
+ key = convert_to_backward_compatible_key(key)
+ depth = indent.scan(/ /).length
if quote.empty? && val.empty?
new_hash = {}
stack[depth][key] = new_hash
@@ -67,7 +63,6 @@ module Bundler
last_empty_key = key
last_hash = stack[depth]
else
- val = [] if val == "[]" # empty array
stack[depth][key] = val
end
elsif match = ARRAY_REGEX.match(line)
@@ -81,13 +76,14 @@ module Bundler
end
# for settings' keys
- def convert_to_backward_compatible_key!(key)
- key << "/" if /https?:/i.match?(key) && !%r{/\Z}.match?(key)
- key.gsub!(".", "__")
+ def convert_to_backward_compatible_key(key)
+ key = "#{key}/" if key =~ /https?:/i && key !~ %r{/\Z}
+ key = key.gsub(".", "__") if key.include?(".")
+ key
end
class << self
- private :dump_hash, :convert_to_backward_compatible_key!
+ private :dump_hash, :convert_to_backward_compatible_key
end
end
end
diff --git a/lib/cgi.rb b/lib/cgi.rb
index faa00d0cae..7dc3a64941 100644
--- a/lib/cgi.rb
+++ b/lib/cgi.rb
@@ -288,7 +288,7 @@
#
class CGI
- VERSION = "0.4.0"
+ VERSION = "0.3.7"
end
require 'cgi/core'
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
index 9498e2f9fa..1c4ef6a600 100644
--- a/lib/cgi/cookie.rb
+++ b/lib/cgi/cookie.rb
@@ -190,9 +190,10 @@ class CGI
values ||= ""
values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) }
if cookies.has_key?(name)
- values = cookies[name].value + values
+ cookies[name].concat(values)
+ else
+ cookies[name] = Cookie.new(name, *values)
end
- cookies[name] = Cookie.new(name, *values)
end
cookies
diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb
index aab60869bb..70c7ebca42 100644
--- a/lib/cgi/session.rb
+++ b/lib/cgi/session.rb
@@ -279,7 +279,7 @@ class CGI
# fields are surrounded by a <fieldset> tag in HTML 4 generation, which
# is _not_ invisible on many browsers; you may wish to disable the
# use of fieldsets with code similar to the following
- # (see https://blade.ruby-lang.org/ruby-list/37805)
+ # (see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/37805)
#
# cgi = CGI.new("html4")
# class << cgi
diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb
index 4986e544e0..ce77a0ccd5 100644
--- a/lib/cgi/util.rb
+++ b/lib/cgi/util.rb
@@ -36,7 +36,7 @@ module CGI::Util
# URL-encode a string following RFC 3986
# Space characters (+" "+) are encoded with (+"%20"+)
- # url_encoded_string = CGI.escapeURIComponent("'Stop!' said Fred")
+ # url_encoded_string = CGI.escape("'Stop!' said Fred")
# # => "%27Stop%21%27%20said%20Fred"
def escapeURIComponent(string)
encoding = string.encoding
@@ -46,10 +46,9 @@ module CGI::Util
end
buffer.force_encoding(encoding)
end
- alias escape_uri_component escapeURIComponent
# URL-decode a string following RFC 3986 with encoding(optional).
- # string = CGI.unescapeURIComponent("%27Stop%21%27+said%20Fred")
+ # string = CGI.unescape("%27Stop%21%27+said%20Fred")
# # => "'Stop!'+said Fred"
def unescapeURIComponent(string, encoding = @@accept_charset)
str = string.b
@@ -60,8 +59,6 @@ module CGI::Util
str.valid_encoding? ? str : str.force_encoding(string.encoding)
end
- alias unescape_uri_component unescapeURIComponent
-
# The set of special characters and their escaped values
TABLE_FOR_ESCAPE_HTML__ = {
"'" => '&#39;',
@@ -93,12 +90,9 @@ module CGI::Util
end
end
- # TruffleRuby runs the pure-Ruby variant faster, do not use the C extension there
- unless RUBY_ENGINE == 'truffleruby'
- begin
- require 'cgi/escape'
- rescue LoadError
- end
+ begin
+ require 'cgi/escape'
+ rescue LoadError
end
# Unescape a string that has been HTML-escaped
@@ -184,7 +178,7 @@ module CGI::Util
def escapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
- string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do
+ string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do
CGI.escapeHTML($&)
end
else
@@ -204,7 +198,7 @@ module CGI::Util
def unescapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
- string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) do
+ string.gsub(/&lt;\/?(?:#{elements.join("|")})\b(?>[^&]+|&(?![gl]t;)\w+;)*(?:&gt;)?/im) do
unescapeHTML($&)
end
else
diff --git a/lib/csv.rb b/lib/csv.rb
index e8aa20ddd2..0307033941 100644
--- a/lib/csv.rb
+++ b/lib/csv.rb
@@ -70,7 +70,7 @@
# == What is CSV, really?
#
# CSV maintains a pretty strict definition of CSV taken directly from
-# {the RFC}[https://www.ietf.org/rfc/rfc4180.txt]. I relax the rules in only one
+# {the RFC}[http://www.ietf.org/rfc/rfc4180.txt]. I relax the rules in only one
# place and that is to make using this library easier. CSV will parse all valid
# CSV.
#
@@ -102,6 +102,14 @@ require_relative "csv/writer"
# == \CSV
#
+# === In a Hurry?
+#
+# If you are familiar with \CSV data and have a particular task in mind,
+# you may want to go directly to the:
+# - {Recipes for CSV}[doc/csv/recipes/recipes_rdoc.html].
+#
+# Otherwise, read on here, about the API: classes, methods, and constants.
+#
# === \CSV Data
#
# \CSV (comma-separated values) data is a text representation of a table:
@@ -846,15 +854,6 @@ class CSV
end
end
- # The error thrown when the parser encounters invalid encoding in CSV.
- class InvalidEncodingError < MalformedCSVError
- attr_reader :encoding
- def initialize(encoding, line_number)
- @encoding = encoding
- super("Invalid byte sequence in #{encoding}", line_number)
- end
- end
-
#
# A FieldInfo Struct contains details about a field's position in the data
# source it was read from. CSV will pass this Struct to some blocks that make
@@ -1315,8 +1314,8 @@ class CSV
#
# Arguments:
# * Argument +path_or_io+ must be a file path or an \IO stream.
- # * Argument +mode+, if given, must be a \File mode.
- # See {Access Modes}[rdoc-ref:File@Access+Modes].
+ # * Argument +mode+, if given, must be a \File mode
+ # See {Open Mode}[https://ruby-doc.org/core/IO.html#method-c-new-label-Open+Mode].
# * Arguments <tt>**options</tt> must be keyword options.
# See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
# * This method optionally accepts an additional <tt>:encoding</tt> option
@@ -1522,8 +1521,8 @@ class CSV
#
# * Argument +path+, if given, must be the path to a file.
# :include: ../doc/csv/arguments/io.rdoc
- # * Argument +mode+, if given, must be a \File mode.
- # See {Access Modes}[rdoc-ref:File@Access+Modes].
+ # * Argument +mode+, if given, must be a \File mode
+ # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
# * Arguments <tt>**options</tt> must be keyword options.
# See {Options for Generating}[#class-CSV-label-Options+for+Generating].
# * This method optionally accepts an additional <tt>:encoding</tt> option
diff --git a/lib/csv/delete_suffix.rb b/lib/csv/delete_suffix.rb
new file mode 100644
index 0000000000..d457718997
--- /dev/null
+++ b/lib/csv/delete_suffix.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# This provides String#delete_suffix? for Ruby 2.4.
+unless String.method_defined?(:delete_suffix)
+ class CSV
+ module DeleteSuffix
+ refine String do
+ def delete_suffix(suffix)
+ if end_with?(suffix)
+ self[0...-suffix.size]
+ else
+ self
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/csv/match_p.rb b/lib/csv/match_p.rb
new file mode 100644
index 0000000000..775559a3eb
--- /dev/null
+++ b/lib/csv/match_p.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# This provides String#match? and Regexp#match? for Ruby 2.3.
+unless String.method_defined?(:match?)
+ class CSV
+ module MatchP
+ refine String do
+ def match?(pattern)
+ self =~ pattern
+ end
+ end
+
+ refine Regexp do
+ def match?(string)
+ self =~ string
+ end
+ end
+ end
+ end
+end
diff --git a/lib/csv/parser.rb b/lib/csv/parser.rb
index 4da87fbac8..afb3131cd5 100644
--- a/lib/csv/parser.rb
+++ b/lib/csv/parser.rb
@@ -101,7 +101,7 @@ class CSV
position = @scanner.pos
offset = 0
n_row_separator_chars = row_separator.size
- # trace(__method__, :start, input)
+ # trace(__method__, :start, line, input)
while true
input.each_line(row_separator) do |line|
@scanner.pos += line.bytesize
@@ -157,7 +157,6 @@ class CSV
# trace(__method__, pattern, :done, :last, value) if @last_scanner
return value if @last_scanner
- # trace(__method__, pattern, :done, :nil) if value.nil?
return nil if value.nil?
while @scanner.eos? and read_chunk and (sub_value = @scanner.scan(pattern))
# trace(__method__, pattern, :sub, sub_value)
@@ -201,8 +200,7 @@ class CSV
# trace(__method__, :rescan, start, buffer)
string = @scanner.string
if scanner == @scanner
- keep = string.byteslice(start,
- string.bytesize - @scanner.pos - start)
+ keep = string.byteslice(start, string.bytesize - start)
else
keep = string
end
@@ -414,7 +412,8 @@ class CSV
else
lineno = @lineno + 1
end
- raise InvalidEncodingError.new(@encoding, lineno)
+ message = "Invalid byte sequence in #{@encoding}"
+ raise MalformedCSVError.new(message, lineno)
rescue UnexpectedError => error
if @scanner
ignore_broken_line
@@ -486,6 +485,7 @@ class CSV
message = ":quote_char has to be nil or a single character String"
raise ArgumentError, message
end
+ @double_quote_character = @quote_character * 2
@escaped_quote_character = Regexp.escape(@quote_character)
@escaped_quote = Regexp.new(@escaped_quote_character)
end
@@ -875,7 +875,8 @@ class CSV
!line.valid_encoding?
end
if index
- raise InvalidEncodingError.new(@encoding, @lineno + index + 1)
+ message = "Invalid byte sequence in #{@encoding}"
+ raise MalformedCSVError.new(message, @lineno + index + 1)
end
end
Scanner.new(string)
diff --git a/lib/csv/version.rb b/lib/csv/version.rb
index 9c65803a34..e05d63d801 100644
--- a/lib/csv/version.rb
+++ b/lib/csv/version.rb
@@ -2,5 +2,5 @@
class CSV
# The version of the installed library.
- VERSION = "3.2.8"
+ VERSION = "3.2.6"
end
diff --git a/lib/delegate.gemspec b/lib/delegate.gemspec
deleted file mode 100644
index 6c3feac74b..0000000000
--- a/lib/delegate.gemspec
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Provides three abilities to delegate method calls to an object.}
- spec.description = %q{Provides three abilities to delegate method calls to an object.}
- spec.homepage = "https://github.com/ruby/delegate"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.require_paths = ["lib"]
- spec.required_ruby_version = '>= 2.7'
-end
diff --git a/lib/delegate.rb b/lib/delegate.rb
index 4d8994d8a0..387a5f063d 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -39,7 +39,7 @@
# Be advised, RDoc will not detect delegated methods.
#
class Delegator < BasicObject
- VERSION = "0.3.1"
+ VERSION = "0.3.0"
kernel = ::Kernel.dup
kernel.class_eval do
diff --git a/lib/delegate/delegate.gemspec b/lib/delegate/delegate.gemspec
new file mode 100644
index 0000000000..1cfacfeb2f
--- /dev/null
+++ b/lib/delegate/delegate.gemspec
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Provides three abilities to delegate method calls to an object.}
+ spec.description = %q{Provides three abilities to delegate method calls to an object.}
+ spec.homepage = "https://github.com/ruby/delegate"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.require_paths = ["lib"]
+ spec.required_ruby_version = '>= 2.7'
+end
diff --git a/lib/did_you_mean.rb b/lib/did_you_mean.rb
index e177665099..2df238da06 100644
--- a/lib/did_you_mean.rb
+++ b/lib/did_you_mean.rb
@@ -113,7 +113,7 @@ module DidYouMean
correct_error LoadError, RequirePathChecker if RUBY_VERSION >= '2.8.0'
correct_error NoMatchingPatternKeyError, PatternKeyNameChecker if defined?(::NoMatchingPatternKeyError)
- # TODO: Remove on the 3.4 development start:
+ # TODO: Remove on 3.3:
class DeprecatedMapping # :nodoc:
def []=(key, value)
warn "Calling `DidYouMean::SPELL_CHECKERS[#{key.to_s}] = #{value.to_s}' has been deprecated. " \
@@ -132,7 +132,7 @@ module DidYouMean
end
end
- # TODO: Remove on the 3.4 development start:
+ # TODO: Remove on 3.3:
SPELL_CHECKERS = DeprecatedMapping.new
deprecate_constant :SPELL_CHECKERS
private_constant :DeprecatedMapping
diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb
index 5a85e42975..23181bb834 100644
--- a/lib/drb/drb.rb
+++ b/lib/drb/drb.rb
@@ -2,7 +2,7 @@
#
# = drb/drb.rb
#
-# Distributed Ruby: _dRuby_
+# Distributed Ruby: _dRuby_ version 2.0.4
#
# Copyright (c) 1999-2003 Masatoshi SEKI. You can redistribute it and/or
# modify it under the same terms as Ruby.
@@ -50,7 +50,6 @@ require 'socket'
require 'io/wait'
require 'monitor'
require_relative 'eq'
-require_relative 'version'
#
# == Overview
diff --git a/lib/drb/ssl.rb b/lib/drb/ssl.rb
index 392d6560e9..54ab1ef395 100644
--- a/lib/drb/ssl.rb
+++ b/lib/drb/ssl.rb
@@ -73,14 +73,6 @@ module DRb
# :SSLTmpDhCallback ::
# A DH callback. See OpenSSL::SSL::SSLContext.tmp_dh_callback
#
- # :SSLMinVersion ::
- # This is the minimum SSL version to allow. See
- # OpenSSL::SSL::SSLContext#min_version=.
- #
- # :SSLMaxVersion ::
- # This is the maximum SSL version to allow. See
- # OpenSSL::SSL::SSLContext#max_version=.
- #
# :SSLVerifyMode ::
# This is the SSL verification mode. See OpenSSL::SSL::VERIFY_* for
# available modes. The default is OpenSSL::SSL::VERIFY_NONE
@@ -216,8 +208,6 @@ module DRb
ctx = ::OpenSSL::SSL::SSLContext.new
ctx.cert = @cert
ctx.key = @pkey
- ctx.min_version = self[:SSLMinVersion]
- ctx.max_version = self[:SSLMaxVersion]
ctx.client_ca = self[:SSLClientCA]
ctx.ca_path = self[:SSLCACertificatePath]
ctx.ca_file = self[:SSLCACertificateFile]
diff --git a/lib/drb/version.rb b/lib/drb/version.rb
index 73fa4c18fd..10d33445b6 100644
--- a/lib/drb/version.rb
+++ b/lib/drb/version.rb
@@ -1,3 +1,3 @@
module DRb
- VERSION = "2.2.0"
+ VERSION = "2.1.1"
end
diff --git a/lib/erb.gemspec b/lib/erb.gemspec
index 94a8fd5c3e..d973cc10de 100644
--- a/lib/erb.gemspec
+++ b/lib/erb.gemspec
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
spec.name = 'erb'
spec.version = ERB.const_get(:VERSION, false)
spec.authors = ['Masatoshi SEKI', 'Takashi Kokubun']
- spec.email = ['seki@ruby-lang.org', 'k0kubun@ruby-lang.org']
+ spec.email = ['seki@ruby-lang.org', 'takashikkbn@gmail.com']
spec.summary = %q{An easy to use but powerful templating system for Ruby.}
spec.description = %q{An easy to use but powerful templating system for Ruby.}
diff --git a/lib/erb.rb b/lib/erb.rb
index bc1615d7da..754419f819 100644
--- a/lib/erb.rb
+++ b/lib/erb.rb
@@ -307,11 +307,11 @@ class ERB
# def build
# b = binding
# # create and run templates, filling member data variables
- # ERB.new(<<~'END_PRODUCT', trim_mode: "", eoutvar: "@product").result b
+ # ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@product").result b
# <%= PRODUCT[:name] %>
# <%= PRODUCT[:desc] %>
# END_PRODUCT
- # ERB.new(<<~'END_PRICE', trim_mode: "", eoutvar: "@price").result b
+ # ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@price").result b
# <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
# <%= PRODUCT[:desc] %>
# END_PRICE
diff --git a/lib/erb/compiler.rb b/lib/erb/compiler.rb
index 7096c8dcea..547d2c4c44 100644
--- a/lib/erb/compiler.rb
+++ b/lib/erb/compiler.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: true
#--
# ERB::Compiler
#
diff --git a/lib/erb/def_method.rb b/lib/erb/def_method.rb
index aee989a926..17f9c0f9fa 100644
--- a/lib/erb/def_method.rb
+++ b/lib/erb/def_method.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: true
#--
# ERB::DefMethod
#
diff --git a/lib/erb/util.rb b/lib/erb/util.rb
index 1d2a36275d..0c1e7482a8 100644
--- a/lib/erb/util.rb
+++ b/lib/erb/util.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: true
#--
# ERB::Escape
#
diff --git a/lib/erb/version.rb b/lib/erb/version.rb
index 295fc5fa6f..38e1b76ff4 100644
--- a/lib/erb/version.rb
+++ b/lib/erb/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
class ERB
- VERSION = '4.0.3'
+ VERSION = '4.0.2'
private_constant :VERSION
end
diff --git a/lib/error_highlight/base.rb b/lib/error_highlight/base.rb
index 7d2ff0c889..062871ee16 100644
--- a/lib/error_highlight/base.rb
+++ b/lib/error_highlight/base.rb
@@ -98,40 +98,9 @@ module ErrorHighlight
end
end
- OPT_GETCONSTANT_PATH = (RUBY_VERSION.split(".").map {|s| s.to_i } <=> [3, 2]) >= 0
- private_constant :OPT_GETCONSTANT_PATH
-
def spot
return nil unless @node
- if OPT_GETCONSTANT_PATH && @node.type == :COLON2
- # In Ruby 3.2 or later, a nested constant access (like `Foo::Bar::Baz`)
- # is compiled to one instruction (opt_getconstant_path).
- # @node points to the node of the whole `Foo::Bar::Baz` even if `Foo`
- # or `Foo::Bar` causes NameError.
- # So we try to spot the sub-node that causes the NameError by using
- # `NameError#name`.
- subnodes = []
- node = @node
- while node.type == :COLON2
- node2, const = node.children
- subnodes << node if const == @name
- node = node2
- end
- if node.type == :CONST || node.type == :COLON3
- if node.children.first == @name
- subnodes << node
- end
-
- # If we found only one sub-node whose name is equal to @name, use it
- return nil if subnodes.size != 1
- @node = subnodes.first
- else
- # Do nothing; opt_getconstant_path is used only when the const base is
- # NODE_CONST (`Foo`) or NODE_COLON3 (`::Foo`)
- end
- end
-
case @node.type
when :CALL, :QCALL
diff --git a/lib/fileutils.rb b/lib/fileutils.rb
index 8ec5a3ad12..b495078f93 100644
--- a/lib/fileutils.rb
+++ b/lib/fileutils.rb
@@ -3,7 +3,7 @@
begin
require 'rbconfig'
rescue LoadError
- # for make rjit-headers
+ # for make mjit-headers
end
# Namespace for file utility methods for copying, moving, removing, etc.
@@ -180,7 +180,7 @@ end
# - {CVE-2004-0452}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452].
#
module FileUtils
- VERSION = "1.7.2"
+ VERSION = "1.7.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -192,6 +192,8 @@ module FileUtils
#
# FileUtils.pwd # => "/rdoc/fileutils"
#
+ # FileUtils.getwd is an alias for FileUtils.pwd.
+ #
# Related: FileUtils.cd.
#
def pwd
@@ -233,6 +235,8 @@ module FileUtils
# cd ..
# cd fileutils
#
+ # FileUtils.chdir is an alias for FileUtils.cd.
+ #
# Related: FileUtils.pwd.
#
def cd(dir, verbose: nil, &block) # :yield: dir
@@ -511,6 +515,8 @@ module FileUtils
# Raises an exception if +dest+ is the path to an existing file
# and keyword argument +force+ is not +true+.
#
+ # FileUtils#link is an alias for FileUtils#ln.
+ #
# Related: FileUtils.link_entry (has different options).
#
def ln(src, dest, force: nil, noop: nil, verbose: nil)
@@ -701,6 +707,8 @@ module FileUtils
# ln -sf src2.txt dest2.txt
# ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3
#
+ # FileUtils.symlink is an alias for FileUtils.ln_s.
+ #
# Related: FileUtils.ln_sf.
#
def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
@@ -868,6 +876,8 @@ module FileUtils
#
# Raises an exception if +src+ is a directory.
#
+ # FileUtils.copy is an alias for FileUtils.cp.
+ #
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
@@ -1154,6 +1164,8 @@ module FileUtils
# mv src0 dest0
# mv src1.txt src1 dest1
#
+ # FileUtils.move is an alias for FileUtils.mv.
+ #
def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
return if noop
@@ -1211,6 +1223,8 @@ module FileUtils
#
# rm src0.dat src0.txt
#
+ # FileUtils.remove is an alias for FileUtils.rm.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm(list, force: nil, noop: nil, verbose: nil)
@@ -1236,6 +1250,8 @@ module FileUtils
#
# See FileUtils.rm for keyword arguments.
#
+ # FileUtils.safe_unlink is an alias for FileUtils.rm_f.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_f(list, noop: nil, verbose: nil)
@@ -1323,6 +1339,8 @@ module FileUtils
#
# See FileUtils.rm_r for keyword arguments.
#
+ # FileUtils.rmtree is an alias for FileUtils.rm_rf.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
@@ -1624,13 +1642,7 @@ module FileUtils
st = File.stat(s)
unless File.exist?(d) and compare_file(s, d)
remove_file d, true
- if d.end_with?('/')
- mkdir_p d
- copy_file s, d + File.basename(s)
- else
- mkdir_p File.expand_path('..', d)
- copy_file s, d
- end
+ copy_file s, d
File.utime st.atime, st.mtime, d if preserve
File.chmod fu_mode(mode, st), d if mode
File.chown uid, gid, d if uid or gid
diff --git a/lib/find.gemspec b/lib/find.gemspec
index cb845e9409..3f0aadcdae 100644
--- a/lib/find.gemspec
+++ b/lib/find.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "find"
+ spec.version = "0.1.1"
spec.authors = ['Kazuki Tsujimoto']
spec.email = ['kazuki@callcc.net']
diff --git a/lib/find.rb b/lib/find.rb
index 98a79cc76d..9bee99c66d 100644
--- a/lib/find.rb
+++ b/lib/find.rb
@@ -27,8 +27,6 @@
#
module Find
- VERSION = "0.2.0"
-
#
# Calls the associated block with the name of every file and directory listed
# as arguments, then recursively on their subdirectories, and so on.
diff --git a/lib/getoptlong.gemspec b/lib/getoptlong.gemspec
deleted file mode 100644
index c2f65dcaab..0000000000
--- a/lib/getoptlong.gemspec
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{GetoptLong for Ruby}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/getoptlong"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.require_paths = ["lib"]
-end
diff --git a/lib/getoptlong.rb b/lib/getoptlong.rb
index c825962160..5ae0e1497c 100644
--- a/lib/getoptlong.rb
+++ b/lib/getoptlong.rb
@@ -352,7 +352,7 @@
#
# Command line:
#
-# $ ruby fibonacci.rb --number 6 --verbose yes
+# $ ruby fibonacci.rb --number 6 --verbose yes
#
# Output:
#
@@ -368,7 +368,7 @@
#
class GetoptLong
# Version.
- VERSION = "0.2.1"
+ VERSION = "0.2.0"
#
# Orderings.
diff --git a/lib/getoptlong/getoptlong.gemspec b/lib/getoptlong/getoptlong.gemspec
new file mode 100644
index 0000000000..dfe087b886
--- /dev/null
+++ b/lib/getoptlong/getoptlong.gemspec
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{GetoptLong for Ruby}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/getoptlong"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb
index 75922baa90..7a5cf94830 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -176,7 +176,9 @@ class IPAddr
def include?(other)
other = coerce_other(other)
return false unless other.family == family
- begin_addr <= other.begin_addr && end_addr >= other.end_addr
+ range = to_range
+ other = other.to_range
+ range.begin <= other.begin && range.end >= other.end
end
alias === include?
@@ -261,8 +263,7 @@ class IPAddr
# Returns true if the ipaddr is a private address. IPv4 addresses
# in 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 as defined in RFC
# 1918 and IPv6 Unique Local Addresses in fc00::/7 as defined in RFC
- # 4193 are considered private. Private IPv4 addresses in the
- # IPv4-mapped IPv6 address range are also considered private.
+ # 4193 are considered private.
def private?
case @family
when Socket::AF_INET
@@ -270,12 +271,7 @@ class IPAddr
@addr & 0xfff00000 == 0xac100000 || # 172.16.0.0/12
@addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16
when Socket::AF_INET6
- @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000 ||
- (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
- @addr & 0xff000000 == 0x0a000000 || # ::ffff:10.0.0.0/8
- @addr & 0xfff00000 == 0xac100000 || # ::ffff::172.16.0.0/12
- @addr & 0xffff0000 == 0xc0a80000 # ::ffff::192.168.0.0/16
- ))
+ @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000
else
raise AddressFamilyError, "unsupported address family"
end
@@ -404,6 +400,17 @@ class IPAddr
# Creates a Range object for the network address.
def to_range
+ begin_addr = (@addr & @mask_addr)
+
+ case @family
+ when Socket::AF_INET
+ end_addr = (@addr | (IN4MASK ^ @mask_addr))
+ when Socket::AF_INET6
+ end_addr = (@addr | (IN6MASK ^ @mask_addr))
+ else
+ raise AddressFamilyError, "unsupported address family"
+ end
+
self.class.new(begin_addr, @family)..self.class.new(end_addr, @family)
end
@@ -484,21 +491,6 @@ class IPAddr
protected
- def begin_addr
- @addr & @mask_addr
- end
-
- def end_addr
- case @family
- when Socket::AF_INET
- @addr | (IN4MASK ^ @mask_addr)
- when Socket::AF_INET6
- @addr | (IN6MASK ^ @mask_addr)
- else
- raise AddressFamilyError, "unsupported address family"
- end
- end
-
# Set +@addr+, the internal stored ip address, to given +addr+. The
# parameter +addr+ is validated using the first +family+ member,
# which is +Socket::AF_INET+ or +Socket::AF_INET6+.
diff --git a/lib/irb.rb b/lib/irb.rb
index 655abaf069..2db99bcd43 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -1,9 +1,14 @@
# frozen_string_literal: false
#
# irb.rb - irb main module
+# $Release Version: 0.9.6 $
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
require "ripper"
require "reline"
@@ -12,14 +17,12 @@ require_relative "irb/context"
require_relative "irb/extend-command"
require_relative "irb/ruby-lex"
-require_relative "irb/statement"
require_relative "irb/input-method"
require_relative "irb/locale"
require_relative "irb/color"
require_relative "irb/version"
require_relative "irb/easter-egg"
-require_relative "irb/debug"
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
# expressions read from the standard input.
@@ -140,10 +143,6 @@ require_relative "irb/debug"
#
# IRB.conf[:USE_AUTOCOMPLETE] = false
#
-# To enable enhanced completion using type information, add the following to your +.irbrc+:
-#
-# IRB.conf[:COMPLETOR] = :type
-#
# === History
#
# By default, irb will store the last 1000 commands you used in
@@ -160,7 +159,7 @@ require_relative "irb/debug"
#
# IRB.conf[:EVAL_HISTORY] = <number>
#
-# See IRB::Context#eval_history= and EvalHistory class. The history of command
+# See IRB::Context#eval_history= and History class. The history of command
# results is not permanently saved in any file.
#
# == Customizing the IRB Prompt
@@ -200,9 +199,10 @@ require_relative "irb/debug"
# For instance, the default prompt mode is defined as follows:
#
# IRB.conf[:PROMPT_MODE][:DEFAULT] = {
-# :PROMPT_I => "%N(%m):%03n> ",
-# :PROMPT_S => "%N(%m):%03n%l ",
-# :PROMPT_C => "%N(%m):%03n* ",
+# :PROMPT_I => "%N(%m):%03n:%i> ",
+# :PROMPT_N => "%N(%m):%03n:%i> ",
+# :PROMPT_S => "%N(%m):%03n:%i%l ",
+# :PROMPT_C => "%N(%m):%03n:%i* ",
# :RETURN => "%s\n" # used to printf
# }
#
@@ -210,30 +210,35 @@ require_relative "irb/debug"
#
# # :NULL:
# # :PROMPT_I:
+# # :PROMPT_N:
# # :PROMPT_S:
# # :PROMPT_C:
# # :RETURN: |
# # %s
# # :DEFAULT:
-# # :PROMPT_I: ! '%N(%m):%03n> '
-# # :PROMPT_S: ! '%N(%m):%03n%l '
-# # :PROMPT_C: ! '%N(%m):%03n* '
+# # :PROMPT_I: ! '%N(%m):%03n:%i> '
+# # :PROMPT_N: ! '%N(%m):%03n:%i> '
+# # :PROMPT_S: ! '%N(%m):%03n:%i%l '
+# # :PROMPT_C: ! '%N(%m):%03n:%i* '
# # :RETURN: |
# # => %s
# # :CLASSIC:
# # :PROMPT_I: ! '%N(%m):%03n:%i> '
+# # :PROMPT_N: ! '%N(%m):%03n:%i> '
# # :PROMPT_S: ! '%N(%m):%03n:%i%l '
# # :PROMPT_C: ! '%N(%m):%03n:%i* '
# # :RETURN: |
# # %s
# # :SIMPLE:
# # :PROMPT_I: ! '>> '
+# # :PROMPT_N: ! '>> '
# # :PROMPT_S:
# # :PROMPT_C: ! '?> '
# # :RETURN: |
# # => %s
# # :INF_RUBY:
-# # :PROMPT_I: ! '%N(%m):%03n> '
+# # :PROMPT_I: ! '%N(%m):%03n:%i> '
+# # :PROMPT_N:
# # :PROMPT_S:
# # :PROMPT_C:
# # :RETURN: |
@@ -241,6 +246,7 @@ require_relative "irb/debug"
# # :AUTO_INDENT: true
# # :XMP:
# # :PROMPT_I:
+# # :PROMPT_N:
# # :PROMPT_S:
# # :PROMPT_C:
# # :RETURN: |2
@@ -371,6 +377,26 @@ module IRB
# An exception raised by IRB.irb_abort
class Abort < Exception;end
+ @CONF = {}
+
+
+ # Displays current configuration.
+ #
+ # Modifying the configuration is achieved by sending a message to IRB.conf.
+ #
+ # See IRB@Configuration for more information.
+ def IRB.conf
+ @CONF
+ end
+
+ # Returns the current version of IRB, including release version and last
+ # updated date.
+ def IRB.version
+ if v = @CONF[:VERSION] then return v end
+
+ @CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
+ end
+
# The current IRB::Context of the session, see IRB.conf
#
# irb
@@ -395,6 +421,11 @@ module IRB
irb.run(@CONF)
end
+ # Calls each event hook of <code>IRB.conf[:AT_EXIT]</code> when the current session quits.
+ def IRB.irb_at_exit
+ @CONF[:AT_EXIT].each{|hook| hook.call}
+ end
+
# Quits irb
def IRB.irb_exit(irb, ret)
throw :IRB_EXIT, ret
@@ -408,32 +439,46 @@ module IRB
end
class Irb
+ ASSIGNMENT_NODE_TYPES = [
+ # Local, instance, global, class, constant, instance, and index assignment:
+ # "foo = bar",
+ # "@foo = bar",
+ # "$foo = bar",
+ # "@@foo = bar",
+ # "::Foo = bar",
+ # "a::Foo = bar",
+ # "Foo = bar"
+ # "foo.bar = 1"
+ # "foo[1] = bar"
+ :assign,
+
+ # Operation assignment:
+ # "foo += bar"
+ # "foo -= bar"
+ # "foo ||= bar"
+ # "foo &&= bar"
+ :opassign,
+
+ # Multiple assignment:
+ # "foo, bar = 1, 2
+ :massign,
+ ]
# Note: instance and index assignment expressions could also be written like:
# "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former
# be parsed as :assign and echo will be suppressed, but the latter is
# parsed as a :method_add_arg and the output won't be suppressed
- PROMPT_MAIN_TRUNCATE_LENGTH = 32
- PROMPT_MAIN_TRUNCATE_OMISSION = '...'.freeze
- CONTROL_CHARACTERS_PATTERN = "\x00-\x1F".freeze
-
- # Returns the current context of this irb session
- attr_reader :context
- # The lexer used by this irb session
- attr_accessor :scanner
-
# Creates a new irb session
def initialize(workspace = nil, input_method = nil)
@context = Context.new(self, workspace, input_method)
- @context.workspace.load_commands_to_main
+ @context.main.extend ExtendCommandBundle
@signal_status = :IN_IRB
@scanner = RubyLex.new
- @line_no = 1
end
- # A hook point for `debug` command's breakpoint after :IRB_EXIT as well as its clean-up
+ # A hook point for `debug` command's TracePoint after :IRB_EXIT as well as its clean-up
def debug_break
- # it means the debug integration has been activated
+ # it means the debug command is executed
if defined?(DEBUGGER__) && DEBUGGER__.respond_to?(:capture_frames_without_irb)
# after leaving this initial breakpoint, revert the capture_frames patch
DEBUGGER__.singleton_class.send(:alias_method, :capture_frames, :capture_frames_without_irb)
@@ -442,49 +487,10 @@ module IRB
end
end
- def debug_readline(binding)
- workspace = IRB::WorkSpace.new(binding)
- context.workspace = workspace
- context.workspace.load_commands_to_main
- @line_no += 1
-
- # When users run:
- # 1. Debugging commands, like `step 2`
- # 2. Any input that's not irb-command, like `foo = 123`
- #
- # Irb#eval_input will simply return the input, and we need to pass it to the debugger.
- input = if IRB.conf[:SAVE_HISTORY] && context.io.support_history_saving?
- # Previous IRB session's history has been saved when `Irb#run` is exited
- # We need to make sure the saved history is not saved again by reseting the counter
- context.io.reset_history_counter
-
- begin
- eval_input
- ensure
- context.io.save_history
- end
- else
- eval_input
- end
-
- if input&.include?("\n")
- @line_no += input.count("\n") - 1
- end
-
- input
- end
-
def run(conf = IRB.conf)
- in_nested_session = !!conf[:MAIN_CONTEXT]
conf[:IRB_RC].call(context) if conf[:IRB_RC]
conf[:MAIN_CONTEXT] = context
- save_history = !in_nested_session && conf[:SAVE_HISTORY] && context.io.support_history_saving?
-
- if save_history
- context.io.load_history
- end
-
prev_trap = trap("SIGINT") do
signal_handle
end
@@ -496,26 +502,93 @@ module IRB
ensure
trap("SIGINT", prev_trap)
conf[:AT_EXIT].each{|hook| hook.call}
- context.io.save_history if save_history
end
end
+ # Returns the current context of this irb session
+ attr_reader :context
+ # The lexer used by this irb session
+ attr_accessor :scanner
+
# Evaluates input for this session.
def eval_input
- configure_io
+ exc = nil
+
+ @scanner.set_prompt do
+ |ltype, indent, continue, line_no|
+ if ltype
+ f = @context.prompt_s
+ elsif continue
+ f = @context.prompt_c
+ elsif indent > 0
+ f = @context.prompt_n
+ else
+ f = @context.prompt_i
+ end
+ f = "" unless f
+ if @context.prompting?
+ @context.io.prompt = p = prompt(f, ltype, indent, line_no)
+ else
+ @context.io.prompt = p = ""
+ end
+ if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
+ unless ltype
+ prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
+ ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
+ indent * 2 - p.size
+ ind += 2 if continue
+ @context.io.prompt = p + " " * ind if ind > 0
+ end
+ end
+ @context.io.prompt
+ end
- each_top_level_statement do |statement, line_no|
- signal_status(:IN_EVAL) do
- begin
- # If the integration with debugger is activated, we return certain input if it should be dealt with by debugger
- if @context.with_debugger && statement.should_be_handled_by_debugger?
- return statement.code
+ @scanner.set_input(@context.io, context: @context) do
+ signal_status(:IN_INPUT) do
+ if l = @context.io.gets
+ print l if @context.verbose?
+ else
+ if @context.ignore_eof? and @context.io.readable_after_eof?
+ l = "\n"
+ if @context.verbose?
+ printf "Use \"exit\" to leave %s\n", @context.ap_name
+ end
+ else
+ print "\n" if @context.prompting?
end
+ end
+ l
+ end
+ end
- @context.evaluate(statement.evaluable_code, line_no)
+ @scanner.set_auto_indent(@context) if @context.auto_indent_mode
- if @context.echo? && !statement.suppresses_echo?
- if statement.is_assignment?
+ @scanner.each_top_level_statement(@context) do |line, line_no|
+ signal_status(:IN_EVAL) do
+ begin
+ line.untaint if RUBY_VERSION < '2.7'
+ if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
+ IRB.set_measure_callback
+ end
+ # Assignment expression check should be done before @context.evaluate to handle code like `a /2#/ if false; a = 1`
+ is_assignment = assignment_expression?(line)
+ if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
+ result = nil
+ last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) }
+ IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) { |chain, item|
+ _name, callback, arg = item
+ proc {
+ callback.(@context, line, line_no, arg, exception: exc) do
+ chain.call
+ end
+ }
+ }.call
+ @context.set_last_value(result)
+ else
+ @context.evaluate(line, line_no, exception: exc)
+ end
+ if @context.echo?
+ if is_assignment
if @context.echo_on_assignment?
output_value(@context.echo_on_assignment? == :truncate)
end
@@ -523,146 +596,17 @@ module IRB
output_value
end
end
+ rescue Interrupt => exc
rescue SystemExit, SignalException
raise
- rescue Interrupt, Exception => exc
- handle_exception(exc)
- @context.workspace.local_variable_set(:_, exc)
- end
- end
- end
- end
-
- def read_input(prompt)
- signal_status(:IN_INPUT) do
- @context.io.prompt = prompt
- if l = @context.io.gets
- print l if @context.verbose?
- else
- if @context.ignore_eof? and @context.io.readable_after_eof?
- l = "\n"
- if @context.verbose?
- printf "Use \"exit\" to leave %s\n", @context.ap_name
- end
+ rescue Exception => exc
else
- print "\n" if @context.prompting?
+ exc = nil
+ next
end
- end
- l
- end
- end
-
- def readmultiline
- prompt = generate_prompt([], false, 0)
-
- # multiline
- return read_input(prompt) if @context.io.respond_to?(:check_termination)
-
- # nomultiline
- code = ''
- line_offset = 0
- loop do
- line = read_input(prompt)
- unless line
- return code.empty? ? nil : code
- end
-
- code << line
-
- # Accept any single-line input for symbol aliases or commands that transform args
- return code if single_line_command?(code)
-
- tokens, opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
- return code if terminated
-
- line_offset += 1
- continue = @scanner.should_continue?(tokens)
- prompt = generate_prompt(opens, continue, line_offset)
- end
- end
-
- def each_top_level_statement
- loop do
- code = readmultiline
- break unless code
-
- if code != "\n"
- yield build_statement(code), @line_no
- end
- @line_no += code.count("\n")
- rescue RubyLex::TerminateLineInput
- end
- end
-
- def build_statement(code)
- code.force_encoding(@context.io.encoding)
- command_or_alias, arg = code.split(/\s/, 2)
- # Transform a non-identifier alias (@, $) or keywords (next, break)
- command_name = @context.command_aliases[command_or_alias.to_sym]
- command = command_name || command_or_alias
- command_class = ExtendCommandBundle.load_command(command)
-
- if command_class
- Statement::Command.new(code, command, arg, command_class)
- else
- is_assignment_expression = @scanner.assignment_expression?(code, local_variables: @context.local_variables)
- Statement::Expression.new(code, is_assignment_expression)
- end
- end
-
- def single_line_command?(code)
- command = code.split(/\s/, 2).first
- @context.symbol_alias?(command) || @context.transform_args?(command)
- end
-
- def configure_io
- if @context.io.respond_to?(:check_termination)
- @context.io.check_termination do |code|
- if Reline::IOGate.in_pasting?
- rest = @scanner.check_termination_in_prev_line(code, local_variables: @context.local_variables)
- if rest
- Reline.delete_text
- rest.bytes.reverse_each do |c|
- Reline.ungetc(c)
- end
- true
- else
- false
- end
- else
- # Accept any single-line input for symbol aliases or commands that transform args
- next true if single_line_command?(code)
-
- _tokens, _opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
- terminated
- end
- end
- end
- if @context.io.respond_to?(:dynamic_prompt)
- @context.io.dynamic_prompt do |lines|
- lines << '' if lines.empty?
- tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, local_variables: @context.local_variables)
- line_results = IRB::NestingParser.parse_by_line(tokens)
- tokens_until_line = []
- line_results.map.with_index do |(line_tokens, _prev_opens, next_opens, _min_depth), line_num_offset|
- line_tokens.each do |token, _s|
- # Avoid appending duplicated token. Tokens that include "\n" like multiline tstring_content can exist in multiple lines.
- tokens_until_line << token if token != tokens_until_line.last
- end
- continue = @scanner.should_continue?(tokens_until_line)
- generate_prompt(next_opens, continue, line_num_offset)
- end
- end
- end
-
- if @context.io.respond_to?(:auto_indent) and @context.auto_indent_mode
- @context.io.auto_indent do |lines, line_index, byte_pointer, is_newline|
- next nil if lines == [nil] # Workaround for exit IRB with CTRL+d
- next nil if !is_newline && lines[line_index]&.byteslice(0, byte_pointer)&.match?(/\A\s*\z/)
-
- code = lines[0..line_index].map { |l| "#{l}\n" }.join
- tokens = RubyLex.ripper_lex_without_warning(code, local_variables: @context.local_variables)
- @scanner.process_indent_level(tokens, lines, line_index, is_newline)
+ handle_exception(exc)
+ @context.workspace.local_variable_set(:_, exc)
+ exc = nil
end
end
end
@@ -791,6 +735,16 @@ module IRB
end
end
+ # Evaluates the given block using the given +context+ as the Context.
+ def suspend_context(context)
+ @context, back_context = context, @context
+ begin
+ yield back_context
+ ensure
+ @context = back_context
+ end
+ end
+
# Handler for the signal SIGINT, see Kernel#trap for more information.
def signal_handle
unless @context.ignore_sigint?
@@ -826,6 +780,45 @@ module IRB
end
end
+ def prompt(prompt, ltype, indent, line_no) # :nodoc:
+ p = prompt.dup
+ p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
+ case $2
+ when "N"
+ @context.irb_name
+ when "m"
+ @context.main.to_s
+ when "M"
+ @context.main.inspect
+ when "l"
+ ltype
+ when "i"
+ if indent < 0
+ if $1
+ "-".rjust($1.to_i)
+ else
+ "-"
+ end
+ else
+ if $1
+ format("%" + $1 + "d", indent)
+ else
+ indent.to_s
+ end
+ end
+ when "n"
+ if $1
+ format("%" + $1 + "d", line_no)
+ else
+ line_no.to_s
+ end
+ when "%"
+ "%"
+ end
+ end
+ p
+ end
+
def output_value(omit = false) # :nodoc:
str = @context.inspect_last_value
multiline_p = str.include?("\n")
@@ -879,83 +872,50 @@ module IRB
format("#<%s: %s>", self.class, ary.join(", "))
end
- private
-
- def generate_prompt(opens, continue, line_offset)
- ltype = @scanner.ltype_from_open_tokens(opens)
- indent = @scanner.calc_indent_level(opens)
- continue = opens.any? || continue
- line_no = @line_no + line_offset
-
- if ltype
- f = @context.prompt_s
- elsif continue
- f = @context.prompt_c
- else
- f = @context.prompt_i
- end
- f = "" unless f
- if @context.prompting?
- p = format_prompt(f, ltype, indent, line_no)
- else
- p = ""
- end
- if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
- unless ltype
- prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
- ind = format_prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
- indent * 2 - p.size
- p += " " * ind if ind > 0
- end
- end
- p
+ def assignment_expression?(line)
+ # Try to parse the line and check if the last of possibly multiple
+ # expressions is an assignment type.
+
+ # If the expression is invalid, Ripper.sexp should return nil which will
+ # result in false being returned. Any valid expression should return an
+ # s-expression where the second element of the top level array is an
+ # array of parsed expressions. The first element of each expression is the
+ # expression's type.
+ verbose, $VERBOSE = $VERBOSE, nil
+ code = "#{RubyLex.generate_local_variables_assign_code(@context.local_variables) || 'nil;'}\n#{line}"
+ # Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
+ node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
+ ASSIGNMENT_NODE_TYPES.include?(node_type)
+ ensure
+ $VERBOSE = verbose
end
- def truncate_prompt_main(str) # :nodoc:
- str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
- if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
- str
- else
- str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
- end
- end
+ ATTR_TTY = "\e[%sm"
+ def ATTR_TTY.[](*a) self % a.join(";"); end
+ ATTR_PLAIN = ""
+ def ATTR_PLAIN.[](*) self; end
+ end
- def format_prompt(format, ltype, indent, line_no) # :nodoc:
- format.gsub(/%([0-9]+)?([a-zA-Z])/) do
- case $2
- when "N"
- @context.irb_name
- when "m"
- truncate_prompt_main(@context.main.to_s)
- when "M"
- truncate_prompt_main(@context.main.inspect)
- when "l"
- ltype
- when "i"
- if indent < 0
- if $1
- "-".rjust($1.to_i)
- else
- "-"
- end
- else
- if $1
- format("%" + $1 + "d", indent)
- else
- indent.to_s
- end
- end
- when "n"
- if $1
- format("%" + $1 + "d", line_no)
- else
- line_no.to_s
- end
- when "%"
- "%"
- end
+ def @CONF.inspect
+ IRB.version unless self[:VERSION]
+
+ array = []
+ for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
+ case k
+ when :MAIN_CONTEXT, :__TMP__EHV__
+ array.push format("CONF[:%s]=...myself...", k.id2name)
+ when :PROMPT
+ s = v.collect{
+ |kk, vv|
+ ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
+ format(":%s=>{%s}", kk.id2name, ss.join(", "))
+ }
+ array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
+ else
+ array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
end
end
+ array.join("\n")
end
end
@@ -1016,34 +976,14 @@ class Binding
# Cooked potato: true
#
#
- # See IRB@Usage for more information.
+ # See IRB@IRB+Usage for more information.
def irb(show_code: true)
- # Setup IRB with the current file's path and no command line arguments
IRB.setup(source_location[0], argv: [])
- # Create a new workspace using the current binding
workspace = IRB::WorkSpace.new(self)
- # Print the code around the binding if show_code is true
STDOUT.print(workspace.code_around_binding) if show_code
- # Get the original IRB instance
- debugger_irb = IRB.instance_variable_get(:@debugger_irb)
-
- irb_path = File.expand_path(source_location[0])
-
- if debugger_irb
- # If we're already in a debugger session, set the workspace and irb_path for the original IRB instance
- debugger_irb.context.workspace = workspace
- debugger_irb.context.irb_path = irb_path
- # If we've started a debugger session and hit another binding.irb, we don't want to start an IRB session
- # instead, we want to resume the irb:rdbg session.
- IRB::Debug.setup(debugger_irb)
- IRB::Debug.insert_debug_break
- debugger_irb.debug_break
- else
- # If we're not in a debugger session, create a new IRB instance with the current workspace
- binding_irb = IRB::Irb.new(workspace)
- binding_irb.context.irb_path = irb_path
- binding_irb.run(IRB.conf)
- binding_irb.debug_break
- end
+ binding_irb = IRB::Irb.new(workspace)
+ binding_irb.context.irb_path = File.expand_path(source_location[0])
+ binding_irb.run(IRB.conf)
+ binding_irb.debug_break
end
end
diff --git a/lib/irb/cmd/chws.rb b/lib/irb/cmd/chws.rb
index 31045f9bbb..7c84ba0a4b 100644
--- a/lib/irb/cmd/chws.rb
+++ b/lib/irb/cmd/chws.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# change-ws.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require_relative "nop"
require_relative "../ext/change-ws"
@@ -13,7 +19,7 @@ module IRB
module ExtendCommand
class CurrentWorkingWorkspace < Nop
- category "Workspace"
+ category "IRB"
description "Show the current workspace."
def execute(*obj)
@@ -22,7 +28,7 @@ module IRB
end
class ChangeWorkspace < Nop
- category "Workspace"
+ category "IRB"
description "Change the current workspace to an object."
def execute(*obj)
diff --git a/lib/irb/cmd/debug.rb b/lib/irb/cmd/debug.rb
index 9eca964218..7d39b9fa27 100644
--- a/lib/irb/cmd/debug.rb
+++ b/lib/irb/cmd/debug.rb
@@ -1,5 +1,4 @@
require_relative "nop"
-require_relative "../debug"
module IRB
# :stopdoc:
@@ -13,46 +12,37 @@ module IRB
'<internal:prelude>',
binding.method(:irb).source_location.first,
].map { |file| /\A#{Regexp.escape(file)}:\d+:in `irb'\z/ }
+ IRB_DIR = File.expand_path('..', __dir__)
def execute(pre_cmds: nil, do_cmds: nil)
- if irb_context.with_debugger
- # If IRB is already running with a debug session, throw the command and IRB.debug_readline will pass it to the debugger.
- if cmd = pre_cmds || do_cmds
- throw :IRB_EXIT, cmd
- else
- puts "IRB is already running with a debug session."
- return
- end
- else
- # If IRB is not running with a debug session yet, then:
- # 1. Check if the debugging command is run from a `binding.irb` call.
- # 2. If so, try setting up the debug gem.
- # 3. Insert a debug breakpoint at `Irb#debug_break` with the intended command.
- # 4. Exit the current Irb#run call via `throw :IRB_EXIT`.
- # 5. `Irb#debug_break` will be called and trigger the breakpoint, which will run the intended command.
- unless binding_irb?
- puts "`debug` command is only available when IRB is started with binding.irb"
- return
- end
-
- if IRB.respond_to?(:JobManager)
- warn "Can't start the debugger when IRB is running in a multi-IRB session."
- return
- end
-
- unless IRB::Debug.setup(irb_context.irb)
- puts <<~MSG
- You need to install the debug gem before using this command.
- If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
- MSG
- return
- end
+ unless binding_irb?
+ puts "`debug` command is only available when IRB is started with binding.irb"
+ return
+ end
- IRB::Debug.insert_debug_break(pre_cmds: pre_cmds, do_cmds: do_cmds)
+ unless setup_debugger
+ puts <<~MSG
+ You need to install the debug gem before using this command.
+ If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
+ MSG
+ return
+ end
- # exit current Irb#run call
- throw :IRB_EXIT
+ options = { oneshot: true, hook_call: false }
+ if pre_cmds || do_cmds
+ options[:command] = ['irb', pre_cmds, do_cmds]
end
+ if DEBUGGER__::LineBreakpoint.instance_method(:initialize).parameters.include?([:key, :skip_src])
+ options[:skip_src] = true
+ end
+
+ # To make debugger commands like `next` or `continue` work without asking
+ # the user to quit IRB after that, we need to exit IRB first and then hit
+ # a TracePoint on #debug_break.
+ file, lineno = IRB::Irb.instance_method(:debug_break).source_location
+ DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
+ # exit current Irb#run call
+ throw :IRB_EXIT
end
private
@@ -64,6 +54,72 @@ module IRB
end
end
end
+
+ module SkipPathHelperForIRB
+ def skip_internal_path?(path)
+ # The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
+ super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
+ end
+ end
+
+ def setup_debugger
+ unless defined?(DEBUGGER__::SESSION)
+ begin
+ require "debug/session"
+ rescue LoadError # debug.gem is not written in Gemfile
+ return false unless load_bundled_debug_gem
+ end
+ DEBUGGER__.start(nonstop: true)
+ end
+
+ unless DEBUGGER__.respond_to?(:capture_frames_without_irb)
+ DEBUGGER__.singleton_class.send(:alias_method, :capture_frames_without_irb, :capture_frames)
+
+ def DEBUGGER__.capture_frames(*args)
+ frames = capture_frames_without_irb(*args)
+ frames.reject! do |frame|
+ frame.realpath&.start_with?(IRB_DIR) || frame.path == "<internal:prelude>"
+ end
+ frames
+ end
+
+ DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
+ end
+
+ true
+ end
+
+ # This is used when debug.gem is not written in Gemfile. Even if it's not
+ # installed by `bundle install`, debug.gem is installed by default because
+ # it's a bundled gem. This method tries to activate and load that.
+ def load_bundled_debug_gem
+ # Discover latest debug.gem under GEM_PATH
+ debug_gem = Gem.paths.path.flat_map { |path| Dir.glob("#{path}/gems/debug-*") }.select do |path|
+ File.basename(path).match?(/\Adebug-\d+\.\d+\.\d+(\w+)?\z/)
+ end.sort_by do |path|
+ Gem::Version.new(File.basename(path).delete_prefix('debug-'))
+ end.last
+ return false unless debug_gem
+
+ # Discover debug/debug.so under extensions for Ruby 3.2+
+ ext_name = "/debug/debug.#{RbConfig::CONFIG['DLEXT']}"
+ ext_path = Gem.paths.path.flat_map do |path|
+ Dir.glob("#{path}/extensions/**/#{File.basename(debug_gem)}#{ext_name}")
+ end.first
+
+ # Attempt to forcibly load the bundled gem
+ if ext_path
+ $LOAD_PATH << ext_path.delete_suffix(ext_name)
+ end
+ $LOAD_PATH << "#{debug_gem}/lib"
+ begin
+ require "debug/session"
+ puts "Loaded #{File.basename(debug_gem)}"
+ true
+ rescue LoadError
+ false
+ end
+ end
end
class DebugCommand < Debug
diff --git a/lib/irb/cmd/edit.rb b/lib/irb/cmd/edit.rb
index 69606beea0..0103891cf4 100644
--- a/lib/irb/cmd/edit.rb
+++ b/lib/irb/cmd/edit.rb
@@ -1,6 +1,5 @@
require 'shellwords'
require_relative "nop"
-require_relative "../source_finder"
module IRB
# :stopdoc:
@@ -8,7 +7,7 @@ module IRB
module ExtendCommand
class Edit < Nop
category "Misc"
- description 'Open a file with the editor command defined with `ENV["VISUAL"]` or `ENV["EDITOR"]`.'
+ description 'Open a file with the editor command defined with `ENV["EDITOR"]`.'
class << self
def transform_args(args)
@@ -29,15 +28,17 @@ module IRB
end
if !File.exist?(path)
+ require_relative "show_source"
+
source =
begin
- SourceFinder.new(@irb_context).find_source(path)
+ ShowSource.find_source(path, @irb_context)
rescue NameError
# if user enters a path that doesn't exist, it'll cause NameError when passed here because find_source would try to evaluate it as well
# in this case, we should just ignore the error
end
- if source
+ if source && File.exist?(source.file)
path = source.file
else
puts "Can not find file: #{path}"
@@ -45,12 +46,12 @@ module IRB
end
end
- if editor = (ENV['VISUAL'] || ENV['EDITOR'])
+ if editor = ENV['EDITOR']
puts "command: '#{editor}'"
puts " path: #{path}"
system(*Shellwords.split(editor), path)
else
- puts "Can not find editor setting: ENV['VISUAL'] or ENV['EDITOR']"
+ puts "Can not find editor setting: ENV['EDITOR']"
end
end
end
diff --git a/lib/irb/cmd/fork.rb b/lib/irb/cmd/fork.rb
new file mode 100644
index 0000000000..255a670dce
--- /dev/null
+++ b/lib/irb/cmd/fork.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: false
+#
+# fork.rb -
+# $Release Version: 0.9.6 $
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Fork < Nop
+ def execute
+ pid = __send__ ExtendCommand.irb_original_method_name("fork")
+ unless pid
+ class << self
+ alias_method :exit, ExtendCommand.irb_original_method_name('exit')
+ end
+ if block_given?
+ begin
+ yield
+ ensure
+ exit
+ end
+ end
+ end
+ pid
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/help.rb b/lib/irb/cmd/help.rb
index 64b885c383..2a135cdb14 100644
--- a/lib/irb/cmd/help.rb
+++ b/lib/irb/cmd/help.rb
@@ -1,23 +1,63 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
+#
+# help.rb - helper using ri
+# $Release Version: 0.9.6$
+# $Revision$
+#
+# --
+#
+#
+#
-require_relative "show_doc"
+require_relative "nop"
module IRB
+ # :stopdoc:
+
module ExtendCommand
- class Help < ShowDoc
- category "Context"
- description "[DEPRECATED] Enter the mode to look up RI documents."
+ class Help < Nop
+ class << self
+ def transform_args(args)
+ # Return a string literal as is for backward compatibility
+ if args.empty? || string_literal?(args)
+ args
+ else # Otherwise, consider the input as a String for convenience
+ args.strip.dump
+ end
+ end
+ end
- DEPRECATION_MESSAGE = <<~MSG
- [Deprecation] The `help` command will be repurposed to display command help in the future.
- For RI document lookup, please use the `show_doc` command instead.
- For command help, please use `show_cmds` for now.
- MSG
+ category "Context"
+ description "Enter the mode to look up RI documents."
def execute(*names)
- warn DEPRECATION_MESSAGE
- super
+ require 'rdoc/ri/driver'
+ opts = RDoc::RI::Driver.process_args([])
+ IRB::ExtendCommand::Help.const_set(:Ri, RDoc::RI::Driver.new(opts))
+ rescue LoadError, SystemExit
+ IRB::ExtendCommand::Help.remove_method(:execute)
+ # raise NoMethodError in ensure
+ else
+ def execute(*names)
+ if names.empty?
+ Ri.interactive
+ return
+ end
+ names.each do |name|
+ begin
+ Ri.display_name(name.to_s)
+ rescue RDoc::RI::Error
+ puts $!.message
+ end
+ end
+ nil
+ end
+ nil
+ ensure
+ execute(*names)
end
end
end
+
+ # :startdoc:
end
diff --git a/lib/irb/cmd/irb_info.rb b/lib/irb/cmd/irb_info.rb
index 5b905a09bd..da11e8d40b 100644
--- a/lib/irb/cmd/irb_info.rb
+++ b/lib/irb/cmd/irb_info.rb
@@ -11,21 +11,24 @@ module IRB
description "Show information about IRB."
def execute
- str = "Ruby version: #{RUBY_VERSION}\n"
- str += "IRB version: #{IRB.version}\n"
- str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
- str += "Completion: #{IRB.CurrentContext.io.respond_to?(:completion_info) ? IRB.CurrentContext.io.completion_info : 'off'}\n"
- str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
- str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
- str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
- str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
- str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
- if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
- str += "Code page: #{codepage}\n"
- end
- puts str
- nil
+ Class.new {
+ def inspect
+ str = "Ruby version: #{RUBY_VERSION}\n"
+ str += "IRB version: #{IRB.version}\n"
+ str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
+ str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
+ str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
+ str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
+ str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
+ str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
+ if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
+ codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
+ str += "Code page: #{codepage}\n"
+ end
+ str
+ end
+ alias_method :to_s, :inspect
+ }.new
end
end
end
diff --git a/lib/irb/cmd/load.rb b/lib/irb/cmd/load.rb
index a3e797a7e0..2897bbd975 100644
--- a/lib/irb/cmd/load.rb
+++ b/lib/irb/cmd/load.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# load.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require_relative "nop"
require_relative "../ext/loader"
diff --git a/lib/irb/cmd/ls.rb b/lib/irb/cmd/ls.rb
index 791b1c1b21..b65fae2bf1 100644
--- a/lib/irb/cmd/ls.rb
+++ b/lib/irb/cmd/ls.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
require "reline"
-require "stringio"
require_relative "nop"
-require_relative "../pager"
require_relative "../color"
module IRB
@@ -35,42 +33,26 @@ module IRB
o.dump("instance variables", obj.instance_variables)
o.dump("class variables", klass.class_variables)
o.dump("locals", locals)
- o.print_result
+ nil
end
def dump_methods(o, klass, obj)
singleton_class = begin obj.singleton_class; rescue TypeError; nil end
- dumped_mods = Array.new
- ancestors = klass.ancestors
- ancestors = ancestors.reject { |c| c >= Object } if klass < Object
- singleton_ancestors = (singleton_class&.ancestors || []).reject { |c| c >= Class }
-
- # singleton_class' ancestors should be at the front
- maps = class_method_map(singleton_ancestors, dumped_mods) + class_method_map(ancestors, dumped_mods)
+ maps = class_method_map((singleton_class || klass).ancestors)
maps.each do |mod, methods|
name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods"
o.dump(name, methods)
end
end
- def class_method_map(classes, dumped_mods)
- dumped_methods = Array.new
- classes.map do |mod|
- next if dumped_mods.include? mod
-
- dumped_mods << mod
-
- methods = mod.public_instance_methods(false).select do |method|
- if dumped_methods.include? method
- false
- else
- dumped_methods << method
- true
- end
+ def class_method_map(classes)
+ dumped = Array.new
+ classes.reject { |mod| mod >= Object }.map do |mod|
+ methods = mod.public_instance_methods(false).select do |m|
+ dumped.push(m) unless dumped.include?(m)
end
-
[mod, methods]
- end.compact
+ end.reverse
end
class Output
@@ -79,11 +61,6 @@ module IRB
def initialize(grep: nil)
@grep = grep
@line_width = screen_width - MARGIN.length # right padding
- @io = StringIO.new
- end
-
- def print_result
- Pager.page_content(@io.string)
end
def dump(name, strs)
@@ -92,12 +69,12 @@ module IRB
return if strs.empty?
# Attempt a single line
- @io.print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
+ print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
- @io.puts strs.join(MARGIN)
+ puts strs.join(MARGIN)
return
end
- @io.puts
+ puts
# Dump with the largest # of columns that fits on a line
cols = strs.size
@@ -106,7 +83,7 @@ module IRB
end
widths = col_widths(strs, cols: cols)
strs.each_slice(cols) do |ss|
- @io.puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
+ puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
end
end
diff --git a/lib/irb/cmd/nop.rb b/lib/irb/cmd/nop.rb
index 7fb197c51f..c616c054a8 100644
--- a/lib/irb/cmd/nop.rb
+++ b/lib/irb/cmd/nop.rb
@@ -1,9 +1,14 @@
# frozen_string_literal: false
#
# nop.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
module IRB
# :stopdoc:
@@ -30,19 +35,32 @@ module IRB
end
end
- def self.execute(irb_context, *opts, **kwargs, &block)
- command = new(irb_context)
- command.execute(*opts, **kwargs, &block)
- rescue CommandArgumentError => e
- puts e.message
+ if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
+ def self.execute(conf, *opts, **kwargs, &block)
+ command = new(conf)
+ command.execute(*opts, **kwargs, &block)
+ rescue CommandArgumentError => e
+ puts e.message
+ end
+ else
+ def self.execute(conf, *opts, &block)
+ command = new(conf)
+ command.execute(*opts, &block)
+ rescue CommandArgumentError => e
+ puts e.message
+ end
end
- def initialize(irb_context)
- @irb_context = irb_context
+ def initialize(conf)
+ @irb_context = conf
end
attr_reader :irb_context
+ def irb
+ @irb_context.irb
+ end
+
def execute(*opts)
#nop
end
diff --git a/lib/irb/cmd/pushws.rb b/lib/irb/cmd/pushws.rb
index 59996ceb0c..41d2e705f1 100644
--- a/lib/irb/cmd/pushws.rb
+++ b/lib/irb/cmd/pushws.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# change-ws.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require_relative "nop"
require_relative "../ext/workspaces"
@@ -12,7 +18,7 @@ module IRB
module ExtendCommand
class Workspaces < Nop
- category "Workspace"
+ category "IRB"
description "Show workspaces."
def execute(*obj)
@@ -21,7 +27,7 @@ module IRB
end
class PushWorkspace < Workspaces
- category "Workspace"
+ category "IRB"
description "Push an object to the workspace stack."
def execute(*obj)
@@ -31,7 +37,7 @@ module IRB
end
class PopWorkspace < Workspaces
- category "Workspace"
+ category "IRB"
description "Pop a workspace from the workspace stack."
def execute(*obj)
diff --git a/lib/irb/cmd/show_cmds.rb b/lib/irb/cmd/show_cmds.rb
index 7d6b3ec266..acced27d48 100644
--- a/lib/irb/cmd/show_cmds.rb
+++ b/lib/irb/cmd/show_cmds.rb
@@ -2,7 +2,6 @@
require "stringio"
require_relative "nop"
-require_relative "../pager"
module IRB
# :stopdoc:
@@ -15,17 +14,7 @@ module IRB
def execute(*args)
commands_info = IRB::ExtendCommandBundle.all_commands_info
commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
-
- if irb_context.with_debugger
- # Remove the original "Debugging" category
- commands_grouped_by_categories.delete("Debugging")
- # Remove the `help` command as it's delegated to the debugger
- commands_grouped_by_categories["Context"].delete_if { |cmd| cmd[:display_name] == :help }
- # Add an empty "Debugging (from debug.gem)" category at the end
- commands_grouped_by_categories["Debugging (from debug.gem)"] = []
- end
-
- longest_cmd_name_length = commands_info.map { |c| c[:display_name].length }.max
+ longest_cmd_name_length = commands_info.map { |c| c[:display_name] }.max { |a, b| a.length <=> b.length }.length
output = StringIO.new
@@ -39,12 +28,9 @@ module IRB
output.puts
end
- # Append the debugger help at the end
- if irb_context.with_debugger
- output.puts DEBUGGER__.help
- end
+ puts output.string
- Pager.page_content(output.string)
+ nil
end
end
end
diff --git a/lib/irb/cmd/show_doc.rb b/lib/irb/cmd/show_doc.rb
deleted file mode 100644
index 99dd9ab95a..0000000000
--- a/lib/irb/cmd/show_doc.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "nop"
-
-module IRB
- module ExtendCommand
- class ShowDoc < Nop
- class << self
- def transform_args(args)
- # Return a string literal as is for backward compatibility
- if args.empty? || string_literal?(args)
- args
- else # Otherwise, consider the input as a String for convenience
- args.strip.dump
- end
- end
- end
-
- category "Context"
- description "Enter the mode to look up RI documents."
-
- def execute(*names)
- require 'rdoc/ri/driver'
-
- unless ShowDoc.const_defined?(:Ri)
- opts = RDoc::RI::Driver.process_args([])
- ShowDoc.const_set(:Ri, RDoc::RI::Driver.new(opts))
- end
-
- if names.empty?
- Ri.interactive
- else
- names.each do |name|
- begin
- Ri.display_name(name.to_s)
- rescue RDoc::RI::Error
- puts $!.message
- end
- end
- end
-
- nil
- rescue LoadError, SystemExit
- warn "Can't display document because `rdoc` is not installed."
- end
- end
- end
-end
diff --git a/lib/irb/cmd/show_source.rb b/lib/irb/cmd/show_source.rb
index 49cab43fab..ea700be4bf 100644
--- a/lib/irb/cmd/show_source.rb
+++ b/lib/irb/cmd/show_source.rb
@@ -1,11 +1,12 @@
# frozen_string_literal: true
require_relative "nop"
-require_relative "../source_finder"
-require_relative "../pager"
require_relative "../color"
+require_relative "../ruby-lex"
module IRB
+ # :stopdoc:
+
module ExtendCommand
class ShowSource < Nop
category "Context"
@@ -20,6 +21,50 @@ module IRB
args.strip.dump
end
end
+
+ def find_source(str, irb_context)
+ case str
+ when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
+ eval(str, irb_context.workspace.binding) # trigger autoload
+ base = irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
+ file, line = base.const_source_location(str) if base.respond_to?(:const_source_location) # Ruby 2.7+
+ when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
+ owner = eval(Regexp.last_match[:owner], irb_context.workspace.binding)
+ method = Regexp.last_match[:method]
+ if owner.respond_to?(:instance_method) && owner.instance_methods.include?(method.to_sym)
+ file, line = owner.instance_method(method).source_location
+ end
+ when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
+ receiver = eval(Regexp.last_match[:receiver] || 'self', irb_context.workspace.binding)
+ method = Regexp.last_match[:method]
+ file, line = receiver.method(method).source_location if receiver.respond_to?(method)
+ end
+ if file && line
+ Source.new(file: file, first_line: line, last_line: find_end(file, line))
+ end
+ end
+
+ private
+
+ def find_end(file, first_line)
+ return first_line unless File.exist?(file)
+ lex = RubyLex.new
+ lines = File.read(file).lines[(first_line - 1)..-1]
+ tokens = RubyLex.ripper_lex_without_warning(lines.join)
+ prev_tokens = []
+
+ # chunk with line number
+ tokens.chunk { |tok| tok.pos[0] }.each do |lnum, chunk|
+ code = lines[0..lnum].join
+ prev_tokens.concat chunk
+ continue = lex.process_continue(prev_tokens)
+ code_block_open = lex.check_code_block(code, prev_tokens)
+ if !continue && !code_block_open
+ return first_line + lnum
+ end
+ end
+ first_line
+ end
end
def execute(str = nil)
@@ -28,9 +73,8 @@ module IRB
return
end
- source = SourceFinder.new(@irb_context).find_source(str)
-
- if source
+ source = self.class.find_source(str, @irb_context)
+ if source && File.exist?(source.file)
show_source(source)
else
puts "Error: Couldn't locate a definition for #{str}"
@@ -40,22 +84,29 @@ module IRB
private
+ # @param [IRB::ExtendCommand::ShowSource::Source] source
def show_source(source)
- file_content = IRB::Color.colorize_code(File.read(source.file))
- code = file_content.lines[(source.first_line - 1)...source.last_line].join
- content = <<~CONTENT
-
- #{bold("From")}: #{source.file}:#{source.first_line}
-
- #{code}
- CONTENT
-
- Pager.page_content(content)
+ puts
+ puts "#{bold("From")}: #{source.file}:#{source.first_line}"
+ puts
+ code = IRB::Color.colorize_code(File.read(source.file))
+ puts code.lines[(source.first_line - 1)...source.last_line].join
+ puts
end
def bold(str)
Color.colorize(str, [:BOLD])
end
+
+ Source = Struct.new(
+ :file, # @param [String] - file name
+ :first_line, # @param [String] - first line
+ :last_line, # @param [String] - last line
+ keyword_init: true,
+ )
+ private_constant :Source
end
end
+
+ # :startdoc:
end
diff --git a/lib/irb/cmd/subirb.rb b/lib/irb/cmd/subirb.rb
index 5ffd646416..699b35fcb4 100644
--- a/lib/irb/cmd/subirb.rb
+++ b/lib/irb/cmd/subirb.rb
@@ -1,8 +1,13 @@
# frozen_string_literal: false
-#
# multi.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require_relative "nop"
@@ -11,95 +16,52 @@ module IRB
module ExtendCommand
class MultiIRBCommand < Nop
- def execute(*args)
+ def initialize(conf)
+ super
extend_irb_context
end
private
- def print_deprecated_warning
- warn <<~MSG
- Multi-irb commands are deprecated and will be removed in IRB 2.0.0. Please use workspace commands instead.
- If you have any use case for multi-irb, please leave a comment at https://github.com/ruby/irb/issues/653
- MSG
- end
-
def extend_irb_context
# this extension patches IRB context like IRB.CurrentContext
require_relative "../ext/multi-irb"
end
-
- def print_debugger_warning
- warn "Multi-IRB commands are not available when the debugger is enabled."
- end
end
class IrbCommand < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
+ category "IRB"
description "Start a child IRB."
def execute(*obj)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- super
IRB.irb(nil, *obj)
end
end
class Jobs < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
+ category "IRB"
description "List of current sessions."
def execute
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- super
IRB.JobManager
end
end
class Foreground < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
+ category "IRB"
description "Switches to the session of the given number."
def execute(key = nil)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- super
-
raise CommandArgumentError.new("Please specify the id of target IRB job (listed in the `jobs` command).") unless key
IRB.JobManager.switch(key)
end
end
class Kill < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
+ category "IRB"
description "Kills the session with the given number."
def execute(*keys)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- super
IRB.JobManager.kill(*keys)
end
end
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index ad8670160c..6378e14856 100644
--- a/lib/irb/color.rb
+++ b/lib/irb/color.rb
@@ -9,14 +9,12 @@ module IRB # :nodoc:
BOLD = 1
UNDERLINE = 4
REVERSE = 7
- BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
- WHITE = 37
TOKEN_KEYWORDS = {
on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__', '__ENCODING__'],
@@ -199,9 +197,15 @@ module IRB # :nodoc:
end
end
- lexer.scan.each do |elem|
- next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
- on_scan.call(elem)
+ if lexer.respond_to?(:scan) # Ruby 2.7+
+ lexer.scan.each do |elem|
+ next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
+ on_scan.call(elem)
+ end
+ else
+ lexer.parse.sort_by(&:pos).each do |elem|
+ on_scan.call(elem)
+ end
end
# yield uncolorable DATA section
yield(nil, inner_code.byteslice(byte_pos...inner_code.bytesize), nil) if byte_pos < inner_code.bytesize
@@ -238,7 +242,7 @@ module IRB # :nodoc:
case token
when :on_symbeg, :on_symbols_beg, :on_qsymbols_beg
@stack << true
- when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw, :on_backtick
+ when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw
if @stack.last # Pop only when it's Symbol
@stack.pop
return prev_state
diff --git a/lib/irb/color_printer.rb b/lib/irb/color_printer.rb
index 31644aa7f9..1127bcecb4 100644
--- a/lib/irb/color_printer.rb
+++ b/lib/irb/color_printer.rb
@@ -4,9 +4,6 @@ require_relative 'color'
module IRB
class ColorPrinter < ::PP
- METHOD_RESPOND_TO = Object.instance_method(:respond_to?)
- METHOD_INSPECT = Object.instance_method(:inspect)
-
class << self
def pp(obj, out = $>, width = screen_width)
q = ColorPrinter.new(out, width)
@@ -25,11 +22,9 @@ module IRB
end
def pp(obj)
- if String === obj
+ if obj.is_a?(String)
# Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
text(obj.inspect)
- elsif !METHOD_RESPOND_TO.bind(obj).call(:inspect)
- text(METHOD_INSPECT.bind(obj).call)
else
super
end
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index e3ebe4abff..34640e17f9 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: false
#
# irb/completion.rb -
+# $Release Version: 0.9$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
# From Original Idea of shugo@ruby-lang.org
#
@@ -8,7 +10,30 @@
require_relative 'ruby-lex'
module IRB
- class BaseCompletor # :nodoc:
+ module InputCompletor # :nodoc:
+ using Module.new {
+ refine ::Binding do
+ def eval_methods
+ ::Kernel.instance_method(:methods).bind(eval("self")).call
+ end
+
+ def eval_private_methods
+ ::Kernel.instance_method(:private_methods).bind(eval("self")).call
+ end
+
+ def eval_instance_variables
+ ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
+ end
+
+ def eval_global_variables
+ ::Kernel.instance_method(:global_variables).bind(eval("self")).call
+ end
+
+ def eval_class_constants
+ ::Module.instance_method(:constants).bind(eval("self.class")).call
+ end
+ end
+ }
# Set of reserved words used by Ruby, you should not use these for
# constants or variables
@@ -33,19 +58,21 @@ module IRB
yield
]
- def completion_candidates(preposing, target, postposing, bind:)
- raise NotImplementedError
- end
+ BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
- def doc_namespace(preposing, matched, postposing, bind:)
- raise NotImplementedError
+ def self.absolute_path?(p) # TODO Remove this method after 2.6 EOL.
+ if File.respond_to?(:absolute_path?)
+ File.absolute_path?(p)
+ else
+ File.absolute_path(p) == p
+ end
end
GEM_PATHS =
if defined?(Gem::Specification)
Gem::Specification.latest_specs(true).map { |s|
s.require_paths.map { |p|
- if File.absolute_path?(p)
+ if absolute_path?(p)
p
else
File.join(s.full_gem_path, p)
@@ -56,7 +83,7 @@ module IRB
[]
end.freeze
- def retrieve_gem_and_system_load_path
+ def self.retrieve_gem_and_system_load_path
candidates = (GEM_PATHS | $LOAD_PATH)
candidates.map do |p|
if p.respond_to?(:to_path)
@@ -67,8 +94,8 @@ module IRB
end.compact.sort
end
- def retrieve_files_to_require_from_load_path
- @files_from_load_path ||=
+ def self.retrieve_files_to_require_from_load_path
+ @@files_from_load_path ||=
(
shortest = []
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
@@ -86,43 +113,13 @@ module IRB
)
end
- def retrieve_files_to_require_relative_from_current_dir
- @files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
+ def self.retrieve_files_to_require_relative_from_current_dir
+ @@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
}
end
- end
-
- class RegexpCompletor < BaseCompletor # :nodoc:
- using Module.new {
- refine ::Binding do
- def eval_methods
- ::Kernel.instance_method(:methods).bind(eval("self")).call
- end
- def eval_private_methods
- ::Kernel.instance_method(:private_methods).bind(eval("self")).call
- end
-
- def eval_instance_variables
- ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
- end
-
- def eval_global_variables
- ::Kernel.instance_method(:global_variables).bind(eval("self")).call
- end
-
- def eval_class_constants
- ::Module.instance_method(:constants).bind(eval("self.class")).call
- end
- end
- }
-
- def inspect
- 'RegexpCompletor'
- end
-
- def complete_require_path(target, preposing, postposing)
+ CompletionRequireProc = lambda { |target, preposing = nil, postposing = nil|
if target =~ /\A(['"])([^'"]+)\Z/
quote = $1
actual_target = $2
@@ -137,44 +134,44 @@ module IRB
break
end
end
- return unless tok&.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
-
- case tok.tok
- when 'require'
- retrieve_files_to_require_from_load_path.select { |path|
- path.start_with?(actual_target)
- }.map { |path|
- quote + path
- }
- when 'require_relative'
- retrieve_files_to_require_relative_from_current_dir.select { |path|
- path.start_with?(actual_target)
- }.map { |path|
- quote + path
- }
+ result = []
+ if tok && tok.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
+ case tok.tok
+ when 'require'
+ result = retrieve_files_to_require_from_load_path.select { |path|
+ path.start_with?(actual_target)
+ }.map { |path|
+ quote + path
+ }
+ when 'require_relative'
+ result = retrieve_files_to_require_relative_from_current_dir.select { |path|
+ path.start_with?(actual_target)
+ }.map { |path|
+ quote + path
+ }
+ end
end
- end
+ result
+ }
- def completion_candidates(preposing, target, postposing, bind:)
+ CompletionProc = lambda { |target, preposing = nil, postposing = nil|
if preposing && postposing
- result = complete_require_path(target, preposing, postposing)
- return result if result
+ result = CompletionRequireProc.(target, preposing, postposing)
+ unless result
+ result = retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
+ end
+ result
+ else
+ retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
end
- retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
- end
-
- def doc_namespace(_preposing, matched, _postposing, bind:)
- retrieve_completion_data(matched, bind: bind, doc_namespace: true)
- end
+ }
- def retrieve_completion_data(input, bind:, doc_namespace:)
+ def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
case input
- # this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
- # details are described in: https://github.com/ruby/irb/pull/523
- when /^(.*["'`])\.([^.]*)$/
+ when /^((["'`]).*\2)\.([^.]*)$/
# String
receiver = $1
- message = $2
+ message = $3
if doc_namespace
"String.#{message}"
@@ -183,9 +180,7 @@ module IRB
select_message(receiver, message, candidates)
end
- # this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
- # details are described in: https://github.com/ruby/irb/pull/523
- when /^(.*\/)\.([^.]*)$/
+ when /^(\/[^\/]*\/)\.([^.]*)$/
# Regexp
receiver = $1
message = $2
@@ -222,14 +217,14 @@ module IRB
select_message(receiver, message, proc_candidates | hash_candidates)
end
- when /^(:[^:.]+)$/
+ when /^(:[^:.]*)$/
# Symbol
if doc_namespace
nil
else
sym = $1
candidates = Symbol.all_symbols.collect do |s|
- s.inspect
+ ":" + s.id2name.encode(Encoding.default_external)
rescue EncodingError
# ignore
end
@@ -244,7 +239,7 @@ module IRB
if doc_namespace
candidates.find { |i| i == receiver }
else
- candidates.grep(/^#{Regexp.quote(receiver)}/).collect{|e| "::" + e}
+ candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
end
when /^([A-Z].*)::([^:.]*)$/
@@ -363,6 +358,14 @@ module IRB
else
# func1.func2
candidates = []
+ to_ignore = ignored_modules
+ ObjectSpace.each_object(Module){|m|
+ next if (to_ignore.include?(m) rescue true)
+ next unless m.respond_to?(:instance_methods) # JRuby has modules that represent java packages. They don't include many common ruby methods
+ candidates.concat m.instance_methods(false).collect{|x| x.to_s}
+ }
+ candidates.sort!
+ candidates.uniq!
end
if doc_namespace
@@ -405,10 +408,44 @@ module IRB
end
end
+ PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
+ begin
+ require 'rdoc'
+ rescue LoadError
+ return
+ end
+
+ RDocRIDriver ||= RDoc::RI::Driver.new
+
+ if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
+ IRB.__send__(:easter_egg)
+ return
+ end
+
+ namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
+ return unless namespace
+
+ if namespace.is_a?(Array)
+ out = RDoc::Markup::Document.new
+ namespace.each do |m|
+ begin
+ RDocRIDriver.add_method(out, m)
+ rescue RDoc::RI::Driver::NotFoundError
+ end
+ end
+ RDocRIDriver.display(out)
+ else
+ begin
+ RDocRIDriver.display_names([namespace])
+ rescue RDoc::RI::Driver::NotFoundError
+ end
+ end
+ }
+
# Set of available operators in Ruby
Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
- def select_message(receiver, message, candidates, sep = ".")
+ def self.select_message(receiver, message, candidates, sep = ".")
candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
case e
when /^[a-zA-Z_]/
@@ -419,21 +456,30 @@ module IRB
end
end
end
- end
- module InputCompletor
- class << self
- private def regexp_completor
- @regexp_completor ||= RegexpCompletor.new
+ def self.ignored_modules
+ # We could cache the result, but this is very fast already.
+ # By using this approach, we avoid Module#name calls, which are
+ # relatively slow when there are a lot of anonymous modules defined.
+ s = {}
+
+ scanner = lambda do |m|
+ next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses.
+ s[m] = true
+ m.constants(false).each do |c|
+ value = m.const_get(c)
+ scanner.call(value) if value.is_a?(Module)
+ end
end
- def retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
- regexp_completor.retrieve_completion_data(input, bind: bind, doc_namespace: doc_namespace)
+ %i(IRB RubyLex).each do |sym|
+ next unless Object.const_defined?(sym)
+ scanner.call(Object.const_get(sym))
end
+
+ s.delete(IRB::Context) if defined?(IRB::Context)
+
+ s
end
- CompletionProc = ->(target, preposing = nil, postposing = nil) {
- regexp_completor.completion_candidates(preposing, target, postposing, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding)
- }
end
- deprecate_constant :InputCompletor
end
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
index 5dfe9d0d71..91fbb2fcf1 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -1,9 +1,14 @@
# frozen_string_literal: false
#
# irb/context.rb - irb context
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
require_relative "workspace"
require_relative "inspector"
require_relative "input-method"
@@ -86,14 +91,14 @@ module IRB
when nil
if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
# Both of multiline mode and singleline mode aren't specified.
- @io = RelineInputMethod.new(build_completor)
+ @io = RelineInputMethod.new
else
@io = nil
end
when false
@io = nil
when true
- @io = RelineInputMethod.new(build_completor)
+ @io = RelineInputMethod.new
end
unless @io
case use_singleline?
@@ -129,6 +134,8 @@ module IRB
else
@io = input_method
end
+ self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY]
+
@extra_doc_dirs = IRB.conf[:EXTRA_DOC_DIRS]
@echo = IRB.conf[:ECHO]
@@ -149,61 +156,6 @@ module IRB
@command_aliases = IRB.conf[:COMMAND_ALIASES]
end
- private def build_completor
- completor_type = IRB.conf[:COMPLETOR]
- case completor_type
- when :regexp
- return RegexpCompletor.new
- when :type
- completor = build_type_completor
- return completor if completor
- else
- warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
- end
- # Fallback to RegexpCompletor
- RegexpCompletor.new
- end
-
- TYPE_COMPLETION_REQUIRED_PRISM_VERSION = '0.17.1'
-
- private def build_type_completor
- unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') && RUBY_ENGINE != 'truffleruby'
- warn 'TypeCompletion requires RUBY_VERSION >= 3.0.0'
- return
- end
- begin
- require 'prism'
- rescue LoadError => e
- warn "TypeCompletion requires Prism: #{e.message}"
- return
- end
- unless Gem::Version.new(Prism::VERSION) >= Gem::Version.new(TYPE_COMPLETION_REQUIRED_PRISM_VERSION)
- warn "TypeCompletion requires Prism::VERSION >= #{TYPE_COMPLETION_REQUIRED_PRISM_VERSION}"
- return
- end
- require 'irb/type_completion/completor'
- TypeCompletion::Types.preload_in_thread
- TypeCompletion::Completor.new
- end
-
- def save_history=(val)
- IRB.conf[:SAVE_HISTORY] = val
- end
-
- def save_history
- IRB.conf[:SAVE_HISTORY]
- end
-
- # A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
- def history_file
- IRB.conf[:HISTORY_FILE]
- end
-
- # Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
- def history_file=(hist)
- IRB.conf[:HISTORY_FILE] = hist
- end
-
# The top-level workspace, see WorkSpace#main
def main
@workspace.main
@@ -266,19 +218,8 @@ module IRB
#
# See IRB@Customizing+the+IRB+Prompt for more information.
attr_accessor :prompt_c
-
- # TODO: Remove this when developing v2.0
- def prompt_n
- warn "IRB::Context#prompt_n is deprecated and will be removed in the next major release."
- ""
- end
-
- # TODO: Remove this when developing v2.0
- def prompt_n=(_)
- warn "IRB::Context#prompt_n= is deprecated and will be removed in the next major release."
- ""
- end
-
+ # See IRB@Customizing+the+IRB+Prompt for more information.
+ attr_accessor :prompt_n
# Can be either the default <code>IRB.conf[:AUTO_INDENT]</code>, or the
# mode set by #prompt_mode=
#
@@ -393,8 +334,6 @@ module IRB
# User-defined IRB command aliases
attr_accessor :command_aliases
- attr_accessor :with_debugger
-
# Alias for #use_multiline
alias use_multiline? use_multiline
# Alias for #use_singleline
@@ -462,6 +401,7 @@ module IRB
@prompt_i = pconf[:PROMPT_I]
@prompt_s = pconf[:PROMPT_S]
@prompt_c = pconf[:PROMPT_C]
+ @prompt_n = pconf[:PROMPT_N]
@return_format = pconf[:RETURN]
@return_format = "%s\n" if @return_format == nil
if ai = pconf.include?(:AUTO_INDENT)
@@ -538,31 +478,28 @@ module IRB
@inspect_mode
end
- def evaluate(line, line_no) # :nodoc:
+ def evaluate(line, line_no, exception: nil) # :nodoc:
@line_no = line_no
- result = nil
+ if exception
+ line_no -= 1
+ line = "begin ::Kernel.raise _; rescue _.class\n#{line}\n""end"
+ @workspace.local_variable_set(:_, exception)
+ end
- if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
- IRB.set_measure_callback
+ # Transform a non-identifier alias (@, $) or keywords (next, break)
+ command, args = line.split(/\s/, 2)
+ if original = command_aliases[command.to_sym]
+ line = line.gsub(/\A#{Regexp.escape(command)}/, original.to_s)
+ command = original
end
- if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
- last_proc = proc do
- result = @workspace.evaluate(line, irb_path, line_no)
- end
- IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) do |chain, item|
- _name, callback, arg = item
- proc do
- callback.(self, line, line_no, arg) do
- chain.call
- end
- end
- end.call
- else
- result = @workspace.evaluate(line, irb_path, line_no)
+ # Hook command-specific transformation
+ command_class = ExtendCommandBundle.load_command(command)
+ if command_class&.respond_to?(:transform_args)
+ line = "#{command} #{command_class.transform_args(args)}"
end
- set_last_value(result)
+ set_last_value(@workspace.evaluate(self, line, irb_path, line_no))
end
def inspect_last_value # :nodoc:
diff --git a/lib/irb/debug.rb b/lib/irb/debug.rb
deleted file mode 100644
index e522d39300..0000000000
--- a/lib/irb/debug.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Debug
- IRB_DIR = File.expand_path('..', __dir__)
-
- class << self
- def insert_debug_break(pre_cmds: nil, do_cmds: nil)
- options = { oneshot: true, hook_call: false }
-
- if pre_cmds || do_cmds
- options[:command] = ['irb', pre_cmds, do_cmds]
- end
- if DEBUGGER__::LineBreakpoint.instance_method(:initialize).parameters.include?([:key, :skip_src])
- options[:skip_src] = true
- end
-
- # To make debugger commands like `next` or `continue` work without asking
- # the user to quit IRB after that, we need to exit IRB first and then hit
- # a TracePoint on #debug_break.
- file, lineno = IRB::Irb.instance_method(:debug_break).source_location
- DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
- end
-
- def setup(irb)
- # When debug session is not started at all
- unless defined?(DEBUGGER__::SESSION)
- begin
- require "debug/session"
- rescue LoadError # debug.gem is not written in Gemfile
- return false unless load_bundled_debug_gem
- end
- DEBUGGER__::CONFIG.set_config
- configure_irb_for_debugger(irb)
-
- DEBUGGER__.initialize_session{ IRB::Debug::UI.new(irb) }
- end
-
- # When debug session was previously started but not by IRB
- if defined?(DEBUGGER__::SESSION) && !irb.context.with_debugger
- configure_irb_for_debugger(irb)
- DEBUGGER__::SESSION.reset_ui(IRB::Debug::UI.new(irb))
- end
-
- # Apply patches to debug gem so it skips IRB frames
- unless DEBUGGER__.respond_to?(:capture_frames_without_irb)
- DEBUGGER__.singleton_class.send(:alias_method, :capture_frames_without_irb, :capture_frames)
-
- def DEBUGGER__.capture_frames(*args)
- frames = capture_frames_without_irb(*args)
- frames.reject! do |frame|
- frame.realpath&.start_with?(IRB_DIR) || frame.path == "<internal:prelude>"
- end
- frames
- end
-
- DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
- end
-
- true
- end
-
- private
-
- def configure_irb_for_debugger(irb)
- require 'irb/debug/ui'
- IRB.instance_variable_set(:@debugger_irb, irb)
- irb.context.with_debugger = true
- irb.context.irb_name += ":rdbg"
- end
-
- module SkipPathHelperForIRB
- def skip_internal_path?(path)
- # The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
- super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
- end
- end
-
- # This is used when debug.gem is not written in Gemfile. Even if it's not
- # installed by `bundle install`, debug.gem is installed by default because
- # it's a bundled gem. This method tries to activate and load that.
- def load_bundled_debug_gem
- # Discover latest debug.gem under GEM_PATH
- debug_gem = Gem.paths.path.flat_map { |path| Dir.glob("#{path}/gems/debug-*") }.select do |path|
- File.basename(path).match?(/\Adebug-\d+\.\d+\.\d+(\w+)?\z/)
- end.sort_by do |path|
- Gem::Version.new(File.basename(path).delete_prefix('debug-'))
- end.last
- return false unless debug_gem
-
- # Discover debug/debug.so under extensions for Ruby 3.2+
- ext_name = "/debug/debug.#{RbConfig::CONFIG['DLEXT']}"
- ext_path = Gem.paths.path.flat_map do |path|
- Dir.glob("#{path}/extensions/**/#{File.basename(debug_gem)}#{ext_name}")
- end.first
-
- # Attempt to forcibly load the bundled gem
- if ext_path
- $LOAD_PATH << ext_path.delete_suffix(ext_name)
- end
- $LOAD_PATH << "#{debug_gem}/lib"
- begin
- require "debug/session"
- puts "Loaded #{File.basename(debug_gem)}"
- true
- rescue LoadError
- false
- end
- end
- end
- end
-end
diff --git a/lib/irb/debug/ui.rb b/lib/irb/debug/ui.rb
deleted file mode 100644
index 307097b8c9..0000000000
--- a/lib/irb/debug/ui.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-require 'io/console/size'
-require 'debug/console'
-
-module IRB
- module Debug
- class UI < DEBUGGER__::UI_Base
- def initialize(irb)
- @irb = irb
- end
-
- def remote?
- false
- end
-
- def activate session, on_fork: false
- end
-
- def deactivate
- end
-
- def width
- if (w = IO.console_size[1]) == 0 # for tests PTY
- 80
- else
- w
- end
- end
-
- def quit n
- yield
- exit n
- end
-
- def ask prompt
- setup_interrupt do
- print prompt
- ($stdin.gets || '').strip
- end
- end
-
- def puts str = nil
- case str
- when Array
- str.each{|line|
- $stdout.puts line.chomp
- }
- when String
- str.each_line{|line|
- $stdout.puts line.chomp
- }
- when nil
- $stdout.puts
- end
- end
-
- def readline _
- setup_interrupt do
- tc = DEBUGGER__::SESSION.instance_variable_get(:@tc)
- cmd = @irb.debug_readline(tc.current_frame.binding || TOPLEVEL_BINDING)
-
- case cmd
- when nil # when user types C-d
- "continue"
- else
- cmd
- end
- end
- end
-
- def setup_interrupt
- DEBUGGER__::SESSION.intercept_trap_sigint false do
- current_thread = Thread.current # should be session_server thread
-
- prev_handler = trap(:INT){
- current_thread.raise Interrupt
- }
-
- yield
- ensure
- trap(:INT, prev_handler)
- end
- end
-
- def after_fork_parent
- parent_pid = Process.pid
-
- at_exit{
- DEBUGGER__::SESSION.intercept_trap_sigint_end
- trap(:SIGINT, :IGNORE)
-
- if Process.pid == parent_pid
- # only check child process from its parent
- begin
- # wait for all child processes to keep terminal
- Process.waitpid
- rescue Errno::ESRCH, Errno::ECHILD
- end
- end
- }
- end
- end
- end
-end
diff --git a/lib/irb/easter-egg.rb b/lib/irb/easter-egg.rb
index adc0834d55..3e79692de9 100644
--- a/lib/irb/easter-egg.rb
+++ b/lib/irb/easter-egg.rb
@@ -98,26 +98,18 @@ module IRB
end
end
- private def easter_egg_logo(type)
- @easter_egg_logos ||= File.read(File.join(__dir__, 'ruby_logo.aa'), encoding: 'UTF-8:UTF-8')
- .split(/TYPE: ([A-Z]+)\n/)[1..]
- .each_slice(2)
- .to_h
- @easter_egg_logos[type.to_s.upcase]
- end
-
private def easter_egg(type = nil)
type ||= [:logo, :dancing].sample
case type
when :logo
- require "rdoc"
- RDoc::RI::Driver.new.page do |io|
- io.write easter_egg_logo(:large)
+ File.open(File.join(__dir__, 'ruby_logo.aa')) do |f|
+ require "rdoc"
+ RDoc::RI::Driver.new.page do |io|
+ IO.copy_stream(f, io)
+ end
end
when :dancing
- STDOUT.cooked do
- interrupted = false
- prev_trap = trap("SIGINT") { interrupted = true }
+ begin
canvas = Canvas.new(Reline.get_screen_size)
Reline::IOGate.set_winch_handler do
canvas = Canvas.new(Reline.get_screen_size)
@@ -133,12 +125,10 @@ module IRB
buff[0, 20] = "\e[0mPress Ctrl+C to stop\e[31m\e[1m"
print "\e[H" + buff
sleep 0.05
- break if interrupted
end
rescue Interrupt
ensure
print "\e[0m\e[?1049l"
- trap("SIGINT", prev_trap)
end
end
end
diff --git a/lib/irb/ext/change-ws.rb b/lib/irb/ext/change-ws.rb
index c0f810a4c8..4c57e44eab 100644
--- a/lib/irb/ext/change-ws.rb
+++ b/lib/irb/ext/change-ws.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# irb/ext/cb.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
class Context
diff --git a/lib/irb/ext/eval_history.rb b/lib/irb/ext/eval_history.rb
deleted file mode 100644
index 1a04178b40..0000000000
--- a/lib/irb/ext/eval_history.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: false
-#
-# history.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-module IRB # :nodoc:
-
- class Context
-
- NOPRINTING_IVARS.push "@eval_history_values"
-
- # See #set_last_value
- alias _set_last_value set_last_value
-
- def set_last_value(value)
- _set_last_value(value)
-
- if defined?(@eval_history) && @eval_history
- @eval_history_values.push @line_no, @last_value
- @workspace.evaluate "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
- end
-
- @last_value
- end
-
- remove_method :eval_history= if method_defined?(:eval_history=)
- # The command result history limit. This method is not available until
- # #eval_history= was called with non-nil value (directly or via
- # setting <code>IRB.conf[:EVAL_HISTORY]</code> in <code>.irbrc</code>).
- attr_reader :eval_history
- # Sets command result history limit. Default value is set from
- # <code>IRB.conf[:EVAL_HISTORY]</code>.
- #
- # +no+ is an Integer or +nil+.
- #
- # Returns +no+ of history items if greater than 0.
- #
- # If +no+ is 0, the number of history items is unlimited.
- #
- # If +no+ is +nil+, execution result history isn't used (default).
- #
- # EvalHistory values are available via <code>__</code> variable, see
- # IRB::EvalHistory.
- def eval_history=(no)
- if no
- if defined?(@eval_history) && @eval_history
- @eval_history_values.size(no)
- else
- @eval_history_values = EvalHistory.new(no)
- IRB.conf[:__TMP__EHV__] = @eval_history_values
- @workspace.evaluate("__ = IRB.conf[:__TMP__EHV__]")
- IRB.conf.delete(:__TMP_EHV__)
- end
- else
- @eval_history_values = nil
- end
- @eval_history = no
- end
- end
-
- # Represents history of results of previously evaluated commands.
- #
- # Available via <code>__</code> variable, only if <code>IRB.conf[:EVAL_HISTORY]</code>
- # or <code>IRB::CurrentContext().eval_history</code> is non-nil integer value
- # (by default it is +nil+).
- #
- # Example (in `irb`):
- #
- # # Initialize history
- # IRB::CurrentContext().eval_history = 10
- # # => 10
- #
- # # Perform some commands...
- # 1 + 2
- # # => 3
- # puts 'x'
- # # x
- # # => nil
- # raise RuntimeError
- # # ...error raised
- #
- # # Inspect history (format is "<item number> <evaluated value>":
- # __
- # # => 1 10
- # # 2 3
- # # 3 nil
- #
- # __[1]
- # # => 10
- #
- class EvalHistory
-
- def initialize(size = 16) # :nodoc:
- @size = size
- @contents = []
- end
-
- def size(size) # :nodoc:
- if size != 0 && size < @size
- @contents = @contents[@size - size .. @size]
- end
- @size = size
- end
-
- # Get one item of the content (both positive and negative indexes work).
- def [](idx)
- begin
- if idx >= 0
- @contents.find{|no, val| no == idx}[1]
- else
- @contents[idx][1]
- end
- rescue NameError
- nil
- end
- end
-
- def push(no, val) # :nodoc:
- @contents.push [no, val]
- @contents.shift if @size != 0 && @contents.size > @size
- end
-
- alias real_inspect inspect
-
- def inspect # :nodoc:
- if @contents.empty?
- return real_inspect
- end
-
- unless (last = @contents.pop)[1].equal?(self)
- @contents.push last
- last = nil
- end
- str = @contents.collect{|no, val|
- if val.equal?(self)
- "#{no} ...self-history..."
- else
- "#{no} #{val.inspect}"
- end
- }.join("\n")
- if str == ""
- str = "Empty."
- end
- @contents.push last if last
- str
- end
- end
-end
diff --git a/lib/irb/ext/history.rb b/lib/irb/ext/history.rb
new file mode 100644
index 0000000000..fc304c6f6c
--- /dev/null
+++ b/lib/irb/ext/history.rb
@@ -0,0 +1,155 @@
+# frozen_string_literal: false
+#
+# history.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+module IRB # :nodoc:
+
+ class Context
+
+ NOPRINTING_IVARS.push "@eval_history_values"
+
+ # See #set_last_value
+ alias _set_last_value set_last_value
+
+ def set_last_value(value)
+ _set_last_value(value)
+
+ if defined?(@eval_history) && @eval_history
+ @eval_history_values.push @line_no, @last_value
+ @workspace.evaluate self, "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
+ end
+
+ @last_value
+ end
+
+ remove_method :eval_history= if method_defined?(:eval_history=)
+ # The command result history limit. This method is not available until
+ # #eval_history= was called with non-nil value (directly or via
+ # setting <code>IRB.conf[:EVAL_HISTORY]</code> in <code>.irbrc</code>).
+ attr_reader :eval_history
+ # Sets command result history limit. Default value is set from
+ # <code>IRB.conf[:EVAL_HISTORY]</code>.
+ #
+ # +no+ is an Integer or +nil+.
+ #
+ # Returns +no+ of history items if greater than 0.
+ #
+ # If +no+ is 0, the number of history items is unlimited.
+ #
+ # If +no+ is +nil+, execution result history isn't used (default).
+ #
+ # History values are available via <code>__</code> variable, see
+ # IRB::History.
+ def eval_history=(no)
+ if no
+ if defined?(@eval_history) && @eval_history
+ @eval_history_values.size(no)
+ else
+ @eval_history_values = History.new(no)
+ IRB.conf[:__TMP__EHV__] = @eval_history_values
+ @workspace.evaluate(self, "__ = IRB.conf[:__TMP__EHV__]")
+ IRB.conf.delete(:__TMP_EHV__)
+ end
+ else
+ @eval_history_values = nil
+ end
+ @eval_history = no
+ end
+ end
+
+ # Represents history of results of previously evaluated commands.
+ #
+ # Available via <code>__</code> variable, only if <code>IRB.conf[:EVAL_HISTORY]</code>
+ # or <code>IRB::CurrentContext().eval_history</code> is non-nil integer value
+ # (by default it is +nil+).
+ #
+ # Example (in `irb`):
+ #
+ # # Initialize history
+ # IRB::CurrentContext().eval_history = 10
+ # # => 10
+ #
+ # # Perform some commands...
+ # 1 + 2
+ # # => 3
+ # puts 'x'
+ # # x
+ # # => nil
+ # raise RuntimeError
+ # # ...error raised
+ #
+ # # Inspect history (format is "<item number> <evaluated value>":
+ # __
+ # # => 1 10
+ # # 2 3
+ # # 3 nil
+ #
+ # __[1]
+ # # => 10
+ #
+ class History
+
+ def initialize(size = 16) # :nodoc:
+ @size = size
+ @contents = []
+ end
+
+ def size(size) # :nodoc:
+ if size != 0 && size < @size
+ @contents = @contents[@size - size .. @size]
+ end
+ @size = size
+ end
+
+ # Get one item of the content (both positive and negative indexes work).
+ def [](idx)
+ begin
+ if idx >= 0
+ @contents.find{|no, val| no == idx}[1]
+ else
+ @contents[idx][1]
+ end
+ rescue NameError
+ nil
+ end
+ end
+
+ def push(no, val) # :nodoc:
+ @contents.push [no, val]
+ @contents.shift if @size != 0 && @contents.size > @size
+ end
+
+ alias real_inspect inspect
+
+ def inspect # :nodoc:
+ if @contents.empty?
+ return real_inspect
+ end
+
+ unless (last = @contents.pop)[1].equal?(self)
+ @contents.push last
+ last = nil
+ end
+ str = @contents.collect{|no, val|
+ if val.equal?(self)
+ "#{no} ...self-history..."
+ else
+ "#{no} #{val.inspect}"
+ end
+ }.join("\n")
+ if str == ""
+ str = "Empty."
+ end
+ @contents.push last if last
+ str
+ end
+ end
+end
diff --git a/lib/irb/ext/loader.rb b/lib/irb/ext/loader.rb
index d65695df3b..af028996e7 100644
--- a/lib/irb/ext/loader.rb
+++ b/lib/irb/ext/loader.rb
@@ -1,8 +1,15 @@
# frozen_string_literal: false
#
# loader.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
+
module IRB # :nodoc:
# Raised in the event of an exception in a file loaded from an Irb session
@@ -24,8 +31,31 @@ module IRB # :nodoc:
load_file(path, priv)
end
+ if File.respond_to?(:absolute_path?)
+ def absolute_path?(path)
+ File.absolute_path?(path)
+ end
+ else
+ separator =
+ if File::ALT_SEPARATOR
+ "[#{Regexp.quote(File::SEPARATOR + File::ALT_SEPARATOR)}]"
+ else
+ File::SEPARATOR
+ end
+ ABSOLUTE_PATH_PATTERN = # :nodoc:
+ case Dir.pwd
+ when /\A\w:/, /\A#{separator}{2}/
+ /\A(?:\w:|#{separator})#{separator}/
+ else
+ /\A#{separator}/
+ end
+ def absolute_path?(path)
+ ABSOLUTE_PATH_PATTERN =~ path
+ end
+ end
+
def search_file_from_ruby_path(fn) # :nodoc:
- if File.absolute_path?(fn)
+ if absolute_path?(fn)
return fn if File.exist?(fn)
return nil
end
@@ -42,7 +72,6 @@ module IRB # :nodoc:
#
# See Irb#suspend_input_method for more information.
def source_file(path)
- irb = irb_context.irb
irb.suspend_name(path, File.basename(path)) do
FileInputMethod.open(path) do |io|
irb.suspend_input_method(io) do
@@ -67,7 +96,6 @@ module IRB # :nodoc:
#
# See Irb#suspend_input_method for more information.
def load_file(path, priv = nil)
- irb = irb_context.irb
irb.suspend_name(path, File.basename(path)) do
if priv
diff --git a/lib/irb/ext/multi-irb.rb b/lib/irb/ext/multi-irb.rb
index 1c20489137..e57d43a569 100644
--- a/lib/irb/ext/multi-irb.rb
+++ b/lib/irb/ext/multi-irb.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# irb/multi-irb.rb - multiple irb module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
class JobManager
diff --git a/lib/irb/ext/save-history.rb b/lib/irb/ext/save-history.rb
new file mode 100644
index 0000000000..9e7620545a
--- /dev/null
+++ b/lib/irb/ext/save-history.rb
@@ -0,0 +1,130 @@
+# frozen_string_literal: false
+# save-history.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+module IRB
+ module HistorySavingAbility # :nodoc:
+ end
+
+ class Context
+ def init_save_history# :nodoc:
+ unless (class<<@io;self;end).include?(HistorySavingAbility)
+ @io.extend(HistorySavingAbility)
+ end
+ end
+
+ # A copy of the default <code>IRB.conf[:SAVE_HISTORY]</code>
+ def save_history
+ IRB.conf[:SAVE_HISTORY]
+ end
+
+ remove_method(:save_history=) if method_defined?(:save_history=)
+ # Sets <code>IRB.conf[:SAVE_HISTORY]</code> to the given +val+ and calls
+ # #init_save_history with this context.
+ #
+ # Will store the number of +val+ entries of history in the #history_file
+ #
+ # Add the following to your +.irbrc+ to change the number of history
+ # entries stored to 1000:
+ #
+ # IRB.conf[:SAVE_HISTORY] = 1000
+ def save_history=(val)
+ IRB.conf[:SAVE_HISTORY] = val
+ if val
+ main_context = IRB.conf[:MAIN_CONTEXT]
+ main_context = self unless main_context
+ main_context.init_save_history
+ end
+ end
+
+ # A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
+ def history_file
+ IRB.conf[:HISTORY_FILE]
+ end
+
+ # Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
+ def history_file=(hist)
+ IRB.conf[:HISTORY_FILE] = hist
+ end
+ end
+
+ module HistorySavingAbility # :nodoc:
+ def HistorySavingAbility.extended(obj)
+ IRB.conf[:AT_EXIT].push proc{obj.save_history}
+ obj.load_history
+ obj
+ end
+
+ def load_history
+ return unless self.class.const_defined?(:HISTORY)
+ history = self.class::HISTORY
+ if history_file = IRB.conf[:HISTORY_FILE]
+ history_file = File.expand_path(history_file)
+ end
+ history_file = IRB.rc_file("_history") unless history_file
+ if File.exist?(history_file)
+ File.open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
+ f.each { |l|
+ l = l.chomp
+ if self.class == RelineInputMethod and history.last&.end_with?("\\")
+ history.last.delete_suffix!("\\")
+ history.last << "\n" << l
+ else
+ history << l
+ end
+ }
+ end
+ @loaded_history_lines = history.size
+ @loaded_history_mtime = File.mtime(history_file)
+ end
+ end
+
+ def save_history
+ return unless self.class.const_defined?(:HISTORY)
+ history = self.class::HISTORY
+ if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0
+ if history_file = IRB.conf[:HISTORY_FILE]
+ history_file = File.expand_path(history_file)
+ end
+ history_file = IRB.rc_file("_history") unless history_file
+
+ # Change the permission of a file that already exists[BUG #7694]
+ begin
+ if File.stat(history_file).mode & 066 != 0
+ File.chmod(0600, history_file)
+ end
+ rescue Errno::ENOENT
+ rescue Errno::EPERM
+ return
+ rescue
+ raise
+ end
+
+ if File.exist?(history_file) &&
+ File.mtime(history_file) != @loaded_history_mtime
+ history = history[@loaded_history_lines..-1] if @loaded_history_lines
+ append_history = true
+ end
+
+ File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
+ hist = history.map{ |l| l.split("\n").join("\\\n") }
+ unless append_history
+ begin
+ hist = hist.last(num) if hist.size > num and num > 0
+ rescue RangeError # bignum too big to convert into `long'
+ # Do nothing because the bignum should be treated as inifinity
+ end
+ end
+ f.puts(hist)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/irb/ext/tracer.rb b/lib/irb/ext/tracer.rb
index 3eaeb70ef2..67ac4bb965 100644
--- a/lib/irb/ext/tracer.rb
+++ b/lib/irb/ext/tracer.rb
@@ -1,14 +1,20 @@
# frozen_string_literal: false
#
# irb/lib/tracer.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
begin
require "tracer"
rescue LoadError
- $stderr.puts "Tracer extension of IRB is enabled but tracer gem wasn't found."
+ $stderr.puts "Tracer extension of IRB is enabled but tracer gem doesn't found."
module IRB
+ TracerLoadError = true
class Context
def use_tracer=(opt)
# do nothing
@@ -64,12 +70,12 @@ module IRB
if context.use_tracer? && file != nil && line != nil
Tracer.on
begin
- __evaluate__(statements, file, line)
+ __evaluate__(context, statements, file, line)
ensure
Tracer.off
end
else
- __evaluate__(statements, file || __FILE__, line || __LINE__)
+ __evaluate__(context, statements, file || __FILE__, line || __LINE__)
end
end
end
diff --git a/lib/irb/ext/use-loader.rb b/lib/irb/ext/use-loader.rb
index d0b8c2d4f4..1897bc89e0 100644
--- a/lib/irb/ext/use-loader.rb
+++ b/lib/irb/ext/use-loader.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# use-loader.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require_relative "../cmd/load"
require_relative "loader"
diff --git a/lib/irb/ext/workspaces.rb b/lib/irb/ext/workspaces.rb
index 9defc3e17b..730b58e64d 100644
--- a/lib/irb/ext/workspaces.rb
+++ b/lib/irb/ext/workspaces.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# push-ws.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
class Context
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
index 514293a438..d0829a06c4 100644
--- a/lib/irb/extend-command.rb
+++ b/lib/irb/extend-command.rb
@@ -1,9 +1,14 @@
# frozen_string_literal: false
#
# irb/extend-command.rb - irb extend command
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
module IRB # :nodoc:
# Installs the default irb extensions command bundle.
module ExtendCommandBundle
@@ -157,12 +162,8 @@ module IRB # :nodoc:
[
:irb_help, :Help, "cmd/help",
- [:help, NO_OVERRIDE],
- ],
-
- [
- :irb_show_doc, :ShowDoc, "cmd/show_doc",
[:show_doc, NO_OVERRIDE],
+ [:help, NO_OVERRIDE],
],
[
@@ -250,7 +251,7 @@ module IRB # :nodoc:
#
# The optional +load_file+ parameter will be required within the method
# definition.
- def self.def_extend_command(cmd_name, cmd_class, load_file, *aliases)
+ def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
case cmd_class
when Symbol
cmd_class = cmd_class.id2name
@@ -259,12 +260,34 @@ module IRB # :nodoc:
cmd_class = cmd_class.name
end
- line = __LINE__; eval %[
- def #{cmd_name}(*opts, **kwargs, &b)
- Kernel.require_relative "#{load_file}"
- ::IRB::ExtendCommand::#{cmd_class}.execute(irb_context, *opts, **kwargs, &b)
- end
- ], nil, __FILE__, line
+ if load_file
+ kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
+ line = __LINE__; eval %[
+ def #{cmd_name}(*opts#{kwargs}, &b)
+ require_relative "#{load_file}"
+ arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
+ args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
+ args << "*opts#{kwargs}" if arity < 0
+ args << "&block"
+ args = args.join(", ")
+ line = __LINE__; eval %[
+ unless singleton_class.class_variable_defined?(:@@#{cmd_name}_)
+ singleton_class.class_variable_set(:@@#{cmd_name}_, true)
+ def self.#{cmd_name}_(\#{args})
+ ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
+ end
+ end
+ ], nil, __FILE__, line
+ __send__ :#{cmd_name}_, *opts#{kwargs}, &b
+ end
+ ], nil, __FILE__, line
+ else
+ line = __LINE__; eval %[
+ def #{cmd_name}(*opts, &b)
+ ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
+ end
+ ], nil, __FILE__, line
+ end
for ali, flag in aliases
@ALIASES.push [ali, cmd_name, flag]
@@ -289,7 +312,7 @@ module IRB # :nodoc:
alias_method to, from
}
else
- Kernel.warn "irb: warn: can't alias #{to} from #{from}.\n"
+ Kernel.print "irb: warn: can't alias #{to} from #{from}.\n"
end
end
@@ -316,9 +339,10 @@ module IRB # :nodoc:
CE = ContextExtender # :nodoc:
@EXTEND_COMMANDS = [
- [:eval_history=, "ext/eval_history.rb"],
+ [:eval_history=, "ext/history.rb"],
[:use_tracer=, "ext/tracer.rb"],
[:use_loader=, "ext/use-loader.rb"],
+ [:save_history=, "ext/save-history.rb"],
]
# Installs the default context extensions as irb commands:
@@ -326,6 +350,7 @@ module IRB # :nodoc:
# Context#eval_history=:: +irb/ext/history.rb+
# Context#use_tracer=:: +irb/ext/tracer.rb+
# Context#use_loader=:: +irb/ext/use-loader.rb+
+ # Context#save_history=:: +irb/ext/save-history.rb+
def self.install_extend_commands
for args in @EXTEND_COMMANDS
def_extend_command(*args)
@@ -351,4 +376,58 @@ module IRB # :nodoc:
CE.install_extend_commands
end
+
+ # A convenience module for extending Ruby methods.
+ module MethodExtender
+ # Extends the given +base_method+ with a prefix call to the given
+ # +extend_method+.
+ def def_pre_proc(base_method, extend_method)
+ base_method = base_method.to_s
+ extend_method = extend_method.to_s
+
+ alias_name = new_alias_name(base_method)
+ module_eval %[
+ alias_method alias_name, base_method
+ def #{base_method}(*opts)
+ __send__ :#{extend_method}, *opts
+ __send__ :#{alias_name}, *opts
+ end
+ ]
+ end
+
+ # Extends the given +base_method+ with a postfix call to the given
+ # +extend_method+.
+ def def_post_proc(base_method, extend_method)
+ base_method = base_method.to_s
+ extend_method = extend_method.to_s
+
+ alias_name = new_alias_name(base_method)
+ module_eval %[
+ alias_method alias_name, base_method
+ def #{base_method}(*opts)
+ __send__ :#{alias_name}, *opts
+ __send__ :#{extend_method}, *opts
+ end
+ ]
+ end
+
+ # Returns a unique method name to use as an alias for the given +name+.
+ #
+ # Usually returns <code>#{prefix}#{name}#{postfix}<num></code>, example:
+ #
+ # new_alias_name('foo') #=> __alias_of__foo__
+ # def bar; end
+ # new_alias_name('bar') #=> __alias_of__bar__2
+ def new_alias_name(name, prefix = "__alias_of__", postfix = "__")
+ base_name = "#{prefix}#{name}#{postfix}"
+ all_methods = instance_methods(true) + private_instance_methods(true)
+ same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/)
+ return base_name if same_methods.empty?
+ no = same_methods.size
+ while !same_methods.include?(alias_name = base_name + no)
+ no += 1
+ end
+ alias_name
+ end
+ end
end
diff --git a/lib/irb/frame.rb b/lib/irb/frame.rb
index 14768bd8f6..de54a98f1b 100644
--- a/lib/irb/frame.rb
+++ b/lib/irb/frame.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# frame.rb -
+# $Release Version: 0.9$
+# $Revision$
# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd)
#
+# --
+#
+#
+#
module IRB
class Frame
diff --git a/lib/irb/help.rb b/lib/irb/help.rb
index ca12810de1..3eeaf841b0 100644
--- a/lib/irb/help.rb
+++ b/lib/irb/help.rb
@@ -1,8 +1,16 @@
# frozen_string_literal: false
#
# irb/help.rb - print usage module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#
+# --
+#
+#
+#
+
+require_relative 'magic-file'
module IRB
# Outputs the irb help message, see IRB@Command+line+options.
@@ -10,7 +18,7 @@ module IRB
lc = IRB.conf[:LC_MESSAGES]
path = lc.find("irb/help-message")
space_line = false
- File.open(path){|f|
+ IRB::MagicFile.open(path){|f|
f.each_line do |l|
if /^\s*$/ =~ l
lc.puts l unless space_line
diff --git a/lib/irb/history.rb b/lib/irb/history.rb
deleted file mode 100644
index 84d69e19cd..0000000000
--- a/lib/irb/history.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-module IRB
- module HistorySavingAbility # :nodoc:
- def support_history_saving?
- true
- end
-
- def reset_history_counter
- @loaded_history_lines = self.class::HISTORY.size if defined? @loaded_history_lines
- end
-
- def load_history
- history = self.class::HISTORY
-
- if history_file = IRB.conf[:HISTORY_FILE]
- history_file = File.expand_path(history_file)
- end
- history_file = IRB.rc_file("_history") unless history_file
- if File.exist?(history_file)
- File.open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
- f.each { |l|
- l = l.chomp
- if self.class == RelineInputMethod and history.last&.end_with?("\\")
- history.last.delete_suffix!("\\")
- history.last << "\n" << l
- else
- history << l
- end
- }
- end
- @loaded_history_lines = history.size
- @loaded_history_mtime = File.mtime(history_file)
- end
- end
-
- def save_history
- history = self.class::HISTORY.to_a
-
- if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0
- if history_file = IRB.conf[:HISTORY_FILE]
- history_file = File.expand_path(history_file)
- end
- history_file = IRB.rc_file("_history") unless history_file
-
- # Change the permission of a file that already exists[BUG #7694]
- begin
- if File.stat(history_file).mode & 066 != 0
- File.chmod(0600, history_file)
- end
- rescue Errno::ENOENT
- rescue Errno::EPERM
- return
- rescue
- raise
- end
-
- if File.exist?(history_file) &&
- File.mtime(history_file) != @loaded_history_mtime
- history = history[@loaded_history_lines..-1] if @loaded_history_lines
- append_history = true
- end
-
- File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
- hist = history.map{ |l| l.split("\n").join("\\\n") }
- unless append_history
- begin
- hist = hist.last(num) if hist.size > num and num > 0
- rescue RangeError # bignum too big to convert into `long'
- # Do nothing because the bignum should be treated as inifinity
- end
- end
- f.puts(hist)
- end
- end
- end
- end
-end
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index 470903b451..55453cc8f7 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -1,45 +1,16 @@
# frozen_string_literal: false
#
# irb/init.rb - irb initialize module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
- @CONF = {}
- # Displays current configuration.
- #
- # Modifying the configuration is achieved by sending a message to IRB.conf.
- #
- # See IRB@Configuration for more information.
- def IRB.conf
- @CONF
- end
-
- def @CONF.inspect
- array = []
- for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
- case k
- when :MAIN_CONTEXT, :__TMP__EHV__
- array.push format("CONF[:%s]=...myself...", k.id2name)
- when :PROMPT
- s = v.collect{
- |kk, vv|
- ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
- format(":%s=>{%s}", kk.id2name, ss.join(", "))
- }
- array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
- else
- array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
- end
- end
- array.join("\n")
- end
-
- # Returns the current version of IRB, including release version and last
- # updated date.
- def IRB.version
- format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
- end
# initialize config
def IRB.setup(ap_path, argv: ::ARGV)
@@ -63,7 +34,6 @@ module IRB # :nodoc:
unless ap_path and @CONF[:AP_NAME]
ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb")
end
- @CONF[:VERSION] = version
@CONF[:AP_NAME] = File::basename(ap_path, ".rb")
@CONF[:IRB_NAME] = "irb"
@@ -76,7 +46,6 @@ module IRB # :nodoc:
@CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
@CONF[:USE_COLORIZE] = (nc = ENV['NO_COLOR']).nil? || nc.empty?
@CONF[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "true") != "false"
- @CONF[:COMPLETOR] = :regexp
@CONF[:INSPECT_MODE] = true
@CONF[:USE_TRACER] = false
@CONF[:USE_LOADER] = false
@@ -95,30 +64,35 @@ module IRB # :nodoc:
@CONF[:PROMPT] = {
:NULL => {
:PROMPT_I => nil,
+ :PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => "%s\n"
},
:DEFAULT => {
- :PROMPT_I => "%N(%m):%03n> ",
- :PROMPT_S => "%N(%m):%03n%l ",
- :PROMPT_C => "%N(%m):%03n* ",
+ :PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => "%N(%m):%03n:%i> ",
+ :PROMPT_S => "%N(%m):%03n:%i%l ",
+ :PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "=> %s\n"
},
:CLASSIC => {
:PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "%s\n"
},
:SIMPLE => {
:PROMPT_I => ">> ",
+ :PROMPT_N => ">> ",
:PROMPT_S => "%l> ",
:PROMPT_C => "?> ",
:RETURN => "=> %s\n"
},
:INF_RUBY => {
- :PROMPT_I => "%N(%m):%03n> ",
+ :PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => "%s\n",
@@ -126,6 +100,7 @@ module IRB # :nodoc:
},
:XMP => {
:PROMPT_I => nil,
+ :PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => " ==>%s\n"
@@ -330,10 +305,6 @@ module IRB # :nodoc:
@CONF[:USE_AUTOCOMPLETE] = true
when "--noautocomplete"
@CONF[:USE_AUTOCOMPLETE] = false
- when "--regexp-completor"
- @CONF[:COMPLETOR] = :regexp
- when "--type-completor"
- @CONF[:COMPLETOR] = :type
when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/
opt = $1 || argv.shift
prompt_mode = opt.upcase.tr("-", "_").intern
@@ -436,9 +407,9 @@ module IRB # :nodoc:
end
if home = ENV["HOME"]
yield proc{|rc| home+"/.irb#{rc}"}
- yield proc{|rc| home+"/.config/irb/irb#{rc}"}
end
current_dir = Dir.pwd
+ yield proc{|rc| current_dir+"/.config/irb/irb#{rc}"}
yield proc{|rc| current_dir+"/.irb#{rc}"}
yield proc{|rc| current_dir+"/irb#{rc.sub(/\A_?/, '.')}"}
yield proc{|rc| current_dir+"/_irb#{rc}"}
@@ -456,6 +427,8 @@ module IRB # :nodoc:
end
end
+
+ DefaultEncodings = Struct.new(:external, :internal)
class << IRB
private
def set_encoding(extern, intern = nil, override: true)
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index 94ad28cd63..9480573195 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -1,17 +1,30 @@
# frozen_string_literal: false
#
# irb/input-method.rb - input methods used irb
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
+require_relative 'src_encoding'
+require_relative 'magic-file'
require_relative 'completion'
-require_relative "history"
require 'io/console'
require 'reline'
module IRB
+ STDIN_FILE_NAME = "(line)" # :nodoc:
class InputMethod
- BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
+
+ # Creates a new input method object
+ def initialize(file = STDIN_FILE_NAME)
+ @file_name = file
+ end
+ # The file name of this input method, usually given during initialization.
+ attr_reader :file_name
# The irb prompt associated with this input method
attr_accessor :prompt
@@ -40,10 +53,6 @@ module IRB
false
end
- def support_history_saving?
- false
- end
-
# For debug message
def inspect
'Abstract InputMethod'
@@ -53,6 +62,7 @@ module IRB
class StdioInputMethod < InputMethod
# Creates a new input method object
def initialize
+ super
@line_no = 0
@line = []
@stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
@@ -126,9 +136,12 @@ module IRB
# Creates a new input method object
def initialize(file)
- @io = file.is_a?(IO) ? file : File.open(file)
+ super
+ @io = file.is_a?(IO) ? file : IRB::MagicFile.open(file)
@external_encoding = @io.external_encoding
end
+ # The file name of this input method, usually given during initialization.
+ attr_reader :file_name
# Whether the end of this input method has been reached, returns +true+ if
# there is no more data to read.
@@ -161,95 +174,114 @@ module IRB
end
end
- class ReadlineInputMethod < StdioInputMethod
- def self.initialize_readline
- require "readline"
- rescue LoadError
- else
- include ::Readline
- end
+ begin
+ class ReadlineInputMethod < InputMethod
+ def self.initialize_readline
+ require "readline"
+ rescue LoadError
+ else
+ include ::Readline
+ end
- include HistorySavingAbility
+ # Creates a new input method object using Readline
+ def initialize
+ self.class.initialize_readline
+ if Readline.respond_to?(:encoding_system_needs)
+ IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
+ end
+ super
- # Creates a new input method object using Readline
- def initialize
- self.class.initialize_readline
- if Readline.respond_to?(:encoding_system_needs)
- IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
- end
+ @line_no = 0
+ @line = []
+ @eof = false
- super
+ @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+ @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
- @eof = false
- @completor = RegexpCompletor.new
+ if Readline.respond_to?("basic_word_break_characters=")
+ Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
+ end
+ Readline.completion_append_character = nil
+ Readline.completion_proc = IRB::InputCompletor::CompletionProc
+ end
- if Readline.respond_to?("basic_word_break_characters=")
- Readline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
+ # Reads the next line from this input method.
+ #
+ # See IO#gets for more information.
+ def gets
+ Readline.input = @stdin
+ Readline.output = @stdout
+ if l = readline(@prompt, false)
+ HISTORY.push(l) if !l.empty?
+ @line[@line_no += 1] = l + "\n"
+ else
+ @eof = true
+ l
+ end
end
- Readline.completion_append_character = nil
- Readline.completion_proc = ->(target) {
- bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
- @completor.completion_candidates('', target, '', bind: bind)
- }
- end
- def completion_info
- 'RegexpCompletor'
- end
+ # Whether the end of this input method has been reached, returns +true+
+ # if there is no more data to read.
+ #
+ # See IO#eof? for more information.
+ def eof?
+ @eof
+ end
- # Reads the next line from this input method.
- #
- # See IO#gets for more information.
- def gets
- Readline.input = @stdin
- Readline.output = @stdout
- if l = readline(@prompt, false)
- HISTORY.push(l) if !l.empty?
- @line[@line_no += 1] = l + "\n"
- else
- @eof = true
- l
+ # Whether this input method is still readable when there is no more data to
+ # read.
+ #
+ # See IO#eof for more information.
+ def readable_after_eof?
+ true
end
- end
- # Whether the end of this input method has been reached, returns +true+
- # if there is no more data to read.
- #
- # See IO#eof? for more information.
- def eof?
- @eof
- end
+ # Returns the current line number for #io.
+ #
+ # #line counts the number of times #gets is called.
+ #
+ # See IO#lineno for more information.
+ def line(line_no)
+ @line[line_no]
+ end
- # For debug message
- def inspect
- readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline'
- str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}"
- inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
- str += " and #{inputrc_path}" if File.exist?(inputrc_path)
- str
+ # The external encoding for standard input.
+ def encoding
+ @stdin.external_encoding
+ end
+
+ # For debug message
+ def inspect
+ readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline'
+ str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}"
+ inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
+ str += " and #{inputrc_path}" if File.exist?(inputrc_path)
+ str
+ end
end
end
- class RelineInputMethod < StdioInputMethod
- HISTORY = Reline::HISTORY
- include HistorySavingAbility
+ class RelineInputMethod < InputMethod
+ include Reline
+
# Creates a new input method object using Reline
- def initialize(completor)
+ def initialize
IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)
+ super
- super()
-
+ @line_no = 0
+ @line = []
@eof = false
- @completor = completor
- Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
+ @stdin = ::IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+ @stdout = ::IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+
+ if Reline.respond_to?("basic_word_break_characters=")
+ Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
+ end
Reline.completion_append_character = nil
Reline.completer_quote_characters = ''
- Reline.completion_proc = ->(target, preposing, postposing) {
- bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
- @completion_params = [preposing, target, postposing, bind]
- @completor.completion_candidates(preposing, target, postposing, bind: bind)
- }
+ Reline.completion_proc = IRB::InputCompletor::CompletionProc
Reline.output_modifier_proc =
if IRB.conf[:USE_COLORIZE]
proc do |output, complete: |
@@ -262,23 +294,18 @@ module IRB
Reline::Unicode.escape_for_print(output)
end
end
- Reline.dig_perfect_match_proc = ->(matched) { display_document(matched) }
+ Reline.dig_perfect_match_proc = IRB::InputCompletor::PerfectMatchedProc
Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
if IRB.conf[:USE_AUTOCOMPLETE]
begin
require 'rdoc'
- Reline.add_dialog_proc(:show_doc, show_doc_dialog_proc, Reline::DEFAULT_DIALOG_CONTEXT)
+ Reline.add_dialog_proc(:show_doc, SHOW_DOC_DIALOG, Reline::DEFAULT_DIALOG_CONTEXT)
rescue LoadError
end
end
end
- def completion_info
- autocomplete_message = Reline.autocompletion ? 'Autocomplete' : 'Tab Complete'
- "#{autocomplete_message}, #{@completor.inspect}"
- end
-
def check_termination(&block)
@check_termination_proc = block
end
@@ -291,152 +318,98 @@ module IRB
@auto_indent_proc = block
end
- def show_doc_dialog_proc
- doc_namespace = ->(matched) {
- preposing, _target, postposing, bind = @completion_params
- @completor.doc_namespace(preposing, matched, postposing, bind: bind)
- }
- ->() {
- dialog.trap_key = nil
- alt_d = [
- [Reline::Key.new(nil, 0xE4, true)], # Normal Alt+d.
- [27, 100], # Normal Alt+d when convert-meta isn't used.
- [195, 164], # The "ä" that appears when Alt+d is pressed on xterm.
- [226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2.
- ]
-
- if just_cursor_moving and completion_journey_data.nil?
- return nil
- end
- cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
- return nil if result.nil? or pointer.nil? or pointer < 0
+ SHOW_DOC_DIALOG = ->() {
+ dialog.trap_key = nil
+ alt_d = [
+ [Reline::Key.new(nil, 0xE4, true)], # Normal Alt+d.
+ [27, 100], # Normal Alt+d when convert-meta isn't used.
+ [195, 164], # The "ä" that appears when Alt+d is pressed on xterm.
+ [226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2.
+ ]
- name = doc_namespace.call(result[pointer])
- show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
+ if just_cursor_moving and completion_journey_data.nil?
+ return nil
+ end
+ cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
+ return nil if result.nil? or pointer.nil? or pointer < 0
+ name = result[pointer]
+ name = IRB::InputCompletor.retrieve_completion_data(name, doc_namespace: true)
- options = {}
- options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
- driver = RDoc::RI::Driver.new(options)
+ options = {}
+ options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
+ driver = RDoc::RI::Driver.new(options)
- if key.match?(dialog.name)
- if show_easter_egg
- IRB.__send__(:easter_egg)
- else
- begin
- driver.display_names([name])
- rescue RDoc::RI::Driver::NotFoundError
- end
- end
+ if key.match?(dialog.name)
+ begin
+ driver.display_names([name])
+ rescue RDoc::RI::Driver::NotFoundError
end
+ end
+ begin
+ name = driver.expand_name(name)
+ rescue RDoc::RI::Driver::NotFoundError
+ return nil
+ rescue
+ return nil # unknown error
+ end
+ doc = nil
+ used_for_class = false
+ if not name =~ /#|\./
+ found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
+ if not found.empty?
+ doc = driver.class_document(name, found, klasses, includes, extends)
+ used_for_class = true
+ end
+ end
+ unless used_for_class
+ doc = RDoc::Markup::Document.new
begin
- name = driver.expand_name(name)
+ driver.add_method(doc, name)
rescue RDoc::RI::Driver::NotFoundError
- return nil
+ doc = nil
rescue
return nil # unknown error
end
- doc = nil
- used_for_class = false
- if not name =~ /#|\./
- found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
- if not found.empty?
- doc = driver.class_document(name, found, klasses, includes, extends)
- used_for_class = true
- end
- end
- unless used_for_class
- doc = RDoc::Markup::Document.new
- begin
- driver.add_method(doc, name)
- rescue RDoc::RI::Driver::NotFoundError
- doc = nil
- rescue
- return nil # unknown error
- end
- end
- return nil if doc.nil?
- width = 40
-
- right_x = cursor_pos_to_render.x + autocomplete_dialog.width
- if right_x + width > screen_width
- right_width = screen_width - (right_x + 1)
- left_x = autocomplete_dialog.column - width
- left_x = 0 if left_x < 0
- left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
- if right_width.positive? and left_width.positive?
- if right_width >= left_width
- width = right_width
- x = right_x
- else
- width = left_width
- x = left_x
- end
- elsif right_width.positive? and left_width <= 0
+ end
+ return nil if doc.nil?
+ width = 40
+
+ right_x = cursor_pos_to_render.x + autocomplete_dialog.width
+ if right_x + width > screen_width
+ right_width = screen_width - (right_x + 1)
+ left_x = autocomplete_dialog.column - width
+ left_x = 0 if left_x < 0
+ left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
+ if right_width.positive? and left_width.positive?
+ if right_width >= left_width
width = right_width
x = right_x
- elsif right_width <= 0 and left_width.positive?
+ else
width = left_width
x = left_x
- else # Both are negative width.
- return nil
end
- else
+ elsif right_width.positive? and left_width <= 0
+ width = right_width
x = right_x
+ elsif right_width <= 0 and left_width.positive?
+ width = left_width
+ x = left_x
+ else # Both are negative width.
+ return nil
end
- formatter = RDoc::Markup::ToAnsi.new
- formatter.width = width
- dialog.trap_key = alt_d
- mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
- if show_easter_egg
- type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode : :ascii
- contents = IRB.send(:easter_egg_logo, type).split("\n")
- message = "Press #{mod_key}+d to see more"
- contents[0][0, message.size] = message
- else
- message = "Press #{mod_key}+d to read the full document"
- contents = [message] + doc.accept(formatter).split("\n")
- end
- contents = contents.take(preferred_dialog_height)
-
- y = cursor_pos_to_render.y
- Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
- }
- end
-
- def display_document(matched, driver: nil)
- begin
- require 'rdoc'
- rescue LoadError
- return
- end
-
- if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
- IRB.__send__(:easter_egg)
- return
- end
-
- _target, preposing, postposing, bind = @completion_params
- namespace = @completor.doc_namespace(preposing, matched, postposing, bind: bind)
- return unless namespace
-
- driver ||= RDoc::RI::Driver.new
- if namespace.is_a?(Array)
- out = RDoc::Markup::Document.new
- namespace.each do |m|
- begin
- driver.add_method(out, m)
- rescue RDoc::RI::Driver::NotFoundError
- end
- end
- driver.display(out)
else
- begin
- driver.display_names([namespace])
- rescue RDoc::RI::Driver::NotFoundError
- end
+ x = right_x
end
- end
+ formatter = RDoc::Markup::ToAnsi.new
+ formatter.width = width
+ dialog.trap_key = alt_d
+ message = 'Press Alt+d to read the full document'
+ contents = [message] + doc.accept(formatter).split("\n")
+
+ y = cursor_pos_to_render.y
+ DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
+ }
# Reads the next line from this input method.
#
@@ -446,8 +419,8 @@ module IRB
Reline.output = @stdout
Reline.prompt_proc = @prompt_proc
Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc
- if l = Reline.readmultiline(@prompt, false, &@check_termination_proc)
- Reline::HISTORY.push(l) if !l.empty?
+ if l = readmultiline(@prompt, false, &@check_termination_proc)
+ HISTORY.push(l) if !l.empty?
@line[@line_no += 1] = l + "\n"
else
@eof = true
@@ -463,11 +436,37 @@ module IRB
@eof
end
+ # Whether this input method is still readable when there is no more data to
+ # read.
+ #
+ # See IO#eof for more information.
+ def readable_after_eof?
+ true
+ end
+
+ # Returns the current line number for #io.
+ #
+ # #line counts the number of times #gets is called.
+ #
+ # See IO#lineno for more information.
+ def line(line_no)
+ @line[line_no]
+ end
+
+ # The external encoding for standard input.
+ def encoding
+ @stdin.external_encoding
+ end
+
# For debug message
def inspect
config = Reline::Config.new
str = "RelineInputMethod with Reline #{Reline::VERSION}"
- inputrc_path = File.expand_path(config.inputrc_path)
+ if config.respond_to?(:inputrc_path)
+ inputrc_path = File.expand_path(config.inputrc_path)
+ else
+ inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
+ end
str += " and #{inputrc_path}" if File.exist?(inputrc_path)
str
end
diff --git a/lib/irb/inspector.rb b/lib/irb/inspector.rb
index ee3b19efdc..d8c0ba90cf 100644
--- a/lib/irb/inspector.rb
+++ b/lib/irb/inspector.rb
@@ -1,8 +1,15 @@
# frozen_string_literal: false
#
# irb/inspector.rb - inspect methods
+# $Release Version: 0.9.6$
+# $Revision: 1.19 $
+# $Date: 2002/06/11 07:51:31 $
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
@@ -35,7 +42,6 @@ module IRB # :nodoc:
# irb(main):001:0> "what?" #=> omg! what?
#
class Inspector
- KERNEL_INSPECT = Object.instance_method(:inspect)
# Default inspectors available to irb, this includes:
#
# +:pp+:: Using Kernel#pretty_inspect
@@ -94,17 +100,9 @@ module IRB # :nodoc:
# Proc to call when the input is evaluated and output in irb.
def inspect_value(v)
@inspect.call(v)
- rescue => e
- puts "An error occurred when inspecting the object: #{e.inspect}"
-
- begin
- puts "Result of Kernel#inspect: #{KERNEL_INSPECT.bind_call(v)}"
- ''
- rescue => e
- puts "An error occurred when running Kernel#inspect: #{e.inspect}"
- puts e.backtrace.join("\n")
- ''
- end
+ rescue
+ puts "(Object doesn't support #inspect)"
+ ''
end
end
diff --git a/lib/irb/irb.gemspec b/lib/irb/irb.gemspec
index a008a39f9d..c3e8a4dc58 100644
--- a/lib/irb/irb.gemspec
+++ b/lib/irb/irb.gemspec
@@ -16,11 +16,6 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/irb"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
- spec.metadata["documentation_uri"] = spec.homepage
- spec.metadata["changelog_uri"] = "#{spec.homepage}/releases"
-
spec.files = [
".document",
"Gemfile",
@@ -39,8 +34,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6")
- spec.add_dependency "reline", ">= 0.3.8"
- spec.add_dependency "rdoc"
+ spec.add_dependency "reline", ">= 0.3.0"
end
diff --git a/lib/irb/lc/error.rb b/lib/irb/lc/error.rb
index a5ec150865..cb5c21cdb4 100644
--- a/lib/irb/lc/error.rb
+++ b/lib/irb/lc/error.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# irb/lc/error.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
# :stopdoc:
diff --git a/lib/irb/lc/help-message b/lib/irb/lc/help-message
index c7846b755d..5b23f4c41e 100644
--- a/lib/irb/lc/help-message
+++ b/lib/irb/lc/help-message
@@ -22,17 +22,14 @@ Usage: irb.rb [options] [programfile] [arguments]
Show truncated result on assignment (default).
--inspect Use 'inspect' for output.
--noinspect Don't use 'inspect' for output.
- --multiline Use multiline editor module (default).
- --nomultiline Don't use multiline editor module.
+ --multiline Use multiline editor module.
+ --nomultiline Don't use multiline editor module (default).
--singleline Use single line editor module.
--nosingleline Don't use single line editor module (default).
--colorize Use color-highlighting (default).
--nocolorize Don't use color-highlighting.
--autocomplete Use auto-completion (default).
--noautocomplete Don't use auto-completion.
- --regexp-completor
- Use regexp based completion (default).
- --type-completor Use type based completion.
--prompt prompt-mode, --prompt-mode prompt-mode
Set prompt mode. Pre-defined prompt modes are:
'default', 'classic', 'simple', 'inf-ruby', 'xmp', 'null'.
diff --git a/lib/irb/lc/ja/encoding_aliases.rb b/lib/irb/lc/ja/encoding_aliases.rb
new file mode 100644
index 0000000000..08180c3ec2
--- /dev/null
+++ b/lib/irb/lc/ja/encoding_aliases.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: false
+module IRB
+ # :stopdoc:
+
+ class Locale
+ @@legacy_encoding_alias_map = {
+ 'ujis' => Encoding::EUC_JP,
+ 'euc' => Encoding::EUC_JP
+ }.freeze
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/lc/ja/error.rb b/lib/irb/lc/ja/error.rb
index 50d72c4a10..5e3622cbae 100644
--- a/lib/irb/lc/ja/error.rb
+++ b/lib/irb/lc/ja/error.rb
@@ -1,8 +1,14 @@
+# -*- coding: utf-8 -*-
# frozen_string_literal: false
-#
# irb/lc/ja/error.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
# :stopdoc:
diff --git a/lib/irb/lc/ja/help-message b/lib/irb/lc/ja/help-message
index cec339cf2f..1c15d331ea 100644
--- a/lib/irb/lc/ja/help-message
+++ b/lib/irb/lc/ja/help-message
@@ -21,9 +21,6 @@ Usage: irb.rb [options] [programfile] [arguments]
--nocolorize 色付けを利用しない.
--autocomplete オートコンプリートを利用する.
--noautocomplete オートコンプリートを利用しない.
- --regexp-completor
- 補完に正規表現を利用する.
- --type-completor 補完に型情報を利用する.
--prompt prompt-mode/--prompt-mode prompt-mode
プロンプトモードを切替えます. 現在定義されているプ
ロンプトモードは, default, simple, xmp, inf-rubyが
diff --git a/lib/irb/locale.rb b/lib/irb/locale.rb
index f94aa0f40b..bb44b41002 100644
--- a/lib/irb/locale.rb
+++ b/lib/irb/locale.rb
@@ -1,9 +1,14 @@
# frozen_string_literal: false
#
# irb/locale.rb - internationalization module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
module IRB # :nodoc:
class Locale
@@ -15,11 +20,7 @@ module IRB # :nodoc:
]x
LOCALE_DIR = "/lc/"
- LEGACY_ENCODING_ALIAS_MAP = {
- 'ujis' => Encoding::EUC_JP,
- 'euc' => Encoding::EUC_JP
- }
-
+ @@legacy_encoding_alias_map = {}.freeze
@@loaded = []
def initialize(locale = nil)
@@ -30,11 +31,11 @@ module IRB # :nodoc:
@lang, @territory, @encoding_name, @modifier = m[:language], m[:territory], m[:codeset], m[:modifier]
if @encoding_name
- if @encoding = LEGACY_ENCODING_ALIAS_MAP[@encoding_name]
+ begin load 'irb/encoding_aliases.rb'; rescue LoadError; end
+ if @encoding = @@legacy_encoding_alias_map[@encoding_name]
warn(("%s is obsolete. use %s" % ["#{@lang}_#{@territory}.#{@encoding_name}", "#{@lang}_#{@territory}.#{@encoding.name}"]), uplevel: 1)
- else
- @encoding = Encoding.find(@encoding_name) rescue nil
end
+ @encoding = Encoding.find(@encoding_name) rescue nil
end
end
@encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
@@ -82,12 +83,39 @@ module IRB # :nodoc:
super(*ary)
end
- def load(file)
+ def require(file, priv = nil)
+ rex = Regexp.new("lc/#{Regexp.quote(file)}\.(so|o|sl|rb)?")
+ return false if $".find{|f| f =~ rex}
+
+ case file
+ when /\.rb$/
+ begin
+ load(file, priv)
+ $".push file
+ return true
+ rescue LoadError
+ end
+ when /\.(so|o|sl)$/
+ return super
+ end
+
+ begin
+ load(f = file + ".rb")
+ $".push f #"
+ return true
+ rescue LoadError
+ return ruby_require(file)
+ end
+ end
+
+ alias toplevel_load load
+
+ def load(file, priv=nil)
found = find(file)
if found
unless @@loaded.include?(found)
@@loaded << found # cache
- Kernel.load(found)
+ return real_load(found, priv)
end
else
raise LoadError, "No such file to load -- #{file}"
@@ -106,6 +134,16 @@ module IRB # :nodoc:
end
end
+ private
+ def real_load(path, priv)
+ src = MagicFile.open(path){|f| f.read}
+ if priv
+ eval("self", TOPLEVEL_BINDING).extend(Module.new {eval(src, nil, path)})
+ else
+ eval(src, TOPLEVEL_BINDING, path)
+ end
+ end
+
# @param paths load paths in which IRB find a localized file.
# @param dir directory
# @param file basename to be localized
diff --git a/lib/irb/magic-file.rb b/lib/irb/magic-file.rb
new file mode 100644
index 0000000000..34e06d64b3
--- /dev/null
+++ b/lib/irb/magic-file.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: false
+module IRB
+ class << (MagicFile = Object.new)
+ # see parser_magic_comment in parse.y
+ ENCODING_SPEC_RE = %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
+
+ def open(path)
+ io = File.open(path, 'rb')
+ line = io.gets
+ line = io.gets if line[0,2] == "#!"
+ encoding = detect_encoding(line)
+ internal_encoding = encoding
+ encoding ||= IRB.default_src_encoding
+ io.rewind
+ io.set_encoding(encoding, internal_encoding)
+
+ if block_given?
+ begin
+ return (yield io)
+ ensure
+ io.close
+ end
+ else
+ return io
+ end
+ end
+
+ private
+ def detect_encoding(line)
+ return unless line[0] == ?#
+ line = line[1..-1]
+ line = $1 if line[/-\*-\s*(.*?)\s*-*-$/]
+ return nil unless ENCODING_SPEC_RE =~ line
+ encoding = $1
+ return encoding.sub(/-(?:mac|dos|unix)/i, '')
+ end
+ end
+end
diff --git a/lib/irb/nesting_parser.rb b/lib/irb/nesting_parser.rb
deleted file mode 100644
index 3d4db82444..0000000000
--- a/lib/irb/nesting_parser.rb
+++ /dev/null
@@ -1,227 +0,0 @@
-# frozen_string_literal: true
-module IRB
- module NestingParser
- IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
-
- # Scan each token and call the given block with array of token and other information for parsing
- def self.scan_opens(tokens)
- opens = []
- pending_heredocs = []
- first_token_on_line = true
- tokens.each do |t|
- skip = false
- last_tok, state, args = opens.last
- case state
- when :in_unquoted_symbol
- unless IGNORE_TOKENS.include?(t.event)
- opens.pop
- skip = true
- end
- when :in_lambda_head
- opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
- when :in_method_head
- unless IGNORE_TOKENS.include?(t.event)
- next_args = []
- body = nil
- if args.include?(:receiver)
- case t.event
- when :on_lparen, :on_ivar, :on_gvar, :on_cvar
- # def (receiver). | def @ivar. | def $gvar. | def @@cvar.
- next_args << :dot
- when :on_kw
- case t.tok
- when 'self', 'true', 'false', 'nil'
- # def self(arg) | def self.
- next_args.push(:arg, :dot)
- else
- # def if(arg)
- skip = true
- next_args << :arg
- end
- when :on_op, :on_backtick
- # def +(arg)
- skip = true
- next_args << :arg
- when :on_ident, :on_const
- # def a(arg) | def a.
- next_args.push(:arg, :dot)
- end
- end
- if args.include?(:dot)
- # def receiver.name
- next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
- end
- if args.include?(:name)
- if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
- # def name(arg) | def receiver.name(arg)
- next_args << :arg
- skip = true
- end
- end
- if args.include?(:arg)
- case t.event
- when :on_nl, :on_semicolon
- # def recever.f;
- body = :normal
- when :on_lparen
- # def recever.f()
- next_args << :eq
- else
- if t.event == :on_op && t.tok == '='
- # def receiver.f =
- body = :oneliner
- else
- # def recever.f arg
- next_args << :arg_without_paren
- end
- end
- end
- if args.include?(:eq)
- if t.event == :on_op && t.tok == '='
- body = :oneliner
- else
- body = :normal
- end
- end
- if args.include?(:arg_without_paren)
- if %i[on_semicolon on_nl].include?(t.event)
- # def f a;
- body = :normal
- else
- # def f a, b
- next_args << :arg_without_paren
- end
- end
- if body == :oneliner
- opens.pop
- elsif body
- opens[-1] = [last_tok, nil]
- else
- opens[-1] = [last_tok, :in_method_head, next_args]
- end
- end
- when :in_for_while_until_condition
- if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
- skip = true if t.event == :on_kw && t.tok == 'do'
- opens[-1] = [last_tok, nil]
- end
- end
-
- unless skip
- case t.event
- when :on_kw
- case t.tok
- when 'begin', 'class', 'module', 'do', 'case'
- opens << [t, nil]
- when 'end'
- opens.pop
- when 'def'
- opens << [t, :in_method_head, [:receiver, :name]]
- when 'if', 'unless'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens << [t, nil]
- end
- when 'while', 'until'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens << [t, :in_for_while_until_condition]
- end
- when 'ensure', 'rescue'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens.pop
- opens << [t, nil]
- end
- when 'elsif', 'else', 'when'
- opens.pop
- opens << [t, nil]
- when 'for'
- opens << [t, :in_for_while_until_condition]
- when 'in'
- if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
- opens.pop
- opens << [t, nil]
- end
- end
- when :on_tlambda
- opens << [t, :in_lambda_head]
- when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
- opens << [t, nil]
- when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
- opens.pop
- when :on_heredoc_beg
- pending_heredocs << t
- when :on_heredoc_end
- opens.pop
- when :on_backtick
- opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG)
- when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
- opens << [t, nil]
- when :on_tstring_end, :on_regexp_end, :on_label_end
- opens.pop
- when :on_symbeg
- if t.tok == ':'
- opens << [t, :in_unquoted_symbol]
- else
- opens << [t, nil]
- end
- end
- end
- if t.event == :on_nl || t.event == :on_semicolon
- first_token_on_line = true
- elsif t.event != :on_sp
- first_token_on_line = false
- end
- if pending_heredocs.any? && t.tok.include?("\n")
- pending_heredocs.reverse_each { |t| opens << [t, nil] }
- pending_heredocs = []
- end
- yield t, opens if block_given?
- end
- opens.map(&:first) + pending_heredocs.reverse
- end
-
- def self.open_tokens(tokens)
- # scan_opens without block will return a list of open tokens at last token position
- scan_opens(tokens)
- end
-
- # Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
- # Example code
- # ["hello
- # world"+(
- # First line
- # line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
- # prev_opens: []
- # next_tokens: [lbracket, tstring_beg]
- # min_depth: 0 (minimum at beginning of line)
- # Second line
- # line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
- # prev_opens: [lbracket, tstring_beg]
- # next_tokens: [lbracket, lparen]
- # min_depth: 1 (minimum just after tstring_end)
- def self.parse_by_line(tokens)
- line_tokens = []
- prev_opens = []
- min_depth = 0
- output = []
- last_opens = scan_opens(tokens) do |t, opens|
- depth = t == opens.last&.first ? opens.size - 1 : opens.size
- min_depth = depth if depth < min_depth
- if t.tok.include?("\n")
- t.tok.each_line do |line|
- line_tokens << [t, line]
- next if line[-1] != "\n"
- next_opens = opens.map(&:first)
- output << [line_tokens, prev_opens, next_opens, min_depth]
- prev_opens = next_opens
- min_depth = prev_opens.size
- line_tokens = []
- end
- else
- line_tokens << [t, t.tok]
- end
- end
- output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
- output
- end
- end
-end
diff --git a/lib/irb/notifier.rb b/lib/irb/notifier.rb
index 612de3df16..d0e413dd68 100644
--- a/lib/irb/notifier.rb
+++ b/lib/irb/notifier.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# notifier.rb - output methods used by irb
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require_relative "output-method"
diff --git a/lib/irb/output-method.rb b/lib/irb/output-method.rb
index f5ea57111d..3fda708cb0 100644
--- a/lib/irb/output-method.rb
+++ b/lib/irb/output-method.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# output-method.rb - output methods used by irb
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
# An abstract output class for IO in irb. This is mainly used internally by
diff --git a/lib/irb/pager.rb b/lib/irb/pager.rb
deleted file mode 100644
index 1194e41f6f..0000000000
--- a/lib/irb/pager.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # The implementation of this class is borrowed from RDoc's lib/rdoc/ri/driver.rb.
- # Please do NOT use this class directly outside of IRB.
- class Pager
- PAGE_COMMANDS = [ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq
-
- class << self
- def page_content(content)
- if content_exceeds_screen_height?(content)
- page do |io|
- io.puts content
- end
- else
- $stdout.puts content
- end
- end
-
- def page
- if STDIN.tty? && pager = setup_pager
- begin
- pid = pager.pid
- yield pager
- ensure
- pager.close
- end
- else
- yield $stdout
- end
- # When user presses Ctrl-C, IRB would raise `IRB::Abort`
- # But since Pager is implemented by running paging commands like `less` in another process with `IO.popen`,
- # the `IRB::Abort` exception only interrupts IRB's execution but doesn't affect the pager
- # So to properly terminate the pager with Ctrl-C, we need to catch `IRB::Abort` and kill the pager process
- rescue IRB::Abort
- Process.kill("TERM", pid) if pid
- nil
- rescue Errno::EPIPE
- end
-
- private
-
- def content_exceeds_screen_height?(content)
- screen_height, screen_width = begin
- Reline.get_screen_size
- rescue Errno::EINVAL
- [24, 80]
- end
-
- pageable_height = screen_height - 3 # leave some space for previous and the current prompt
-
- # If the content has more lines than the pageable height
- content.lines.count > pageable_height ||
- # Or if the content is a few long lines
- pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
- end
-
- def setup_pager
- require 'shellwords'
-
- PAGE_COMMANDS.each do |pager|
- pager = Shellwords.split(pager)
- next if pager.empty?
-
- if pager.first == 'less' || pager.first == 'more'
- pager << '-R' unless pager.include?('-R')
- end
-
- begin
- io = IO.popen(pager, 'w')
- rescue
- next
- end
-
- if $? && $?.pid == io.pid && $?.exited? # pager didn't work
- next
- end
-
- return io
- end
-
- nil
- end
- end
- end
-end
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
index 4bce2aa6b2..85b336fbe1 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -1,124 +1,165 @@
# frozen_string_literal: false
#
# irb/ruby-lex.rb - ruby lexcal analyzer
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require "ripper"
require "jruby" if RUBY_ENGINE == "jruby"
-require_relative "nesting_parser"
-
-module IRB
- # :stopdoc:
- class RubyLex
- ASSIGNMENT_NODE_TYPES = [
- # Local, instance, global, class, constant, instance, and index assignment:
- # "foo = bar",
- # "@foo = bar",
- # "$foo = bar",
- # "@@foo = bar",
- # "::Foo = bar",
- # "a::Foo = bar",
- # "Foo = bar"
- # "foo.bar = 1"
- # "foo[1] = bar"
- :assign,
-
- # Operation assignment:
- # "foo += bar"
- # "foo -= bar"
- # "foo ||= bar"
- # "foo &&= bar"
- :opassign,
-
- # Multiple assignment:
- # "foo, bar = 1, 2
- :massign,
- ]
-
- class TerminateLineInput < StandardError
- def initialize
- super("Terminate Line Input")
- end
- end
- def self.compile_with_errors_suppressed(code, line_no: 1)
- begin
- result = yield code, line_no
- rescue ArgumentError
- # Ruby can issue an error for the code if there is an
- # incomplete magic comment for encoding in it. Force an
- # expression with a new line before the code in this
- # case to prevent magic comment handling. To make sure
- # line numbers in the lexed code remain the same,
- # decrease the line number by one.
- code = ";\n#{code}"
- line_no -= 1
- result = yield code, line_no
- end
- result
+# :stopdoc:
+class RubyLex
+
+ class TerminateLineInput < StandardError
+ def initialize
+ super("Terminate Line Input")
end
+ end
+
+ def initialize
+ @exp_line_no = @line_no = 1
+ @indent = 0
+ @continue = false
+ @line = ""
+ @prompt = nil
+ end
- ERROR_TOKENS = [
- :on_parse_error,
- :compile_error,
- :on_assign_error,
- :on_alias_error,
- :on_class_name_error,
- :on_param_error
- ]
-
- def self.generate_local_variables_assign_code(local_variables)
- "#{local_variables.join('=')}=nil;" unless local_variables.empty?
+ def self.compile_with_errors_suppressed(code, line_no: 1)
+ begin
+ result = yield code, line_no
+ rescue ArgumentError
+ # Ruby can issue an error for the code if there is an
+ # incomplete magic comment for encoding in it. Force an
+ # expression with a new line before the code in this
+ # case to prevent magic comment handling. To make sure
+ # line numbers in the lexed code remain the same,
+ # decrease the line number by one.
+ code = ";\n#{code}"
+ line_no -= 1
+ result = yield code, line_no
end
+ result
+ end
- # Some part of the code is not included in Ripper's token.
- # Example: DATA part, token after heredoc_beg when heredoc has unclosed embexpr.
- # With interpolated tokens, tokens.map(&:tok).join will be equal to code.
- def self.interpolate_ripper_ignored_tokens(code, tokens)
- line_positions = [0]
- code.lines.each do |line|
- line_positions << line_positions.last + line.bytesize
- end
- prev_byte_pos = 0
- interpolated = []
- prev_line = 1
- tokens.each do |t|
- line, col = t.pos
- byte_pos = line_positions[line - 1] + col
- if prev_byte_pos < byte_pos
- tok = code.byteslice(prev_byte_pos...byte_pos)
- pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
- interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
- prev_line += tok.count("\n")
+ # io functions
+ def set_input(io, p = nil, context:, &block)
+ @io = io
+ if @io.respond_to?(:check_termination)
+ @io.check_termination do |code|
+ if Reline::IOGate.in_pasting?
+ lex = RubyLex.new
+ rest = lex.check_termination_in_prev_line(code, context: context)
+ if rest
+ Reline.delete_text
+ rest.bytes.reverse_each do |c|
+ Reline.ungetc(c)
+ end
+ true
+ else
+ false
+ end
+ else
+ # Accept any single-line input for symbol aliases or commands that transform args
+ command = code.split(/\s/, 2).first
+ if context.symbol_alias?(command) || context.transform_args?(command)
+ next true
+ end
+
+ code.gsub!(/\s*\z/, '').concat("\n")
+ ltype, indent, continue, code_block_open = check_state(code, context: context)
+ if ltype or indent > 0 or continue or code_block_open
+ false
+ else
+ true
+ end
end
- interpolated << t
- prev_byte_pos = byte_pos + t.tok.bytesize
- prev_line += t.tok.count("\n")
end
- if prev_byte_pos < code.bytesize
- tok = code.byteslice(prev_byte_pos..)
- pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
- interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
- end
- interpolated
end
+ if @io.respond_to?(:dynamic_prompt)
+ @io.dynamic_prompt do |lines|
+ lines << '' if lines.empty?
+ result = []
+ tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, context: context)
+ code = String.new
+ partial_tokens = []
+ unprocessed_tokens = []
+ line_num_offset = 0
+ tokens.each do |t|
+ partial_tokens << t
+ unprocessed_tokens << t
+ if t.tok.include?("\n")
+ t_str = t.tok
+ t_str.each_line("\n") do |s|
+ code << s << "\n"
+ ltype, indent, continue, code_block_open = check_state(code, partial_tokens, context: context)
+ result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
+ line_num_offset += 1
+ end
+ unprocessed_tokens = []
+ else
+ code << t.tok
+ end
+ end
- def self.ripper_lex_without_warning(code, local_variables: [])
- verbose, $VERBOSE = $VERBOSE, nil
- lvars_code = generate_local_variables_assign_code(local_variables)
- original_code = code
- if lvars_code
- code = "#{lvars_code}\n#{code}"
- line_no = 0
- else
- line_no = 1
+ unless unprocessed_tokens.empty?
+ ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens, context: context)
+ result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
+ end
+ result
end
+ end
- compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
- lexer = Ripper::Lexer.new(inner_code, '-', line_no)
- tokens = []
- lexer.scan.each do |t|
+ if p.respond_to?(:call)
+ @input = p
+ elsif block_given?
+ @input = block
+ else
+ @input = Proc.new{@io.gets}
+ end
+ end
+
+ def set_prompt(p = nil, &block)
+ p = block if block_given?
+ if p.respond_to?(:call)
+ @prompt = p
+ else
+ @prompt = Proc.new{print p}
+ end
+ end
+
+ ERROR_TOKENS = [
+ :on_parse_error,
+ :compile_error,
+ :on_assign_error,
+ :on_alias_error,
+ :on_class_name_error,
+ :on_param_error
+ ]
+
+ def self.generate_local_variables_assign_code(local_variables)
+ "#{local_variables.join('=')}=nil;" unless local_variables.empty?
+ end
+
+ def self.ripper_lex_without_warning(code, context: nil)
+ verbose, $VERBOSE = $VERBOSE, nil
+ lvars_code = generate_local_variables_assign_code(context&.local_variables || [])
+ if lvars_code
+ code = "#{lvars_code}\n#{code}"
+ line_no = 0
+ else
+ line_no = 1
+ end
+
+ compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
+ lexer = Ripper::Lexer.new(inner_code, '-', line_no)
+ if lexer.respond_to?(:scan) # Ruby 2.7+
+ lexer.scan.each_with_object([]) do |t, tokens|
next if t.pos.first == 0
prev_tk = tokens.last
position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
@@ -128,347 +169,698 @@ module IRB
tokens << t
end
end
- interpolate_ripper_ignored_tokens(original_code, tokens)
+ else
+ lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos)
end
- ensure
- $VERBOSE = verbose
end
+ ensure
+ $VERBOSE = verbose
+ end
- def check_code_state(code, local_variables:)
- tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
- opens = NestingParser.open_tokens(tokens)
- [tokens, opens, code_terminated?(code, tokens, opens, local_variables: local_variables)]
+ def find_prev_spaces(line_index)
+ return 0 if @tokens.size == 0
+ md = @tokens[0].tok.match(/(\A +)/)
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
+ line_count = 0
+ @tokens.each_with_index do |t, i|
+ if t.tok.include?("\n")
+ line_count += t.tok.count("\n")
+ if line_count >= line_index
+ return prev_spaces
+ end
+ if (@tokens.size - 1) > i
+ md = @tokens[i + 1].tok.match(/(\A +)/)
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
+ end
+ end
end
+ prev_spaces
+ end
- def code_terminated?(code, tokens, opens, local_variables:)
- case check_code_syntax(code, local_variables: local_variables)
- when :unrecoverable_error
- true
- when :recoverable_error
- false
- when :other_error
- opens.empty? && !should_continue?(tokens)
- when :valid
- !should_continue?(tokens)
+ def set_auto_indent(context)
+ if @io.respond_to?(:auto_indent) and context.auto_indent_mode
+ @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
+ if is_newline
+ @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: context)
+ prev_spaces = find_prev_spaces(line_index)
+ depth_difference = check_newline_depth_difference
+ depth_difference = 0 if depth_difference < 0
+ prev_spaces + depth_difference * 2
+ else
+ code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
+ last_line = lines[line_index]&.byteslice(0, byte_pointer)
+ code += last_line if last_line
+ @tokens = self.class.ripper_lex_without_warning(code, context: context)
+ check_corresponding_token_depth(lines, line_index)
+ end
end
end
+ end
- def assignment_expression?(code, local_variables:)
- # Try to parse the code and check if the last of possibly multiple
- # expressions is an assignment type.
+ def check_state(code, tokens = nil, context: nil)
+ tokens = self.class.ripper_lex_without_warning(code, context: context) unless tokens
+ ltype = process_literal_type(tokens)
+ indent = process_nesting_level(tokens)
+ continue = process_continue(tokens)
+ lvars_code = self.class.generate_local_variables_assign_code(context.local_variables)
+ code = "#{lvars_code}\n#{code}" if lvars_code
+ code_block_open = check_code_block(code, tokens)
+ [ltype, indent, continue, code_block_open]
+ end
- # If the expression is invalid, Ripper.sexp should return nil which will
- # result in false being returned. Any valid expression should return an
- # s-expression where the second element of the top level array is an
- # array of parsed expressions. The first element of each expression is the
- # expression's type.
- verbose, $VERBOSE = $VERBOSE, nil
- code = "#{RubyLex.generate_local_variables_assign_code(local_variables) || 'nil;'}\n#{code}"
- # Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
- node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
- ASSIGNMENT_NODE_TYPES.include?(node_type)
- ensure
- $VERBOSE = verbose
+ def prompt
+ if @prompt
+ @prompt.call(@ltype, @indent, @continue, @line_no)
end
+ end
- def should_continue?(tokens)
- # Look at the last token and check if IRB need to continue reading next line.
- # Example code that should continue: `a\` `a +` `a.`
- # Trailing spaces, newline, comments are skipped
- return true if tokens.last&.event == :on_sp && tokens.last.tok == "\\\n"
-
- tokens.reverse_each do |token|
- case token.event
- when :on_sp, :on_nl, :on_ignored_nl, :on_comment, :on_embdoc_beg, :on_embdoc, :on_embdoc_end
- # Skip
- when :on_regexp_end, :on_heredoc_end, :on_semicolon
- # State is EXPR_BEG but should not continue
- return false
- else
- # Endless range should not continue
- return false if token.event == :on_op && token.tok.match?(/\A\.\.\.?\z/)
+ def initialize_input
+ @ltype = nil
+ @indent = 0
+ @continue = false
+ @line = ""
+ @exp_line_no = @line_no
+ @code_block_open = false
+ end
- # EXPR_DOT and most of the EXPR_BEG should continue
- return token.state.anybits?(Ripper::EXPR_BEG | Ripper::EXPR_DOT)
+ def each_top_level_statement(context)
+ initialize_input
+ catch(:TERM_INPUT) do
+ loop do
+ begin
+ prompt
+ unless l = lex(context)
+ throw :TERM_INPUT if @line == ''
+ else
+ @line_no += l.count("\n")
+ if l == "\n"
+ @exp_line_no += 1
+ next
+ end
+ @line.concat l
+ if @code_block_open or @ltype or @continue or @indent > 0
+ next
+ end
+ end
+ if @line != "\n"
+ @line.force_encoding(@io.encoding)
+ yield @line, @exp_line_no
+ end
+ raise TerminateLineInput if @io.eof?
+ @line = ''
+ @exp_line_no = @line_no
+
+ @indent = 0
+ rescue TerminateLineInput
+ initialize_input
+ prompt
end
end
- false
end
+ end
- def check_code_syntax(code, local_variables:)
- lvars_code = RubyLex.generate_local_variables_assign_code(local_variables)
- code = "#{lvars_code}\n#{code}"
+ def lex(context)
+ line = @input.call
+ if @io.respond_to?(:check_termination)
+ return line # multiline
+ end
+ code = @line + (line.nil? ? '' : line)
+ code.gsub!(/\s*\z/, '').concat("\n")
+ @tokens = self.class.ripper_lex_without_warning(code, context: context)
+ @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens, context: context)
+ line
+ end
- begin # check if parser error are available
- verbose, $VERBOSE = $VERBOSE, nil
- case RUBY_ENGINE
- when 'ruby'
- self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
- RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no)
- end
- when 'jruby'
- JRuby.compile_ir(code)
- else
- catch(:valid) do
- eval("BEGIN { throw :valid, true }\n#{code}")
- false
- end
+ def process_continue(tokens = @tokens)
+ # last token is always newline
+ if tokens.size >= 2 and tokens[-2].event == :on_regexp_end
+ # end of regexp literal
+ return false
+ elsif tokens.size >= 2 and tokens[-2].event == :on_semicolon
+ return false
+ elsif tokens.size >= 2 and tokens[-2].event == :on_kw and ['begin', 'else', 'ensure'].include?(tokens[-2].tok)
+ return false
+ elsif !tokens.empty? and tokens.last.tok == "\\\n"
+ return true
+ elsif tokens.size >= 1 and tokens[-1].event == :on_heredoc_end # "EOH\n"
+ return false
+ elsif tokens.size >= 2 and tokens[-2].state.anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) and tokens[-2].tok !~ /\A\.\.\.?\z/
+ # end of literal except for regexp
+ # endless range at end of line is not a continue
+ return true
+ end
+ false
+ end
+
+ def check_code_block(code, tokens = @tokens)
+ return true if tokens.empty?
+ if tokens.last.event == :on_heredoc_beg
+ return true
+ end
+
+ begin # check if parser error are available
+ verbose, $VERBOSE = $VERBOSE, nil
+ case RUBY_ENGINE
+ when 'ruby'
+ self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
+ RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no)
end
- rescue EncodingError
- # This is for a hash with invalid encoding symbol, {"\xAE": 1}
- :unrecoverable_error
- rescue SyntaxError => e
- case e.message
- when /unterminated (?:string|regexp) meets end of file/
- # "unterminated regexp meets end of file"
- #
- # example:
- # /
- #
- # "unterminated string meets end of file"
- #
- # example:
- # '
- return :recoverable_error
- when /syntax error, unexpected end-of-input/
- # "syntax error, unexpected end-of-input, expecting keyword_end"
- #
- # example:
- # if true
- # hoge
- # if false
- # fuga
- # end
- return :recoverable_error
- when /syntax error, unexpected keyword_end/
- # "syntax error, unexpected keyword_end"
- #
- # example:
- # if (
- # end
- #
- # example:
- # end
- return :unrecoverable_error
- when /syntax error, unexpected '\.'/
- # "syntax error, unexpected '.'"
- #
- # example:
- # .
- return :unrecoverable_error
- when /unexpected tREGEXP_BEG/
- # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('"
- #
- # example:
- # method / f /
- return :unrecoverable_error
- else
- return :other_error
+ when 'jruby'
+ JRuby.compile_ir(code)
+ else
+ catch(:valid) do
+ eval("BEGIN { throw :valid, true }\n#{code}")
+ false
end
- ensure
- $VERBOSE = verbose
end
- :valid
+ rescue EncodingError
+ # This is for a hash with invalid encoding symbol, {"\xAE": 1}
+ rescue SyntaxError => e
+ case e.message
+ when /unterminated (?:string|regexp) meets end of file/
+ # "unterminated regexp meets end of file"
+ #
+ # example:
+ # /
+ #
+ # "unterminated string meets end of file"
+ #
+ # example:
+ # '
+ return true
+ when /syntax error, unexpected end-of-input/
+ # "syntax error, unexpected end-of-input, expecting keyword_end"
+ #
+ # example:
+ # if true
+ # hoge
+ # if false
+ # fuga
+ # end
+ return true
+ when /syntax error, unexpected keyword_end/
+ # "syntax error, unexpected keyword_end"
+ #
+ # example:
+ # if (
+ # end
+ #
+ # example:
+ # end
+ return false
+ when /syntax error, unexpected '\.'/
+ # "syntax error, unexpected '.'"
+ #
+ # example:
+ # .
+ return false
+ when /unexpected tREGEXP_BEG/
+ # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('"
+ #
+ # example:
+ # method / f /
+ return false
+ end
+ ensure
+ $VERBOSE = verbose
end
- def calc_indent_level(opens)
- indent_level = 0
- opens.each_with_index do |t, index|
- case t.event
- when :on_heredoc_beg
- if opens[index + 1]&.event != :on_heredoc_beg
- if t.tok.match?(/^<<[~-]/)
- indent_level += 1
- else
- indent_level = 0
- end
+ last_lex_state = tokens.last.state
+
+ if last_lex_state.allbits?(Ripper::EXPR_BEG)
+ return false
+ elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_CLASS)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_FNAME)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_VALUE)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_ARG)
+ return false
+ end
+
+ false
+ end
+
+ def process_nesting_level(tokens = @tokens)
+ indent = 0
+ in_oneliner_def = nil
+ tokens.each_with_index { |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
+ else
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
+ if t.tok == '='
+ in_oneliner_def = :BODY
end
- when :on_tstring_beg, :on_regexp_beg, :on_symbeg, :on_backtick
- # No indent: "", //, :"", ``
- # Indent: %(), %r(), %i(), %x()
- indent_level += 1 if t.tok.start_with? '%'
- when :on_embdoc_beg
- indent_level = 0
else
- indent_level += 1
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ indent -= 1
+ end
+ in_oneliner_def = nil
end
end
- indent_level
- end
- FREE_INDENT_TOKENS = %i[on_tstring_beg on_backtick on_regexp_beg on_symbeg]
+ case t.event
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
+ indent += 1
+ when :on_rbracket, :on_rbrace, :on_rparen
+ indent -= 1
+ when :on_kw
+ next if index > 0 and tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
+ case t.tok
+ when 'do'
+ syntax_of_do = take_corresponding_syntax_to_kw_do(tokens, index)
+ indent += 1 if syntax_of_do == :method_calling
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
+ indent += 1
+ when 'if', 'unless', 'while', 'until'
+ # postfix if/unless/while/until must be Ripper::EXPR_LABEL
+ indent += 1 unless t.state.allbits?(Ripper::EXPR_LABEL)
+ when 'end'
+ indent -= 1
+ end
+ end
+ # percent literals are not indented
+ }
+ indent
+ end
- def free_indent_token?(token)
- FREE_INDENT_TOKENS.include?(token&.event)
+ def is_method_calling?(tokens, index)
+ tk = tokens[index]
+ if tk.state.anybits?(Ripper::EXPR_CMDARG) and tk.event == :on_ident
+ # The target method call to pass the block with "do".
+ return true
+ elsif tk.state.anybits?(Ripper::EXPR_ARG) and tk.event == :on_ident
+ non_sp_index = tokens[0..(index - 1)].rindex{ |t| t.event != :on_sp }
+ if non_sp_index
+ prev_tk = tokens[non_sp_index]
+ if prev_tk.state.anybits?(Ripper::EXPR_DOT) and prev_tk.event == :on_period
+ # The target method call with receiver to pass the block with "do".
+ return true
+ end
+ end
end
+ false
+ end
- # Calculates the difference of pasted code's indent and indent calculated from tokens
- def indent_difference(lines, line_results, line_index)
- loop do
- _tokens, prev_opens, _next_opens, min_depth = line_results[line_index]
- open_token = prev_opens.last
- if !open_token || (open_token.event != :on_heredoc_beg && !free_indent_token?(open_token))
- # If the leading whitespace is an indent, return the difference
- indent_level = calc_indent_level(prev_opens.take(min_depth))
- calculated_indent = 2 * indent_level
- actual_indent = lines[line_index][/^ */].size
- return actual_indent - calculated_indent
- elsif open_token.event == :on_heredoc_beg && open_token.tok.match?(/^<<[^-~]/)
- return 0
- end
- # If the leading whitespace is not an indent but part of a multiline token
- # Calculate base_indent of the multiline token's beginning line
- line_index = open_token.pos[0] - 1
+ def take_corresponding_syntax_to_kw_do(tokens, index)
+ syntax_of_do = nil
+ # Finding a syntax corresponding to "do".
+ index.downto(0) do |i|
+ tk = tokens[i]
+ # In "continue", the token isn't the corresponding syntax to "do".
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t.event != :on_sp }
+ first_in_fomula = false
+ if non_sp_index.nil?
+ first_in_fomula = true
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index].event)
+ first_in_fomula = true
+ end
+ if is_method_calling?(tokens, i)
+ syntax_of_do = :method_calling
+ break if first_in_fomula
+ elsif tk.event == :on_kw && %w{while until for}.include?(tk.tok)
+ # A loop syntax in front of "do" found.
+ #
+ # while cond do # also "until" or "for"
+ # end
+ #
+ # This "do" doesn't increment indent because the loop syntax already
+ # incremented.
+ syntax_of_do = :loop_syntax
+ break if first_in_fomula
end
end
+ syntax_of_do
+ end
+
+ def is_the_in_correspond_to_a_for(tokens, index)
+ syntax_of_in = nil
+ # Finding a syntax corresponding to "do".
+ index.downto(0) do |i|
+ tk = tokens[i]
+ # In "continue", the token isn't the corresponding syntax to "do".
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t.event != :on_sp }
+ first_in_fomula = false
+ if non_sp_index.nil?
+ first_in_fomula = true
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index].event)
+ first_in_fomula = true
+ end
+ if tk.event == :on_kw && tk.tok == 'for'
+ # A loop syntax in front of "do" found.
+ #
+ # while cond do # also "until" or "for"
+ # end
+ #
+ # This "do" doesn't increment indent because the loop syntax already
+ # incremented.
+ syntax_of_in = :for
+ end
+ break if first_in_fomula
+ end
+ syntax_of_in
+ end
- def process_indent_level(tokens, lines, line_index, is_newline)
- line_results = NestingParser.parse_by_line(tokens)
- result = line_results[line_index]
- if result
- _tokens, prev_opens, next_opens, min_depth = result
+ def check_newline_depth_difference
+ depth_difference = 0
+ open_brace_on_line = 0
+ in_oneliner_def = nil
+ @tokens.each_with_index do |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
else
- # When last line is empty
- prev_opens = next_opens = line_results.last[2]
- min_depth = next_opens.size
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
+ if t.tok == '='
+ in_oneliner_def = :BODY
+ end
+ else
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ depth_difference -= 1
+ end
+ in_oneliner_def = nil
+ end
end
- # To correctly indent line like `end.map do`, we use shortest open tokens on each line for indent calculation.
- # Shortest open tokens can be calculated by `opens.take(min_depth)`
- indent = 2 * calc_indent_level(prev_opens.take(min_depth))
+ case t.event
+ when :on_ignored_nl, :on_nl, :on_comment
+ if index != (@tokens.size - 1) and in_oneliner_def != :BODY
+ depth_difference = 0
+ open_brace_on_line = 0
+ end
+ next
+ when :on_sp
+ next
+ end
- preserve_indent = lines[line_index - (is_newline ? 1 : 0)][/^ */].size
+ case t.event
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
+ depth_difference += 1
+ open_brace_on_line += 1
+ when :on_rbracket, :on_rbrace, :on_rparen
+ depth_difference -= 1 if open_brace_on_line > 0
+ when :on_kw
+ next if index > 0 and @tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
+ case t.tok
+ when 'do'
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
+ depth_difference += 1 if syntax_of_do == :method_calling
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
+ depth_difference += 1
+ when 'if', 'unless', 'while', 'until', 'rescue'
+ # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
+ depth_difference += 1
+ end
+ when 'else', 'elsif', 'ensure', 'when'
+ depth_difference += 1
+ when 'in'
+ unless is_the_in_correspond_to_a_for(@tokens, index)
+ depth_difference += 1
+ end
+ when 'end'
+ depth_difference -= 1
+ end
+ end
+ end
+ depth_difference
+ end
- prev_open_token = prev_opens.last
- next_open_token = next_opens.last
+ def check_corresponding_token_depth(lines, line_index)
+ corresponding_token_depth = nil
+ is_first_spaces_of_line = true
+ is_first_printable_of_line = true
+ spaces_of_nest = []
+ spaces_at_line_head = 0
+ open_brace_on_line = 0
+ in_oneliner_def = nil
+
+ if heredoc_scope?
+ return lines[line_index][/^ */].length
+ end
- # Calculates base indent for pasted code on the line where prev_open_token is located
- # irb(main):001:1* if a # base_indent is 2, indent calculated from tokens is 0
- # irb(main):002:1* if b # base_indent is 6, indent calculated from tokens is 2
- # irb(main):003:0> c # base_indent is 6, indent calculated from tokens is 4
- if prev_open_token
- base_indent = [0, indent_difference(lines, line_results, prev_open_token.pos[0] - 1)].max
+ @tokens.each_with_index do |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
else
- base_indent = 0
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
+ if t.tok == '='
+ in_oneliner_def = :BODY
+ end
+ else
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ if is_first_printable_of_line
+ corresponding_token_depth = spaces_of_nest.pop
+ else
+ spaces_of_nest.pop
+ corresponding_token_depth = nil
+ end
+ end
+ in_oneliner_def = nil
+ end
end
- if free_indent_token?(prev_open_token)
- if is_newline && prev_open_token.pos[0] == line_index
- # First newline inside free-indent token
- base_indent + indent
- else
- # Accept any number of indent inside free-indent token
- preserve_indent
+ case t.event
+ when :on_ignored_nl, :on_nl, :on_comment
+ if in_oneliner_def != :BODY
+ corresponding_token_depth = nil
+ spaces_at_line_head = 0
+ is_first_spaces_of_line = true
+ is_first_printable_of_line = true
+ open_brace_on_line = 0
end
- elsif prev_open_token&.event == :on_embdoc_beg || next_open_token&.event == :on_embdoc_beg
- if prev_open_token&.event == next_open_token&.event
- # Accept any number of indent inside embdoc content
- preserve_indent
+ next
+ when :on_sp
+ spaces_at_line_head = t.tok.count(' ') if is_first_spaces_of_line
+ is_first_spaces_of_line = false
+ next
+ end
+
+ case t.event
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
+ spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2)
+ open_brace_on_line += 1
+ when :on_rbracket, :on_rbrace, :on_rparen
+ if is_first_printable_of_line
+ corresponding_token_depth = spaces_of_nest.pop
else
- # =begin or =end
- 0
+ spaces_of_nest.pop
+ corresponding_token_depth = nil
end
- elsif prev_open_token&.event == :on_heredoc_beg
- tok = prev_open_token.tok
- if prev_opens.size <= next_opens.size
- if is_newline && lines[line_index].empty? && line_results[line_index - 1][1].last != next_open_token
- # First line in heredoc
- tok.match?(/^<<[-~]/) ? base_indent + indent : indent
- elsif tok.match?(/^<<~/)
- # Accept extra indent spaces inside `<<~` heredoc
- [base_indent + indent, preserve_indent].max
+ open_brace_on_line -= 1
+ when :on_kw
+ next if index > 0 and @tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
+ case t.tok
+ when 'do'
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
+ if syntax_of_do == :method_calling
+ spaces_of_nest.push(spaces_at_line_head)
+ end
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
+ spaces_of_nest.push(spaces_at_line_head)
+ when 'rescue'
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
+ corresponding_token_depth = spaces_of_nest.last
+ end
+ when 'if', 'unless', 'while', 'until'
+ # postfix if/unless/while/until must be Ripper::EXPR_LABEL
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
+ spaces_of_nest.push(spaces_at_line_head)
+ end
+ when 'else', 'elsif', 'ensure', 'when'
+ corresponding_token_depth = spaces_of_nest.last
+ when 'in'
+ if in_keyword_case_scope?
+ corresponding_token_depth = spaces_of_nest.last
+ end
+ when 'end'
+ if is_first_printable_of_line
+ corresponding_token_depth = spaces_of_nest.pop
else
- # Accept any number of indent inside other heredoc
- preserve_indent
+ spaces_of_nest.pop
+ corresponding_token_depth = nil
end
- else
- # Heredoc close
- prev_line_indent_level = calc_indent_level(prev_opens)
- tok.match?(/^<<[~-]/) ? base_indent + 2 * (prev_line_indent_level - 1) : 0
end
- else
- base_indent + indent
end
+ is_first_spaces_of_line = false
+ is_first_printable_of_line = false
end
+ corresponding_token_depth
+ end
- LTYPE_TOKENS = %i[
- on_heredoc_beg on_tstring_beg
- on_regexp_beg on_symbeg on_backtick
- on_symbols_beg on_qsymbols_beg
- on_words_beg on_qwords_beg
- ]
+ def check_string_literal(tokens)
+ i = 0
+ start_token = []
+ end_type = []
+ pending_heredocs = []
+ while i < tokens.size
+ t = tokens[i]
+ case t.event
+ when *end_type.last
+ start_token.pop
+ end_type.pop
+ when :on_tstring_beg
+ start_token << t
+ end_type << [:on_tstring_end, :on_label_end]
+ when :on_regexp_beg
+ start_token << t
+ end_type << :on_regexp_end
+ when :on_symbeg
+ acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw on_int on_backtick}
+ if (i + 1) < tokens.size
+ if acceptable_single_tokens.all?{ |st| tokens[i + 1].event != st }
+ start_token << t
+ end_type << :on_tstring_end
+ else
+ i += 1
+ end
+ end
+ when :on_backtick
+ if t.state.allbits?(Ripper::EXPR_BEG)
+ start_token << t
+ end_type << :on_tstring_end
+ end
+ when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg
+ start_token << t
+ end_type << :on_tstring_end
+ when :on_heredoc_beg
+ pending_heredocs << t
+ end
- def ltype_from_open_tokens(opens)
- start_token = opens.reverse_each.find do |tok|
- LTYPE_TOKENS.include?(tok.event)
+ if pending_heredocs.any? && t.tok.include?("\n")
+ pending_heredocs.reverse_each do |t|
+ start_token << t
+ end_type << :on_heredoc_end
+ end
+ pending_heredocs = []
end
- return nil unless start_token
+ i += 1
+ end
+ pending_heredocs.first || start_token.last
+ end
- case start_token&.event
- when :on_tstring_beg
- case start_token&.tok
- when ?" then ?"
- when /^%.$/ then ?"
- when /^%Q.$/ then ?"
- when ?' then ?'
- when /^%q.$/ then ?'
+ def process_literal_type(tokens = @tokens)
+ start_token = check_string_literal(tokens)
+ return nil if start_token == ""
+
+ case start_token&.event
+ when :on_tstring_beg
+ case start_token&.tok
+ when ?" then ?"
+ when /^%.$/ then ?"
+ when /^%Q.$/ then ?"
+ when ?' then ?'
+ when /^%q.$/ then ?'
+ end
+ when :on_regexp_beg then ?/
+ when :on_symbeg then ?:
+ when :on_backtick then ?`
+ when :on_qwords_beg then ?]
+ when :on_words_beg then ?]
+ when :on_qsymbols_beg then ?]
+ when :on_symbols_beg then ?]
+ when :on_heredoc_beg
+ start_token&.tok =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/
+ case $1
+ when ?" then ?"
+ when ?' then ?'
+ when ?` then ?`
+ else ?"
+ end
+ else
+ nil
+ end
+ end
+
+ def check_termination_in_prev_line(code, context: nil)
+ tokens = self.class.ripper_lex_without_warning(code, context: context)
+ past_first_newline = false
+ index = tokens.rindex do |t|
+ # traverse first token before last line
+ if past_first_newline
+ if t.tok.include?("\n")
+ true
end
- when :on_regexp_beg then ?/
- when :on_symbeg then ?:
- when :on_backtick then ?`
- when :on_qwords_beg then ?]
- when :on_words_beg then ?]
- when :on_qsymbols_beg then ?]
- when :on_symbols_beg then ?]
- when :on_heredoc_beg
- start_token&.tok =~ /<<[-~]?(['"`])\w+\1/
- $1 || ?"
+ elsif t.tok.include?("\n")
+ past_first_newline = true
+ false
else
- nil
+ false
end
end
- def check_termination_in_prev_line(code, local_variables:)
- tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
- past_first_newline = false
- index = tokens.rindex do |t|
- # traverse first token before last line
- if past_first_newline
- if t.tok.include?("\n")
- true
- end
- elsif t.tok.include?("\n")
- past_first_newline = true
- false
- else
- false
+ if index
+ first_token = nil
+ last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
+ last_line_tokens.each do |t|
+ unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
+ first_token = t
+ break
end
end
- if index
- first_token = nil
- last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
- last_line_tokens.each do |t|
- unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
- first_token = t
- break
- end
+ if first_token.nil?
+ return false
+ elsif first_token && first_token.state == Ripper::EXPR_DOT
+ return false
+ else
+ tokens_without_last_line = tokens[0..index]
+ ltype = process_literal_type(tokens_without_last_line)
+ indent = process_nesting_level(tokens_without_last_line)
+ continue = process_continue(tokens_without_last_line)
+ code_block_open = check_code_block(tokens_without_last_line.map(&:tok).join(''), tokens_without_last_line)
+ if ltype or indent > 0 or continue or code_block_open
+ return false
+ else
+ return last_line_tokens.map(&:tok).join('')
end
+ end
+ end
+ false
+ end
- if first_token && first_token.state != Ripper::EXPR_DOT
- tokens_without_last_line = tokens[0..index]
- code_without_last_line = tokens_without_last_line.map(&:tok).join
- opens_without_last_line = NestingParser.open_tokens(tokens_without_last_line)
- if code_terminated?(code_without_last_line, tokens_without_last_line, opens_without_last_line, local_variables: local_variables)
- return last_line_tokens.map(&:tok).join
- end
- end
+ private
+
+ def heredoc_scope?
+ heredoc_tokens = @tokens.select { |t| [:on_heredoc_beg, :on_heredoc_end].include?(t.event) }
+ heredoc_tokens[-1]&.event == :on_heredoc_beg
+ end
+
+ def in_keyword_case_scope?
+ kw_tokens = @tokens.select { |t| t.event == :on_kw && ['case', 'for', 'end'].include?(t.tok) }
+ counter = 0
+ kw_tokens.reverse.each do |t|
+ if t.tok == 'case'
+ return true if counter.zero?
+ counter += 1
+ elsif t.tok == 'for'
+ counter += 1
+ elsif t.tok == 'end'
+ counter -= 1
end
- false
end
+ false
end
- # :startdoc:
end
-
-RubyLex = IRB::RubyLex
-Object.deprecate_constant(:RubyLex)
+# :startdoc:
diff --git a/lib/irb/ruby_logo.aa b/lib/irb/ruby_logo.aa
index 61fe22c94a..a34a3e2f28 100644
--- a/lib/irb/ruby_logo.aa
+++ b/lib/irb/ruby_logo.aa
@@ -1,4 +1,3 @@
-TYPE: LARGE
-+smJYYN?mm-
HB"BBYT TQg NggT
@@ -36,45 +35,3 @@ TYPE: LARGE
m7 NW H N HSVO1z=?11-
NgTH bB kH WBHWWHBHWmQgg&gggggNNN
NNggggggNN
-TYPE: ASCII
- ,,,;;;;''''';;;'';,
- ,,;'' ';;,;;; ',
- ,,'' ;;'';'''';;;;;;
- ,;' ;; ',, ;
- ,;' ,;' ';, ;
- ;' ,;; ',,,;
- ,' ,;;,,,,,,,,,,,;;;;
- ;' ;;';;;; ,;;
- ;' ,;' ;; '',, ,;;;
- ;; ,;' ; '';, ,; ;'
-;; ,;;' ;; ;; ;;
-;;, ,,;;' ; ;'; ;;
-;';;,,,,;;;;;;;,,, ;; ,' ; ;;
-; ;;''' ,;'; ''';,,, ; ,;' ;;;;
-;;;;, ; '; ''';;;' ';;;
-;'; ;, ;' '; ,;' ', ;;;
-;;; ; ,; '; ,,' ',, ;;
-;;; '; ;' ';,,'' ';,;;
- '; ';,; ,,;''''''''';;;;;;,,;;;
- ';,,;;,,;;;;;;;;;;''''''''''''''
-TYPE: UNICODE
- ⣀⣤⣴⣾⣿⣿⣿⡛⠛⠛⠛⠛⣻⣿⠿⠛⠛⠶⣤⡀
- ⣀⣴⠾⠛⠉⠁ ⠙⣿⣶⣤⣶⣟⣉ ⠈⠻⣦
- ⣀⣴⠟⠋ ⢸⣿⠟⠻⣯⡙⠛⠛⠛⠶⠶⠶⢶⣽⣇
- ⣠⡾⠋⠁ ⣾⡿ ⠈⠛⢦⣄ ⣿
- ⣠⡾⠋ ⣰⣿⠃ ⠙⠷⣤⡀ ⣿
- ⢀⡾⠋ ⣰⣿⡏ ⠈⠻⣦⣄⢠⣿
- ⣰⠟⠁ ⣴⣿⣿⣁⣀⣠⣤⣤⣤⣤⣤⣤⣤⣴⠶⠿⣿⡏
- ⣼⠏ ⢀⣾⣿⠟⣿⠿⣯⣍⠁ ⣰⣿⡇
- ⢀⣼⠋ ⢀⣴⣿⠟⠁ ⢸⡇ ⠙⠻⢦⣄⡀ ⢠⡿⣿⡇
-⢀⣾⡏ ⢀⣴⣿⠟⠁ ⣿ ⠉⠻⢶⣄⡀⣰⡟ ⣿⠃
-⣾⣿⠁ ⣠⣶⡿⠋⠁ ⢹⡇ ⠈⣿⡏ ⢸⣿
-⣿⣿⡆ ⢀⣠⣴⣿⡿⠋ ⠈⣿ ⢀⡾⠋⣿ ⢸⣿
-⣿⠸⣿⣶⣤⣤⣤⣤⣶⣾⠿⠿⣿⣿⠶⣤⣤⣀⡀ ⢹⡇ ⣴⠟⠁ ⣿⡀⢸⣿
-⣿⢀⣿⣟⠛⠋⠉⠁ ⢰⡟⠹⣧ ⠈⠉⠛⠻⠶⢦⣤⣀⡀ ⠈⣿ ⣠⡾⠃ ⢸⡇⢸⡇
-⣿⣾⣿⢿⡄ ⣿⠁ ⠘⣧ ⠉⠙⠛⠷⣿⣿⡋ ⠸⣇⣸⡇
-⣿⠃⣿⠈⢿⡄ ⣸⠇ ⠘⣧ ⢀⣤⠾⠋⠈⠻⣦⡀ ⣿⣿⡇
-⣿⢸⡏ ⠈⣷⡀ ⢠⡿ ⠘⣧⡀ ⣠⡴⠟⠁ ⠈⠻⣦⣀ ⢿⣿⠁
-⢻⣾⡇ ⠘⣷ ⣼⠃ ⠘⣷⣠⣴⠟⠋ ⠙⢷⣄⢸⣿
- ⠻⣧⡀ ⠘⣧⣰⡏ ⢀⣠⣤⠶⠛⠉⠛⠛⠛⠛⠛⠛⠻⢶⣶⣶⣶⣶⣶⣤⣤⣽⣿⣿
- ⠈⠛⠷⢦⣤⣽⣿⣥⣤⣶⣶⡿⠿⠿⠶⠶⠶⠶⠾⠛⠛⠛⠛⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠁
diff --git a/lib/irb/source_finder.rb b/lib/irb/source_finder.rb
deleted file mode 100644
index 959919e8ac..0000000000
--- a/lib/irb/source_finder.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "ruby-lex"
-
-module IRB
- class SourceFinder
- Source = Struct.new(
- :file, # @param [String] - file name
- :first_line, # @param [String] - first line
- :last_line, # @param [String] - last line
- keyword_init: true,
- )
- private_constant :Source
-
- def initialize(irb_context)
- @irb_context = irb_context
- end
-
- def find_source(signature)
- context_binding = @irb_context.workspace.binding
- case signature
- when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
- eval(signature, context_binding) # trigger autoload
- base = context_binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
- file, line = base.const_source_location(signature)
- when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
- owner = eval(Regexp.last_match[:owner], context_binding)
- method = Regexp.last_match[:method]
- if owner.respond_to?(:instance_method)
- methods = owner.instance_methods + owner.private_instance_methods
- file, line = owner.instance_method(method).source_location if methods.include?(method.to_sym)
- end
- when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
- receiver = eval(Regexp.last_match[:receiver] || 'self', context_binding)
- method = Regexp.last_match[:method]
- file, line = receiver.method(method).source_location if receiver.respond_to?(method, true)
- end
- if file && line && File.exist?(file)
- Source.new(file: file, first_line: line, last_line: find_end(file, line))
- end
- end
-
- private
-
- def find_end(file, first_line)
- lex = RubyLex.new
- lines = File.read(file).lines[(first_line - 1)..-1]
- tokens = RubyLex.ripper_lex_without_warning(lines.join)
- prev_tokens = []
-
- # chunk with line number
- tokens.chunk { |tok| tok.pos[0] }.each do |lnum, chunk|
- code = lines[0..lnum].join
- prev_tokens.concat chunk
- continue = lex.should_continue?(prev_tokens)
- syntax = lex.check_code_syntax(code, local_variables: [])
- if !continue && syntax == :valid
- return first_line + lnum
- end
- end
- first_line
- end
- end
-end
diff --git a/lib/irb/src_encoding.rb b/lib/irb/src_encoding.rb
new file mode 100644
index 0000000000..99aea2b43e
--- /dev/null
+++ b/lib/irb/src_encoding.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: false
+# DO NOT WRITE ANY MAGIC COMMENT HERE.
+module IRB
+ def self.default_src_encoding
+ return __ENCODING__
+ end
+end
diff --git a/lib/irb/statement.rb b/lib/irb/statement.rb
deleted file mode 100644
index b12110600c..0000000000
--- a/lib/irb/statement.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- class Statement
- attr_reader :code
-
- def is_assignment?
- raise NotImplementedError
- end
-
- def suppresses_echo?
- raise NotImplementedError
- end
-
- def should_be_handled_by_debugger?
- raise NotImplementedError
- end
-
- def evaluable_code
- raise NotImplementedError
- end
-
- class Expression < Statement
- def initialize(code, is_assignment)
- @code = code
- @is_assignment = is_assignment
- end
-
- def suppresses_echo?
- @code.match?(/;\s*\z/)
- end
-
- def should_be_handled_by_debugger?
- true
- end
-
- def is_assignment?
- @is_assignment
- end
-
- def evaluable_code
- @code
- end
- end
-
- class Command < Statement
- def initialize(code, command, arg, command_class)
- @code = code
- @command = command
- @arg = arg
- @command_class = command_class
- end
-
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- false
- end
-
- def should_be_handled_by_debugger?
- require_relative 'cmd/help'
- require_relative 'cmd/debug'
- IRB::ExtendCommand::DebugCommand > @command_class || IRB::ExtendCommand::Help == @command_class
- end
-
- def evaluable_code
- # Hook command-specific transformation to return valid Ruby code
- if @command_class.respond_to?(:transform_args)
- arg = @command_class.transform_args(@arg)
- else
- arg = @arg
- end
-
- [@command, arg].compact.join(' ')
- end
- end
- end
-end
diff --git a/lib/irb/type_completion/completor.rb b/lib/irb/type_completion/completor.rb
deleted file mode 100644
index e893fd8adc..0000000000
--- a/lib/irb/type_completion/completor.rb
+++ /dev/null
@@ -1,235 +0,0 @@
-# frozen_string_literal: true
-
-require 'prism'
-require 'irb/completion'
-require_relative 'type_analyzer'
-
-module IRB
- module TypeCompletion
- class Completor < BaseCompletor # :nodoc:
- HIDDEN_METHODS = %w[Namespace TypeName] # defined by rbs, should be hidden
-
- class << self
- attr_accessor :last_completion_error
- end
-
- def inspect
- name = 'TypeCompletion::Completor'
- prism_info = "Prism: #{Prism::VERSION}"
- if Types.rbs_builder
- "#{name}(#{prism_info}, RBS: #{RBS::VERSION})"
- elsif Types.rbs_load_error
- "#{name}(#{prism_info}, RBS: #{Types.rbs_load_error.inspect})"
- else
- "#{name}(#{prism_info}, RBS: loading)"
- end
- end
-
- def completion_candidates(preposing, target, _postposing, bind:)
- @preposing = preposing
- verbose, $VERBOSE = $VERBOSE, nil
- code = "#{preposing}#{target}"
- @result = analyze code, bind
- name, candidates = candidates_from_result(@result)
-
- all_symbols_pattern = /\A[ -\/:-@\[-`\{-~]*\z/
- candidates.map(&:to_s).select { !_1.match?(all_symbols_pattern) && _1.start_with?(name) }.uniq.sort.map do
- target + _1[name.size..]
- end
- rescue SyntaxError, StandardError => e
- Completor.last_completion_error = e
- handle_error(e)
- []
- ensure
- $VERBOSE = verbose
- end
-
- def doc_namespace(preposing, matched, postposing, bind:)
- name = matched[/[a-zA-Z_0-9]*[!?=]?\z/]
- method_doc = -> type do
- type = type.types.find { _1.all_methods.include? name.to_sym }
- case type
- when Types::SingletonType
- "#{Types.class_name_of(type.module_or_class)}.#{name}"
- when Types::InstanceType
- "#{Types.class_name_of(type.klass)}##{name}"
- end
- end
- call_or_const_doc = -> type do
- if name =~ /\A[A-Z]/
- type = type.types.grep(Types::SingletonType).find { _1.module_or_class.const_defined?(name) }
- type.module_or_class == Object ? name : "#{Types.class_name_of(type.module_or_class)}::#{name}" if type
- else
- method_doc.call(type)
- end
- end
-
- value_doc = -> type do
- return unless type
- type.types.each do |t|
- case t
- when Types::SingletonType
- return Types.class_name_of(t.module_or_class)
- when Types::InstanceType
- return Types.class_name_of(t.klass)
- end
- end
- nil
- end
-
- case @result
- in [:call_or_const, type, _name, _self_call]
- call_or_const_doc.call type
- in [:const, type, _name, scope]
- if type
- call_or_const_doc.call type
- else
- value_doc.call scope[name]
- end
- in [:gvar, _name, scope]
- value_doc.call scope["$#{name}"]
- in [:ivar, _name, scope]
- value_doc.call scope["@#{name}"]
- in [:cvar, _name, scope]
- value_doc.call scope["@@#{name}"]
- in [:call, type, _name, _self_call]
- method_doc.call type
- in [:lvar_or_method, _name, scope]
- if scope.local_variables.include?(name)
- value_doc.call scope[name]
- else
- method_doc.call scope.self_type
- end
- else
- end
- end
-
- def candidates_from_result(result)
- candidates = case result
- in [:require, name]
- retrieve_files_to_require_from_load_path
- in [:require_relative, name]
- retrieve_files_to_require_relative_from_current_dir
- in [:call_or_const, type, name, self_call]
- ((self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS) | type.constants
- in [:const, type, name, scope]
- if type
- scope_constants = type.types.flat_map do |t|
- scope.table_module_constants(t.module_or_class) if t.is_a?(Types::SingletonType)
- end
- (scope_constants.compact | type.constants.map(&:to_s)).sort
- else
- scope.constants.sort | ReservedWords
- end
- in [:ivar, name, scope]
- ivars = scope.instance_variables.sort
- name == '@' ? ivars + scope.class_variables.sort : ivars
- in [:cvar, name, scope]
- scope.class_variables
- in [:gvar, name, scope]
- scope.global_variables
- in [:symbol, name]
- Symbol.all_symbols.map { _1.inspect[1..] }
- in [:call, type, name, self_call]
- (self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS
- in [:lvar_or_method, name, scope]
- scope.self_type.all_methods.map(&:to_s) | scope.local_variables | ReservedWords
- else
- []
- end
- [name || '', candidates]
- end
-
- def analyze(code, binding = Object::TOPLEVEL_BINDING)
- # Workaround for https://github.com/ruby/prism/issues/1592
- return if code.match?(/%[qQ]\z/)
-
- ast = Prism.parse(code, scopes: [binding.local_variables]).value
- name = code[/(@@|@|\$)?\w*[!?=]?\z/]
- *parents, target_node = find_target ast, code.bytesize - name.bytesize
- return unless target_node
-
- calculate_scope = -> { TypeAnalyzer.calculate_target_type_scope(binding, parents, target_node).last }
- calculate_type_scope = ->(node) { TypeAnalyzer.calculate_target_type_scope binding, [*parents, target_node], node }
-
- case target_node
- when Prism::StringNode, Prism::InterpolatedStringNode
- call_node, args_node = parents.last(2)
- return unless call_node.is_a?(Prism::CallNode) && call_node.receiver.nil?
- return unless args_node.is_a?(Prism::ArgumentsNode) && args_node.arguments.size == 1
-
- case call_node.name
- when :require
- [:require, name.rstrip]
- when :require_relative
- [:require_relative, name.rstrip]
- end
- when Prism::SymbolNode
- if parents.last.is_a? Prism::BlockArgumentNode # method(&:target)
- receiver_type, _scope = calculate_type_scope.call target_node
- [:call, receiver_type, name, false]
- else
- [:symbol, name] unless name.empty?
- end
- when Prism::CallNode
- return [:lvar_or_method, name, calculate_scope.call] if target_node.receiver.nil?
-
- self_call = target_node.receiver.is_a? Prism::SelfNode
- op = target_node.call_operator
- receiver_type, _scope = calculate_type_scope.call target_node.receiver
- receiver_type = receiver_type.nonnillable if op == '&.'
- [op == '::' ? :call_or_const : :call, receiver_type, name, self_call]
- when Prism::LocalVariableReadNode, Prism::LocalVariableTargetNode
- [:lvar_or_method, name, calculate_scope.call]
- when Prism::ConstantReadNode, Prism::ConstantTargetNode
- if parents.last.is_a? Prism::ConstantPathNode
- path_node = parents.last
- if path_node.parent # A::B
- receiver, scope = calculate_type_scope.call(path_node.parent)
- [:const, receiver, name, scope]
- else # ::A
- scope = calculate_scope.call
- [:const, Types::SingletonType.new(Object), name, scope]
- end
- else
- [:const, nil, name, calculate_scope.call]
- end
- when Prism::GlobalVariableReadNode, Prism::GlobalVariableTargetNode
- [:gvar, name, calculate_scope.call]
- when Prism::InstanceVariableReadNode, Prism::InstanceVariableTargetNode
- [:ivar, name, calculate_scope.call]
- when Prism::ClassVariableReadNode, Prism::ClassVariableTargetNode
- [:cvar, name, calculate_scope.call]
- end
- end
-
- def find_target(node, position)
- location = (
- case node
- when Prism::CallNode
- node.message_loc
- when Prism::SymbolNode
- node.value_loc
- when Prism::StringNode
- node.content_loc
- when Prism::InterpolatedStringNode
- node.closing_loc if node.parts.empty?
- end
- )
- return [node] if location&.start_offset == position
-
- node.compact_child_nodes.each do |n|
- match = find_target(n, position)
- next unless match
- match.unshift node
- return match
- end
-
- [node] if node.location.start_offset == position
- end
-
- def handle_error(e)
- end
- end
- end
-end
diff --git a/lib/irb/type_completion/methods.rb b/lib/irb/type_completion/methods.rb
deleted file mode 100644
index 8a88b6d0f9..0000000000
--- a/lib/irb/type_completion/methods.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module TypeCompletion
- module Methods
- OBJECT_SINGLETON_CLASS_METHOD = Object.instance_method(:singleton_class)
- OBJECT_INSTANCE_VARIABLES_METHOD = Object.instance_method(:instance_variables)
- OBJECT_INSTANCE_VARIABLE_GET_METHOD = Object.instance_method(:instance_variable_get)
- OBJECT_CLASS_METHOD = Object.instance_method(:class)
- MODULE_NAME_METHOD = Module.instance_method(:name)
- end
- end
-end
diff --git a/lib/irb/type_completion/scope.rb b/lib/irb/type_completion/scope.rb
deleted file mode 100644
index 5a58a0ed65..0000000000
--- a/lib/irb/type_completion/scope.rb
+++ /dev/null
@@ -1,412 +0,0 @@
-# frozen_string_literal: true
-
-require 'set'
-require_relative 'types'
-
-module IRB
- module TypeCompletion
-
- class RootScope
- attr_reader :module_nesting, :self_object
-
- def initialize(binding, self_object, local_variables)
- @binding = binding
- @self_object = self_object
- @cache = {}
- modules = [*binding.eval('::Module.nesting'), Object]
- @module_nesting = modules.map { [_1, []] }
- binding_local_variables = binding.local_variables
- uninitialized_locals = local_variables - binding_local_variables
- uninitialized_locals.each { @cache[_1] = Types::NIL }
- @local_variables = (local_variables | binding_local_variables).map(&:to_s).to_set
- @global_variables = Kernel.global_variables.map(&:to_s).to_set
- @owned_constants_cache = {}
- end
-
- def level() = 0
-
- def level_of(_name, _var_type) = 0
-
- def mutable?() = false
-
- def module_own_constant?(mod, name)
- set = (@owned_constants_cache[mod] ||= Set.new(mod.constants.map(&:to_s)))
- set.include? name
- end
-
- def get_const(nesting, path, _key = nil)
- return unless nesting
-
- result = path.reduce nesting do |mod, name|
- return nil unless mod.is_a?(Module) && module_own_constant?(mod, name)
- mod.const_get name
- end
- Types.type_from_object result
- end
-
- def get_cvar(nesting, path, name, _key = nil)
- return Types::NIL unless nesting
-
- result = path.reduce nesting do |mod, n|
- return Types::NIL unless mod.is_a?(Module) && module_own_constant?(mod, n)
- mod.const_get n
- end
- value = result.class_variable_get name if result.is_a?(Module) && name.size >= 3 && result.class_variable_defined?(name)
- Types.type_from_object value
- end
-
- def [](name)
- @cache[name] ||= (
- value = case RootScope.type_by_name name
- when :ivar
- begin
- Methods::OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(@self_object, name)
- rescue NameError
- end
- when :lvar
- begin
- @binding.local_variable_get(name)
- rescue NameError
- end
- when :gvar
- @binding.eval name if @global_variables.include? name
- end
- Types.type_from_object(value)
- )
- end
-
- def self_type
- Types.type_from_object @self_object
- end
-
- def local_variables() = @local_variables.to_a
-
- def global_variables() = @global_variables.to_a
-
- def self.type_by_name(name)
- if name.start_with? '@@'
- # "@@cvar" or "@@cvar::[module_id]::[module_path]"
- :cvar
- elsif name.start_with? '@'
- :ivar
- elsif name.start_with? '$'
- :gvar
- elsif name.start_with? '%'
- :internal
- elsif name[0].downcase != name[0] || name[0].match?(/\d/)
- # "ConstName" or "[module_id]::[const_path]"
- :const
- else
- :lvar
- end
- end
- end
-
- class Scope
- BREAK_RESULT = '%break'
- NEXT_RESULT = '%next'
- RETURN_RESULT = '%return'
- PATTERNMATCH_BREAK = '%match'
-
- attr_reader :parent, :mergeable_changes, :level, :module_nesting
-
- def self.from_binding(binding, locals) = new(RootScope.new(binding, binding.receiver, locals))
-
- def initialize(parent, table = {}, trace_ivar: true, trace_lvar: true, self_type: nil, nesting: nil)
- @parent = parent
- @level = parent.level + 1
- @trace_ivar = trace_ivar
- @trace_lvar = trace_lvar
- @module_nesting = nesting ? [nesting, *parent.module_nesting] : parent.module_nesting
- @self_type = self_type
- @terminated = false
- @jump_branches = []
- @mergeable_changes = @table = table.transform_values { [level, _1] }
- end
-
- def mutable? = true
-
- def terminated?
- @terminated
- end
-
- def terminate_with(type, value)
- return if terminated?
- store_jump type, value, @mergeable_changes
- terminate
- end
-
- def store_jump(type, value, changes)
- return if terminated?
- if has_own?(type)
- changes[type] = [level, value]
- @jump_branches << changes
- elsif @parent.mutable?
- @parent.store_jump(type, value, changes)
- end
- end
-
- def terminate
- return if terminated?
- @terminated = true
- @table = @mergeable_changes.dup
- end
-
- def trace?(name)
- return false unless @parent
- type = RootScope.type_by_name(name)
- type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
- end
-
- def level_of(name, var_type)
- case var_type
- when :ivar
- return level unless @trace_ivar
- when :gvar
- return 0
- end
- variable_level, = @table[name]
- variable_level || parent.level_of(name, var_type)
- end
-
- def get_const(nesting, path, key = nil)
- key ||= [nesting.__id__, path].join('::')
- _l, value = @table[key]
- value || @parent.get_const(nesting, path, key)
- end
-
- def get_cvar(nesting, path, name, key = nil)
- key ||= [name, nesting.__id__, path].join('::')
- _l, value = @table[key]
- value || @parent.get_cvar(nesting, path, name, key)
- end
-
- def [](name)
- type = RootScope.type_by_name(name)
- if type == :const
- return get_const(nil, nil, name) || Types::NIL if name.include?('::')
-
- module_nesting.each do |(nesting, path)|
- value = get_const nesting, [*path, name]
- return value if value
- end
- return Types::NIL
- elsif type == :cvar
- return get_cvar(nil, nil, nil, name) if name.include?('::')
-
- nesting, path = module_nesting.first
- return get_cvar(nesting, path, name)
- end
- level, value = @table[name]
- if level
- value
- elsif trace? name
- @parent[name]
- elsif type == :ivar
- self_instance_variable_get name
- end
- end
-
- def set_const(nesting, path, value)
- key = [nesting.__id__, path].join('::')
- @table[key] = [0, value]
- end
-
- def set_cvar(nesting, path, name, value)
- key = [name, nesting.__id__, path].join('::')
- @table[key] = [0, value]
- end
-
- def []=(name, value)
- type = RootScope.type_by_name(name)
- if type == :const
- if name.include?('::')
- @table[name] = [0, value]
- else
- parent_module, parent_path = module_nesting.first
- set_const parent_module, [*parent_path, name], value
- end
- return
- elsif type == :cvar
- if name.include?('::')
- @table[name] = [0, value]
- else
- parent_module, parent_path = module_nesting.first
- set_cvar parent_module, parent_path, name, value
- end
- return
- end
- variable_level = level_of name, type
- @table[name] = [variable_level, value] if variable_level
- end
-
- def self_type
- @self_type || @parent.self_type
- end
-
- def global_variables
- gvar_keys = @table.keys.select do |name|
- RootScope.type_by_name(name) == :gvar
- end
- gvar_keys | @parent.global_variables
- end
-
- def local_variables
- lvar_keys = @table.keys.select do |name|
- RootScope.type_by_name(name) == :lvar
- end
- lvar_keys |= @parent.local_variables if @trace_lvar
- lvar_keys
- end
-
- def table_constants
- constants = module_nesting.flat_map do |mod, path|
- prefix = [mod.__id__, *path].join('::') + '::'
- @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
- end.uniq
- constants |= @parent.table_constants if @parent.mutable?
- constants
- end
-
- def table_module_constants(mod)
- prefix = "#{mod.__id__}::"
- constants = @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
- constants |= @parent.table_constants if @parent.mutable?
- constants
- end
-
- def base_scope
- @parent.mutable? ? @parent.base_scope : @parent
- end
-
- def table_instance_variables
- ivars = @table.keys.select { RootScope.type_by_name(_1) == :ivar }
- ivars |= @parent.table_instance_variables if @parent.mutable? && @trace_ivar
- ivars
- end
-
- def instance_variables
- self_singleton_types = self_type.types.grep(Types::SingletonType)
- singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
- base_self = base_scope.self_object
- self_instance_variables = singleton_classes.flat_map do |singleton_class|
- if singleton_class.respond_to? :attached_object
- Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(singleton_class.attached_object).map(&:to_s)
- elsif singleton_class == Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(base_self)
- Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(base_self).map(&:to_s)
- else
- []
- end
- end
- [
- self_singleton_types.flat_map { _1.module_or_class.instance_variables.map(&:to_s) },
- self_instance_variables || [],
- table_instance_variables
- ].inject(:|)
- end
-
- def self_instance_variable_get(name)
- self_objects = self_type.types.grep(Types::SingletonType).map(&:module_or_class)
- singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
- base_self = base_scope.self_object
- singleton_classes.each do |singleton_class|
- if singleton_class.respond_to? :attached_object
- self_objects << singleton_class.attached_object
- elsif singleton_class == base_self.singleton_class
- self_objects << base_self
- end
- end
- types = self_objects.map do |object|
- value = begin
- Methods::OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(object, name)
- rescue NameError
- end
- Types.type_from_object value
- end
- Types::UnionType[*types]
- end
-
- def table_class_variables
- cvars = @table.keys.filter_map { _1.split('::', 2).first if RootScope.type_by_name(_1) == :cvar }
- cvars |= @parent.table_class_variables if @parent.mutable?
- cvars
- end
-
- def class_variables
- cvars = table_class_variables
- m, = module_nesting.first
- cvars |= m.class_variables.map(&:to_s) if m.is_a? Module
- cvars
- end
-
- def constants
- module_nesting.flat_map do |nest,|
- nest.constants
- end.map(&:to_s) | table_constants
- end
-
- def merge_jumps
- if terminated?
- @terminated = false
- @table = @mergeable_changes
- merge @jump_branches
- @terminated = true
- else
- merge [*@jump_branches, {}]
- end
- end
-
- def conditional(&block)
- run_branches(block, ->(_s) {}).first || Types::NIL
- end
-
- def never(&block)
- block.call Scope.new(self, { BREAK_RESULT => nil, NEXT_RESULT => nil, PATTERNMATCH_BREAK => nil, RETURN_RESULT => nil })
- end
-
- def run_branches(*blocks)
- results = []
- branches = []
- blocks.each do |block|
- scope = Scope.new self
- result = block.call scope
- next if scope.terminated?
- results << result
- branches << scope.mergeable_changes
- end
- terminate if branches.empty?
- merge branches
- results
- end
-
- def has_own?(name)
- @table.key? name
- end
-
- def update(child_scope)
- current_level = level
- child_scope.mergeable_changes.each do |name, (level, value)|
- self[name] = value if level <= current_level
- end
- end
-
- protected
-
- def merge(branches)
- current_level = level
- merge = {}
- branches.each do |changes|
- changes.each do |name, (level, value)|
- next if current_level < level
- (merge[name] ||= []) << value
- end
- end
- merge.each do |name, values|
- values << self[name] unless values.size == branches.size
- values.compact!
- self[name] = Types::UnionType[*values.compact] unless values.empty?
- end
- end
- end
- end
-end
diff --git a/lib/irb/type_completion/type_analyzer.rb b/lib/irb/type_completion/type_analyzer.rb
deleted file mode 100644
index c4a41e4999..0000000000
--- a/lib/irb/type_completion/type_analyzer.rb
+++ /dev/null
@@ -1,1169 +0,0 @@
-# frozen_string_literal: true
-
-require 'set'
-require_relative 'types'
-require_relative 'scope'
-require 'prism'
-
-module IRB
- module TypeCompletion
- class TypeAnalyzer
- class DigTarget
- def initialize(parents, receiver, &block)
- @dig_ids = parents.to_h { [_1.__id__, true] }
- @target_id = receiver.__id__
- @block = block
- end
-
- def dig?(node) = @dig_ids[node.__id__]
- def target?(node) = @target_id == node.__id__
- def resolve(type, scope)
- @block.call type, scope
- end
- end
-
- OBJECT_METHODS = {
- to_s: Types::STRING,
- to_str: Types::STRING,
- to_a: Types::ARRAY,
- to_ary: Types::ARRAY,
- to_h: Types::HASH,
- to_hash: Types::HASH,
- to_i: Types::INTEGER,
- to_int: Types::INTEGER,
- to_f: Types::FLOAT,
- to_c: Types::COMPLEX,
- to_r: Types::RATIONAL
- }
-
- def initialize(dig_targets)
- @dig_targets = dig_targets
- end
-
- def evaluate(node, scope)
- method = "evaluate_#{node.type}"
- if respond_to? method
- result = send method, node, scope
- else
- result = Types::NIL
- end
- @dig_targets.resolve result, scope if @dig_targets.target? node
- result
- end
-
- def evaluate_program_node(node, scope)
- evaluate node.statements, scope
- end
-
- def evaluate_statements_node(node, scope)
- if node.body.empty?
- Types::NIL
- else
- node.body.map { evaluate _1, scope }.last
- end
- end
-
- def evaluate_def_node(node, scope)
- if node.receiver
- self_type = evaluate node.receiver, scope
- else
- current_self_types = scope.self_type.types
- self_types = current_self_types.map do |type|
- if type.is_a?(Types::SingletonType) && type.module_or_class.is_a?(Class)
- Types::InstanceType.new type.module_or_class
- else
- type
- end
- end
- self_type = Types::UnionType[*self_types]
- end
- if @dig_targets.dig?(node.body) || @dig_targets.dig?(node.parameters)
- params_table = node.locals.to_h { [_1.to_s, Types::NIL] }
- method_scope = Scope.new(
- scope,
- { **params_table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil, Scope::RETURN_RESULT => nil },
- self_type: self_type,
- trace_lvar: false,
- trace_ivar: false
- )
- if node.parameters
- # node.parameters is Prism::ParametersNode
- assign_parameters node.parameters, method_scope, [], {}
- end
-
- if @dig_targets.dig?(node.body)
- method_scope.conditional do |s|
- evaluate node.body, s
- end
- end
- method_scope.merge_jumps
- scope.update method_scope
- end
- Types::SYMBOL
- end
-
- def evaluate_integer_node(_node, _scope) = Types::INTEGER
-
- def evaluate_float_node(_node, _scope) = Types::FLOAT
-
- def evaluate_rational_node(_node, _scope) = Types::RATIONAL
-
- def evaluate_imaginary_node(_node, _scope) = Types::COMPLEX
-
- def evaluate_string_node(_node, _scope) = Types::STRING
-
- def evaluate_x_string_node(_node, _scope)
- Types::UnionType[Types::STRING, Types::NIL]
- end
-
- def evaluate_symbol_node(_node, _scope) = Types::SYMBOL
-
- def evaluate_regular_expression_node(_node, _scope) = Types::REGEXP
-
- def evaluate_string_concat_node(node, scope)
- evaluate node.left, scope
- evaluate node.right, scope
- Types::STRING
- end
-
- def evaluate_interpolated_string_node(node, scope)
- node.parts.each { evaluate _1, scope }
- Types::STRING
- end
-
- def evaluate_interpolated_x_string_node(node, scope)
- node.parts.each { evaluate _1, scope }
- Types::STRING
- end
-
- def evaluate_interpolated_symbol_node(node, scope)
- node.parts.each { evaluate _1, scope }
- Types::SYMBOL
- end
-
- def evaluate_interpolated_regular_expression_node(node, scope)
- node.parts.each { evaluate _1, scope }
- Types::REGEXP
- end
-
- def evaluate_embedded_statements_node(node, scope)
- node.statements ? evaluate(node.statements, scope) : Types::NIL
- Types::STRING
- end
-
- def evaluate_embedded_variable_node(node, scope)
- evaluate node.variable, scope
- Types::STRING
- end
-
- def evaluate_array_node(node, scope)
- Types.array_of evaluate_list_splat_items(node.elements, scope)
- end
-
- def evaluate_hash_node(node, scope) = evaluate_hash(node, scope)
- def evaluate_keyword_hash_node(node, scope) = evaluate_hash(node, scope)
- def evaluate_hash(node, scope)
- keys = []
- values = []
- node.elements.each do |assoc|
- case assoc
- when Prism::AssocNode
- keys << evaluate(assoc.key, scope)
- values << evaluate(assoc.value, scope)
- when Prism::AssocSplatNode
- next unless assoc.value # def f(**); {**}
-
- hash = evaluate assoc.value, scope
- unless hash.is_a?(Types::InstanceType) && hash.klass == Hash
- hash = method_call hash, :to_hash, [], nil, nil, scope
- end
- if hash.is_a?(Types::InstanceType) && hash.klass == Hash
- keys << hash.params[:K] if hash.params[:K]
- values << hash.params[:V] if hash.params[:V]
- end
- end
- end
- if keys.empty? && values.empty?
- Types::InstanceType.new Hash
- else
- Types::InstanceType.new Hash, K: Types::UnionType[*keys], V: Types::UnionType[*values]
- end
- end
-
- def evaluate_parentheses_node(node, scope)
- node.body ? evaluate(node.body, scope) : Types::NIL
- end
-
- def evaluate_constant_path_node(node, scope)
- type, = evaluate_constant_node_info node, scope
- type
- end
-
- def evaluate_self_node(_node, scope) = scope.self_type
-
- def evaluate_true_node(_node, _scope) = Types::TRUE
-
- def evaluate_false_node(_node, _scope) = Types::FALSE
-
- def evaluate_nil_node(_node, _scope) = Types::NIL
-
- def evaluate_source_file_node(_node, _scope) = Types::STRING
-
- def evaluate_source_line_node(_node, _scope) = Types::INTEGER
-
- def evaluate_source_encoding_node(_node, _scope) = Types::InstanceType.new(Encoding)
-
- def evaluate_numbered_reference_read_node(_node, _scope)
- Types::UnionType[Types::STRING, Types::NIL]
- end
-
- def evaluate_back_reference_read_node(_node, _scope)
- Types::UnionType[Types::STRING, Types::NIL]
- end
-
- def evaluate_reference_read(node, scope)
- scope[node.name.to_s] || Types::NIL
- end
- alias evaluate_constant_read_node evaluate_reference_read
- alias evaluate_global_variable_read_node evaluate_reference_read
- alias evaluate_local_variable_read_node evaluate_reference_read
- alias evaluate_class_variable_read_node evaluate_reference_read
- alias evaluate_instance_variable_read_node evaluate_reference_read
-
-
- def evaluate_call_node(node, scope)
- is_field_assign = node.name.match?(/[^<>=!\]]=\z/) || (node.name == :[]= && !node.call_operator)
- receiver_type = node.receiver ? evaluate(node.receiver, scope) : scope.self_type
- evaluate_method = lambda do |scope|
- args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
-
- if block_sym_node
- block_sym = block_sym_node.value
- if @dig_targets.target? block_sym_node
- # method(args, &:completion_target)
- call_block_proc = ->(block_args, _self_type) do
- block_receiver = block_args.first || Types::OBJECT
- @dig_targets.resolve block_receiver, scope
- Types::OBJECT
- end
- else
- call_block_proc = ->(block_args, _self_type) do
- block_receiver, *rest = block_args
- block_receiver ? method_call(block_receiver || Types::OBJECT, block_sym, rest, nil, nil, scope) : Types::OBJECT
- end
- end
- elsif node.block.is_a? Prism::BlockNode
- call_block_proc = ->(block_args, block_self_type) do
- scope.conditional do |s|
- numbered_parameters = node.block.locals.grep(/\A_[1-9]/).map(&:to_s)
- params_table = node.block.locals.to_h { [_1.to_s, Types::NIL] }
- table = { **params_table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil }
- block_scope = Scope.new s, table, self_type: block_self_type, trace_ivar: !block_self_type
- # TODO kwargs
- if node.block.parameters&.parameters
- # node.block.parameters is Prism::BlockParametersNode
- assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
- elsif !numbered_parameters.empty?
- assign_numbered_parameters numbered_parameters, block_scope, block_args, {}
- end
- result = node.block.body ? evaluate(node.block.body, block_scope) : Types::NIL
- block_scope.merge_jumps
- s.update block_scope
- nexts = block_scope[Scope::NEXT_RESULT]
- breaks = block_scope[Scope::BREAK_RESULT]
- if block_scope.terminated?
- [Types::UnionType[*nexts], breaks]
- else
- [Types::UnionType[result, *nexts], breaks]
- end
- end
- end
- elsif has_block
- call_block_proc = ->(_block_args, _self_type) { Types::OBJECT }
- end
- result = method_call receiver_type, node.name, args_types, kwargs_types, call_block_proc, scope
- if is_field_assign
- args_types.last || Types::NIL
- else
- result
- end
- end
- if node.call_operator == '&.'
- result = scope.conditional { evaluate_method.call _1 }
- if receiver_type.nillable?
- Types::UnionType[result, Types::NIL]
- else
- result
- end
- else
- evaluate_method.call scope
- end
- end
-
- def evaluate_and_node(node, scope) = evaluate_and_or(node, scope, and_op: true)
- def evaluate_or_node(node, scope) = evaluate_and_or(node, scope, and_op: false)
- def evaluate_and_or(node, scope, and_op:)
- left = evaluate node.left, scope
- right = scope.conditional { evaluate node.right, _1 }
- if and_op
- Types::UnionType[right, Types::NIL, Types::FALSE]
- else
- Types::UnionType[left, right]
- end
- end
-
- def evaluate_call_operator_write_node(node, scope) = evaluate_call_write(node, scope, :operator, node.write_name)
- def evaluate_call_and_write_node(node, scope) = evaluate_call_write(node, scope, :and, node.write_name)
- def evaluate_call_or_write_node(node, scope) = evaluate_call_write(node, scope, :or, node.write_name)
- def evaluate_index_operator_write_node(node, scope) = evaluate_call_write(node, scope, :operator, :[]=)
- def evaluate_index_and_write_node(node, scope) = evaluate_call_write(node, scope, :and, :[]=)
- def evaluate_index_or_write_node(node, scope) = evaluate_call_write(node, scope, :or, :[]=)
- def evaluate_call_write(node, scope, operator, write_name)
- receiver_type = evaluate node.receiver, scope
- if write_name == :[]=
- args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
- else
- args_types = []
- end
- if block_sym_node
- block_sym = block_sym_node.value
- call_block_proc = ->(block_args, _self_type) do
- block_receiver, *rest = block_args
- block_receiver ? method_call(block_receiver || Types::OBJECT, block_sym, rest, nil, nil, scope) : Types::OBJECT
- end
- elsif has_block
- call_block_proc = ->(_block_args, _self_type) { Types::OBJECT }
- end
- method = write_name.to_s.delete_suffix('=')
- left = method_call receiver_type, method, args_types, kwargs_types, call_block_proc, scope
- case operator
- when :and
- right = scope.conditional { evaluate node.value, _1 }
- Types::UnionType[right, Types::NIL, Types::FALSE]
- when :or
- right = scope.conditional { evaluate node.value, _1 }
- Types::UnionType[left, right]
- else
- right = evaluate node.value, scope
- method_call left, node.operator, [right], nil, nil, scope, name_match: false
- end
- end
-
- def evaluate_variable_operator_write(node, scope)
- left = scope[node.name.to_s] || Types::OBJECT
- right = evaluate node.value, scope
- scope[node.name.to_s] = method_call left, node.operator, [right], nil, nil, scope, name_match: false
- end
- alias evaluate_global_variable_operator_write_node evaluate_variable_operator_write
- alias evaluate_local_variable_operator_write_node evaluate_variable_operator_write
- alias evaluate_class_variable_operator_write_node evaluate_variable_operator_write
- alias evaluate_instance_variable_operator_write_node evaluate_variable_operator_write
-
- def evaluate_variable_and_write(node, scope)
- right = scope.conditional { evaluate node.value, scope }
- scope[node.name.to_s] = Types::UnionType[right, Types::NIL, Types::FALSE]
- end
- alias evaluate_global_variable_and_write_node evaluate_variable_and_write
- alias evaluate_local_variable_and_write_node evaluate_variable_and_write
- alias evaluate_class_variable_and_write_node evaluate_variable_and_write
- alias evaluate_instance_variable_and_write_node evaluate_variable_and_write
-
- def evaluate_variable_or_write(node, scope)
- left = scope[node.name.to_s] || Types::OBJECT
- right = scope.conditional { evaluate node.value, scope }
- scope[node.name.to_s] = Types::UnionType[left, right]
- end
- alias evaluate_global_variable_or_write_node evaluate_variable_or_write
- alias evaluate_local_variable_or_write_node evaluate_variable_or_write
- alias evaluate_class_variable_or_write_node evaluate_variable_or_write
- alias evaluate_instance_variable_or_write_node evaluate_variable_or_write
-
- def evaluate_constant_operator_write_node(node, scope)
- left = scope[node.name.to_s] || Types::OBJECT
- right = evaluate node.value, scope
- scope[node.name.to_s] = method_call left, node.operator, [right], nil, nil, scope, name_match: false
- end
-
- def evaluate_constant_and_write_node(node, scope)
- right = scope.conditional { evaluate node.value, scope }
- scope[node.name.to_s] = Types::UnionType[right, Types::NIL, Types::FALSE]
- end
-
- def evaluate_constant_or_write_node(node, scope)
- left = scope[node.name.to_s] || Types::OBJECT
- right = scope.conditional { evaluate node.value, scope }
- scope[node.name.to_s] = Types::UnionType[left, right]
- end
-
- def evaluate_constant_path_operator_write_node(node, scope)
- left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
- right = evaluate node.value, scope
- value = method_call left, node.operator, [right], nil, nil, scope, name_match: false
- const_path_write receiver, name, value, scope
- value
- end
-
- def evaluate_constant_path_and_write_node(node, scope)
- _left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
- right = scope.conditional { evaluate node.value, scope }
- value = Types::UnionType[right, Types::NIL, Types::FALSE]
- const_path_write receiver, name, value, scope
- value
- end
-
- def evaluate_constant_path_or_write_node(node, scope)
- left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
- right = scope.conditional { evaluate node.value, scope }
- value = Types::UnionType[left, right]
- const_path_write receiver, name, value, scope
- value
- end
-
- def evaluate_constant_path_write_node(node, scope)
- receiver = evaluate node.target.parent, scope if node.target.parent
- value = evaluate node.value, scope
- const_path_write receiver, node.target.child.name.to_s, value, scope
- value
- end
-
- def evaluate_lambda_node(node, scope)
- local_table = node.locals.to_h { [_1.to_s, Types::OBJECT] }
- block_scope = Scope.new scope, { **local_table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil, Scope::RETURN_RESULT => nil }
- block_scope.conditional do |s|
- assign_parameters node.parameters.parameters, s, [], {} if node.parameters&.parameters
- evaluate node.body, s if node.body
- end
- block_scope.merge_jumps
- scope.update block_scope
- Types::PROC
- end
-
- def evaluate_reference_write(node, scope)
- scope[node.name.to_s] = evaluate node.value, scope
- end
- alias evaluate_constant_write_node evaluate_reference_write
- alias evaluate_global_variable_write_node evaluate_reference_write
- alias evaluate_local_variable_write_node evaluate_reference_write
- alias evaluate_class_variable_write_node evaluate_reference_write
- alias evaluate_instance_variable_write_node evaluate_reference_write
-
- def evaluate_multi_write_node(node, scope)
- evaluated_receivers = {}
- evaluate_multi_write_receiver node, scope, evaluated_receivers
- value = (
- if node.value.is_a? Prism::ArrayNode
- if node.value.elements.any?(Prism::SplatNode)
- evaluate node.value, scope
- else
- node.value.elements.map do |n|
- evaluate n, scope
- end
- end
- elsif node.value
- evaluate node.value, scope
- else
- Types::NIL
- end
- )
- evaluate_multi_write node, value, scope, evaluated_receivers
- value.is_a?(Array) ? Types.array_of(*value) : value
- end
-
- def evaluate_if_node(node, scope) = evaluate_if_unless(node, scope)
- def evaluate_unless_node(node, scope) = evaluate_if_unless(node, scope)
- def evaluate_if_unless(node, scope)
- evaluate node.predicate, scope
- Types::UnionType[*scope.run_branches(
- -> { node.statements ? evaluate(node.statements, _1) : Types::NIL },
- -> { node.consequent ? evaluate(node.consequent, _1) : Types::NIL }
- )]
- end
-
- def evaluate_else_node(node, scope)
- node.statements ? evaluate(node.statements, scope) : Types::NIL
- end
-
- def evaluate_while_until(node, scope)
- inner_scope = Scope.new scope, { Scope::BREAK_RESULT => nil }
- evaluate node.predicate, inner_scope
- if node.statements
- inner_scope.conditional do |s|
- evaluate node.statements, s
- end
- end
- inner_scope.merge_jumps
- scope.update inner_scope
- breaks = inner_scope[Scope::BREAK_RESULT]
- breaks ? Types::UnionType[breaks, Types::NIL] : Types::NIL
- end
- alias evaluate_while_node evaluate_while_until
- alias evaluate_until_node evaluate_while_until
-
- def evaluate_break_node(node, scope) = evaluate_jump(node, scope, :break)
- def evaluate_next_node(node, scope) = evaluate_jump(node, scope, :next)
- def evaluate_return_node(node, scope) = evaluate_jump(node, scope, :return)
- def evaluate_jump(node, scope, mode)
- internal_key = (
- case mode
- when :break
- Scope::BREAK_RESULT
- when :next
- Scope::NEXT_RESULT
- when :return
- Scope::RETURN_RESULT
- end
- )
- jump_value = (
- arguments = node.arguments&.arguments
- if arguments.nil? || arguments.empty?
- Types::NIL
- elsif arguments.size == 1 && !arguments.first.is_a?(Prism::SplatNode)
- evaluate arguments.first, scope
- else
- Types.array_of evaluate_list_splat_items(arguments, scope)
- end
- )
- scope.terminate_with internal_key, jump_value
- Types::NIL
- end
-
- def evaluate_yield_node(node, scope)
- evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
- Types::OBJECT
- end
-
- def evaluate_redo_node(_node, scope)
- scope.terminate
- Types::NIL
- end
-
- def evaluate_retry_node(_node, scope)
- scope.terminate
- Types::NIL
- end
-
- def evaluate_forwarding_super_node(_node, _scope) = Types::OBJECT
-
- def evaluate_super_node(node, scope)
- evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
- Types::OBJECT
- end
-
- def evaluate_begin_node(node, scope)
- return_type = node.statements ? evaluate(node.statements, scope) : Types::NIL
- if node.rescue_clause
- if node.else_clause
- return_types = scope.run_branches(
- ->{ evaluate node.rescue_clause, _1 },
- ->{ evaluate node.else_clause, _1 }
- )
- else
- return_types = [
- return_type,
- scope.conditional { evaluate node.rescue_clause, _1 }
- ]
- end
- return_type = Types::UnionType[*return_types]
- end
- if node.ensure_clause&.statements
- # ensure_clause is Prism::EnsureNode
- evaluate node.ensure_clause.statements, scope
- end
- return_type
- end
-
- def evaluate_rescue_node(node, scope)
- run_rescue = lambda do |s|
- if node.reference
- error_classes_type = evaluate_list_splat_items node.exceptions, s
- error_types = error_classes_type.types.filter_map do
- Types::InstanceType.new _1.module_or_class if _1.is_a?(Types::SingletonType)
- end
- error_types << Types::InstanceType.new(StandardError) if error_types.empty?
- error_type = Types::UnionType[*error_types]
- case node.reference
- when Prism::LocalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::ConstantTargetNode
- s[node.reference.name.to_s] = error_type
- when Prism::CallNode
- evaluate node.reference, s
- end
- end
- node.statements ? evaluate(node.statements, s) : Types::NIL
- end
- if node.consequent # begin; rescue A; rescue B; end
- types = scope.run_branches(
- run_rescue,
- -> { evaluate node.consequent, _1 }
- )
- Types::UnionType[*types]
- else
- run_rescue.call scope
- end
- end
-
- def evaluate_rescue_modifier_node(node, scope)
- a = evaluate node.expression, scope
- b = scope.conditional { evaluate node.rescue_expression, _1 }
- Types::UnionType[a, b]
- end
-
- def evaluate_singleton_class_node(node, scope)
- klass_types = evaluate(node.expression, scope).types.filter_map do |type|
- Types::SingletonType.new type.klass if type.is_a? Types::InstanceType
- end
- klass_types = [Types::CLASS] if klass_types.empty?
- table = node.locals.to_h { [_1.to_s, Types::NIL] }
- sclass_scope = Scope.new(
- scope,
- { **table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil, Scope::RETURN_RESULT => nil },
- trace_ivar: false,
- trace_lvar: false,
- self_type: Types::UnionType[*klass_types]
- )
- result = node.body ? evaluate(node.body, sclass_scope) : Types::NIL
- scope.update sclass_scope
- result
- end
-
- def evaluate_class_node(node, scope) = evaluate_class_module(node, scope, true)
- def evaluate_module_node(node, scope) = evaluate_class_module(node, scope, false)
- def evaluate_class_module(node, scope, is_class)
- unless node.constant_path.is_a?(Prism::ConstantReadNode) || node.constant_path.is_a?(Prism::ConstantPathNode)
- # Incomplete class/module `class (statement[cursor_here])::Name; end`
- evaluate node.constant_path, scope
- return Types::NIL
- end
- const_type, _receiver, parent_module, name = evaluate_constant_node_info node.constant_path, scope
- if is_class
- select_class_type = -> { _1.is_a?(Types::SingletonType) && _1.module_or_class.is_a?(Class) }
- module_types = const_type.types.select(&select_class_type)
- module_types += evaluate(node.superclass, scope).types.select(&select_class_type) if node.superclass
- module_types << Types::CLASS if module_types.empty?
- else
- module_types = const_type.types.select { _1.is_a?(Types::SingletonType) && !_1.module_or_class.is_a?(Class) }
- module_types << Types::MODULE if module_types.empty?
- end
- return Types::NIL unless node.body
-
- table = node.locals.to_h { [_1.to_s, Types::NIL] }
- if !name.empty? && (parent_module.is_a?(Module) || parent_module.nil?)
- value = parent_module.const_get name if parent_module&.const_defined? name
- unless value
- value_type = scope[name]
- value = value_type.module_or_class if value_type.is_a? Types::SingletonType
- end
-
- if value.is_a? Module
- nesting = [value, []]
- else
- if parent_module
- nesting = [parent_module, [name]]
- else
- parent_nesting, parent_path = scope.module_nesting.first
- nesting = [parent_nesting, parent_path + [name]]
- end
- nesting_key = [nesting[0].__id__, nesting[1]].join('::')
- nesting_value = is_class ? Types::CLASS : Types::MODULE
- end
- else
- # parent_module == :unknown
- # TODO: dummy module
- end
- module_scope = Scope.new(
- scope,
- { **table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil, Scope::RETURN_RESULT => nil },
- trace_ivar: false,
- trace_lvar: false,
- self_type: Types::UnionType[*module_types],
- nesting: nesting
- )
- module_scope[nesting_key] = nesting_value if nesting_value
- result = evaluate(node.body, module_scope)
- scope.update module_scope
- result
- end
-
- def evaluate_for_node(node, scope)
- node.statements
- collection = evaluate node.collection, scope
- inner_scope = Scope.new scope, { Scope::BREAK_RESULT => nil }
- ary_type = method_call collection, :to_ary, [], nil, nil, nil, name_match: false
- element_types = ary_type.types.filter_map do |ary|
- ary.params[:Elem] if ary.is_a?(Types::InstanceType) && ary.klass == Array
- end
- element_type = Types::UnionType[*element_types]
- inner_scope.conditional do |s|
- evaluate_write node.index, element_type, s, nil
- evaluate node.statements, s if node.statements
- end
- inner_scope.merge_jumps
- scope.update inner_scope
- breaks = inner_scope[Scope::BREAK_RESULT]
- breaks ? Types::UnionType[breaks, collection] : collection
- end
-
- def evaluate_case_node(node, scope)
- target = evaluate(node.predicate, scope) if node.predicate
- # TODO
- branches = node.conditions.map do |condition|
- ->(s) { evaluate_case_match target, condition, s }
- end
- if node.consequent
- branches << ->(s) { evaluate node.consequent, s }
- elsif node.conditions.any? { _1.is_a? Prism::WhenNode }
- branches << ->(_s) { Types::NIL }
- end
- Types::UnionType[*scope.run_branches(*branches)]
- end
-
- def evaluate_match_required_node(node, scope)
- value_type = evaluate node.value, scope
- evaluate_match_pattern value_type, node.pattern, scope
- Types::NIL # void value
- end
-
- def evaluate_match_predicate_node(node, scope)
- value_type = evaluate node.value, scope
- scope.conditional { evaluate_match_pattern value_type, node.pattern, _1 }
- Types::BOOLEAN
- end
-
- def evaluate_range_node(node, scope)
- beg_type = evaluate node.left, scope if node.left
- end_type = evaluate node.right, scope if node.right
- elem = (Types::UnionType[*[beg_type, end_type].compact]).nonnillable
- Types::InstanceType.new Range, Elem: elem
- end
-
- def evaluate_defined_node(node, scope)
- scope.conditional { evaluate node.value, _1 }
- Types::UnionType[Types::STRING, Types::NIL]
- end
-
- def evaluate_flip_flop_node(node, scope)
- scope.conditional { evaluate node.left, _1 } if node.left
- scope.conditional { evaluate node.right, _1 } if node.right
- Types::BOOLEAN
- end
-
- def evaluate_multi_target_node(node, scope)
- # Raw MultiTargetNode, incomplete code like `a,b`, `*a`.
- evaluate_multi_write_receiver node, scope, nil
- Types::NIL
- end
-
- def evaluate_splat_node(node, scope)
- # Raw SplatNode, incomplete code like `*a.`
- evaluate_multi_write_receiver node.expression, scope, nil if node.expression
- Types::NIL
- end
-
- def evaluate_implicit_node(node, scope)
- evaluate node.value, scope
- end
-
- def evaluate_match_write_node(node, scope)
- # /(?<a>)(?<b>)/ =~ string
- evaluate node.call, scope
- node.locals.each { scope[_1.to_s] = Types::UnionType[Types::STRING, Types::NIL] }
- Types::BOOLEAN
- end
-
- def evaluate_match_last_line_node(_node, _scope)
- Types::BOOLEAN
- end
-
- def evaluate_interpolated_match_last_line_node(node, scope)
- node.parts.each { evaluate _1, scope }
- Types::BOOLEAN
- end
-
- def evaluate_pre_execution_node(node, scope)
- node.statements ? evaluate(node.statements, scope) : Types::NIL
- end
-
- def evaluate_post_execution_node(node, scope)
- node.statements && @dig_targets.dig?(node.statements) ? evaluate(node.statements, scope) : Types::NIL
- end
-
- def evaluate_alias_method_node(_node, _scope) = Types::NIL
- def evaluate_alias_global_variable_node(_node, _scope) = Types::NIL
- def evaluate_undef_node(_node, _scope) = Types::NIL
- def evaluate_missing_node(_node, _scope) = Types::NIL
-
- def evaluate_call_node_arguments(call_node, scope)
- # call_node.arguments is Prism::ArgumentsNode
- arguments = call_node.arguments&.arguments&.dup || []
- block_arg = call_node.block.expression if call_node.block.is_a?(Prism::BlockArgumentNode)
- kwargs = arguments.pop.elements if arguments.last.is_a?(Prism::KeywordHashNode)
- args_types = arguments.map do |arg|
- case arg
- when Prism::ForwardingArgumentsNode
- # `f(a, ...)` treat like splat
- nil
- when Prism::SplatNode
- evaluate arg.expression, scope if arg.expression
- nil # TODO: splat
- else
- evaluate arg, scope
- end
- end
- if kwargs
- kwargs_types = kwargs.map do |arg|
- case arg
- when Prism::AssocNode
- if arg.key.is_a?(Prism::SymbolNode)
- [arg.key.value, evaluate(arg.value, scope)]
- else
- evaluate arg.key, scope
- evaluate arg.value, scope
- nil
- end
- when Prism::AssocSplatNode
- evaluate arg.value, scope if arg.value
- nil
- end
- end.compact.to_h
- end
- if block_arg.is_a? Prism::SymbolNode
- block_sym_node = block_arg
- elsif block_arg
- evaluate block_arg, scope
- end
- [args_types, kwargs_types, block_sym_node, !!block_arg]
- end
-
- def const_path_write(receiver, name, value, scope)
- if receiver # receiver::A = value
- singleton_type = receiver.types.find { _1.is_a? Types::SingletonType }
- scope.set_const singleton_type.module_or_class, name, value if singleton_type
- else # ::A = value
- scope.set_const Object, name, value
- end
- end
-
- def assign_required_parameter(node, value, scope)
- case node
- when Prism::RequiredParameterNode
- scope[node.name.to_s] = value || Types::OBJECT
- when Prism::MultiTargetNode
- parameters = [*node.lefts, *node.rest, *node.rights]
- values = value ? sized_splat(value, :to_ary, parameters.size) : []
- parameters.zip values do |n, v|
- assign_required_parameter n, v, scope
- end
- when Prism::SplatNode
- splat_value = value ? Types.array_of(value) : Types::ARRAY
- assign_required_parameter node.expression, splat_value, scope if node.expression
- end
- end
-
- def evaluate_constant_node_info(node, scope)
- case node
- when Prism::ConstantPathNode
- name = node.child.name.to_s
- if node.parent
- receiver = evaluate node.parent, scope
- if receiver.is_a? Types::SingletonType
- parent_module = receiver.module_or_class
- end
- else
- parent_module = Object
- end
- if parent_module
- type = scope.get_const(parent_module, [name]) || Types::NIL
- else
- parent_module = :unknown
- type = Types::NIL
- end
- when Prism::ConstantReadNode
- name = node.name.to_s
- type = scope[name]
- end
- @dig_targets.resolve type, scope if @dig_targets.target? node
- [type, receiver, parent_module, name]
- end
-
-
- def assign_parameters(node, scope, args, kwargs)
- args = args.dup
- kwargs = kwargs.dup
- size = node.requireds.size + node.optionals.size + (node.rest ? 1 : 0) + node.posts.size
- args = sized_splat(args.first, :to_ary, size) if size >= 2 && args.size == 1
- reqs = args.shift node.requireds.size
- if node.rest
- # node.rest is Prism::RestParameterNode
- posts = []
- opts = args.shift node.optionals.size
- rest = args
- else
- posts = args.pop node.posts.size
- opts = args
- rest = []
- end
- node.requireds.zip reqs do |n, v|
- assign_required_parameter n, v, scope
- end
- node.optionals.zip opts do |n, v|
- # n is Prism::OptionalParameterNode
- values = [v]
- values << evaluate(n.value, scope) if n.value
- scope[n.name.to_s] = Types::UnionType[*values.compact]
- end
- node.posts.zip posts do |n, v|
- assign_required_parameter n, v, scope
- end
- if node.rest&.name
- # node.rest is Prism::RestParameterNode
- scope[node.rest.name.to_s] = Types.array_of(*rest)
- end
- node.keywords.each do |n|
- name = n.name.to_s.delete(':')
- values = [kwargs.delete(name)]
- # n is Prism::OptionalKeywordParameterNode (has n.value) or Prism::RequiredKeywordParameterNode (does not have n.value)
- values << evaluate(n.value, scope) if n.respond_to?(:value)
- scope[name] = Types::UnionType[*values.compact]
- end
- # node.keyword_rest is Prism::KeywordRestParameterNode or Prism::ForwardingParameterNode or Prism::NoKeywordsParameterNode
- if node.keyword_rest.is_a?(Prism::KeywordRestParameterNode) && node.keyword_rest.name
- scope[node.keyword_rest.name.to_s] = Types::InstanceType.new(Hash, K: Types::SYMBOL, V: Types::UnionType[*kwargs.values])
- end
- if node.block&.name
- # node.block is Prism::BlockParameterNode
- scope[node.block.name.to_s] = Types::PROC
- end
- end
-
- def assign_numbered_parameters(numbered_parameters, scope, args, _kwargs)
- return if numbered_parameters.empty?
- max_num = numbered_parameters.map { _1[1].to_i }.max
- if max_num == 1
- scope['_1'] = args.first || Types::NIL
- else
- args = sized_splat(args.first, :to_ary, max_num) if args.size == 1
- numbered_parameters.each do |name|
- index = name[1].to_i - 1
- scope[name] = args[index] || Types::NIL
- end
- end
- end
-
- def evaluate_case_match(target, node, scope)
- case node
- when Prism::WhenNode
- node.conditions.each { evaluate _1, scope }
- node.statements ? evaluate(node.statements, scope) : Types::NIL
- when Prism::InNode
- pattern = node.pattern
- if pattern.is_a?(Prism::IfNode) || pattern.is_a?(Prism::UnlessNode)
- cond_node = pattern.predicate
- pattern = pattern.statements.body.first
- end
- evaluate_match_pattern(target, pattern, scope)
- evaluate cond_node, scope if cond_node # TODO: conditional branch
- node.statements ? evaluate(node.statements, scope) : Types::NIL
- end
- end
-
- def evaluate_match_pattern(value, pattern, scope)
- # TODO: scope.terminate_with Scope::PATTERNMATCH_BREAK, Types::NIL
- case pattern
- when Prism::FindPatternNode
- # TODO
- evaluate_match_pattern Types::OBJECT, pattern.left, scope
- pattern.requireds.each { evaluate_match_pattern Types::OBJECT, _1, scope }
- evaluate_match_pattern Types::OBJECT, pattern.right, scope
- when Prism::ArrayPatternNode
- # TODO
- pattern.requireds.each { evaluate_match_pattern Types::OBJECT, _1, scope }
- evaluate_match_pattern Types::OBJECT, pattern.rest, scope if pattern.rest
- pattern.posts.each { evaluate_match_pattern Types::OBJECT, _1, scope }
- Types::ARRAY
- when Prism::HashPatternNode
- # TODO
- pattern.elements.each { evaluate_match_pattern Types::OBJECT, _1, scope }
- if pattern.respond_to?(:rest) && pattern.rest
- evaluate_match_pattern Types::OBJECT, pattern.rest, scope
- end
- Types::HASH
- when Prism::AssocNode
- evaluate_match_pattern value, pattern.value, scope if pattern.value
- Types::OBJECT
- when Prism::AssocSplatNode
- # TODO
- evaluate_match_pattern Types::HASH, pattern.value, scope
- Types::OBJECT
- when Prism::PinnedVariableNode
- evaluate pattern.variable, scope
- when Prism::PinnedExpressionNode
- evaluate pattern.expression, scope
- when Prism::LocalVariableTargetNode
- scope[pattern.name.to_s] = value
- when Prism::AlternationPatternNode
- Types::UnionType[evaluate_match_pattern(value, pattern.left, scope), evaluate_match_pattern(value, pattern.right, scope)]
- when Prism::CapturePatternNode
- capture_type = class_or_value_to_instance evaluate_match_pattern(value, pattern.value, scope)
- value = capture_type unless capture_type.types.empty? || capture_type.types == [Types::OBJECT]
- evaluate_match_pattern value, pattern.target, scope
- when Prism::SplatNode
- value = Types.array_of value
- evaluate_match_pattern value, pattern.expression, scope if pattern.expression
- value
- else
- # literal node
- type = evaluate(pattern, scope)
- class_or_value_to_instance(type)
- end
- end
-
- def class_or_value_to_instance(type)
- instance_types = type.types.map do |t|
- t.is_a?(Types::SingletonType) ? Types::InstanceType.new(t.module_or_class) : t
- end
- Types::UnionType[*instance_types]
- end
-
- def evaluate_write(node, value, scope, evaluated_receivers)
- case node
- when Prism::MultiTargetNode
- evaluate_multi_write node, value, scope, evaluated_receivers
- when Prism::CallNode
- evaluated_receivers&.[](node.receiver) || evaluate(node.receiver, scope) if node.receiver
- when Prism::SplatNode
- evaluate_write node.expression, Types.array_of(value), scope, evaluated_receivers if node.expression
- when Prism::LocalVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::ConstantTargetNode
- scope[node.name.to_s] = value
- when Prism::ConstantPathTargetNode
- receiver = evaluated_receivers&.[](node.parent) || evaluate(node.parent, scope) if node.parent
- const_path_write receiver, node.child.name.to_s, value, scope
- value
- end
- end
-
- def evaluate_multi_write(node, values, scope, evaluated_receivers)
- pre_targets = node.lefts
- splat_target = node.rest
- post_targets = node.rights
- size = pre_targets.size + (splat_target ? 1 : 0) + post_targets.size
- values = values.is_a?(Array) ? values.dup : sized_splat(values, :to_ary, size)
- pre_pairs = pre_targets.zip(values.shift(pre_targets.size))
- post_pairs = post_targets.zip(values.pop(post_targets.size))
- splat_pairs = splat_target ? [[splat_target, Types::UnionType[*values]]] : []
- (pre_pairs + splat_pairs + post_pairs).each do |target, value|
- evaluate_write target, value || Types::NIL, scope, evaluated_receivers
- end
- end
-
- def evaluate_multi_write_receiver(node, scope, evaluated_receivers)
- case node
- when Prism::MultiWriteNode, Prism::MultiTargetNode
- targets = [*node.lefts, *node.rest, *node.rights]
- targets.each { evaluate_multi_write_receiver _1, scope, evaluated_receivers }
- when Prism::CallNode
- if node.receiver
- receiver = evaluate(node.receiver, scope)
- evaluated_receivers[node.receiver] = receiver if evaluated_receivers
- end
- if node.arguments
- node.arguments.arguments&.each do |arg|
- if arg.is_a? Prism::SplatNode
- evaluate arg.expression, scope
- else
- evaluate arg, scope
- end
- end
- end
- when Prism::SplatNode
- evaluate_multi_write_receiver node.expression, scope, evaluated_receivers if node.expression
- end
- end
-
- def evaluate_list_splat_items(list, scope)
- items = list.flat_map do |node|
- if node.is_a? Prism::SplatNode
- next unless node.expression # def f(*); [*]
-
- splat = evaluate node.expression, scope
- array_elem, non_array = partition_to_array splat.nonnillable, :to_a
- [*array_elem, *non_array]
- else
- evaluate node, scope
- end
- end.compact.uniq
- Types::UnionType[*items]
- end
-
- def sized_splat(value, method, size)
- array_elem, non_array = partition_to_array value, method
- values = [Types::UnionType[*array_elem, *non_array]]
- values += [array_elem] * (size - 1) if array_elem && size >= 1
- values
- end
-
- def partition_to_array(value, method)
- arrays, non_arrays = value.types.partition { _1.is_a?(Types::InstanceType) && _1.klass == Array }
- non_arrays.select! do |type|
- to_array_result = method_call type, method, [], nil, nil, nil, name_match: false
- if to_array_result.is_a?(Types::InstanceType) && to_array_result.klass == Array
- arrays << to_array_result
- false
- else
- true
- end
- end
- array_elem = arrays.empty? ? nil : Types::UnionType[*arrays.map { _1.params[:Elem] || Types::OBJECT }]
- non_array = non_arrays.empty? ? nil : Types::UnionType[*non_arrays]
- [array_elem, non_array]
- end
-
- def method_call(receiver, method_name, args, kwargs, block, scope, name_match: true)
- methods = Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
- block_called = false
- type_breaks = methods.map do |method, given_params, method_params|
- receiver_vars = receiver.is_a?(Types::InstanceType) ? receiver.params : {}
- free_vars = method.type.free_variables - receiver_vars.keys.to_set
- vars = receiver_vars.merge Types.match_free_variables(free_vars, method_params, given_params)
- if block && method.block
- params_type = method.block.type.required_positionals.map do |func_param|
- Types.from_rbs_type func_param.type, receiver, vars
- end
- self_type = Types.from_rbs_type method.block.self_type, receiver, vars if method.block.self_type
- block_response, breaks = block.call params_type, self_type
- block_called = true
- vars.merge! Types.match_free_variables(free_vars - vars.keys.to_set, [method.block.type.return_type], [block_response])
- end
- if Types.method_return_bottom?(method)
- [nil, breaks]
- else
- [Types.from_rbs_type(method.type.return_type, receiver, vars || {}), breaks]
- end
- end
- block&.call [], nil unless block_called
- terminates = !type_breaks.empty? && type_breaks.map(&:first).all?(&:nil?)
- types = type_breaks.map(&:first).compact
- breaks = type_breaks.map(&:last).compact
- types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
-
- if method_name.to_sym == :new
- receiver.types.each do |type|
- if type.is_a?(Types::SingletonType) && type.module_or_class.is_a?(Class)
- types << Types::InstanceType.new(type.module_or_class)
- end
- end
- end
- scope&.terminate if terminates && breaks.empty?
- Types::UnionType[*types, *breaks]
- end
-
- def self.calculate_target_type_scope(binding, parents, target)
- dig_targets = DigTarget.new(parents, target) do |type, scope|
- return type, scope
- end
- program = parents.first
- scope = Scope.from_binding(binding, program.locals)
- new(dig_targets).evaluate program, scope
- [Types::NIL, scope]
- end
- end
- end
-end
diff --git a/lib/irb/type_completion/types.rb b/lib/irb/type_completion/types.rb
deleted file mode 100644
index f0f2342ffe..0000000000
--- a/lib/irb/type_completion/types.rb
+++ /dev/null
@@ -1,426 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'methods'
-
-module IRB
- module TypeCompletion
- module Types
- OBJECT_TO_TYPE_SAMPLE_SIZE = 50
-
- singleton_class.attr_reader :rbs_builder, :rbs_load_error
-
- def self.preload_in_thread
- return if @preload_started
-
- @preload_started = true
- Thread.new do
- load_rbs_builder
- end
- end
-
- def self.load_rbs_builder
- require 'rbs'
- require 'rbs/cli'
- loader = RBS::CLI::LibraryOptions.new.loader
- loader.add path: Pathname('sig')
- @rbs_builder = RBS::DefinitionBuilder.new env: RBS::Environment.from_loader(loader).resolve_type_names
- rescue LoadError, StandardError => e
- @rbs_load_error = e
- nil
- end
-
- def self.class_name_of(klass)
- klass = klass.superclass if klass.singleton_class?
- Methods::MODULE_NAME_METHOD.bind_call klass
- end
-
- def self.rbs_search_method(klass, method_name, singleton)
- klass.ancestors.each do |ancestor|
- name = class_name_of ancestor
- next unless name && rbs_builder
- type_name = RBS::TypeName(name).absolute!
- definition = (singleton ? rbs_builder.build_singleton(type_name) : rbs_builder.build_instance(type_name)) rescue nil
- method = definition.methods[method_name] if definition
- return method if method
- end
- nil
- end
-
- def self.method_return_type(type, method_name)
- receivers = type.types.map do |t|
- case t
- in SingletonType
- [t, t.module_or_class, true]
- in InstanceType
- [t, t.klass, false]
- end
- end
- types = receivers.flat_map do |receiver_type, klass, singleton|
- method = rbs_search_method klass, method_name, singleton
- next [] unless method
- method.method_types.map do |method|
- from_rbs_type(method.type.return_type, receiver_type, {})
- end
- end
- UnionType[*types]
- end
-
- def self.rbs_methods(type, method_name, args_types, kwargs_type, has_block)
- return [] unless rbs_builder
-
- receivers = type.types.map do |t|
- case t
- in SingletonType
- [t, t.module_or_class, true]
- in InstanceType
- [t, t.klass, false]
- end
- end
- has_splat = args_types.include?(nil)
- methods_with_score = receivers.flat_map do |receiver_type, klass, singleton|
- method = rbs_search_method klass, method_name, singleton
- next [] unless method
- method.method_types.map do |method_type|
- score = 0
- score += 2 if !!method_type.block == has_block
- reqs = method_type.type.required_positionals
- opts = method_type.type.optional_positionals
- rest = method_type.type.rest_positionals
- trailings = method_type.type.trailing_positionals
- keyreqs = method_type.type.required_keywords
- keyopts = method_type.type.optional_keywords
- keyrest = method_type.type.rest_keywords
- args = args_types
- if kwargs_type&.any? && keyreqs.empty? && keyopts.empty? && keyrest.nil?
- kw_value_type = UnionType[*kwargs_type.values]
- args += [InstanceType.new(Hash, K: SYMBOL, V: kw_value_type)]
- end
- if has_splat
- score += 1 if args.count(&:itself) <= reqs.size + opts.size + trailings.size
- elsif reqs.size + trailings.size <= args.size && (rest || args.size <= reqs.size + opts.size + trailings.size)
- score += 2
- centers = args[reqs.size...-trailings.size]
- given = args.first(reqs.size) + centers.take(opts.size) + args.last(trailings.size)
- expected = (reqs + opts.take(centers.size) + trailings).map(&:type)
- if rest
- given << UnionType[*centers.drop(opts.size)]
- expected << rest.type
- end
- if given.any?
- score += given.zip(expected).count do |t, e|
- e = from_rbs_type e, receiver_type
- intersect?(t, e) || (intersect?(STRING, e) && t.methods.include?(:to_str)) || (intersect?(INTEGER, e) && t.methods.include?(:to_int)) || (intersect?(ARRAY, e) && t.methods.include?(:to_ary))
- end.fdiv(given.size)
- end
- end
- [[method_type, given || [], expected || []], score]
- end
- end
- max_score = methods_with_score.map(&:last).max
- methods_with_score.select { _2 == max_score }.map(&:first)
- end
-
- def self.intersect?(a, b)
- atypes = a.types.group_by(&:class)
- btypes = b.types.group_by(&:class)
- if atypes[SingletonType] && btypes[SingletonType]
- aa, bb = [atypes, btypes].map {|types| types[SingletonType].map(&:module_or_class) }
- return true if (aa & bb).any?
- end
-
- aa, bb = [atypes, btypes].map {|types| (types[InstanceType] || []).map(&:klass) }
- (aa.flat_map(&:ancestors) & bb).any?
- end
-
- def self.type_from_object(object)
- case object
- when Array
- InstanceType.new Array, { Elem: union_type_from_objects(object) }
- when Hash
- InstanceType.new Hash, { K: union_type_from_objects(object.keys), V: union_type_from_objects(object.values) }
- when Module
- SingletonType.new object
- else
- klass = Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(object) rescue Methods::OBJECT_CLASS_METHOD.bind_call(object)
- InstanceType.new klass
- end
- end
-
- def self.union_type_from_objects(objects)
- values = objects.size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
- klasses = values.map { Methods::OBJECT_CLASS_METHOD.bind_call(_1) }
- UnionType[*klasses.uniq.map { InstanceType.new _1 }]
- end
-
- class SingletonType
- attr_reader :module_or_class
- def initialize(module_or_class)
- @module_or_class = module_or_class
- end
- def transform() = yield(self)
- def methods() = @module_or_class.methods
- def all_methods() = methods | Kernel.methods
- def constants() = @module_or_class.constants
- def types() = [self]
- def nillable?() = false
- def nonnillable() = self
- def inspect
- "#{module_or_class}.itself"
- end
- end
-
- class InstanceType
- attr_reader :klass, :params
- def initialize(klass, params = {})
- @klass = klass
- @params = params
- end
- def transform() = yield(self)
- def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods
- def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods
- def constants() = []
- def types() = [self]
- def nillable?() = (@klass == NilClass)
- def nonnillable() = self
- def rbs_methods
- name = Types.class_name_of(@klass)
- return {} unless name && Types.rbs_builder
-
- type_name = RBS::TypeName(name).absolute!
- Types.rbs_builder.build_instance(type_name).methods rescue {}
- end
- def inspect
- if params.empty?
- inspect_without_params
- else
- params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
- "#{inspect_without_params}#{params_string}"
- end
- end
- def inspect_without_params
- if klass == NilClass
- 'nil'
- elsif klass == TrueClass
- 'true'
- elsif klass == FalseClass
- 'false'
- else
- klass.singleton_class? ? klass.superclass.to_s : klass.to_s
- end
- end
- end
-
- NIL = InstanceType.new NilClass
- OBJECT = InstanceType.new Object
- TRUE = InstanceType.new TrueClass
- FALSE = InstanceType.new FalseClass
- SYMBOL = InstanceType.new Symbol
- STRING = InstanceType.new String
- INTEGER = InstanceType.new Integer
- RANGE = InstanceType.new Range
- REGEXP = InstanceType.new Regexp
- FLOAT = InstanceType.new Float
- RATIONAL = InstanceType.new Rational
- COMPLEX = InstanceType.new Complex
- ARRAY = InstanceType.new Array
- HASH = InstanceType.new Hash
- CLASS = InstanceType.new Class
- MODULE = InstanceType.new Module
- PROC = InstanceType.new Proc
-
- class UnionType
- attr_reader :types
-
- def initialize(*types)
- @types = []
- singletons = []
- instances = {}
- collect = -> type do
- case type
- in UnionType
- type.types.each(&collect)
- in InstanceType
- params = (instances[type.klass] ||= {})
- type.params.each do |k, v|
- (params[k] ||= []) << v
- end
- in SingletonType
- singletons << type
- end
- end
- types.each(&collect)
- @types = singletons.uniq + instances.map do |klass, params|
- InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
- end
- end
-
- def transform(&block)
- UnionType[*types.map(&block)]
- end
-
- def nillable?
- types.any?(&:nillable?)
- end
-
- def nonnillable
- UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
- end
-
- def self.[](*types)
- type = new(*types)
- if type.types.empty?
- OBJECT
- elsif type.types.size == 1
- type.types.first
- else
- type
- end
- end
-
- def methods() = @types.flat_map(&:methods).uniq
- def all_methods() = @types.flat_map(&:all_methods).uniq
- def constants() = @types.flat_map(&:constants).uniq
- def inspect() = @types.map(&:inspect).join(' | ')
- end
-
- BOOLEAN = UnionType[TRUE, FALSE]
-
- def self.array_of(*types)
- type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
- InstanceType.new Array, Elem: type
- end
-
- def self.from_rbs_type(return_type, self_type, extra_vars = {})
- case return_type
- when RBS::Types::Bases::Self
- self_type
- when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
- NIL
- when RBS::Types::Bases::Any, RBS::Types::Bases::Void
- OBJECT
- when RBS::Types::Bases::Class
- self_type.transform do |type|
- case type
- in SingletonType
- InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
- in InstanceType
- SingletonType.new type.klass
- end
- end
- UnionType[*types]
- when RBS::Types::Bases::Bool
- BOOLEAN
- when RBS::Types::Bases::Instance
- self_type.transform do |type|
- if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
- InstanceType.new type.module_or_class
- else
- OBJECT
- end
- end
- when RBS::Types::Union
- UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
- when RBS::Types::Proc
- PROC
- when RBS::Types::Tuple
- elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
- InstanceType.new Array, Elem: elem
- when RBS::Types::Record
- InstanceType.new Hash, K: SYMBOL, V: OBJECT
- when RBS::Types::Literal
- InstanceType.new return_type.literal.class
- when RBS::Types::Variable
- if extra_vars.key? return_type.name
- extra_vars[return_type.name]
- elsif self_type.is_a? InstanceType
- self_type.params[return_type.name] || OBJECT
- elsif self_type.is_a? UnionType
- types = self_type.types.filter_map do |t|
- t.params[return_type.name] if t.is_a? InstanceType
- end
- UnionType[*types]
- else
- OBJECT
- end
- when RBS::Types::Optional
- UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
- when RBS::Types::Alias
- case return_type.name.name
- when :int
- INTEGER
- when :boolish
- BOOLEAN
- when :string
- STRING
- else
- # TODO: ???
- OBJECT
- end
- when RBS::Types::Interface
- # unimplemented
- OBJECT
- when RBS::Types::ClassInstance
- klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
- if return_type.args
- args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
- names = rbs_builder.build_singleton(return_type.name).type_params
- params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
- end
- InstanceType.new klass, params || {}
- end
- end
-
- def self.method_return_bottom?(method)
- method.type.return_type.is_a? RBS::Types::Bases::Bottom
- end
-
- def self.match_free_variables(vars, types, values)
- accumulator = {}
- types.zip values do |t, v|
- _match_free_variable(vars, t, v, accumulator) if v
- end
- accumulator.transform_values { UnionType[*_1] }
- end
-
- def self._match_free_variable(vars, rbs_type, value, accumulator)
- case [rbs_type, value]
- in [RBS::Types::Variable,]
- (accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
- in [RBS::Types::ClassInstance, InstanceType]
- names = rbs_builder.build_singleton(rbs_type.name).type_params
- names.zip(rbs_type.args).each do |name, arg|
- v = value.params[name]
- _match_free_variable vars, arg, v, accumulator if v
- end
- in [RBS::Types::Tuple, InstanceType] if value.klass == Array
- v = value.params[:Elem]
- rbs_type.types.each do |t|
- _match_free_variable vars, t, v, accumulator
- end
- in [RBS::Types::Record, InstanceType] if value.klass == Hash
- # TODO
- in [RBS::Types::Interface,]
- definition = rbs_builder.build_interface rbs_type.name
- convert = {}
- definition.type_params.zip(rbs_type.args).each do |from, arg|
- convert[from] = arg.name if arg.is_a? RBS::Types::Variable
- end
- return if convert.empty?
- ac = {}
- definition.methods.each do |method_name, method|
- return_type = method_return_type value, method_name
- method.defs.each do |method_def|
- interface_return_type = method_def.type.type.return_type
- _match_free_variable convert, interface_return_type, return_type, ac
- end
- end
- convert.each do |from, to|
- values = ac[from]
- (accumulator[to] ||= []).concat values if values
- end
- else
- end
- end
- end
- end
-end
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
index c33c4f798c..d1c0e54fdc 100644
--- a/lib/irb/version.rb
+++ b/lib/irb/version.rb
@@ -1,11 +1,17 @@
# frozen_string_literal: false
#
# irb/version.rb - irb version definition file
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#
+# --
+#
+#
+#
module IRB # :nodoc:
- VERSION = "1.9.0"
+ VERSION = "1.6.2"
@RELEASE_VERSION = VERSION
- @LAST_UPDATE_DATE = "2023-11-11"
+ @LAST_UPDATE_DATE = "2022-12-13"
end
diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb
index 2bf3d5e0f1..e5ef52528a 100644
--- a/lib/irb/workspace.rb
+++ b/lib/irb/workspace.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# irb/workspace-binding.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require "delegate"
@@ -108,12 +114,8 @@ EOF
# <code>IRB.conf[:__MAIN__]</code>
attr_reader :main
- def load_commands_to_main
- main.extend ExtendCommandBundle
- end
-
# Evaluate the given +statements+ within the context of this workspace.
- def evaluate(statements, file = __FILE__, line = __LINE__)
+ def evaluate(context, statements, file = __FILE__, line = __LINE__)
eval(statements, @binding, file, line)
end
@@ -126,8 +128,6 @@ EOF
end
# error message manipulator
- # WARN: Rails patches this method to filter its own backtrace. Be cautious when changing it.
- # See: https://github.com/rails/rails/blob/main/railties/lib/rails/commands/console/console_command.rb#L8:~:text=def,filter_backtrace
def filter_backtrace(bt)
return nil if bt =~ /\/irb\/.*\.rb/
return nil if bt =~ /\/irb\.rb/
@@ -142,7 +142,11 @@ EOF
end
def code_around_binding
- file, pos = @binding.source_location
+ if @binding.respond_to?(:source_location)
+ file, pos = @binding.source_location
+ else
+ file, pos = @binding.eval('[__FILE__, __LINE__]')
+ end
if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file]
code = ::SCRIPT_LINES__[file].join('')
@@ -169,5 +173,8 @@ EOF
"\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
end
+
+ def IRB.delete_caller
+ end
end
end
diff --git a/lib/irb/ws-for-case-2.rb b/lib/irb/ws-for-case-2.rb
index a0f617e4ed..eb173fddca 100644
--- a/lib/irb/ws-for-case-2.rb
+++ b/lib/irb/ws-for-case-2.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# irb/ws-for-case-2.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
while true
IRB::BINDING_QUEUE.push _ = binding
diff --git a/lib/irb/xmp.rb b/lib/irb/xmp.rb
index 94c700b484..88cbd88525 100644
--- a/lib/irb/xmp.rb
+++ b/lib/irb/xmp.rb
@@ -1,8 +1,14 @@
# frozen_string_literal: false
#
# xmp.rb - irb version of gotoken xmp
+# $Release Version: 0.9$
+# $Revision$
# by Keiju ISHITSUKA(Nippon Rational Inc.)
#
+# --
+#
+#
+#
require_relative "../irb"
require_relative "frame"
diff --git a/lib/logger.rb b/lib/logger.rb
index 4099955ef2..7e4dacc911 100644
--- a/lib/logger.rb
+++ b/lib/logger.rb
@@ -10,7 +10,6 @@
#
# A simple system for logging messages. See Logger for more documentation.
-require 'fiber'
require 'monitor'
require 'rbconfig'
@@ -265,7 +264,8 @@ require_relative 'logger/errors'
# logger.error! # => 3
# logger.fatal! # => 4
#
-# You can retrieve the log level with method #level.
+# You can retrieve the log level with method
+# {level}[Logger.html#attribute-i-level]:
#
# logger.level = Logger::ERROR
# logger.level # => 3
@@ -380,9 +380,7 @@ class Logger
include Severity
# Logging severity threshold (e.g. <tt>Logger::INFO</tt>).
- def level
- @level_override[Fiber.current] || @level
- end
+ attr_reader :level
# Sets the log level; returns +severity+.
# See {Log Level}[rdoc-ref:Logger@Log+Level].
@@ -397,23 +395,24 @@ class Logger
# Logger#sev_threshold= is an alias for Logger#level=.
#
def level=(severity)
- @level = Severity.coerce(severity)
- end
-
- # Adjust the log level during the block execution for the current Fiber only
- #
- # logger.with_level(:debug) do
- # logger.debug { "Hello" }
- # end
- def with_level(severity)
- prev, @level_override[Fiber.current] = level, Severity.coerce(severity)
- begin
- yield
- ensure
- if prev
- @level_override[Fiber.current] = prev
+ if severity.is_a?(Integer)
+ @level = severity
+ else
+ case severity.to_s.downcase
+ when 'debug'
+ @level = DEBUG
+ when 'info'
+ @level = INFO
+ when 'warn'
+ @level = WARN
+ when 'error'
+ @level = ERROR
+ when 'fatal'
+ @level = FATAL
+ when 'unknown'
+ @level = UNKNOWN
else
- @level_override.delete(Fiber.current)
+ raise ArgumentError, "invalid log level: #{severity}"
end
end
end
@@ -584,7 +583,6 @@ class Logger
self.datetime_format = datetime_format
self.formatter = formatter
@logdev = nil
- @level_override = {}
if logdev && logdev != File::NULL
@logdev = LogDevice.new(logdev, shift_age: shift_age,
shift_size: shift_size,
diff --git a/lib/logger/logger.gemspec b/lib/logger/logger.gemspec
index 5e8232e4ab..d12db625d9 100644
--- a/lib/logger/logger.gemspec
+++ b/lib/logger/logger.gemspec
@@ -18,5 +18,9 @@ Gem::Specification.new do |spec|
spec.files = Dir.glob("lib/**/*.rb") + ["logger.gemspec"]
spec.require_paths = ["lib"]
- spec.required_ruby_version = ">= 2.5.0"
+ spec.required_ruby_version = ">= 2.3.0"
+
+ spec.add_development_dependency "bundler", ">= 0"
+ spec.add_development_dependency "rake", ">= 12.3.3"
+ spec.add_development_dependency "test-unit"
end
diff --git a/lib/logger/severity.rb b/lib/logger/severity.rb
index e96fb0d320..b38afb7d22 100644
--- a/lib/logger/severity.rb
+++ b/lib/logger/severity.rb
@@ -15,24 +15,5 @@ class Logger
FATAL = 4
# An unknown message that should always be logged.
UNKNOWN = 5
-
- LEVELS = {
- "debug" => DEBUG,
- "info" => INFO,
- "warn" => WARN,
- "error" => ERROR,
- "fatal" => FATAL,
- "unknown" => UNKNOWN,
- }
- private_constant :LEVELS
-
- def self.coerce(severity)
- if severity.is_a?(Integer)
- severity
- else
- key = severity.to_s.downcase
- LEVELS[key] || raise(ArgumentError, "invalid log level: #{severity}")
- end
- end
end
end
diff --git a/lib/logger/version.rb b/lib/logger/version.rb
index 202b6e4fba..f85c72eed3 100644
--- a/lib/logger/version.rb
+++ b/lib/logger/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
class Logger
- VERSION = "1.6.0"
+ VERSION = "1.5.3"
end
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index 6da7dde5f1..0fbc1cc2e5 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -89,16 +89,26 @@ module MakeMakefile
unless defined? $configure_args
$configure_args = {}
- args = CONFIG["configure_args"].shellsplit
- if arg = ENV["CONFIGURE_ARGS"]
- args.push(*arg.shellsplit)
+ args = CONFIG["configure_args"]
+ if ENV["CONFIGURE_ARGS"]
+ args << " " << ENV["CONFIGURE_ARGS"]
end
- args.delete_if {|a| /\A--(?:top(?:src)?|src|cur)dir(?=\z|=)/ =~ a}
- for arg in args.concat(ARGV)
+ for arg in Shellwords::shellwords(args)
arg, val = arg.split('=', 2)
next unless arg
arg.tr!('_', '-')
- if arg.sub!(/\A(?!--)/, '--')
+ if arg.sub!(/^(?!--)/, '--')
+ val or next
+ arg.downcase!
+ end
+ next if /^--(?:top|topsrc|src|cur)dir$/ =~ arg
+ $configure_args[arg] = val || true
+ end
+ for arg in ARGV
+ arg, val = arg.split('=', 2)
+ next unless arg
+ arg.tr!('_', '-')
+ if arg.sub!(/^(?!--)/, '--')
val or next
arg.downcase!
end
@@ -971,11 +981,7 @@ SRC
# Internal use only.
#
def checking_for(m, fmt = nil)
- if f = caller_locations(1, 1).first.base_label and /\A\w/ =~ f
- f += ": "
- else
- f = ""
- end
+ f = caller[0][/in `([^<].*)'$/, 1] and f << ": " #` for vim #'
m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... "
message "%s", m
a = r = nil
@@ -1792,8 +1798,7 @@ SRC
# application.
#
def dir_config(target, idefault=nil, ldefault=nil)
- key = [target, idefault, ldefault].compact.join("\0")
- if conf = $config_dirs[key]
+ if conf = $config_dirs[target]
return conf
end
@@ -1803,13 +1808,9 @@ SRC
end
idir = with_config(target + "-include", idefault)
- if conf = $arg_config.assoc("--with-#{target}-include")
- conf[1] ||= "${#{target}-dir}/include"
- end
+ $arg_config.last[1] ||= "${#{target}-dir}/include"
ldir = with_config(target + "-lib", ldefault)
- if conf = $arg_config.assoc("--with-#{target}-lib")
- conf[1] ||= "${#{target}-dir}/#{_libdir_basename}"
- end
+ $arg_config.last[1] ||= "${#{target}-dir}/#{_libdir_basename}"
idirs = idir ? Array === idir ? idir.dup : idir.split(File::PATH_SEPARATOR) : []
if defaults
@@ -1831,7 +1832,7 @@ SRC
end
$LIBPATH = ldirs | $LIBPATH
- $config_dirs[key] = [idir, ldir]
+ $config_dirs[target] = [idir, ldir]
end
# Returns compile/link information about an installed library in a tuple of <code>[cflags,
@@ -1854,73 +1855,66 @@ SRC
# invoked with the options and a stripped output string is returned without
# modifying any of the global values mentioned above.
def pkg_config(pkg, *options)
- fmt = "not found"
- def fmt.%(x)
- x ? x.inspect : self
- end
-
- checking_for "pkg-config for #{pkg}", fmt do
- _, ldir = dir_config(pkg)
- if ldir
- pkg_config_path = "#{ldir}/pkgconfig"
- if File.directory?(pkg_config_path)
- Logging.message("PKG_CONFIG_PATH = %s\n", pkg_config_path)
- envs = ["PKG_CONFIG_PATH"=>[pkg_config_path, ENV["PKG_CONFIG_PATH"]].compact.join(File::PATH_SEPARATOR)]
- end
+ _, ldir = dir_config(pkg)
+ if ldir
+ pkg_config_path = "#{ldir}/pkgconfig"
+ if File.directory?(pkg_config_path)
+ Logging.message("PKG_CONFIG_PATH = %s\n", pkg_config_path)
+ envs = ["PKG_CONFIG_PATH"=>[pkg_config_path, ENV["PKG_CONFIG_PATH"]].compact.join(File::PATH_SEPARATOR)]
end
- if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
+ end
+ if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
# if and only if package specific config command is given
- elsif ($PKGCONFIG ||=
- (pkgconfig = with_config("pkg-config") {config_string("PKG_CONFIG") || "pkg-config"}) &&
- find_executable0(pkgconfig) && pkgconfig) and
- xsystem([*envs, $PKGCONFIG, "--exists", pkg])
- # default to pkg-config command
- pkgconfig = $PKGCONFIG
- args = [pkg]
- elsif find_executable0(pkgconfig = "#{pkg}-config")
+ elsif ($PKGCONFIG ||=
+ (pkgconfig = with_config("pkg-config") {config_string("PKG_CONFIG") || "pkg-config"}) &&
+ find_executable0(pkgconfig) && pkgconfig) and
+ xsystem([*envs, $PKGCONFIG, "--exists", pkg])
+ # default to pkg-config command
+ pkgconfig = $PKGCONFIG
+ args = [pkg]
+ elsif find_executable0(pkgconfig = "#{pkg}-config")
# default to package specific config command, as a last resort.
+ else
+ pkgconfig = nil
+ end
+ if pkgconfig
+ get = proc {|opts|
+ opts = Array(opts).map { |o| "--#{o}" }
+ opts = xpopen([*envs, pkgconfig, *opts, *args], err:[:child, :out], &:read)
+ Logging.open {puts opts.each_line.map{|s|"=> #{s.inspect}"}}
+ opts.strip if $?.success?
+ }
+ end
+ orig_ldflags = $LDFLAGS
+ if get and !options.empty?
+ get[options]
+ elsif get and try_ldflags(ldflags = get['libs'])
+ if incflags = get['cflags-only-I']
+ $INCFLAGS << " " << incflags
+ cflags = get['cflags-only-other']
else
- pkgconfig = nil
- end
- if pkgconfig
- get = proc {|opts|
- opts = Array(opts).map { |o| "--#{o}" }
- opts = xpopen([*envs, pkgconfig, *opts, *args], err:[:child, :out], &:read)
- Logging.open {puts opts.each_line.map{|s|"=> #{s.inspect}"}}
- opts.strip if $?.success?
- }
+ cflags = get['cflags']
end
- orig_ldflags = $LDFLAGS
- if get and !options.empty?
- get[options]
- elsif get and try_ldflags(ldflags = get['libs'])
- if incflags = get['cflags-only-I']
- $INCFLAGS << " " << incflags
- cflags = get['cflags-only-other']
- else
- cflags = get['cflags']
- end
- libs = get['libs-only-l']
- if cflags
- $CFLAGS += " " << cflags
- $CXXFLAGS += " " << cflags
- end
- if libs
- ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ")
- else
- libs, ldflags = Shellwords.shellwords(ldflags).partition {|s| s =~ /-l([^ ]+)/ }.map {|l|l.quote.join(" ")}
- end
- $libs += " " << libs
-
- $LDFLAGS = [orig_ldflags, ldflags].join(' ')
- Logging::message "package configuration for %s\n", pkg
- Logging::message "incflags: %s\ncflags: %s\nldflags: %s\nlibs: %s\n\n",
- incflags, cflags, ldflags, libs
- [[incflags, cflags].join(' '), ldflags, libs]
+ libs = get['libs-only-l']
+ if cflags
+ $CFLAGS += " " << cflags
+ $CXXFLAGS += " " << cflags
+ end
+ if libs
+ ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ")
else
- Logging::message "package configuration for %s is not found\n", pkg
- nil
+ libs, ldflags = Shellwords.shellwords(ldflags).partition {|s| s =~ /-l([^ ]+)/ }.map {|l|l.quote.join(" ")}
end
+ $libs += " " << libs
+
+ $LDFLAGS = [orig_ldflags, ldflags].join(' ')
+ Logging::message "package configuration for %s\n", pkg
+ Logging::message "incflags: %s\ncflags: %s\nldflags: %s\nlibs: %s\n\n",
+ incflags, cflags, ldflags, libs
+ [[incflags, cflags].join(' '), ldflags, libs]
+ else
+ Logging::message "package configuration for %s is not found\n", pkg
+ nil
end
end
@@ -1970,14 +1964,14 @@ SRC
def configuration(srcdir)
mk = []
- verbose = with_config('verbose') ? "1" : (CONFIG['MKMF_VERBOSE'] || "0")
+ CONFIG['MKMF_VERBOSE'] ||= "0"
vpath = $VPATH.dup
CONFIG["hdrdir"] ||= $hdrdir
mk << %{
SHELL = /bin/sh
# V=0 quiet, V=1 verbose. other values don't work.
-V = #{verbose}
+V = #{CONFIG['MKMF_VERBOSE']}
V0 = $(V:0=)
Q1 = $(V:1=)
Q = $(Q1:0=@)
@@ -2704,7 +2698,7 @@ MESSAGE
when $mswin
$nmake = ?m if /nmake/i =~ make
end
- $ignore_error = " 2> #{File::NULL} || #{$mswin ? 'exit /b0' : 'true'}"
+ $ignore_error = $nmake ? '' : ' 2> /dev/null || true'
RbConfig::CONFIG["srcdir"] = CONFIG["srcdir"] =
$srcdir = arg_config("--srcdir", File.dirname($0))
diff --git a/lib/mutex_m.gemspec b/lib/mutex_m.gemspec
index ebbda2606c..f614dcd9a0 100644
--- a/lib/mutex_m.gemspec
+++ b/lib/mutex_m.gemspec
@@ -20,7 +20,6 @@ Gem::Specification.new do |spec|
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
- spec.required_ruby_version = '>= 2.5'
spec.add_development_dependency "bundler"
spec.add_development_dependency "rake"
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
index 7e55181881..17ec9924e4 100644
--- a/lib/mutex_m.rb
+++ b/lib/mutex_m.rb
@@ -40,15 +40,17 @@
#
module Mutex_m
- VERSION = "0.2.0"
+ VERSION = "0.1.2"
Ractor.make_shareable(VERSION) if defined?(Ractor)
def Mutex_m.define_aliases(cl) # :nodoc:
- cl.alias_method(:locked?, :mu_locked?)
- cl.alias_method(:lock, :mu_lock)
- cl.alias_method(:unlock, :mu_unlock)
- cl.alias_method(:try_lock, :mu_try_lock)
- cl.alias_method(:synchronize, :mu_synchronize)
+ cl.module_eval %q{
+ alias locked? mu_locked?
+ alias lock mu_lock
+ alias unlock mu_unlock
+ alias try_lock mu_try_lock
+ alias synchronize mu_synchronize
+ }
end
def Mutex_m.append_features(cl) # :nodoc:
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 34ca0669eb..387df4b8f4 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -722,7 +722,7 @@ module Net #:nodoc:
class HTTP < Protocol
# :stopdoc:
- VERSION = "0.4.0"
+ VERSION = "0.4.1"
HTTPVersion = '1.1'
begin
require 'zlib'
diff --git a/lib/net/net-protocol.gemspec b/lib/net/net-protocol.gemspec
index 29ad2504eb..c03621cb0d 100644
--- a/lib/net/net-protocol.gemspec
+++ b/lib/net/net-protocol.gemspec
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.require_paths = ["lib"]
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 197ea09089..ea0752a971 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -26,7 +26,7 @@ require 'io/wait'
module Net # :nodoc:
class Protocol #:nodoc: internal use only
- VERSION = "0.2.2"
+ VERSION = "0.2.1"
private
def Protocol.protocol_param(name, val)
diff --git a/lib/observer.gemspec b/lib/observer.gemspec
deleted file mode 100644
index 93e61b8c84..0000000000
--- a/lib/observer.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Implementation of the Observer object-oriented design pattern.}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/observer"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-end
diff --git a/lib/observer.rb b/lib/observer.rb
index 75832cace2..ef70e39dd8 100644
--- a/lib/observer.rb
+++ b/lib/observer.rb
@@ -136,7 +136,7 @@
# ticker.add_observer(warner, :call)
# ticker.run
module Observable
- VERSION = "0.1.2"
+ VERSION = "0.1.1"
#
# Add +observer+ as an observer on this object. So that it will receive
diff --git a/lib/observer/observer.gemspec b/lib/observer/observer.gemspec
new file mode 100644
index 0000000000..46538e881a
--- /dev/null
+++ b/lib/observer/observer.gemspec
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Implementation of the Observer object-oriented design pattern.}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/observer"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/open-uri.gemspec b/lib/open-uri.gemspec
index b6aaf35200..cad63e4d80 100644
--- a/lib/open-uri.gemspec
+++ b/lib/open-uri.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", "."].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "open-uri"
+ spec.version = "0.3.0"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/open-uri.rb b/lib/open-uri.rb
index 00e4c2d9b8..93e8cfcdb7 100644
--- a/lib/open-uri.rb
+++ b/lib/open-uri.rb
@@ -31,7 +31,6 @@ module URI
super
end
end
- singleton_class.send(:ruby2_keywords, :open) if respond_to?(:ruby2_keywords, true)
end
# OpenURI is an easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP.
@@ -90,9 +89,6 @@ end
# Author:: Tanaka Akira <akr@m17n.org>
module OpenURI
-
- VERSION = "0.4.0"
-
Options = {
:proxy => true,
:proxy_http_basic_authentication => true,
diff --git a/lib/open3.rb b/lib/open3.rb
index 72c9ae5962..9652b27194 100644
--- a/lib/open3.rb
+++ b/lib/open3.rb
@@ -31,182 +31,57 @@
require 'open3/version'
-# \Module \Open3 supports creating child processes
-# with access to their $stdin, $stdout, and $stderr streams.
-#
-# == What's Here
-#
-# Each of these methods executes a given command in a new process or subshell,
-# or multiple commands in new processes and/or subshells:
-#
-# - Each of these methods executes a single command in a process or subshell,
-# accepts a string for input to $stdin,
-# and returns string output from $stdout, $stderr, or both:
-#
-# - Open3.capture2: Executes the command;
-# returns the string from $stdout.
-# - Open3.capture2e: Executes the command;
-# returns the string from merged $stdout and $stderr.
-# - Open3.capture3: Executes the command;
-# returns strings from $stdout and $stderr.
-#
-# - Each of these methods executes a single command in a process or subshell,
-# and returns pipes for $stdin, $stdout, and/or $stderr:
-#
-# - Open3.popen2: Executes the command;
-# returns pipes for $stdin and $stdout.
-# - Open3.popen2e: Executes the command;
-# returns pipes for $stdin and merged $stdout and $stderr.
-# - Open3.popen3: Executes the command;
-# returns pipes for $stdin, $stdout, and $stderr.
-#
-# - Each of these methods executes one or more commands in processes and/or subshells,
-# returns pipes for the first $stdin, the last $stdout, or both:
-#
-# - Open3.pipeline_r: Returns a pipe for the last $stdout.
-# - Open3.pipeline_rw: Returns pipes for the first $stdin and the last $stdout.
-# - Open3.pipeline_w: Returns a pipe for the first $stdin.
-# - Open3.pipeline_start: Does not wait for processes to complete.
-# - Open3.pipeline: Waits for processes to complete.
-#
-# Each of the methods above accepts:
-#
-# - An optional hash of environment variable names and values;
-# see {Execution Environment}[rdoc-ref:Process#Execution+Environment].
-# - A required string argument that is a +command_line+ or +exe_path+;
-# see {Argument command_line or exe_path}[rdoc-ref:Process#Argument+command_line+or+exe_path].
-# - An optional hash of execution options;
-# see {Execution Options}[rdoc-ref:Process#Execution+Options].
-#
module Open3
- # :call-seq:
- # Open3.popen3([env, ] command_line, options = {}) -> [stdin, stdout, stderr, wait_thread]
- # Open3.popen3([env, ] exe_path, *args, options = {}) -> [stdin, stdout, stderr, wait_thread]
- # Open3.popen3([env, ] command_line, options = {}) {|stdin, stdout, stderr, wait_thread| ... } -> object
- # Open3.popen3([env, ] exe_path, *args, options = {}) {|stdin, stdout, stderr, wait_thread| ... } -> object
- #
- # Basically a wrapper for Process.spawn that:
- #
- # - Creates a child process, by calling Process.spawn with the given arguments.
- # - Creates streams +stdin+, +stdout+, and +stderr+,
- # which are the standard input, standard output, and standard error streams
- # in the child process.
- # - Creates thread +wait_thread+ that waits for the child process to exit;
- # the thread has method +pid+, which returns the process ID
- # of the child process.
- #
- # With no block given, returns the array
- # <tt>[stdin, stdout, stderr, wait_thread]</tt>.
- # The caller should close each of the three returned streams.
- #
- # stdin, stdout, stderr, wait_thread = Open3.popen3('echo')
- # # => [#<IO:fd 8>, #<IO:fd 10>, #<IO:fd 12>, #<Process::Waiter:0x00007f58d5428f58 run>]
- # stdin.close
- # stdout.close
- # stderr.close
- # wait_thread.pid # => 2210481
- # wait_thread.value # => #<Process::Status: pid 2210481 exit 0>
- #
- # With a block given, calls the block with the four variables
- # (three streams and the wait thread)
- # and returns the block's return value.
- # The caller need not close the streams:
- #
- # Open3.popen3('echo') do |stdin, stdout, stderr, wait_thread|
- # p stdin
- # p stdout
- # p stderr
- # p wait_thread
- # p wait_thread.pid
- # p wait_thread.value
- # end
- #
- # Output:
- #
- # #<IO:fd 6>
- # #<IO:fd 7>
- # #<IO:fd 9>
- # #<Process::Waiter:0x00007f58d53606e8 sleep>
- # 2211047
- # #<Process::Status: pid 2211047 exit 0>
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # Argument +options+ is a hash of options for the new process;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
+ # Open stdin, stdout, and stderr streams and start external executable.
+ # In addition, a thread to wait for the started process is created.
+ # The thread has a pid method and a thread variable :pid which is the pid of
+ # the started process.
#
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
+ # Block form:
#
- # Open3.popen3('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
- # Open3.popen3('echo') {|*args| p args } # Built-in.
- # Open3.popen3('date > date.tmp') {|*args| p args } # Contains meta character.
- #
- # Output (similar for each call above):
- #
- # [#<IO:(closed)>, #<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f58d52f28c8 dead>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.popen3('echo "Foo"') { |i, o, e, t| o.gets }
- # "Foo\n"
- #
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
+ # Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
#
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # Non-block form:
#
- # Example:
- #
- # Open3.popen3('/usr/bin/date') { |i, o, e, t| o.gets }
- # # => "Wed Sep 27 02:56:44 PM CDT 2023\n"
+ # stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts])
+ # pid = wait_thr[:pid] # pid of the started process
+ # ...
+ # stdin.close # stdin, stdout and stderr should be closed explicitly in this form.
+ # stdout.close
+ # stderr.close
+ # exit_status = wait_thr.value # Process::Status object returned.
#
- # Ruby invokes the executable directly, with no shell and no shell expansion:
+ # The parameters env, cmd, and opts are passed to Process.spawn.
+ # A commandline string and a list of argument strings can be accepted as follows:
#
- # Open3.popen3('doesnt_exist') { |i, o, e, t| o.gets } # Raises Errno::ENOENT
+ # Open3.popen3("echo abc") {|i, o, e, t| ... }
+ # Open3.popen3("echo", "abc") {|i, o, e, t| ... }
+ # Open3.popen3(["echo", "argv0"], "abc") {|i, o, e, t| ... }
#
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
+ # If the last parameter, opts, is a Hash, it is recognized as an option for Process.spawn.
#
- # Open3.popen3('echo', 'C #') { |i, o, e, t| o.gets }
- # # => "C #\n"
- # Open3.popen3('echo', 'hello', 'world') { |i, o, e, t| o.gets }
- # # => "hello world\n"
+ # Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
+ # p o.read.chomp #=> "/"
+ # }
#
- # Take care to avoid deadlocks.
- # Output streams +stdout+ and +stderr+ have fixed-size buffers,
- # so reading extensively from one but not the other can cause a deadlock
- # when the unread buffer fills.
- # To avoid that, +stdout+ and +stderr+ should be read simultaneously
- # (using threads or IO.select).
+ # wait_thr.value waits for the termination of the process.
+ # The block form also waits for the process when it returns.
#
- # Related:
+ # Closing stdin, stdout and stderr does not wait for the process to complete.
#
- # - Open3.popen2: Makes the standard input and standard output streams
- # of the child process available as separate streams,
- # with no access to the standard error stream.
- # - Open3.popen2e: Makes the standard input and the merge
- # of the standard output and standard error streams
- # of the child process available as separate streams.
+ # You should be careful to avoid deadlocks.
+ # Since pipes are fixed length buffers,
+ # Open3.popen3("prog") {|i, o, e, t| o.read } deadlocks if
+ # the program generates too much output on stderr.
+ # You should read stdout and stderr simultaneously (using threads or IO.select).
+ # However, if you don't need stderr output, you can use Open3.popen2.
+ # If merged stdout and stderr output is not a problem, you can use Open3.popen2e.
+ # If you really need stdout and stderr output as separate strings, you can consider Open3.capture3.
#
def popen3(*cmd, &block)
if Hash === cmd.last
@@ -229,124 +104,45 @@ module Open3
end
module_function :popen3
- # :call-seq:
- # Open3.popen2([env, ] command_line, options = {}) -> [stdin, stdout, wait_thread]
- # Open3.popen2([env, ] exe_path, *args, options = {}) -> [stdin, stdout, wait_thread]
- # Open3.popen2([env, ] command_line, options = {}) {|stdin, stdout, wait_thread| ... } -> object
- # Open3.popen2([env, ] exe_path, *args, options = {}) {|stdin, stdout, wait_thread| ... } -> object
- #
- # Basically a wrapper for Process.spawn that:
- #
- # - Creates a child process, by calling Process.spawn with the given arguments.
- # - Creates streams +stdin+ and +stdout+,
- # which are the standard input and standard output streams
- # in the child process.
- # - Creates thread +wait_thread+ that waits for the child process to exit;
- # the thread has method +pid+, which returns the process ID
- # of the child process.
- #
- # With no block given, returns the array
- # <tt>[stdin, stdout, wait_thread]</tt>.
- # The caller should close each of the two returned streams.
- #
- # stdin, stdout, wait_thread = Open3.popen2('echo')
- # # => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f58d52dbe98 run>]
- # stdin.close
- # stdout.close
- # wait_thread.pid # => 2263572
- # wait_thread.value # => #<Process::Status: pid 2263572 exit 0>
- #
- # With a block given, calls the block with the three variables
- # (two streams and the wait thread)
- # and returns the block's return value.
- # The caller need not close the streams:
- #
- # Open3.popen2('echo') do |stdin, stdout, wait_thread|
- # p stdin
- # p stdout
- # p wait_thread
- # p wait_thread.pid
- # p wait_thread.value
- # end
- #
- # Output:
- #
- # #<IO:fd 6>
- # #<IO:fd 7>
- # #<Process::Waiter:0x00007f58d59a34b0 sleep>
- # 2263636
- # #<Process::Status: pid 2263636 exit 0>
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # Argument +options+ is a hash of options for the new process;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The single required argument is one of the following:
+ # Open3.popen2 is similar to Open3.popen3 except that it doesn't create a pipe for
+ # the standard error stream.
#
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
+ # Block form:
#
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
- #
- # Open3.popen2('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
- # Open3.popen2('echo') {|*args| p args } # Built-in.
- # Open3.popen2('date > date.tmp') {|*args| p args } # Contains meta character.
- #
- # Output (similar for each call above):
- #
- # # => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577dfe410 dead>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.popen2('echo "Foo"') { |i, o, t| o.gets }
- # "Foo\n"
+ # Open3.popen2([env,] cmd... [, opts]) {|stdin, stdout, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
#
- # <b>Argument +exe_path+</b>
+ # Non-block form:
#
- # Argument +exe_path+ is one of the following:
+ # stdin, stdout, wait_thr = Open3.popen2([env,] cmd... [, opts])
+ # ...
+ # stdin.close # stdin and stdout should be closed explicitly in this form.
+ # stdout.close
#
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # See Process.spawn for the optional hash arguments _env_ and _opts_.
#
# Example:
#
- # Open3.popen2('/usr/bin/date') { |i, o, t| o.gets }
- # # => "Thu Sep 28 09:41:06 AM CDT 2023\n"
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.popen2('doesnt_exist') { |i, o, t| o.gets } # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.popen2('echo', 'C #') { |i, o, t| o.gets }
- # # => "C #\n"
- # Open3.popen2('echo', 'hello', 'world') { |i, o, t| o.gets }
- # # => "hello world\n"
- #
+ # Open3.popen2("wc -c") {|i,o,t|
+ # i.print "answer to life the universe and everything"
+ # i.close
+ # p o.gets #=> "42\n"
+ # }
#
- # Related:
+ # Open3.popen2("bc -q") {|i,o,t|
+ # i.puts "obase=13"
+ # i.puts "6 * 9"
+ # p o.gets #=> "42\n"
+ # }
#
- # - Open3.popen2e: Makes the standard input and the merge
- # of the standard output and standard error streams
- # of the child process available as separate streams.
- # - Open3.popen3: Makes the standard input, standard output,
- # and standard error streams
- # of the child process available as separate streams.
+ # Open3.popen2("dc") {|i,o,t|
+ # i.print "42P"
+ # i.close
+ # p o.read #=> "*"
+ # }
#
def popen2(*cmd, &block)
if Hash === cmd.last
@@ -366,123 +162,36 @@ module Open3
end
module_function :popen2
- # :call-seq:
- # Open3.popen2e([env, ] command_line, options = {}) -> [stdin, stdout_and_stderr, wait_thread]
- # Open3.popen2e([env, ] exe_path, *args, options = {}) -> [stdin, stdout_and_stderr, wait_thread]
- # Open3.popen2e([env, ] command_line, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } -> object
- # Open3.popen2e([env, ] exe_path, *args, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } -> object
- #
- # Basically a wrapper for Process.spawn that:
- #
- # - Creates a child process, by calling Process.spawn with the given arguments.
- # - Creates streams +stdin+, +stdout_and_stderr+,
- # which are the standard input and the merge of the standard output
- # and standard error streams in the child process.
- # - Creates thread +wait_thread+ that waits for the child process to exit;
- # the thread has method +pid+, which returns the process ID
- # of the child process.
- #
- # With no block given, returns the array
- # <tt>[stdin, stdout_and_stderr, wait_thread]</tt>.
- # The caller should close each of the two returned streams.
- #
- # stdin, stdout_and_stderr, wait_thread = Open3.popen2e('echo')
- # # => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f7577da4398 run>]
- # stdin.close
- # stdout_and_stderr.close
- # wait_thread.pid # => 2274600
- # wait_thread.value # => #<Process::Status: pid 2274600 exit 0>
- #
- # With a block given, calls the block with the three variables
- # (two streams and the wait thread)
- # and returns the block's return value.
- # The caller need not close the streams:
- #
- # Open3.popen2e('echo') do |stdin, stdout_and_stderr, wait_thread|
- # p stdin
- # p stdout_and_stderr
- # p wait_thread
- # p wait_thread.pid
- # p wait_thread.value
- # end
- #
- # Output:
- #
- # #<IO:fd 6>
- # #<IO:fd 7>
- # #<Process::Waiter:0x00007f75777578c8 sleep>
- # 2274763
- # #<Process::Status: pid 2274763 exit 0>
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # Argument +options+ is a hash of options for the new process;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
+ # Open3.popen2e is similar to Open3.popen3 except that it merges
+ # the standard output stream and the standard error stream.
#
- # Open3.popen2e('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
- # Open3.popen2e('echo') {|*args| p args } # Built-in.
- # Open3.popen2e('date > date.tmp') {|*args| p args } # Contains meta character.
+ # Block form:
#
- # Output (similar for each call above):
- #
- # # => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577d8a1f0 dead>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.popen2e('echo "Foo"') { |i, o_and_e, t| o_and_e.gets }
- # "Foo\n"
+ # Open3.popen2e([env,] cmd... [, opts]) {|stdin, stdout_and_stderr, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
#
- # <b>Argument +exe_path+</b>
+ # Non-block form:
#
- # Argument +exe_path+ is one of the following:
+ # stdin, stdout_and_stderr, wait_thr = Open3.popen2e([env,] cmd... [, opts])
+ # ...
+ # stdin.close # stdin and stdout_and_stderr should be closed explicitly in this form.
+ # stdout_and_stderr.close
#
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # See Process.spawn for the optional hash arguments _env_ and _opts_.
#
# Example:
- #
- # Open3.popen2e('/usr/bin/date') { |i, o_and_e, t| o_and_e.gets }
- # # => "Thu Sep 28 01:58:45 PM CDT 2023\n"
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.popen2e('doesnt_exist') { |i, o_and_e, t| o_and_e.gets } # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.popen2e('echo', 'C #') { |i, o_and_e, t| o_and_e.gets }
- # # => "C #\n"
- # Open3.popen2e('echo', 'hello', 'world') { |i, o_and_e, t| o_and_e.gets }
- # # => "hello world\n"
- #
- # Related:
- #
- # - Open3.popen2: Makes the standard input and standard output streams
- # of the child process available as separate streams,
- # with no access to the standard error stream.
- # - Open3.popen3: Makes the standard input, standard output,
- # and standard error streams
- # of the child process available as separate streams.
+ # # check gcc warnings
+ # source = "foo.c"
+ # Open3.popen2e("gcc", "-Wall", source) {|i,oe,t|
+ # oe.each {|line|
+ # if /warning/ =~ line
+ # ...
+ # end
+ # }
+ # }
#
def popen2e(*cmd, &block)
if Hash === cmd.last
@@ -529,95 +238,44 @@ module Open3
private :popen_run
end
- # :call-seq:
- # Open3.capture3([env, ] command_line, options = {}) -> [stdout_s, stderr_s, status]
- # Open3.capture3([env, ] exe_path, *args, options = {}) -> [stdout_s, stderr_s, status]
- #
- # Basically a wrapper for Open3.popen3 that:
- #
- # - Creates a child process, by calling Open3.popen3 with the given arguments
- # (except for certain entries in hash +options+; see below).
- # - Returns as strings +stdout_s+ and +stderr_s+ the standard output
- # and standard error of the child process.
- # - Returns as +status+ a <tt>Process::Status</tt> object
- # that represents the exit status of the child process.
- #
- # Returns the array <tt>[stdout_s, stderr_s, status]</tt>:
- #
- # stdout_s, stderr_s, status = Open3.capture3('echo "Foo"')
- # # => ["Foo\n", "", #<Process::Status: pid 2281954 exit 0>]
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # Argument +options+ is a hash of options for the new process;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The hash +options+ is passed to method Open3.popen3;
- # two options have local effect in method Open3.capture3:
- #
- # - If entry <tt>options[:stdin_data]</tt> exists, the entry is removed
- # and its string value is sent to the command's standard input:
- #
- # Open3.capture3('tee', stdin_data: 'Foo')
- # # => ["Foo", "", #<Process::Status: pid 2319575 exit 0>]
- #
- # - If entry <tt>options[:binmode]</tt> exists, the entry is removed
- # the internal streams are set to binary mode.
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
- #
- # Open3.capture3('if true; then echo "Foo"; fi') # Shell reserved word.
- # # => ["Foo\n", "", #<Process::Status: pid 2282025 exit 0>]
- # Open3.capture3('echo') # Built-in.
- # # => ["\n", "", #<Process::Status: pid 2282092 exit 0>]
- # Open3.capture3('date > date.tmp') # Contains meta character.
- # # => ["", "", #<Process::Status: pid 2282110 exit 0>]
- #
- # The command line may also contain arguments and options for the command:
+ # Open3.capture3 captures the standard output and the standard error of a command.
#
- # Open3.capture3('echo "Foo"')
- # # => ["Foo\n", "", #<Process::Status: pid 2282092 exit 0>]
+ # stdout_str, stderr_str, status = Open3.capture3([env,] cmd... [, opts])
#
- # <b>Argument +exe_path+</b>
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # <code>opts[:stdin_data]</code> and <code>opts[:binmode]</code>. See Process.spawn.
#
- # Argument +exe_path+ is one of the following:
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # If <code>opts[:binmode]</code> is true, internal pipes are set to binary mode.
#
- # Example:
- #
- # Open3.capture3('/usr/bin/date')
- # # => ["Thu Sep 28 05:03:51 PM CDT 2023\n", "", #<Process::Status: pid 2282300 exit 0>]
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
+ # Examples:
#
- # Open3.capture3('doesnt_exist') # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.capture3('echo', 'C #')
- # # => ["C #\n", "", #<Process::Status: pid 2282368 exit 0>]
- # Open3.capture3('echo', 'hello', 'world')
- # # => ["hello world\n", "", #<Process::Status: pid 2282372 exit 0>]
+ # # dot is a command of graphviz.
+ # graph = <<'End'
+ # digraph g {
+ # a -> b
+ # }
+ # End
+ # drawn_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)
+ #
+ # o, e, s = Open3.capture3("echo abc; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
+ # p o #=> "abc\n"
+ # p e #=> "bar\nbaz\nfoo\n"
+ # p s #=> #<Process::Status: pid 32682 exit 0>
+ #
+ # # generate a thumbnail image using the convert command of ImageMagick.
+ # # However, if the image is really stored in a file,
+ # # system("convert", "-thumbnail", "80", "png:#{filename}", "png:-") is better
+ # # because of reduced memory consumption.
+ # # But if the image is stored in a DB or generated by the gnuplot Open3.capture2 example,
+ # # Open3.capture3 should be considered.
+ # #
+ # image = File.read("/usr/share/openclipart/png/animals/mammals/sheep-md-v0.1.png", :binmode=>true)
+ # thumbnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
+ # if s.success?
+ # STDOUT.binmode; print thumbnail
+ # end
#
def capture3(*cmd)
if Hash === cmd.last
@@ -651,94 +309,34 @@ module Open3
end
module_function :capture3
- # :call-seq:
- # Open3.capture2([env, ] command_line, options = {}) -> [stdout_s, status]
- # Open3.capture2([env, ] exe_path, *args, options = {}) -> [stdout_s, status]
- #
- # Basically a wrapper for Open3.popen3 that:
- #
- # - Creates a child process, by calling Open3.popen3 with the given arguments
- # (except for certain entries in hash +options+; see below).
- # - Returns as string +stdout_s+ the standard output of the child process.
- # - Returns as +status+ a <tt>Process::Status</tt> object
- # that represents the exit status of the child process.
- #
- # Returns the array <tt>[stdout_s, status]</tt>:
- #
- # stdout_s, status = Open3.capture2('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2326047 exit 0>]
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # Argument +options+ is a hash of options for the new process;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The hash +options+ is passed to method Open3.popen3;
- # two options have local effect in method Open3.capture2:
- #
- # - If entry <tt>options[:stdin_data]</tt> exists, the entry is removed
- # and its string value is sent to the command's standard input:
- #
- # Open3.capture2('tee', stdin_data: 'Foo')
- #
- # # => ["Foo", #<Process::Status: pid 2326087 exit 0>]
- #
- # the internal streams are set to binary mode.
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
+ # Open3.capture2 captures the standard output of a command.
#
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
+ # stdout_str, status = Open3.capture2([env,] cmd... [, opts])
#
- # Open3.capture2('if true; then echo "Foo"; fi') # Shell reserved word.
- # # => ["Foo\n", #<Process::Status: pid 2326131 exit 0>]
- # Open3.capture2('echo') # Built-in.
- # # => ["\n", #<Process::Status: pid 2326139 exit 0>]
- # Open3.capture2('date > date.tmp') # Contains meta character.
- # # => ["", #<Process::Status: pid 2326174 exit 0>]
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # <code>opts[:stdin_data]</code> and <code>opts[:binmode]</code>. See Process.spawn.
#
- # The command line may also contain arguments and options for the command:
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # Open3.capture2('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]
- #
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
- #
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # If <code>opts[:binmode]</code> is true, internal pipes are set to binary mode.
#
# Example:
#
- # Open3.capture2('/usr/bin/date')
- # # => ["Fri Sep 29 01:00:39 PM CDT 2023\n", #<Process::Status: pid 2326222 exit 0>]
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.capture2('doesnt_exist') # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.capture2('echo', 'C #')
- # # => ["C #\n", #<Process::Status: pid 2326267 exit 0>]
- # Open3.capture2('echo', 'hello', 'world')
- # # => ["hello world\n", #<Process::Status: pid 2326299 exit 0>]
+ # # factor is a command for integer factorization.
+ # o, s = Open3.capture2("factor", :stdin_data=>"42")
+ # p o #=> "42: 2 3 7\n"
+ #
+ # # generate x**2 graph in png using gnuplot.
+ # gnuplot_commands = <<"End"
+ # set terminal png
+ # plot x**2, "-" with lines
+ # 1 14
+ # 2 1
+ # 3 8
+ # 4 5
+ # e
+ # End
+ # image, s = Open3.capture2("gnuplot", :stdin_data=>gnuplot_commands, :binmode=>true)
#
def capture2(*cmd)
if Hash === cmd.last
@@ -772,94 +370,21 @@ module Open3
end
module_function :capture2
- # :call-seq:
- # Open3.capture2e([env, ] command_line, options = {}) -> [stdout_and_stderr_s, status]
- # Open3.capture2e([env, ] exe_path, *args, options = {}) -> [stdout_and_stderr_s, status]
- #
- # Basically a wrapper for Open3.popen3 that:
- #
- # - Creates a child process, by calling Open3.popen3 with the given arguments
- # (except for certain entries in hash +options+; see below).
- # - Returns as string +stdout_and_stderr_s+ the merged standard output
- # and standard error of the child process.
- # - Returns as +status+ a <tt>Process::Status</tt> object
- # that represents the exit status of the child process.
- #
- # Returns the array <tt>[stdout_and_stderr_s, status]</tt>:
- #
- # stdout_and_stderr_s, status = Open3.capture2e('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2371692 exit 0>]
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # Argument +options+ is a hash of options for the new process;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The hash +options+ is passed to method Open3.popen3;
- # two options have local effect in method Open3.capture2e:
- #
- # - If entry <tt>options[:stdin_data]</tt> exists, the entry is removed
- # and its string value is sent to the command's standard input:
- #
- # Open3.capture2e('tee', stdin_data: 'Foo')
- # # => ["Foo", #<Process::Status: pid 2371732 exit 0>]
- #
- # the internal streams are set to binary mode.
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
+ # Open3.capture2e captures the standard output and the standard error of a command.
#
- # Open3.capture2e('if true; then echo "Foo"; fi') # Shell reserved word.
- # # => ["Foo\n", #<Process::Status: pid 2371740 exit 0>]
- # Open3.capture2e('echo') # Built-in.
- # # => ["\n", #<Process::Status: pid 2371774 exit 0>]
- # Open3.capture2e('date > date.tmp') # Contains meta character.
- # # => ["", #<Process::Status: pid 2371812 exit 0>]
+ # stdout_and_stderr_str, status = Open3.capture2e([env,] cmd... [, opts])
#
- # The command line may also contain arguments and options for the command:
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # <code>opts[:stdin_data]</code> and <code>opts[:binmode]</code>. See Process.spawn.
#
- # Open3.capture2e('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
- #
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # If <code>opts[:binmode]</code> is true, internal pipes are set to binary mode.
#
# Example:
#
- # Open3.capture2e('/usr/bin/date')
- # # => ["Sat Sep 30 09:01:46 AM CDT 2023\n", #<Process::Status: pid 2371820 exit 0>]
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.capture2e('doesnt_exist') # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.capture2e('echo', 'C #')
- # # => ["C #\n", #<Process::Status: pid 2371856 exit 0>]
- # Open3.capture2e('echo', 'hello', 'world')
- # # => ["hello world\n", #<Process::Status: pid 2371894 exit 0>]
+ # # capture make log
+ # make_log, s = Open3.capture2e("make")
#
def capture2e(*cmd)
if Hash === cmd.last
@@ -1108,54 +633,57 @@ module Open3
end
module_function :pipeline_start
- # :call-seq:
- # Open3.pipeline([env, ] *cmds, options = {}) -> array_of_statuses
- #
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
- #
- # - Creates a child process for each of the given +cmds+
- # by calling Process.spawn.
- # - Pipes the +stdout+ from each child to the +stdin+ of the next child,
- # or, for the last child, to the caller's +stdout+.
- # - Waits for all child processes to exit.
- # - Returns an array of Process::Status objects (one for each child).
- #
- # A simple example:
- #
- # Open3.pipeline('ls', 'grep [A-Z]')
- # # => [#<Process::Status: pid 1343895 exit 0>, #<Process::Status: pid 1343897 exit 0>]
+ # Open3.pipeline starts a list of commands as a pipeline.
+ # It waits for the completion of the commands.
+ # No pipes are created for stdin of the first command and
+ # stdout of the last command.
#
- # Output:
+ # status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])
#
- # Gemfile
- # LICENSE.txt
- # Rakefile
- # README.md
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
#
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
+ # Note that env and opts are optional, as Process.spawn.
#
- # If the first argument is a hash, it becomes leading argument +env+
- # in each call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # Example:
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in each call to Process.spawn'
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # fname = "/usr/share/man/man1/ruby.1.gz"
+ # p Open3.pipeline(["zcat", fname], "nroff -man", "less")
+ # #=> [#<Process::Status: pid 11817 exit 0>,
+ # # #<Process::Status: pid 11820 exit 0>,
+ # # #<Process::Status: pid 11828 exit 0>]
#
- # Each remaining argument in +cmds+ is one of:
+ # fname = "/usr/share/man/man1/ls.1.gz"
+ # Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")
#
- # - A +command_line+: a string that begins with a shell reserved word
- # or special built-in, or contains one or more metacharacters.
- # - An +exe_path+: the string path to an executable to be called.
- # - An array containing a +command_line+ or an +exe_path+,
- # along with zero or more string arguments for the command.
+ # # convert PDF to PS and send to a printer by lpr
+ # pdf_file = "paper.pdf"
+ # printer = "printer-name"
+ # Open3.pipeline(["pdftops", pdf_file, "-"],
+ # ["lpr", "-P#{printer}"])
+ #
+ # # count lines
+ # Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")
+ #
+ # # cyclic pipeline
+ # r,w = IO.pipe
+ # w.print "ibase=14\n10\n"
+ # Open3.pipeline("bc", "tee /dev/tty", :in=>r, :out=>w)
+ # #=> 14
+ # # 18
+ # # 22
+ # # 30
+ # # 42
+ # # 58
+ # # 78
+ # # 106
+ # # 202
#
def pipeline(*cmds)
if Hash === cmds.last
diff --git a/lib/open3/open3.gemspec b/lib/open3/open3.gemspec
index 21980decac..a33fca7444 100644
--- a/lib/open3/open3.gemspec
+++ b/lib/open3/open3.gemspec
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/open3/version.rb b/lib/open3/version.rb
index 378b389110..b6b6ee2c9c 100644
--- a/lib/open3/version.rb
+++ b/lib/open3/version.rb
@@ -1,3 +1,3 @@
module Open3
- VERSION = "0.2.0"
+ VERSION = "0.1.2"
end
diff --git a/lib/optparse.rb b/lib/optparse.rb
index 832b928a2d..53a4387bd8 100644
--- a/lib/optparse.rb
+++ b/lib/optparse.rb
@@ -48,7 +48,7 @@
#
# == OptionParser
#
-# === New to +OptionParser+?
+# === New to \OptionParser?
#
# See the {Tutorial}[optparse/tutorial.rdoc].
#
@@ -152,14 +152,14 @@
# OptionParser supports the ability to coerce command line arguments
# into objects for us.
#
-# OptionParser comes with a few ready-to-use kinds of type
+# OptionParser comes with a few ready-to-use kinds of type
# coercion. They are:
#
-# - Date -- Anything accepted by +Date.parse+ (need to require +optparse/date+)
-# - DateTime -- Anything accepted by +DateTime.parse+ (need to require +optparse/date+)
-# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+ (need to require +optparse/time+)
-# - URI -- Anything accepted by +URI.parse+ (need to require +optparse/uri+)
-# - Shellwords -- Anything accepted by +Shellwords.shellwords+ (need to require +optparse/shellwords+)
+# - Date -- Anything accepted by +Date.parse+
+# - DateTime -- Anything accepted by +DateTime.parse+
+# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+
+# - URI -- Anything accepted by +URI.parse+
+# - Shellwords -- Anything accepted by +Shellwords.shellwords+
# - String -- Any non-empty string
# - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040)
# - Float -- Any float. (e.g. 10, 3.14, -100E+13)
@@ -425,7 +425,7 @@
# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
#
class OptionParser
- OptionParser::Version = "0.4.0"
+ OptionParser::Version = "0.3.1"
# :stopdoc:
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
@@ -1775,16 +1775,7 @@ XXX
# # params["bar"] = "x" # --bar x
# # params["zot"] = "z" # --zot Z
#
- # Option +symbolize_names+ (boolean) specifies whether returned Hash keys should be Symbols; defaults to +false+ (use Strings).
- #
- # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option", symbolize_names: true)
- # # params[:a] = true # -a
- # # params[:b] = "1" # -b1
- # # params[:foo] = "1" # --foo
- # # params[:bar] = "x" # --bar x
- # # params[:zot] = "z" # --zot Z
- #
- def getopts(*args, symbolize_names: false)
+ def getopts(*args)
argv = Array === args.first ? args.shift : default_argv
single_options, *long_options = *args
@@ -1813,14 +1804,14 @@ XXX
end
parse_in_order(argv, result.method(:[]=))
- symbolize_names ? result.transform_keys(&:to_sym) : result
+ result
end
#
# See #getopts.
#
- def self.getopts(*args, symbolize_names: false)
- new.getopts(*args, symbolize_names: symbolize_names)
+ def self.getopts(*args)
+ new.getopts(*args)
end
#
@@ -2298,8 +2289,8 @@ XXX
# rescue OptionParser::ParseError
# end
#
- def getopts(*args, symbolize_names: false)
- options.getopts(self, *args, symbolize_names: symbolize_names)
+ def getopts(*args)
+ options.getopts(self, *args)
end
#
diff --git a/lib/ostruct.gemspec b/lib/ostruct.gemspec
deleted file mode 100644
index 08a7aefb05..0000000000
--- a/lib/ostruct.gemspec
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Marc-Andre Lafortune"]
- spec.email = ["ruby-core@marc-andre.ca"]
-
- spec.summary = %q{Class to build custom data structures, similar to a Hash.}
- spec.description = %q{Class to build custom data structures, similar to a Hash.}
- spec.homepage = "https://github.com/ruby/ostruct"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = ">= 2.5.0"
-
- spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/ostruct.rb", "ostruct.gemspec"]
- spec.require_paths = ["lib"]
-end
diff --git a/lib/ostruct.rb b/lib/ostruct.rb
index fa882b7b9b..a08561d6c9 100644
--- a/lib/ostruct.rb
+++ b/lib/ostruct.rb
@@ -107,15 +107,7 @@
# For all these reasons, consider not using OpenStruct at all.
#
class OpenStruct
- VERSION = "0.6.0"
-
- HAS_PERFORMANCE_WARNINGS = begin
- Warning[:performance]
- true
- rescue NoMethodError, ArgumentError
- false
- end
- private_constant :HAS_PERFORMANCE_WARNINGS
+ VERSION = "0.5.5"
#
# Creates a new OpenStruct object. By default, the resulting OpenStruct
@@ -132,10 +124,6 @@ class OpenStruct
# data # => #<OpenStruct country="Australia", capital="Canberra">
#
def initialize(hash=nil)
- if HAS_PERFORMANCE_WARNINGS && Warning[:performance]
- warn "OpenStruct use is discouraged for performance reasons", uplevel: 1, category: :performance
- end
-
if hash
update_to_values!(hash)
else
diff --git a/lib/ostruct/ostruct.gemspec b/lib/ostruct/ostruct.gemspec
new file mode 100644
index 0000000000..31ecc312c3
--- /dev/null
+++ b/lib/ostruct/ostruct.gemspec
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Marc-Andre Lafortune"]
+ spec.email = ["ruby-core@marc-andre.ca"]
+
+ spec.summary = %q{Class to build custom data structures, similar to a Hash.}
+ spec.description = %q{Class to build custom data structures, similar to a Hash.}
+ spec.homepage = "https://github.com/ruby/ostruct"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+ spec.required_ruby_version = ">= 2.5.0"
+
+ spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/ostruct.rb", "ostruct.gemspec"]
+ spec.require_paths = ["lib"]
+
+ spec.add_development_dependency "bundler"
+ spec.add_development_dependency "rake"
+end
diff --git a/lib/pp.gemspec b/lib/pp.gemspec
index 27a92a8ce4..3f08f400c4 100644
--- a/lib/pp.gemspec
+++ b/lib/pp.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "pp"
+ spec.version = "0.4.0"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/pp.rb b/lib/pp.rb
index 1708dee05e..81551aa116 100644
--- a/lib/pp.rb
+++ b/lib/pp.rb
@@ -46,7 +46,6 @@ require 'prettyprint'
#
# To define a customized pretty printing function for your classes,
# redefine method <code>#pretty_print(pp)</code> in the class.
-# Note that <code>require 'pp'</code> is needed before redefining <code>#pretty_print(pp)</code>.
#
# <code>#pretty_print</code> takes the +pp+ argument, which is an instance of the PP class.
# The method uses #text, #breakable, #nest, #group and #pp to print the
@@ -62,9 +61,6 @@ require 'prettyprint'
# Tanaka Akira <akr@fsij.org>
class PP < PrettyPrint
-
- VERSION = "0.5.0"
-
# Returns the usable width for +out+.
# As the width of +out+:
# 1. If +out+ is assigned to a tty device, its width is used.
@@ -633,6 +629,10 @@ end
module Kernel
# Returns a pretty printed object as a string.
#
+ # In order to use this method you must first require the PP module:
+ #
+ # require 'pp'
+ #
# See the PP module for more information.
def pretty_inspect
PP.pp(self, ''.dup)
diff --git a/lib/prettyprint.gemspec b/lib/prettyprint.gemspec
index a18adb174b..eae2227d60 100644
--- a/lib/prettyprint.gemspec
+++ b/lib/prettyprint.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "prettyprint"
+ spec.version = "0.1.1"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/prettyprint.rb b/lib/prettyprint.rb
index 6f50192f5d..188c2e6db0 100644
--- a/lib/prettyprint.rb
+++ b/lib/prettyprint.rb
@@ -23,18 +23,16 @@
#
# == References
# Christian Lindig, Strictly Pretty, March 2000,
-# https://lindig.github.io/papers/strictly-pretty-2000.pdf
+# http://www.st.cs.uni-sb.de/~lindig/papers/#pretty
#
# Philip Wadler, A prettier printer, March 1998,
-# https://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
+# http://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
#
# == Author
# Tanaka Akira <akr@fsij.org>
#
class PrettyPrint
- VERSION = "0.2.0"
-
# This is a convenience method which is same as follows:
#
# begin
diff --git a/lib/prism.rb b/lib/prism.rb
deleted file mode 100644
index 350febcaa8..0000000000
--- a/lib/prism.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: true
-
-# The Prism Ruby parser.
-#
-# "Parsing Ruby is suddenly manageable!"
-# - You, hopefully
-#
-module Prism
- # There are many files in prism that are templated to handle every node type,
- # which means the files can end up being quite large. We autoload them to make
- # our require speed faster since consuming libraries are unlikely to use all
- # of these features.
-
- autoload :BasicVisitor, "prism/visitor"
- autoload :Compiler, "prism/compiler"
- autoload :Debug, "prism/debug"
- autoload :DesugarCompiler, "prism/desugar_compiler"
- autoload :Dispatcher, "prism/dispatcher"
- autoload :DSL, "prism/dsl"
- autoload :LexCompat, "prism/lex_compat"
- autoload :LexRipper, "prism/lex_compat"
- autoload :MutationCompiler, "prism/mutation_compiler"
- autoload :NodeInspector, "prism/node_inspector"
- autoload :RipperCompat, "prism/ripper_compat"
- autoload :Pack, "prism/pack"
- autoload :Pattern, "prism/pattern"
- autoload :Serialize, "prism/serialize"
- autoload :Visitor, "prism/visitor"
-
- # Some of these constants are not meant to be exposed, so marking them as
- # private here.
-
- private_constant :Debug
- private_constant :LexCompat
- private_constant :LexRipper
-
- # :call-seq:
- # Prism::lex_compat(source, **options) -> Array
- #
- # Returns an array of tokens that closely resembles that of the Ripper lexer.
- # The only difference is that since we don't keep track of lexer state in the
- # same way, it's going to always return the NONE state.
- #
- # For supported options, see Prism::parse.
- def self.lex_compat(source, **options)
- LexCompat.new(source, **options).result
- end
-
- # :call-seq:
- # Prism::lex_ripper(source) -> Array
- #
- # This lexes with the Ripper lex. It drops any space events but otherwise
- # returns the same tokens. Raises SyntaxError if the syntax in source is
- # invalid.
- def self.lex_ripper(source)
- LexRipper.new(source).result
- end
-
- # :call-seq:
- # Prism::load(source, serialized) -> ParseResult
- #
- # Load the serialized AST using the source as a reference into a tree.
- def self.load(source, serialized)
- Serialize.load(source, serialized)
- end
-end
-
-require_relative "prism/node"
-require_relative "prism/node_ext"
-require_relative "prism/parse_result"
-require_relative "prism/parse_result/comments"
-require_relative "prism/parse_result/newlines"
-
-# This is a Ruby implementation of the prism parser. If we're running on CRuby
-# and we haven't explicitly set the PRISM_FFI_BACKEND environment variable, then
-# it's going to require the built library. Otherwise, it's going to require a
-# module that uses FFI to call into the library.
-if RUBY_ENGINE == "ruby" and !ENV["PRISM_FFI_BACKEND"]
- require "prism/prism"
-else
- require_relative "prism/ffi"
-end
diff --git a/lib/prism/debug.rb b/lib/prism/debug.rb
deleted file mode 100644
index d0469adc9a..0000000000
--- a/lib/prism/debug.rb
+++ /dev/null
@@ -1,195 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # This module is used for testing and debugging and is not meant to be used by
- # consumers of this library.
- module Debug
- # A wrapper around a RubyVM::InstructionSequence that provides a more
- # convenient interface for accessing parts of the iseq.
- class ISeq # :nodoc:
- attr_reader :parts
-
- def initialize(parts)
- @parts = parts
- end
-
- def type
- parts[0]
- end
-
- def local_table
- parts[10]
- end
-
- def instructions
- parts[13]
- end
-
- def each_child
- instructions.each do |instruction|
- # Only look at arrays. Other instructions are line numbers or
- # tracepoint events.
- next unless instruction.is_a?(Array)
-
- instruction.each do |opnd|
- # Only look at arrays. Other operands are literals.
- next unless opnd.is_a?(Array)
-
- # Only look at instruction sequences. Other operands are literals.
- next unless opnd[0] == "YARVInstructionSequence/SimpleDataFormat"
-
- yield ISeq.new(opnd)
- end
- end
- end
- end
-
- private_constant :ISeq
-
- # :call-seq:
- # Debug::cruby_locals(source) -> Array
- #
- # For the given source, compiles with CRuby and returns a list of all of the
- # sets of local variables that were encountered.
- def self.cruby_locals(source)
- verbose, $VERBOSE = $VERBOSE, nil
-
- begin
- locals = []
- stack = [ISeq.new(RubyVM::InstructionSequence.compile(source).to_a)]
-
- while (iseq = stack.pop)
- names = [*iseq.local_table]
- names.map!.with_index do |name, index|
- # When an anonymous local variable is present in the iseq's local
- # table, it is represented as the stack offset from the top.
- # However, when these are dumped to binary and read back in, they
- # are replaced with the symbol :#arg_rest. To consistently handle
- # this, we replace them here with their index.
- if name == :"#arg_rest"
- names.length - index + 1
- else
- name
- end
- end
-
- locals << names
- iseq.each_child { |child| stack << child }
- end
-
- locals
- ensure
- $VERBOSE = verbose
- end
- end
-
- # Used to hold the place of a local that will be in the local table but
- # cannot be accessed directly from the source code. For example, the
- # iteration variable in a for loop or the positional parameter on a method
- # definition that is destructured.
- AnonymousLocal = Object.new
- private_constant :AnonymousLocal
-
- # :call-seq:
- # Debug::prism_locals(source) -> Array
- #
- # For the given source, parses with prism and returns a list of all of the
- # sets of local variables that were encountered.
- def self.prism_locals(source)
- locals = []
- stack = [Prism.parse(source).value]
-
- while (node = stack.pop)
- case node
- when BlockNode, DefNode, LambdaNode
- names = node.locals
-
- params = node.parameters
- params = params&.parameters unless node.is_a?(DefNode)
-
- # prism places parameters in the same order that they appear in the
- # source. CRuby places them in the order that they need to appear
- # according to their own internal calling convention. We mimic that
- # order here so that we can compare properly.
- if params
- sorted = [
- *params.requireds.map do |required|
- if required.is_a?(RequiredParameterNode)
- required.name
- else
- AnonymousLocal
- end
- end,
- *params.optionals.map(&:name),
- *((params.rest.name || :*) if params.rest && params.rest.operator != ","),
- *params.posts.map do |post|
- if post.is_a?(RequiredParameterNode)
- post.name
- else
- AnonymousLocal
- end
- end,
- *params.keywords.grep(RequiredKeywordParameterNode).map(&:name),
- *params.keywords.grep(OptionalKeywordParameterNode).map(&:name),
- ]
-
- if params.keyword_rest.is_a?(ForwardingParameterNode)
- sorted.push(:*, :&, :"...")
- end
-
- sorted << AnonymousLocal if params.keywords.any?
-
- # Recurse down the parameter tree to find any destructured
- # parameters and add them after the other parameters.
- param_stack = params.requireds.concat(params.posts).grep(MultiTargetNode).reverse
- while (param = param_stack.pop)
- case param
- when MultiTargetNode
- param_stack.concat(param.rights.reverse)
- param_stack << param.rest
- param_stack.concat(param.lefts.reverse)
- when RequiredParameterNode
- sorted << param.name
- when SplatNode
- sorted << param.expression.name if param.expression
- end
- end
-
- names = sorted.concat(names - sorted)
- end
-
- names.map!.with_index do |name, index|
- if name == AnonymousLocal
- names.length - index + 1
- else
- name
- end
- end
-
- locals << names
- when ClassNode, ModuleNode, ProgramNode, SingletonClassNode
- locals << node.locals
- when ForNode
- locals << [2]
- when PostExecutionNode
- locals.push([], [])
- when InterpolatedRegularExpressionNode
- locals << [] if node.once?
- end
-
- stack.concat(node.compact_child_nodes)
- end
-
- locals
- end
-
- # :call-seq:
- # Debug::newlines(source) -> Array
- #
- # For the given source string, return the byte offsets of every newline in
- # the source.
- def self.newlines(source)
- Prism.parse(source).source.offsets
- end
- end
-end
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
deleted file mode 100644
index 3624217686..0000000000
--- a/lib/prism/desugar_compiler.rb
+++ /dev/null
@@ -1,206 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # DesugarCompiler is a compiler that desugars Ruby code into a more primitive
- # form. This is useful for consumers that want to deal with fewer node types.
- class DesugarCompiler < MutationCompiler
- # @@foo &&= bar
- #
- # becomes
- #
- # @@foo && @@foo = bar
- def visit_class_variable_and_write_node(node)
- desugar_and_write_node(node, ClassVariableReadNode, ClassVariableWriteNode, node.name)
- end
-
- # @@foo ||= bar
- #
- # becomes
- #
- # defined?(@@foo) ? @@foo : @@foo = bar
- def visit_class_variable_or_write_node(node)
- desugar_or_write_defined_node(node, ClassVariableReadNode, ClassVariableWriteNode, node.name)
- end
-
- # @@foo += bar
- #
- # becomes
- #
- # @@foo = @@foo + bar
- def visit_class_variable_operator_write_node(node)
- desugar_operator_write_node(node, ClassVariableReadNode, ClassVariableWriteNode, node.name)
- end
-
- # Foo &&= bar
- #
- # becomes
- #
- # Foo && Foo = bar
- def visit_constant_and_write_node(node)
- desugar_and_write_node(node, ConstantReadNode, ConstantWriteNode, node.name)
- end
-
- # Foo ||= bar
- #
- # becomes
- #
- # defined?(Foo) ? Foo : Foo = bar
- def visit_constant_or_write_node(node)
- desugar_or_write_defined_node(node, ConstantReadNode, ConstantWriteNode, node.name)
- end
-
- # Foo += bar
- #
- # becomes
- #
- # Foo = Foo + bar
- def visit_constant_operator_write_node(node)
- desugar_operator_write_node(node, ConstantReadNode, ConstantWriteNode, node.name)
- end
-
- # $foo &&= bar
- #
- # becomes
- #
- # $foo && $foo = bar
- def visit_global_variable_and_write_node(node)
- desugar_and_write_node(node, GlobalVariableReadNode, GlobalVariableWriteNode, node.name)
- end
-
- # $foo ||= bar
- #
- # becomes
- #
- # defined?($foo) ? $foo : $foo = bar
- def visit_global_variable_or_write_node(node)
- desugar_or_write_defined_node(node, GlobalVariableReadNode, GlobalVariableWriteNode, node.name)
- end
-
- # $foo += bar
- #
- # becomes
- #
- # $foo = $foo + bar
- def visit_global_variable_operator_write_node(node)
- desugar_operator_write_node(node, GlobalVariableReadNode, GlobalVariableWriteNode, node.name)
- end
-
- # @foo &&= bar
- #
- # becomes
- #
- # @foo && @foo = bar
- def visit_instance_variable_and_write_node(node)
- desugar_and_write_node(node, InstanceVariableReadNode, InstanceVariableWriteNode, node.name)
- end
-
- # @foo ||= bar
- #
- # becomes
- #
- # @foo || @foo = bar
- def visit_instance_variable_or_write_node(node)
- desugar_or_write_node(node, InstanceVariableReadNode, InstanceVariableWriteNode, node.name)
- end
-
- # @foo += bar
- #
- # becomes
- #
- # @foo = @foo + bar
- def visit_instance_variable_operator_write_node(node)
- desugar_operator_write_node(node, InstanceVariableReadNode, InstanceVariableWriteNode, node.name)
- end
-
- # foo &&= bar
- #
- # becomes
- #
- # foo && foo = bar
- def visit_local_variable_and_write_node(node)
- desugar_and_write_node(node, LocalVariableReadNode, LocalVariableWriteNode, node.name, node.depth)
- end
-
- # foo ||= bar
- #
- # becomes
- #
- # foo || foo = bar
- def visit_local_variable_or_write_node(node)
- desugar_or_write_node(node, LocalVariableReadNode, LocalVariableWriteNode, node.name, node.depth)
- end
-
- # foo += bar
- #
- # becomes
- #
- # foo = foo + bar
- def visit_local_variable_operator_write_node(node)
- desugar_operator_write_node(node, LocalVariableReadNode, LocalVariableWriteNode, node.name, node.depth)
- end
-
- private
-
- # Desugar `x &&= y` to `x && x = y`
- def desugar_and_write_node(node, read_class, write_class, *arguments)
- AndNode.new(
- read_class.new(*arguments, node.name_loc),
- write_class.new(*arguments, node.name_loc, node.value, node.operator_loc, node.location),
- node.operator_loc,
- node.location
- )
- end
-
- # Desugar `x += y` to `x = x + y`
- def desugar_operator_write_node(node, read_class, write_class, *arguments)
- write_class.new(
- *arguments,
- node.name_loc,
- CallNode.new(
- read_class.new(*arguments, node.name_loc),
- nil,
- node.operator_loc.copy(length: node.operator_loc.length - 1),
- nil,
- ArgumentsNode.new([node.value], 0, node.value.location),
- nil,
- nil,
- 0,
- node.operator_loc.slice.chomp("="),
- node.location
- ),
- node.operator_loc.copy(start_offset: node.operator_loc.end_offset - 1, length: 1),
- node.location
- )
- end
-
- # Desugar `x ||= y` to `x || x = y`
- def desugar_or_write_node(node, read_class, write_class, *arguments)
- OrNode.new(
- read_class.new(*arguments, node.name_loc),
- write_class.new(*arguments, node.name_loc, node.value, node.operator_loc, node.location),
- node.operator_loc,
- node.location
- )
- end
-
- # Desugar `x ||= y` to `defined?(x) ? x : x = y`
- def desugar_or_write_defined_node(node, read_class, write_class, *arguments)
- IfNode.new(
- node.operator_loc,
- DefinedNode.new(nil, read_class.new(*arguments, node.name_loc), nil, node.operator_loc, node.name_loc),
- StatementsNode.new([read_class.new(*arguments, node.name_loc)], node.location),
- ElseNode.new(
- node.operator_loc,
- StatementsNode.new(
- [write_class.new(*arguments, node.name_loc, node.value, node.operator_loc, node.location)],
- node.location
- ),
- node.operator_loc,
- node.location
- ),
- node.operator_loc,
- node.location
- )
- end
- end
-end
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
deleted file mode 100644
index 96102201b3..0000000000
--- a/lib/prism/ffi.rb
+++ /dev/null
@@ -1,328 +0,0 @@
-# frozen_string_literal: true
-
-# This file is responsible for mirroring the API provided by the C extension by
-# using FFI to call into the shared library.
-
-require "rbconfig"
-require "ffi"
-
-module Prism
- BACKEND = :FFI
-
- module LibRubyParser # :nodoc:
- extend FFI::Library
-
- # Define the library that we will be pulling functions from. Note that this
- # must align with the build shared library from make/rake.
- ffi_lib File.expand_path("../../build/librubyparser.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
-
- # Convert a native C type declaration into a symbol that FFI understands.
- # For example:
- #
- # const char * -> :pointer
- # bool -> :bool
- # size_t -> :size_t
- # void -> :void
- #
- def self.resolve_type(type)
- type = type.strip
- type.end_with?("*") ? :pointer : type.delete_prefix("const ").to_sym
- end
-
- # Read through the given header file and find the declaration of each of the
- # given functions. For each one, define a function with the same name and
- # signature as the C function.
- def self.load_exported_functions_from(header, *functions)
- File.foreach(File.expand_path("../../include/#{header}", __dir__)) do |line|
- # We only want to attempt to load exported functions.
- next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
-
- # We only want to load the functions that we are interested in.
- next unless functions.any? { |function| line.include?(function) }
-
- # Parse the function declaration.
- unless /^PRISM_EXPORTED_FUNCTION (?<return_type>.+) (?<name>\w+)\((?<arg_types>.+)\);$/ =~ line
- raise "Could not parse #{line}"
- end
-
- # Delete the function from the list of functions we are looking for to
- # mark it as having been found.
- functions.delete(name)
-
- # Split up the argument types into an array, ensure we handle the case
- # where there are no arguments (by explicit void).
- arg_types = arg_types.split(",").map(&:strip)
- arg_types = [] if arg_types == %w[void]
-
- # Resolve the type of the argument by dropping the name of the argument
- # first if it is present.
- arg_types.map! { |type| resolve_type(type.sub(/\w+$/, "")) }
-
- # Attach the function using the FFI library.
- attach_function name, arg_types, resolve_type(return_type)
- end
-
- # If we didn't find all of the functions, raise an error.
- raise "Could not find functions #{functions.inspect}" unless functions.empty?
- end
-
- load_exported_functions_from(
- "prism.h",
- "pm_version",
- "pm_serialize_parse",
- "pm_serialize_parse_comments",
- "pm_serialize_lex",
- "pm_serialize_parse_lex"
- )
-
- load_exported_functions_from(
- "prism/util/pm_buffer.h",
- "pm_buffer_sizeof",
- "pm_buffer_init",
- "pm_buffer_value",
- "pm_buffer_length",
- "pm_buffer_free"
- )
-
- load_exported_functions_from(
- "prism/util/pm_string.h",
- "pm_string_mapped_init",
- "pm_string_free",
- "pm_string_source",
- "pm_string_length",
- "pm_string_sizeof"
- )
-
- # This object represents a pm_buffer_t. We only use it as an opaque pointer,
- # so it doesn't need to know the fields of pm_buffer_t.
- class PrismBuffer # :nodoc:
- SIZEOF = LibRubyParser.pm_buffer_sizeof
-
- attr_reader :pointer
-
- def initialize(pointer)
- @pointer = pointer
- end
-
- def value
- LibRubyParser.pm_buffer_value(pointer)
- end
-
- def length
- LibRubyParser.pm_buffer_length(pointer)
- end
-
- def read
- value.read_string(length)
- end
-
- # Initialize a new buffer and yield it to the block. The buffer will be
- # automatically freed when the block returns.
- def self.with(&block)
- pointer = FFI::MemoryPointer.new(SIZEOF)
-
- begin
- raise unless LibRubyParser.pm_buffer_init(pointer)
- yield new(pointer)
- ensure
- LibRubyParser.pm_buffer_free(pointer)
- pointer.free
- end
- end
- end
-
- # This object represents a pm_string_t. We only use it as an opaque pointer,
- # so it doesn't have to be an FFI::Struct.
- class PrismString # :nodoc:
- SIZEOF = LibRubyParser.pm_string_sizeof
-
- attr_reader :pointer
-
- def initialize(pointer)
- @pointer = pointer
- end
-
- def source
- LibRubyParser.pm_string_source(pointer)
- end
-
- def length
- LibRubyParser.pm_string_length(pointer)
- end
-
- def read
- source.read_string(length)
- end
-
- # Yields a pm_string_t pointer to the given block.
- def self.with(filepath, &block)
- pointer = FFI::MemoryPointer.new(SIZEOF)
-
- begin
- raise unless LibRubyParser.pm_string_mapped_init(pointer, filepath)
- yield new(pointer)
- ensure
- LibRubyParser.pm_string_free(pointer)
- pointer.free
- end
- end
- end
- end
-
- # Mark the LibRubyParser module as private as it should only be called through
- # the prism module.
- private_constant :LibRubyParser
-
- # The version constant is set by reading the result of calling pm_version.
- VERSION = LibRubyParser.pm_version.read_string
-
- class << self
- # Mirror the Prism.dump API by using the serialization API.
- def dump(code, **options)
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_parse(buffer.pointer, code, code.bytesize, dump_options(options))
- buffer.read
- end
- end
-
- # Mirror the Prism.dump_file API by using the serialization API.
- def dump_file(filepath, **options)
- LibRubyParser::PrismString.with(filepath) do |string|
- dump(string.read, **options, filepath: filepath)
- end
- end
-
- # Mirror the Prism.lex API by using the serialization API.
- def lex(code, **options)
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_lex(buffer.pointer, code, code.bytesize, dump_options(options))
- Serialize.load_tokens(Source.new(code), buffer.read)
- end
- end
-
- # Mirror the Prism.lex_file API by using the serialization API.
- def lex_file(filepath, **options)
- LibRubyParser::PrismString.with(filepath) do |string|
- lex(string.read, **options, filepath: filepath)
- end
- end
-
- # Mirror the Prism.parse API by using the serialization API.
- def parse(code, **options)
- Prism.load(code, dump(code, **options))
- end
-
- # Mirror the Prism.parse_file API by using the serialization API. This uses
- # native strings instead of Ruby strings because it allows us to use mmap when
- # it is available.
- def parse_file(filepath, **options)
- LibRubyParser::PrismString.with(filepath) do |string|
- parse(string.read, **options, filepath: filepath)
- end
- end
-
- # Mirror the Prism.parse_comments API by using the serialization API.
- def parse_comments(code, **options)
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_parse_comments(buffer.pointer, code, code.bytesize, dump_options(options))
-
- source = Source.new(code)
- loader = Serialize::Loader.new(source, buffer.read)
-
- loader.load_header
- loader.load_force_encoding
- loader.load_start_line
- loader.load_comments
- end
- end
-
- # Mirror the Prism.parse_file_comments API by using the serialization
- # API. This uses native strings instead of Ruby strings because it allows us
- # to use mmap when it is available.
- def parse_file_comments(filepath, **options)
- LibRubyParser::PrismString.with(filepath) do |string|
- parse_comments(string.read, **options, filepath: filepath)
- end
- end
-
- # Mirror the Prism.parse_lex API by using the serialization API.
- def parse_lex(code, **options)
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_parse_lex(buffer.pointer, code, code.bytesize, dump_options(options))
-
- source = Source.new(code)
- loader = Serialize::Loader.new(source, buffer.read)
-
- tokens = loader.load_tokens
- node, comments, magic_comments, errors, warnings = loader.load_nodes
- tokens.each { |token,| token.value.force_encoding(loader.encoding) }
-
- ParseResult.new([node, tokens], comments, magic_comments, errors, warnings, source)
- end
- end
-
- # Mirror the Prism.parse_lex_file API by using the serialization API.
- def parse_lex_file(filepath, **options)
- LibRubyParser::PrismString.with(filepath) do |string|
- parse_lex(string.read, **options, filepath: filepath)
- end
- end
-
- private
-
- # Convert the given options into a serialized options string.
- def dump_options(options)
- template = +""
- values = []
-
- template << "L"
- if (filepath = options[:filepath])
- values.push(filepath.bytesize, filepath.b)
- template << "A*"
- else
- values << 0
- end
-
- template << "L"
- values << options.fetch(:line, 1)
-
- template << "L"
- if (encoding = options[:encoding])
- name = encoding.name
- values.push(name.bytesize, name.b)
- template << "A*"
- else
- values << 0
- end
-
- template << "C"
- values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
-
- template << "C"
- values << (options[:verbose] ? 0 : 1)
-
- template << "L"
- if (scopes = options[:scopes])
- values << scopes.length
-
- scopes.each do |scope|
- template << "L"
- values << scope.length
-
- scope.each do |local|
- name = local.name
- template << "L"
- values << name.bytesize
-
- template << "A*"
- values << name.b
- end
- end
- else
- values << 0
- end
-
- values.pack(template)
- end
- end
-end
diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb
deleted file mode 100644
index b6d12053a0..0000000000
--- a/lib/prism/lex_compat.rb
+++ /dev/null
@@ -1,882 +0,0 @@
-# frozen_string_literal: true
-
-require "delegate"
-
-module Prism
- # This class is responsible for lexing the source using prism and then
- # converting those tokens to be compatible with Ripper. In the vast majority
- # of cases, this is a one-to-one mapping of the token type. Everything else
- # generally lines up. However, there are a few cases that require special
- # handling.
- class LexCompat # :nodoc:
- # This is a mapping of prism token types to Ripper token types. This is a
- # many-to-one mapping because we split up our token types, whereas Ripper
- # tends to group them.
- RIPPER = {
- AMPERSAND: :on_op,
- AMPERSAND_AMPERSAND: :on_op,
- AMPERSAND_AMPERSAND_EQUAL: :on_op,
- AMPERSAND_DOT: :on_op,
- AMPERSAND_EQUAL: :on_op,
- BACK_REFERENCE: :on_backref,
- BACKTICK: :on_backtick,
- BANG: :on_op,
- BANG_EQUAL: :on_op,
- BANG_TILDE: :on_op,
- BRACE_LEFT: :on_lbrace,
- BRACE_RIGHT: :on_rbrace,
- BRACKET_LEFT: :on_lbracket,
- BRACKET_LEFT_ARRAY: :on_lbracket,
- BRACKET_LEFT_RIGHT: :on_op,
- BRACKET_LEFT_RIGHT_EQUAL: :on_op,
- BRACKET_RIGHT: :on_rbracket,
- CARET: :on_op,
- CARET_EQUAL: :on_op,
- CHARACTER_LITERAL: :on_CHAR,
- CLASS_VARIABLE: :on_cvar,
- COLON: :on_op,
- COLON_COLON: :on_op,
- COMMA: :on_comma,
- COMMENT: :on_comment,
- CONSTANT: :on_const,
- DOT: :on_period,
- DOT_DOT: :on_op,
- DOT_DOT_DOT: :on_op,
- EMBDOC_BEGIN: :on_embdoc_beg,
- EMBDOC_END: :on_embdoc_end,
- EMBDOC_LINE: :on_embdoc,
- EMBEXPR_BEGIN: :on_embexpr_beg,
- EMBEXPR_END: :on_embexpr_end,
- EMBVAR: :on_embvar,
- EOF: :on_eof,
- EQUAL: :on_op,
- EQUAL_EQUAL: :on_op,
- EQUAL_EQUAL_EQUAL: :on_op,
- EQUAL_GREATER: :on_op,
- EQUAL_TILDE: :on_op,
- FLOAT: :on_float,
- FLOAT_IMAGINARY: :on_imaginary,
- FLOAT_RATIONAL: :on_rational,
- FLOAT_RATIONAL_IMAGINARY: :on_imaginary,
- GREATER: :on_op,
- GREATER_EQUAL: :on_op,
- GREATER_GREATER: :on_op,
- GREATER_GREATER_EQUAL: :on_op,
- GLOBAL_VARIABLE: :on_gvar,
- HEREDOC_END: :on_heredoc_end,
- HEREDOC_START: :on_heredoc_beg,
- IDENTIFIER: :on_ident,
- IGNORED_NEWLINE: :on_ignored_nl,
- INTEGER: :on_int,
- INTEGER_IMAGINARY: :on_imaginary,
- INTEGER_RATIONAL: :on_rational,
- INTEGER_RATIONAL_IMAGINARY: :on_imaginary,
- INSTANCE_VARIABLE: :on_ivar,
- INVALID: :INVALID,
- KEYWORD___ENCODING__: :on_kw,
- KEYWORD___LINE__: :on_kw,
- KEYWORD___FILE__: :on_kw,
- KEYWORD_ALIAS: :on_kw,
- KEYWORD_AND: :on_kw,
- KEYWORD_BEGIN: :on_kw,
- KEYWORD_BEGIN_UPCASE: :on_kw,
- KEYWORD_BREAK: :on_kw,
- KEYWORD_CASE: :on_kw,
- KEYWORD_CLASS: :on_kw,
- KEYWORD_DEF: :on_kw,
- KEYWORD_DEFINED: :on_kw,
- KEYWORD_DO: :on_kw,
- KEYWORD_DO_LOOP: :on_kw,
- KEYWORD_ELSE: :on_kw,
- KEYWORD_ELSIF: :on_kw,
- KEYWORD_END: :on_kw,
- KEYWORD_END_UPCASE: :on_kw,
- KEYWORD_ENSURE: :on_kw,
- KEYWORD_FALSE: :on_kw,
- KEYWORD_FOR: :on_kw,
- KEYWORD_IF: :on_kw,
- KEYWORD_IF_MODIFIER: :on_kw,
- KEYWORD_IN: :on_kw,
- KEYWORD_MODULE: :on_kw,
- KEYWORD_NEXT: :on_kw,
- KEYWORD_NIL: :on_kw,
- KEYWORD_NOT: :on_kw,
- KEYWORD_OR: :on_kw,
- KEYWORD_REDO: :on_kw,
- KEYWORD_RESCUE: :on_kw,
- KEYWORD_RESCUE_MODIFIER: :on_kw,
- KEYWORD_RETRY: :on_kw,
- KEYWORD_RETURN: :on_kw,
- KEYWORD_SELF: :on_kw,
- KEYWORD_SUPER: :on_kw,
- KEYWORD_THEN: :on_kw,
- KEYWORD_TRUE: :on_kw,
- KEYWORD_UNDEF: :on_kw,
- KEYWORD_UNLESS: :on_kw,
- KEYWORD_UNLESS_MODIFIER: :on_kw,
- KEYWORD_UNTIL: :on_kw,
- KEYWORD_UNTIL_MODIFIER: :on_kw,
- KEYWORD_WHEN: :on_kw,
- KEYWORD_WHILE: :on_kw,
- KEYWORD_WHILE_MODIFIER: :on_kw,
- KEYWORD_YIELD: :on_kw,
- LABEL: :on_label,
- LABEL_END: :on_label_end,
- LAMBDA_BEGIN: :on_tlambeg,
- LESS: :on_op,
- LESS_EQUAL: :on_op,
- LESS_EQUAL_GREATER: :on_op,
- LESS_LESS: :on_op,
- LESS_LESS_EQUAL: :on_op,
- METHOD_NAME: :on_ident,
- MINUS: :on_op,
- MINUS_EQUAL: :on_op,
- MINUS_GREATER: :on_tlambda,
- NEWLINE: :on_nl,
- NUMBERED_REFERENCE: :on_backref,
- PARENTHESIS_LEFT: :on_lparen,
- PARENTHESIS_LEFT_PARENTHESES: :on_lparen,
- PARENTHESIS_RIGHT: :on_rparen,
- PERCENT: :on_op,
- PERCENT_EQUAL: :on_op,
- PERCENT_LOWER_I: :on_qsymbols_beg,
- PERCENT_LOWER_W: :on_qwords_beg,
- PERCENT_LOWER_X: :on_backtick,
- PERCENT_UPPER_I: :on_symbols_beg,
- PERCENT_UPPER_W: :on_words_beg,
- PIPE: :on_op,
- PIPE_EQUAL: :on_op,
- PIPE_PIPE: :on_op,
- PIPE_PIPE_EQUAL: :on_op,
- PLUS: :on_op,
- PLUS_EQUAL: :on_op,
- QUESTION_MARK: :on_op,
- RATIONAL_FLOAT: :on_rational,
- RATIONAL_INTEGER: :on_rational,
- REGEXP_BEGIN: :on_regexp_beg,
- REGEXP_END: :on_regexp_end,
- SEMICOLON: :on_semicolon,
- SLASH: :on_op,
- SLASH_EQUAL: :on_op,
- STAR: :on_op,
- STAR_EQUAL: :on_op,
- STAR_STAR: :on_op,
- STAR_STAR_EQUAL: :on_op,
- STRING_BEGIN: :on_tstring_beg,
- STRING_CONTENT: :on_tstring_content,
- STRING_END: :on_tstring_end,
- SYMBOL_BEGIN: :on_symbeg,
- TILDE: :on_op,
- UAMPERSAND: :on_op,
- UCOLON_COLON: :on_op,
- UDOT_DOT: :on_op,
- UDOT_DOT_DOT: :on_op,
- UMINUS: :on_op,
- UMINUS_NUM: :on_op,
- UPLUS: :on_op,
- USTAR: :on_op,
- USTAR_STAR: :on_op,
- WORDS_SEP: :on_words_sep,
- "__END__": :on___end__
- }.freeze
-
- # When we produce tokens, we produce the same arrays that Ripper does.
- # However, we add a couple of convenience methods onto them to make them a
- # little easier to work with. We delegate all other methods to the array.
- class Token < SimpleDelegator
- # The location of the token in the source.
- def location
- self[0]
- end
-
- # The type of the token.
- def event
- self[1]
- end
-
- # The slice of the source that this token represents.
- def value
- self[2]
- end
-
- # The state of the lexer when this token was produced.
- def state
- self[3]
- end
- end
-
- # Ripper doesn't include the rest of the token in the event, so we need to
- # trim it down to just the content on the first line when comparing.
- class EndContentToken < Token
- def ==(other) # :nodoc:
- [self[0], self[1], self[2][0..self[2].index("\n")], self[3]] == other
- end
- end
-
- # Tokens where state should be ignored
- # used for :on_comment, :on_heredoc_end, :on_embexpr_end
- class IgnoreStateToken < Token
- def ==(other) # :nodoc:
- self[0...-1] == other[0...-1]
- end
- end
-
- # Ident tokens for the most part are exactly the same, except sometimes we
- # know an ident is a local when ripper doesn't (when they are introduced
- # through named captures in regular expressions). In that case we don't
- # compare the state.
- class IdentToken < Token
- def ==(other) # :nodoc:
- (self[0...-1] == other[0...-1]) && (
- (other[3] == Ripper::EXPR_LABEL | Ripper::EXPR_END) ||
- (other[3] & Ripper::EXPR_ARG_ANY != 0)
- )
- end
- end
-
- # Ignored newlines can occasionally have a LABEL state attached to them, so
- # we compare the state differently here.
- class IgnoredNewlineToken < Token
- def ==(other) # :nodoc:
- return false unless self[0...-1] == other[0...-1]
-
- if self[4] == Ripper::EXPR_ARG | Ripper::EXPR_LABELED
- other[4] & Ripper::EXPR_ARG | Ripper::EXPR_LABELED > 0
- else
- self[4] == other[4]
- end
- end
- end
-
- # If we have an identifier that follows a method name like:
- #
- # def foo bar
- #
- # then Ripper will mark bar as END|LABEL if there is a local in a parent
- # scope named bar because it hasn't pushed the local table yet. We do this
- # more accurately, so we need to allow comparing against both END and
- # END|LABEL.
- class ParamToken < Token
- def ==(other) # :nodoc:
- (self[0...-1] == other[0...-1]) && (
- (other[3] == Ripper::EXPR_END) ||
- (other[3] == Ripper::EXPR_END | Ripper::EXPR_LABEL)
- )
- end
- end
-
- # A heredoc in this case is a list of tokens that belong to the body of the
- # heredoc that should be appended onto the list of tokens when the heredoc
- # closes.
- module Heredoc # :nodoc:
- # Heredocs that are no dash or tilde heredocs are just a list of tokens.
- # We need to keep them around so that we can insert them in the correct
- # order back into the token stream and set the state of the last token to
- # the state that the heredoc was opened in.
- class PlainHeredoc # :nodoc:
- attr_reader :tokens
-
- def initialize
- @tokens = []
- end
-
- def <<(token)
- tokens << token
- end
-
- def to_a
- tokens
- end
- end
-
- # Dash heredocs are a little more complicated. They are a list of tokens
- # that need to be split on "\\\n" to mimic Ripper's behavior. We also need
- # to keep track of the state that the heredoc was opened in.
- class DashHeredoc # :nodoc:
- attr_reader :split, :tokens
-
- def initialize(split)
- @split = split
- @tokens = []
- end
-
- def <<(token)
- tokens << token
- end
-
- def to_a
- embexpr_balance = 0
-
- tokens.each_with_object([]) do |token, results|
- case token.event
- when :on_embexpr_beg
- embexpr_balance += 1
- results << token
- when :on_embexpr_end
- embexpr_balance -= 1
- results << token
- when :on_tstring_content
- if embexpr_balance == 0
- lineno = token[0][0]
- column = token[0][1]
-
- if split
- # Split on "\\\n" to mimic Ripper's behavior. Use a lookbehind
- # to keep the delimiter in the result.
- token.value.split(/(?<=[^\\]\\\n)|(?<=[^\\]\\\r\n)/).each_with_index do |value, index|
- column = 0 if index > 0
- results << Token.new([[lineno, column], :on_tstring_content, value, token.state])
- lineno += value.count("\n")
- end
- else
- results << token
- end
- else
- results << token
- end
- else
- results << token
- end
- end
- end
- end
-
- # Heredocs that are dedenting heredocs are a little more complicated.
- # Ripper outputs on_ignored_sp tokens for the whitespace that is being
- # removed from the output. prism only modifies the node itself and keeps
- # the token the same. This simplifies prism, but makes comparing against
- # Ripper much harder because there is a length mismatch.
- #
- # Fortunately, we already have to pull out the heredoc tokens in order to
- # insert them into the stream in the correct order. As such, we can do
- # some extra manipulation on the tokens to make them match Ripper's
- # output by mirroring the dedent logic that Ripper uses.
- class DedentingHeredoc # :nodoc:
- TAB_WIDTH = 8
-
- attr_reader :tokens, :dedent_next, :dedent, :embexpr_balance
-
- def initialize
- @tokens = []
- @dedent_next = true
- @dedent = nil
- @embexpr_balance = 0
- @ended_on_newline = false
- end
-
- # As tokens are coming in, we track the minimum amount of common leading
- # whitespace on plain string content tokens. This allows us to later
- # remove that amount of whitespace from the beginning of each line.
- def <<(token)
- case token.event
- when :on_embexpr_beg, :on_heredoc_beg
- @embexpr_balance += 1
- @dedent = 0 if @dedent_next && @ended_on_newline
- when :on_embexpr_end, :on_heredoc_end
- @embexpr_balance -= 1
- when :on_tstring_content
- if embexpr_balance == 0
- line = token.value
-
- if dedent_next && !(line.strip.empty? && line.end_with?("\n"))
- leading = line[/\A(\s*)\n?/, 1]
- next_dedent = 0
-
- leading.each_char do |char|
- if char == "\t"
- next_dedent = next_dedent - (next_dedent % TAB_WIDTH) + TAB_WIDTH
- else
- next_dedent += 1
- end
- end
-
- @dedent = [dedent, next_dedent].compact.min
- @dedent_next = true
- @ended_on_newline = line.end_with?("\n")
- tokens << token
- return
- end
- end
- end
-
- @dedent_next = token.event == :on_tstring_content && embexpr_balance == 0
- @ended_on_newline = false
- tokens << token
- end
-
- def to_a
- # If every line in the heredoc is blank, we still need to split up the
- # string content token into multiple tokens.
- if dedent.nil?
- results = []
- embexpr_balance = 0
-
- tokens.each do |token|
- case token.event
- when :on_embexpr_beg, :on_heredoc_beg
- embexpr_balance += 1
- results << token
- when :on_embexpr_end, :on_heredoc_end
- embexpr_balance -= 1
- results << token
- when :on_tstring_content
- if embexpr_balance == 0
- lineno = token[0][0]
- column = token[0][1]
-
- token.value.split(/(?<=\n)/).each_with_index do |value, index|
- column = 0 if index > 0
- results << Token.new([[lineno, column], :on_tstring_content, value, token.state])
- lineno += 1
- end
- else
- results << token
- end
- else
- results << token
- end
- end
-
- return results
- end
-
- # If the minimum common whitespace is 0, then we need to concatenate
- # string nodes together that are immediately adjacent.
- if dedent == 0
- results = []
- embexpr_balance = 0
-
- index = 0
- max_index = tokens.length
-
- while index < max_index
- token = tokens[index]
- results << token
- index += 1
-
- case token.event
- when :on_embexpr_beg, :on_heredoc_beg
- embexpr_balance += 1
- when :on_embexpr_end, :on_heredoc_end
- embexpr_balance -= 1
- when :on_tstring_content
- if embexpr_balance == 0
- while index < max_index && tokens[index].event == :on_tstring_content
- token.value << tokens[index].value
- index += 1
- end
- end
- end
- end
-
- return results
- end
-
- # Otherwise, we're going to run through each token in the list and
- # insert on_ignored_sp tokens for the amount of dedent that we need to
- # perform. We also need to remove the dedent from the beginning of
- # each line of plain string content tokens.
- results = []
- dedent_next = true
- embexpr_balance = 0
-
- tokens.each do |token|
- # Notice that the structure of this conditional largely matches the
- # whitespace calculation we performed above. This is because
- # checking if the subsequent token needs to be dedented is common to
- # both the dedent calculation and the ignored_sp insertion.
- case token.event
- when :on_embexpr_beg
- embexpr_balance += 1
- results << token
- when :on_embexpr_end
- embexpr_balance -= 1
- results << token
- when :on_tstring_content
- if embexpr_balance == 0
- # Here we're going to split the string on newlines, but maintain
- # the newlines in the resulting array. We'll do that with a look
- # behind assertion.
- splits = token.value.split(/(?<=\n)/)
- index = 0
-
- while index < splits.length
- line = splits[index]
- lineno = token[0][0] + index
- column = token[0][1]
-
- # Blank lines do not count toward common leading whitespace
- # calculation and do not need to be dedented.
- if dedent_next || index > 0
- column = 0
- end
-
- # If the dedent is 0 and we're not supposed to dedent the next
- # line or this line doesn't start with whitespace, then we
- # should concatenate the rest of the string to match ripper.
- if dedent == 0 && (!dedent_next || !line.start_with?(/\s/))
- line = splits[index..].join
- index = splits.length
- end
-
- # If we are supposed to dedent this line or if this is not the
- # first line of the string and this line isn't entirely blank,
- # then we need to insert an on_ignored_sp token and remove the
- # dedent from the beginning of the line.
- if (dedent > 0) && (dedent_next || index > 0)
- deleting = 0
- deleted_chars = []
-
- # Gather up all of the characters that we're going to
- # delete, stopping when you hit a character that would put
- # you over the dedent amount.
- line.each_char.with_index do |char, i|
- case char
- when "\r"
- if line[i + 1] == "\n"
- break
- end
- when "\n"
- break
- when "\t"
- deleting = deleting - (deleting % TAB_WIDTH) + TAB_WIDTH
- else
- deleting += 1
- end
-
- break if deleting > dedent
- deleted_chars << char
- end
-
- # If we have something to delete, then delete it from the
- # string and insert an on_ignored_sp token.
- if deleted_chars.any?
- ignored = deleted_chars.join
- line.delete_prefix!(ignored)
-
- results << Token.new([[lineno, 0], :on_ignored_sp, ignored, token[3]])
- column = ignored.length
- end
- end
-
- results << Token.new([[lineno, column], token[1], line, token[3]]) unless line.empty?
- index += 1
- end
- else
- results << token
- end
- else
- results << token
- end
-
- dedent_next =
- ((token.event == :on_tstring_content) || (token.event == :on_heredoc_end)) &&
- embexpr_balance == 0
- end
-
- results
- end
- end
-
- # Here we will split between the two types of heredocs and return the
- # object that will store their tokens.
- def self.build(opening)
- case opening.value[2]
- when "~"
- DedentingHeredoc.new
- when "-"
- DashHeredoc.new(opening.value[3] != "'")
- else
- PlainHeredoc.new
- end
- end
- end
-
- private_constant :Heredoc
-
- attr_reader :source, :options
-
- def initialize(source, **options)
- @source = source
- @options = options
- end
-
- def result
- tokens = []
-
- state = :default
- heredoc_stack = [[]]
-
- result = Prism.lex(source, **options)
- result_value = result.value
- previous_state = nil
-
- # In previous versions of Ruby, Ripper wouldn't flush the bom before the
- # first token, so we had to have a hack in place to account for that. This
- # checks for that behavior.
- bom_flushed = Ripper.lex("\xEF\xBB\xBF# test")[0][0][1] == 0
- bom = source.byteslice(0..2) == "\xEF\xBB\xBF"
-
- result_value.each_with_index do |(token, lex_state), index|
- lineno = token.location.start_line
- column = token.location.start_column
-
- # If there's a UTF-8 byte-order mark as the start of the file, then for
- # certain tokens ripper sets the first token back by 3 bytes. It also
- # keeps the byte order mark in the first token's value. This is weird,
- # and I don't want to mirror that in our parser. So instead, we'll match
- # up the columns and values here.
- if bom && lineno == 1
- column -= 3
-
- if index == 0 && column == 0 && !bom_flushed
- flushed =
- case token.type
- when :BACK_REFERENCE, :INSTANCE_VARIABLE, :CLASS_VARIABLE,
- :GLOBAL_VARIABLE, :NUMBERED_REFERENCE, :PERCENT_LOWER_I,
- :PERCENT_LOWER_X, :PERCENT_LOWER_W, :PERCENT_UPPER_I,
- :PERCENT_UPPER_W, :STRING_BEGIN
- true
- when :REGEXP_BEGIN, :SYMBOL_BEGIN
- token.value.start_with?("%")
- else
- false
- end
-
- unless flushed
- column -= 3
- value = token.value
- value.prepend(String.new("\xEF\xBB\xBF", encoding: value.encoding))
- end
- end
- end
-
- event = RIPPER.fetch(token.type)
- value = token.value
- lex_state = Ripper::Lexer::State.new(lex_state)
-
- token =
- case event
- when :on___end__
- EndContentToken.new([[lineno, column], event, value, lex_state])
- when :on_comment
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
- when :on_heredoc_end
- # Heredoc end tokens can be emitted in an odd order, so we don't
- # want to bother comparing the state on them.
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
- when :on_ident
- if lex_state == Ripper::EXPR_END
- # If we have an identifier that follows a method name like:
- #
- # def foo bar
- #
- # then Ripper will mark bar as END|LABEL if there is a local in a
- # parent scope named bar because it hasn't pushed the local table
- # yet. We do this more accurately, so we need to allow comparing
- # against both END and END|LABEL.
- ParamToken.new([[lineno, column], event, value, lex_state])
- elsif lex_state == Ripper::EXPR_END | Ripper::EXPR_LABEL
- # In the event that we're comparing identifiers, we're going to
- # allow a little divergence. Ripper doesn't account for local
- # variables introduced through named captures in regexes, and we
- # do, which accounts for this difference.
- IdentToken.new([[lineno, column], event, value, lex_state])
- else
- Token.new([[lineno, column], event, value, lex_state])
- end
- when :on_embexpr_end
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
- when :on_ignored_nl
- # Ignored newlines can occasionally have a LABEL state attached to
- # them which doesn't actually impact anything. We don't mirror that
- # state so we ignored it.
- IgnoredNewlineToken.new([[lineno, column], event, value, lex_state])
- when :on_regexp_end
- # On regex end, Ripper scans and then sets end state, so the ripper
- # lexed output is begin, when it should be end. prism sets lex state
- # correctly to end state, but we want to be able to compare against
- # Ripper's lexed state. So here, if it's a regexp end token, we
- # output the state as the previous state, solely for the sake of
- # comparison.
- previous_token = result_value[index - 1][0]
- lex_state =
- if RIPPER.fetch(previous_token.type) == :on_embexpr_end
- # If the previous token is embexpr_end, then we have to do even
- # more processing. The end of an embedded expression sets the
- # state to the state that it had at the beginning of the
- # embedded expression. So we have to go and find that state and
- # set it here.
- counter = 1
- current_index = index - 1
-
- until counter == 0
- current_index -= 1
- current_event = RIPPER.fetch(result_value[current_index][0].type)
- counter += { on_embexpr_beg: -1, on_embexpr_end: 1 }[current_event] || 0
- end
-
- Ripper::Lexer::State.new(result_value[current_index][1])
- else
- previous_state
- end
-
- Token.new([[lineno, column], event, value, lex_state])
- when :on_eof
- previous_token = result_value[index - 1][0]
-
- # If we're at the end of the file and the previous token was a
- # comment and there is still whitespace after the comment, then
- # Ripper will append a on_nl token (even though there isn't
- # necessarily a newline). We mirror that here.
- start_offset = previous_token.location.end_offset
- end_offset = token.location.start_offset
-
- if previous_token.type == :COMMENT && start_offset < end_offset
- if bom
- start_offset += 3
- end_offset += 3
- end
-
- tokens << Token.new([[lineno, 0], :on_nl, source.byteslice(start_offset...end_offset), lex_state])
- end
-
- Token.new([[lineno, column], event, value, lex_state])
- else
- Token.new([[lineno, column], event, value, lex_state])
- end
-
- previous_state = lex_state
-
- # The order in which tokens appear in our lexer is different from the
- # order that they appear in Ripper. When we hit the declaration of a
- # heredoc in prism, we skip forward and lex the rest of the content of
- # the heredoc before going back and lexing at the end of the heredoc
- # identifier.
- #
- # To match up to ripper, we keep a small state variable around here to
- # track whether we're in the middle of a heredoc or not. In this way we
- # can shuffle around the token to match Ripper's output.
- case state
- when :default
- # The default state is when there are no heredocs at all. In this
- # state we can append the token to the list of tokens and move on.
- tokens << token
-
- # If we get the declaration of a heredoc, then we open a new heredoc
- # and move into the heredoc_opened state.
- if event == :on_heredoc_beg
- state = :heredoc_opened
- heredoc_stack.last << Heredoc.build(token)
- end
- when :heredoc_opened
- # The heredoc_opened state is when we've seen the declaration of a
- # heredoc and are now lexing the body of the heredoc. In this state we
- # push tokens onto the most recently created heredoc.
- heredoc_stack.last.last << token
-
- case event
- when :on_heredoc_beg
- # If we receive a heredoc declaration while lexing the body of a
- # heredoc, this means we have nested heredocs. In this case we'll
- # push a new heredoc onto the stack and stay in the heredoc_opened
- # state since we're now lexing the body of the new heredoc.
- heredoc_stack << [Heredoc.build(token)]
- when :on_heredoc_end
- # If we receive the end of a heredoc, then we're done lexing the
- # body of the heredoc. In this case we now have a completed heredoc
- # but need to wait for the next newline to push it into the token
- # stream.
- state = :heredoc_closed
- end
- when :heredoc_closed
- if %i[on_nl on_ignored_nl on_comment].include?(event) || (event == :on_tstring_content && value.end_with?("\n"))
- if heredoc_stack.size > 1
- flushing = heredoc_stack.pop
- heredoc_stack.last.last << token
-
- flushing.each do |heredoc|
- heredoc.to_a.each do |flushed_token|
- heredoc_stack.last.last << flushed_token
- end
- end
-
- state = :heredoc_opened
- next
- end
- elsif event == :on_heredoc_beg
- tokens << token
- state = :heredoc_opened
- heredoc_stack.last << Heredoc.build(token)
- next
- elsif heredoc_stack.size > 1
- heredoc_stack[-2].last << token
- next
- end
-
- heredoc_stack.last.each do |heredoc|
- tokens.concat(heredoc.to_a)
- end
-
- heredoc_stack.last.clear
- state = :default
-
- tokens << token
- end
- end
-
- # Drop the EOF token from the list
- tokens = tokens[0...-1]
-
- # We sort by location to compare against Ripper's output
- tokens.sort_by!(&:location)
-
- ParseResult.new(tokens, result.comments, result.magic_comments, result.errors, result.warnings, [])
- end
- end
-
- private_constant :LexCompat
-
- # This is a class that wraps the Ripper lexer to produce almost exactly the
- # same tokens.
- class LexRipper # :nodoc:
- attr_reader :source
-
- def initialize(source)
- @source = source
- end
-
- def result
- previous = []
- results = []
-
- Ripper.lex(source, raise_errors: true).each do |token|
- case token[1]
- when :on_sp
- # skip
- when :on_tstring_content
- if previous[1] == :on_tstring_content && (token[2].start_with?("\#$") || token[2].start_with?("\#@"))
- previous[2] << token[2]
- else
- results << token
- previous = token
- end
- when :on_words_sep
- if previous[1] == :on_words_sep
- previous[2] << token[2]
- else
- results << token
- previous = token
- end
- else
- results << token
- previous = token
- end
- end
-
- results
- end
- end
-
- private_constant :LexRipper
-end
diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb
deleted file mode 100644
index 4febc615c1..0000000000
--- a/lib/prism/node_ext.rb
+++ /dev/null
@@ -1,152 +0,0 @@
-# frozen_string_literal: true
-
-# Here we are reopening the prism module to provide methods on nodes that aren't
-# templated and are meant as convenience methods.
-module Prism
- module RegularExpressionOptions # :nodoc:
- # Returns a numeric value that represents the flags that were used to create
- # the regular expression.
- def options
- o = flags & (RegularExpressionFlags::IGNORE_CASE | RegularExpressionFlags::EXTENDED | RegularExpressionFlags::MULTI_LINE)
- o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
- o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
- o
- end
- end
-
- private_constant :RegularExpressionOptions
-
- class FloatNode < Node
- # Returns the value of the node as a Ruby Float.
- def value
- Float(slice)
- end
- end
-
- class ImaginaryNode < Node
- # Returns the value of the node as a Ruby Complex.
- def value
- Complex(0, numeric.value)
- end
- end
-
- class IntegerNode < Node
- # Returns the value of the node as a Ruby Integer.
- def value
- Integer(slice)
- end
- end
-
- class InterpolatedMatchLastLineNode < Node
- include RegularExpressionOptions
- end
-
- class InterpolatedRegularExpressionNode < Node
- include RegularExpressionOptions
- end
-
- class MatchLastLineNode < Node
- include RegularExpressionOptions
- end
-
- class RationalNode < Node
- # Returns the value of the node as a Ruby Rational.
- def value
- Rational(slice.chomp("r"))
- end
- end
-
- class RegularExpressionNode < Node
- include RegularExpressionOptions
- end
-
- class ConstantReadNode < Node
- # Returns the list of parts for the full name of this constant.
- # For example: [:Foo]
- def full_name_parts
- [name]
- end
-
- # Returns the full name of this constant. For example: "Foo"
- def full_name
- name.name
- end
- end
-
- class ConstantPathNode < Node
- # Returns the list of parts for the full name of this constant path.
- # For example: [:Foo, :Bar]
- def full_name_parts
- parts = [child.name]
- current = parent
-
- while current.is_a?(ConstantPathNode)
- parts.unshift(current.child.name)
- current = current.parent
- end
-
- parts.unshift(current&.name || :"")
- end
-
- # Returns the full name of this constant path. For example: "Foo::Bar"
- def full_name
- full_name_parts.join("::")
- end
- end
-
- class ConstantPathTargetNode < Node
- # Returns the list of parts for the full name of this constant path.
- # For example: [:Foo, :Bar]
- def full_name_parts
- (parent&.full_name_parts || [:""]).push(child.name)
- end
-
- # Returns the full name of this constant path. For example: "Foo::Bar"
- def full_name
- full_name_parts.join("::")
- end
- end
-
- class ParametersNode < Node
- # Mirrors the Method#parameters method.
- def signature
- names = []
-
- requireds.each do |param|
- names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
- end
-
- optionals.each { |param| names << [:opt, param.name] }
- names << [:rest, rest.name || :*] if rest
-
- posts.each do |param|
- names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
- end
-
- # Regardless of the order in which the keywords were defined, the required
- # keywords always come first followed by the optional keywords.
- keyopt = []
- keywords.each do |param|
- if param.is_a?(OptionalKeywordParameterNode)
- keyopt << param
- else
- names << [:keyreq, param.name]
- end
- end
-
- keyopt.each { |param| names << [:key, param.name] }
-
- case keyword_rest
- when ForwardingParameterNode
- names.concat([[:rest, :*], [:keyrest, :**], [:block, :&]])
- when KeywordRestParameterNode
- names << [:keyrest, keyword_rest.name || :**]
- when NoKeywordsParameterNode
- names << [:nokey]
- end
-
- names << [:block, block.name || :&] if block
- names
- end
- end
-end
diff --git a/lib/prism/node_inspector.rb b/lib/prism/node_inspector.rb
deleted file mode 100644
index d77af33c3a..0000000000
--- a/lib/prism/node_inspector.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # This object is responsible for generating the output for the inspect method
- # implementations of child nodes.
- class NodeInspector # :nodoc:
- attr_reader :prefix, :output
-
- def initialize(prefix = "")
- @prefix = prefix
- @output = +""
- end
-
- # Appends a line to the output with the current prefix.
- def <<(line)
- output << "#{prefix}#{line}"
- end
-
- # This generates a string that is used as the header of the inspect output
- # for any given node.
- def header(node)
- output = +"@ #{node.class.name.split("::").last} ("
- output << "location: (#{node.location.start_line},#{node.location.start_column})-(#{node.location.end_line},#{node.location.end_column})"
- output << ", newline: true" if node.newline?
- output << ")\n"
- output
- end
-
- # Generates a string that represents a list of nodes. It handles properly
- # using the box drawing characters to make the output look nice.
- def list(prefix, nodes)
- output = +"(length: #{nodes.length})\n"
- last_index = nodes.length - 1
-
- nodes.each_with_index do |node, index|
- pointer, preadd = (index == last_index) ? ["└── ", " "] : ["├── ", "│ "]
- node_prefix = "#{prefix}#{preadd}"
- output << node.inspect(NodeInspector.new(node_prefix)).sub(node_prefix, "#{prefix}#{pointer}")
- end
-
- output
- end
-
- # Generates a string that represents a location field on a node.
- def location(value)
- if value
- "(#{value.start_line},#{value.start_column})-(#{value.end_line},#{value.end_column}) = #{value.slice.inspect}"
- else
- "∅"
- end
- end
-
- # Generates a string that represents a child node.
- def child_node(node, append)
- node.inspect(child_inspector(append)).delete_prefix(prefix)
- end
-
- # Returns a new inspector that can be used to inspect a child node.
- def child_inspector(append)
- NodeInspector.new("#{prefix}#{append}")
- end
-
- # Returns the output as a string.
- def to_str
- output
- end
- end
-end
diff --git a/lib/prism/pack.rb b/lib/prism/pack.rb
deleted file mode 100644
index 00caf553c6..0000000000
--- a/lib/prism/pack.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # A parser for the pack template language.
- module Pack
- %i[
- SPACE
- COMMENT
- INTEGER
- UTF8
- BER
- FLOAT
- STRING_SPACE_PADDED
- STRING_NULL_PADDED
- STRING_NULL_TERMINATED
- STRING_MSB
- STRING_LSB
- STRING_HEX_HIGH
- STRING_HEX_LOW
- STRING_UU
- STRING_MIME
- STRING_BASE64
- STRING_FIXED
- STRING_POINTER
- MOVE
- BACK
- NULL
-
- UNSIGNED
- SIGNED
- SIGNED_NA
-
- AGNOSTIC_ENDIAN
- LITTLE_ENDIAN
- BIG_ENDIAN
- NATIVE_ENDIAN
- ENDIAN_NA
-
- SIZE_SHORT
- SIZE_INT
- SIZE_LONG
- SIZE_LONG_LONG
- SIZE_8
- SIZE_16
- SIZE_32
- SIZE_64
- SIZE_P
- SIZE_NA
-
- LENGTH_FIXED
- LENGTH_MAX
- LENGTH_RELATIVE
- LENGTH_NA
- ].each do |const|
- const_set(const, const)
- end
-
- # A directive in the pack template language.
- class Directive
- # A symbol representing the version of Ruby.
- attr_reader :version
-
- # A symbol representing whether or not we are packing or unpacking.
- attr_reader :variant
-
- # A byteslice of the source string that this directive represents.
- attr_reader :source
-
- # The type of the directive.
- attr_reader :type
-
- # The type of signedness of the directive.
- attr_reader :signed
-
- # The type of endianness of the directive.
- attr_reader :endian
-
- # The size of the directive.
- attr_reader :size
-
- # The length type of this directive (used for integers).
- attr_reader :length_type
-
- # The length of this directive (used for integers).
- attr_reader :length
-
- # Initialize a new directive with the given values.
- def initialize(version, variant, source, type, signed, endian, size, length_type, length)
- @version = version
- @variant = variant
- @source = source
- @type = type
- @signed = signed
- @endian = endian
- @size = size
- @length_type = length_type
- @length = length
- end
-
- # The descriptions of the various types of endianness.
- ENDIAN_DESCRIPTIONS = {
- AGNOSTIC_ENDIAN: "agnostic",
- LITTLE_ENDIAN: "little-endian (VAX)",
- BIG_ENDIAN: "big-endian (network)",
- NATIVE_ENDIAN: "native-endian",
- ENDIAN_NA: "n/a"
- }
-
- # The descriptions of the various types of signedness.
- SIGNED_DESCRIPTIONS = {
- UNSIGNED: "unsigned",
- SIGNED: "signed",
- SIGNED_NA: "n/a"
- }
-
- # The descriptions of the various types of sizes.
- SIZE_DESCRIPTIONS = {
- SIZE_SHORT: "short",
- SIZE_INT: "int-width",
- SIZE_LONG: "long",
- SIZE_LONG_LONG: "long long",
- SIZE_8: "8-bit",
- SIZE_16: "16-bit",
- SIZE_32: "32-bit",
- SIZE_64: "64-bit",
- SIZE_P: "pointer-width"
- }
-
- # Provide a human-readable description of the directive.
- def describe
- case type
- when SPACE
- "whitespace"
- when COMMENT
- "comment"
- when INTEGER
- if size == SIZE_8
- base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} integer"
- else
- base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} integer"
- end
- case length_type
- when LENGTH_FIXED
- if length > 1
- base + ", x#{length}"
- else
- base
- end
- when LENGTH_MAX
- base + ", as many as possible"
- end
- when UTF8
- "UTF-8 character"
- when BER
- "BER-compressed integer"
- when FLOAT
- "#{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} float"
- when STRING_SPACE_PADDED
- "arbitrary binary string (space padded)"
- when STRING_NULL_PADDED
- "arbitrary binary string (null padded, count is width)"
- when STRING_NULL_TERMINATED
- "arbitrary binary string (null padded, count is width), except that null is added with *"
- when STRING_MSB
- "bit string (MSB first)"
- when STRING_LSB
- "bit string (LSB first)"
- when STRING_HEX_HIGH
- "hex string (high nibble first)"
- when STRING_HEX_LOW
- "hex string (low nibble first)"
- when STRING_UU
- "UU-encoded string"
- when STRING_MIME
- "quoted printable, MIME encoding"
- when STRING_BASE64
- "base64 encoded string"
- when STRING_FIXED
- "pointer to a structure (fixed-length string)"
- when STRING_POINTER
- "pointer to a null-terminated string"
- when MOVE
- "move to absolute position"
- when BACK
- "back up a byte"
- when NULL
- "null byte"
- else
- raise
- end
- end
- end
-
- # The result of parsing a pack template.
- class Format
- # A list of the directives in the template.
- attr_reader :directives
-
- # The encoding of the template.
- attr_reader :encoding
-
- # Create a new Format with the given directives and encoding.
- def initialize(directives, encoding)
- @directives = directives
- @encoding = encoding
- end
-
- # Provide a human-readable description of the format.
- def describe
- source_width = directives.map { |d| d.source.inspect.length }.max
- directive_lines = directives.map do |directive|
- if directive.type == SPACE
- source = directive.source.inspect
- else
- source = directive.source
- end
- " #{source.ljust(source_width)} #{directive.describe}"
- end
-
- (["Directives:"] + directive_lines + ["Encoding:", " #{encoding}"]).join("\n")
- end
- end
- end
-end
diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb
deleted file mode 100644
index 170a529bea..0000000000
--- a/lib/prism/parse_result.rb
+++ /dev/null
@@ -1,429 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # This represents a source of Ruby code that has been parsed. It is used in
- # conjunction with locations to allow them to resolve line numbers and source
- # ranges.
- class Source
- # The source code that this source object represents.
- attr_reader :source
-
- # The line number where this source starts.
- attr_accessor :start_line
-
- # The list of newline byte offsets in the source code.
- attr_reader :offsets
-
- # Create a new source object with the given source code and newline byte
- # offsets. If no newline byte offsets are given, they will be computed from
- # the source code.
- def initialize(source, start_line = 1, offsets = compute_offsets(source))
- @source = source
- @start_line = start_line
- @offsets = offsets
- end
-
- # Perform a byteslice on the source code using the given byte offset and
- # byte length.
- def slice(offset, length)
- source.byteslice(offset, length)
- end
-
- # Binary search through the offsets to find the line number for the given
- # byte offset.
- def line(value)
- start_line + find_line(value)
- end
-
- # Return the byte offset of the start of the line corresponding to the given
- # byte offset.
- def line_offset(value)
- offsets[find_line(value)]
- end
-
- # Return the column number for the given byte offset.
- def column(value)
- value - offsets[find_line(value)]
- end
-
- private
-
- # Binary search through the offsets to find the line number for the given
- # byte offset.
- def find_line(value)
- left = 0
- right = offsets.length - 1
-
- while left <= right
- mid = left + (right - left) / 2
- return mid if offsets[mid] == value
-
- if offsets[mid] < value
- left = mid + 1
- else
- right = mid - 1
- end
- end
-
- left - 1
- end
-
- # Find all of the newlines in the source code and return their byte offsets
- # from the start of the string an array.
- def compute_offsets(code)
- offsets = [0]
- code.b.scan("\n") { offsets << $~.end(0) }
- offsets
- end
- end
-
- # This represents a location in the source.
- class Location
- # A Source object that is used to determine more information from the given
- # offset and length.
- protected attr_reader :source
-
- # The byte offset from the beginning of the source where this location
- # starts.
- attr_reader :start_offset
-
- # The length of this location in bytes.
- attr_reader :length
-
- # The list of comments attached to this location
- attr_reader :comments
-
- # Create a new location object with the given source, start byte offset, and
- # byte length.
- def initialize(source, start_offset, length)
- @source = source
- @start_offset = start_offset
- @length = length
- @comments = []
- end
-
- # Create a new location object with the given options.
- def copy(**options)
- Location.new(
- options.fetch(:source) { source },
- options.fetch(:start_offset) { start_offset },
- options.fetch(:length) { length }
- )
- end
-
- # Returns a string representation of this location.
- def inspect
- "#<Prism::Location @start_offset=#{@start_offset} @length=#{@length} start_line=#{start_line}>"
- end
-
- # The source code that this location represents.
- def slice
- source.slice(start_offset, length)
- end
-
- # The byte offset from the beginning of the source where this location ends.
- def end_offset
- start_offset + length
- end
-
- # The line number where this location starts.
- def start_line
- source.line(start_offset)
- end
-
- # The content of the line where this location starts before this location.
- def start_line_slice
- offset = source.line_offset(start_offset)
- source.slice(offset, start_offset - offset)
- end
-
- # The line number where this location ends.
- def end_line
- source.line(end_offset)
- end
-
- # The column number in bytes where this location starts from the start of
- # the line.
- def start_column
- source.column(start_offset)
- end
-
- # The column number in bytes where this location ends from the start of the
- # line.
- def end_column
- source.column(end_offset)
- end
-
- # Implement the hash pattern matching interface for Location.
- def deconstruct_keys(keys)
- { start_offset: start_offset, end_offset: end_offset }
- end
-
- # Implement the pretty print interface for Location.
- def pretty_print(q)
- q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column})")
- end
-
- # Returns true if the given other location is equal to this location.
- def ==(other)
- other.is_a?(Location) &&
- other.start_offset == start_offset &&
- other.end_offset == end_offset
- end
-
- # Returns a new location that stretches from this location to the given
- # other location. Raises an error if this location is not before the other
- # location or if they don't share the same source.
- def join(other)
- raise "Incompatible sources" if source != other.source
- raise "Incompatible locations" if start_offset > other.start_offset
-
- Location.new(source, start_offset, other.end_offset - start_offset)
- end
-
- # Returns a null location that does not correspond to a source and points to
- # the beginning of the file. Useful for when you want a location object but
- # do not care where it points.
- def self.null
- new(nil, 0, 0)
- end
- end
-
- # This represents a comment that was encountered during parsing. It is the
- # base class for all comment types.
- class Comment
- # The location of this comment in the source.
- attr_reader :location
-
- # Create a new comment object with the given location.
- def initialize(location)
- @location = location
- end
-
- # Implement the hash pattern matching interface for Comment.
- def deconstruct_keys(keys)
- { location: location }
- end
-
- # This can only be true for inline comments.
- def trailing?
- false
- end
- end
-
- # InlineComment objects are the most common. They correspond to comments in
- # the source file like this one that start with #.
- class InlineComment < Comment
- # Returns true if this comment happens on the same line as other code and
- # false if the comment is by itself.
- def trailing?
- !location.start_line_slice.strip.empty?
- end
-
- # Returns a string representation of this comment.
- def inspect
- "#<Prism::InlineComment @location=#{location.inspect}>"
- end
- end
-
- # EmbDocComment objects correspond to comments that are surrounded by =begin
- # and =end.
- class EmbDocComment < Comment
- # Returns a string representation of this comment.
- def inspect
- "#<Prism::EmbDocComment @location=#{location.inspect}>"
- end
- end
-
- # DATAComment objects correspond to comments that are after the __END__
- # keyword in a source file.
- class DATAComment < Comment
- # Returns a string representation of this comment.
- def inspect
- "#<Prism::DATAComment @location=#{location.inspect}>"
- end
- end
-
- # This represents a magic comment that was encountered during parsing.
- class MagicComment
- # A Location object representing the location of the key in the source.
- attr_reader :key_loc
-
- # A Location object representing the location of the value in the source.
- attr_reader :value_loc
-
- # Create a new magic comment object with the given key and value locations.
- def initialize(key_loc, value_loc)
- @key_loc = key_loc
- @value_loc = value_loc
- end
-
- # Returns the key of the magic comment by slicing it from the source code.
- def key
- key_loc.slice
- end
-
- # Returns the value of the magic comment by slicing it from the source code.
- def value
- value_loc.slice
- end
-
- # Implement the hash pattern matching interface for MagicComment.
- def deconstruct_keys(keys)
- { key_loc: key_loc, value_loc: value_loc }
- end
-
- # Returns a string representation of this magic comment.
- def inspect
- "#<Prism::MagicComment @key=#{key.inspect} @value=#{value.inspect}>"
- end
- end
-
- # This represents an error that was encountered during parsing.
- class ParseError
- # The message associated with this error.
- attr_reader :message
-
- # A Location object representing the location of this error in the source.
- attr_reader :location
-
- # Create a new error object with the given message and location.
- def initialize(message, location)
- @message = message
- @location = location
- end
-
- # Implement the hash pattern matching interface for ParseError.
- def deconstruct_keys(keys)
- { message: message, location: location }
- end
-
- # Returns a string representation of this error.
- def inspect
- "#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"
- end
- end
-
- # This represents a warning that was encountered during parsing.
- class ParseWarning
- # The message associated with this warning.
- attr_reader :message
-
- # A Location object representing the location of this warning in the source.
- attr_reader :location
-
- # Create a new warning object with the given message and location.
- def initialize(message, location)
- @message = message
- @location = location
- end
-
- # Implement the hash pattern matching interface for ParseWarning.
- def deconstruct_keys(keys)
- { message: message, location: location }
- end
-
- # Returns a string representation of this warning.
- def inspect
- "#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"
- end
- end
-
- # This represents the result of a call to ::parse or ::parse_file. It contains
- # the AST, any comments that were encounters, and any errors that were
- # encountered.
- class ParseResult
- # The value that was generated by parsing. Normally this holds the AST, but
- # it can sometimes how a list of tokens or other results passed back from
- # the parser.
- attr_reader :value
-
- # The list of comments that were encountered during parsing.
- attr_reader :comments
-
- # The list of magic comments that were encountered during parsing.
- attr_reader :magic_comments
-
- # The list of errors that were generated during parsing.
- attr_reader :errors
-
- # The list of warnings that were generated during parsing.
- attr_reader :warnings
-
- # A Source instance that represents the source code that was parsed.
- attr_reader :source
-
- # Create a new parse result object with the given values.
- def initialize(value, comments, magic_comments, errors, warnings, source)
- @value = value
- @comments = comments
- @magic_comments = magic_comments
- @errors = errors
- @warnings = warnings
- @source = source
- end
-
- # Implement the hash pattern matching interface for ParseResult.
- def deconstruct_keys(keys)
- { value: value, comments: comments, magic_comments: magic_comments, errors: errors, warnings: warnings }
- end
-
- # Returns true if there were no errors during parsing and false if there
- # were.
- def success?
- errors.empty?
- end
-
- # Returns true if there were errors during parsing and false if there were
- # not.
- def failure?
- !success?
- end
- end
-
- # This represents a token from the Ruby source.
- class Token
- # The type of token that this token is.
- attr_reader :type
-
- # A byteslice of the source that this token represents.
- attr_reader :value
-
- # A Location object representing the location of this token in the source.
- attr_reader :location
-
- # Create a new token object with the given type, value, and location.
- def initialize(type, value, location)
- @type = type
- @value = value
- @location = location
- end
-
- # Implement the hash pattern matching interface for Token.
- def deconstruct_keys(keys)
- { type: type, value: value, location: location }
- end
-
- # Implement the pretty print interface for Token.
- def pretty_print(q)
- q.group do
- q.text(type.to_s)
- self.location.pretty_print(q)
- q.text("(")
- q.nest(2) do
- q.breakable("")
- q.pp(value)
- end
- q.breakable("")
- q.text(")")
- end
- end
-
- # Returns true if the given other token is equal to this token.
- def ==(other)
- other.is_a?(Token) &&
- other.type == type &&
- other.value == value
- end
- end
-end
diff --git a/lib/prism/parse_result/comments.rb b/lib/prism/parse_result/comments.rb
deleted file mode 100644
index 7a3a47de50..0000000000
--- a/lib/prism/parse_result/comments.rb
+++ /dev/null
@@ -1,177 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- class ParseResult
- # When we've parsed the source, we have both the syntax tree and the list of
- # comments that we found in the source. This class is responsible for
- # walking the tree and finding the nearest location to attach each comment.
- #
- # It does this by first finding the nearest locations to each comment.
- # Locations can either come from nodes directly or from location fields on
- # nodes. For example, a `ClassNode` has an overall location encompassing the
- # entire class, but it also has a location for the `class` keyword.
- #
- # Once the nearest locations are found, it determines which one to attach
- # to. If it's a trailing comment (a comment on the same line as other source
- # code), it will favor attaching to the nearest location that occurs before
- # the comment. Otherwise it will favor attaching to the nearest location
- # that is after the comment.
- class Comments
- # A target for attaching comments that is based on a specific node's
- # location.
- class NodeTarget # :nodoc:
- attr_reader :node
-
- def initialize(node)
- @node = node
- end
-
- def start_offset
- node.location.start_offset
- end
-
- def end_offset
- node.location.end_offset
- end
-
- def encloses?(comment)
- start_offset <= comment.location.start_offset &&
- comment.location.end_offset <= end_offset
- end
-
- def <<(comment)
- node.location.comments << comment
- end
- end
-
- # A target for attaching comments that is based on a location field on a
- # node. For example, the `end` token of a ClassNode.
- class LocationTarget # :nodoc:
- attr_reader :location
-
- def initialize(location)
- @location = location
- end
-
- def start_offset
- location.start_offset
- end
-
- def end_offset
- location.end_offset
- end
-
- def encloses?(comment)
- false
- end
-
- def <<(comment)
- location.comments << comment
- end
- end
-
- # The parse result that we are attaching comments to.
- attr_reader :parse_result
-
- # Create a new Comments object that will attach comments to the given
- # parse result.
- def initialize(parse_result)
- @parse_result = parse_result
- end
-
- # Attach the comments to their respective locations in the tree by
- # mutating the parse result.
- def attach!
- parse_result.comments.each do |comment|
- preceding, enclosing, following = nearest_targets(parse_result.value, comment)
- target =
- if comment.trailing?
- preceding || following || enclosing || NodeTarget.new(parse_result.value)
- else
- # If a comment exists on its own line, prefer a leading comment.
- following || preceding || enclosing || NodeTarget.new(parse_result.value)
- end
-
- target << comment
- end
- end
-
- private
-
- # Responsible for finding the nearest targets to the given comment within
- # the context of the given encapsulating node.
- def nearest_targets(node, comment)
- comment_start = comment.location.start_offset
- comment_end = comment.location.end_offset
-
- targets = []
- node.comment_targets.map do |value|
- case value
- when StatementsNode
- targets.concat(value.body.map { |node| NodeTarget.new(node) })
- when Node
- targets << NodeTarget.new(value)
- when Location
- targets << LocationTarget.new(value)
- end
- end
-
- targets.sort_by!(&:start_offset)
- preceding = nil
- following = nil
-
- left = 0
- right = targets.length
-
- # This is a custom binary search that finds the nearest nodes to the
- # given comment. When it finds a node that completely encapsulates the
- # comment, it recurses downward into the tree.
- while left < right
- middle = (left + right) / 2
- target = targets[middle]
-
- target_start = target.start_offset
- target_end = target.end_offset
-
- if target.encloses?(comment)
- # The comment is completely contained by this target. Abandon the
- # binary search at this level.
- return nearest_targets(target.node, comment)
- end
-
- if target_end <= comment_start
- # This target falls completely before the comment. Because we will
- # never consider this target or any targets before it again, this
- # target must be the closest preceding target we have encountered so
- # far.
- preceding = target
- left = middle + 1
- next
- end
-
- if comment_end <= target_start
- # This target falls completely after the comment. Because we will
- # never consider this target or any targets after it again, this
- # target must be the closest following target we have encountered so
- # far.
- following = target
- right = middle
- next
- end
-
- # This should only happen if there is a bug in this parser.
- raise "Comment location overlaps with a target location"
- end
-
- [preceding, NodeTarget.new(node), following]
- end
- end
-
- private_constant :Comments
-
- # Attach the list of comments to their respective locations in the tree.
- def attach_comments!
- Comments.new(self).attach!
- end
- end
-end
diff --git a/lib/prism/parse_result/newlines.rb b/lib/prism/parse_result/newlines.rb
deleted file mode 100644
index ca05f5b702..0000000000
--- a/lib/prism/parse_result/newlines.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- class ParseResult
- # The :line tracepoint event gets fired whenever the Ruby VM encounters an
- # expression on a new line. The types of expressions that can trigger this
- # event are:
- #
- # * if statements
- # * unless statements
- # * nodes that are children of statements lists
- #
- # In order to keep track of the newlines, we have a list of offsets that
- # come back from the parser. We assign these offsets to the first nodes that
- # we find in the tree that are on those lines.
- #
- # Note that the logic in this file should be kept in sync with the Java
- # MarkNewlinesVisitor, since that visitor is responsible for marking the
- # newlines for JRuby/TruffleRuby.
- class Newlines < Visitor
- # Create a new Newlines visitor with the given newline offsets.
- def initialize(newline_marked)
- @newline_marked = newline_marked
- end
-
- # Permit block/lambda nodes to mark newlines within themselves.
- def visit_block_node(node)
- old_newline_marked = @newline_marked
- @newline_marked = Array.new(old_newline_marked.size, false)
-
- begin
- super(node)
- ensure
- @newline_marked = old_newline_marked
- end
- end
-
- alias_method :visit_lambda_node, :visit_block_node
-
- # Mark if/unless nodes as newlines.
- def visit_if_node(node)
- node.set_newline_flag(@newline_marked)
- super(node)
- end
-
- alias_method :visit_unless_node, :visit_if_node
-
- # Permit statements lists to mark newlines within themselves.
- def visit_statements_node(node)
- node.body.each do |child|
- child.set_newline_flag(@newline_marked)
- end
- super(node)
- end
- end
-
- private_constant :Newlines
-
- # Walk the tree and mark nodes that are on a new line.
- def mark_newlines!
- value.accept(Newlines.new(Array.new(1 + source.offsets.size, false)))
- end
- end
-end
diff --git a/lib/prism/pattern.rb b/lib/prism/pattern.rb
deleted file mode 100644
index e1643671ec..0000000000
--- a/lib/prism/pattern.rb
+++ /dev/null
@@ -1,250 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # A pattern is an object that wraps a Ruby pattern matching expression. The
- # expression would normally be passed to an `in` clause within a `case`
- # expression or a rightward assignment expression. For example, in the
- # following snippet:
- #
- # case node
- # in ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]
- # end
- #
- # the pattern is the <tt>ConstantPathNode[...]</tt> expression.
- #
- # The pattern gets compiled into an object that responds to #call by running
- # the #compile method. This method itself will run back through Prism to
- # parse the expression into a tree, then walk the tree to generate the
- # necessary callable objects. For example, if you wanted to compile the
- # expression above into a callable, you would:
- #
- # callable = Prism::Pattern.new("ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]").compile
- # callable.call(node)
- #
- # The callable object returned by #compile is guaranteed to respond to #call
- # with a single argument, which is the node to match against. It also is
- # guaranteed to respond to #===, which means it itself can be used in a `case`
- # expression, as in:
- #
- # case node
- # when callable
- # end
- #
- # If the query given to the initializer cannot be compiled into a valid
- # matcher (either because of a syntax error or because it is using syntax we
- # do not yet support) then a Prism::Pattern::CompilationError will be
- # raised.
- class Pattern
- # Raised when the query given to a pattern is either invalid Ruby syntax or
- # is using syntax that we don't yet support.
- class CompilationError < StandardError
- # Create a new CompilationError with the given representation of the node
- # that caused the error.
- def initialize(repr)
- super(<<~ERROR)
- prism was unable to compile the pattern you provided into a usable
- expression. It failed on to understand the node represented by:
-
- #{repr}
-
- Note that not all syntax supported by Ruby's pattern matching syntax
- is also supported by prism's patterns. If you're using some syntax
- that you believe should be supported, please open an issue on
- GitHub at https://github.com/ruby/prism/issues/new.
- ERROR
- end
- end
-
- # The query that this pattern was initialized with.
- attr_reader :query
-
- # Create a new pattern with the given query. The query should be a string
- # containing a Ruby pattern matching expression.
- def initialize(query)
- @query = query
- @compiled = nil
- end
-
- # Compile the query into a callable object that can be used to match against
- # nodes.
- def compile
- result = Prism.parse("case nil\nin #{query}\nend")
- compile_node(result.value.statements.body.last.conditions.last.pattern)
- end
-
- # Scan the given node and all of its children for nodes that match the
- # pattern. If a block is given, it will be called with each node that
- # matches the pattern. If no block is given, an enumerator will be returned
- # that will yield each node that matches the pattern.
- def scan(root)
- return to_enum(__method__, root) unless block_given?
-
- @compiled ||= compile
- queue = [root]
-
- while (node = queue.shift)
- yield node if @compiled.call(node)
- queue.concat(node.compact_child_nodes)
- end
- end
-
- private
-
- # Shortcut for combining two procs into one that returns true if both return
- # true.
- def combine_and(left, right)
- ->(other) { left.call(other) && right.call(other) }
- end
-
- # Shortcut for combining two procs into one that returns true if either
- # returns true.
- def combine_or(left, right)
- ->(other) { left.call(other) || right.call(other) }
- end
-
- # Raise an error because the given node is not supported.
- def compile_error(node)
- raise CompilationError, node.inspect
- end
-
- # in [foo, bar, baz]
- def compile_array_pattern_node(node)
- compile_error(node) if !node.rest.nil? || node.posts.any?
-
- constant = node.constant
- compiled_constant = compile_node(constant) if constant
-
- preprocessed = node.requireds.map { |required| compile_node(required) }
-
- compiled_requireds = ->(other) do
- deconstructed = other.deconstruct
-
- deconstructed.length == preprocessed.length &&
- preprocessed
- .zip(deconstructed)
- .all? { |(matcher, value)| matcher.call(value) }
- end
-
- if compiled_constant
- combine_and(compiled_constant, compiled_requireds)
- else
- compiled_requireds
- end
- end
-
- # in foo | bar
- def compile_alternation_pattern_node(node)
- combine_or(compile_node(node.left), compile_node(node.right))
- end
-
- # in Prism::ConstantReadNode
- def compile_constant_path_node(node)
- parent = node.parent
-
- if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
- compile_node(node.child)
- else
- compile_error(node)
- end
- end
-
- # in ConstantReadNode
- # in String
- def compile_constant_read_node(node)
- value = node.slice
-
- if Prism.const_defined?(value, false)
- clazz = Prism.const_get(value)
-
- ->(other) { clazz === other }
- elsif Object.const_defined?(value, false)
- clazz = Object.const_get(value)
-
- ->(other) { clazz === other }
- else
- compile_error(node)
- end
- end
-
- # in InstanceVariableReadNode[name: Symbol]
- # in { name: Symbol }
- def compile_hash_pattern_node(node)
- compile_error(node) if node.rest
- compiled_constant = compile_node(node.constant) if node.constant
-
- preprocessed =
- node.elements.to_h do |element|
- [element.key.unescaped.to_sym, compile_node(element.value)]
- end
-
- compiled_keywords = ->(other) do
- deconstructed = other.deconstruct_keys(preprocessed.keys)
-
- preprocessed.all? do |keyword, matcher|
- deconstructed.key?(keyword) && matcher.call(deconstructed[keyword])
- end
- end
-
- if compiled_constant
- combine_and(compiled_constant, compiled_keywords)
- else
- compiled_keywords
- end
- end
-
- # in nil
- def compile_nil_node(node)
- ->(attribute) { attribute.nil? }
- end
-
- # in /foo/
- def compile_regular_expression_node(node)
- regexp = Regexp.new(node.unescaped, node.closing[1..])
-
- ->(attribute) { regexp === attribute }
- end
-
- # in ""
- # in "foo"
- def compile_string_node(node)
- string = node.unescaped
-
- ->(attribute) { string === attribute }
- end
-
- # in :+
- # in :foo
- def compile_symbol_node(node)
- symbol = node.unescaped.to_sym
-
- ->(attribute) { symbol === attribute }
- end
-
- # Compile any kind of node. Dispatch out to the individual compilation
- # methods based on the type of node.
- def compile_node(node)
- case node
- when AlternationPatternNode
- compile_alternation_pattern_node(node)
- when ArrayPatternNode
- compile_array_pattern_node(node)
- when ConstantPathNode
- compile_constant_path_node(node)
- when ConstantReadNode
- compile_constant_read_node(node)
- when HashPatternNode
- compile_hash_pattern_node(node)
- when NilNode
- compile_nil_node(node)
- when RegularExpressionNode
- compile_regular_expression_node(node)
- when StringNode
- compile_string_node(node)
- when SymbolNode
- compile_symbol_node(node)
- else
- compile_error(node)
- end
- end
- end
-end
diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec
deleted file mode 100644
index 23e7b3833b..0000000000
--- a/lib/prism/prism.gemspec
+++ /dev/null
@@ -1,123 +0,0 @@
-# frozen_string_literal: true
-
-Gem::Specification.new do |spec|
- spec.name = "prism"
- spec.version = "0.17.1"
- spec.authors = ["Shopify"]
- spec.email = ["ruby@shopify.com"]
-
- spec.summary = "Prism Ruby parser"
- spec.homepage = "https://github.com/ruby/prism"
- spec.license = "MIT"
-
- spec.required_ruby_version = ">= 3.0.0"
-
- spec.require_paths = ["lib"]
- spec.files = [
- "CHANGELOG.md",
- "CODE_OF_CONDUCT.md",
- "CONTRIBUTING.md",
- "LICENSE.md",
- "Makefile",
- "README.md",
- "config.yml",
- "docs/build_system.md",
- "docs/building.md",
- "docs/configuration.md",
- "docs/design.md",
- "docs/encoding.md",
- "docs/fuzzing.md",
- "docs/heredocs.md",
- "docs/javascript.md",
- "docs/mapping.md",
- "docs/releasing.md",
- "docs/ripper.md",
- "docs/ruby_api.md",
- "docs/serialization.md",
- "docs/testing.md",
- "ext/prism/api_node.c",
- "ext/prism/api_pack.c",
- "ext/prism/extension.c",
- "ext/prism/extension.h",
- "include/prism.h",
- "include/prism/ast.h",
- "include/prism/defines.h",
- "include/prism/diagnostic.h",
- "include/prism/enc/pm_encoding.h",
- "include/prism/node.h",
- "include/prism/options.h",
- "include/prism/pack.h",
- "include/prism/parser.h",
- "include/prism/prettyprint.h",
- "include/prism/regexp.h",
- "include/prism/util/pm_buffer.h",
- "include/prism/util/pm_char.h",
- "include/prism/util/pm_constant_pool.h",
- "include/prism/util/pm_list.h",
- "include/prism/util/pm_memchr.h",
- "include/prism/util/pm_newline_list.h",
- "include/prism/util/pm_state_stack.h",
- "include/prism/util/pm_strncasecmp.h",
- "include/prism/util/pm_string.h",
- "include/prism/util/pm_string_list.h",
- "include/prism/util/pm_strpbrk.h",
- "include/prism/version.h",
- "lib/prism.rb",
- "lib/prism/compiler.rb",
- "lib/prism/debug.rb",
- "lib/prism/desugar_compiler.rb",
- "lib/prism/dispatcher.rb",
- "lib/prism/dsl.rb",
- "lib/prism/ffi.rb",
- "lib/prism/lex_compat.rb",
- "lib/prism/mutation_compiler.rb",
- "lib/prism/node.rb",
- "lib/prism/node_ext.rb",
- "lib/prism/node_inspector.rb",
- "lib/prism/pack.rb",
- "lib/prism/parse_result.rb",
- "lib/prism/pattern.rb",
- "lib/prism/ripper_compat.rb",
- "lib/prism/serialize.rb",
- "lib/prism/parse_result/comments.rb",
- "lib/prism/parse_result/newlines.rb",
- "lib/prism/visitor.rb",
- "src/diagnostic.c",
- "src/enc/pm_big5.c",
- "src/enc/pm_euc_jp.c",
- "src/enc/pm_gbk.c",
- "src/enc/pm_shift_jis.c",
- "src/enc/pm_tables.c",
- "src/enc/pm_unicode.c",
- "src/enc/pm_windows_31j.c",
- "src/node.c",
- "src/pack.c",
- "src/prettyprint.c",
- "src/regexp.c",
- "src/serialize.c",
- "src/token_type.c",
- "src/util/pm_buffer.c",
- "src/util/pm_char.c",
- "src/util/pm_constant_pool.c",
- "src/util/pm_list.c",
- "src/util/pm_memchr.c",
- "src/util/pm_newline_list.c",
- "src/util/pm_state_stack.c",
- "src/util/pm_string.c",
- "src/util/pm_string_list.c",
- "src/util/pm_strncasecmp.c",
- "src/util/pm_strpbrk.c",
- "src/options.c",
- "src/prism.c",
- "prism.gemspec",
- "sig/prism.rbs",
- "sig/prism_static.rbs",
- "rbi/prism.rbi",
- "rbi/prism_static.rbi"
- ]
-
- spec.extensions = ["ext/prism/extconf.rb"]
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
- spec.metadata["source_code_uri"] = "https://github.com/ruby/prism"
- spec.metadata["changelog_uri"] = "https://github.com/ruby/prism/blob/main/CHANGELOG.md"
-end
diff --git a/lib/prism/ripper_compat.rb b/lib/prism/ripper_compat.rb
deleted file mode 100644
index 624e608cc1..0000000000
--- a/lib/prism/ripper_compat.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-# frozen_string_literal: true
-
-require "ripper"
-
-module Prism
- # This class is meant to provide a compatibility layer between prism and
- # Ripper. It functions by parsing the entire tree first and then walking it
- # and executing each of the Ripper callbacks as it goes.
- #
- # This class is going to necessarily be slower than the native Ripper API. It
- # is meant as a stopgap until developers migrate to using prism. It is also
- # meant as a test harness for the prism parser.
- class RipperCompat
- # This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
- # returns the arrays of [type, *children].
- class SexpBuilder < RipperCompat
- private
-
- Ripper::PARSER_EVENTS.each do |event|
- define_method(:"on_#{event}") do |*args|
- [event, *args]
- end
- end
-
- Ripper::SCANNER_EVENTS.each do |event|
- define_method(:"on_#{event}") do |value|
- [:"@#{event}", value, [lineno, column]]
- end
- end
- end
-
- # This class mirrors the ::Ripper::SexpBuilderPP subclass of ::Ripper that
- # returns the same values as ::Ripper::SexpBuilder except with a couple of
- # niceties that flatten linked lists into arrays.
- class SexpBuilderPP < SexpBuilder
- private
-
- def _dispatch_event_new # :nodoc:
- []
- end
-
- def _dispatch_event_push(list, item) # :nodoc:
- list << item
- list
- end
-
- Ripper::PARSER_EVENT_TABLE.each do |event, arity|
- case event
- when /_new\z/
- alias_method :"on_#{event}", :_dispatch_event_new if arity == 0
- when /_add\z/
- alias_method :"on_#{event}", :_dispatch_event_push
- end
- end
- end
-
- # The source that is being parsed.
- attr_reader :source
-
- # The current line number of the parser.
- attr_reader :lineno
-
- # The current column number of the parser.
- attr_reader :column
-
- # Create a new RipperCompat object with the given source.
- def initialize(source)
- @source = source
- @result = nil
- @lineno = nil
- @column = nil
- end
-
- ############################################################################
- # Public interface
- ############################################################################
-
- # True if the parser encountered an error during parsing.
- def error?
- result.errors.any?
- end
-
- # Parse the source and return the result.
- def parse
- result.value.accept(self) unless error?
- end
-
- ############################################################################
- # Visitor methods
- ############################################################################
-
- # This method is responsible for dispatching to the correct visitor method
- # based on the type of the node.
- def visit(node)
- node&.accept(self)
- end
-
- # Visit a CallNode node.
- def visit_call_node(node)
- if !node.opening_loc && node.arguments.arguments.length == 1
- bounds(node.receiver.location)
- left = visit(node.receiver)
-
- bounds(node.arguments.arguments.first.location)
- right = visit(node.arguments.arguments.first)
-
- on_binary(left, source[node.message_loc.start_offset...node.message_loc.end_offset].to_sym, right)
- else
- raise NotImplementedError
- end
- end
-
- # Visit an IntegerNode node.
- def visit_integer_node(node)
- bounds(node.location)
- on_int(source[node.location.start_offset...node.location.end_offset])
- end
-
- # Visit a StatementsNode node.
- def visit_statements_node(node)
- bounds(node.location)
- node.body.inject(on_stmts_new) do |stmts, stmt|
- on_stmts_add(stmts, visit(stmt))
- end
- end
-
- # Visit a token found during parsing.
- def visit_token(node)
- bounds(node.location)
-
- case node.type
- when :MINUS
- on_op(node.value)
- when :PLUS
- on_op(node.value)
- else
- raise NotImplementedError, "Unknown token: #{node.type}"
- end
- end
-
- # Visit a ProgramNode node.
- def visit_program_node(node)
- bounds(node.location)
- on_program(visit(node.statements))
- end
-
- ############################################################################
- # Entrypoints for subclasses
- ############################################################################
-
- # This is a convenience method that runs the SexpBuilder subclass parser.
- def self.sexp_raw(source)
- SexpBuilder.new(source).parse
- end
-
- # This is a convenience method that runs the SexpBuilderPP subclass parser.
- def self.sexp(source)
- SexpBuilderPP.new(source).parse
- end
-
- private
-
- # This method is responsible for updating lineno and column information
- # to reflect the current node.
- #
- # This method could be drastically improved with some caching on the start
- # of every line, but for now it's good enough.
- def bounds(location)
- start_offset = location.start_offset
-
- @lineno = source[0..start_offset].count("\n") + 1
- @column = start_offset - (source.rindex("\n", start_offset) || 0)
- end
-
- # Lazily initialize the parse result.
- def result
- @result ||= Prism.parse(source)
- end
-
- def _dispatch0; end # :nodoc:
- def _dispatch1(_); end # :nodoc:
- def _dispatch2(_, _); end # :nodoc:
- def _dispatch3(_, _, _); end # :nodoc:
- def _dispatch4(_, _, _, _); end # :nodoc:
- def _dispatch5(_, _, _, _, _); end # :nodoc:
- def _dispatch7(_, _, _, _, _, _, _); end # :nodoc:
-
- (Ripper::SCANNER_EVENT_TABLE.merge(Ripper::PARSER_EVENT_TABLE)).each do |event, arity|
- alias_method :"on_#{event}", :"_dispatch#{arity}"
- end
- end
-end
diff --git a/lib/pstore.gemspec b/lib/pstore.gemspec
deleted file mode 100644
index 86051d2f43..0000000000
--- a/lib/pstore.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Transactional File Storage for Ruby Objects}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/pstore"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = "https://github.com/ruby/pstore"
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-end
diff --git a/lib/pstore.rb b/lib/pstore.rb
index 818ffa07e0..72deaa1017 100644
--- a/lib/pstore.rb
+++ b/lib/pstore.rb
@@ -326,7 +326,7 @@ require "digest"
# end
#
class PStore
- VERSION = "0.1.3"
+ VERSION = "0.1.2"
RDWR_ACCESS = {mode: IO::RDWR | IO::CREAT | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
RD_ACCESS = {mode: IO::RDONLY | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
@@ -487,6 +487,8 @@ class PStore
# end
#
# Raises an exception if called outside a transaction block.
+ #
+ # PStore#roots is an alias for PStore#keys.
def keys
in_transaction
@table.keys
@@ -502,6 +504,8 @@ class PStore
# end
#
# Raises an exception if called outside a transaction block.
+ #
+ # PStore#root? is an alias for PStore#key?.
def key?(key)
in_transaction
@table.key? key
@@ -517,8 +521,8 @@ class PStore
end
# Exits the current transaction block, committing any changes
- # specified in the
- # {transaction block}[rdoc-ref:PStore@The+Transaction+Block].
+ # specified in the transaction block.
+ # See {Committing or Aborting}[rdoc-ref:PStore@Committing+or+Aborting].
#
# Raises an exception if called outside a transaction block.
def commit
@@ -528,8 +532,8 @@ class PStore
end
# Exits the current transaction block, discarding any changes
- # specified in the
- # {transaction block}[rdoc-ref:PStore@The+Transaction+Block].
+ # specified in the transaction block.
+ # See {Committing or Aborting}[rdoc-ref:PStore@Committing+or+Aborting].
#
# Raises an exception if called outside a transaction block.
def abort
diff --git a/lib/pstore/pstore.gemspec b/lib/pstore/pstore.gemspec
new file mode 100644
index 0000000000..8425795afe
--- /dev/null
+++ b/lib/pstore/pstore.gemspec
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Transactional File Storage for Ruby Objects}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/pstore"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = "https://github.com/ruby/pstore"
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/racc.rb b/lib/racc.rb
new file mode 100644
index 0000000000..f6e4ac03a8
--- /dev/null
+++ b/lib/racc.rb
@@ -0,0 +1,6 @@
+require 'racc/compat'
+require 'racc/debugflags'
+require 'racc/grammar'
+require 'racc/state'
+require 'racc/exception'
+require 'racc/info'
diff --git a/lib/racc/compat.rb b/lib/racc/compat.rb
new file mode 100644
index 0000000000..62f4f630be
--- /dev/null
+++ b/lib/racc/compat.rb
@@ -0,0 +1,33 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+unless Object.method_defined?(:__send)
+ class Object
+ alias __send __send__
+ end
+end
+
+unless Object.method_defined?(:__send!)
+ class Object
+ alias __send! __send__
+ end
+end
+
+unless Array.method_defined?(:map!)
+ class Array
+ if Array.method_defined?(:collect!)
+ alias map! collect!
+ else
+ alias map! filter
+ end
+ end
+end
diff --git a/lib/racc/debugflags.rb b/lib/racc/debugflags.rb
new file mode 100644
index 0000000000..ee34cf2314
--- /dev/null
+++ b/lib/racc/debugflags.rb
@@ -0,0 +1,60 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ class DebugFlags
+ def DebugFlags.parse_option_string(s)
+ parse = rule = token = state = la = prec = conf = false
+ s.split(//).each do |ch|
+ case ch
+ when 'p' then parse = true
+ when 'r' then rule = true
+ when 't' then token = true
+ when 's' then state = true
+ when 'l' then la = true
+ when 'c' then prec = true
+ when 'o' then conf = true
+ else
+ raise "unknown debug flag char: #{ch.inspect}"
+ end
+ end
+ new(parse, rule, token, state, la, prec, conf)
+ end
+
+ def initialize(parse = false, rule = false, token = false, state = false,
+ la = false, prec = false, conf = false)
+ @parse = parse
+ @rule = rule
+ @token = token
+ @state = state
+ @la = la
+ @prec = prec
+ @any = (parse || rule || token || state || la || prec)
+ @status_logging = conf
+ end
+
+ attr_reader :parse
+ attr_reader :rule
+ attr_reader :token
+ attr_reader :state
+ attr_reader :la
+ attr_reader :prec
+
+ def any?
+ @any
+ end
+
+ attr_reader :status_logging
+ end
+
+end
diff --git a/lib/racc/exception.rb b/lib/racc/exception.rb
new file mode 100644
index 0000000000..c11dc2e43e
--- /dev/null
+++ b/lib/racc/exception.rb
@@ -0,0 +1,16 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+ class Error < StandardError; end
+ class CompileError < Error; end
+end
diff --git a/lib/racc/grammar.rb b/lib/racc/grammar.rb
new file mode 100644
index 0000000000..01c4c3df69
--- /dev/null
+++ b/lib/racc/grammar.rb
@@ -0,0 +1,1118 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/compat'
+require 'racc/iset'
+require 'racc/sourcetext'
+require 'racc/logfilegenerator'
+require 'racc/exception'
+require 'forwardable'
+
+module Racc
+
+ class Grammar
+
+ def initialize(debug_flags = DebugFlags.new)
+ @symboltable = SymbolTable.new
+ @debug_symbol = debug_flags.token
+ @rules = [] # :: [Rule]
+ @start = nil
+ @n_expected_srconflicts = nil
+ @prec_table = []
+ @prec_table_closed = false
+ @closed = false
+ @states = nil
+ end
+
+ attr_reader :start
+ attr_reader :symboltable
+ attr_accessor :n_expected_srconflicts
+
+ def [](x)
+ @rules[x]
+ end
+
+ def each_rule(&block)
+ @rules.each(&block)
+ end
+
+ alias each each_rule
+
+ def each_index(&block)
+ @rules.each_index(&block)
+ end
+
+ def each_with_index(&block)
+ @rules.each_with_index(&block)
+ end
+
+ def size
+ @rules.size
+ end
+
+ def to_s
+ "<Racc::Grammar>"
+ end
+
+ extend Forwardable
+
+ def_delegator "@symboltable", :each, :each_symbol
+ def_delegator "@symboltable", :each_terminal
+ def_delegator "@symboltable", :each_nonterminal
+
+ def intern(value, dummy = false)
+ @symboltable.intern(value, dummy)
+ end
+
+ def symbols
+ @symboltable.symbols
+ end
+
+ def nonterminal_base
+ @symboltable.nt_base
+ end
+
+ def useless_nonterminal_exist?
+ n_useless_nonterminals() != 0
+ end
+
+ def n_useless_nonterminals
+ @n_useless_nonterminals ||= each_useless_nonterminal.count
+ end
+
+ def each_useless_nonterminal
+ return to_enum __method__ unless block_given?
+
+ @symboltable.each_nonterminal do |sym|
+ yield sym if sym.useless?
+ end
+ end
+
+ def useless_rule_exist?
+ n_useless_rules() != 0
+ end
+
+ def n_useless_rules
+ @n_useless_rules ||= each_useless_rule.count
+ end
+
+ def each_useless_rule
+ return to_enum __method__ unless block_given?
+
+ each do |r|
+ yield r if r.useless?
+ end
+ end
+
+ def nfa
+ (@states ||= States.new(self)).nfa
+ end
+
+ def dfa
+ (@states ||= States.new(self)).dfa
+ end
+
+ alias states dfa
+
+ def state_transition_table
+ states().state_transition_table
+ end
+
+ def parser_class
+ states = states() # cache
+ if $DEBUG
+ srcfilename = caller(1).first.slice(/\A(.*?):/, 1)
+ begin
+ write_log srcfilename + ".output"
+ rescue SystemCallError
+ end
+ report = lambda {|s| $stderr.puts "racc: #{srcfilename}: #{s}" }
+ if states.should_report_srconflict?
+ report["#{states.n_srconflicts} shift/reduce conflicts"]
+ end
+ if states.rrconflict_exist?
+ report["#{states.n_rrconflicts} reduce/reduce conflicts"]
+ end
+ g = states.grammar
+ if g.useless_nonterminal_exist?
+ report["#{g.n_useless_nonterminals} useless nonterminals"]
+ end
+ if g.useless_rule_exist?
+ report["#{g.n_useless_rules} useless rules"]
+ end
+ end
+ states.state_transition_table.parser_class
+ end
+
+ def write_log(path)
+ File.open(path, 'w') {|f|
+ LogFileGenerator.new(states()).output f
+ }
+ end
+
+ #
+ # Grammar Definition Interface
+ #
+
+ def add(rule)
+ raise ArgumentError, "rule added after the Grammar closed" if @closed
+ @rules.push rule
+ end
+
+ def added?(sym)
+ @rules.detect {|r| r.target == sym }
+ end
+
+ def start_symbol=(s)
+ raise CompileError, "start symbol set twice'" if @start
+ @start = s
+ end
+
+ def declare_precedence(assoc, syms)
+ raise CompileError, "precedence table defined twice" if @prec_table_closed
+ @prec_table.push [assoc, syms]
+ end
+
+ def end_precedence_declaration(reverse)
+ @prec_table_closed = true
+ return if @prec_table.empty?
+ table = reverse ? @prec_table.reverse : @prec_table
+ table.each_with_index do |(assoc, syms), idx|
+ syms.each do |sym|
+ sym.assoc = assoc
+ sym.precedence = idx
+ end
+ end
+ end
+
+ #
+ # Dynamic Generation Interface
+ #
+
+ def Grammar.define(&block)
+ env = DefinitionEnv.new
+ env.instance_eval(&block)
+ env.grammar
+ end
+
+ class DefinitionEnv
+ def initialize
+ @grammar = Grammar.new
+ @seqs = Hash.new(0)
+ @delayed = []
+ end
+
+ def grammar
+ flush_delayed
+ @grammar.each do |rule|
+ if rule.specified_prec
+ rule.specified_prec = @grammar.intern(rule.specified_prec)
+ end
+ end
+ @grammar.init
+ @grammar
+ end
+
+ def precedence_table(&block)
+ env = PrecedenceDefinitionEnv.new(@grammar)
+ env.instance_eval(&block)
+ @grammar.end_precedence_declaration env.reverse
+ end
+
+ def method_missing(mid, *args, &block)
+ unless mid.to_s[-1,1] == '='
+ super # raises NoMethodError
+ end
+ target = @grammar.intern(mid.to_s.chop.intern)
+ unless args.size == 1
+ raise ArgumentError, "too many arguments for #{mid} (#{args.size} for 1)"
+ end
+ _add target, args.first
+ end
+
+ def _add(target, x)
+ case x
+ when Sym
+ @delayed.each do |rule|
+ rule.replace x, target if rule.target == x
+ end
+ @grammar.symboltable.delete x
+ else
+ x.each_rule do |r|
+ r.target = target
+ @grammar.add r
+ end
+ end
+ flush_delayed
+ end
+
+ def _delayed_add(rule)
+ @delayed.push rule
+ end
+
+ def _added?(sym)
+ @grammar.added?(sym) or @delayed.detect {|r| r.target == sym }
+ end
+
+ def flush_delayed
+ return if @delayed.empty?
+ @delayed.each do |rule|
+ @grammar.add rule
+ end
+ @delayed.clear
+ end
+
+ def seq(*list, &block)
+ Rule.new(nil, list.map {|x| _intern(x) }, UserAction.proc(block))
+ end
+
+ def null(&block)
+ seq(&block)
+ end
+
+ def action(&block)
+ id = "@#{@seqs["action"] += 1}".intern
+ _delayed_add Rule.new(@grammar.intern(id), [], UserAction.proc(block))
+ id
+ end
+
+ alias _ action
+
+ def option(sym, default = nil, &block)
+ _defmetasyntax("option", _intern(sym), block) {|target|
+ seq() { default } | seq(sym)
+ }
+ end
+
+ def many(sym, &block)
+ _defmetasyntax("many", _intern(sym), block) {|target|
+ seq() { [] }\
+ | seq(target, sym) {|list, x| list.push x; list }
+ }
+ end
+
+ def many1(sym, &block)
+ _defmetasyntax("many1", _intern(sym), block) {|target|
+ seq(sym) {|x| [x] }\
+ | seq(target, sym) {|list, x| list.push x; list }
+ }
+ end
+
+ def separated_by(sep, sym, &block)
+ option(separated_by1(sep, sym), [], &block)
+ end
+
+ def separated_by1(sep, sym, &block)
+ _defmetasyntax("separated_by1", _intern(sym), block) {|target|
+ seq(sym) {|x| [x] }\
+ | seq(target, sep, sym) {|list, _, x| list.push x; list }
+ }
+ end
+
+ def _intern(x)
+ case x
+ when Symbol, String
+ @grammar.intern(x)
+ when Racc::Sym
+ x
+ else
+ raise TypeError, "wrong type #{x.class} (expected Symbol/String/Racc::Sym)"
+ end
+ end
+
+ private
+
+ def _defmetasyntax(type, id, action, &block)
+ if action
+ idbase = "#{type}@#{id}-#{@seqs[type] += 1}"
+ target = _wrap(idbase, "#{idbase}-core", action)
+ _register("#{idbase}-core", &block)
+ else
+ target = _register("#{type}@#{id}", &block)
+ end
+ @grammar.intern(target)
+ end
+
+ def _register(target_name)
+ target = target_name.intern
+ unless _added?(@grammar.intern(target))
+ yield(target).each_rule do |rule|
+ rule.target = @grammar.intern(target)
+ _delayed_add rule
+ end
+ end
+ target
+ end
+
+ def _wrap(target_name, sym, block)
+ target = target_name.intern
+ _delayed_add Rule.new(@grammar.intern(target),
+ [@grammar.intern(sym.intern)],
+ UserAction.proc(block))
+ target
+ end
+ end
+
+ class PrecedenceDefinitionEnv
+ def initialize(g)
+ @grammar = g
+ @prechigh_seen = false
+ @preclow_seen = false
+ @reverse = false
+ end
+
+ attr_reader :reverse
+
+ def higher
+ if @prechigh_seen
+ raise CompileError, "prechigh used twice"
+ end
+ @prechigh_seen = true
+ end
+
+ def lower
+ if @preclow_seen
+ raise CompileError, "preclow used twice"
+ end
+ if @prechigh_seen
+ @reverse = true
+ end
+ @preclow_seen = true
+ end
+
+ def left(*syms)
+ @grammar.declare_precedence :Left, syms.map {|s| @grammar.intern(s) }
+ end
+
+ def right(*syms)
+ @grammar.declare_precedence :Right, syms.map {|s| @grammar.intern(s) }
+ end
+
+ def nonassoc(*syms)
+ @grammar.declare_precedence :Nonassoc, syms.map {|s| @grammar.intern(s)}
+ end
+ end
+
+ #
+ # Computation
+ #
+
+ def init
+ return if @closed
+ @closed = true
+ @start ||= @rules.map {|r| r.target }.detect {|sym| not sym.dummy? }
+ raise CompileError, 'no rule in input' if @rules.empty?
+ add_start_rule
+ @rules.freeze
+ fix_ident
+ compute_hash
+ compute_heads
+ determine_terminals
+ compute_nullable_0
+ @symboltable.fix
+ compute_locate
+ @symboltable.each_nonterminal {|t| compute_expand t }
+ compute_nullable
+ compute_useless
+ end
+
+ private
+
+ def add_start_rule
+ r = Rule.new(@symboltable.dummy,
+ [@start, @symboltable.anchor, @symboltable.anchor],
+ UserAction.empty)
+ r.ident = 0
+ r.hash = 0
+ r.precedence = nil
+ @rules.unshift r
+ end
+
+ # Rule#ident
+ # LocationPointer#ident
+ def fix_ident
+ @rules.each_with_index do |rule, idx|
+ rule.ident = idx
+ end
+ end
+
+ # Rule#hash
+ def compute_hash
+ hash = 4 # size of dummy rule
+ @rules.each do |rule|
+ rule.hash = hash
+ hash += (rule.size + 1)
+ end
+ end
+
+ # Sym#heads
+ def compute_heads
+ @rules.each do |rule|
+ rule.target.heads.push rule.ptrs[0]
+ end
+ end
+
+ # Sym#terminal?
+ def determine_terminals
+ @symboltable.each do |s|
+ s.term = s.heads.empty?
+ end
+ end
+
+ # Sym#self_null?
+ def compute_nullable_0
+ @symboltable.each do |s|
+ if s.terminal?
+ s.snull = false
+ else
+ s.snull = s.heads.any? {|loc| loc.reduce? }
+ end
+ end
+ end
+
+ # Sym#locate
+ def compute_locate
+ @rules.each do |rule|
+ t = nil
+ rule.ptrs.each do |ptr|
+ unless ptr.reduce?
+ tok = ptr.dereference
+ tok.locate.push ptr
+ t = tok if tok.terminal?
+ end
+ end
+ rule.precedence = t
+ end
+ end
+
+ # Sym#expand
+ def compute_expand(t)
+ puts "expand> #{t.to_s}" if @debug_symbol
+ t.expand = _compute_expand(t, ISet.new, [])
+ puts "expand< #{t.to_s}: #{t.expand.to_s}" if @debug_symbol
+ end
+
+ def _compute_expand(t, set, lock)
+ if tmp = t.expand
+ set.update tmp
+ return set
+ end
+ tok = nil
+ set.update_a t.heads
+ t.heads.each do |ptr|
+ tok = ptr.dereference
+ if tok and tok.nonterminal?
+ unless lock[tok.ident]
+ lock[tok.ident] = true
+ _compute_expand tok, set, lock
+ end
+ end
+ end
+ set
+ end
+
+ # Sym#nullable?, Rule#nullable?
+ def compute_nullable
+ @rules.each {|r| r.null = false }
+ @symboltable.each {|t| t.null = false }
+ r = @rules.dup
+ s = @symboltable.nonterminals
+ begin
+ rs = r.size
+ ss = s.size
+ check_rules_nullable r
+ check_symbols_nullable s
+ end until rs == r.size and ss == s.size
+ end
+
+ def check_rules_nullable(rules)
+ rules.delete_if do |rule|
+ rule.null = true
+ rule.symbols.each do |t|
+ unless t.nullable?
+ rule.null = false
+ break
+ end
+ end
+ rule.nullable?
+ end
+ end
+
+ def check_symbols_nullable(symbols)
+ symbols.delete_if do |sym|
+ sym.heads.each do |ptr|
+ if ptr.rule.nullable?
+ sym.null = true
+ break
+ end
+ end
+ sym.nullable?
+ end
+ end
+
+ # Sym#useless?, Rule#useless?
+ # FIXME: what means "useless"?
+ def compute_useless
+ @symboltable.each_terminal {|sym| sym.useless = false }
+ @symboltable.each_nonterminal {|sym| sym.useless = true }
+ @rules.each {|rule| rule.useless = true }
+ r = @rules.dup
+ s = @symboltable.nonterminals
+ begin
+ rs = r.size
+ ss = s.size
+ check_rules_useless r
+ check_symbols_useless s
+ end until r.size == rs and s.size == ss
+ end
+
+ def check_rules_useless(rules)
+ rules.delete_if do |rule|
+ rule.useless = false
+ rule.symbols.each do |sym|
+ if sym.useless?
+ rule.useless = true
+ break
+ end
+ end
+ not rule.useless?
+ end
+ end
+
+ def check_symbols_useless(s)
+ s.delete_if do |t|
+ t.heads.each do |ptr|
+ unless ptr.rule.useless?
+ t.useless = false
+ break
+ end
+ end
+ not t.useless?
+ end
+ end
+
+ end # class Grammar
+
+
+ class Rule
+
+ def initialize(target, syms, act)
+ @target = target
+ @symbols = syms
+ @action = act
+ @alternatives = []
+
+ @ident = nil
+ @hash = nil
+ @ptrs = nil
+ @precedence = nil
+ @specified_prec = nil
+ @null = nil
+ @useless = nil
+ end
+
+ attr_accessor :target
+ attr_reader :symbols
+ attr_reader :action
+
+ def |(x)
+ @alternatives.push x.rule
+ self
+ end
+
+ def rule
+ self
+ end
+
+ def each_rule(&block)
+ yield self
+ @alternatives.each(&block)
+ end
+
+ attr_accessor :ident
+
+ attr_reader :hash
+ attr_reader :ptrs
+
+ def hash=(n)
+ @hash = n
+ ptrs = []
+ @symbols.each_with_index do |sym, idx|
+ ptrs.push LocationPointer.new(self, idx, sym)
+ end
+ ptrs.push LocationPointer.new(self, @symbols.size, nil)
+ @ptrs = ptrs
+ end
+
+ def precedence
+ @specified_prec || @precedence
+ end
+
+ def precedence=(sym)
+ @precedence ||= sym
+ end
+
+ def prec(sym, &block)
+ @specified_prec = sym
+ if block
+ unless @action.empty?
+ raise CompileError, 'both of rule action block and prec block given'
+ end
+ @action = UserAction.proc(block)
+ end
+ self
+ end
+
+ attr_accessor :specified_prec
+
+ def nullable?() @null end
+ def null=(n) @null = n end
+
+ def useless?() @useless end
+ def useless=(u) @useless = u end
+
+ def inspect
+ "#<Racc::Rule id=#{@ident} (#{@target})>"
+ end
+
+ def ==(other)
+ other.kind_of?(Rule) and @ident == other.ident
+ end
+
+ def [](idx)
+ @symbols[idx]
+ end
+
+ def size
+ @symbols.size
+ end
+
+ def empty?
+ @symbols.empty?
+ end
+
+ def to_s
+ "#<rule#{@ident}>"
+ end
+
+ def accept?
+ if tok = @symbols[-1]
+ tok.anchor?
+ else
+ false
+ end
+ end
+
+ def each(&block)
+ @symbols.each(&block)
+ end
+
+ def replace(src, dest)
+ @target = dest
+ @symbols = @symbols.map {|s| s == src ? dest : s }
+ end
+
+ end # class Rule
+
+
+ class UserAction
+
+ def UserAction.source_text(src)
+ new(src, nil)
+ end
+
+ def UserAction.proc(pr = nil, &block)
+ if pr and block
+ raise ArgumentError, "both of argument and block given"
+ end
+ new(nil, pr || block)
+ end
+
+ def UserAction.empty
+ new(nil, nil)
+ end
+
+ private_class_method :new
+
+ def initialize(src, proc)
+ @source = src
+ @proc = proc
+ end
+
+ attr_reader :source
+ attr_reader :proc
+
+ def source?
+ not @proc
+ end
+
+ def proc?
+ not @source
+ end
+
+ def empty?
+ not @proc and not @source
+ end
+
+ def name
+ "{action type=#{@source || @proc || 'nil'}}"
+ end
+
+ alias inspect name
+
+ end
+
+
+ class OrMark
+ def initialize(lineno)
+ @lineno = lineno
+ end
+
+ def name
+ '|'
+ end
+
+ alias inspect name
+
+ attr_reader :lineno
+ end
+
+
+ class Prec
+ def initialize(symbol, lineno)
+ @symbol = symbol
+ @lineno = lineno
+ end
+
+ def name
+ "=#{@symbol}"
+ end
+
+ alias inspect name
+
+ attr_reader :symbol
+ attr_reader :lineno
+ end
+
+
+ #
+ # A set of rule and position in it's RHS.
+ # Note that the number of pointers is more than rule's RHS array,
+ # because pointer points right edge of the final symbol when reducing.
+ #
+ class LocationPointer
+
+ def initialize(rule, i, sym)
+ @rule = rule
+ @index = i
+ @symbol = sym
+ @ident = @rule.hash + i
+ @reduce = sym.nil?
+ end
+
+ attr_reader :rule
+ attr_reader :index
+ attr_reader :symbol
+
+ alias dereference symbol
+
+ attr_reader :ident
+ alias hash ident
+ attr_reader :reduce
+ alias reduce? reduce
+
+ def to_s
+ sprintf('(%d,%d %s)',
+ @rule.ident, @index, (reduce?() ? '#' : @symbol.to_s))
+ end
+
+ alias inspect to_s
+
+ def eql?(ot)
+ @hash == ot.hash
+ end
+
+ alias == eql?
+
+ def head?
+ @index == 0
+ end
+
+ def next
+ @rule.ptrs[@index + 1] or ptr_bug!
+ end
+
+ alias increment next
+
+ def before(len)
+ @rule.ptrs[@index - len] or ptr_bug!
+ end
+
+ private
+
+ def ptr_bug!
+ raise "racc: fatal: pointer not exist: self: #{to_s}"
+ end
+
+ end # class LocationPointer
+
+
+ class SymbolTable
+
+ include Enumerable
+
+ def initialize
+ @symbols = [] # :: [Racc::Sym]
+ @cache = {} # :: {(String|Symbol) => Racc::Sym}
+ @dummy = intern(:$start, true)
+ @anchor = intern(false, true) # Symbol ID = 0
+ @error = intern(:error, false) # Symbol ID = 1
+ end
+
+ attr_reader :dummy
+ attr_reader :anchor
+ attr_reader :error
+
+ def [](id)
+ @symbols[id]
+ end
+
+ def intern(val, dummy = false)
+ @cache[val] ||=
+ begin
+ sym = Sym.new(val, dummy)
+ @symbols.push sym
+ sym
+ end
+ end
+
+ attr_reader :symbols
+ alias to_a symbols
+
+ def delete(sym)
+ @symbols.delete sym
+ @cache.delete sym.value
+ end
+
+ attr_reader :nt_base
+
+ def nt_max
+ @symbols.size
+ end
+
+ def each(&block)
+ @symbols.each(&block)
+ end
+
+ def terminals(&block)
+ @symbols[0, @nt_base]
+ end
+
+ def each_terminal(&block)
+ @terms.each(&block)
+ end
+
+ def nonterminals
+ @symbols[@nt_base, @symbols.size - @nt_base]
+ end
+
+ def each_nonterminal(&block)
+ @nterms.each(&block)
+ end
+
+ def fix
+ terms, nterms = @symbols.partition {|s| s.terminal? }
+ @symbols = terms + nterms
+ @terms = terms
+ @nterms = nterms
+ @nt_base = terms.size
+ fix_ident
+ check_terminals
+ end
+
+ private
+
+ def fix_ident
+ @symbols.each_with_index do |t, i|
+ t.ident = i
+ end
+ end
+
+ def check_terminals
+ return unless @symbols.any? {|s| s.should_terminal? }
+ @anchor.should_terminal
+ @error.should_terminal
+ each_terminal do |t|
+ t.should_terminal if t.string_symbol?
+ end
+ each do |s|
+ s.should_terminal if s.assoc
+ end
+ terminals().reject {|t| t.should_terminal? }.each do |t|
+ raise CompileError, "terminal #{t} not declared as terminal"
+ end
+ nonterminals().select {|n| n.should_terminal? }.each do |n|
+ raise CompileError, "symbol #{n} declared as terminal but is not terminal"
+ end
+ end
+
+ end # class SymbolTable
+
+
+ # Stands terminal and nonterminal symbols.
+ class Sym
+
+ def initialize(value, dummyp)
+ @ident = nil
+ @value = value
+ @dummyp = dummyp
+
+ @term = nil
+ @nterm = nil
+ @should_terminal = false
+ @precedence = nil
+ case value
+ when Symbol
+ @to_s = value.to_s
+ @serialized = value.inspect
+ @string = false
+ when String
+ @to_s = value.inspect
+ @serialized = value.dump
+ @string = true
+ when false
+ @to_s = '$end'
+ @serialized = 'false'
+ @string = false
+ when ErrorSymbolValue
+ @to_s = 'error'
+ @serialized = 'Object.new'
+ @string = false
+ else
+ raise ArgumentError, "unknown symbol value: #{value.class}"
+ end
+
+ @heads = []
+ @locate = []
+ @snull = nil
+ @null = nil
+ @expand = nil
+ @useless = nil
+ end
+
+ class << self
+ def once_writer(nm)
+ nm = nm.id2name
+ module_eval(<<-EOS)
+ def #{nm}=(v)
+ raise 'racc: fatal: @#{nm} != nil' unless @#{nm}.nil?
+ @#{nm} = v
+ end
+ EOS
+ end
+ end
+
+ once_writer :ident
+ attr_reader :ident
+
+ alias hash ident
+
+ attr_reader :value
+
+ def dummy?
+ @dummyp
+ end
+
+ def terminal?
+ @term
+ end
+
+ def nonterminal?
+ @nterm
+ end
+
+ def term=(t)
+ raise 'racc: fatal: term= called twice' unless @term.nil?
+ @term = t
+ @nterm = !t
+ end
+
+ def should_terminal
+ @should_terminal = true
+ end
+
+ def should_terminal?
+ @should_terminal
+ end
+
+ def string_symbol?
+ @string
+ end
+
+ def serialize
+ @serialized
+ end
+
+ attr_writer :serialized
+
+ attr_accessor :precedence
+ attr_accessor :assoc
+
+ def to_s
+ @to_s.dup
+ end
+
+ alias inspect to_s
+
+ def |(x)
+ rule() | x.rule
+ end
+
+ def rule
+ Rule.new(nil, [self], UserAction.empty)
+ end
+
+ #
+ # cache
+ #
+
+ attr_reader :heads
+ attr_reader :locate
+
+ def self_null?
+ @snull
+ end
+
+ once_writer :snull
+
+ def nullable?
+ @null
+ end
+
+ def null=(n)
+ @null = n
+ end
+
+ attr_reader :expand
+ once_writer :expand
+
+ def useless?
+ @useless
+ end
+
+ def useless=(f)
+ @useless = f
+ end
+
+ end # class Sym
+
+end # module Racc
diff --git a/lib/racc/grammarfileparser.rb b/lib/racc/grammarfileparser.rb
new file mode 100644
index 0000000000..c7d1207f0b
--- /dev/null
+++ b/lib/racc/grammarfileparser.rb
@@ -0,0 +1,561 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc'
+require 'racc/compat'
+require 'racc/grammar'
+require 'racc/parserfilegenerator'
+require 'racc/sourcetext'
+require 'stringio'
+
+module Racc
+
+ grammar = Grammar.define {
+ g = self
+
+ g.class = seq(:CLASS, :cname, many(:param), :RULE, :rules, option(:END))
+
+ g.cname = seq(:rubyconst) {|name|
+ @result.params.classname = name
+ }\
+ | seq(:rubyconst, "<", :rubyconst) {|c, _, s|
+ @result.params.classname = c
+ @result.params.superclass = s
+ }
+
+ g.rubyconst = separated_by1(:colon2, :SYMBOL) {|syms|
+ syms.map {|s| s.to_s }.join('::')
+ }
+
+ g.colon2 = seq(':', ':')
+
+ g.param = seq(:CONV, many1(:convdef), :END) {|*|
+ #@grammar.end_convert_block # FIXME
+ }\
+ | seq(:PRECHIGH, many1(:precdef), :PRECLOW) {|*|
+ @grammar.end_precedence_declaration true
+ }\
+ | seq(:PRECLOW, many1(:precdef), :PRECHIGH) {|*|
+ @grammar.end_precedence_declaration false
+ }\
+ | seq(:START, :symbol) {|_, sym|
+ @grammar.start_symbol = sym
+ }\
+ | seq(:TOKEN, :symbols) {|_, syms|
+ syms.each do |s|
+ s.should_terminal
+ end
+ }\
+ | seq(:OPTION, :options) {|_, syms|
+ syms.each do |opt|
+ case opt
+ when 'result_var'
+ @result.params.result_var = true
+ when 'no_result_var'
+ @result.params.result_var = false
+ when 'omit_action_call'
+ @result.params.omit_action_call = true
+ when 'no_omit_action_call'
+ @result.params.omit_action_call = false
+ else
+ raise CompileError, "unknown option: #{opt}"
+ end
+ end
+ }\
+ | seq(:EXPECT, :DIGIT) {|_, num|
+ if @grammar.n_expected_srconflicts
+ raise CompileError, "`expect' seen twice"
+ end
+ @grammar.n_expected_srconflicts = num
+ }
+
+ g.convdef = seq(:symbol, :STRING) {|sym, code|
+ sym.serialized = code
+ }
+
+ g.precdef = seq(:LEFT, :symbols) {|_, syms|
+ @grammar.declare_precedence :Left, syms
+ }\
+ | seq(:RIGHT, :symbols) {|_, syms|
+ @grammar.declare_precedence :Right, syms
+ }\
+ | seq(:NONASSOC, :symbols) {|_, syms|
+ @grammar.declare_precedence :Nonassoc, syms
+ }
+
+ g.symbols = seq(:symbol) {|sym|
+ [sym]
+ }\
+ | seq(:symbols, :symbol) {|list, sym|
+ list.push sym
+ list
+ }\
+ | seq(:symbols, "|")
+
+ g.symbol = seq(:SYMBOL) {|sym| @grammar.intern(sym) }\
+ | seq(:STRING) {|str| @grammar.intern(str) }
+
+ g.options = many(:SYMBOL) {|syms| syms.map {|s| s.to_s } }
+
+ g.rules = option(:rules_core) {|list|
+ add_rule_block list unless list.empty?
+ nil
+ }
+
+ g.rules_core = seq(:symbol) {|sym|
+ [sym]
+ }\
+ | seq(:rules_core, :rule_item) {|list, i|
+ list.push i
+ list
+ }\
+ | seq(:rules_core, ';') {|list, *|
+ add_rule_block list unless list.empty?
+ list.clear
+ list
+ }\
+ | seq(:rules_core, ':') {|list, *|
+ next_target = list.pop
+ add_rule_block list unless list.empty?
+ [next_target]
+ }
+
+ g.rule_item = seq(:symbol)\
+ | seq("|") {|*|
+ OrMark.new(@scanner.lineno)
+ }\
+ | seq("=", :symbol) {|_, sym|
+ Prec.new(sym, @scanner.lineno)
+ }\
+ | seq(:ACTION) {|src|
+ UserAction.source_text(src)
+ }
+ }
+
+ GrammarFileParser = grammar.parser_class
+
+ if grammar.states.srconflict_exist?
+ raise 'Racc boot script fatal: S/R conflict in build'
+ end
+ if grammar.states.rrconflict_exist?
+ raise 'Racc boot script fatal: R/R conflict in build'
+ end
+
+ class GrammarFileParser # reopen
+
+ class Result
+ def initialize(grammar)
+ @grammar = grammar
+ @params = ParserFileGenerator::Params.new
+ end
+
+ attr_reader :grammar
+ attr_reader :params
+ end
+
+ def GrammarFileParser.parse_file(filename)
+ parse(File.read(filename), filename, 1)
+ end
+
+ def GrammarFileParser.parse(src, filename = '-', lineno = 1)
+ new().parse(src, filename, lineno)
+ end
+
+ def initialize(debug_flags = DebugFlags.new)
+ @yydebug = debug_flags.parse
+ end
+
+ def parse(src, filename = '-', lineno = 1)
+ @filename = filename
+ @lineno = lineno
+ @scanner = GrammarFileScanner.new(src, @filename)
+ @scanner.debug = @yydebug
+ @grammar = Grammar.new
+ @result = Result.new(@grammar)
+ @embedded_action_seq = 0
+ yyparse @scanner, :yylex
+ parse_user_code
+ @result.grammar.init
+ @result
+ end
+
+ private
+
+ def next_token
+ @scanner.scan
+ end
+
+ def on_error(tok, val, _values)
+ if val.respond_to?(:id2name)
+ v = val.id2name
+ elsif val.kind_of?(String)
+ v = val
+ else
+ v = val.inspect
+ end
+ raise CompileError, "#{location()}: unexpected token '#{v}'"
+ end
+
+ def location
+ "#{@filename}:#{@lineno - 1 + @scanner.lineno}"
+ end
+
+ def add_rule_block(list)
+ sprec = nil
+ target = list.shift
+ case target
+ when OrMark, UserAction, Prec
+ raise CompileError, "#{target.lineno}: unexpected symbol #{target.name}"
+ end
+ curr = []
+ list.each do |i|
+ case i
+ when OrMark
+ add_rule target, curr, sprec
+ curr = []
+ sprec = nil
+ when Prec
+ raise CompileError, "'=<prec>' used twice in one rule" if sprec
+ sprec = i.symbol
+ else
+ curr.push i
+ end
+ end
+ add_rule target, curr, sprec
+ end
+
+ def add_rule(target, list, sprec)
+ if list.last.kind_of?(UserAction)
+ act = list.pop
+ else
+ act = UserAction.empty
+ end
+ list.map! {|s| s.kind_of?(UserAction) ? embedded_action(s) : s }
+ rule = Rule.new(target, list, act)
+ rule.specified_prec = sprec
+ @grammar.add rule
+ end
+
+ def embedded_action(act)
+ sym = @grammar.intern("@#{@embedded_action_seq += 1}".intern, true)
+ @grammar.add Rule.new(sym, [], act)
+ sym
+ end
+
+ #
+ # User Code Block
+ #
+
+ def parse_user_code
+ line = @scanner.lineno
+ _, *blocks = *@scanner.epilogue.split(/^----/)
+ blocks.each do |block|
+ header, *body = block.lines.to_a
+ label0, paths = *header.sub(/\A-+/, '').split('=', 2)
+ label = canonical_label(label0)
+ (paths ? paths.strip.split(' ') : []).each do |path|
+ add_user_code label, SourceText.new(File.read(path), path, 1)
+ end
+ add_user_code label, SourceText.new(body.join(''), @filename, line + 1)
+ line += (1 + body.size)
+ end
+ end
+
+ USER_CODE_LABELS = {
+ 'header' => :header,
+ 'prepare' => :header, # obsolete
+ 'inner' => :inner,
+ 'footer' => :footer,
+ 'driver' => :footer # obsolete
+ }
+
+ def canonical_label(src)
+ label = src.to_s.strip.downcase.slice(/\w+/)
+ unless USER_CODE_LABELS.key?(label)
+ raise CompileError, "unknown user code type: #{label.inspect}"
+ end
+ label
+ end
+
+ def add_user_code(label, src)
+ @result.params.public_send(USER_CODE_LABELS[label]).push src
+ end
+
+ end
+
+
+ class GrammarFileScanner
+
+ def initialize(str, filename = '-')
+ @lines = str.b.split(/\n|\r\n|\r/)
+ @filename = filename
+ @lineno = -1
+ @line_head = true
+ @in_rule_blk = false
+ @in_conv_blk = false
+ @in_block = nil
+ @epilogue = ''
+ @debug = false
+ next_line
+ end
+
+ attr_reader :epilogue
+
+ def lineno
+ @lineno + 1
+ end
+
+ attr_accessor :debug
+
+ def yylex(&block)
+ unless @debug
+ yylex0(&block)
+ else
+ yylex0 do |sym, tok|
+ $stderr.printf "%7d %-10s %s\n", lineno(), sym.inspect, tok.inspect
+ yield [sym, tok]
+ end
+ end
+ end
+
+ private
+
+ def yylex0
+ begin
+ until @line.empty?
+ @line.sub!(/\A\s+/, '')
+ if /\A\#/ =~ @line
+ break
+ elsif /\A\/\*/ =~ @line
+ skip_comment
+ elsif s = reads(/\A[a-zA-Z_]\w*/)
+ yield [atom_symbol(s), s.intern]
+ elsif s = reads(/\A\d+/)
+ yield [:DIGIT, s.to_i]
+ elsif ch = reads(/\A./)
+ case ch
+ when '"', "'"
+ yield [:STRING, eval(scan_quoted(ch))]
+ when '{'
+ lineno = lineno()
+ yield [:ACTION, SourceText.new(scan_action(), @filename, lineno)]
+ else
+ if ch == '|'
+ @line_head = false
+ end
+ yield [ch, ch]
+ end
+ else
+ end
+ end
+ end while next_line()
+ yield nil
+ end
+
+ def next_line
+ @lineno += 1
+ @line = @lines[@lineno]
+ if not @line or /\A----/ =~ @line
+ @epilogue = @lines.join("\n")
+ @lines.clear
+ @line = nil
+ if @in_block
+ @lineno -= 1
+ scan_error! sprintf('unterminated %s', @in_block)
+ end
+ false
+ else
+ @line.sub!(/(?:\n|\r\n|\r)\z/, '')
+ @line_head = true
+ true
+ end
+ end
+
+ ReservedWord = {
+ 'right' => :RIGHT,
+ 'left' => :LEFT,
+ 'nonassoc' => :NONASSOC,
+ 'preclow' => :PRECLOW,
+ 'prechigh' => :PRECHIGH,
+ 'token' => :TOKEN,
+ 'convert' => :CONV,
+ 'options' => :OPTION,
+ 'start' => :START,
+ 'expect' => :EXPECT,
+ 'class' => :CLASS,
+ 'rule' => :RULE,
+ 'end' => :END
+ }
+
+ def atom_symbol(token)
+ if token == 'end'
+ symbol = :END
+ @in_conv_blk = false
+ @in_rule_blk = false
+ else
+ if @line_head and not @in_conv_blk and not @in_rule_blk
+ symbol = ReservedWord[token] || :SYMBOL
+ else
+ symbol = :SYMBOL
+ end
+ case symbol
+ when :RULE then @in_rule_blk = true
+ when :CONV then @in_conv_blk = true
+ end
+ end
+ @line_head = false
+ symbol
+ end
+
+ def skip_comment
+ @in_block = 'comment'
+ until m = /\*\//.match(@line)
+ next_line
+ end
+ @line = m.post_match
+ @in_block = nil
+ end
+
+ $raccs_print_type = false
+
+ def scan_action
+ buf = String.new
+ nest = 1
+ pre = nil
+ @in_block = 'action'
+ begin
+ pre = nil
+ if s = reads(/\A\s+/)
+ # does not set 'pre'
+ buf << s
+ end
+ until @line.empty?
+ if s = reads(/\A[^'"`{}%#\/\$]+/)
+ buf << (pre = s)
+ next
+ end
+ case ch = read(1)
+ when '{'
+ nest += 1
+ buf << (pre = ch)
+ when '}'
+ nest -= 1
+ if nest == 0
+ @in_block = nil
+ buf.sub!(/[ \t\f]+\z/, '')
+ return buf
+ end
+ buf << (pre = ch)
+ when '#' # comment
+ buf << ch << @line
+ break
+ when "'", '"', '`'
+ buf << (pre = scan_quoted(ch))
+ when '%'
+ if literal_head? pre, @line
+ # % string, regexp, array
+ buf << ch
+ case ch = read(1)
+ when /[qQx]/n
+ buf << ch << (pre = scan_quoted(read(1), '%string'))
+ when /wW/n
+ buf << ch << (pre = scan_quoted(read(1), '%array'))
+ when /s/n
+ buf << ch << (pre = scan_quoted(read(1), '%symbol'))
+ when /r/n
+ buf << ch << (pre = scan_quoted(read(1), '%regexp'))
+ when /[a-zA-Z0-9= ]/n # does not include "_"
+ scan_error! "unknown type of % literal '%#{ch}'"
+ else
+ buf << (pre = scan_quoted(ch, '%string'))
+ end
+ else
+ # operator
+ buf << '||op->' if $raccs_print_type
+ buf << (pre = ch)
+ end
+ when '/'
+ if literal_head? pre, @line
+ # regexp
+ buf << (pre = scan_quoted(ch, 'regexp'))
+ else
+ # operator
+ buf << '||op->' if $raccs_print_type
+ buf << (pre = ch)
+ end
+ when '$' # gvar
+ buf << ch << (pre = read(1))
+ else
+ raise 'racc: fatal: must not happen'
+ end
+ end
+ buf << "\n"
+ end while next_line()
+ raise 'racc: fatal: scan finished before parser finished'
+ end
+
+ def literal_head?(pre, post)
+ (!pre || /[a-zA-Z_0-9]/n !~ pre[-1,1]) &&
+ !post.empty? && /\A[\s\=]/n !~ post
+ end
+
+ def read(len)
+ s = @line[0, len]
+ @line = @line[len .. -1]
+ s
+ end
+
+ def reads(re)
+ m = re.match(@line) or return nil
+ @line = m.post_match
+ m[0]
+ end
+
+ def scan_quoted(left, tag = 'string')
+ buf = left.dup
+ buf = "||#{tag}->" + buf if $raccs_print_type
+ re = get_quoted_re(left)
+ sv, @in_block = @in_block, tag
+ begin
+ if s = reads(re)
+ buf << s
+ break
+ else
+ buf << @line
+ end
+ end while next_line()
+ @in_block = sv
+ buf << "<-#{tag}||" if $raccs_print_type
+ buf
+ end
+
+ LEFT_TO_RIGHT = {
+ '(' => ')',
+ '{' => '}',
+ '[' => ']',
+ '<' => '>'
+ }
+
+ CACHE = {}
+
+ def get_quoted_re(left)
+ term = Regexp.quote(LEFT_TO_RIGHT[left] || left)
+ CACHE[left] ||= /\A[^#{term}\\]*(?:\\.[^\\#{term}]*)*#{term}/
+ end
+
+ def scan_error!(msg)
+ raise CompileError, "#{lineno()}: #{msg}"
+ end
+
+ end
+
+end # module Racc
diff --git a/lib/racc/info.rb b/lib/racc/info.rb
new file mode 100644
index 0000000000..37bff7edba
--- /dev/null
+++ b/lib/racc/info.rb
@@ -0,0 +1,17 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+ VERSION = '1.6.2'
+ Version = VERSION
+ Copyright = 'Copyright (c) 1999-2006 Minero Aoki'
+end
diff --git a/lib/racc/iset.rb b/lib/racc/iset.rb
new file mode 100644
index 0000000000..339221d21b
--- /dev/null
+++ b/lib/racc/iset.rb
@@ -0,0 +1,92 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ # An "indexed" set. All items must respond to :ident.
+ class ISet
+
+ def initialize(a = [])
+ @set = a
+ end
+
+ attr_reader :set
+
+ def add(i)
+ @set[i.ident] = i
+ end
+
+ def [](key)
+ @set[key.ident]
+ end
+
+ def []=(key, val)
+ @set[key.ident] = val
+ end
+
+ alias include? []
+ alias key? []
+
+ def update(other)
+ s = @set
+ o = other.set
+ o.each_index do |idx|
+ if t = o[idx]
+ s[idx] = t
+ end
+ end
+ end
+
+ def update_a(a)
+ s = @set
+ a.each {|i| s[i.ident] = i }
+ end
+
+ def delete(key)
+ i = @set[key.ident]
+ @set[key.ident] = nil
+ i
+ end
+
+ def each(&block)
+ @set.compact.each(&block)
+ end
+
+ def to_a
+ @set.compact
+ end
+
+ def to_s
+ "[#{@set.compact.join(' ')}]"
+ end
+
+ alias inspect to_s
+
+ def size
+ @set.nitems
+ end
+
+ def empty?
+ @set.nitems == 0
+ end
+
+ def clear
+ @set.clear
+ end
+
+ def dup
+ ISet.new(@set.dup)
+ end
+
+ end # class ISet
+
+end # module Racc
diff --git a/lib/racc/logfilegenerator.rb b/lib/racc/logfilegenerator.rb
new file mode 100644
index 0000000000..2f5aa0c8b0
--- /dev/null
+++ b/lib/racc/logfilegenerator.rb
@@ -0,0 +1,212 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ class LogFileGenerator
+
+ def initialize(states, debug_flags = DebugFlags.new)
+ @states = states
+ @grammar = states.grammar
+ @debug_flags = debug_flags
+ end
+
+ def output(out)
+ output_conflict out; out.puts
+ output_useless out; out.puts
+ output_rule out; out.puts
+ output_token out; out.puts
+ output_state out
+ end
+
+ #
+ # Warnings
+ #
+
+ def output_conflict(out)
+ @states.each do |state|
+ if state.srconf
+ out.printf "state %d contains %d shift/reduce conflicts\n",
+ state.stateid, state.srconf.size
+ end
+ if state.rrconf
+ out.printf "state %d contains %d reduce/reduce conflicts\n",
+ state.stateid, state.rrconf.size
+ end
+ end
+ end
+
+ def output_useless(out)
+ @grammar.each do |rl|
+ if rl.useless?
+ out.printf "rule %d (%s) never reduced\n",
+ rl.ident, rl.target.to_s
+ end
+ end
+ @grammar.each_nonterminal do |t|
+ if t.useless?
+ out.printf "useless nonterminal %s\n", t.to_s
+ end
+ end
+ end
+
+ #
+ # States
+ #
+
+ def output_state(out)
+ out << "--------- State ---------\n"
+
+ showall = @debug_flags.la || @debug_flags.state
+ @states.each do |state|
+ out << "\nstate #{state.ident}\n\n"
+
+ (showall ? state.closure : state.core).each do |ptr|
+ pointer_out(out, ptr) if ptr.rule.ident != 0 or showall
+ end
+ out << "\n"
+
+ action_out out, state
+ end
+ end
+
+ def pointer_out(out, ptr)
+ buf = sprintf("%4d) %s :", ptr.rule.ident, ptr.rule.target.to_s)
+ ptr.rule.symbols.each_with_index do |tok, idx|
+ buf << ' _' if idx == ptr.index
+ buf << ' ' << tok.to_s
+ end
+ buf << ' _' if ptr.reduce?
+ out.puts buf
+ end
+
+ def action_out(f, state)
+ sr = state.srconf && state.srconf.dup
+ rr = state.rrconf && state.rrconf.dup
+ acts = state.action
+ keys = acts.keys
+ keys.sort! {|a,b| a.ident <=> b.ident }
+
+ [ Shift, Reduce, Error, Accept ].each do |klass|
+ keys.delete_if do |tok|
+ act = acts[tok]
+ if act.kind_of?(klass)
+ outact f, tok, act
+ if sr and c = sr.delete(tok)
+ outsrconf f, c
+ end
+ if rr and c = rr.delete(tok)
+ outrrconf f, c
+ end
+
+ true
+ else
+ false
+ end
+ end
+ end
+ sr.each {|tok, c| outsrconf f, c } if sr
+ rr.each {|tok, c| outrrconf f, c } if rr
+
+ act = state.defact
+ if not act.kind_of?(Error) or @debug_flags.any?
+ outact f, '$default', act
+ end
+
+ f.puts
+ state.goto_table.each do |t, st|
+ if t.nonterminal?
+ f.printf " %-12s go to state %d\n", t.to_s, st.ident
+ end
+ end
+ end
+
+ def outact(f, t, act)
+ case act
+ when Shift
+ f.printf " %-12s shift, and go to state %d\n",
+ t.to_s, act.goto_id
+ when Reduce
+ f.printf " %-12s reduce using rule %d (%s)\n",
+ t.to_s, act.ruleid, act.rule.target.to_s
+ when Accept
+ f.printf " %-12s accept\n", t.to_s
+ when Error
+ f.printf " %-12s error\n", t.to_s
+ else
+ raise "racc: fatal: wrong act for outact: act=#{act}(#{act.class})"
+ end
+ end
+
+ def outsrconf(f, confs)
+ confs.each do |c|
+ r = c.reduce
+ f.printf " %-12s [reduce using rule %d (%s)]\n",
+ c.shift.to_s, r.ident, r.target.to_s
+ end
+ end
+
+ def outrrconf(f, confs)
+ confs.each do |c|
+ r = c.low_prec
+ f.printf " %-12s [reduce using rule %d (%s)]\n",
+ c.token.to_s, r.ident, r.target.to_s
+ end
+ end
+
+ #
+ # Rules
+ #
+
+ def output_rule(out)
+ out.print "-------- Grammar --------\n\n"
+ @grammar.each do |rl|
+ if @debug_flags.any? or rl.ident != 0
+ out.printf "rule %d %s: %s\n",
+ rl.ident, rl.target.to_s, rl.symbols.join(' ')
+ end
+ end
+ end
+
+ #
+ # Tokens
+ #
+
+ def output_token(out)
+ out.print "------- Symbols -------\n\n"
+
+ out.print "**Nonterminals, with rules where they appear\n\n"
+ @grammar.each_nonterminal do |t|
+ tmp = <<SRC
+ %s (%d)
+ on right: %s
+ on left : %s
+SRC
+ out.printf tmp, t.to_s, t.ident,
+ symbol_locations(t.locate).join(' '),
+ symbol_locations(t.heads).join(' ')
+ end
+
+ out.print "\n**Terminals, with rules where they appear\n\n"
+ @grammar.each_terminal do |t|
+ out.printf " %s (%d) %s\n",
+ t.to_s, t.ident, symbol_locations(t.locate).join(' ')
+ end
+ end
+
+ def symbol_locations(locs)
+ locs.map {|loc| loc.rule.ident }.reject {|n| n == 0 }.uniq
+ end
+
+ end
+
+end # module Racc
diff --git a/lib/racc/parser-text.rb b/lib/racc/parser-text.rb
new file mode 100644
index 0000000000..0579f4ce9b
--- /dev/null
+++ b/lib/racc/parser-text.rb
@@ -0,0 +1,637 @@
+module Racc
+ PARSER_TEXT = <<'__end_of_file__'
+# frozen_string_literal: false
+#--
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+#
+# As a special exception, when this code is copied by Racc
+# into a Racc output file, you may use that output file
+# without restriction.
+#++
+
+require 'racc/info'
+
+unless defined?(NotImplementedError)
+ NotImplementedError = NotImplementError # :nodoc:
+end
+
+module Racc
+ class ParseError < StandardError; end
+end
+unless defined?(::ParseError)
+ ParseError = Racc::ParseError # :nodoc:
+end
+
+# Racc is a LALR(1) parser generator.
+# It is written in Ruby itself, and generates Ruby programs.
+#
+# == Command-line Reference
+#
+# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
+# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
+# [-v] [--verbose]
+# [-O<var>filename</var>] [--log-file=<var>filename</var>]
+# [-g] [--debug]
+# [-E] [--embedded]
+# [-l] [--no-line-convert]
+# [-c] [--line-convert-all]
+# [-a] [--no-omit-actions]
+# [-C] [--check-only]
+# [-S] [--output-status]
+# [--version] [--copyright] [--help] <var>grammarfile</var>
+#
+# [+grammarfile+]
+# Racc grammar file. Any extension is permitted.
+# [-o+outfile+, --output-file=+outfile+]
+# A filename for output. default is <+filename+>.tab.rb
+# [-O+filename+, --log-file=+filename+]
+# Place logging output in file +filename+.
+# Default log file name is <+filename+>.output.
+# [-e+rubypath+, --executable=+rubypath+]
+# output executable file(mode 755). where +path+ is the Ruby interpreter.
+# [-v, --verbose]
+# verbose mode. create +filename+.output file, like yacc's y.output file.
+# [-g, --debug]
+# add debug code to parser class. To display debuggin information,
+# use this '-g' option and set @yydebug true in parser class.
+# [-E, --embedded]
+# Output parser which doesn't need runtime files (racc/parser.rb).
+# [-C, --check-only]
+# Check syntax of racc grammar file and quit.
+# [-S, --output-status]
+# Print messages time to time while compiling.
+# [-l, --no-line-convert]
+# turns off line number converting.
+# [-c, --line-convert-all]
+# Convert line number of actions, inner, header and footer.
+# [-a, --no-omit-actions]
+# Call all actions, even if an action is empty.
+# [--version]
+# print Racc version and quit.
+# [--copyright]
+# Print copyright and quit.
+# [--help]
+# Print usage and quit.
+#
+# == Generating Parser Using Racc
+#
+# To compile Racc grammar file, simply type:
+#
+# $ racc parse.y
+#
+# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
+#
+# == Writing A Racc Grammar File
+#
+# If you want your own parser, you have to write a grammar file.
+# A grammar file contains the name of your parser class, grammar for the parser,
+# user code, and anything else.
+# When writing a grammar file, yacc's knowledge is helpful.
+# If you have not used yacc before, Racc is not too difficult.
+#
+# Here's an example Racc grammar file.
+#
+# class Calcparser
+# rule
+# target: exp { print val[0] }
+#
+# exp: exp '+' exp
+# | exp '*' exp
+# | '(' exp ')'
+# | NUMBER
+# end
+#
+# Racc grammar files resemble yacc files.
+# But (of course), this is Ruby code.
+# yacc's $$ is the 'result', $0, $1... is
+# an array called 'val', and $-1, $-2... is an array called '_values'.
+#
+# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
+# more information on grammar files.
+#
+# == Parser
+#
+# Then you must prepare the parse entry method. There are two types of
+# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
+#
+# Racc::Parser#do_parse is simple.
+#
+# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
+# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
+# EOF is [false, false].
+# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
+# If you want to change this, see the grammar reference.
+#
+# Racc::Parser#yyparse is little complicated, but useful.
+# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
+#
+# For example, <code>yyparse(obj, :scan)</code> causes
+# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
+#
+# == Debugging
+#
+# When debugging, "-v" or/and the "-g" option is helpful.
+#
+# "-v" creates verbose log file (.output).
+# "-g" creates a "Verbose Parser".
+# Verbose Parser prints the internal status when parsing.
+# But it's _not_ automatic.
+# You must use -g option and set +@yydebug+ to +true+ in order to get output.
+# -g option only creates the verbose parser.
+#
+# === Racc reported syntax error.
+#
+# Isn't there too many "end"?
+# grammar of racc file is changed in v0.10.
+#
+# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
+#
+# === Racc reported "XXXX conflicts".
+#
+# Try "racc -v xxxx.y".
+# It causes producing racc's internal log file, xxxx.output.
+#
+# === Generated parsers does not work correctly
+#
+# Try "racc -g xxxx.y".
+# This command let racc generate "debugging parser".
+# Then set @yydebug=true in your parser.
+# It produces a working log of your parser.
+#
+# == Re-distributing Racc runtime
+#
+# A parser, which is created by Racc, requires the Racc runtime module;
+# racc/parser.rb.
+#
+# Ruby 1.8.x comes with Racc runtime module,
+# you need NOT distribute Racc runtime files.
+#
+# If you want to include the Racc runtime module with your parser.
+# This can be done by using '-E' option:
+#
+# $ racc -E -omyparser.rb myparser.y
+#
+# This command creates myparser.rb which `includes' Racc runtime.
+# Only you must do is to distribute your parser file (myparser.rb).
+#
+# Note: parser.rb is ruby license, but your parser is not.
+# Your own parser is completely yours.
+module Racc
+
+ unless defined?(Racc_No_Extensions)
+ Racc_No_Extensions = false # :nodoc:
+ end
+
+ class Parser
+
+ Racc_Runtime_Version = ::Racc::VERSION
+ Racc_Runtime_Core_Version_R = ::Racc::VERSION
+
+ begin
+ if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
+ require 'jruby'
+ require 'racc/cparse-jruby.jar'
+ com.headius.racc.Cparse.new.load(JRuby.runtime, false)
+ else
+ require 'racc/cparse'
+ end
+
+ unless new.respond_to?(:_racc_do_parse_c, true)
+ raise LoadError, 'old cparse.so'
+ end
+ if Racc_No_Extensions
+ raise LoadError, 'selecting ruby version of racc runtime core'
+ end
+
+ Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
+ Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
+ Racc_Runtime_Type = 'c' # :nodoc:
+ rescue LoadError
+ Racc_Main_Parsing_Routine = :_racc_do_parse_rb
+ Racc_YY_Parse_Method = :_racc_yyparse_rb
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
+ Racc_Runtime_Type = 'ruby'
+ end
+
+ def Parser.racc_runtime_type # :nodoc:
+ Racc_Runtime_Type
+ end
+
+ def _racc_setup
+ @yydebug = false unless self.class::Racc_debug_parser
+ @yydebug = false unless defined?(@yydebug)
+ if @yydebug
+ @racc_debug_out = $stderr unless defined?(@racc_debug_out)
+ @racc_debug_out ||= $stderr
+ end
+ arg = self.class::Racc_arg
+ arg[13] = true if arg.size < 14
+ arg
+ end
+
+ def _racc_init_sysvars
+ @racc_state = [0]
+ @racc_tstack = []
+ @racc_vstack = []
+
+ @racc_t = nil
+ @racc_val = nil
+
+ @racc_read_next = true
+
+ @racc_user_yyerror = false
+ @racc_error_status = 0
+ end
+
+ # The entry point of the parser. This method is used with #next_token.
+ # If Racc wants to get token (and its value), calls next_token.
+ #
+ # Example:
+ # def parse
+ # @q = [[1,1],
+ # [2,2],
+ # [3,3],
+ # [false, '$']]
+ # do_parse
+ # end
+ #
+ # def next_token
+ # @q.shift
+ # end
+ class_eval %{
+ def do_parse
+ #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
+ end
+ }
+
+ # The method to fetch next token.
+ # If you use #do_parse method, you must implement #next_token.
+ #
+ # The format of return value is [TOKEN_SYMBOL, VALUE].
+ # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
+ # for 'IDENT'. ";" (String) for ';'.
+ #
+ # The final symbol (End of file) must be false.
+ def next_token
+ raise NotImplementedError, "#{self.class}\#next_token is not defined"
+ end
+
+ def _racc_do_parse_rb(arg, in_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+ tok = act = i = nil
+
+ catch(:racc_end_parse) {
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ if @racc_read_next
+ if @racc_t != 0 # not EOF
+ tok, @racc_val = next_token()
+ unless tok # EOF
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ racc_read_token(@racc_t, tok, @racc_val) if @yydebug
+ @racc_read_next = false
+ end
+ end
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ else
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ }
+ end
+
+ # Another entry point for the parser.
+ # If you use this method, you must implement RECEIVER#METHOD_ID method.
+ #
+ # RECEIVER#METHOD_ID is a method to get next token.
+ # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
+ class_eval %{
+ def yyparse(recv, mid)
+ #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
+ end
+ }
+
+ def _racc_yyparse_rb(recv, mid, arg, c_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+
+ catch(:racc_end_parse) {
+ until i = action_pointer[@racc_state[-1]]
+ while act = _racc_evalact(action_default[@racc_state[-1]], arg)
+ ;
+ end
+ end
+ recv.__send__(mid) do |tok, val|
+ unless tok
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ @racc_val = val
+ @racc_read_next = false
+
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+
+ while !(i = action_pointer[@racc_state[-1]]) ||
+ ! @racc_read_next ||
+ @racc_t == 0 # $
+ unless i and i += @racc_t and
+ i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ end
+ }
+ end
+
+ ###
+ ### common
+ ###
+
+ def _racc_evalact(act, arg)
+ action_table, action_check, _, action_pointer,
+ _, _, _, _,
+ _, _, _, shift_n,
+ reduce_n, * = arg
+ nerr = 0 # tmp
+
+ if act > 0 and act < shift_n
+ #
+ # shift
+ #
+ if @racc_error_status > 0
+ @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
+ end
+ @racc_vstack.push @racc_val
+ @racc_state.push act
+ @racc_read_next = true
+ if @yydebug
+ @racc_tstack.push @racc_t
+ racc_shift @racc_t, @racc_tstack, @racc_vstack
+ end
+
+ elsif act < 0 and act > -reduce_n
+ #
+ # reduce
+ #
+ code = catch(:racc_jump) {
+ @racc_state.push _racc_do_reduce(arg, act)
+ false
+ }
+ if code
+ case code
+ when 1 # yyerror
+ @racc_user_yyerror = true # user_yyerror
+ return -reduce_n
+ when 2 # yyaccept
+ return shift_n
+ else
+ raise '[Racc Bug] unknown jump code'
+ end
+ end
+
+ elsif act == shift_n
+ #
+ # accept
+ #
+ racc_accept if @yydebug
+ throw :racc_end_parse, @racc_vstack[0]
+
+ elsif act == -reduce_n
+ #
+ # error
+ #
+ case @racc_error_status
+ when 0
+ unless arg[21] # user_yyerror
+ nerr += 1
+ on_error @racc_t, @racc_val, @racc_vstack
+ end
+ when 3
+ if @racc_t == 0 # is $
+ # We're at EOF, and another error occurred immediately after
+ # attempting auto-recovery
+ throw :racc_end_parse, nil
+ end
+ @racc_read_next = true
+ end
+ @racc_user_yyerror = false
+ @racc_error_status = 3
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ i += 1 # error token
+ if i >= 0 and
+ (act = action_table[i]) and
+ action_check[i] == @racc_state[-1]
+ break
+ end
+ end
+ throw :racc_end_parse, nil if @racc_state.size <= 1
+ @racc_state.pop
+ @racc_vstack.pop
+ if @yydebug
+ @racc_tstack.pop
+ racc_e_pop @racc_state, @racc_tstack, @racc_vstack
+ end
+ end
+ return act
+
+ else
+ raise "[Racc Bug] unknown action #{act.inspect}"
+ end
+
+ racc_next_state(@racc_state[-1], @racc_state) if @yydebug
+
+ nil
+ end
+
+ def _racc_do_reduce(arg, act)
+ _, _, _, _,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, _, _,
+ _, use_result, * = arg
+
+ state = @racc_state
+ vstack = @racc_vstack
+ tstack = @racc_tstack
+
+ i = act * -3
+ len = reduce_table[i]
+ reduce_to = reduce_table[i+1]
+ method_id = reduce_table[i+2]
+ void_array = []
+
+ tmp_t = tstack[-len, len] if @yydebug
+ tmp_v = vstack[-len, len]
+ tstack[-len, len] = void_array if @yydebug
+ vstack[-len, len] = void_array
+ state[-len, len] = void_array
+
+ # tstack must be updated AFTER method call
+ if use_result
+ vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
+ else
+ vstack.push __send__(method_id, tmp_v, vstack)
+ end
+ tstack.push reduce_to
+
+ racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
+
+ k1 = reduce_to - nt_base
+ if i = goto_pointer[k1]
+ i += state[-1]
+ if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
+ return curstate
+ end
+ end
+ goto_default[k1]
+ end
+
+ # This method is called when a parse error is found.
+ #
+ # ERROR_TOKEN_ID is an internal ID of token which caused error.
+ # You can get string representation of this ID by calling
+ # #token_to_str.
+ #
+ # ERROR_VALUE is a value of error token.
+ #
+ # value_stack is a stack of symbol values.
+ # DO NOT MODIFY this object.
+ #
+ # This method raises ParseError by default.
+ #
+ # If this method returns, parsers enter "error recovering mode".
+ def on_error(t, val, vstack)
+ raise ParseError, sprintf("\nparse error on value %s (%s)",
+ val.inspect, token_to_str(t) || '?')
+ end
+
+ # Enter error recovering mode.
+ # This method does not call #on_error.
+ def yyerror
+ throw :racc_jump, 1
+ end
+
+ # Exit parser.
+ # Return value is +Symbol_Value_Stack[0]+.
+ def yyaccept
+ throw :racc_jump, 2
+ end
+
+ # Leave error recovering mode.
+ def yyerrok
+ @racc_error_status = 0
+ end
+
+ # For debugging output
+ def racc_read_token(t, tok, val)
+ @racc_debug_out.print 'read '
+ @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
+ @racc_debug_out.puts val.inspect
+ @racc_debug_out.puts
+ end
+
+ def racc_shift(tok, tstack, vstack)
+ @racc_debug_out.puts "shift #{racc_token2str tok}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_reduce(toks, sim, tstack, vstack)
+ out = @racc_debug_out
+ out.print 'reduce '
+ if toks.empty?
+ out.print ' <none>'
+ else
+ toks.each {|t| out.print ' ', racc_token2str(t) }
+ end
+ out.puts " --> #{racc_token2str(sim)}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_accept
+ @racc_debug_out.puts 'accept'
+ @racc_debug_out.puts
+ end
+
+ def racc_e_pop(state, tstack, vstack)
+ @racc_debug_out.puts 'error recovering mode: pop token'
+ racc_print_states state
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_next_state(curstate, state)
+ @racc_debug_out.puts "goto #{curstate}"
+ racc_print_states state
+ @racc_debug_out.puts
+ end
+
+ def racc_print_stacks(t, v)
+ out = @racc_debug_out
+ out.print ' ['
+ t.each_index do |i|
+ out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
+ end
+ out.puts ' ]'
+ end
+
+ def racc_print_states(s)
+ out = @racc_debug_out
+ out.print ' ['
+ s.each {|st| out.print ' ', st }
+ out.puts ' ]'
+ end
+
+ def racc_token2str(tok)
+ self.class::Racc_token_to_s_table[tok] or
+ raise "[Racc Bug] can't convert token #{tok} to string"
+ end
+
+ # Convert internal ID of token symbol to the string.
+ def token_to_str(t)
+ self.class::Racc_token_to_s_table[t]
+ end
+
+ end
+
+end
+
+__end_of_file__
+end
diff --git a/lib/racc/parser.rb b/lib/racc/parser.rb
new file mode 100644
index 0000000000..078bfef3e9
--- /dev/null
+++ b/lib/racc/parser.rb
@@ -0,0 +1,632 @@
+# frozen_string_literal: false
+#--
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+#
+# As a special exception, when this code is copied by Racc
+# into a Racc output file, you may use that output file
+# without restriction.
+#++
+
+require 'racc/info'
+
+unless defined?(NotImplementedError)
+ NotImplementedError = NotImplementError # :nodoc:
+end
+
+module Racc
+ class ParseError < StandardError; end
+end
+unless defined?(::ParseError)
+ ParseError = Racc::ParseError # :nodoc:
+end
+
+# Racc is a LALR(1) parser generator.
+# It is written in Ruby itself, and generates Ruby programs.
+#
+# == Command-line Reference
+#
+# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
+# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
+# [-v] [--verbose]
+# [-O<var>filename</var>] [--log-file=<var>filename</var>]
+# [-g] [--debug]
+# [-E] [--embedded]
+# [-l] [--no-line-convert]
+# [-c] [--line-convert-all]
+# [-a] [--no-omit-actions]
+# [-C] [--check-only]
+# [-S] [--output-status]
+# [--version] [--copyright] [--help] <var>grammarfile</var>
+#
+# [+grammarfile+]
+# Racc grammar file. Any extension is permitted.
+# [-o+outfile+, --output-file=+outfile+]
+# A filename for output. default is <+filename+>.tab.rb
+# [-O+filename+, --log-file=+filename+]
+# Place logging output in file +filename+.
+# Default log file name is <+filename+>.output.
+# [-e+rubypath+, --executable=+rubypath+]
+# output executable file(mode 755). where +path+ is the Ruby interpreter.
+# [-v, --verbose]
+# verbose mode. create +filename+.output file, like yacc's y.output file.
+# [-g, --debug]
+# add debug code to parser class. To display debuggin information,
+# use this '-g' option and set @yydebug true in parser class.
+# [-E, --embedded]
+# Output parser which doesn't need runtime files (racc/parser.rb).
+# [-C, --check-only]
+# Check syntax of racc grammar file and quit.
+# [-S, --output-status]
+# Print messages time to time while compiling.
+# [-l, --no-line-convert]
+# turns off line number converting.
+# [-c, --line-convert-all]
+# Convert line number of actions, inner, header and footer.
+# [-a, --no-omit-actions]
+# Call all actions, even if an action is empty.
+# [--version]
+# print Racc version and quit.
+# [--copyright]
+# Print copyright and quit.
+# [--help]
+# Print usage and quit.
+#
+# == Generating Parser Using Racc
+#
+# To compile Racc grammar file, simply type:
+#
+# $ racc parse.y
+#
+# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
+#
+# == Writing A Racc Grammar File
+#
+# If you want your own parser, you have to write a grammar file.
+# A grammar file contains the name of your parser class, grammar for the parser,
+# user code, and anything else.
+# When writing a grammar file, yacc's knowledge is helpful.
+# If you have not used yacc before, Racc is not too difficult.
+#
+# Here's an example Racc grammar file.
+#
+# class Calcparser
+# rule
+# target: exp { print val[0] }
+#
+# exp: exp '+' exp
+# | exp '*' exp
+# | '(' exp ')'
+# | NUMBER
+# end
+#
+# Racc grammar files resemble yacc files.
+# But (of course), this is Ruby code.
+# yacc's $$ is the 'result', $0, $1... is
+# an array called 'val', and $-1, $-2... is an array called '_values'.
+#
+# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
+# more information on grammar files.
+#
+# == Parser
+#
+# Then you must prepare the parse entry method. There are two types of
+# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
+#
+# Racc::Parser#do_parse is simple.
+#
+# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
+# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
+# EOF is [false, false].
+# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
+# If you want to change this, see the grammar reference.
+#
+# Racc::Parser#yyparse is little complicated, but useful.
+# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
+#
+# For example, <code>yyparse(obj, :scan)</code> causes
+# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
+#
+# == Debugging
+#
+# When debugging, "-v" or/and the "-g" option is helpful.
+#
+# "-v" creates verbose log file (.output).
+# "-g" creates a "Verbose Parser".
+# Verbose Parser prints the internal status when parsing.
+# But it's _not_ automatic.
+# You must use -g option and set +@yydebug+ to +true+ in order to get output.
+# -g option only creates the verbose parser.
+#
+# === Racc reported syntax error.
+#
+# Isn't there too many "end"?
+# grammar of racc file is changed in v0.10.
+#
+# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
+#
+# === Racc reported "XXXX conflicts".
+#
+# Try "racc -v xxxx.y".
+# It causes producing racc's internal log file, xxxx.output.
+#
+# === Generated parsers does not work correctly
+#
+# Try "racc -g xxxx.y".
+# This command let racc generate "debugging parser".
+# Then set @yydebug=true in your parser.
+# It produces a working log of your parser.
+#
+# == Re-distributing Racc runtime
+#
+# A parser, which is created by Racc, requires the Racc runtime module;
+# racc/parser.rb.
+#
+# Ruby 1.8.x comes with Racc runtime module,
+# you need NOT distribute Racc runtime files.
+#
+# If you want to include the Racc runtime module with your parser.
+# This can be done by using '-E' option:
+#
+# $ racc -E -omyparser.rb myparser.y
+#
+# This command creates myparser.rb which `includes' Racc runtime.
+# Only you must do is to distribute your parser file (myparser.rb).
+#
+# Note: parser.rb is ruby license, but your parser is not.
+# Your own parser is completely yours.
+module Racc
+
+ unless defined?(Racc_No_Extensions)
+ Racc_No_Extensions = false # :nodoc:
+ end
+
+ class Parser
+
+ Racc_Runtime_Version = ::Racc::VERSION
+ Racc_Runtime_Core_Version_R = ::Racc::VERSION
+
+ begin
+ if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
+ require 'jruby'
+ require 'racc/cparse-jruby.jar'
+ com.headius.racc.Cparse.new.load(JRuby.runtime, false)
+ else
+ require 'racc/cparse'
+ end
+
+ unless new.respond_to?(:_racc_do_parse_c, true)
+ raise LoadError, 'old cparse.so'
+ end
+ if Racc_No_Extensions
+ raise LoadError, 'selecting ruby version of racc runtime core'
+ end
+
+ Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
+ Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
+ Racc_Runtime_Type = 'c' # :nodoc:
+ rescue LoadError
+ Racc_Main_Parsing_Routine = :_racc_do_parse_rb
+ Racc_YY_Parse_Method = :_racc_yyparse_rb
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
+ Racc_Runtime_Type = 'ruby'
+ end
+
+ def Parser.racc_runtime_type # :nodoc:
+ Racc_Runtime_Type
+ end
+
+ def _racc_setup
+ @yydebug = false unless self.class::Racc_debug_parser
+ @yydebug = false unless defined?(@yydebug)
+ if @yydebug
+ @racc_debug_out = $stderr unless defined?(@racc_debug_out)
+ @racc_debug_out ||= $stderr
+ end
+ arg = self.class::Racc_arg
+ arg[13] = true if arg.size < 14
+ arg
+ end
+
+ def _racc_init_sysvars
+ @racc_state = [0]
+ @racc_tstack = []
+ @racc_vstack = []
+
+ @racc_t = nil
+ @racc_val = nil
+
+ @racc_read_next = true
+
+ @racc_user_yyerror = false
+ @racc_error_status = 0
+ end
+
+ # The entry point of the parser. This method is used with #next_token.
+ # If Racc wants to get token (and its value), calls next_token.
+ #
+ # Example:
+ # def parse
+ # @q = [[1,1],
+ # [2,2],
+ # [3,3],
+ # [false, '$']]
+ # do_parse
+ # end
+ #
+ # def next_token
+ # @q.shift
+ # end
+ class_eval %{
+ def do_parse
+ #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
+ end
+ }
+
+ # The method to fetch next token.
+ # If you use #do_parse method, you must implement #next_token.
+ #
+ # The format of return value is [TOKEN_SYMBOL, VALUE].
+ # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
+ # for 'IDENT'. ";" (String) for ';'.
+ #
+ # The final symbol (End of file) must be false.
+ def next_token
+ raise NotImplementedError, "#{self.class}\#next_token is not defined"
+ end
+
+ def _racc_do_parse_rb(arg, in_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+ tok = act = i = nil
+
+ catch(:racc_end_parse) {
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ if @racc_read_next
+ if @racc_t != 0 # not EOF
+ tok, @racc_val = next_token()
+ unless tok # EOF
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ racc_read_token(@racc_t, tok, @racc_val) if @yydebug
+ @racc_read_next = false
+ end
+ end
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ else
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ }
+ end
+
+ # Another entry point for the parser.
+ # If you use this method, you must implement RECEIVER#METHOD_ID method.
+ #
+ # RECEIVER#METHOD_ID is a method to get next token.
+ # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
+ class_eval %{
+ def yyparse(recv, mid)
+ #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
+ end
+ }
+
+ def _racc_yyparse_rb(recv, mid, arg, c_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+
+ catch(:racc_end_parse) {
+ until i = action_pointer[@racc_state[-1]]
+ while act = _racc_evalact(action_default[@racc_state[-1]], arg)
+ ;
+ end
+ end
+ recv.__send__(mid) do |tok, val|
+ unless tok
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ @racc_val = val
+ @racc_read_next = false
+
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+
+ while !(i = action_pointer[@racc_state[-1]]) ||
+ ! @racc_read_next ||
+ @racc_t == 0 # $
+ unless i and i += @racc_t and
+ i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ end
+ }
+ end
+
+ ###
+ ### common
+ ###
+
+ def _racc_evalact(act, arg)
+ action_table, action_check, _, action_pointer,
+ _, _, _, _,
+ _, _, _, shift_n,
+ reduce_n, * = arg
+ nerr = 0 # tmp
+
+ if act > 0 and act < shift_n
+ #
+ # shift
+ #
+ if @racc_error_status > 0
+ @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
+ end
+ @racc_vstack.push @racc_val
+ @racc_state.push act
+ @racc_read_next = true
+ if @yydebug
+ @racc_tstack.push @racc_t
+ racc_shift @racc_t, @racc_tstack, @racc_vstack
+ end
+
+ elsif act < 0 and act > -reduce_n
+ #
+ # reduce
+ #
+ code = catch(:racc_jump) {
+ @racc_state.push _racc_do_reduce(arg, act)
+ false
+ }
+ if code
+ case code
+ when 1 # yyerror
+ @racc_user_yyerror = true # user_yyerror
+ return -reduce_n
+ when 2 # yyaccept
+ return shift_n
+ else
+ raise '[Racc Bug] unknown jump code'
+ end
+ end
+
+ elsif act == shift_n
+ #
+ # accept
+ #
+ racc_accept if @yydebug
+ throw :racc_end_parse, @racc_vstack[0]
+
+ elsif act == -reduce_n
+ #
+ # error
+ #
+ case @racc_error_status
+ when 0
+ unless arg[21] # user_yyerror
+ nerr += 1
+ on_error @racc_t, @racc_val, @racc_vstack
+ end
+ when 3
+ if @racc_t == 0 # is $
+ # We're at EOF, and another error occurred immediately after
+ # attempting auto-recovery
+ throw :racc_end_parse, nil
+ end
+ @racc_read_next = true
+ end
+ @racc_user_yyerror = false
+ @racc_error_status = 3
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ i += 1 # error token
+ if i >= 0 and
+ (act = action_table[i]) and
+ action_check[i] == @racc_state[-1]
+ break
+ end
+ end
+ throw :racc_end_parse, nil if @racc_state.size <= 1
+ @racc_state.pop
+ @racc_vstack.pop
+ if @yydebug
+ @racc_tstack.pop
+ racc_e_pop @racc_state, @racc_tstack, @racc_vstack
+ end
+ end
+ return act
+
+ else
+ raise "[Racc Bug] unknown action #{act.inspect}"
+ end
+
+ racc_next_state(@racc_state[-1], @racc_state) if @yydebug
+
+ nil
+ end
+
+ def _racc_do_reduce(arg, act)
+ _, _, _, _,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, _, _,
+ _, use_result, * = arg
+
+ state = @racc_state
+ vstack = @racc_vstack
+ tstack = @racc_tstack
+
+ i = act * -3
+ len = reduce_table[i]
+ reduce_to = reduce_table[i+1]
+ method_id = reduce_table[i+2]
+ void_array = []
+
+ tmp_t = tstack[-len, len] if @yydebug
+ tmp_v = vstack[-len, len]
+ tstack[-len, len] = void_array if @yydebug
+ vstack[-len, len] = void_array
+ state[-len, len] = void_array
+
+ # tstack must be updated AFTER method call
+ if use_result
+ vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
+ else
+ vstack.push __send__(method_id, tmp_v, vstack)
+ end
+ tstack.push reduce_to
+
+ racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
+
+ k1 = reduce_to - nt_base
+ if i = goto_pointer[k1]
+ i += state[-1]
+ if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
+ return curstate
+ end
+ end
+ goto_default[k1]
+ end
+
+ # This method is called when a parse error is found.
+ #
+ # ERROR_TOKEN_ID is an internal ID of token which caused error.
+ # You can get string representation of this ID by calling
+ # #token_to_str.
+ #
+ # ERROR_VALUE is a value of error token.
+ #
+ # value_stack is a stack of symbol values.
+ # DO NOT MODIFY this object.
+ #
+ # This method raises ParseError by default.
+ #
+ # If this method returns, parsers enter "error recovering mode".
+ def on_error(t, val, vstack)
+ raise ParseError, sprintf("\nparse error on value %s (%s)",
+ val.inspect, token_to_str(t) || '?')
+ end
+
+ # Enter error recovering mode.
+ # This method does not call #on_error.
+ def yyerror
+ throw :racc_jump, 1
+ end
+
+ # Exit parser.
+ # Return value is +Symbol_Value_Stack[0]+.
+ def yyaccept
+ throw :racc_jump, 2
+ end
+
+ # Leave error recovering mode.
+ def yyerrok
+ @racc_error_status = 0
+ end
+
+ # For debugging output
+ def racc_read_token(t, tok, val)
+ @racc_debug_out.print 'read '
+ @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
+ @racc_debug_out.puts val.inspect
+ @racc_debug_out.puts
+ end
+
+ def racc_shift(tok, tstack, vstack)
+ @racc_debug_out.puts "shift #{racc_token2str tok}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_reduce(toks, sim, tstack, vstack)
+ out = @racc_debug_out
+ out.print 'reduce '
+ if toks.empty?
+ out.print ' <none>'
+ else
+ toks.each {|t| out.print ' ', racc_token2str(t) }
+ end
+ out.puts " --> #{racc_token2str(sim)}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_accept
+ @racc_debug_out.puts 'accept'
+ @racc_debug_out.puts
+ end
+
+ def racc_e_pop(state, tstack, vstack)
+ @racc_debug_out.puts 'error recovering mode: pop token'
+ racc_print_states state
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_next_state(curstate, state)
+ @racc_debug_out.puts "goto #{curstate}"
+ racc_print_states state
+ @racc_debug_out.puts
+ end
+
+ def racc_print_stacks(t, v)
+ out = @racc_debug_out
+ out.print ' ['
+ t.each_index do |i|
+ out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
+ end
+ out.puts ' ]'
+ end
+
+ def racc_print_states(s)
+ out = @racc_debug_out
+ out.print ' ['
+ s.each {|st| out.print ' ', st }
+ out.puts ' ]'
+ end
+
+ def racc_token2str(tok)
+ self.class::Racc_token_to_s_table[tok] or
+ raise "[Racc Bug] can't convert token #{tok} to string"
+ end
+
+ # Convert internal ID of token symbol to the string.
+ def token_to_str(t)
+ self.class::Racc_token_to_s_table[t]
+ end
+
+ end
+
+end
diff --git a/lib/racc/parserfilegenerator.rb b/lib/racc/parserfilegenerator.rb
new file mode 100644
index 0000000000..7131026929
--- /dev/null
+++ b/lib/racc/parserfilegenerator.rb
@@ -0,0 +1,468 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/compat'
+require 'racc/sourcetext'
+require 'racc/parser-text'
+require 'rbconfig'
+
+module Racc
+
+ class ParserFileGenerator
+
+ class Params
+ def self.bool_attr(name)
+ module_eval(<<-End)
+ def #{name}?
+ @#{name}
+ end
+
+ def #{name}=(b)
+ @#{name} = b
+ end
+ End
+ end
+
+ attr_accessor :filename
+ attr_accessor :classname
+ attr_accessor :superclass
+ bool_attr :omit_action_call
+ bool_attr :result_var
+ attr_accessor :header
+ attr_accessor :inner
+ attr_accessor :footer
+
+ bool_attr :debug_parser
+ bool_attr :convert_line
+ bool_attr :convert_line_all
+ bool_attr :embed_runtime
+ bool_attr :make_executable
+ attr_accessor :interpreter
+
+ def initialize
+ # Parameters derived from parser
+ self.filename = nil
+ self.classname = nil
+ self.superclass = 'Racc::Parser'
+ self.omit_action_call = true
+ self.result_var = true
+ self.header = []
+ self.inner = []
+ self.footer = []
+
+ # Parameters derived from command line options
+ self.debug_parser = false
+ self.convert_line = true
+ self.convert_line_all = false
+ self.embed_runtime = false
+ self.make_executable = false
+ self.interpreter = nil
+ end
+ end
+
+ def initialize(states, params)
+ @states = states
+ @grammar = states.grammar
+ @params = params
+ end
+
+ def generate_parser
+ string_io = StringIO.new
+
+ init_line_conversion_system
+ @f = string_io
+ parser_file
+
+ string_io.rewind
+ string_io.read
+ end
+
+ def generate_parser_file(destpath)
+ init_line_conversion_system
+ File.open(destpath, 'w') {|f|
+ @f = f
+ parser_file
+ }
+ File.chmod 0755, destpath if @params.make_executable?
+ end
+
+ private
+
+ def parser_file
+ shebang @params.interpreter if @params.make_executable?
+ notice
+ line
+ if @params.embed_runtime?
+ embed_library runtime_source()
+ else
+ require 'racc/parser.rb'
+ end
+ header
+ parser_class(@params.classname, @params.superclass) {
+ inner
+ state_transition_table
+ }
+ footer
+ end
+
+ c = ::RbConfig::CONFIG
+ RUBY_PATH = "#{c['bindir']}/#{c['ruby_install_name']}#{c['EXEEXT']}"
+
+ def shebang(path)
+ line '#!' + (path == 'ruby' ? RUBY_PATH : path)
+ end
+
+ def notice
+ line %q[#]
+ line %q[# DO NOT MODIFY!!!!]
+ line %Q[# This file is automatically generated by Racc #{Racc::Version}]
+ line %Q[# from Racc grammar file "#{@params.filename}".]
+ line %q[#]
+ end
+
+ def runtime_source
+ SourceText.new(::Racc::PARSER_TEXT, 'racc/parser.rb', 1)
+ end
+
+ def embed_library(src)
+ line %[###### #{src.filename} begin]
+ line %[unless $".index '#{src.filename}']
+ line %[$".push '#{src.filename}']
+ put src, @params.convert_line?
+ line %[end]
+ line %[###### #{src.filename} end]
+ end
+
+ def require(feature)
+ line "require '#{feature}'"
+ end
+
+ def parser_class(classname, superclass)
+ mods = classname.split('::')
+ classid = mods.pop
+ mods.each do |mod|
+ indent; line "module #{mod}"
+ cref_push mod
+ end
+ indent; line "class #{classid} < #{superclass}"
+ cref_push classid
+ yield
+ cref_pop
+ indent; line "end \# class #{classid}"
+ mods.reverse_each do |mod|
+ cref_pop
+ indent; line "end \# module #{mod}"
+ end
+ end
+
+ def header
+ @params.header.each do |src|
+ line
+ put src, @params.convert_line_all?
+ end
+ end
+
+ def inner
+ @params.inner.each do |src|
+ line
+ put src, @params.convert_line?
+ end
+ end
+
+ def footer
+ @params.footer.each do |src|
+ line
+ put src, @params.convert_line_all?
+ end
+ end
+
+ # Low Level Routines
+
+ def put(src, convert_line = false)
+ if convert_line
+ replace_location(src) {
+ @f.puts src.text
+ }
+ else
+ @f.puts src.text
+ end
+ end
+
+ def line(str = '')
+ @f.puts str
+ end
+
+ def init_line_conversion_system
+ @cref = []
+ @used_separator = {}
+ end
+
+ def cref_push(name)
+ @cref.push name
+ end
+
+ def cref_pop
+ @cref.pop
+ end
+
+ def indent
+ @f.print ' ' * @cref.size
+ end
+
+ def toplevel?
+ @cref.empty?
+ end
+
+ def replace_location(src)
+ sep = make_separator(src)
+ @f.print 'self.class.' if toplevel?
+ @f.puts "module_eval(<<'#{sep}', '#{src.filename}', #{src.lineno})"
+ yield
+ @f.puts sep
+ end
+
+ def make_separator(src)
+ sep = unique_separator(src.filename)
+ sep *= 2 while src.text.index(sep)
+ sep
+ end
+
+ def unique_separator(id)
+ sep = String.new "...end #{id}/module_eval..."
+ while @used_separator.key?(sep)
+ sep.concat sprintf('%02x', rand(255))
+ end
+ @used_separator[sep] = true
+ sep
+ end
+
+ #
+ # State Transition Table Serialization
+ #
+
+ public
+
+ def put_state_transition_table(f)
+ @f = f
+ state_transition_table
+ end
+
+ private
+
+ def state_transition_table
+ table = @states.state_transition_table
+ table.use_result_var = @params.result_var?
+ table.debug_parser = @params.debug_parser?
+
+ line "##### State transition tables begin ###"
+ line
+ integer_list 'racc_action_table', table.action_table
+ line
+ integer_list 'racc_action_check', table.action_check
+ line
+ integer_list 'racc_action_pointer', table.action_pointer
+ line
+ integer_list 'racc_action_default', table.action_default
+ line
+ integer_list 'racc_goto_table', table.goto_table
+ line
+ integer_list 'racc_goto_check', table.goto_check
+ line
+ integer_list 'racc_goto_pointer', table.goto_pointer
+ line
+ integer_list 'racc_goto_default', table.goto_default
+ line
+ i_i_sym_list 'racc_reduce_table', table.reduce_table
+ line
+ line "racc_reduce_n = #{table.reduce_n}"
+ line
+ line "racc_shift_n = #{table.shift_n}"
+ line
+ sym_int_hash 'racc_token_table', table.token_table
+ line
+ line "racc_nt_base = #{table.nt_base}"
+ line
+ line "racc_use_result_var = #{table.use_result_var}"
+ line
+ @f.print(unindent_auto(<<-End))
+ Racc_arg = [
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
+ End
+ line
+ string_list 'Racc_token_to_s_table', table.token_to_s_table
+ line
+ line "Racc_debug_parser = #{table.debug_parser}"
+ line
+ line '##### State transition tables end #####'
+ actions
+ end
+
+ def integer_list(name, table)
+ sep = ''
+ line "#{name} = ["
+ table.each_slice(10) do |ns|
+ @f.print sep; sep = ",\n"
+ @f.print ns.map {|n| sprintf('%6s', n ? n.to_s : 'nil') }.join(',')
+ end
+ line ' ]'
+ end
+
+ def i_i_sym_list(name, table)
+ sep = ''
+ line "#{name} = ["
+ table.each_slice(3) do |len, target, mid|
+ @f.print sep; sep = ",\n"
+ @f.printf ' %d, %d, %s', len, target, mid.inspect
+ end
+ line " ]"
+ end
+
+ def sym_int_hash(name, h)
+ sep = "\n"
+ @f.print "#{name} = {"
+ h.to_a.sort_by {|sym, i| i }.each do |sym, i|
+ @f.print sep; sep = ",\n"
+ @f.printf " %s => %d", sym.serialize, i
+ end
+ line " }"
+ end
+
+ def string_list(name, list)
+ sep = " "
+ line "#{name} = ["
+ list.each do |s|
+ @f.print sep; sep = ",\n "
+ @f.print s.dump
+ end
+ line ' ]'
+ end
+
+ def actions
+ @grammar.each do |rule|
+ unless rule.action.source?
+ raise "racc: fatal: cannot generate parser file when any action is a Proc"
+ end
+ end
+
+ if @params.result_var?
+ decl = ', result'
+ retval = "\n result"
+ default_body = ''
+ else
+ decl = ''
+ retval = ''
+ default_body = 'val[0]'
+ end
+ @grammar.each do |rule|
+ line
+ if rule.action.empty? and @params.omit_action_call?
+ line "# reduce #{rule.ident} omitted"
+ else
+ src0 = rule.action.source || SourceText.new(default_body, __FILE__, 0)
+ if @params.convert_line?
+ src = remove_blank_lines(src0)
+ delim = make_delimiter(src.text)
+ @f.printf unindent_auto(<<-End),
+ module_eval(<<'%s', '%s', %d)
+ def _reduce_%d(val, _values%s)
+ %s%s
+ end
+ %s
+ End
+ delim, src.filename, src.lineno - 1,
+ rule.ident, decl,
+ src.text, retval,
+ delim
+ else
+ src = remove_blank_lines(src0)
+ @f.printf unindent_auto(<<-End),
+ def _reduce_%d(val, _values%s)
+ %s%s
+ end
+ End
+ rule.ident, decl,
+ src.text, retval
+ end
+ end
+ end
+ line
+ @f.printf unindent_auto(<<-'End'), decl
+ def _reduce_none(val, _values%s)
+ val[0]
+ end
+ End
+ line
+ end
+
+ def remove_blank_lines(src)
+ body = src.text.dup
+ line = src.lineno
+ while body.slice!(/\A[ \t\f]*(?:\n|\r\n|\r)/)
+ line += 1
+ end
+ SourceText.new(body, src.filename, line)
+ end
+
+ def make_delimiter(body)
+ delim = '.,.,'
+ while body.index(delim)
+ delim *= 2
+ end
+ delim
+ end
+
+ def unindent_auto(str)
+ lines = str.lines.to_a
+ n = minimum_indent(lines)
+ lines.map {|line| detab(line).sub(indent_re(n), '').rstrip + "\n" }.join('')
+ end
+
+ def minimum_indent(lines)
+ lines.map {|line| n_indent(line) }.min
+ end
+
+ def n_indent(line)
+ line.slice(/\A\s+/).size
+ end
+
+ RE_CACHE = {}
+
+ def indent_re(n)
+ RE_CACHE[n] ||= /\A {#{n}}/
+ end
+
+ def detab(str, ts = 8)
+ add = 0
+ len = nil
+ str.gsub(/\t/) {
+ len = ts - ($`.size + add) % ts
+ add += len - 1
+ ' ' * len
+ }
+ end
+
+ end
+
+end
diff --git a/lib/racc/racc.gemspec b/lib/racc/racc.gemspec
new file mode 100644
index 0000000000..1095c8f47e
--- /dev/null
+++ b/lib/racc/racc.gemspec
@@ -0,0 +1,58 @@
+# -*- encoding: utf-8 -*-
+
+begin
+ require_relative "lib/racc/info"
+rescue LoadError # Fallback to load version file in ruby core repository
+ require_relative "info"
+end
+
+Gem::Specification.new do |s|
+ s.name = "racc"
+ s.version = Racc::VERSION
+ s.summary = "Racc is a LALR(1) parser generator"
+ s.description = <<DESC
+Racc is a LALR(1) parser generator.
+ It is written in Ruby itself, and generates Ruby program.
+
+ NOTE: Ruby 1.8.x comes with Racc runtime module. You
+ can run your parsers generated by racc 1.4.x out of the
+ box.
+DESC
+ s.authors = ["Minero Aoki", "Aaron Patterson"]
+ s.email = [nil, "aaron@tenderlovemaking.com"]
+ s.homepage = "https://github.com/ruby/racc"
+ s.licenses = ["Ruby", "BSD-2-Clause"]
+ s.executables = ["racc"]
+ s.files = [
+ "COPYING", "ChangeLog", "TODO",
+ "README.ja.rdoc", "README.rdoc", "bin/racc",
+ "ext/racc/MANIFEST",
+ "ext/racc/cparse/cparse.c",
+ "ext/racc/cparse/extconf.rb",
+ "lib/racc.rb", "lib/racc/compat.rb",
+ "lib/racc/debugflags.rb", "lib/racc/exception.rb",
+ "lib/racc/grammar.rb", "lib/racc/grammarfileparser.rb",
+ "lib/racc/info.rb", "lib/racc/iset.rb",
+ "lib/racc/logfilegenerator.rb", "lib/racc/parser-text.rb",
+ "lib/racc/parser.rb", "lib/racc/parserfilegenerator.rb",
+ "lib/racc/sourcetext.rb",
+ "lib/racc/state.rb", "lib/racc/statetransitiontable.rb",
+ "lib/racc/static.rb",
+ "doc/en/NEWS.en.rdoc", "doc/en/grammar2.en.rdoc",
+ "doc/en/grammar.en.rdoc", "doc/ja/NEWS.ja.rdoc",
+ "doc/ja/command.ja.html", "doc/ja/debug.ja.rdoc",
+ "doc/ja/grammar.ja.rdoc", "doc/ja/index.ja.html",
+ "doc/ja/parser.ja.rdoc", "doc/ja/usage.ja.html",
+ ]
+ s.require_paths = ["lib"]
+ s.required_ruby_version = ">= 2.5"
+ s.rdoc_options = ["--main", "README.rdoc"]
+ s.extra_rdoc_files = ["README.ja.rdoc", "README.rdoc"]
+
+ if RUBY_PLATFORM =~ /java/
+ s.files << 'lib/racc/cparse-jruby.jar'
+ s.platform = 'java'
+ else
+ s.extensions = ["ext/racc/cparse/extconf.rb"]
+ end
+end
diff --git a/lib/racc/sourcetext.rb b/lib/racc/sourcetext.rb
new file mode 100644
index 0000000000..de52dcae9b
--- /dev/null
+++ b/lib/racc/sourcetext.rb
@@ -0,0 +1,35 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ class SourceText
+ def initialize(text, filename, lineno)
+ @text = text
+ @filename = filename
+ @lineno = lineno
+ end
+
+ attr_reader :text
+ attr_reader :filename
+ attr_reader :lineno
+
+ def to_s
+ "#<SourceText #{location()}>"
+ end
+
+ def location
+ "#{@filename}:#{@lineno}"
+ end
+ end
+
+end
diff --git a/lib/racc/state.rb b/lib/racc/state.rb
new file mode 100644
index 0000000000..f85809fbeb
--- /dev/null
+++ b/lib/racc/state.rb
@@ -0,0 +1,972 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/iset'
+require 'racc/statetransitiontable'
+require 'racc/exception'
+require 'forwardable'
+
+module Racc
+
+ # A table of LALR states.
+ class States
+
+ include Enumerable
+
+ def initialize(grammar, debug_flags = DebugFlags.new)
+ @grammar = grammar
+ @symboltable = grammar.symboltable
+ @d_state = debug_flags.state
+ @d_la = debug_flags.la
+ @d_prec = debug_flags.prec
+ @states = []
+ @statecache = {}
+ @actions = ActionTable.new(@grammar, self)
+ @nfa_computed = false
+ @dfa_computed = false
+ end
+
+ attr_reader :grammar
+ attr_reader :actions
+
+ def size
+ @states.size
+ end
+
+ def inspect
+ '#<state table>'
+ end
+
+ alias to_s inspect
+
+ def [](i)
+ @states[i]
+ end
+
+ def each_state(&block)
+ @states.each(&block)
+ end
+
+ alias each each_state
+
+ def each_index(&block)
+ @states.each_index(&block)
+ end
+
+ extend Forwardable
+
+ def_delegator "@actions", :shift_n
+ def_delegator "@actions", :reduce_n
+ def_delegator "@actions", :nt_base
+
+ def should_report_srconflict?
+ srconflict_exist? and
+ (n_srconflicts() != @grammar.n_expected_srconflicts)
+ end
+
+ def srconflict_exist?
+ n_srconflicts() != 0
+ end
+
+ def n_srconflicts
+ @n_srconflicts ||= inject(0) {|sum, st| sum + st.n_srconflicts }
+ end
+
+ def rrconflict_exist?
+ n_rrconflicts() != 0
+ end
+
+ def n_rrconflicts
+ @n_rrconflicts ||= inject(0) {|sum, st| sum + st.n_rrconflicts }
+ end
+
+ def state_transition_table
+ @state_transition_table ||= StateTransitionTable.generate(self.dfa)
+ end
+
+ #
+ # NFA (Non-deterministic Finite Automaton) Computation
+ #
+
+ public
+
+ def nfa
+ return self if @nfa_computed
+ compute_nfa
+ @nfa_computed = true
+ self
+ end
+
+ private
+
+ def compute_nfa
+ @grammar.init
+ # add state 0
+ core_to_state [ @grammar[0].ptrs[0] ]
+ # generate LALR states
+ cur = 0
+ @gotos = []
+ while cur < @states.size
+ generate_states @states[cur] # state is added here
+ cur += 1
+ end
+ @actions.init
+ end
+
+ def generate_states(state)
+ puts "dstate: #{state}" if @d_state
+
+ table = {}
+ state.closure.each do |ptr|
+ if sym = ptr.dereference
+ addsym table, sym, ptr.next
+ end
+ end
+ table.each do |sym, core|
+ puts "dstate: sym=#{sym} ncore=#{core}" if @d_state
+
+ dest = core_to_state(core.to_a)
+ state.goto_table[sym] = dest
+ id = sym.nonterminal?() ? @gotos.size : nil
+ g = Goto.new(id, sym, state, dest)
+ @gotos.push g if sym.nonterminal?
+ state.gotos[sym] = g
+ puts "dstate: #{state.ident} --#{sym}--> #{dest.ident}" if @d_state
+
+ # check infinite recursion
+ if state.ident == dest.ident and state.closure.size == 1
+ raise CompileError,
+ sprintf("Infinite recursion: state %d, with rule %d",
+ state.ident, state.ptrs[0].rule.ident)
+ end
+ end
+ end
+
+ def addsym(table, sym, ptr)
+ unless s = table[sym]
+ table[sym] = s = ISet.new
+ end
+ s.add ptr
+ end
+
+ def core_to_state(core)
+ #
+ # convert CORE to a State object.
+ # If matching state does not exist, create it and add to the table.
+ #
+
+ k = fingerprint(core)
+ unless dest = @statecache[k]
+ # not registered yet
+ dest = State.new(@states.size, core)
+ @states.push dest
+
+ @statecache[k] = dest
+
+ puts "core_to_state: create state ID #{dest.ident}" if @d_state
+ else
+ if @d_state
+ puts "core_to_state: dest is cached ID #{dest.ident}"
+ puts "core_to_state: dest core #{dest.core.join(' ')}"
+ end
+ end
+
+ dest
+ end
+
+ def fingerprint(arr)
+ arr.map {|i| i.ident }.pack('L*')
+ end
+
+ #
+ # DFA (Deterministic Finite Automaton) Generation
+ #
+
+ public
+
+ def dfa
+ return self if @dfa_computed
+ nfa
+ compute_dfa
+ @dfa_computed = true
+ self
+ end
+
+ private
+
+ def compute_dfa
+ la = lookahead()
+ @states.each do |state|
+ state.la = la
+ resolve state
+ end
+ set_accept
+ @states.each do |state|
+ pack state
+ end
+ check_useless
+ end
+
+ def lookahead
+ #
+ # lookahead algorithm ver.3 -- from bison 1.26
+ #
+
+ gotos = @gotos
+ if @d_la
+ puts "\n--- goto ---"
+ gotos.each_with_index {|g, i| print i, ' '; p g }
+ end
+
+ ### initialize_LA()
+ ### set_goto_map()
+ la_rules = []
+ @states.each do |state|
+ state.check_la la_rules
+ end
+
+ ### initialize_F()
+ f = create_tmap(gotos.size)
+ reads = []
+ edge = []
+ gotos.each do |goto|
+ goto.to_state.goto_table.each do |t, st|
+ if t.terminal?
+ f[goto.ident] |= (1 << t.ident)
+ elsif t.nullable?
+ edge.push goto.to_state.gotos[t].ident
+ end
+ end
+ if edge.empty?
+ reads.push nil
+ else
+ reads.push edge
+ edge = []
+ end
+ end
+ digraph f, reads
+ if @d_la
+ puts "\n--- F1 (reads) ---"
+ print_tab gotos, reads, f
+ end
+
+ ### build_relations()
+ ### compute_FOLLOWS
+ path = nil
+ edge = []
+ lookback = Array.new(la_rules.size, nil)
+ includes = []
+ gotos.each do |goto|
+ goto.symbol.heads.each do |ptr|
+ path = record_path(goto.from_state, ptr.rule)
+ lastgoto = path.last
+ st = lastgoto ? lastgoto.to_state : goto.from_state
+ if st.conflict?
+ addrel lookback, st.rruleid(ptr.rule), goto
+ end
+ path.reverse_each do |g|
+ break if g.symbol.terminal?
+ edge.push g.ident
+ break unless g.symbol.nullable?
+ end
+ end
+ if edge.empty?
+ includes.push nil
+ else
+ includes.push edge
+ edge = []
+ end
+ end
+ includes = transpose(includes)
+ digraph f, includes
+ if @d_la
+ puts "\n--- F2 (includes) ---"
+ print_tab gotos, includes, f
+ end
+
+ ### compute_lookaheads
+ la = create_tmap(la_rules.size)
+ lookback.each_with_index do |arr, i|
+ if arr
+ arr.each do |g|
+ la[i] |= f[g.ident]
+ end
+ end
+ end
+ if @d_la
+ puts "\n--- LA (lookback) ---"
+ print_tab la_rules, lookback, la
+ end
+
+ la
+ end
+
+ def create_tmap(size)
+ Array.new(size, 0) # use Integer as bitmap
+ end
+
+ def addrel(tbl, i, item)
+ if a = tbl[i]
+ a.push item
+ else
+ tbl[i] = [item]
+ end
+ end
+
+ def record_path(begst, rule)
+ st = begst
+ path = []
+ rule.symbols.each do |t|
+ goto = st.gotos[t]
+ path.push goto
+ st = goto.to_state
+ end
+ path
+ end
+
+ def transpose(rel)
+ new = Array.new(rel.size, nil)
+ rel.each_with_index do |arr, idx|
+ if arr
+ arr.each do |i|
+ addrel new, i, idx
+ end
+ end
+ end
+ new
+ end
+
+ def digraph(map, relation)
+ n = relation.size
+ index = Array.new(n, nil)
+ vertices = []
+ @infinity = n + 2
+
+ index.each_index do |i|
+ if not index[i] and relation[i]
+ traverse i, index, vertices, map, relation
+ end
+ end
+ end
+
+ def traverse(i, index, vertices, map, relation)
+ vertices.push i
+ index[i] = height = vertices.size
+
+ if rp = relation[i]
+ rp.each do |proci|
+ unless index[proci]
+ traverse proci, index, vertices, map, relation
+ end
+ if index[i] > index[proci]
+ # circulative recursion !!!
+ index[i] = index[proci]
+ end
+ map[i] |= map[proci]
+ end
+ end
+
+ if index[i] == height
+ while true
+ proci = vertices.pop
+ index[proci] = @infinity
+ break if i == proci
+
+ map[proci] |= map[i]
+ end
+ end
+ end
+
+ # for debug
+ def print_atab(idx, tab)
+ tab.each_with_index do |i,ii|
+ printf '%-20s', idx[ii].inspect
+ p i
+ end
+ end
+
+ def print_tab(idx, rel, tab)
+ tab.each_with_index do |bin,i|
+ print i, ' ', idx[i].inspect, ' << '; p rel[i]
+ print ' '
+ each_t(@symboltable, bin) {|t| print ' ', t }
+ puts
+ end
+ end
+
+ # for debug
+ def print_tab_i(idx, rel, tab, i)
+ bin = tab[i]
+ print i, ' ', idx[i].inspect, ' << '; p rel[i]
+ print ' '
+ each_t(@symboltable, bin) {|t| print ' ', t }
+ end
+
+ # for debug
+ def printb(i)
+ each_t(@symboltable, i) do |t|
+ print t, ' '
+ end
+ puts
+ end
+
+ def each_t(tbl, set)
+ 0.upto( set.size ) do |i|
+ (0..7).each do |ii|
+ if set[idx = i * 8 + ii] == 1
+ yield tbl[idx]
+ end
+ end
+ end
+ end
+
+ #
+ # resolve
+ #
+
+ def resolve(state)
+ if state.conflict?
+ resolve_rr state, state.ritems
+ resolve_sr state, state.stokens
+ else
+ if state.rrules.empty?
+ # shift
+ state.stokens.each do |t|
+ state.action[t] = @actions.shift(state.goto_table[t])
+ end
+ else
+ # reduce
+ state.defact = @actions.reduce(state.rrules[0])
+ end
+ end
+ end
+
+ def resolve_rr(state, r)
+ r.each do |item|
+ item.each_la(@symboltable) do |t|
+ act = state.action[t]
+ if act
+ unless act.kind_of?(Reduce)
+ raise "racc: fatal: #{act.class} in action table"
+ end
+ # Cannot resolve R/R conflict (on t).
+ # Reduce with upper rule as default.
+ state.rr_conflict act.rule, item.rule, t
+ else
+ # No conflict.
+ state.action[t] = @actions.reduce(item.rule)
+ end
+ end
+ end
+ end
+
+ def resolve_sr(state, s)
+ s.each do |stok|
+ goto = state.goto_table[stok]
+ act = state.action[stok]
+
+ unless act
+ # no conflict
+ state.action[stok] = @actions.shift(goto)
+ else
+ unless act.kind_of?(Reduce)
+ puts 'DEBUG -------------------------------'
+ p stok
+ p act
+ state.action.each do |k,v|
+ print k.inspect, ' ', v.inspect, "\n"
+ end
+ raise "racc: fatal: #{act.class} in action table"
+ end
+
+ # conflict on stok
+
+ rtok = act.rule.precedence
+ case do_resolve_sr(stok, rtok)
+ when :Reduce
+ # action is already set
+
+ when :Shift
+ # overwrite
+ act.decref
+ state.action[stok] = @actions.shift(goto)
+
+ when :Error
+ act.decref
+ state.action[stok] = @actions.error
+
+ when :CantResolve
+ # shift as default
+ act.decref
+ state.action[stok] = @actions.shift(goto)
+ state.sr_conflict stok, act.rule
+ end
+ end
+ end
+ end
+
+ ASSOC = {
+ :Left => :Reduce,
+ :Right => :Shift,
+ :Nonassoc => :Error
+ }
+
+ def do_resolve_sr(stok, rtok)
+ puts "resolve_sr: s/r conflict: rtok=#{rtok}, stok=#{stok}" if @d_prec
+
+ unless rtok and rtok.precedence
+ puts "resolve_sr: no prec for #{rtok}(R)" if @d_prec
+ return :CantResolve
+ end
+ rprec = rtok.precedence
+
+ unless stok and stok.precedence
+ puts "resolve_sr: no prec for #{stok}(S)" if @d_prec
+ return :CantResolve
+ end
+ sprec = stok.precedence
+
+ ret = if rprec == sprec
+ ASSOC[rtok.assoc] or
+ raise "racc: fatal: #{rtok}.assoc is not Left/Right/Nonassoc"
+ else
+ (rprec > sprec) ? (:Reduce) : (:Shift)
+ end
+
+ puts "resolve_sr: resolved as #{ret.id2name}" if @d_prec
+ ret
+ end
+
+ #
+ # complete
+ #
+
+ def set_accept
+ anch = @symboltable.anchor
+ init_state = @states[0].goto_table[@grammar.start]
+ targ_state = init_state.action[anch].goto_state
+ acc_state = targ_state.action[anch].goto_state
+
+ acc_state.action.clear
+ acc_state.goto_table.clear
+ acc_state.defact = @actions.accept
+ end
+
+ def pack(state)
+ ### find most frequently used reduce rule
+ act = state.action
+ arr = Array.new(@grammar.size, 0)
+ act.each do |t, a|
+ arr[a.ruleid] += 1 if a.kind_of?(Reduce)
+ end
+ i = arr.max
+ s = (i > 0) ? arr.index(i) : nil
+
+ ### set & delete default action
+ if s
+ r = @actions.reduce(s)
+ if not state.defact or state.defact == r
+ act.delete_if {|t, a| a == r }
+ state.defact = r
+ end
+ else
+ state.defact ||= @actions.error
+ end
+ end
+
+ def check_useless
+ used = []
+ @actions.each_reduce do |act|
+ if not act or act.refn == 0
+ act.rule.useless = true
+ else
+ t = act.rule.target
+ used[t.ident] = t
+ end
+ end
+ @symboltable.nt_base.upto(@symboltable.nt_max - 1) do |n|
+ unless used[n]
+ @symboltable[n].useless = true
+ end
+ end
+ end
+
+ end # class StateTable
+
+
+ # A LALR state.
+ class State
+
+ def initialize(ident, core)
+ @ident = ident
+ @core = core
+ @goto_table = {}
+ @gotos = {}
+ @stokens = nil
+ @ritems = nil
+ @action = {}
+ @defact = nil
+ @rrconf = nil
+ @srconf = nil
+
+ @closure = make_closure(@core)
+ end
+
+ attr_reader :ident
+ alias stateid ident
+ alias hash ident
+
+ attr_reader :core
+ attr_reader :closure
+
+ attr_reader :goto_table
+ attr_reader :gotos
+
+ attr_reader :stokens
+ attr_reader :ritems
+ attr_reader :rrules
+
+ attr_reader :action
+ attr_accessor :defact # default action
+
+ attr_reader :rrconf
+ attr_reader :srconf
+
+ def inspect
+ "<state #{@ident}>"
+ end
+
+ alias to_s inspect
+
+ def ==(oth)
+ @ident == oth.ident
+ end
+
+ alias eql? ==
+
+ def make_closure(core)
+ set = ISet.new
+ core.each do |ptr|
+ set.add ptr
+ if t = ptr.dereference and t.nonterminal?
+ set.update_a t.expand
+ end
+ end
+ set.to_a
+ end
+
+ def check_la(la_rules)
+ @conflict = false
+ s = []
+ r = []
+ @closure.each do |ptr|
+ if t = ptr.dereference
+ if t.terminal?
+ s[t.ident] = t
+ if t.ident == 1 # $error
+ @conflict = true
+ end
+ end
+ else
+ r.push ptr.rule
+ end
+ end
+ unless r.empty?
+ if not s.empty? or r.size > 1
+ @conflict = true
+ end
+ end
+ s.compact!
+ @stokens = s
+ @rrules = r
+
+ if @conflict
+ @la_rules_i = la_rules.size
+ @la_rules = r.map {|i| i.ident }
+ la_rules.concat r
+ else
+ @la_rules_i = @la_rules = nil
+ end
+ end
+
+ def conflict?
+ @conflict
+ end
+
+ def rruleid(rule)
+ if i = @la_rules.index(rule.ident)
+ @la_rules_i + i
+ else
+ puts '/// rruleid'
+ p self
+ p rule
+ p @rrules
+ p @la_rules_i
+ raise 'racc: fatal: cannot get reduce rule id'
+ end
+ end
+
+ def la=(la)
+ return unless @conflict
+ i = @la_rules_i
+ @ritems = r = []
+ @rrules.each do |rule|
+ r.push Item.new(rule, la[i])
+ i += 1
+ end
+ end
+
+ def rr_conflict(high, low, ctok)
+ c = RRconflict.new(@ident, high, low, ctok)
+
+ @rrconf ||= {}
+ if a = @rrconf[ctok]
+ a.push c
+ else
+ @rrconf[ctok] = [c]
+ end
+ end
+
+ def sr_conflict(shift, reduce)
+ c = SRconflict.new(@ident, shift, reduce)
+
+ @srconf ||= {}
+ if a = @srconf[shift]
+ a.push c
+ else
+ @srconf[shift] = [c]
+ end
+ end
+
+ def n_srconflicts
+ @srconf ? @srconf.size : 0
+ end
+
+ def n_rrconflicts
+ @rrconf ? @rrconf.size : 0
+ end
+
+ end # class State
+
+
+ #
+ # Represents a transition on the grammar.
+ # "Real goto" means a transition by nonterminal,
+ # but this class treats also terminal's.
+ # If one is a terminal transition, .ident returns nil.
+ #
+ class Goto
+ def initialize(ident, sym, from, to)
+ @ident = ident
+ @symbol = sym
+ @from_state = from
+ @to_state = to
+ end
+
+ attr_reader :ident
+ attr_reader :symbol
+ attr_reader :from_state
+ attr_reader :to_state
+
+ def inspect
+ "(#{@from_state.ident}-#{@symbol}->#{@to_state.ident})"
+ end
+ end
+
+
+ # LALR item. A set of rule and its lookahead tokens.
+ class Item
+ def initialize(rule, la)
+ @rule = rule
+ @la = la
+ end
+
+ attr_reader :rule
+ attr_reader :la
+
+ def each_la(tbl)
+ la = @la
+ 0.upto(la.size - 1) do |i|
+ (0..7).each do |ii|
+ if la[idx = i * 8 + ii] == 1
+ yield tbl[idx]
+ end
+ end
+ end
+ end
+ end
+
+
+ # The table of LALR actions. Actions are either of
+ # Shift, Reduce, Accept and Error.
+ class ActionTable
+
+ def initialize(rt, st)
+ @grammar = rt
+ @statetable = st
+
+ @reduce = []
+ @shift = []
+ @accept = nil
+ @error = nil
+ end
+
+ def init
+ @grammar.each do |rule|
+ @reduce.push Reduce.new(rule)
+ end
+ @statetable.each do |state|
+ @shift.push Shift.new(state)
+ end
+ @accept = Accept.new
+ @error = Error.new
+ end
+
+ def reduce_n
+ @reduce.size
+ end
+
+ def reduce(i)
+ case i
+ when Rule then i = i.ident
+ when Integer then ;
+ else
+ raise "racc: fatal: wrong class #{i.class} for reduce"
+ end
+
+ r = @reduce[i] or raise "racc: fatal: reduce action #{i.inspect} not exist"
+ r.incref
+ r
+ end
+
+ def each_reduce(&block)
+ @reduce.each(&block)
+ end
+
+ def shift_n
+ @shift.size
+ end
+
+ def shift(i)
+ case i
+ when State then i = i.ident
+ when Integer then ;
+ else
+ raise "racc: fatal: wrong class #{i.class} for shift"
+ end
+
+ @shift[i] or raise "racc: fatal: shift action #{i} does not exist"
+ end
+
+ def each_shift(&block)
+ @shift.each(&block)
+ end
+
+ attr_reader :accept
+ attr_reader :error
+
+ end
+
+
+ class Shift
+ def initialize(goto)
+ @goto_state = goto
+ end
+
+ attr_reader :goto_state
+
+ def goto_id
+ @goto_state.ident
+ end
+
+ def inspect
+ "<shift #{@goto_state.ident}>"
+ end
+ end
+
+
+ class Reduce
+ def initialize(rule)
+ @rule = rule
+ @refn = 0
+ end
+
+ attr_reader :rule
+ attr_reader :refn
+
+ def ruleid
+ @rule.ident
+ end
+
+ def inspect
+ "<reduce #{@rule.ident}>"
+ end
+
+ def incref
+ @refn += 1
+ end
+
+ def decref
+ @refn -= 1
+ raise 'racc: fatal: act.refn < 0' if @refn < 0
+ end
+ end
+
+ class Accept
+ def inspect
+ "<accept>"
+ end
+ end
+
+ class Error
+ def inspect
+ "<error>"
+ end
+ end
+
+ class SRconflict
+ def initialize(sid, shift, reduce)
+ @stateid = sid
+ @shift = shift
+ @reduce = reduce
+ end
+
+ attr_reader :stateid
+ attr_reader :shift
+ attr_reader :reduce
+
+ def to_s
+ sprintf('state %d: S/R conflict rule %d reduce and shift %s',
+ @stateid, @reduce.ruleid, @shift.to_s)
+ end
+ end
+
+ class RRconflict
+ def initialize(sid, high, low, tok)
+ @stateid = sid
+ @high_prec = high
+ @low_prec = low
+ @token = tok
+ end
+
+ attr_reader :stateid
+ attr_reader :high_prec
+ attr_reader :low_prec
+ attr_reader :token
+
+ def to_s
+ sprintf('state %d: R/R conflict with rule %d and %d on %s',
+ @stateid, @high_prec.ident, @low_prec.ident, @token.to_s)
+ end
+ end
+
+end
diff --git a/lib/racc/statetransitiontable.rb b/lib/racc/statetransitiontable.rb
new file mode 100644
index 0000000000..d75fa1657a
--- /dev/null
+++ b/lib/racc/statetransitiontable.rb
@@ -0,0 +1,311 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/parser'
+
+module Racc
+
+ StateTransitionTable = Struct.new(:action_table,
+ :action_check,
+ :action_default,
+ :action_pointer,
+ :goto_table,
+ :goto_check,
+ :goto_default,
+ :goto_pointer,
+ :token_table,
+ :reduce_table,
+ :reduce_n,
+ :shift_n,
+ :nt_base,
+ :token_to_s_table,
+ :use_result_var,
+ :debug_parser)
+ class StateTransitionTable # reopen
+ def StateTransitionTable.generate(states)
+ StateTransitionTableGenerator.new(states).generate
+ end
+
+ def initialize(states)
+ super()
+ @states = states
+ @grammar = states.grammar
+ self.use_result_var = true
+ self.debug_parser = true
+ end
+
+ attr_reader :states
+ attr_reader :grammar
+
+ def parser_class
+ ParserClassGenerator.new(@states).generate
+ end
+
+ def token_value_table
+ h = {}
+ token_table().each do |sym, i|
+ h[sym.value] = i
+ end
+ h
+ end
+ end
+
+
+ class StateTransitionTableGenerator
+
+ def initialize(states)
+ @states = states
+ @grammar = states.grammar
+ end
+
+ def generate
+ t = StateTransitionTable.new(@states)
+ gen_action_tables t, @states
+ gen_goto_tables t, @grammar
+ t.token_table = token_table(@grammar)
+ t.reduce_table = reduce_table(@grammar)
+ t.reduce_n = @states.reduce_n
+ t.shift_n = @states.shift_n
+ t.nt_base = @grammar.nonterminal_base
+ t.token_to_s_table = @grammar.symbols.map {|sym| sym.to_s }
+ t
+ end
+
+ def reduce_table(grammar)
+ t = [0, 0, :racc_error]
+ grammar.each_with_index do |rule, idx|
+ next if idx == 0
+ t.push rule.size
+ t.push rule.target.ident
+ t.push(if rule.action.empty? # and @params.omit_action_call?
+ then :_reduce_none
+ else "_reduce_#{idx}".intern
+ end)
+ end
+ t
+ end
+
+ def token_table(grammar)
+ h = {}
+ grammar.symboltable.terminals.each do |t|
+ h[t] = t.ident
+ end
+ h
+ end
+
+ def gen_action_tables(t, states)
+ t.action_table = yytable = []
+ t.action_check = yycheck = []
+ t.action_default = yydefact = []
+ t.action_pointer = yypact = []
+ e1 = []
+ e2 = []
+ states.each do |state|
+ yydefact.push act2actid(state.defact)
+ if state.action.empty?
+ yypact.push nil
+ next
+ end
+ vector = []
+ state.action.each do |tok, act|
+ vector[tok.ident] = act2actid(act)
+ end
+ addent e1, vector, state.ident, yypact
+ end
+ set_table e1, e2, yytable, yycheck, yypact
+ end
+
+ def gen_goto_tables(t, grammar)
+ t.goto_table = yytable2 = []
+ t.goto_check = yycheck2 = []
+ t.goto_pointer = yypgoto = []
+ t.goto_default = yydefgoto = []
+ e1 = []
+ e2 = []
+ grammar.each_nonterminal do |tok|
+ tmp = []
+
+ # decide default
+ freq = Array.new(@states.size, 0)
+ @states.each do |state|
+ st = state.goto_table[tok]
+ if st
+ st = st.ident
+ freq[st] += 1
+ end
+ tmp[state.ident] = st
+ end
+ max = freq.max
+ if max > 1
+ default = freq.index(max)
+ tmp.map! {|i| default == i ? nil : i }
+ else
+ default = nil
+ end
+ yydefgoto.push default
+
+ # delete default value
+ tmp.pop until tmp.last or tmp.empty?
+ if tmp.compact.empty?
+ # only default
+ yypgoto.push nil
+ next
+ end
+
+ addent e1, tmp, (tok.ident - grammar.nonterminal_base), yypgoto
+ end
+ set_table e1, e2, yytable2, yycheck2, yypgoto
+ end
+
+ def addent(all, arr, chkval, ptr)
+ max = arr.size
+ min = nil
+ arr.each_with_index do |item, idx|
+ if item
+ min ||= idx
+ end
+ end
+ ptr.push(-7777) # mark
+ arr = arr[min...max]
+ all.push [arr, chkval, mkmapexp(arr), min, ptr.size - 1]
+ end
+
+ n = 2 ** 16
+ begin
+ Regexp.compile("a{#{n}}")
+ RE_DUP_MAX = n
+ rescue RegexpError
+ n /= 2
+ retry
+ end
+
+ def mkmapexp(arr)
+ i = ii = 0
+ as = arr.size
+ map = String.new
+ maxdup = RE_DUP_MAX
+ curr = nil
+ while i < as
+ ii = i + 1
+ if arr[i]
+ ii += 1 while ii < as and arr[ii]
+ curr = '-'
+ else
+ ii += 1 while ii < as and not arr[ii]
+ curr = '.'
+ end
+
+ offset = ii - i
+ if offset == 1
+ map << curr
+ else
+ while offset > maxdup
+ map << "#{curr}{#{maxdup}}"
+ offset -= maxdup
+ end
+ map << "#{curr}{#{offset}}" if offset > 1
+ end
+ i = ii
+ end
+ Regexp.compile(map, Regexp::NOENCODING)
+ end
+
+ def set_table(entries, dummy, tbl, chk, ptr)
+ upper = 0
+ map = '-' * 10240
+
+ # sort long to short
+ entries.sort_by!.with_index {|a,i| [-a[0].size, i] }
+
+ entries.each do |arr, chkval, expr, min, ptri|
+ if upper + arr.size > map.size
+ map << '-' * (arr.size + 1024)
+ end
+ idx = map.index(expr)
+ ptr[ptri] = idx - min
+ arr.each_with_index do |item, i|
+ if item
+ i += idx
+ tbl[i] = item
+ chk[i] = chkval
+ map[i] = ?o
+ end
+ end
+ upper = idx + arr.size
+ end
+ end
+
+ def act2actid(act)
+ case act
+ when Shift then act.goto_id
+ when Reduce then -act.ruleid
+ when Accept then @states.shift_n
+ when Error then @states.reduce_n * -1
+ else
+ raise "racc: fatal: wrong act type #{act.class} in action table"
+ end
+ end
+
+ end
+
+
+ class ParserClassGenerator
+
+ def initialize(states)
+ @states = states
+ @grammar = states.grammar
+ end
+
+ def generate
+ table = @states.state_transition_table
+ c = Class.new(::Racc::Parser)
+ c.const_set :Racc_arg, [table.action_table,
+ table.action_check,
+ table.action_default,
+ table.action_pointer,
+ table.goto_table,
+ table.goto_check,
+ table.goto_default,
+ table.goto_pointer,
+ table.nt_base,
+ table.reduce_table,
+ table.token_value_table,
+ table.shift_n,
+ table.reduce_n,
+ false]
+ c.const_set :Racc_token_to_s_table, table.token_to_s_table
+ c.const_set :Racc_debug_parser, true
+ define_actions c
+ c
+ end
+
+ private
+
+ def define_actions(c)
+ c.module_eval "def _reduce_none(vals, vstack) vals[0] end"
+ @grammar.each do |rule|
+ if rule.action.empty?
+ c.alias_method("_reduce_#{rule.ident}", :_reduce_none)
+ else
+ c.define_method("_racc_action_#{rule.ident}", &rule.action.proc)
+ c.module_eval(<<-End, __FILE__, __LINE__ + 1)
+ def _reduce_#{rule.ident}(vals, vstack)
+ _racc_action_#{rule.ident}(*vals)
+ end
+ End
+ end
+ end
+ end
+
+ end
+
+end # module Racc
diff --git a/lib/racc/static.rb b/lib/racc/static.rb
new file mode 100644
index 0000000000..bebbeb5aa6
--- /dev/null
+++ b/lib/racc/static.rb
@@ -0,0 +1,5 @@
+require 'racc'
+require 'racc/parser'
+require 'racc/grammarfileparser'
+require 'racc/parserfilegenerator'
+require 'racc/logfilegenerator'
diff --git a/lib/random/formatter.rb b/lib/random/formatter.rb
index 7fe7785e1a..4dea61c16c 100644
--- a/lib/random/formatter.rb
+++ b/lib/random/formatter.rb
@@ -174,125 +174,6 @@ module Random::Formatter
"%08x-%04x-%04x-%04x-%04x%08x" % ary
end
- alias uuid_v4 uuid
-
- # Generate a random v7 UUID (Universally Unique IDentifier).
- #
- # require 'random/formatter'
- #
- # Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
- # Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
- # Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
- # Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
- # # |<--sorted-->| |<----- random ---->|
- #
- # # or
- # prng = Random.new
- # prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
- #
- # The version 7 UUID starts with the least significant 48 bits of a 64 bit
- # Unix timestamp (milliseconds since the epoch) and fills the remaining bits
- # with random data, excluding the version and variant bits.
- #
- # This allows version 7 UUIDs to be sorted by creation time. Time ordered
- # UUIDs can be used for better database index locality of newly inserted
- # records, which may have a significant performance benefit compared to random
- # data inserts.
- #
- # The result contains 74 random bits (9.25 random bytes).
- #
- # Note that this method cannot be made reproducable with Kernel#srand, which
- # can only affect the random bits. The sorted bits will still be based on
- # Process.clock_gettime.
- #
- # See draft-ietf-uuidrev-rfc4122bis[https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/]
- # for details of UUIDv7.
- #
- # ==== Monotonicity
- #
- # UUIDv7 has millisecond precision by default, so multiple UUIDs created
- # within the same millisecond are not issued in monotonically increasing
- # order. To create UUIDs that are time-ordered with sub-millisecond
- # precision, up to 12 bits of additional timestamp may added with
- # +extra_timestamp_bits+. The extra timestamp precision comes at the expense
- # of random bits. Setting <tt>extra_timestamp_bits: 12</tt> provides ~244ns
- # of precision, but only 62 random bits (7.75 random bytes).
- #
- # prng = Random.new
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
- # # =>
- # ["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
- # "0188d4c7-13da-753b-83a5-7fb9b2afaeea",
- # "0188d4c7-13da-754a-88ea-ac0baeedd8db",
- # "0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
- # # |<--- sorted --->| |<-- random --->|
- #
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
- # # =>
- # ["0188d4c7-3333-7a95-850a-de6edb858f7e",
- # "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order
- # "0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order
- # "0188d4c7-3333-7af9-87c3-8f612edac82e"]
- # # |<--- sorted -->||<---- random --->|
- #
- # Any rollbacks of the system clock will break monotonicity. UUIDv7 is based
- # on UTC, which excludes leap seconds and can rollback the clock. To avoid
- # this, the system clock can synchronize with an NTP server configured to use
- # a "leap smear" approach. NTP or PTP will also be needed to synchronize
- # across distributed nodes.
- #
- # Counters and other mechanisms for stronger guarantees of monotonicity are
- # not implemented. Applications with stricter requirements should follow
- # {Section 6.2}[https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-07.html#monotonicity_counters]
- # of the specification.
- #
- def uuid_v7(extra_timestamp_bits: 0)
- case (extra_timestamp_bits = Integer(extra_timestamp_bits))
- when 0 # min timestamp precision
- ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
- rand = random_bytes(10)
- rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version
- rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant
- "%08x-%04x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- rand.unpack("H4H4H12").join("-")
- ]
-
- when 12 # max timestamp precision
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- extra_bits = ns * 4096 / 1_000_000
- rand = random_bytes(8)
- rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant
- "%08x-%04x-7%03x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- extra_bits,
- rand.unpack("H4H12").join("-")
- ]
-
- when (0..12) # the generic version is slower than the special cases above
- rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN")
- rand_mask_bits = 12 - extra_timestamp_bits
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- "%08x-%04x-%04x-%04x-%04x%08x" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- 0x7000 |
- ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) |
- rand_a & ((1 << rand_mask_bits) - 1),
- 0x8000 | (rand_b1 & 0x3fff),
- rand_b2,
- rand_b3
- ]
-
- else
- raise ArgumentError, "extra_timestamp_bits must be in 0..12"
- end
- end
-
private def gen_random(n)
self.bytes(n)
end
@@ -345,13 +226,11 @@ module Random::Formatter
#
# The argument _n_ specifies the length, in characters, of the alphanumeric
# string to be generated.
- # The argument _chars_ specifies the character list which the result is
- # consist of.
#
# If _n_ is not specified or is nil, 16 is assumed.
# It may be larger in the future.
#
- # The result may contain A-Z, a-z and 0-9, unless _chars_ is specified.
+ # The result may contain A-Z, a-z and 0-9.
#
# require 'random/formatter'
#
@@ -359,13 +238,8 @@ module Random::Formatter
# # or
# prng = Random.new
# prng.alphanumeric(10) #=> "i6K93NdqiH"
- #
- # Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
- # # or
- # prng = Random.new
- # prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
- def alphanumeric(n = nil, chars: ALPHANUMERIC)
+ def alphanumeric(n=nil)
n = 16 if n.nil?
- choose(chars, n)
+ choose(ALPHANUMERIC, n)
end
end
diff --git a/lib/rdoc/alias.rb b/lib/rdoc/alias.rb
index 446cf9ccb4..858e053049 100644
--- a/lib/rdoc/alias.rb
+++ b/lib/rdoc/alias.rb
@@ -109,3 +109,4 @@ class RDoc::Alias < RDoc::CodeObject
end
end
+
diff --git a/lib/rdoc/anon_class.rb b/lib/rdoc/anon_class.rb
index 3c2f0e1877..d02a38c2cf 100644
--- a/lib/rdoc/anon_class.rb
+++ b/lib/rdoc/anon_class.rb
@@ -8,3 +8,4 @@
class RDoc::AnonClass < RDoc::ClassModule
end
+
diff --git a/lib/rdoc/any_method.rb b/lib/rdoc/any_method.rb
index 465c4a4fb2..051f946a10 100644
--- a/lib/rdoc/any_method.rb
+++ b/lib/rdoc/any_method.rb
@@ -116,13 +116,6 @@ class RDoc::AnyMethod < RDoc::MethodAttr
end
##
- # Whether the method has a call-seq.
-
- def has_call_seq?
- !!(@call_seq || is_alias_for&._call_seq)
- end
-
- ##
# Loads is_alias_for from the internal name. Returns nil if the alias
# cannot be found.
@@ -304,14 +297,6 @@ class RDoc::AnyMethod < RDoc::MethodAttr
end
##
- # Whether to skip the method description, true for methods that have
- # aliases with a call-seq that doesn't include the method name.
-
- def skip_description?
- has_call_seq? && call_seq.nil? && !!(is_alias_for || !aliases.empty?)
- end
-
- ##
# Sets the store for this method and its referenced code objects.
def store= store
diff --git a/lib/rdoc/attr.rb b/lib/rdoc/attr.rb
index a403235933..f780b3b976 100644
--- a/lib/rdoc/attr.rb
+++ b/lib/rdoc/attr.rb
@@ -173,3 +173,4 @@ class RDoc::Attr < RDoc::MethodAttr
end
end
+
diff --git a/lib/rdoc/class_module.rb b/lib/rdoc/class_module.rb
index c69e14b5e4..7609080fbf 100644
--- a/lib/rdoc/class_module.rb
+++ b/lib/rdoc/class_module.rb
@@ -799,3 +799,4 @@ class RDoc::ClassModule < RDoc::Context
end
end
+
diff --git a/lib/rdoc/comment.rb b/lib/rdoc/comment.rb
index 04ec226436..9e90999eac 100644
--- a/lib/rdoc/comment.rb
+++ b/lib/rdoc/comment.rb
@@ -6,8 +6,8 @@
# Each comment may have a different markup format set by #format=. By default
# 'rdoc' is used. The :markup: directive tells RDoc which format to use.
#
-# See RDoc::MarkupReference@Directive+for+Specifying+RDoc+Source+Format.
-
+# See RDoc::Markup@Other+directives for instructions on adding an alternate
+# format.
class RDoc::Comment
@@ -97,26 +97,42 @@ class RDoc::Comment
# comment. The difficulty is to make sure not to match lines starting
# with ARGF at the same indent, but that are after the first description
# paragraph.
- if /^(?<S> ((?!\n)\s)*+ (?# whitespaces except newline))
- :?call-seq:
- (?<B> \g<S>(?<N>\n|\z) (?# trailing spaces))?
- (?<seq>
- (\g<S>(?!\w)\S.*\g<N>)*
- (?>
- (?<H> \g<S>\w+ (?# ' # ARGF' in the example above))
- .*\g<N>)?
- (\g<S>\S.*\g<N> (?# other non-blank line))*+
- (\g<B>+(\k<H>.*\g<N> (?# ARGF.to_a lines))++)*+
- )
- (?m:^\s*$|\z)
- /x =~ @text
- seq = $~[:seq]
-
+ if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then
all_start, all_stop = $~.offset(0)
+ seq_start, seq_stop = $~.offset(1)
+
+ # we get the following lines that start with the leading word at the
+ # same indent, even if they have blank lines before
+ if $1 =~ /(^\s*\n)+^(\s*\w+)/m then
+ leading = $2 # ' * ARGF' in the example above
+ re = %r%
+ \A(
+ (^\s*\n)+
+ (^#{Regexp.escape leading}.*?\n)+
+ )+
+ ^\s*$
+ %xm
+
+ if @text[seq_stop..-1] =~ re then
+ all_stop = seq_stop + $~.offset(0).last
+ seq_stop = seq_stop + $~.offset(1).last
+ end
+ end
+
+ seq = @text[seq_start..seq_stop]
+ seq.gsub!(/^\s*(\S|\n)/m, '\1')
@text.slice! all_start...all_stop
- seq.gsub!(/^\s*/, '')
- method.call_seq = seq
+ method.call_seq = seq.chomp
+
+ else
+ regexp = /^\s*:?call-seq:(.*?)(^\s*$|\z)/m
+ if regexp =~ @text then
+ @text = @text.sub(regexp, '')
+ seq = $1
+ seq.gsub!(/^\s*/, '')
+ method.call_seq = seq
+ end
end
method
@@ -133,7 +149,12 @@ class RDoc::Comment
# HACK dubious
def encode! encoding
- @text = String.new @text, encoding: encoding
+ # TODO: Remove this condition after Ruby 2.2 EOL
+ if RUBY_VERSION < '2.3.0'
+ @text = @text.force_encoding encoding
+ else
+ @text = String.new @text, encoding: encoding
+ end
self
end
diff --git a/lib/rdoc/constant.rb b/lib/rdoc/constant.rb
index 12b8be775c..0c3d7505a1 100644
--- a/lib/rdoc/constant.rb
+++ b/lib/rdoc/constant.rb
@@ -184,3 +184,4 @@ class RDoc::Constant < RDoc::CodeObject
end
end
+
diff --git a/lib/rdoc/context/section.rb b/lib/rdoc/context/section.rb
index aecd4e0213..c316efe99f 100644
--- a/lib/rdoc/context/section.rb
+++ b/lib/rdoc/context/section.rb
@@ -231,3 +231,4 @@ class RDoc::Context::Section
end
end
+
diff --git a/lib/rdoc/cross_reference.rb b/lib/rdoc/cross_reference.rb
index f3b703a559..319bbc02ac 100644
--- a/lib/rdoc/cross_reference.rb
+++ b/lib/rdoc/cross_reference.rb
@@ -223,3 +223,4 @@ class RDoc::CrossReference
end
end
+
diff --git a/lib/rdoc/encoding.rb b/lib/rdoc/encoding.rb
index 8a921c7011..cf60badd24 100644
--- a/lib/rdoc/encoding.rb
+++ b/lib/rdoc/encoding.rb
@@ -124,7 +124,12 @@ module RDoc::Encoding
if text.kind_of? RDoc::Comment
text.encode! encoding
else
- String.new text, encoding: encoding
+ # TODO: Remove this condition after Ruby 2.2 EOL
+ if RUBY_VERSION < '2.3.0'
+ text.force_encoding encoding
+ else
+ String.new text, encoding: encoding
+ end
end
end
diff --git a/lib/rdoc/erb_partial.rb b/lib/rdoc/erb_partial.rb
index 043d763db1..d6e3f41b7e 100644
--- a/lib/rdoc/erb_partial.rb
+++ b/lib/rdoc/erb_partial.rb
@@ -16,3 +16,4 @@ class RDoc::ERBPartial < ERB
end
end
+
diff --git a/lib/rdoc/erbio.rb b/lib/rdoc/erbio.rb
index 0f98eaedee..0d5f96e133 100644
--- a/lib/rdoc/erbio.rb
+++ b/lib/rdoc/erbio.rb
@@ -20,8 +20,12 @@ class RDoc::ERBIO < ERB
##
# Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize
- def initialize str, trim_mode: nil, eoutvar: 'io'
- super(str, trim_mode: trim_mode, eoutvar: eoutvar)
+ def initialize str, safe_level = nil, legacy_trim_mode = nil, legacy_eoutvar = 'io', trim_mode: nil, eoutvar: 'io'
+ if RUBY_VERSION >= '2.6'
+ super(str, trim_mode: trim_mode, eoutvar: eoutvar)
+ else
+ super(str, safe_level, legacy_trim_mode, legacy_eoutvar)
+ end
end
##
@@ -35,3 +39,4 @@ class RDoc::ERBIO < ERB
end
end
+
diff --git a/lib/rdoc/extend.rb b/lib/rdoc/extend.rb
index 7d57433de6..e1b182902e 100644
--- a/lib/rdoc/extend.rb
+++ b/lib/rdoc/extend.rb
@@ -7,3 +7,4 @@
class RDoc::Extend < RDoc::Mixin
end
+
diff --git a/lib/rdoc/generator/darkfish.rb b/lib/rdoc/generator/darkfish.rb
index 1b408a6f8e..60e0265e8c 100644
--- a/lib/rdoc/generator/darkfish.rb
+++ b/lib/rdoc/generator/darkfish.rb
@@ -610,7 +610,7 @@ class RDoc::Generator::Darkfish
@classes = @store.all_classes_and_modules.sort
@files = @store.all_files.sort
- @methods = @classes.flat_map { |m| m.method_list }.sort
+ @methods = @classes.map { |m| m.method_list }.flatten.sort
@modsort = get_sorted_module_list @classes
end
@@ -778,7 +778,11 @@ class RDoc::Generator::Darkfish
erbout = "_erbout_#{file_var}"
end
- template = klass.new template, trim_mode: '-', eoutvar: erbout
+ if RUBY_VERSION >= '2.6'
+ template = klass.new template, trim_mode: '-', eoutvar: erbout
+ else
+ template = klass.new template, nil, '-', erbout
+ end
@template_cache[file] = template
template
end
diff --git a/lib/rdoc/generator/json_index.rb b/lib/rdoc/generator/json_index.rb
index c454910d5c..3a1000033d 100644
--- a/lib/rdoc/generator/json_index.rb
+++ b/lib/rdoc/generator/json_index.rb
@@ -230,9 +230,9 @@ class RDoc::Generator::JsonIndex
def index_methods
debug_msg " generating method search index"
- list = @classes.uniq.flat_map do |klass|
+ list = @classes.uniq.map do |klass|
klass.method_list
- end.sort_by do |method|
+ end.flatten.sort_by do |method|
[method.name, method.parent.full_name]
end
diff --git a/lib/rdoc/generator/markup.rb b/lib/rdoc/generator/markup.rb
index 76b7d458aa..b54265717c 100644
--- a/lib/rdoc/generator/markup.rb
+++ b/lib/rdoc/generator/markup.rb
@@ -157,3 +157,4 @@ class RDoc::TopLevel
end
end
+
diff --git a/lib/rdoc/generator/ri.rb b/lib/rdoc/generator/ri.rb
index 1c2f018f97..0eef1d03f5 100644
--- a/lib/rdoc/generator/ri.rb
+++ b/lib/rdoc/generator/ri.rb
@@ -28,3 +28,4 @@ class RDoc::Generator::RI
end
end
+
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
index afc7f7b88d..9c49b31376 100644
--- a/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
@@ -3,7 +3,7 @@
<div id="search-field-wrapper">
<input id="search-field" role="combobox" aria-label="Search"
aria-autocomplete="list" aria-controls="search-results"
- type="text" name="search" placeholder="Search (/) for a class, method, ..." spellcheck="false"
+ type="text" name="search" placeholder="Search" spellcheck="false"
title="Type to search, Up and Down to navigate, Enter to load">
</div>
diff --git a/lib/rdoc/generator/template/darkfish/class.rhtml b/lib/rdoc/generator/template/darkfish/class.rhtml
index d6510336df..97d175dddc 100644
--- a/lib/rdoc/generator/template/darkfish/class.rhtml
+++ b/lib/rdoc/generator/template/darkfish/class.rhtml
@@ -112,10 +112,6 @@
<%- end -%>
</div>
<%- end -%>
- <%- elsif method.has_call_seq? then -%>
- <div class="method-heading">
- <span class="method-name"><%= h method.name %></span>
- </div>
<%- else -%>
<div class="method-heading">
<span class="method-name"><%= h method.name %></span><span
@@ -127,7 +123,6 @@
<%- end -%>
</div>
- <%- unless method.skip_description? then -%>
<div class="method-description">
<%- if method.comment then -%>
<%= method.description.strip %>
@@ -150,7 +145,6 @@
</div>
<%- end -%>
</div>
- <%- end -%>
<%- unless method.aliases.empty? then -%>
<div class="aliases">
diff --git a/lib/rdoc/generator/template/darkfish/css/rdoc.css b/lib/rdoc/generator/template/darkfish/css/rdoc.css
index f845d6cecb..1be815f503 100644
--- a/lib/rdoc/generator/template/darkfish/css/rdoc.css
+++ b/lib/rdoc/generator/template/darkfish/css/rdoc.css
@@ -17,14 +17,6 @@ body {
background: #fafafa;
font-family: Lato, sans-serif;
font-weight: 300;
-
- /* Layout */
- display: grid;
- grid-template-columns: auto 1fr;
-}
-
-body > :last-child {
- grid-column: 1 / 3;
}
h1 span,
@@ -189,25 +181,21 @@ table tr:nth-child(even) td {
/* @group Top-Level Structure */
nav {
+ float: left;
+ width: 260px;
font-family: Helvetica, sans-serif;
font-size: 14px;
border-right: 1px solid #ccc;
position: sticky;
top: 0;
overflow: auto;
-
- /* Layout */
- width: 260px; /* fallback */
- width: max(50px, 20vw);
- min-width: 50px;
- max-width: 80vw;
height: calc(100vh - 100px); /* reduce the footer height */
- resize: horizontal;
}
main {
display: block;
- margin: 1em;
+ margin: 0 2em 5em 260px;
+ padding-left: 20px;
min-width: 340px;
font-size: 16px;
}
@@ -226,6 +214,7 @@ main h6 {
}
#validator-badges {
+ clear: both;
margin: 1em 1em 2em;
font-size: smaller;
}
@@ -320,26 +309,23 @@ dl.note-list dt {
background: url(../images/arrow_up.png) no-repeat right center;
}
-.nav-section details > summary {
+.nav-section details summary {
display: block;
}
-.nav-section details > summary::-webkit-details-marker {
+.nav-section details summary::-webkit-details-marker {
display: none;
}
-.nav-section details > summary::before {
+.nav-section details summary:before {
content: "";
}
-.nav-section details > summary::after {
- content: "\25B6"; /* BLACK RIGHT-POINTING TRIANGLE */
- font-size: 0.8em;
- margin-left: 0.4em;
+.nav-section details summary:after {
+ content: " \25B6"; /* BLACK RIGHT-POINTING TRIANGLE */
}
-
-.nav-section details[open] > summary::after {
- content: "\25BD"; /* WHITE DOWN-POINTING TRIANGLE */
+.nav-section details[open] > summary:after {
+ content: " \25BD"; /* WHITE DOWN-POINTING TRIANGLE */
}
/* @end */
@@ -567,7 +553,7 @@ main .method-click-advice {
line-height: 20px;
background: url(../images/zoom.png) no-repeat right top;
}
-main .method-header:hover .method-click-advice {
+main .method-heading:hover .method-click-advice {
visibility: visible;
}
diff --git a/lib/rdoc/generator/template/darkfish/js/darkfish.js b/lib/rdoc/generator/template/darkfish/js/darkfish.js
index 19a85c54e1..d0c9467751 100644
--- a/lib/rdoc/generator/template/darkfish/js/darkfish.js
+++ b/lib/rdoc/generator/template/darkfish/js/darkfish.js
@@ -78,20 +78,7 @@ function hookSearch() {
search.scrollIntoView = search.scrollInWindow;
};
-function hookFocus() {
- document.addEventListener("keydown", (event) => {
- if (document.activeElement.tagName === 'INPUT') {
- return;
- }
- if (event.key === "/") {
- event.preventDefault();
- document.querySelector('#search-field').focus();
- }
- });
-}
-
document.addEventListener('DOMContentLoaded', function() {
hookSourceViews();
hookSearch();
- hookFocus();
});
diff --git a/lib/rdoc/generator/template/darkfish/js/search.js b/lib/rdoc/generator/template/darkfish/js/search.js
index d3cded1d57..58e52afecf 100644
--- a/lib/rdoc/generator/template/darkfish/js/search.js
+++ b/lib/rdoc/generator/template/darkfish/js/search.js
@@ -15,9 +15,9 @@ Search.prototype = Object.assign({}, Navigation, new function() {
this.init = function() {
var _this = this;
var observer = function(e) {
- switch(e.key) {
- case 'ArrowUp':
- case 'ArrowDown':
+ switch(e.keyCode) {
+ case 38: // Event.KEY_UP
+ case 40: // Event.KEY_DOWN
return;
}
_this.search(_this.input.value);
diff --git a/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
index 54a376c9e5..941ff9d630 100644
--- a/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
+++ b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
@@ -36,9 +36,8 @@
unless table.empty? then %>
<ul>
<%- table.each do |item| -%>
-<%- label = item.respond_to?(:label) ? item.label(klass) : item.aref -%>
- <li><a href="<%= klass.path %>#<%= label %>"><%= item.plain_html %></a>
-<%- end -%>
+ <li><a href="<%= klass.path %>#<%= item.aref %>"><%= item.plain_html %></a>
+<%- end -%>
</ul>
<%- end -%>
</li>
@@ -47,9 +46,9 @@
<h2 id="methods">Methods</h2>
<ul>
-<%- @store.all_classes_and_modules.flat_map do |mod|
+<%- @store.all_classes_and_modules.map do |mod|
mod.method_list
- end.sort.each do |method| %>
+ end.flatten.sort.each do |method| %>
<li class="method">
<a href="<%= method.path %>"><%= h method.pretty_name %></a>
&mdash;
diff --git a/lib/rdoc/generator/template/json_index/js/navigation.js b/lib/rdoc/generator/template/json_index/js/navigation.js
index 137e3a0038..dfad74b1ae 100644
--- a/lib/rdoc/generator/template/json_index/js/navigation.js
+++ b/lib/rdoc/generator/template/json_index/js/navigation.js
@@ -23,24 +23,24 @@ Navigation = new function() {
this.onkeydown = function(e) {
if (!this.navigationActive) return;
- switch(e.key) {
- case 'ArrowLeft':
+ switch(e.keyCode) {
+ case 37: //Event.KEY_LEFT:
if (this.moveLeft()) e.preventDefault();
break;
- case 'ArrowUp':
- if (e.key == 'ArrowUp' || e.ctrlKey) {
+ case 38: //Event.KEY_UP:
+ if (e.keyCode == 38 || e.ctrlKey) {
if (this.moveUp()) e.preventDefault();
}
break;
- case 'ArrowRight':
+ case 39: //Event.KEY_RIGHT:
if (this.moveRight()) e.preventDefault();
break;
- case 'ArrowDown':
- if (e.key == 'ArrowDown' || e.ctrlKey) {
+ case 40: //Event.KEY_DOWN:
+ if (e.keyCode == 40 || e.ctrlKey) {
if (this.moveDown()) e.preventDefault();
}
break;
- case 'Enter':
+ case 13: //Event.KEY_RETURN:
if (this.current) e.preventDefault();
this.select(this.current);
break;
diff --git a/lib/rdoc/ghost_method.rb b/lib/rdoc/ghost_method.rb
index 25f951e35e..2488feb9d7 100644
--- a/lib/rdoc/ghost_method.rb
+++ b/lib/rdoc/ghost_method.rb
@@ -4,3 +4,4 @@
class RDoc::GhostMethod < RDoc::AnyMethod
end
+
diff --git a/lib/rdoc/include.rb b/lib/rdoc/include.rb
index c3e0d45e47..b3ad610649 100644
--- a/lib/rdoc/include.rb
+++ b/lib/rdoc/include.rb
@@ -7,3 +7,4 @@
class RDoc::Include < RDoc::Mixin
end
+
diff --git a/lib/rdoc/markdown.rb b/lib/rdoc/markdown.rb
index 157f2fa3fe..a0709b6352 100644
--- a/lib/rdoc/markdown.rb
+++ b/lib/rdoc/markdown.rb
@@ -175,7 +175,7 @@
# [dingus]: http://daringfireball.net/projects/markdown/dingus
# [GFM]: https://github.github.com/gfm/
# [pegmarkdown]: https://github.com/jgm/peg-markdown
-# [PHPE]: https://michelf.ca/projects/php-markdown/extra/#def-list
+# [PHPE]: http://michelf.com/projects/php-markdown/extra/#def-list
# [syntax]: http://daringfireball.net/projects/markdown/syntax
#--
# Last updated to jgm/peg-markdown commit 8f8fc22ef0
diff --git a/lib/rdoc/markdown/entities.rb b/lib/rdoc/markdown/entities.rb
index 265c2eb3f3..d2cf610293 100644
--- a/lib/rdoc/markdown/entities.rb
+++ b/lib/rdoc/markdown/entities.rb
@@ -2129,3 +2129,4 @@ RDoc::Markdown::HTML_ENTITIES = {
"zwj" => [0x0200D],
"zwnj" => [0x0200C],
}
+
diff --git a/lib/rdoc/markup/attr_changer.rb b/lib/rdoc/markup/attr_changer.rb
index e5ba470bb6..4c4bc6479e 100644
--- a/lib/rdoc/markup/attr_changer.rb
+++ b/lib/rdoc/markup/attr_changer.rb
@@ -20,3 +20,4 @@ class RDoc::Markup::AttrChanger
end
end
+
diff --git a/lib/rdoc/markup/attr_span.rb b/lib/rdoc/markup/attr_span.rb
index f1fabf1c3b..20ef11cd6d 100644
--- a/lib/rdoc/markup/attr_span.rb
+++ b/lib/rdoc/markup/attr_span.rb
@@ -33,3 +33,4 @@ class RDoc::Markup::AttrSpan
end
end
+
diff --git a/lib/rdoc/markup/attribute_manager.rb b/lib/rdoc/markup/attribute_manager.rb
index 1162f27284..601e6bc189 100644
--- a/lib/rdoc/markup/attribute_manager.rb
+++ b/lib/rdoc/markup/attribute_manager.rb
@@ -1,19 +1,19 @@
# frozen_string_literal: true
-
##
# Manages changes of attributes in a block of text
-class RDoc::Markup::AttributeManager
- unless ::MatchData.method_defined?(:match_length)
- using ::Module.new {
- refine(::MatchData) {
- def match_length(nth) # :nodoc:
- b, e = offset(nth)
- e - b if b
- end
- }
+unless MatchData.method_defined?(:match_length)
+ using Module.new {
+ refine(MatchData) {
+ def match_length(nth)
+ b, e = offset(nth)
+ e - b if b
+ end
}
- end
+ }
+end
+
+class RDoc::Markup::AttributeManager
##
# The NUL character
@@ -400,3 +400,4 @@ class RDoc::Markup::AttributeManager
end
end
+
diff --git a/lib/rdoc/markup/attributes.rb b/lib/rdoc/markup/attributes.rb
index d9d18b3059..ce014ce928 100644
--- a/lib/rdoc/markup/attributes.rb
+++ b/lib/rdoc/markup/attributes.rb
@@ -68,3 +68,4 @@ class RDoc::Markup::Attributes
end
end
+
diff --git a/lib/rdoc/markup/blank_line.rb b/lib/rdoc/markup/blank_line.rb
index f63ae9479c..3129ab5e7f 100644
--- a/lib/rdoc/markup/blank_line.rb
+++ b/lib/rdoc/markup/blank_line.rb
@@ -25,3 +25,4 @@ class RDoc::Markup::BlankLine
end
end
+
diff --git a/lib/rdoc/markup/block_quote.rb b/lib/rdoc/markup/block_quote.rb
index d9fcbf213c..7a4b3e36b0 100644
--- a/lib/rdoc/markup/block_quote.rb
+++ b/lib/rdoc/markup/block_quote.rb
@@ -12,3 +12,4 @@ class RDoc::Markup::BlockQuote < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/document.rb b/lib/rdoc/markup/document.rb
index 94cf6a3666..f3a5de1fc3 100644
--- a/lib/rdoc/markup/document.rb
+++ b/lib/rdoc/markup/document.rb
@@ -162,3 +162,4 @@ class RDoc::Markup::Document
end
end
+
diff --git a/lib/rdoc/markup/formatter.rb b/lib/rdoc/markup/formatter.rb
index 37a2c2751a..2bac76e838 100644
--- a/lib/rdoc/markup/formatter.rb
+++ b/lib/rdoc/markup/formatter.rb
@@ -263,3 +263,4 @@ class RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/hard_break.rb b/lib/rdoc/markup/hard_break.rb
index de1819c903..046068d5c2 100644
--- a/lib/rdoc/markup/hard_break.rb
+++ b/lib/rdoc/markup/hard_break.rb
@@ -29,3 +29,4 @@ class RDoc::Markup::HardBreak
end
end
+
diff --git a/lib/rdoc/markup/heading.rb b/lib/rdoc/markup/heading.rb
index 02476e5226..93a3a52000 100644
--- a/lib/rdoc/markup/heading.rb
+++ b/lib/rdoc/markup/heading.rb
@@ -76,3 +76,4 @@ RDoc::Markup::Heading =
end
end
+
diff --git a/lib/rdoc/markup/include.rb b/lib/rdoc/markup/include.rb
index 2bf63526b2..ad7c4a9640 100644
--- a/lib/rdoc/markup/include.rb
+++ b/lib/rdoc/markup/include.rb
@@ -40,3 +40,4 @@ class RDoc::Markup::Include
end
end
+
diff --git a/lib/rdoc/markup/indented_paragraph.rb b/lib/rdoc/markup/indented_paragraph.rb
index 992cd7cf81..d42b2e52b8 100644
--- a/lib/rdoc/markup/indented_paragraph.rb
+++ b/lib/rdoc/markup/indented_paragraph.rb
@@ -45,3 +45,4 @@ class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/list.rb b/lib/rdoc/markup/list.rb
index 112b7a1a86..05c3609202 100644
--- a/lib/rdoc/markup/list.rb
+++ b/lib/rdoc/markup/list.rb
@@ -99,3 +99,4 @@ class RDoc::Markup::List
end
end
+
diff --git a/lib/rdoc/markup/list_item.rb b/lib/rdoc/markup/list_item.rb
index 0b8326a69f..d22554ee73 100644
--- a/lib/rdoc/markup/list_item.rb
+++ b/lib/rdoc/markup/list_item.rb
@@ -97,3 +97,4 @@ class RDoc::Markup::ListItem
end
end
+
diff --git a/lib/rdoc/markup/paragraph.rb b/lib/rdoc/markup/paragraph.rb
index 21dfda007a..a2e45ef009 100644
--- a/lib/rdoc/markup/paragraph.rb
+++ b/lib/rdoc/markup/paragraph.rb
@@ -26,3 +26,4 @@ class RDoc::Markup::Paragraph < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/raw.rb b/lib/rdoc/markup/raw.rb
index a7c1c210a6..85e2c8b825 100644
--- a/lib/rdoc/markup/raw.rb
+++ b/lib/rdoc/markup/raw.rb
@@ -67,3 +67,4 @@ class RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/regexp_handling.rb b/lib/rdoc/markup/regexp_handling.rb
index c471fe73c7..6ed868c2c1 100644
--- a/lib/rdoc/markup/regexp_handling.rb
+++ b/lib/rdoc/markup/regexp_handling.rb
@@ -38,3 +38,4 @@ class RDoc::Markup::RegexpHandling
end
end
+
diff --git a/lib/rdoc/markup/rule.rb b/lib/rdoc/markup/rule.rb
index 448148d6d1..38c1dc7f56 100644
--- a/lib/rdoc/markup/rule.rb
+++ b/lib/rdoc/markup/rule.rb
@@ -18,3 +18,4 @@ class RDoc::Markup::Rule < Struct.new :weight
end
end
+
diff --git a/lib/rdoc/markup/to_ansi.rb b/lib/rdoc/markup/to_ansi.rb
index c3eacab21a..6cc3b70e93 100644
--- a/lib/rdoc/markup/to_ansi.rb
+++ b/lib/rdoc/markup/to_ansi.rb
@@ -91,3 +91,4 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
end
end
+
diff --git a/lib/rdoc/markup/to_html.rb b/lib/rdoc/markup/to_html.rb
index 6c9f5733a2..bf323074de 100644
--- a/lib/rdoc/markup/to_html.rb
+++ b/lib/rdoc/markup/to_html.rb
@@ -430,9 +430,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
def parseable? text
verbose, $VERBOSE = $VERBOSE, nil
- catch(:valid) do
- eval("BEGIN { throw :valid, true }\n#{text}")
- end
+ eval("BEGIN {return true}\n#{text}")
rescue SyntaxError
false
ensure
@@ -447,3 +445,4 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb
index 434b622495..a9fd09df41 100644
--- a/lib/rdoc/markup/to_html_crossref.rb
+++ b/lib/rdoc/markup/to_html_crossref.rb
@@ -173,3 +173,4 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
end
end
+
diff --git a/lib/rdoc/markup/to_html_snippet.rb b/lib/rdoc/markup/to_html_snippet.rb
index 8219f0b169..4eb36592b7 100644
--- a/lib/rdoc/markup/to_html_snippet.rb
+++ b/lib/rdoc/markup/to_html_snippet.rb
@@ -282,3 +282,4 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
end
end
+
diff --git a/lib/rdoc/markup/to_joined_paragraph.rb b/lib/rdoc/markup/to_joined_paragraph.rb
index 31cbe0853c..46e07c94ad 100644
--- a/lib/rdoc/markup/to_joined_paragraph.rb
+++ b/lib/rdoc/markup/to_joined_paragraph.rb
@@ -25,9 +25,9 @@ class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter
def accept_paragraph paragraph
parts = paragraph.parts.chunk do |part|
String === part
- end.flat_map do |string, chunk|
+ end.map do |string, chunk|
string ? chunk.join.rstrip : chunk
- end
+ end.flatten
paragraph.parts.replace parts
end
@@ -44,3 +44,4 @@ class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter
alias accept_table ignore
end
+
diff --git a/lib/rdoc/markup/to_label.rb b/lib/rdoc/markup/to_label.rb
index cf808364e9..aa1dbcf2a1 100644
--- a/lib/rdoc/markup/to_label.rb
+++ b/lib/rdoc/markup/to_label.rb
@@ -72,3 +72,4 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
alias start_accepting ignore
end
+
diff --git a/lib/rdoc/markup/to_markdown.rb b/lib/rdoc/markup/to_markdown.rb
index 5dd60e18f5..3ee48becb0 100644
--- a/lib/rdoc/markup/to_markdown.rb
+++ b/lib/rdoc/markup/to_markdown.rb
@@ -189,3 +189,4 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc
end
end
+
diff --git a/lib/rdoc/markup/to_rdoc.rb b/lib/rdoc/markup/to_rdoc.rb
index 6929049582..2a9b05625c 100644
--- a/lib/rdoc/markup/to_rdoc.rb
+++ b/lib/rdoc/markup/to_rdoc.rb
@@ -342,3 +342,4 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/to_table_of_contents.rb b/lib/rdoc/markup/to_table_of_contents.rb
index e5b8225ba3..eb8e8faa16 100644
--- a/lib/rdoc/markup/to_table_of_contents.rb
+++ b/lib/rdoc/markup/to_table_of_contents.rb
@@ -86,3 +86,4 @@ class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter
# :startdoc:
end
+
diff --git a/lib/rdoc/markup/to_test.rb b/lib/rdoc/markup/to_test.rb
index 30113da561..61d3cffaf0 100644
--- a/lib/rdoc/markup/to_test.rb
+++ b/lib/rdoc/markup/to_test.rb
@@ -67,3 +67,4 @@ class RDoc::Markup::ToTest < RDoc::Markup::Formatter
# :startdoc:
end
+
diff --git a/lib/rdoc/markup/to_tt_only.rb b/lib/rdoc/markup/to_tt_only.rb
index 9ac14ed235..9235d33f04 100644
--- a/lib/rdoc/markup/to_tt_only.rb
+++ b/lib/rdoc/markup/to_tt_only.rb
@@ -118,3 +118,4 @@ class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/verbatim.rb b/lib/rdoc/markup/verbatim.rb
index f51c2cfa14..7f1bc29a09 100644
--- a/lib/rdoc/markup/verbatim.rb
+++ b/lib/rdoc/markup/verbatim.rb
@@ -81,3 +81,4 @@ class RDoc::Markup::Verbatim < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/meta_method.rb b/lib/rdoc/meta_method.rb
index 8c95a0f78c..7927a9ce9c 100644
--- a/lib/rdoc/meta_method.rb
+++ b/lib/rdoc/meta_method.rb
@@ -4,3 +4,4 @@
class RDoc::MetaMethod < RDoc::AnyMethod
end
+
diff --git a/lib/rdoc/method_attr.rb b/lib/rdoc/method_attr.rb
index 61ddb32f46..aae3c47e85 100644
--- a/lib/rdoc/method_attr.rb
+++ b/lib/rdoc/method_attr.rb
@@ -416,3 +416,4 @@ class RDoc::MethodAttr < RDoc::CodeObject
end
end
+
diff --git a/lib/rdoc/mixin.rb b/lib/rdoc/mixin.rb
index fa8faefc15..379d7cc526 100644
--- a/lib/rdoc/mixin.rb
+++ b/lib/rdoc/mixin.rb
@@ -118,3 +118,4 @@ class RDoc::Mixin < RDoc::CodeObject
end
end
+
diff --git a/lib/rdoc/normal_class.rb b/lib/rdoc/normal_class.rb
index aa340b5d15..68dfa7d4a3 100644
--- a/lib/rdoc/normal_class.rb
+++ b/lib/rdoc/normal_class.rb
@@ -90,3 +90,4 @@ class RDoc::NormalClass < RDoc::ClassModule
end
end
+
diff --git a/lib/rdoc/normal_module.rb b/lib/rdoc/normal_module.rb
index 498ec4dde2..edf29f8f1c 100644
--- a/lib/rdoc/normal_module.rb
+++ b/lib/rdoc/normal_module.rb
@@ -71,3 +71,4 @@ class RDoc::NormalModule < RDoc::ClassModule
end
end
+
diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb
index 6ee29fd071..eed0f6b39b 100644
--- a/lib/rdoc/options.rb
+++ b/lib/rdoc/options.rb
@@ -565,10 +565,9 @@ class RDoc::Options
@op_dir ||= 'doc'
+ @rdoc_include << "." if @rdoc_include.empty?
root = @root.to_s
- if @rdoc_include.empty? || !@rdoc_include.include?(root)
- @rdoc_include << root
- end
+ @rdoc_include << root unless @rdoc_include.include?(root)
@exclude = self.exclude
diff --git a/lib/rdoc/parser/changelog.rb b/lib/rdoc/parser/changelog.rb
index 2a685d1d79..9245d49376 100644
--- a/lib/rdoc/parser/changelog.rb
+++ b/lib/rdoc/parser/changelog.rb
@@ -332,3 +332,4 @@ class RDoc::Parser::ChangeLog < RDoc::Parser
end
end
end
+
diff --git a/lib/rdoc/parser/markdown.rb b/lib/rdoc/parser/markdown.rb
index 3c316227b9..9ff478f872 100644
--- a/lib/rdoc/parser/markdown.rb
+++ b/lib/rdoc/parser/markdown.rb
@@ -20,3 +20,5 @@ class RDoc::Parser::Markdown < RDoc::Parser
end
end
+
+
diff --git a/lib/rdoc/parser/rd.rb b/lib/rdoc/parser/rd.rb
index 19e47e549d..25f5711731 100644
--- a/lib/rdoc/parser/rd.rb
+++ b/lib/rdoc/parser/rd.rb
@@ -20,3 +20,4 @@ class RDoc::Parser::RD < RDoc::Parser
end
end
+
diff --git a/lib/rdoc/parser/ripper_state_lex.rb b/lib/rdoc/parser/ripper_state_lex.rb
index 27d7373270..5492f08726 100644
--- a/lib/rdoc/parser/ripper_state_lex.rb
+++ b/lib/rdoc/parser/ripper_state_lex.rb
@@ -368,7 +368,7 @@ class RDoc::Parser::RipperStateLex
private def get_symbol_tk(tk)
is_symbol = true
symbol_tk = Token.new(tk.line_no, tk.char_no, :on_symbol)
- if ":'" == tk[:text] or ':"' == tk[:text] or tk[:text].start_with?('%s')
+ if ":'" == tk[:text] or ':"' == tk[:text]
tk1 = get_string_tk(tk)
symbol_tk[:text] = tk1[:text]
symbol_tk[:state] = tk1[:state]
diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb
index 2c8a19f608..b74ead65ab 100644
--- a/lib/rdoc/parser/ruby.rb
+++ b/lib/rdoc/parser/ruby.rb
@@ -8,9 +8,6 @@
# by Keiju ISHITSUKA (Nippon Rational Inc.)
#
-require 'ripper'
-require_relative 'ripper_state_lex'
-
##
# Extracts code elements from a source file returning a TopLevel object
# containing the constituent file elements.
@@ -141,6 +138,9 @@ require_relative 'ripper_state_lex'
# Note that by default, the :method: directive will be ignored if there is a
# standard rdocable item following it.
+require 'ripper'
+require_relative 'ripper_state_lex'
+
class RDoc::Parser::Ruby < RDoc::Parser
parse_files_matching(/\.rbw?$/)
@@ -2134,7 +2134,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then
return
elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then
- return unless tk[:text] =~ /:?\b([\w-]+):\s*(.*)/
+ return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/
directive = $1.downcase
diff --git a/lib/rdoc/parser/ruby_tools.rb b/lib/rdoc/parser/ruby_tools.rb
index 40ea517c4d..681d7166ce 100644
--- a/lib/rdoc/parser/ruby_tools.rb
+++ b/lib/rdoc/parser/ruby_tools.rb
@@ -163,3 +163,5 @@ module RDoc::Parser::RubyTools
end
end
+
+
diff --git a/lib/rdoc/parser/text.rb b/lib/rdoc/parser/text.rb
index 5095d8cc64..01de0cc595 100644
--- a/lib/rdoc/parser/text.rb
+++ b/lib/rdoc/parser/text.rb
@@ -9,3 +9,4 @@
module RDoc::Parser::Text
end
+
diff --git a/lib/rdoc/rd/block_parser.rb b/lib/rdoc/rd/block_parser.rb
index 527147d91d..6f70622c0b 100644
--- a/lib/rdoc/rd/block_parser.rb
+++ b/lib/rdoc/rd/block_parser.rb
@@ -1,659 +1,11 @@
# frozen_string_literal: true
#
# DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.7.3
-# from Racc grammar file "block_parser.ry".
+# This file is automatically generated by Racc 1.6.0
+# from Racc grammar file "".
#
-###### racc/parser.rb begin
-unless $".find {|p| p.end_with?('/racc/parser.rb')}
-$".push "#{__dir__}/racc/parser.rb"
-#--
-# Copyright (c) 1999-2006 Minero Aoki
-#
-# This program is free software.
-# You can distribute/modify this program under the same terms of ruby.
-#
-# As a special exception, when this code is copied by Racc
-# into a Racc output file, you may use that output file
-# without restriction.
-#++
-
-unless $".find {|p| p.end_with?('/racc/info.rb')}
-$".push "#{__dir__}/racc/info.rb"
-
-module Racc
- VERSION = '1.7.3'
- Version = VERSION
- Copyright = 'Copyright (c) 1999-2006 Minero Aoki'
-end
-
-end
-
-
-unless defined?(NotImplementedError)
- NotImplementedError = NotImplementError # :nodoc:
-end
-
-module Racc
- class ParseError < StandardError; end
-end
-unless defined?(::ParseError)
- ParseError = Racc::ParseError # :nodoc:
-end
-
-# Racc is a LALR(1) parser generator.
-# It is written in Ruby itself, and generates Ruby programs.
-#
-# == Command-line Reference
-#
-# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
-# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
-# [-v] [--verbose]
-# [-O<var>filename</var>] [--log-file=<var>filename</var>]
-# [-g] [--debug]
-# [-E] [--embedded]
-# [-l] [--no-line-convert]
-# [-c] [--line-convert-all]
-# [-a] [--no-omit-actions]
-# [-C] [--check-only]
-# [-S] [--output-status]
-# [--version] [--copyright] [--help] <var>grammarfile</var>
-#
-# [+grammarfile+]
-# Racc grammar file. Any extension is permitted.
-# [-o+outfile+, --output-file=+outfile+]
-# A filename for output. default is <+filename+>.tab.rb
-# [-O+filename+, --log-file=+filename+]
-# Place logging output in file +filename+.
-# Default log file name is <+filename+>.output.
-# [-e+rubypath+, --executable=+rubypath+]
-# output executable file(mode 755). where +path+ is the Ruby interpreter.
-# [-v, --verbose]
-# verbose mode. create +filename+.output file, like yacc's y.output file.
-# [-g, --debug]
-# add debug code to parser class. To display debugging information,
-# use this '-g' option and set @yydebug true in parser class.
-# [-E, --embedded]
-# Output parser which doesn't need runtime files (racc/parser.rb).
-# [-F, --frozen]
-# Output parser which declares frozen_string_literals: true
-# [-C, --check-only]
-# Check syntax of racc grammar file and quit.
-# [-S, --output-status]
-# Print messages time to time while compiling.
-# [-l, --no-line-convert]
-# turns off line number converting.
-# [-c, --line-convert-all]
-# Convert line number of actions, inner, header and footer.
-# [-a, --no-omit-actions]
-# Call all actions, even if an action is empty.
-# [--version]
-# print Racc version and quit.
-# [--copyright]
-# Print copyright and quit.
-# [--help]
-# Print usage and quit.
-#
-# == Generating Parser Using Racc
-#
-# To compile Racc grammar file, simply type:
-#
-# $ racc parse.y
-#
-# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
-#
-# == Writing A Racc Grammar File
-#
-# If you want your own parser, you have to write a grammar file.
-# A grammar file contains the name of your parser class, grammar for the parser,
-# user code, and anything else.
-# When writing a grammar file, yacc's knowledge is helpful.
-# If you have not used yacc before, Racc is not too difficult.
-#
-# Here's an example Racc grammar file.
-#
-# class Calcparser
-# rule
-# target: exp { print val[0] }
-#
-# exp: exp '+' exp
-# | exp '*' exp
-# | '(' exp ')'
-# | NUMBER
-# end
-#
-# Racc grammar files resemble yacc files.
-# But (of course), this is Ruby code.
-# yacc's $$ is the 'result', $0, $1... is
-# an array called 'val', and $-1, $-2... is an array called '_values'.
-#
-# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
-# more information on grammar files.
-#
-# == Parser
-#
-# Then you must prepare the parse entry method. There are two types of
-# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
-#
-# Racc::Parser#do_parse is simple.
-#
-# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
-# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
-# EOF is [false, false].
-# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
-# If you want to change this, see the grammar reference.
-#
-# Racc::Parser#yyparse is little complicated, but useful.
-# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
-#
-# For example, <code>yyparse(obj, :scan)</code> causes
-# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
-#
-# == Debugging
-#
-# When debugging, "-v" or/and the "-g" option is helpful.
-#
-# "-v" creates verbose log file (.output).
-# "-g" creates a "Verbose Parser".
-# Verbose Parser prints the internal status when parsing.
-# But it's _not_ automatic.
-# You must use -g option and set +@yydebug+ to +true+ in order to get output.
-# -g option only creates the verbose parser.
-#
-# === Racc reported syntax error.
-#
-# Isn't there too many "end"?
-# grammar of racc file is changed in v0.10.
-#
-# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
-#
-# === Racc reported "XXXX conflicts".
-#
-# Try "racc -v xxxx.y".
-# It causes producing racc's internal log file, xxxx.output.
-#
-# === Generated parsers does not work correctly
-#
-# Try "racc -g xxxx.y".
-# This command let racc generate "debugging parser".
-# Then set @yydebug=true in your parser.
-# It produces a working log of your parser.
-#
-# == Re-distributing Racc runtime
-#
-# A parser, which is created by Racc, requires the Racc runtime module;
-# racc/parser.rb.
-#
-# Ruby 1.8.x comes with Racc runtime module,
-# you need NOT distribute Racc runtime files.
-#
-# If you want to include the Racc runtime module with your parser.
-# This can be done by using '-E' option:
-#
-# $ racc -E -omyparser.rb myparser.y
-#
-# This command creates myparser.rb which `includes' Racc runtime.
-# Only you must do is to distribute your parser file (myparser.rb).
-#
-# Note: parser.rb is ruby license, but your parser is not.
-# Your own parser is completely yours.
-module Racc
-
- unless defined?(Racc_No_Extensions)
- Racc_No_Extensions = false # :nodoc:
- end
-
- class Parser
-
- Racc_Runtime_Version = ::Racc::VERSION
- Racc_Runtime_Core_Version_R = ::Racc::VERSION
-
- begin
- if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
- require 'jruby'
- require 'racc/cparse-jruby.jar'
- com.headius.racc.Cparse.new.load(JRuby.runtime, false)
- else
- require 'racc/cparse'
- end
-
- unless new.respond_to?(:_racc_do_parse_c, true)
- raise LoadError, 'old cparse.so'
- end
- if Racc_No_Extensions
- raise LoadError, 'selecting ruby version of racc runtime core'
- end
-
- Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
- Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
- Racc_Runtime_Type = 'c' # :nodoc:
- rescue LoadError
- Racc_Main_Parsing_Routine = :_racc_do_parse_rb
- Racc_YY_Parse_Method = :_racc_yyparse_rb
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
- Racc_Runtime_Type = 'ruby'
- end
-
- def Parser.racc_runtime_type # :nodoc:
- Racc_Runtime_Type
- end
-
- def _racc_setup
- @yydebug = false unless self.class::Racc_debug_parser
- @yydebug = false unless defined?(@yydebug)
- if @yydebug
- @racc_debug_out = $stderr unless defined?(@racc_debug_out)
- @racc_debug_out ||= $stderr
- end
- arg = self.class::Racc_arg
- arg[13] = true if arg.size < 14
- arg
- end
-
- def _racc_init_sysvars
- @racc_state = [0]
- @racc_tstack = []
- @racc_vstack = []
-
- @racc_t = nil
- @racc_val = nil
-
- @racc_read_next = true
-
- @racc_user_yyerror = false
- @racc_error_status = 0
- end
-
- # The entry point of the parser. This method is used with #next_token.
- # If Racc wants to get token (and its value), calls next_token.
- #
- # Example:
- # def parse
- # @q = [[1,1],
- # [2,2],
- # [3,3],
- # [false, '$']]
- # do_parse
- # end
- #
- # def next_token
- # @q.shift
- # end
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def do_parse
- #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
- end
- RUBY
-
- # The method to fetch next token.
- # If you use #do_parse method, you must implement #next_token.
- #
- # The format of return value is [TOKEN_SYMBOL, VALUE].
- # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
- # for 'IDENT'. ";" (String) for ';'.
- #
- # The final symbol (End of file) must be false.
- def next_token
- raise NotImplementedError, "#{self.class}\#next_token is not defined"
- end
-
- def _racc_do_parse_rb(arg, in_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
- tok = act = i = nil
-
- catch(:racc_end_parse) {
- while true
- if i = action_pointer[@racc_state[-1]]
- if @racc_read_next
- if @racc_t != 0 # not EOF
- tok, @racc_val = next_token()
- unless tok # EOF
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- racc_read_token(@racc_t, tok, @racc_val) if @yydebug
- @racc_read_next = false
- end
- end
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- else
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- }
- end
-
- # Another entry point for the parser.
- # If you use this method, you must implement RECEIVER#METHOD_ID method.
- #
- # RECEIVER#METHOD_ID is a method to get next token.
- # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def yyparse(recv, mid)
- #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
- end
- RUBY
-
- def _racc_yyparse_rb(recv, mid, arg, c_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
-
- catch(:racc_end_parse) {
- until i = action_pointer[@racc_state[-1]]
- while act = _racc_evalact(action_default[@racc_state[-1]], arg)
- ;
- end
- end
- recv.__send__(mid) do |tok, val|
- unless tok
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- @racc_val = val
- @racc_read_next = false
-
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
-
- while !(i = action_pointer[@racc_state[-1]]) ||
- ! @racc_read_next ||
- @racc_t == 0 # $
- unless i and i += @racc_t and
- i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- end
- }
- end
-
- ###
- ### common
- ###
-
- def _racc_evalact(act, arg)
- action_table, action_check, _, action_pointer,
- _, _, _, _,
- _, _, _, shift_n,
- reduce_n, * = arg
- nerr = 0 # tmp
-
- if act > 0 and act < shift_n
- #
- # shift
- #
- if @racc_error_status > 0
- @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
- end
- @racc_vstack.push @racc_val
- @racc_state.push act
- @racc_read_next = true
- if @yydebug
- @racc_tstack.push @racc_t
- racc_shift @racc_t, @racc_tstack, @racc_vstack
- end
-
- elsif act < 0 and act > -reduce_n
- #
- # reduce
- #
- code = catch(:racc_jump) {
- @racc_state.push _racc_do_reduce(arg, act)
- false
- }
- if code
- case code
- when 1 # yyerror
- @racc_user_yyerror = true # user_yyerror
- return -reduce_n
- when 2 # yyaccept
- return shift_n
- else
- raise '[Racc Bug] unknown jump code'
- end
- end
-
- elsif act == shift_n
- #
- # accept
- #
- racc_accept if @yydebug
- throw :racc_end_parse, @racc_vstack[0]
-
- elsif act == -reduce_n
- #
- # error
- #
- case @racc_error_status
- when 0
- unless arg[21] # user_yyerror
- nerr += 1
- on_error @racc_t, @racc_val, @racc_vstack
- end
- when 3
- if @racc_t == 0 # is $
- # We're at EOF, and another error occurred immediately after
- # attempting auto-recovery
- throw :racc_end_parse, nil
- end
- @racc_read_next = true
- end
- @racc_user_yyerror = false
- @racc_error_status = 3
- while true
- if i = action_pointer[@racc_state[-1]]
- i += 1 # error token
- if i >= 0 and
- (act = action_table[i]) and
- action_check[i] == @racc_state[-1]
- break
- end
- end
- throw :racc_end_parse, nil if @racc_state.size <= 1
- @racc_state.pop
- @racc_vstack.pop
- if @yydebug
- @racc_tstack.pop
- racc_e_pop @racc_state, @racc_tstack, @racc_vstack
- end
- end
- return act
-
- else
- raise "[Racc Bug] unknown action #{act.inspect}"
- end
-
- racc_next_state(@racc_state[-1], @racc_state) if @yydebug
-
- nil
- end
-
- def _racc_do_reduce(arg, act)
- _, _, _, _,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, _, _,
- _, use_result, * = arg
-
- state = @racc_state
- vstack = @racc_vstack
- tstack = @racc_tstack
-
- i = act * -3
- len = reduce_table[i]
- reduce_to = reduce_table[i+1]
- method_id = reduce_table[i+2]
- void_array = []
-
- tmp_t = tstack[-len, len] if @yydebug
- tmp_v = vstack[-len, len]
- tstack[-len, len] = void_array if @yydebug
- vstack[-len, len] = void_array
- state[-len, len] = void_array
-
- # tstack must be updated AFTER method call
- if use_result
- vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
- else
- vstack.push __send__(method_id, tmp_v, vstack)
- end
- tstack.push reduce_to
-
- racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
-
- k1 = reduce_to - nt_base
- if i = goto_pointer[k1]
- i += state[-1]
- if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
- return curstate
- end
- end
- goto_default[k1]
- end
-
- # This method is called when a parse error is found.
- #
- # ERROR_TOKEN_ID is an internal ID of token which caused error.
- # You can get string representation of this ID by calling
- # #token_to_str.
- #
- # ERROR_VALUE is a value of error token.
- #
- # value_stack is a stack of symbol values.
- # DO NOT MODIFY this object.
- #
- # This method raises ParseError by default.
- #
- # If this method returns, parsers enter "error recovering mode".
- def on_error(t, val, vstack)
- raise ParseError, sprintf("parse error on value %s (%s)",
- val.inspect, token_to_str(t) || '?')
- end
-
- # Enter error recovering mode.
- # This method does not call #on_error.
- def yyerror
- throw :racc_jump, 1
- end
-
- # Exit parser.
- # Return value is +Symbol_Value_Stack[0]+.
- def yyaccept
- throw :racc_jump, 2
- end
-
- # Leave error recovering mode.
- def yyerrok
- @racc_error_status = 0
- end
-
- # For debugging output
- def racc_read_token(t, tok, val)
- @racc_debug_out.print 'read '
- @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
- @racc_debug_out.puts val.inspect
- @racc_debug_out.puts
- end
-
- def racc_shift(tok, tstack, vstack)
- @racc_debug_out.puts "shift #{racc_token2str tok}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_reduce(toks, sim, tstack, vstack)
- out = @racc_debug_out
- out.print 'reduce '
- if toks.empty?
- out.print ' <none>'
- else
- toks.each {|t| out.print ' ', racc_token2str(t) }
- end
- out.puts " --> #{racc_token2str(sim)}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_accept
- @racc_debug_out.puts 'accept'
- @racc_debug_out.puts
- end
-
- def racc_e_pop(state, tstack, vstack)
- @racc_debug_out.puts 'error recovering mode: pop token'
- racc_print_states state
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_next_state(curstate, state)
- @racc_debug_out.puts "goto #{curstate}"
- racc_print_states state
- @racc_debug_out.puts
- end
-
- def racc_print_stacks(t, v)
- out = @racc_debug_out
- out.print ' ['
- t.each_index do |i|
- out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
- end
- out.puts ' ]'
- end
-
- def racc_print_states(s)
- out = @racc_debug_out
- out.print ' ['
- s.each {|st| out.print ' ', st }
- out.puts ' ]'
- end
-
- def racc_token2str(tok)
- self.class::Racc_token_to_s_table[tok] or
- raise "[Racc Bug] can't convert token #{tok} to string"
- end
-
- # Convert internal ID of token symbol to the string.
- def token_to_str(t)
- self.class::Racc_token_to_s_table[t]
- end
-
- end
-
-end
-
-end
-###### racc/parser.rb end
+require 'racc/parser.rb'
class RDoc::RD
@@ -1008,7 +360,7 @@ def get_included(file)
file_name = File.join dir, file
if File.exist? file_name then
- included = File.readlines file_name
+ included = IO.readlines file_name
break
end
end
@@ -1272,7 +624,6 @@ Racc_arg = [
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
-Ractor.make_shareable(Racc_arg) if defined?(Ractor)
Racc_token_to_s_table = [
"$end",
@@ -1323,7 +674,6 @@ Racc_token_to_s_table = [
"blocks_in_list",
"block_in_list",
"whitelines2" ]
-Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
Racc_debug_parser = false
diff --git a/lib/rdoc/rd/inline.rb b/lib/rdoc/rd/inline.rb
index 77d88b2860..e5cb545728 100644
--- a/lib/rdoc/rd/inline.rb
+++ b/lib/rdoc/rd/inline.rb
@@ -69,3 +69,4 @@ class RDoc::RD::Inline
alias to_s rdoc # :nodoc:
end
+
diff --git a/lib/rdoc/rd/inline_parser.rb b/lib/rdoc/rd/inline_parser.rb
index adacf64d5b..c1da35a109 100644
--- a/lib/rdoc/rd/inline_parser.rb
+++ b/lib/rdoc/rd/inline_parser.rb
@@ -1,659 +1,11 @@
# frozen_string_literal: true
#
# DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.7.3
-# from Racc grammar file "inline_parser.ry".
+# This file is automatically generated by Racc 1.6.0
+# from Racc grammar file "".
#
-###### racc/parser.rb begin
-unless $".find {|p| p.end_with?('/racc/parser.rb')}
-$".push "#{__dir__}/racc/parser.rb"
-#--
-# Copyright (c) 1999-2006 Minero Aoki
-#
-# This program is free software.
-# You can distribute/modify this program under the same terms of ruby.
-#
-# As a special exception, when this code is copied by Racc
-# into a Racc output file, you may use that output file
-# without restriction.
-#++
-
-unless $".find {|p| p.end_with?('/racc/info.rb')}
-$".push "#{__dir__}/racc/info.rb"
-
-module Racc
- VERSION = '1.7.3'
- Version = VERSION
- Copyright = 'Copyright (c) 1999-2006 Minero Aoki'
-end
-
-end
-
-
-unless defined?(NotImplementedError)
- NotImplementedError = NotImplementError # :nodoc:
-end
-
-module Racc
- class ParseError < StandardError; end
-end
-unless defined?(::ParseError)
- ParseError = Racc::ParseError # :nodoc:
-end
-
-# Racc is a LALR(1) parser generator.
-# It is written in Ruby itself, and generates Ruby programs.
-#
-# == Command-line Reference
-#
-# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
-# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
-# [-v] [--verbose]
-# [-O<var>filename</var>] [--log-file=<var>filename</var>]
-# [-g] [--debug]
-# [-E] [--embedded]
-# [-l] [--no-line-convert]
-# [-c] [--line-convert-all]
-# [-a] [--no-omit-actions]
-# [-C] [--check-only]
-# [-S] [--output-status]
-# [--version] [--copyright] [--help] <var>grammarfile</var>
-#
-# [+grammarfile+]
-# Racc grammar file. Any extension is permitted.
-# [-o+outfile+, --output-file=+outfile+]
-# A filename for output. default is <+filename+>.tab.rb
-# [-O+filename+, --log-file=+filename+]
-# Place logging output in file +filename+.
-# Default log file name is <+filename+>.output.
-# [-e+rubypath+, --executable=+rubypath+]
-# output executable file(mode 755). where +path+ is the Ruby interpreter.
-# [-v, --verbose]
-# verbose mode. create +filename+.output file, like yacc's y.output file.
-# [-g, --debug]
-# add debug code to parser class. To display debugging information,
-# use this '-g' option and set @yydebug true in parser class.
-# [-E, --embedded]
-# Output parser which doesn't need runtime files (racc/parser.rb).
-# [-F, --frozen]
-# Output parser which declares frozen_string_literals: true
-# [-C, --check-only]
-# Check syntax of racc grammar file and quit.
-# [-S, --output-status]
-# Print messages time to time while compiling.
-# [-l, --no-line-convert]
-# turns off line number converting.
-# [-c, --line-convert-all]
-# Convert line number of actions, inner, header and footer.
-# [-a, --no-omit-actions]
-# Call all actions, even if an action is empty.
-# [--version]
-# print Racc version and quit.
-# [--copyright]
-# Print copyright and quit.
-# [--help]
-# Print usage and quit.
-#
-# == Generating Parser Using Racc
-#
-# To compile Racc grammar file, simply type:
-#
-# $ racc parse.y
-#
-# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
-#
-# == Writing A Racc Grammar File
-#
-# If you want your own parser, you have to write a grammar file.
-# A grammar file contains the name of your parser class, grammar for the parser,
-# user code, and anything else.
-# When writing a grammar file, yacc's knowledge is helpful.
-# If you have not used yacc before, Racc is not too difficult.
-#
-# Here's an example Racc grammar file.
-#
-# class Calcparser
-# rule
-# target: exp { print val[0] }
-#
-# exp: exp '+' exp
-# | exp '*' exp
-# | '(' exp ')'
-# | NUMBER
-# end
-#
-# Racc grammar files resemble yacc files.
-# But (of course), this is Ruby code.
-# yacc's $$ is the 'result', $0, $1... is
-# an array called 'val', and $-1, $-2... is an array called '_values'.
-#
-# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
-# more information on grammar files.
-#
-# == Parser
-#
-# Then you must prepare the parse entry method. There are two types of
-# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
-#
-# Racc::Parser#do_parse is simple.
-#
-# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
-# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
-# EOF is [false, false].
-# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
-# If you want to change this, see the grammar reference.
-#
-# Racc::Parser#yyparse is little complicated, but useful.
-# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
-#
-# For example, <code>yyparse(obj, :scan)</code> causes
-# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
-#
-# == Debugging
-#
-# When debugging, "-v" or/and the "-g" option is helpful.
-#
-# "-v" creates verbose log file (.output).
-# "-g" creates a "Verbose Parser".
-# Verbose Parser prints the internal status when parsing.
-# But it's _not_ automatic.
-# You must use -g option and set +@yydebug+ to +true+ in order to get output.
-# -g option only creates the verbose parser.
-#
-# === Racc reported syntax error.
-#
-# Isn't there too many "end"?
-# grammar of racc file is changed in v0.10.
-#
-# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
-#
-# === Racc reported "XXXX conflicts".
-#
-# Try "racc -v xxxx.y".
-# It causes producing racc's internal log file, xxxx.output.
-#
-# === Generated parsers does not work correctly
-#
-# Try "racc -g xxxx.y".
-# This command let racc generate "debugging parser".
-# Then set @yydebug=true in your parser.
-# It produces a working log of your parser.
-#
-# == Re-distributing Racc runtime
-#
-# A parser, which is created by Racc, requires the Racc runtime module;
-# racc/parser.rb.
-#
-# Ruby 1.8.x comes with Racc runtime module,
-# you need NOT distribute Racc runtime files.
-#
-# If you want to include the Racc runtime module with your parser.
-# This can be done by using '-E' option:
-#
-# $ racc -E -omyparser.rb myparser.y
-#
-# This command creates myparser.rb which `includes' Racc runtime.
-# Only you must do is to distribute your parser file (myparser.rb).
-#
-# Note: parser.rb is ruby license, but your parser is not.
-# Your own parser is completely yours.
-module Racc
-
- unless defined?(Racc_No_Extensions)
- Racc_No_Extensions = false # :nodoc:
- end
-
- class Parser
-
- Racc_Runtime_Version = ::Racc::VERSION
- Racc_Runtime_Core_Version_R = ::Racc::VERSION
-
- begin
- if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
- require 'jruby'
- require 'racc/cparse-jruby.jar'
- com.headius.racc.Cparse.new.load(JRuby.runtime, false)
- else
- require 'racc/cparse'
- end
-
- unless new.respond_to?(:_racc_do_parse_c, true)
- raise LoadError, 'old cparse.so'
- end
- if Racc_No_Extensions
- raise LoadError, 'selecting ruby version of racc runtime core'
- end
-
- Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
- Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
- Racc_Runtime_Type = 'c' # :nodoc:
- rescue LoadError
- Racc_Main_Parsing_Routine = :_racc_do_parse_rb
- Racc_YY_Parse_Method = :_racc_yyparse_rb
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
- Racc_Runtime_Type = 'ruby'
- end
-
- def Parser.racc_runtime_type # :nodoc:
- Racc_Runtime_Type
- end
-
- def _racc_setup
- @yydebug = false unless self.class::Racc_debug_parser
- @yydebug = false unless defined?(@yydebug)
- if @yydebug
- @racc_debug_out = $stderr unless defined?(@racc_debug_out)
- @racc_debug_out ||= $stderr
- end
- arg = self.class::Racc_arg
- arg[13] = true if arg.size < 14
- arg
- end
-
- def _racc_init_sysvars
- @racc_state = [0]
- @racc_tstack = []
- @racc_vstack = []
-
- @racc_t = nil
- @racc_val = nil
-
- @racc_read_next = true
-
- @racc_user_yyerror = false
- @racc_error_status = 0
- end
-
- # The entry point of the parser. This method is used with #next_token.
- # If Racc wants to get token (and its value), calls next_token.
- #
- # Example:
- # def parse
- # @q = [[1,1],
- # [2,2],
- # [3,3],
- # [false, '$']]
- # do_parse
- # end
- #
- # def next_token
- # @q.shift
- # end
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def do_parse
- #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
- end
- RUBY
-
- # The method to fetch next token.
- # If you use #do_parse method, you must implement #next_token.
- #
- # The format of return value is [TOKEN_SYMBOL, VALUE].
- # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
- # for 'IDENT'. ";" (String) for ';'.
- #
- # The final symbol (End of file) must be false.
- def next_token
- raise NotImplementedError, "#{self.class}\#next_token is not defined"
- end
-
- def _racc_do_parse_rb(arg, in_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
- tok = act = i = nil
-
- catch(:racc_end_parse) {
- while true
- if i = action_pointer[@racc_state[-1]]
- if @racc_read_next
- if @racc_t != 0 # not EOF
- tok, @racc_val = next_token()
- unless tok # EOF
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- racc_read_token(@racc_t, tok, @racc_val) if @yydebug
- @racc_read_next = false
- end
- end
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- else
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- }
- end
-
- # Another entry point for the parser.
- # If you use this method, you must implement RECEIVER#METHOD_ID method.
- #
- # RECEIVER#METHOD_ID is a method to get next token.
- # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def yyparse(recv, mid)
- #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
- end
- RUBY
-
- def _racc_yyparse_rb(recv, mid, arg, c_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
-
- catch(:racc_end_parse) {
- until i = action_pointer[@racc_state[-1]]
- while act = _racc_evalact(action_default[@racc_state[-1]], arg)
- ;
- end
- end
- recv.__send__(mid) do |tok, val|
- unless tok
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- @racc_val = val
- @racc_read_next = false
-
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
-
- while !(i = action_pointer[@racc_state[-1]]) ||
- ! @racc_read_next ||
- @racc_t == 0 # $
- unless i and i += @racc_t and
- i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- end
- }
- end
-
- ###
- ### common
- ###
-
- def _racc_evalact(act, arg)
- action_table, action_check, _, action_pointer,
- _, _, _, _,
- _, _, _, shift_n,
- reduce_n, * = arg
- nerr = 0 # tmp
-
- if act > 0 and act < shift_n
- #
- # shift
- #
- if @racc_error_status > 0
- @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
- end
- @racc_vstack.push @racc_val
- @racc_state.push act
- @racc_read_next = true
- if @yydebug
- @racc_tstack.push @racc_t
- racc_shift @racc_t, @racc_tstack, @racc_vstack
- end
-
- elsif act < 0 and act > -reduce_n
- #
- # reduce
- #
- code = catch(:racc_jump) {
- @racc_state.push _racc_do_reduce(arg, act)
- false
- }
- if code
- case code
- when 1 # yyerror
- @racc_user_yyerror = true # user_yyerror
- return -reduce_n
- when 2 # yyaccept
- return shift_n
- else
- raise '[Racc Bug] unknown jump code'
- end
- end
-
- elsif act == shift_n
- #
- # accept
- #
- racc_accept if @yydebug
- throw :racc_end_parse, @racc_vstack[0]
-
- elsif act == -reduce_n
- #
- # error
- #
- case @racc_error_status
- when 0
- unless arg[21] # user_yyerror
- nerr += 1
- on_error @racc_t, @racc_val, @racc_vstack
- end
- when 3
- if @racc_t == 0 # is $
- # We're at EOF, and another error occurred immediately after
- # attempting auto-recovery
- throw :racc_end_parse, nil
- end
- @racc_read_next = true
- end
- @racc_user_yyerror = false
- @racc_error_status = 3
- while true
- if i = action_pointer[@racc_state[-1]]
- i += 1 # error token
- if i >= 0 and
- (act = action_table[i]) and
- action_check[i] == @racc_state[-1]
- break
- end
- end
- throw :racc_end_parse, nil if @racc_state.size <= 1
- @racc_state.pop
- @racc_vstack.pop
- if @yydebug
- @racc_tstack.pop
- racc_e_pop @racc_state, @racc_tstack, @racc_vstack
- end
- end
- return act
-
- else
- raise "[Racc Bug] unknown action #{act.inspect}"
- end
-
- racc_next_state(@racc_state[-1], @racc_state) if @yydebug
-
- nil
- end
-
- def _racc_do_reduce(arg, act)
- _, _, _, _,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, _, _,
- _, use_result, * = arg
-
- state = @racc_state
- vstack = @racc_vstack
- tstack = @racc_tstack
-
- i = act * -3
- len = reduce_table[i]
- reduce_to = reduce_table[i+1]
- method_id = reduce_table[i+2]
- void_array = []
-
- tmp_t = tstack[-len, len] if @yydebug
- tmp_v = vstack[-len, len]
- tstack[-len, len] = void_array if @yydebug
- vstack[-len, len] = void_array
- state[-len, len] = void_array
-
- # tstack must be updated AFTER method call
- if use_result
- vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
- else
- vstack.push __send__(method_id, tmp_v, vstack)
- end
- tstack.push reduce_to
-
- racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
-
- k1 = reduce_to - nt_base
- if i = goto_pointer[k1]
- i += state[-1]
- if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
- return curstate
- end
- end
- goto_default[k1]
- end
-
- # This method is called when a parse error is found.
- #
- # ERROR_TOKEN_ID is an internal ID of token which caused error.
- # You can get string representation of this ID by calling
- # #token_to_str.
- #
- # ERROR_VALUE is a value of error token.
- #
- # value_stack is a stack of symbol values.
- # DO NOT MODIFY this object.
- #
- # This method raises ParseError by default.
- #
- # If this method returns, parsers enter "error recovering mode".
- def on_error(t, val, vstack)
- raise ParseError, sprintf("parse error on value %s (%s)",
- val.inspect, token_to_str(t) || '?')
- end
-
- # Enter error recovering mode.
- # This method does not call #on_error.
- def yyerror
- throw :racc_jump, 1
- end
-
- # Exit parser.
- # Return value is +Symbol_Value_Stack[0]+.
- def yyaccept
- throw :racc_jump, 2
- end
-
- # Leave error recovering mode.
- def yyerrok
- @racc_error_status = 0
- end
-
- # For debugging output
- def racc_read_token(t, tok, val)
- @racc_debug_out.print 'read '
- @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
- @racc_debug_out.puts val.inspect
- @racc_debug_out.puts
- end
-
- def racc_shift(tok, tstack, vstack)
- @racc_debug_out.puts "shift #{racc_token2str tok}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_reduce(toks, sim, tstack, vstack)
- out = @racc_debug_out
- out.print 'reduce '
- if toks.empty?
- out.print ' <none>'
- else
- toks.each {|t| out.print ' ', racc_token2str(t) }
- end
- out.puts " --> #{racc_token2str(sim)}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_accept
- @racc_debug_out.puts 'accept'
- @racc_debug_out.puts
- end
-
- def racc_e_pop(state, tstack, vstack)
- @racc_debug_out.puts 'error recovering mode: pop token'
- racc_print_states state
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_next_state(curstate, state)
- @racc_debug_out.puts "goto #{curstate}"
- racc_print_states state
- @racc_debug_out.puts
- end
-
- def racc_print_stacks(t, v)
- out = @racc_debug_out
- out.print ' ['
- t.each_index do |i|
- out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
- end
- out.puts ' ]'
- end
-
- def racc_print_states(s)
- out = @racc_debug_out
- out.print ' ['
- s.each {|st| out.print ' ', st }
- out.puts ' ]'
- end
-
- def racc_token2str(tok)
- self.class::Racc_token_to_s_table[tok] or
- raise "[Racc Bug] can't convert token #{tok} to string"
- end
-
- # Convert internal ID of token symbol to the string.
- def token_to_str(t)
- self.class::Racc_token_to_s_table[t]
- end
-
- end
-
-end
-
-end
-###### racc/parser.rb end
+require 'racc/parser.rb'
require 'strscan'
@@ -1300,7 +652,6 @@ Racc_arg = [
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
-Ractor.make_shareable(Racc_arg) if defined?(Ractor)
Racc_token_to_s_table = [
"$end",
@@ -1372,7 +723,6 @@ Racc_token_to_s_table = [
"normal_strings",
"verb_string",
"verb_normal_string" ]
-Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
Racc_debug_parser = false
diff --git a/lib/rdoc/rdoc.gemspec b/lib/rdoc/rdoc.gemspec
index 93a281c8ae..3c96f7deb1 100644
--- a/lib/rdoc/rdoc.gemspec
+++ b/lib/rdoc/rdoc.gemspec
@@ -28,10 +28,6 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
s.homepage = "https://ruby.github.io/rdoc"
s.licenses = ["Ruby"]
- s.metadata["homepage_uri"] = s.homepage
- s.metadata["source_code_uri"] = "https://github.com/ruby/rdoc"
- s.metadata["changelog_uri"] = "#{s.metadata["source_code_uri"]}/releases"
-
s.bindir = "exe"
s.executables = ["rdoc", "ri"]
s.require_paths = ["lib"]
@@ -230,7 +226,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
s.rdoc_options = ["--main", "README.rdoc"]
s.extra_rdoc_files += s.files.grep(%r[\A[^\/]+\.(?:rdoc|md)\z])
- s.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
+ s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
s.required_rubygems_version = Gem::Requirement.new(">= 2.2")
s.add_dependency 'psych', '>= 4.0.0'
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index 2da6d9b575..2d8a9dea8c 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -119,7 +119,7 @@ class RDoc::RDoc
# +files+.
def gather_files files
- files = [@options.root.to_s] if files.empty?
+ files = ["."] if files.empty?
file_list = normalized_file_list files, true, @options.exclude
@@ -429,7 +429,9 @@ The internal error was:
files.reject do |file, *|
file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or
(file =~ /tags$/i and
- /\A(\f\n[^,]+,\d+$|!_TAG_)/.match?(File.binread(file, 100)))
+ File.open(file, 'rb') { |io|
+ io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/
+ })
end
end
diff --git a/lib/rdoc/require.rb b/lib/rdoc/require.rb
index 05e26b84b0..91f9c24e5d 100644
--- a/lib/rdoc/require.rb
+++ b/lib/rdoc/require.rb
@@ -49,3 +49,4 @@ class RDoc::Require < RDoc::CodeObject
end
end
+
diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb
index 08c4d08f81..819cff8aa3 100644
--- a/lib/rdoc/ri/driver.rb
+++ b/lib/rdoc/ri/driver.rb
@@ -34,9 +34,9 @@ class RDoc::RI::Driver
class NotFoundError < Error
- def initialize(klass, suggestion_proc = nil) # :nodoc:
+ def initialize(klass, suggestions = nil) # :nodoc:
@klass = klass
- @suggestion_proc = suggestion_proc
+ @suggestions = suggestions
end
##
@@ -48,9 +48,8 @@ class RDoc::RI::Driver
def message # :nodoc:
str = "Nothing known about #{@klass}"
- suggestions = @suggestion_proc&.call
- if suggestions and !suggestions.empty?
- str += "\nDid you mean? #{suggestions.join("\n ")}"
+ if @suggestions and !@suggestions.empty?
+ str += "\nDid you mean? #{@suggestions.join("\n ")}"
end
str
end
@@ -949,8 +948,8 @@ or the PAGER environment variable.
ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z"))
if ary.length != 1 && ary.first != klass
if check_did_you_mean
- suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass) }
- raise NotFoundError.new(klass, suggestion_proc)
+ suggestions = DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass)
+ raise NotFoundError.new(klass, suggestions)
else
raise NotFoundError, klass
end
@@ -1238,8 +1237,8 @@ or the PAGER environment variable.
methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types
end
methods = methods.uniq
- suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name) }
- raise NotFoundError.new(name, suggestion_proc)
+ suggestions = DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name)
+ raise NotFoundError.new(name, suggestions)
else
raise NotFoundError, name
end
diff --git a/lib/rdoc/ri/store.rb b/lib/rdoc/ri/store.rb
index 96742e7ae3..9f4b03734a 100644
--- a/lib/rdoc/ri/store.rb
+++ b/lib/rdoc/ri/store.rb
@@ -4,3 +4,4 @@ module RDoc::RI
Store = RDoc::Store # :nodoc:
end
+
diff --git a/lib/rdoc/single_class.rb b/lib/rdoc/single_class.rb
index dd16529648..860f06a6e5 100644
--- a/lib/rdoc/single_class.rb
+++ b/lib/rdoc/single_class.rb
@@ -28,3 +28,4 @@ class RDoc::SingleClass < RDoc::ClassModule
end
end
end
+
diff --git a/lib/rdoc/stats/quiet.rb b/lib/rdoc/stats/quiet.rb
index 9c98ea5f86..bc4161b2d4 100644
--- a/lib/rdoc/stats/quiet.rb
+++ b/lib/rdoc/stats/quiet.rb
@@ -57,3 +57,4 @@ class RDoc::Stats::Quiet
def done_adding(*) end
end
+
diff --git a/lib/rdoc/stats/verbose.rb b/lib/rdoc/stats/verbose.rb
index 7090d561f8..6ace8937a2 100644
--- a/lib/rdoc/stats/verbose.rb
+++ b/lib/rdoc/stats/verbose.rb
@@ -42,3 +42,5 @@ class RDoc::Stats::Verbose < RDoc::Stats::Normal
end
end
+
+
diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb
index 9fc540d317..c793e49ed8 100644
--- a/lib/rdoc/store.rb
+++ b/lib/rdoc/store.rb
@@ -556,9 +556,7 @@ class RDoc::Store
def load_cache
#orig_enc = @encoding
- File.open cache_path, 'rb' do |io|
- @cache = Marshal.load io
- end
+ @cache = marshal_load(cache_path)
load_enc = @cache[:encoding]
@@ -615,9 +613,7 @@ class RDoc::Store
def load_class_data klass_name
file = class_file klass_name
- File.open file, 'rb' do |io|
- Marshal.load io
- end
+ marshal_load(file)
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, klass_name)
error.set_backtrace e.backtrace
@@ -630,14 +626,10 @@ class RDoc::Store
def load_method klass_name, method_name
file = method_file klass_name, method_name
- File.open file, 'rb' do |io|
- obj = Marshal.load io
- obj.store = self
- obj.parent =
- find_class_or_module(klass_name) || load_class(klass_name) unless
- obj.parent
- obj
- end
+ obj = marshal_load(file)
+ obj.store = self
+ obj.parent ||= find_class_or_module(klass_name) || load_class(klass_name)
+ obj
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, klass_name + method_name)
error.set_backtrace e.backtrace
@@ -650,11 +642,9 @@ class RDoc::Store
def load_page page_name
file = page_file page_name
- File.open file, 'rb' do |io|
- obj = Marshal.load io
- obj.store = self
- obj
- end
+ obj = marshal_load(file)
+ obj.store = self
+ obj
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, page_name)
error.set_backtrace e.backtrace
@@ -976,4 +966,21 @@ class RDoc::Store
@unique_modules
end
+ private
+ def marshal_load(file)
+ File.open(file, 'rb') {|io| Marshal.load(io, MarshalFilter)}
+ end
+
+ MarshalFilter = proc do |obj|
+ case obj
+ when true, false, nil, Array, Class, Encoding, Hash, Integer, String, Symbol, RDoc::Text
+ else
+ unless obj.class.name.start_with?("RDoc::")
+ raise TypeError, "not permitted class: #{obj.class.name}"
+ end
+ end
+ obj
+ end
+ private_constant :MarshalFilter
+
end
diff --git a/lib/rdoc/task.rb b/lib/rdoc/task.rb
index eb584c9d2a..8ea2d0588c 100644
--- a/lib/rdoc/task.rb
+++ b/lib/rdoc/task.rb
@@ -50,9 +50,6 @@ require 'rake/tasklib'
# [rerdoc]
# Rebuild the rdoc files from scratch, even if they are not out of date.
#
-# [rdoc:coverage]
-# Print RDoc coverage report for all rdoc files.
-#
# Simple Example:
#
# require 'rdoc/task'
@@ -93,8 +90,8 @@ require 'rake/tasklib'
# RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean",
# :rerdoc => "rdoc:force")
#
-# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt>,
-# <tt>:rdoc:force</tt>, and <tt>:rdoc:coverage</tt>.
+# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt> and
+# <tt>:rdoc:force</tt>.
class RDoc::Task < Rake::TaskLib
@@ -251,18 +248,6 @@ class RDoc::Task < Rake::TaskLib
RDoc::RDoc.new.document args
end
- namespace rdoc_task_name do
- desc coverage_task_description
- task coverage_task_name do
- @before_running_rdoc.call if @before_running_rdoc
- opts = option_list << "-C"
- args = opts + @rdoc_files
-
- $stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace
- RDoc::RDoc.new.document args
- end
- end
-
self
end
@@ -303,13 +288,6 @@ class RDoc::Task < Rake::TaskLib
"Rebuild RDoc HTML files"
end
- ##
- # Task description for the coverage task or its renamed description
-
- def coverage_task_description
- "Print RDoc coverage report"
- end
-
private
def rdoc_target
@@ -337,10 +315,6 @@ class RDoc::Task < Rake::TaskLib
end
end
- def coverage_task_name
- "coverage"
- end
-
end
# :stopdoc:
diff --git a/lib/rdoc/token_stream.rb b/lib/rdoc/token_stream.rb
index 8fc6eadd85..f428e2400c 100644
--- a/lib/rdoc/token_stream.rb
+++ b/lib/rdoc/token_stream.rb
@@ -116,3 +116,4 @@ module RDoc::TokenStream
end
end
+
diff --git a/lib/rdoc/top_level.rb b/lib/rdoc/top_level.rb
index e6caa34ee3..b8b6110bb2 100644
--- a/lib/rdoc/top_level.rb
+++ b/lib/rdoc/top_level.rb
@@ -286,3 +286,4 @@ class RDoc::TopLevel < RDoc::Context
end
end
+
diff --git a/lib/rdoc/version.rb b/lib/rdoc/version.rb
index 73071fe5ab..31c1aa0276 100644
--- a/lib/rdoc/version.rb
+++ b/lib/rdoc/version.rb
@@ -5,6 +5,6 @@ module RDoc
##
# RDoc version you are using
- VERSION = '6.6.0'
+ VERSION = '6.5.1.1'
end
diff --git a/lib/reline.rb b/lib/reline.rb
index fb19982081..7800a281ce 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -1,4 +1,5 @@
require 'io/console'
+require 'timeout'
require 'forwardable'
require 'reline/version'
require 'reline/config'
@@ -7,17 +8,15 @@ require 'reline/key_stroke'
require 'reline/line_editor'
require 'reline/history'
require 'reline/terminfo'
-require 'reline/face'
require 'rbconfig'
module Reline
- # NOTE: For making compatible with the rb-readline gem
FILENAME_COMPLETION_PROC = nil
USERNAME_COMPLETION_PROC = nil
class ConfigEncodingConversionError < StandardError; end
- Key = Struct.new(:char, :combined_char, :with_meta) do
+ Key = Struct.new('Key', :char, :combined_char, :with_meta) do
def match?(other)
case other
when Reline::Key
@@ -37,8 +36,10 @@ module Reline
DialogRenderInfo = Struct.new(
:pos,
:contents,
- :face,
- :bg_color, # For the time being, this line should stay here for the compatibility with IRB.
+ :bg_color,
+ :pointer_bg_color,
+ :fg_color,
+ :pointer_fg_color,
:width,
:height,
:scrollbar,
@@ -81,48 +82,44 @@ module Reline
@bracketed_paste_finished = false
end
- def io_gate
- Reline::IOGate
- end
-
def encoding
- io_gate.encoding
+ Reline::IOGate.encoding
end
def completion_append_character=(val)
if val.nil?
@completion_append_character = nil
elsif val.size == 1
- @completion_append_character = val.encode(encoding)
+ @completion_append_character = val.encode(Reline::IOGate.encoding)
elsif val.size > 1
- @completion_append_character = val[0].encode(encoding)
+ @completion_append_character = val[0].encode(Reline::IOGate.encoding)
else
@completion_append_character = nil
end
end
def basic_word_break_characters=(v)
- @basic_word_break_characters = v.encode(encoding)
+ @basic_word_break_characters = v.encode(Reline::IOGate.encoding)
end
def completer_word_break_characters=(v)
- @completer_word_break_characters = v.encode(encoding)
+ @completer_word_break_characters = v.encode(Reline::IOGate.encoding)
end
def basic_quote_characters=(v)
- @basic_quote_characters = v.encode(encoding)
+ @basic_quote_characters = v.encode(Reline::IOGate.encoding)
end
def completer_quote_characters=(v)
- @completer_quote_characters = v.encode(encoding)
+ @completer_quote_characters = v.encode(Reline::IOGate.encoding)
end
def filename_quote_characters=(v)
- @filename_quote_characters = v.encode(encoding)
+ @filename_quote_characters = v.encode(Reline::IOGate.encoding)
end
def special_prefixes=(v)
- @special_prefixes = v.encode(encoding)
+ @special_prefixes = v.encode(Reline::IOGate.encoding)
end
def completion_case_fold=(v)
@@ -168,13 +165,9 @@ module Reline
DialogProc = Struct.new(:dialog_proc, :context)
def add_dialog_proc(name_sym, p, context = nil)
+ raise ArgumentError unless p.respond_to?(:call) or p.nil?
raise ArgumentError unless name_sym.instance_of?(Symbol)
- if p.nil?
- @dialog_proc_list.delete(name_sym)
- else
- raise ArgumentError unless p.respond_to?(:call)
- @dialog_proc_list[name_sym] = DialogProc.new(p, context)
- end
+ @dialog_proc_list[name_sym] = DialogProc.new(p, context)
end
def dialog_proc(name_sym)
@@ -183,16 +176,20 @@ module Reline
def input=(val)
raise TypeError unless val.respond_to?(:getc) or val.nil?
- if val.respond_to?(:getc) && io_gate.respond_to?(:input=)
- io_gate.input = val
+ if val.respond_to?(:getc)
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
+ Reline::ANSI.input = val
+ elsif Reline::IOGate == Reline::GeneralIO
+ Reline::GeneralIO.input = val
+ end
end
end
def output=(val)
raise TypeError unless val.respond_to?(:write) or val.nil?
@output = val
- if io_gate.respond_to?(:output=)
- io_gate.output = val
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
+ Reline::ANSI.output = val
end
end
@@ -215,7 +212,7 @@ module Reline
end
def get_screen_size
- io_gate.get_screen_size
+ Reline::IOGate.get_screen_size
end
Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
@@ -258,33 +255,32 @@ module Reline
pos: cursor_pos_to_render,
contents: result,
scrollbar: true,
- height: [15, preferred_dialog_height].min,
- face: :completion_dialog
+ height: 15,
+ bg_color: 46,
+ pointer_bg_color: 45,
+ fg_color: 37,
+ pointer_fg_color: 37
)
}
Reline::DEFAULT_DIALOG_CONTEXT = Array.new
def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
- Reline.update_iogate
- io_gate.with_raw_input do
- unless confirm_multiline_termination
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
- end
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
-
- whole_buffer = line_editor.whole_buffer.dup
- whole_buffer.taint if RUBY_VERSION < '2.7'
- if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
- Reline::HISTORY << whole_buffer
- end
+ unless confirm_multiline_termination
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
+ end
+ inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
- line_editor.reset_line if line_editor.whole_buffer.nil?
- whole_buffer
+ whole_buffer = line_editor.whole_buffer.dup
+ whole_buffer.taint if RUBY_VERSION < '2.7'
+ if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
+ Reline::HISTORY << whole_buffer
end
+
+ line_editor.reset_line if line_editor.whole_buffer.nil?
+ whole_buffer
end
def readline(prompt = '', add_hist = false)
- Reline.update_iogate
inner_readline(prompt, add_hist, false)
line = line_editor.line.dup
@@ -299,7 +295,7 @@ module Reline
private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
if ENV['RELINE_STDERR_TTY']
- if io_gate.win?
+ if Reline::IOGate.win?
$stderr = File.open(ENV['RELINE_STDERR_TTY'], 'a')
else
$stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
@@ -307,10 +303,10 @@ module Reline
$stderr.sync = true
$stderr.puts "Reline is used by #{Process.pid}"
end
- otio = io_gate.prep
+ otio = Reline::IOGate.prep
may_req_ambiguous_char_width
- line_editor.reset(prompt, encoding: encoding)
+ line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
if multiline
line_editor.multiline_on
if block_given?
@@ -334,7 +330,7 @@ module Reline
unless config.test_mode
config.read
config.reset_default_key_bindings
- io_gate.set_default_key_bindings(config)
+ Reline::IOGate.set_default_key_bindings(config)
end
line_editor.rerender
@@ -343,9 +339,9 @@ module Reline
line_editor.set_signal_handlers
prev_pasting_state = false
loop do
- prev_pasting_state = io_gate.in_pasting?
+ prev_pasting_state = Reline::IOGate.in_pasting?
read_io(config.keyseq_timeout) { |inputs|
- line_editor.set_pasting_state(io_gate.in_pasting?)
+ line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
inputs.each { |c|
line_editor.input_key(c)
line_editor.rerender
@@ -355,29 +351,29 @@ module Reline
@bracketed_paste_finished = false
end
}
- if prev_pasting_state == true and not io_gate.in_pasting? and not line_editor.finished?
+ if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
line_editor.set_pasting_state(false)
prev_pasting_state = false
line_editor.rerender_all
end
break if line_editor.finished?
end
- io_gate.move_cursor_column(0)
+ Reline::IOGate.move_cursor_column(0)
rescue Errno::EIO
# Maybe the I/O has been closed.
rescue StandardError => e
line_editor.finalize
- io_gate.deprep(otio)
+ Reline::IOGate.deprep(otio)
raise e
rescue Exception
# Including Interrupt
line_editor.finalize
- io_gate.deprep(otio)
+ Reline::IOGate.deprep(otio)
raise
end
line_editor.finalize
- io_gate.deprep(otio)
+ Reline::IOGate.deprep(otio)
end
# GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
@@ -392,7 +388,7 @@ module Reline
private def read_io(keyseq_timeout, &block)
buffer = []
loop do
- c = io_gate.getc(Float::INFINITY)
+ c = Reline::IOGate.getc
if c == -1
result = :unmatched
@bracketed_paste_finished = true
@@ -429,8 +425,15 @@ module Reline
end
private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
- succ_c = io_gate.getc(keyseq_timeout.fdiv(1000))
- if succ_c
+ begin
+ succ_c = nil
+ Timeout.timeout(keyseq_timeout / 1000.0) {
+ succ_c = Reline::IOGate.getc
+ }
+ rescue Timeout::Error # cancel matching only when first byte
+ block.([Reline::Key.new(c, c, false)])
+ return :break
+ else
case key_stroke.match_status(buffer.dup.push(succ_c))
when :unmatched
if c == "\e".ord
@@ -440,7 +443,7 @@ module Reline
end
return :break
when :matching
- io_gate.ungetc(succ_c)
+ Reline::IOGate.ungetc(succ_c)
return :next
when :matched
buffer << succ_c
@@ -450,23 +453,27 @@ module Reline
block.(expanded)
return :break
end
- else
- block.([Reline::Key.new(c, c, false)])
- return :break
end
end
private def read_escaped_key(keyseq_timeout, c, block)
- escaped_c = io_gate.getc(keyseq_timeout.fdiv(1000))
-
- if escaped_c.nil?
+ begin
+ escaped_c = nil
+ Timeout.timeout(keyseq_timeout / 1000.0) {
+ escaped_c = Reline::IOGate.getc
+ }
+ rescue Timeout::Error # independent ESC
block.([Reline::Key.new(c, c, false)])
- elsif escaped_c >= 128 # maybe, first byte of multi byte
- block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
- elsif escaped_c == "\e".ord # escape twice
- block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
else
- block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
+ if escaped_c.nil?
+ block.([Reline::Key.new(c, c, false)])
+ elsif escaped_c >= 128 # maybe, first byte of multi byte
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
+ elsif escaped_c == "\e".ord # escape twice
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
+ else
+ block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
+ end
end
end
@@ -476,19 +483,19 @@ module Reline
end
private def may_req_ambiguous_char_width
- @ambiguous_width = 2 if io_gate == Reline::GeneralIO or !STDOUT.tty?
+ @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or !STDOUT.tty?
return if defined? @ambiguous_width
- io_gate.move_cursor_column(0)
+ Reline::IOGate.move_cursor_column(0)
begin
output.write "\u{25bd}"
rescue Encoding::UndefinedConversionError
# LANG=C
@ambiguous_width = 1
else
- @ambiguous_width = io_gate.cursor_pos.x
+ @ambiguous_width = Reline::IOGate.cursor_pos.x
end
- io_gate.move_cursor_column(0)
- io_gate.erase_after_cursor
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
end
end
@@ -551,7 +558,7 @@ module Reline
@core ||= Core.new { |core|
core.config = Reline::Config.new
core.key_stroke = Reline::KeyStroke.new(core.config)
- core.line_editor = Reline::LineEditor.new(core.config, core.encoding)
+ core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
core.basic_word_break_characters = " \t\n`><=;|&{("
core.completer_word_break_characters = " \t\n`><=;|&{("
@@ -564,24 +571,12 @@ module Reline
end
def self.ungetc(c)
- core.io_gate.ungetc(c)
+ Reline::IOGate.ungetc(c)
end
def self.line_editor
core.line_editor
end
-
- def self.update_iogate
- return if core.config.test_mode
-
- # Need to change IOGate when `$stdout.tty?` change from false to true by `$stdout.reopen`
- # Example: rails/spring boot the application in non-tty, then run console in tty.
- if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty?
- require 'reline/ansi'
- remove_const(:IOGate)
- const_set(:IOGate, Reline::ANSI)
- end
- end
end
require 'reline/general_io'
@@ -602,6 +597,4 @@ else
io
end
-Reline::Face.load_initial_configs
-
Reline::HISTORY = Reline::History.new(Reline.core.config)
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
index c2e5075ea8..c40085e50d 100644
--- a/lib/reline/ansi.rb
+++ b/lib/reline/ansi.rb
@@ -1,33 +1,20 @@
require 'io/console'
require 'io/wait'
+require 'timeout'
require_relative 'terminfo'
class Reline::ANSI
CAPNAME_KEY_BINDINGS = {
'khome' => :ed_move_to_beg,
'kend' => :ed_move_to_end,
- 'kdch1' => :key_delete,
- 'kpp' => :ed_search_prev_history,
- 'knp' => :ed_search_next_history,
'kcuu1' => :ed_prev_history,
'kcud1' => :ed_next_history,
'kcuf1' => :ed_next_char,
'kcub1' => :ed_prev_char,
- }
-
- ANSI_CURSOR_KEY_BINDINGS = {
- # Up
- 'A' => [:ed_prev_history, {}],
- # Down
- 'B' => [:ed_next_history, {}],
- # Right
- 'C' => [:ed_next_char, { ctrl: :em_next_word, meta: :em_next_word }],
- # Left
- 'D' => [:ed_prev_char, { ctrl: :ed_prev_word, meta: :ed_prev_word }],
- # End
- 'F' => [:ed_move_to_end, {}],
- # Home
- 'H' => [:ed_move_to_beg, {}],
+ 'cuu' => :ed_prev_history,
+ 'cud' => :ed_next_history,
+ 'cuf' => :ed_next_char,
+ 'cub' => :ed_prev_char,
}
if Reline::Terminfo.enabled?
@@ -42,14 +29,24 @@ class Reline::ANSI
false
end
- def self.set_default_key_bindings(config, allow_terminfo: true)
- set_default_key_bindings_ansi_cursor(config)
- if allow_terminfo && Reline::Terminfo.enabled?
+ def self.set_default_key_bindings(config)
+ if Reline::Terminfo.enabled?
set_default_key_bindings_terminfo(config)
else
set_default_key_bindings_comprehensive_list(config)
end
{
+ # extended entries of terminfo
+ [27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
+ [27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
+ [27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
+ [27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+←, extended entry
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
+ end
+ {
[27, 91, 90] => :completion_journey_up, # S-Tab
}.each_pair do |key, func|
config.add_default_key_binding_by_keymap(:emacs, key, func)
@@ -64,33 +61,18 @@ class Reline::ANSI
end
end
- def self.set_default_key_bindings_ansi_cursor(config)
- ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
- bindings = [["\e[#{char}", default_func]] # CSI + char
- if modifiers[:ctrl]
- # CSI + ctrl_key_modifier + char
- bindings << ["\e[1;5#{char}", modifiers[:ctrl]]
- end
- if modifiers[:meta]
- # CSI + meta_key_modifier + char
- bindings << ["\e[1;3#{char}", modifiers[:meta]]
- # Meta(ESC) + CSI + char
- bindings << ["\e\e[#{char}", modifiers[:meta]]
- end
- bindings.each do |sequence, func|
- key = sequence.bytes
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
- end
-
def self.set_default_key_bindings_terminfo(config)
key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
begin
key_code = Reline::Terminfo.tigetstr(capname)
- [ key_code.bytes, key_binding ]
+ case capname
+ # Escape sequences that omit the move distance and are set to defaults
+ # value 1 may be sometimes sent by pressing the arrow-key.
+ when 'cuu', 'cud', 'cuf', 'cub'
+ [ key_code.sub(/%p1%d/, '').bytes, key_binding ]
+ else
+ [ key_code.bytes, key_binding ]
+ end
rescue Reline::Terminfo::TerminfoError
# capname is undefined
end
@@ -109,8 +91,14 @@ class Reline::ANSI
[27, 91, 49, 126] => :ed_move_to_beg, # Home
[27, 91, 52, 126] => :ed_move_to_end, # End
[27, 91, 51, 126] => :key_delete, # Del
+ [27, 91, 65] => :ed_prev_history, # ↑
+ [27, 91, 66] => :ed_next_history, # ↓
+ [27, 91, 67] => :ed_next_char, # →
+ [27, 91, 68] => :ed_prev_char, # ←
# KDE
+ [27, 91, 72] => :ed_move_to_beg, # Home
+ [27, 91, 70] => :ed_move_to_end, # End
# Del is 0x08
[27, 71, 65] => :ed_prev_history, # ↑
[27, 71, 66] => :ed_next_history, # ↓
@@ -127,6 +115,12 @@ class Reline::ANSI
# Del is 0x08
# Arrow keys are the same of KDE
+ # iTerm2
+ [27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
+ [27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
+ [195, 166] => :em_next_word, # Option+f
+ [195, 162] => :ed_prev_word, # Option+b
+
[27, 79, 65] => :ed_prev_history, # ↑
[27, 79, 66] => :ed_next_history, # ↓
[27, 79, 67] => :ed_next_char, # →
@@ -148,18 +142,12 @@ class Reline::ANSI
@@output = val
end
- def self.with_raw_input
- @@input.raw { yield }
- end
-
@@buf = []
- def self.inner_getc(timeout_second)
+ def self.inner_getc
unless @@buf.empty?
return @@buf.shift
end
until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
- timeout_second -= 0.1
- return nil if timeout_second <= 0
Reline.core.line_editor.resize
end
(c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
@@ -173,43 +161,45 @@ class Reline::ANSI
@@in_bracketed_paste_mode = false
START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
- def self.getc_with_bracketed_paste(timeout_second)
+ def self.getc_with_bracketed_paste
buffer = String.new(encoding: Encoding::ASCII_8BIT)
- buffer << inner_getc(timeout_second)
+ buffer << inner_getc
while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
if START_BRACKETED_PASTE == buffer
@@in_bracketed_paste_mode = true
- return inner_getc(timeout_second)
+ return inner_getc
elsif END_BRACKETED_PASTE == buffer
@@in_bracketed_paste_mode = false
ungetc(-1)
- return inner_getc(timeout_second)
+ return inner_getc
end
- succ_c = inner_getc(Reline.core.config.keyseq_timeout)
-
- if succ_c
- buffer << succ_c
- else
+ begin
+ succ_c = nil
+ Timeout.timeout(Reline.core.config.keyseq_timeout * 100) {
+ succ_c = inner_getc
+ }
+ rescue Timeout::Error
break
+ else
+ buffer << succ_c
end
end
buffer.bytes.reverse_each do |ch|
ungetc ch
end
- inner_getc(timeout_second)
+ inner_getc
end
- # if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
- def self.getc(timeout_second)
+ def self.getc
if Reline.core.config.enable_bracketed_paste
- getc_with_bracketed_paste(timeout_second)
+ getc_with_bracketed_paste
else
- inner_getc(timeout_second)
+ inner_getc
end
end
def self.in_pasting?
- @@in_bracketed_paste_mode or (not empty_buffer?)
+ @@in_bracketed_paste_mode or (not Reline::IOGate.empty_buffer?)
end
def self.empty_buffer?
@@ -334,12 +324,9 @@ class Reline::ANSI
@@output.write "\e[K"
end
- # This only works when the cursor is at the bottom of the scroll range
- # For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
def self.scroll_down(x)
return if x.zero?
- # We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
- @@output.write "\n" * x
+ @@output.write "\e[#{x}S"
end
def self.clear_screen
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
index 4c07a73701..5ba269258f 100644
--- a/lib/reline/config.rb
+++ b/lib/reline/config.rb
@@ -93,7 +93,7 @@ class Reline::Config
end
def editing_mode_is?(*val)
- val.any?(@editing_mode_label)
+ (val.respond_to?(:any?) ? val : [val]).any?(@editing_mode_label)
end
def keymap
@@ -252,7 +252,7 @@ class Reline::Config
end
@skip_section = @if_stack.pop
when 'include'
- read(File.expand_path(args))
+ read(args)
end
end
diff --git a/lib/reline/face.rb b/lib/reline/face.rb
deleted file mode 100644
index b78f3b1ca5..0000000000
--- a/lib/reline/face.rb
+++ /dev/null
@@ -1,157 +0,0 @@
-# frozen_string_literal: true
-
-class Reline::Face
- SGR_PARAMETERS = {
- foreground: {
- black: 30,
- red: 31,
- green: 32,
- yellow: 33,
- blue: 34,
- magenta: 35,
- cyan: 36,
- white: 37,
- bright_black: 90,
- gray: 90,
- bright_red: 91,
- bright_green: 92,
- bright_yellow: 93,
- bright_blue: 94,
- bright_magenta: 95,
- bright_cyan: 96,
- bright_white: 97
- },
- background: {
- black: 40,
- red: 41,
- green: 42,
- yellow: 43,
- blue: 44,
- magenta: 45,
- cyan: 46,
- white: 47,
- bright_black: 100,
- gray: 100,
- bright_red: 101,
- bright_green: 102,
- bright_yellow: 103,
- bright_blue: 104,
- bright_magenta: 105,
- bright_cyan: 106,
- bright_white: 107,
- },
- style: {
- reset: 0,
- bold: 1,
- faint: 2,
- italicized: 3,
- underlined: 4,
- slowly_blinking: 5,
- blinking: 5,
- rapidly_blinking: 6,
- negative: 7,
- concealed: 8,
- crossed_out: 9
- }
- }.freeze
-
- class Config
- ESSENTIAL_DEFINE_NAMES = %i(default enhanced scrollbar).freeze
- RESET_SGR = "\e[0m".freeze
-
- def initialize(name, &block)
- @definition = {}
- block.call(self)
- ESSENTIAL_DEFINE_NAMES.each do |name|
- @definition[name] ||= { style: :reset, escape_sequence: RESET_SGR }
- end
- end
-
- attr_reader :definition
-
- def define(name, **values)
- values[:escape_sequence] = format_to_sgr(values.to_a).freeze
- @definition[name] = values
- end
-
- def [](name)
- @definition.dig(name, :escape_sequence) or raise ArgumentError, "unknown face: #{name}"
- end
-
- private
-
- def sgr_rgb(key, value)
- return nil unless rgb_expression?(value)
- case key
- when :foreground
- "38;2;"
- when :background
- "48;2;"
- end + value[1, 6].scan(/../).map(&:hex).join(";")
- end
-
- def format_to_sgr(ordered_values)
- sgr = "\e[" + ordered_values.map do |key_value|
- key, value = key_value
- case key
- when :foreground, :background
- case value
- when Symbol
- SGR_PARAMETERS[key][value]
- when String
- sgr_rgb(key, value)
- end
- when :style
- [ value ].flatten.map do |style_name|
- SGR_PARAMETERS[:style][style_name]
- end.then do |sgr_parameters|
- sgr_parameters.include?(nil) ? nil : sgr_parameters
- end
- end.then do |rendition_expression|
- unless rendition_expression
- raise ArgumentError, "invalid SGR parameter: #{value.inspect}"
- end
- rendition_expression
- end
- end.join(';') + "m"
- sgr == RESET_SGR ? RESET_SGR : RESET_SGR + sgr
- end
-
- def rgb_expression?(color)
- color.respond_to?(:match?) and color.match?(/\A#[0-9a-fA-F]{6}\z/)
- end
- end
-
- private_constant :SGR_PARAMETERS, :Config
-
- def self.[](name)
- @configs[name]
- end
-
- def self.config(name, &block)
- @configs ||= {}
- @configs[name] = Config.new(name, &block)
- end
-
- def self.configs
- @configs.transform_values(&:definition)
- end
-
- def self.load_initial_configs
- config(:default) do |conf|
- conf.define :default, style: :reset
- conf.define :enhanced, style: :reset
- conf.define :scrollbar, style: :reset
- end
- config(:completion_dialog) do |conf|
- conf.define :default, foreground: :white, background: :cyan
- conf.define :enhanced, foreground: :white, background: :magenta
- conf.define :scrollbar, foreground: :white, background: :cyan
- end
- end
-
- def self.reset_to_initial_configs
- @configs = {}
- load_initial_configs
- end
-end
diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb
index eaae63f925..92c76cbba1 100644
--- a/lib/reline/general_io.rb
+++ b/lib/reline/general_io.rb
@@ -1,13 +1,10 @@
+require 'timeout'
require 'io/wait'
class Reline::GeneralIO
def self.reset(encoding: nil)
@@pasting = false
- if encoding
- @@encoding = encoding
- elsif defined?(@@encoding)
- remove_class_variable(:@@encoding)
- end
+ @@encoding = encoding
end
def self.encoding
@@ -34,11 +31,7 @@ class Reline::GeneralIO
@@input = val
end
- def self.with_raw_input
- yield
- end
-
- def self.getc(_timeout_second)
+ def self.getc
unless @@buf.empty?
return @@buf.shift
end
diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb
index bceffbb53f..c1c61513a9 100644
--- a/lib/reline/key_stroke.rb
+++ b/lib/reline/key_stroke.rb
@@ -1,8 +1,4 @@
class Reline::KeyStroke
- ESC_BYTE = 27
- CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f
- CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f)
-
def initialize(config)
@config = config
end
@@ -77,26 +73,17 @@ class Reline::KeyStroke
return :matched if it.max_by(&:size)&.size&.< input.size
return :matching if it.size > 1
}
- if key_mapping.keys.any? { |lhs| start_with?(input, lhs) }
- :matched
- else
- match_unknown_escape_sequence(input).first
- end
+ key_mapping.keys.select { |lhs|
+ start_with?(input, lhs)
+ }.tap { |it|
+ return it.size > 0 ? :matched : :unmatched
+ }
end
def expand(input)
+ input = compress_meta_key(input)
lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
- unless lhs
- status, size = match_unknown_escape_sequence(input)
- case status
- when :matched
- return [:ed_unassigned] + expand(input.drop(size))
- when :matching
- return [:ed_unassigned]
- else
- return input
- end
- end
+ return input unless lhs
rhs = key_mapping[lhs]
case rhs
@@ -112,36 +99,6 @@ class Reline::KeyStroke
private
- # returns match status of CSI/SS3 sequence and matched length
- def match_unknown_escape_sequence(input)
- idx = 0
- return [:unmatched, nil] unless input[idx] == ESC_BYTE
- idx += 1
- idx += 1 if input[idx] == ESC_BYTE
-
- case input[idx]
- when nil
- return [:matching, nil]
- when 91 # == '['.ord
- # CSI sequence
- idx += 1
- idx += 1 while idx < input.size && CSI_PARAMETER_BYTES_RANGE.cover?(input[idx])
- idx += 1 while idx < input.size && CSI_INTERMEDIATE_BYTES_RANGE.cover?(input[idx])
- input[idx] ? [:matched, idx + 1] : [:matching, nil]
- when 79 # == 'O'.ord
- # SS3 sequence
- input[idx + 1] ? [:matched, idx + 2] : [:matching, nil]
- else
- if idx == 1
- # `ESC char`, make it :unmatched so that it will be handled correctly in `read_2nd_character_of_key_sequence`
- [:unmatched, nil]
- else
- # `ESC ESC char`
- [:matched, idx + 1]
- end
- end
- end
-
def key_mapping
@config.key_bindings
end
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index d71b903701..8153aaba05 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -48,11 +48,10 @@ class Reline::LineEditor
PERFECT_MATCH = :perfect_match
end
- CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
- MenuInfo = Struct.new(:target, :list)
+ CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
+ MenuInfo = Struct.new('MenuInfo', :target, :list)
PROMPT_LIST_CACHE_TIMEOUT = 0.5
- MINIMUM_SCROLLBAR_HEIGHT = 1
def initialize(config, encoding)
@config = config
@@ -60,10 +59,6 @@ class Reline::LineEditor
reset_variables(encoding: encoding)
end
- def io_gate
- Reline::IOGate
- end
-
def set_pasting_state(in_pasting)
@in_pasting = in_pasting
end
@@ -98,7 +93,7 @@ class Reline::LineEditor
mode_string
end
- private def check_multiline_prompt(buffer, force_recalc: false)
+ private def check_multiline_prompt(buffer)
if @vi_arg
prompt = "(arg: #{@vi_arg}) "
@rerender_all = true
@@ -108,7 +103,7 @@ class Reline::LineEditor
else
prompt = @prompt
end
- if simplified_rendering? && !force_recalc
+ if simplified_rendering?
mode_string = check_mode_string
prompt = mode_string + prompt if mode_string
return [prompt, calculate_width(prompt, true), [prompt] * buffer.size]
@@ -224,7 +219,7 @@ class Reline::LineEditor
def set_signal_handlers
@old_trap = Signal.trap('INT') {
- clear_dialog(0)
+ clear_dialog
if @scroll_partial_screen
move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
else
@@ -243,10 +238,21 @@ class Reline::LineEditor
@old_trap.call if @old_trap.respond_to?(:call)
end
}
+ begin
+ @old_tstp_trap = Signal.trap('TSTP') {
+ Reline::IOGate.ungetc("\C-z".ord)
+ @old_tstp_trap.call if @old_tstp_trap.respond_to?(:call)
+ }
+ rescue ArgumentError
+ end
end
def finalize
Signal.trap('INT', @old_trap)
+ begin
+ Signal.trap('TSTP', @old_tstp_trap)
+ rescue ArgumentError
+ end
end
def eof?
@@ -287,7 +293,6 @@ class Reline::LineEditor
@in_pasting = false
@auto_indent_proc = nil
@dialogs = []
- @previous_rendered_dialog_y = 0
@last_key = nil
@resized = false
reset_line
@@ -434,7 +439,6 @@ class Reline::LineEditor
@menu_info = nil
end
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
- cursor_column = (prompt_width + @cursor) % @screen_size.last
if @cleared
clear_screen_buffer(prompt, prompt_list, prompt_width)
@cleared = false
@@ -445,30 +449,34 @@ class Reline::LineEditor
Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
Reline::IOGate.move_cursor_column(0)
@scroll_partial_screen = nil
- new_lines = whole_lines
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
+ prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ new_lines = whole_lines
+ end
modify_lines(new_lines).each_with_index do |line, index|
- @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\r\n"
+ @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n"
Reline::IOGate.erase_after_cursor
end
@output.flush
- clear_dialog(cursor_column)
+ clear_dialog
return
end
new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
rendered = false
if @add_newline_to_end_of_buffer
- clear_dialog_with_trap_key(cursor_column)
- rerender_added_newline(prompt, prompt_width, prompt_list)
+ clear_dialog_with_content
+ rerender_added_newline(prompt, prompt_width)
@add_newline_to_end_of_buffer = false
else
if @just_cursor_moving and not @rerender_all
- clear_dialog_with_trap_key(cursor_column)
+ clear_dialog_with_content
rendered = just_move_cursor
@just_cursor_moving = false
return
elsif @previous_line_index or new_highest_in_this != @highest_in_this
- clear_dialog_with_trap_key(cursor_column)
+ clear_dialog_with_content
rerender_changed_current_line
@previous_line_index = nil
rendered = true
@@ -482,9 +490,13 @@ class Reline::LineEditor
if @is_multiline
if finished?
# Always rerender on finish because output_modifier_proc may return a different output.
- new_lines = whole_lines
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ new_lines = whole_lines
+ end
line = modify_lines(new_lines)[@line_index]
- clear_dialog(cursor_column)
+ clear_dialog
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
render_partial(prompt, prompt_width, line, @first_line_started_from)
move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
@@ -497,7 +509,7 @@ class Reline::LineEditor
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
render_partial(prompt, prompt_width, line, @first_line_started_from)
end
- render_dialog(cursor_column)
+ render_dialog((prompt_width + @cursor) % @screen_size.last)
end
@buffer_of_lines[@line_index] = @line
@rest_height = 0 if @scroll_partial_screen
@@ -566,16 +578,6 @@ class Reline::LineEditor
@line_editor.instance_variable_get(:@screen_size).last
end
- def screen_height
- @line_editor.instance_variable_get(:@screen_size).first
- end
-
- def preferred_dialog_height
- rest_height = @line_editor.instance_variable_get(:@rest_height)
- scroll_partial_screen = @line_editor.instance_variable_get(:@scroll_partial_screen) || 0
- [cursor_pos.y - scroll_partial_screen, rest_height, (screen_height + 6) / 5].max
- end
-
def completion_journey_data
@line_editor.instance_variable_get(:@completion_journey_data)
end
@@ -591,7 +593,7 @@ class Reline::LineEditor
class Dialog
attr_reader :name, :contents, :width
- attr_accessor :scroll_top, :pointer, :column, :vertical_offset, :trap_key
+ attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
def initialize(name, config, proc_scope)
@name = name
@@ -647,12 +649,9 @@ class Reline::LineEditor
DIALOG_DEFAULT_HEIGHT = 20
private def render_dialog(cursor_column)
- changes = @dialogs.map do |dialog|
- old_dialog = dialog.dup
- update_each_dialog(dialog, cursor_column)
- [old_dialog, dialog]
+ @dialogs.each do |dialog|
+ render_each_dialog(dialog, cursor_column)
end
- render_dialog_changes(changes, cursor_column)
end
private def padding_space_with_escape_sequences(str, width)
@@ -662,112 +661,9 @@ class Reline::LineEditor
str + (' ' * padding_width)
end
- private def range_subtract(base_ranges, subtract_ranges)
- indices = base_ranges.flat_map(&:to_a).uniq.sort - subtract_ranges.flat_map(&:to_a)
- chunks = indices.chunk_while { |a, b| a + 1 == b }
- chunks.map { |a| a.first...a.last + 1 }
- end
-
- private def dialog_range(dialog, dialog_y)
- x_range = dialog.column...dialog.column + dialog.width
- y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
- [x_range, y_range]
- end
-
- private def render_dialog_changes(changes, cursor_column)
- # Collect x-coordinate range and content of previous and current dialogs for each line
- old_dialog_ranges = {}
- new_dialog_ranges = {}
- new_dialog_contents = {}
- changes.each do |old_dialog, new_dialog|
- if old_dialog.contents
- x_range, y_range = dialog_range(old_dialog, @previous_rendered_dialog_y)
- y_range.each do |y|
- (old_dialog_ranges[y] ||= []) << x_range
- end
- end
- if new_dialog.contents
- x_range, y_range = dialog_range(new_dialog, @first_line_started_from + @started_from)
- y_range.each do |y|
- (new_dialog_ranges[y] ||= []) << x_range
- (new_dialog_contents[y] ||= []) << [x_range, new_dialog.contents[y - y_range.begin]]
- end
- end
- end
- return if old_dialog_ranges.empty? && new_dialog_ranges.empty?
-
- # Calculate x-coordinate ranges to restore text that was hidden behind dialogs for each line
- ranges_to_restore = {}
- subtract_cache = {}
- old_dialog_ranges.each do |y, old_x_ranges|
- new_x_ranges = new_dialog_ranges[y] || []
- ranges = subtract_cache[[old_x_ranges, new_x_ranges]] ||= range_subtract(old_x_ranges, new_x_ranges)
- ranges_to_restore[y] = ranges if ranges.any?
- end
-
- # Create visual_lines for restoring text hidden behind dialogs
- if ranges_to_restore.any?
- lines = whole_lines
- prompt, _prompt_width, prompt_list = check_multiline_prompt(lines, force_recalc: true)
- modified_lines = modify_lines(lines, force_recalc: true)
- visual_lines = []
- modified_lines.each_with_index { |l, i|
- pr = prompt_list ? prompt_list[i] : prompt
- vl, = split_by_width(pr + l, @screen_size.last)
- vl.compact!
- visual_lines.concat(vl)
- }
- end
-
- # Clear and rerender all dialogs line by line
- Reline::IOGate.hide_cursor
- ymin, ymax = (ranges_to_restore.keys + new_dialog_ranges.keys).minmax
- scroll_partial_screen = @scroll_partial_screen || 0
- screen_y_range = scroll_partial_screen..(scroll_partial_screen + @screen_height - 1)
- ymin = ymin.clamp(screen_y_range.begin, screen_y_range.end)
- ymax = ymax.clamp(screen_y_range.begin, screen_y_range.end)
- dialog_y = @first_line_started_from + @started_from
- cursor_y = dialog_y
- if @highest_in_all <= ymax
- scroll_down(ymax - cursor_y)
- move_cursor_up(ymax - cursor_y)
- end
- (ymin..ymax).each do |y|
- move_cursor_down(y - cursor_y)
- cursor_y = y
- new_x_ranges = new_dialog_ranges[y]
- restore_ranges = ranges_to_restore[y]
- # Restore text that was hidden behind dialogs
- if restore_ranges
- line = visual_lines[y] || ''
- restore_ranges.each do |range|
- col = range.begin
- width = range.end - range.begin
- s = padding_space_with_escape_sequences(Reline::Unicode.take_range(line, col, width), width)
- Reline::IOGate.move_cursor_column(col)
- @output.write "\e[0m#{s}\e[0m"
- end
- max_column = [calculate_width(line, true), new_x_ranges&.map(&:end)&.max || 0].max
- if max_column < restore_ranges.map(&:end).max
- Reline::IOGate.move_cursor_column(max_column)
- Reline::IOGate.erase_after_cursor
- end
- end
- # Render dialog contents
- new_dialog_contents[y]&.each do |x_range, content|
- Reline::IOGate.move_cursor_column(x_range.begin)
- @output.write "\e[0m#{content}\e[0m"
- end
- end
- move_cursor_up(cursor_y - dialog_y)
- Reline::IOGate.move_cursor_column(cursor_column)
- Reline::IOGate.show_cursor
-
- @previous_rendered_dialog_y = dialog_y
- end
-
- private def update_each_dialog(dialog, cursor_column)
+ private def render_each_dialog(dialog, cursor_column)
if @in_pasting
+ clear_each_dialog(dialog)
dialog.contents = nil
dialog.trap_key = nil
return
@@ -775,20 +671,29 @@ class Reline::LineEditor
dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
dialog_render_info = dialog.call(@last_key)
if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
+ dialog.lines_backup = {
+ lines: modify_lines(whole_lines),
+ line_index: @line_index,
+ first_line_started_from: @first_line_started_from,
+ started_from: @started_from,
+ byte_pointer: @byte_pointer
+ }
+ clear_each_dialog(dialog)
dialog.contents = nil
dialog.trap_key = nil
return
end
- contents = dialog_render_info.contents
+ old_dialog = dialog.clone
+ dialog.contents = dialog_render_info.contents
pointer = dialog.pointer
if dialog_render_info.width
dialog.width = dialog_render_info.width
else
- dialog.width = contents.map { |l| calculate_width(l, true) }.max
+ dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
end
height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
- height = contents.size if contents.size < height
- if contents.size > height
+ height = dialog.contents.size if dialog.contents.size < height
+ if dialog.contents.size > height
if dialog.pointer
if dialog.pointer < 0
dialog.scroll_top = 0
@@ -798,24 +703,24 @@ class Reline::LineEditor
dialog.scroll_top = dialog.pointer
end
pointer = dialog.pointer - dialog.scroll_top
- else
- dialog.scroll_top = 0
end
- contents = contents[dialog.scroll_top, height]
+ dialog.contents = dialog.contents[dialog.scroll_top, height]
+ end
+ if dialog.contents and dialog.scroll_top >= dialog.contents.size
+ dialog.scroll_top = dialog.contents.size - height
end
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
bar_max_height = height * 2
moving_distance = (dialog_render_info.contents.size - height) * 2
position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
- bar_height = (bar_max_height * ((contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
- bar_height = MINIMUM_SCROLLBAR_HEIGHT if bar_height < MINIMUM_SCROLLBAR_HEIGHT
- scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
+ bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
+ dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
else
- scrollbar_pos = nil
+ dialog.scrollbar_pos = nil
end
upper_space = @first_line_started_from - @started_from
dialog.column = dialog_render_info.pos.x
- dialog.width += @block_elem_width if scrollbar_pos
+ dialog.width += @block_elem_width if dialog.scrollbar_pos
diff = (dialog.column + dialog.width) - (@screen_size.last)
if diff > 0
dialog.column -= diff
@@ -825,53 +730,207 @@ class Reline::LineEditor
elsif upper_space >= height
dialog.vertical_offset = dialog_render_info.pos.y - height
else
+ if (@rest_height - dialog_render_info.pos.y) < height
+ scroll_down(height + dialog_render_info.pos.y)
+ move_cursor_up(height + dialog_render_info.pos.y)
+ end
dialog.vertical_offset = dialog_render_info.pos.y + 1
end
+ Reline::IOGate.hide_cursor
if dialog.column < 0
dialog.column = 0
dialog.width = @screen_size.last
end
- face = Reline::Face[dialog_render_info.face || :default]
- scrollbar_sgr = face[:scrollbar]
- default_sgr = face[:default]
- enhanced_sgr = face[:enhanced]
- dialog.contents = contents.map.with_index do |item, i|
- line_sgr = i == pointer ? enhanced_sgr : default_sgr
- str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
+ reset_dialog(dialog, old_dialog)
+ move_cursor_down(dialog.vertical_offset)
+ Reline::IOGate.move_cursor_column(dialog.column)
+ dialog.contents.each_with_index do |item, i|
+ if i == pointer
+ fg_color = dialog_render_info.pointer_fg_color
+ bg_color = dialog_render_info.pointer_bg_color
+ else
+ fg_color = dialog_render_info.fg_color
+ bg_color = dialog_render_info.bg_color
+ end
+ str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
- colored_content = "#{line_sgr}#{str}"
- if scrollbar_pos
- if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @full_block
- elsif scrollbar_pos <= (i * 2) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @upper_half_block
- elsif scrollbar_pos <= (i * 2 + 1) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @lower_half_block
+ @output.write "\e[#{bg_color}m\e[#{fg_color}m#{str}"
+ if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
+ @output.write "\e[37m"
+ if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
+ @output.write @full_block
+ elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
+ @output.write @upper_half_block
+ elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
+ @output.write @lower_half_block
else
- colored_content + scrollbar_sgr + ' ' * @block_elem_width
+ @output.write ' ' * @block_elem_width
end
- else
- colored_content
end
+ @output.write "\e[0m"
+ Reline::IOGate.move_cursor_column(dialog.column)
+ move_cursor_down(1) if i < (dialog.contents.size - 1)
end
+ Reline::IOGate.move_cursor_column(cursor_column)
+ move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
+ Reline::IOGate.show_cursor
+ dialog.lines_backup = {
+ lines: modify_lines(whole_lines),
+ line_index: @line_index,
+ first_line_started_from: @first_line_started_from,
+ started_from: @started_from,
+ byte_pointer: @byte_pointer
+ }
end
- private def clear_dialog(cursor_column)
- changes = @dialogs.map do |dialog|
- old_dialog = dialog.dup
- dialog.contents = nil
- [old_dialog, dialog]
+ private def reset_dialog(dialog, old_dialog)
+ return if dialog.lines_backup.nil? or old_dialog.contents.nil?
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
+ visual_lines = []
+ visual_start = nil
+ dialog.lines_backup[:lines].each_with_index { |l, i|
+ pr = prompt_list ? prompt_list[i] : prompt
+ vl, _ = split_by_width(pr + l, @screen_size.last)
+ vl.compact!
+ if i == dialog.lines_backup[:line_index]
+ visual_start = visual_lines.size + dialog.lines_backup[:started_from]
+ end
+ visual_lines.concat(vl)
+ }
+ old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
+ y = @first_line_started_from + @started_from
+ y_diff = y - old_y
+ if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset)
+ # rerender top
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
+ start = visual_start + old_dialog.vertical_offset
+ line_num = dialog.vertical_offset - old_dialog.vertical_offset
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column)
+ if visual_lines[start + i].nil?
+ s = ' ' * old_dialog.width
+ else
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
+ s = padding_space_with_escape_sequences(s, old_dialog.width)
+ end
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
+ end
+ if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
+ # rerender bottom
+ move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
+ start = visual_start + dialog.vertical_offset + dialog.contents.size
+ line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size)
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column)
+ if visual_lines[start + i].nil?
+ s = ' ' * old_dialog.width
+ else
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
+ s = padding_space_with_escape_sequences(s, old_dialog.width)
+ end
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
+ end
+ if old_dialog.column < dialog.column
+ # rerender left
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
+ width = dialog.column - old_dialog.column
+ start = visual_start + old_dialog.vertical_offset
+ line_num = old_dialog.contents.size
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column)
+ if visual_lines[start + i].nil?
+ s = ' ' * width
+ else
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
+ s = padding_space_with_escape_sequences(s, dialog.width)
+ end
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
+ end
+ if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width)
+ # rerender right
+ move_cursor_down(old_dialog.vertical_offset + y_diff)
+ width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width)
+ start = visual_start + old_dialog.vertical_offset
+ line_num = old_dialog.contents.size
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width)
+ if visual_lines[start + i].nil?
+ s = ' ' * width
+ else
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
+ rerender_width = old_dialog.width - dialog.width
+ s = padding_space_with_escape_sequences(s, rerender_width)
+ end
+ Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
end
- render_dialog_changes(changes, cursor_column)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
end
- private def clear_dialog_with_trap_key(cursor_column)
- clear_dialog(cursor_column)
+ private def clear_dialog
@dialogs.each do |dialog|
+ clear_each_dialog(dialog)
+ end
+ end
+
+ private def clear_dialog_with_content
+ @dialogs.each do |dialog|
+ clear_each_dialog(dialog)
+ dialog.contents = nil
dialog.trap_key = nil
end
end
+ private def clear_each_dialog(dialog)
+ dialog.trap_key = nil
+ return unless dialog.contents
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
+ visual_lines = []
+ visual_lines_under_dialog = []
+ visual_start = nil
+ dialog.lines_backup[:lines].each_with_index { |l, i|
+ pr = prompt_list ? prompt_list[i] : prompt
+ vl, _ = split_by_width(pr + l, @screen_size.last)
+ vl.compact!
+ if i == dialog.lines_backup[:line_index]
+ visual_start = visual_lines.size + dialog.lines_backup[:started_from] + dialog.vertical_offset
+ end
+ visual_lines.concat(vl)
+ }
+ visual_lines_under_dialog = visual_lines[visual_start, dialog.contents.size]
+ visual_lines_under_dialog = [] if visual_lines_under_dialog.nil?
+ Reline::IOGate.hide_cursor
+ move_cursor_down(dialog.vertical_offset)
+ dialog_vertical_size = dialog.contents.size
+ dialog_vertical_size.times do |i|
+ if i < visual_lines_under_dialog.size
+ Reline::IOGate.move_cursor_column(dialog.column)
+ str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
+ str = padding_space_with_escape_sequences(str, dialog.width)
+ @output.write "\e[0m#{str}\e[0m"
+ else
+ Reline::IOGate.move_cursor_column(dialog.column)
+ @output.write "\e[0m#{' ' * dialog.width}\e[0m"
+ end
+ move_cursor_down(1) if i < (dialog_vertical_size - 1)
+ end
+ move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ Reline::IOGate.show_cursor
+ end
+
private def calculate_scroll_partial_screen(highest_in_all, cursor_y)
if @screen_height < highest_in_all
old_scroll_partial_screen = @scroll_partial_screen
@@ -905,20 +964,11 @@ class Reline::LineEditor
end
end
- private def rerender_added_newline(prompt, prompt_width, prompt_list)
+ private def rerender_added_newline(prompt, prompt_width)
+ scroll_down(1)
@buffer_of_lines[@previous_line_index] = @line
@line = @buffer_of_lines[@line_index]
- @previous_line_index = nil
- if @in_pasting
- scroll_down(1)
- else
- lines = whole_lines
- prev_line_prompt = @prompt_proc ? prompt_list[@line_index - 1] : prompt
- prev_line_prompt_width = @prompt_proc ? calculate_width(prev_line_prompt, true) : prompt_width
- prev_line = modify_lines(lines)[@line_index - 1]
- move_cursor_up(@started_from)
- render_partial(prev_line_prompt, prev_line_prompt_width, prev_line, @first_line_started_from + @started_from, with_control: false)
- scroll_down(1)
+ unless @in_pasting
render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false)
end
@cursor = @cursor_max = calculate_width(@line)
@@ -927,6 +977,7 @@ class Reline::LineEditor
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
@first_line_started_from += @started_from + 1
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ @previous_line_index = nil
end
def just_move_cursor
@@ -939,18 +990,22 @@ class Reline::LineEditor
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
end
first_line_diff = new_first_line_started_from - @first_line_started_from
- @cursor, @cursor_max, _, @byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
- new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ new_cursor, new_cursor_max, new_started_from, new_byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
+ new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1
calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
@previous_line_index = nil
- @line = @buffer_of_lines[@line_index]
if @rerender_all
+ @line = @buffer_of_lines[@line_index]
rerender_all_lines
@rerender_all = false
true
else
+ @line = @buffer_of_lines[@line_index]
@first_line_started_from = new_first_line_started_from
@started_from = new_started_from
+ @cursor = new_cursor
+ @cursor_max = new_cursor_max
+ @byte_pointer = new_byte_pointer
move_cursor_down(first_line_diff + @started_from)
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
false
@@ -958,7 +1013,11 @@ class Reline::LineEditor
end
private def rerender_changed_current_line
- new_lines = whole_lines
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ new_lines = whole_lines
+ end
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
diff = all_height - @highest_in_all
@@ -1179,8 +1238,8 @@ class Reline::LineEditor
height
end
- private def modify_lines(before, force_recalc: false)
- return before if !force_recalc && (before.nil? || before.empty? || simplified_rendering?)
+ private def modify_lines(before)
+ return before if before.nil? || before.empty? || simplified_rendering?
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
after.lines("\n").map { |l| l.chomp('') }
@@ -1312,8 +1371,8 @@ class Reline::LineEditor
@completion_state = CompletionState::MENU
end
if not just_show_list and target < completed
- @line = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
- line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n").last || String.new(encoding: @encoding)
+ @line = preposing + completed + completion_append_character.to_s + postposing
+ line_to_pointer = preposing + completed + completion_append_character.to_s
@cursor_max = calculate_width(@line)
@cursor = calculate_width(line_to_pointer)
@byte_pointer = line_to_pointer.bytesize
@@ -1511,13 +1570,11 @@ class Reline::LineEditor
return if key.char >= 128 # maybe, first byte of multi byte
method_symbol = @config.editing_mode.get_method(key.combined_char)
if key.with_meta and method_symbol == :ed_unassigned
- if @config.editing_mode_is?(:vi_command, :vi_insert)
- # split ESC + key in vi mode
- method_symbol = @config.editing_mode.get_method("\e".ord)
- process_key("\e".ord, method_symbol)
- method_symbol = @config.editing_mode.get_method(key.char)
- process_key(key.char, method_symbol)
- end
+ # split ESC + key
+ method_symbol = @config.editing_mode.get_method("\e".ord)
+ process_key("\e".ord, method_symbol)
+ method_symbol = @config.editing_mode.get_method(key.char)
+ process_key(key.char, method_symbol)
else
process_key(key.combined_char, method_symbol)
end
@@ -1602,7 +1659,7 @@ class Reline::LineEditor
else
@just_cursor_moving = false
end
- if @is_multiline and @auto_indent_proc and not simplified_rendering? and @line
+ if @is_multiline and @auto_indent_proc and not simplified_rendering?
process_auto_indent
end
end
@@ -1641,14 +1698,14 @@ class Reline::LineEditor
return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
# Fix indent of a line when a newline is inserted to the next
- new_lines = whole_lines
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
md = @line.match(/\A */)
prev_indent = md[0].count(' ')
@line = ' ' * new_indent + @line.lstrip
new_indent = nil
- result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[@line_index - 1].bytesize + 1), false)
+ result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
if result
new_indent = result
end
@@ -1656,20 +1713,23 @@ class Reline::LineEditor
@line = ' ' * new_indent + @line.lstrip
end
end
- new_lines = whole_lines
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ new_lines = whole_lines
+ end
new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
+ new_indent = @cursor_max if new_indent&.> @cursor_max
if new_indent&.>= 0
md = new_lines[@line_index].match(/\A */)
prev_indent = md[0].count(' ')
if @check_new_auto_indent
- line = @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
+ @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
@cursor = new_indent
- @cursor_max = calculate_width(line)
@byte_pointer = new_indent
else
@line = ' ' * new_indent + @line.lstrip
@cursor += new_indent - prev_indent
- @cursor_max = calculate_width(@line)
@byte_pointer += new_indent - prev_indent
end
end
@@ -1743,7 +1803,11 @@ class Reline::LineEditor
target = before
end
if @is_multiline
- lines = whole_lines
+ if @previous_line_index
+ lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ lines = whole_lines
+ end
if @line_index > 0
preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
end
@@ -1843,10 +1907,9 @@ class Reline::LineEditor
@cursor_max = calculate_width(@line)
end
- def whole_lines
- index = @previous_line_index || @line_index
+ def whole_lines(index: @line_index, line: @line)
temp_lines = @buffer_of_lines.dup
- temp_lines[index] = @line
+ temp_lines[index] = line
temp_lines
end
@@ -1854,7 +1917,11 @@ class Reline::LineEditor
if @buffer_of_lines.size == 1 and @line.nil?
nil
else
- whole_lines.join("\n")
+ if @previous_line_index
+ whole_lines(index: @previous_line_index, line: @line).join("\n")
+ else
+ whole_lines.join("\n")
+ end
end
end
@@ -1886,10 +1953,8 @@ class Reline::LineEditor
end
private def key_delete(key)
- if @config.editing_mode_is?(:vi_insert)
+ if @config.editing_mode_is?(:vi_insert, :emacs)
ed_delete_next_char(key)
- elsif @config.editing_mode_is?(:emacs)
- em_delete(key)
end
end
@@ -2595,7 +2660,7 @@ class Reline::LineEditor
alias_method :kill_whole_line, :em_kill_line
private def em_delete(key)
- if @line.empty? and (not @is_multiline or @buffer_of_lines.size == 1) and key == "\C-d".ord
+ if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
@line = nil
if @buffer_of_lines.size > 1
scroll_down(@highest_in_all - @first_line_started_from)
@@ -2693,7 +2758,6 @@ class Reline::LineEditor
@cursor_max -= width
end
end
- alias_method :kill_word, :em_delete_next_word
private def ed_delete_prev_word(key)
if @byte_pointer > 0
@@ -2705,7 +2769,6 @@ class Reline::LineEditor
@cursor_max -= width
end
end
- alias_method :backward_kill_word, :ed_delete_prev_word
private def ed_transpose_chars(key)
if @byte_pointer > 0
@@ -3291,7 +3354,4 @@ class Reline::LineEditor
@mark_pointer = new_pointer
end
alias_method :exchange_point_and_mark, :em_exchange_mark
-
- private def em_meta_next(key)
- end
end
diff --git a/lib/reline/terminfo.rb b/lib/reline/terminfo.rb
index 2cfa32b9f7..f53642b919 100644
--- a/lib/reline/terminfo.rb
+++ b/lib/reline/terminfo.rb
@@ -31,7 +31,21 @@ module Reline::Terminfo
@curses_dl = false
def self.curses_dl
return @curses_dl unless @curses_dl == false
- if Fiddle.const_defined?(:TYPE_VARIADIC)
+ if RUBY_VERSION >= '3.0.0'
+ # Gem module isn't defined in test-all of the Ruby repository, and
+ # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
+ fiddle_supports_variadic = true
+ elsif Fiddle.const_defined?(:VERSION,false) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
+ # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
+ fiddle_supports_variadic = true
+ else
+ fiddle_supports_variadic = false
+ end
+ if fiddle_supports_variadic and not Fiddle.const_defined?(:TYPE_VARIADIC)
+ # If the libffi version is not 3.0.5 or higher, there isn't TYPE_VARIADIC.
+ fiddle_supports_variadic = false
+ end
+ if fiddle_supports_variadic
curses_dl_files.each do |curses_name|
result = Fiddle::Handle.new(curses_name)
rescue Fiddle::DLError
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
index 26ef207ba6..6000c9f82a 100644
--- a/lib/reline/unicode.rb
+++ b/lib/reline/unicode.rb
@@ -38,8 +38,33 @@ class Reline::Unicode
NON_PRINTING_START = "\1"
NON_PRINTING_END = "\2"
CSI_REGEXP = /\e\[[\d;]*[ABCDEFGHJKSTfminsuhl]/
- OSC_REGEXP = /\e\]\d+(?:;[^;\a\e]+)*(?:\a|\e\\)/
+ OSC_REGEXP = /\e\]\d+(?:;[^;]+)*\a/
WIDTH_SCANNER = /\G(?:(#{NON_PRINTING_START})|(#{NON_PRINTING_END})|(#{CSI_REGEXP})|(#{OSC_REGEXP})|(\X))/o
+ NON_PRINTING_START_INDEX = 0
+ NON_PRINTING_END_INDEX = 1
+ CSI_REGEXP_INDEX = 2
+ OSC_REGEXP_INDEX = 3
+ GRAPHEME_CLUSTER_INDEX = 4
+
+ def self.get_mbchar_byte_size_by_first_char(c)
+ # Checks UTF-8 character byte size
+ case c.ord
+ # 0b0xxxxxxx
+ when ->(code) { (code ^ 0b10000000).allbits?(0b10000000) } then 1
+ # 0b110xxxxx
+ when ->(code) { (code ^ 0b00100000).allbits?(0b11100000) } then 2
+ # 0b1110xxxx
+ when ->(code) { (code ^ 0b00010000).allbits?(0b11110000) } then 3
+ # 0b11110xxx
+ when ->(code) { (code ^ 0b00001000).allbits?(0b11111000) } then 4
+ # 0b111110xx
+ when ->(code) { (code ^ 0b00000100).allbits?(0b11111100) } then 5
+ # 0b1111110x
+ when ->(code) { (code ^ 0b00000010).allbits?(0b11111110) } then 6
+ # successor of mbchar
+ else 0
+ end
+ end
def self.escape_for_print(str)
str.chars.map! { |gr|
@@ -107,14 +132,15 @@ class Reline::Unicode
width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
+ rest.scan(WIDTH_SCANNER) do |gc|
case
- when non_printing_start
+ when gc[NON_PRINTING_START_INDEX]
in_zero_width = true
- when non_printing_end
+ when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
- when csi, osc
- when gc
+ when gc[CSI_REGEXP_INDEX], gc[OSC_REGEXP_INDEX]
+ when gc[GRAPHEME_CLUSTER_INDEX]
+ gc = gc[GRAPHEME_CLUSTER_INDEX]
unless in_zero_width
width += get_mbchar_width(gc)
end
@@ -134,28 +160,24 @@ class Reline::Unicode
width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
- seq = String.new(encoding: encoding)
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
+ rest.scan(WIDTH_SCANNER) do |gc|
case
- when non_printing_start
+ when gc[NON_PRINTING_START_INDEX]
in_zero_width = true
- lines.last << NON_PRINTING_START
- when non_printing_end
+ when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
- lines.last << NON_PRINTING_END
- when csi
- lines.last << csi
- seq << csi
- when osc
- lines.last << osc
- seq << osc
- when gc
+ when gc[CSI_REGEXP_INDEX]
+ lines.last << gc[CSI_REGEXP_INDEX]
+ when gc[OSC_REGEXP_INDEX]
+ lines.last << gc[OSC_REGEXP_INDEX]
+ when gc[GRAPHEME_CLUSTER_INDEX]
+ gc = gc[GRAPHEME_CLUSTER_INDEX]
unless in_zero_width
mbchar_width = get_mbchar_width(gc)
if (width += mbchar_width) > max_width
width = mbchar_width
lines << nil
- lines << seq.dup
+ lines << String.new(encoding: encoding)
height += 1
end
end
@@ -172,22 +194,23 @@ class Reline::Unicode
end
# Take a chunk of a String cut by width with escape sequences.
- def self.take_range(str, start_col, max_width)
- chunk = String.new(encoding: str.encoding)
+ def self.take_range(str, start_col, max_width, encoding = str.encoding)
+ chunk = String.new(encoding: encoding)
total_width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
+ rest.scan(WIDTH_SCANNER) do |gc|
case
- when non_printing_start
+ when gc[NON_PRINTING_START_INDEX]
in_zero_width = true
- when non_printing_end
+ when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
- when csi
- chunk << csi
- when osc
- chunk << osc
- when gc
+ when gc[CSI_REGEXP_INDEX]
+ chunk << gc[CSI_REGEXP_INDEX]
+ when gc[OSC_REGEXP_INDEX]
+ chunk << gc[OSC_REGEXP_INDEX]
+ when gc[GRAPHEME_CLUSTER_INDEX]
+ gc = gc[GRAPHEME_CLUSTER_INDEX]
if in_zero_width
chunk << gc
else
diff --git a/lib/reline/unicode/east_asian_width.rb b/lib/reline/unicode/east_asian_width.rb
index fa16a1bb56..89bc9d9435 100644
--- a/lib/reline/unicode/east_asian_width.rb
+++ b/lib/reline/unicode/east_asian_width.rb
@@ -1,6 +1,6 @@
class Reline::Unicode::EastAsianWidth
# This is based on EastAsianWidth.txt
- # UNICODE_VERSION = '15.1.0'
+ # EastAsianWidth.txt
# Fullwidth
TYPE_F = /^[#{ %W(
@@ -60,14 +60,14 @@ class Reline::Unicode::EastAsianWidth
\u{2E80}-\u{2E99}
\u{2E9B}-\u{2EF3}
\u{2F00}-\u{2FD5}
- \u{2FF0}-\u{2FFF}
+ \u{2FF0}-\u{2FFB}
\u{3001}-\u{303E}
\u{3041}-\u{3096}
\u{3099}-\u{30FF}
\u{3105}-\u{312F}
\u{3131}-\u{318E}
\u{3190}-\u{31E3}
- \u{31EF}-\u{321E}
+ \u{31F0}-\u{321E}
\u{3220}-\u{3247}
\u{3250}-\u{4DBF}
\u{4E00}-\u{A48C}
@@ -84,13 +84,8 @@ class Reline::Unicode::EastAsianWidth
\u{17000}-\u{187F7}
\u{18800}-\u{18CD5}
\u{18D00}-\u{18D08}
- \u{1AFF0}-\u{1AFF3}
- \u{1AFF5}-\u{1AFFB}
- \u{1AFFD}-\u{1AFFE}
- \u{1B000}-\u{1B122}
- \u{1B132}
+ \u{1B000}-\u{1B11E}
\u{1B150}-\u{1B152}
- \u{1B155}
\u{1B164}-\u{1B167}
\u{1B170}-\u{1B2FB}
\u{1F004}
@@ -124,21 +119,21 @@ class Reline::Unicode::EastAsianWidth
\u{1F6CC}
\u{1F6D0}-\u{1F6D2}
\u{1F6D5}-\u{1F6D7}
- \u{1F6DC}-\u{1F6DF}
\u{1F6EB}-\u{1F6EC}
\u{1F6F4}-\u{1F6FC}
\u{1F7E0}-\u{1F7EB}
- \u{1F7F0}
\u{1F90C}-\u{1F93A}
\u{1F93C}-\u{1F945}
- \u{1F947}-\u{1F9FF}
- \u{1FA70}-\u{1FA7C}
- \u{1FA80}-\u{1FA88}
- \u{1FA90}-\u{1FABD}
- \u{1FABF}-\u{1FAC5}
- \u{1FACE}-\u{1FADB}
- \u{1FAE0}-\u{1FAE8}
- \u{1FAF0}-\u{1FAF8}
+ \u{1F947}-\u{1F978}
+ \u{1F97A}-\u{1F9CB}
+ \u{1F9CD}-\u{1F9FF}
+ \u{1FA70}-\u{1FA74}
+ \u{1FA78}-\u{1FA7A}
+ \u{1FA80}-\u{1FA86}
+ \u{1FA90}-\u{1FAA8}
+ \u{1FAB0}-\u{1FAB6}
+ \u{1FAC0}-\u{1FAC2}
+ \u{1FAD0}-\u{1FAD6}
\u{20000}-\u{2FFFD}
\u{30000}-\u{3FFFD}
).join }]/
@@ -408,7 +403,8 @@ class Reline::Unicode::EastAsianWidth
\u{0591}-\u{05C7}
\u{05D0}-\u{05EA}
\u{05EF}-\u{05F4}
- \u{0600}-\u{070D}
+ \u{0600}-\u{061C}
+ \u{061E}-\u{070D}
\u{070F}-\u{074A}
\u{074D}-\u{07B1}
\u{07C0}-\u{07FA}
@@ -417,9 +413,9 @@ class Reline::Unicode::EastAsianWidth
\u{0840}-\u{085B}
\u{085E}
\u{0860}-\u{086A}
- \u{0870}-\u{088E}
- \u{0890}-\u{0891}
- \u{0898}-\u{0983}
+ \u{08A0}-\u{08B4}
+ \u{08B6}-\u{08C7}
+ \u{08D3}-\u{0983}
\u{0985}-\u{098C}
\u{098F}-\u{0990}
\u{0993}-\u{09A8}
@@ -497,12 +493,11 @@ class Reline::Unicode::EastAsianWidth
\u{0C0E}-\u{0C10}
\u{0C12}-\u{0C28}
\u{0C2A}-\u{0C39}
- \u{0C3C}-\u{0C44}
+ \u{0C3D}-\u{0C44}
\u{0C46}-\u{0C48}
\u{0C4A}-\u{0C4D}
\u{0C55}-\u{0C56}
\u{0C58}-\u{0C5A}
- \u{0C5D}
\u{0C60}-\u{0C63}
\u{0C66}-\u{0C6F}
\u{0C77}-\u{0C8C}
@@ -514,10 +509,10 @@ class Reline::Unicode::EastAsianWidth
\u{0CC6}-\u{0CC8}
\u{0CCA}-\u{0CCD}
\u{0CD5}-\u{0CD6}
- \u{0CDD}-\u{0CDE}
+ \u{0CDE}
\u{0CE0}-\u{0CE3}
\u{0CE6}-\u{0CEF}
- \u{0CF1}-\u{0CF3}
+ \u{0CF1}-\u{0CF2}
\u{0D00}-\u{0D0C}
\u{0D0E}-\u{0D10}
\u{0D12}-\u{0D44}
@@ -547,7 +542,7 @@ class Reline::Unicode::EastAsianWidth
\u{0EA7}-\u{0EBD}
\u{0EC0}-\u{0EC4}
\u{0EC6}
- \u{0EC8}-\u{0ECE}
+ \u{0EC8}-\u{0ECD}
\u{0ED0}-\u{0ED9}
\u{0EDC}-\u{0EDF}
\u{0F00}-\u{0F47}
@@ -582,8 +577,9 @@ class Reline::Unicode::EastAsianWidth
\u{13F8}-\u{13FD}
\u{1400}-\u{169C}
\u{16A0}-\u{16F8}
- \u{1700}-\u{1715}
- \u{171F}-\u{1736}
+ \u{1700}-\u{170C}
+ \u{170E}-\u{1714}
+ \u{1720}-\u{1736}
\u{1740}-\u{1753}
\u{1760}-\u{176C}
\u{176E}-\u{1770}
@@ -591,7 +587,8 @@ class Reline::Unicode::EastAsianWidth
\u{1780}-\u{17DD}
\u{17E0}-\u{17E9}
\u{17F0}-\u{17F9}
- \u{1800}-\u{1819}
+ \u{1800}-\u{180E}
+ \u{1810}-\u{1819}
\u{1820}-\u{1878}
\u{1880}-\u{18AA}
\u{18B0}-\u{18F5}
@@ -610,9 +607,9 @@ class Reline::Unicode::EastAsianWidth
\u{1A7F}-\u{1A89}
\u{1A90}-\u{1A99}
\u{1AA0}-\u{1AAD}
- \u{1AB0}-\u{1ACE}
- \u{1B00}-\u{1B4C}
- \u{1B50}-\u{1B7E}
+ \u{1AB0}-\u{1AC0}
+ \u{1B00}-\u{1B4B}
+ \u{1B50}-\u{1B7C}
\u{1B80}-\u{1BF3}
\u{1BFC}-\u{1C37}
\u{1C3B}-\u{1C49}
@@ -620,7 +617,8 @@ class Reline::Unicode::EastAsianWidth
\u{1C90}-\u{1CBA}
\u{1CBD}-\u{1CC7}
\u{1CD0}-\u{1CFA}
- \u{1D00}-\u{1F15}
+ \u{1D00}-\u{1DF9}
+ \u{1DFB}-\u{1F15}
\u{1F18}-\u{1F1D}
\u{1F20}-\u{1F45}
\u{1F48}-\u{1F4D}
@@ -655,7 +653,7 @@ class Reline::Unicode::EastAsianWidth
\u{2090}-\u{209C}
\u{20A0}-\u{20A8}
\u{20AA}-\u{20AB}
- \u{20AD}-\u{20C0}
+ \u{20AD}-\u{20BF}
\u{20D0}-\u{20F0}
\u{2100}-\u{2102}
\u{2104}
@@ -769,7 +767,9 @@ class Reline::Unicode::EastAsianWidth
\u{2B51}-\u{2B54}
\u{2B5A}-\u{2B73}
\u{2B76}-\u{2B95}
- \u{2B97}-\u{2CF3}
+ \u{2B97}-\u{2C2E}
+ \u{2C30}-\u{2C5E}
+ \u{2C60}-\u{2CF3}
\u{2CF9}-\u{2D25}
\u{2D27}
\u{2D2D}
@@ -784,16 +784,14 @@ class Reline::Unicode::EastAsianWidth
\u{2DC8}-\u{2DCE}
\u{2DD0}-\u{2DD6}
\u{2DD8}-\u{2DDE}
- \u{2DE0}-\u{2E5D}
+ \u{2DE0}-\u{2E52}
\u{303F}
\u{4DC0}-\u{4DFF}
\u{A4D0}-\u{A62B}
\u{A640}-\u{A6F7}
- \u{A700}-\u{A7CA}
- \u{A7D0}-\u{A7D1}
- \u{A7D3}
- \u{A7D5}-\u{A7D9}
- \u{A7F2}-\u{A82C}
+ \u{A700}-\u{A7BF}
+ \u{A7C2}-\u{A7CA}
+ \u{A7F5}-\u{A82C}
\u{A830}-\u{A839}
\u{A840}-\u{A877}
\u{A880}-\u{A8C5}
@@ -825,11 +823,11 @@ class Reline::Unicode::EastAsianWidth
\u{FB3E}
\u{FB40}-\u{FB41}
\u{FB43}-\u{FB44}
- \u{FB46}-\u{FBC2}
- \u{FBD3}-\u{FD8F}
+ \u{FB46}-\u{FBC1}
+ \u{FBD3}-\u{FD3F}
+ \u{FD50}-\u{FD8F}
\u{FD92}-\u{FDC7}
- \u{FDCF}
- \u{FDF0}-\u{FDFF}
+ \u{FDF0}-\u{FDFD}
\u{FE20}-\u{FE2F}
\u{FE70}-\u{FE74}
\u{FE76}-\u{FEFC}
@@ -863,20 +861,10 @@ class Reline::Unicode::EastAsianWidth
\u{104D8}-\u{104FB}
\u{10500}-\u{10527}
\u{10530}-\u{10563}
- \u{1056F}-\u{1057A}
- \u{1057C}-\u{1058A}
- \u{1058C}-\u{10592}
- \u{10594}-\u{10595}
- \u{10597}-\u{105A1}
- \u{105A3}-\u{105B1}
- \u{105B3}-\u{105B9}
- \u{105BB}-\u{105BC}
+ \u{1056F}
\u{10600}-\u{10736}
\u{10740}-\u{10755}
\u{10760}-\u{10767}
- \u{10780}-\u{10785}
- \u{10787}-\u{107B0}
- \u{107B2}-\u{107BA}
\u{10800}-\u{10805}
\u{10808}
\u{1080A}-\u{10835}
@@ -918,14 +906,13 @@ class Reline::Unicode::EastAsianWidth
\u{10E80}-\u{10EA9}
\u{10EAB}-\u{10EAD}
\u{10EB0}-\u{10EB1}
- \u{10EFD}-\u{10F27}
+ \u{10F00}-\u{10F27}
\u{10F30}-\u{10F59}
- \u{10F70}-\u{10F89}
\u{10FB0}-\u{10FCB}
\u{10FE0}-\u{10FF6}
\u{11000}-\u{1104D}
- \u{11052}-\u{11075}
- \u{1107F}-\u{110C2}
+ \u{11052}-\u{1106F}
+ \u{1107F}-\u{110C1}
\u{110CD}
\u{110D0}-\u{110E8}
\u{110F0}-\u{110F9}
@@ -935,7 +922,7 @@ class Reline::Unicode::EastAsianWidth
\u{11180}-\u{111DF}
\u{111E1}-\u{111F4}
\u{11200}-\u{11211}
- \u{11213}-\u{11241}
+ \u{11213}-\u{1123E}
\u{11280}-\u{11286}
\u{11288}
\u{1128A}-\u{1128D}
@@ -967,11 +954,11 @@ class Reline::Unicode::EastAsianWidth
\u{11600}-\u{11644}
\u{11650}-\u{11659}
\u{11660}-\u{1166C}
- \u{11680}-\u{116B9}
+ \u{11680}-\u{116B8}
\u{116C0}-\u{116C9}
\u{11700}-\u{1171A}
\u{1171D}-\u{1172B}
- \u{11730}-\u{11746}
+ \u{11730}-\u{1173F}
\u{11800}-\u{1183B}
\u{118A0}-\u{118F2}
\u{118FF}-\u{11906}
@@ -987,8 +974,7 @@ class Reline::Unicode::EastAsianWidth
\u{119DA}-\u{119E4}
\u{11A00}-\u{11A47}
\u{11A50}-\u{11AA2}
- \u{11AB0}-\u{11AF8}
- \u{11B00}-\u{11B09}
+ \u{11AC0}-\u{11AF8}
\u{11C00}-\u{11C08}
\u{11C0A}-\u{11C36}
\u{11C38}-\u{11C45}
@@ -1010,23 +996,19 @@ class Reline::Unicode::EastAsianWidth
\u{11D93}-\u{11D98}
\u{11DA0}-\u{11DA9}
\u{11EE0}-\u{11EF8}
- \u{11F00}-\u{11F10}
- \u{11F12}-\u{11F3A}
- \u{11F3E}-\u{11F59}
\u{11FB0}
\u{11FC0}-\u{11FF1}
\u{11FFF}-\u{12399}
\u{12400}-\u{1246E}
\u{12470}-\u{12474}
\u{12480}-\u{12543}
- \u{12F90}-\u{12FF2}
- \u{13000}-\u{13455}
+ \u{13000}-\u{1342E}
+ \u{13430}-\u{13438}
\u{14400}-\u{14646}
\u{16800}-\u{16A38}
\u{16A40}-\u{16A5E}
\u{16A60}-\u{16A69}
- \u{16A6E}-\u{16ABE}
- \u{16AC0}-\u{16AC9}
+ \u{16A6E}-\u{16A6F}
\u{16AD0}-\u{16AED}
\u{16AF0}-\u{16AF5}
\u{16B00}-\u{16B45}
@@ -1043,14 +1025,10 @@ class Reline::Unicode::EastAsianWidth
\u{1BC80}-\u{1BC88}
\u{1BC90}-\u{1BC99}
\u{1BC9C}-\u{1BCA3}
- \u{1CF00}-\u{1CF2D}
- \u{1CF30}-\u{1CF46}
- \u{1CF50}-\u{1CFC3}
\u{1D000}-\u{1D0F5}
\u{1D100}-\u{1D126}
- \u{1D129}-\u{1D1EA}
+ \u{1D129}-\u{1D1E8}
\u{1D200}-\u{1D245}
- \u{1D2C0}-\u{1D2D3}
\u{1D2E0}-\u{1D2F3}
\u{1D300}-\u{1D356}
\u{1D360}-\u{1D378}
@@ -1077,27 +1055,17 @@ class Reline::Unicode::EastAsianWidth
\u{1D7CE}-\u{1DA8B}
\u{1DA9B}-\u{1DA9F}
\u{1DAA1}-\u{1DAAF}
- \u{1DF00}-\u{1DF1E}
- \u{1DF25}-\u{1DF2A}
\u{1E000}-\u{1E006}
\u{1E008}-\u{1E018}
\u{1E01B}-\u{1E021}
\u{1E023}-\u{1E024}
\u{1E026}-\u{1E02A}
- \u{1E030}-\u{1E06D}
- \u{1E08F}
\u{1E100}-\u{1E12C}
\u{1E130}-\u{1E13D}
\u{1E140}-\u{1E149}
\u{1E14E}-\u{1E14F}
- \u{1E290}-\u{1E2AE}
\u{1E2C0}-\u{1E2F9}
\u{1E2FF}
- \u{1E4D0}-\u{1E4F9}
- \u{1E7E0}-\u{1E7E6}
- \u{1E7E8}-\u{1E7EB}
- \u{1E7ED}-\u{1E7EE}
- \u{1E7F0}-\u{1E7FE}
\u{1E800}-\u{1E8C4}
\u{1E8C7}-\u{1E8D6}
\u{1E900}-\u{1E94B}
@@ -1174,8 +1142,8 @@ class Reline::Unicode::EastAsianWidth
\u{1F6D3}-\u{1F6D4}
\u{1F6E0}-\u{1F6EA}
\u{1F6F0}-\u{1F6F3}
- \u{1F700}-\u{1F776}
- \u{1F77B}-\u{1F7D9}
+ \u{1F700}-\u{1F773}
+ \u{1F780}-\u{1F7D8}
\u{1F800}-\u{1F80B}
\u{1F810}-\u{1F847}
\u{1F850}-\u{1F859}
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
index fb1c73cbd9..67a3d694bd 100644
--- a/lib/reline/version.rb
+++ b/lib/reline/version.rb
@@ -1,3 +1,3 @@
module Reline
- VERSION = '0.4.0'
+ VERSION = '0.3.2'
end
diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb
index 6f635f630f..b952329911 100644
--- a/lib/reline/windows.rb
+++ b/lib/reline/windows.rb
@@ -291,11 +291,7 @@ class Reline::Windows
end
end
- def self.with_raw_input
- yield
- end
-
- def self.getc(_timeout_second)
+ def self.getc
check_input_event
@@output_buf.shift
end
diff --git a/lib/resolv.gemspec b/lib/resolv.gemspec
index 6b83e303d7..f221010ab6 100644
--- a/lib/resolv.gemspec
+++ b/lib/resolv.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "resolv"
+ spec.version = "0.2.3"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/resolv.rb b/lib/resolv.rb
index 47c4ef6b3b..eaea69bfd5 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -37,8 +37,6 @@ end
class Resolv
- VERSION = "0.2.2"
-
##
# Looks up the first IP address for +name+.
@@ -198,7 +196,7 @@ class Resolv
next unless addr
@addr2name[addr] = [] unless @addr2name.include? addr
@addr2name[addr] << hostname
- @addr2name[addr].concat(aliases)
+ @addr2name[addr] += aliases
@name2addr[hostname] = [] unless @name2addr.include? hostname
@name2addr[hostname] << addr
aliases.each {|n|
@@ -967,7 +965,7 @@ class Resolv
next unless keyword
case keyword
when 'nameserver'
- nameserver.concat(args)
+ nameserver += args
when 'domain'
next if args.empty?
search = [args[0]]
@@ -1489,14 +1487,14 @@ class Resolv
}
end
- def put_name(d, compress: true)
- put_labels(d.to_a, compress: compress)
+ def put_name(d)
+ put_labels(d.to_a)
end
- def put_labels(d, compress: true)
+ def put_labels(d)
d.each_index {|i|
domain = d[i..-1]
- if compress && idx = @names[domain]
+ if idx = @names[domain]
self.put_pack("n", 0xc000 | idx)
return
else
@@ -1626,6 +1624,7 @@ class Resolv
prev_index = @index
save_index = nil
d = []
+ size = -1
while true
raise DecodeError.new("limit exceeded") if @limit <= @index
case @data.getbyte(@index)
@@ -1646,7 +1645,10 @@ class Resolv
end
@index = idx
else
- d << self.get_label
+ l = self.get_label
+ d << l
+ size += 1 + l.string.bytesize
+ raise DecodeError.new("name label data exceed 255 octets") if size > 255
end
end
end
@@ -2330,7 +2332,7 @@ class Resolv
msg.put_pack("n", @priority)
msg.put_pack("n", @weight)
msg.put_pack("n", @port)
- msg.put_name(@target, compress: false)
+ msg.put_name(@target)
end
def self.decode_rdata(msg) # :nodoc:
diff --git a/lib/rinda/rinda.gemspec b/lib/rinda/rinda.gemspec
index e9f53dd864..0c13e3c2df 100644
--- a/lib/rinda/rinda.gemspec
+++ b/lib/rinda/rinda.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib/rinda", "."].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "rinda"
+ spec.version = "0.1.1"
spec.authors = ["Masatoshi SEKI"]
spec.email = ["seki@ruby-lang.org"]
diff --git a/lib/rinda/rinda.rb b/lib/rinda/rinda.rb
index e1649e3248..e762286d3b 100644
--- a/lib/rinda/rinda.rb
+++ b/lib/rinda/rinda.rb
@@ -18,8 +18,6 @@ require 'drb/drb'
module Rinda
- VERSION = "0.2.0"
-
##
# Rinda error base class
diff --git a/lib/ruby_vm/mjit/c_pointer.rb b/lib/ruby_vm/mjit/c_pointer.rb
new file mode 100644
index 0000000000..a92c2140ae
--- /dev/null
+++ b/lib/ruby_vm/mjit/c_pointer.rb
@@ -0,0 +1,329 @@
+module RubyVM::MJIT # :nodoc: all
+ # Every class under this namespace is a pointer. Even if the type is
+ # immediate, it shouldn't be dereferenced until `*` is called.
+ module CPointer
+ # Note: We'd like to avoid alphabetic method names to avoid a conflict
+ # with member methods. to_i and to_s are considered an exception.
+ class Struct
+ # @param name [String]
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => [RubyVM::MJIT::CType::*, Integer, TrueClass] }]
+ def initialize(addr, sizeof, members)
+ @addr = addr
+ @sizeof = sizeof
+ @members = members
+ end
+
+ # Get a raw address
+ def to_i
+ @addr
+ end
+
+ # Serialized address for generated code
+ def to_s
+ "0x#{@addr.to_s(16)}"
+ end
+
+ # Pointer diff
+ def -(struct)
+ raise ArgumentError if self.class != struct.class
+ (@addr - struct.to_i) / @sizeof
+ end
+
+ # Primitive API that does no automatic dereference
+ # TODO: remove this?
+ # @param member [Symbol]
+ def [](member)
+ type, offset = @members.fetch(member)
+ type.new(@addr + offset / 8)
+ end
+
+ private
+
+ # @param member [Symbol]
+ # @param value [Object]
+ def []=(member, value)
+ type, offset = @members.fetch(member)
+ type[@addr + offset / 8] = value
+ end
+
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => [Integer, RubyVM::MJIT::CType::*] }]
+ def self.define(sizeof, members)
+ Class.new(self) do
+ # Return the size of this type
+ define_singleton_method(:sizeof) { sizeof }
+
+ define_method(:initialize) do |addr = nil|
+ if addr.nil? # TODO: get rid of this feature later
+ addr = Fiddle.malloc(sizeof)
+ end
+ super(addr, sizeof, members)
+ end
+
+ members.each do |member, (type, offset, to_ruby)|
+ # Intelligent API that does automatic dereference
+ define_method(member) do
+ value = self[member]
+ if value.respond_to?(:*)
+ value = value.*
+ end
+ if to_ruby
+ value = C.to_ruby(value)
+ end
+ value
+ end
+
+ define_method("#{member}=") do |value|
+ self[member] = value
+ end
+ end
+ end
+ end
+ end
+
+ # Note: We'd like to avoid alphabetic method names to avoid a conflict
+ # with member methods. to_i is considered an exception.
+ class Union
+ # @param _name [String] To be used when it starts defining a union pointer class
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => RubyVM::MJIT::CType::* }]
+ def initialize(addr, sizeof, members)
+ @addr = addr
+ @sizeof = sizeof
+ @members = members
+ end
+
+ # Get a raw address
+ def to_i
+ @addr
+ end
+
+ # Move addr to access this pointer like an array
+ def +(index)
+ raise ArgumentError unless index.is_a?(Integer)
+ self.class.new(@addr + index * @sizeof)
+ end
+
+ # Pointer diff
+ def -(union)
+ raise ArgumentError if self.class != union.class
+ (@addr - union.instance_variable_get(:@addr)) / @sizeof
+ end
+
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => RubyVM::MJIT::CType::* }]
+ def self.define(sizeof, members)
+ Class.new(self) do
+ # Return the size of this type
+ define_singleton_method(:sizeof) { sizeof }
+
+ define_method(:initialize) do |addr|
+ super(addr, sizeof, members)
+ end
+
+ members.each do |member, type|
+ # Intelligent API that does automatic dereference
+ define_method(member) do
+ value = type.new(@addr)
+ if value.respond_to?(:*)
+ value = value.*
+ end
+ value
+ end
+ end
+ end
+ end
+ end
+
+ class Immediate
+ # @param addr [Integer]
+ # @param size [Integer]
+ # @param pack [String]
+ def initialize(addr, size, pack)
+ @addr = addr
+ @size = size
+ @pack = pack
+ end
+
+ # Get a raw address
+ def to_i
+ @addr
+ end
+
+ # Move addr to addess this pointer like an array
+ def +(index)
+ Immediate.new(@addr + index * @size, @size, @pack)
+ end
+
+ # Dereference
+ def *
+ self[0]
+ end
+
+ # Array access
+ def [](index)
+ return nil if @addr == 0
+ Fiddle::Pointer.new(@addr + index * @size)[0, @size].unpack1(@pack)
+ end
+
+ # Array set
+ def []=(index, value)
+ Fiddle::Pointer.new(@addr + index * @size)[0, @size] = [value].pack(@pack)
+ end
+
+ # Serialized address for generated code. Used for embedding things like body->iseq_encoded.
+ def to_s
+ "0x#{Integer(@addr).to_s(16)}"
+ end
+
+ # @param fiddle_type [Integer] Fiddle::TYPE_*
+ def self.define(fiddle_type)
+ size = Fiddle::PackInfo::SIZE_MAP.fetch(fiddle_type)
+ pack = Fiddle::PackInfo::PACK_MAP.fetch(fiddle_type)
+
+ Class.new(self) do
+ define_method(:initialize) do |addr|
+ super(addr, size, pack)
+ end
+
+ define_singleton_method(:size) do
+ size
+ end
+
+ # Type-level []=: Used by struct fields
+ define_singleton_method(:[]=) do |addr, value|
+ Fiddle::Pointer.new(addr)[0, size] = [value].pack(pack)
+ end
+ end
+ end
+ end
+
+ # -Fiddle::TYPE_CHAR Immediate with special handling of true/false
+ class Bool < Immediate.define(-Fiddle::TYPE_CHAR)
+ # Dereference
+ def *
+ return nil if @addr == 0
+ super != 0
+ end
+
+ def self.[]=(addr, value)
+ super(addr, value ? 1 : 0)
+ end
+ end
+
+ class Pointer
+ attr_reader :type
+
+ # @param addr [Integer]
+ # @param type [Class] RubyVM::MJIT::CType::*
+ def initialize(addr, type)
+ @addr = addr
+ @type = type
+ end
+
+ # Move addr to addess this pointer like an array
+ def +(index)
+ raise ArgumentError unless index.is_a?(Integer)
+ Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP, @type)
+ end
+
+ # Dereference
+ def *
+ return nil if dest_addr == 0
+ @type.new(dest_addr)
+ end
+
+ # Array access
+ def [](index)
+ (self + index).*
+ end
+
+ # Array set
+ # @param index [Integer]
+ # @param value [Integer, RubyVM::MJIT::CPointer::Struct] an address itself or an object that return an address with to_i
+ def []=(index, value)
+ Fiddle::Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP)[0, Fiddle::SIZEOF_VOIDP] =
+ [value.to_i].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
+ end
+
+ private
+
+ def dest_addr
+ Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_VOIDP].unpack1(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
+ end
+
+ def self.define(block)
+ Class.new(self) do
+ define_method(:initialize) do |addr|
+ super(addr, block.call)
+ end
+
+ # Type-level []=: Used by struct fields
+ # @param addr [Integer]
+ # @param value [Integer, RubyVM::MJIT::CPointer::Struct] an address itself, or an object that return an address with to_i
+ define_singleton_method(:[]=) do |addr, value|
+ value = value.to_i
+ Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP] = [value].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
+ end
+ end
+ end
+ end
+
+ class BitField
+ # @param addr [Integer]
+ # @param width [Integer]
+ # @param offset [Integer]
+ def initialize(addr, width, offset)
+ @addr = addr
+ @width = width
+ @offset = offset
+ end
+
+ # Dereference
+ def *
+ byte = Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_CHAR].unpack1('c')
+ if @width == 1
+ bit = (1 & (byte >> @offset))
+ bit == 1
+ elsif @width <= 8 && @offset == 0
+ bitmask = @width.times.sum { |i| 1 << i }
+ byte & bitmask
+ else
+ raise NotImplementedError.new("not-implemented bit field access: width=#{@width} offset=#{@offset}")
+ end
+ end
+
+ # @param width [Integer]
+ # @param offset [Integer]
+ def self.define(width, offset)
+ Class.new(self) do
+ define_method(:initialize) do |addr|
+ super(addr, width, offset)
+ end
+ end
+ end
+ end
+
+ # Give a name to a dynamic CPointer class to see it on inspect
+ def self.with_class_name(prefix, name, cache: false, &block)
+ return block.call if name.empty?
+
+ # Use a cached result only if cache: true
+ class_name = "#{prefix}_#{name}"
+ klass =
+ if cache && self.const_defined?(class_name)
+ self.const_get(class_name)
+ else
+ block.call
+ end
+
+ # Give it a name unless it's already defined
+ unless self.const_defined?(class_name)
+ self.const_set(class_name, klass)
+ end
+
+ klass
+ end
+ end
+end
diff --git a/lib/ruby_vm/mjit/c_type.rb b/lib/ruby_vm/mjit/c_type.rb
new file mode 100644
index 0000000000..9c965ad2fb
--- /dev/null
+++ b/lib/ruby_vm/mjit/c_type.rb
@@ -0,0 +1,91 @@
+require 'fiddle'
+require 'fiddle/pack'
+require_relative 'c_pointer'
+
+module RubyVM::MJIT # :nodoc: all
+ module CType
+ module Struct
+ # @param name [String]
+ # @param members [Hash{ Symbol => [Integer, RubyVM::MJIT::CType::*] }]
+ def self.new(name, sizeof, **members)
+ name = members.keys.join('_') if name.empty?
+ CPointer.with_class_name('Struct', name) do
+ CPointer::Struct.define(sizeof, members)
+ end
+ end
+ end
+
+ module Union
+ # @param name [String]
+ # @param members [Hash{ Symbol => RubyVM::MJIT::CType::* }]
+ def self.new(name, sizeof, **members)
+ name = members.keys.join('_') if name.empty?
+ CPointer.with_class_name('Union', name) do
+ CPointer::Union.define(sizeof, members)
+ end
+ end
+ end
+
+ module Immediate
+ # @param fiddle_type [Integer]
+ def self.new(fiddle_type)
+ name = Fiddle.constants.find do |const|
+ const.start_with?('TYPE_') && Fiddle.const_get(const) == fiddle_type.abs
+ end&.to_s
+ name.delete_prefix!('TYPE_')
+ if fiddle_type.negative?
+ name.prepend('U')
+ end
+ CPointer.with_class_name('Immediate', name, cache: true) do
+ CPointer::Immediate.define(fiddle_type)
+ end
+ end
+
+ # @param type [String]
+ def self.parse(ctype)
+ new(Fiddle::Importer.parse_ctype(ctype))
+ end
+
+ def self.find(size, signed)
+ fiddle_type = TYPE_MAP.fetch(size)
+ fiddle_type = -fiddle_type unless signed
+ new(fiddle_type)
+ end
+
+ TYPE_MAP = Fiddle::PackInfo::SIZE_MAP.map { |type, size| [size, type.abs] }.to_h
+ private_constant :TYPE_MAP
+ end
+
+ module Bool
+ def self.new
+ CPointer::Bool
+ end
+ end
+
+ class Pointer
+ # This takes a block to avoid "stack level too deep" on a cyclic reference
+ # @param block [Proc]
+ def self.new(&block)
+ CPointer.with_class_name('Pointer', block.object_id.to_s) do
+ CPointer::Pointer.define(block)
+ end
+ end
+ end
+
+ module BitField
+ # @param width [Integer]
+ # @param offset [Integer]
+ def self.new(width, offset)
+ CPointer.with_class_name('BitField', "#{offset}_#{width}") do
+ CPointer::BitField.define(width, offset)
+ end
+ end
+ end
+
+ # Types that are referenced but not part of code generation targets
+ Stub = ::Struct.new(:name)
+
+ # Types that it failed to figure out from the header
+ Unknown = Module.new
+ end
+end
diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb
new file mode 100644
index 0000000000..81022cd0a8
--- /dev/null
+++ b/lib/ruby_vm/mjit/compiler.rb
@@ -0,0 +1,952 @@
+# Available variables and macros in JIT-ed function:
+# ec: the first argument of _mjitXXX
+# reg_cfp: the second argument of _mjitXXX
+# GET_CFP(): refers to `reg_cfp`
+# GET_EP(): refers to `reg_cfp->ep`
+# GET_SP(): refers to `reg_cfp->sp`, or `(stack + stack_size)` if local_stack_p
+# GET_SELF(): refers to `cfp_self`
+# GET_LEP(): refers to `VM_EP_LEP(reg_cfp->ep)`
+# EXEC_EC_CFP(): refers to `val = vm_exec(ec, true)` with frame setup
+# CALL_METHOD(): using `GET_CFP()` and `EXEC_EC_CFP()`
+# TOPN(): refers to `reg_cfp->sp`, or `*(stack + (stack_size - num - 1))` if local_stack_p
+# STACK_ADDR_FROM_TOP(): refers to `reg_cfp->sp`, or `stack + (stack_size - num)` if local_stack_p
+# DISPATCH_ORIGINAL_INSN(): expanded in _mjit_compile_insn.erb
+# THROW_EXCEPTION(): specially defined for JIT
+# RESTORE_REGS(): specially defined for `leave`
+class RubyVM::MJIT::Compiler # :nodoc: all
+ C = RubyVM::MJIT.const_get(:C, false)
+ INSNS = RubyVM::MJIT.const_get(:INSNS, false)
+ UNSUPPORTED_INSNS = [
+ :defineclass, # low priority
+ ]
+
+ def initialize = freeze
+
+ # @param iseq [RubyVM::MJIT::CPointer::Struct]
+ # @param funcname [String]
+ # @param id [Integer]
+ # @return [String,NilClass]
+ def compile(iseq, funcname, id)
+ status = C.compile_status.new # not freed for now
+ status.compiled_iseq = iseq.body
+ status.compiled_id = id
+ init_compile_status(status, iseq.body, true) # not freed for now
+ if iseq.body.ci_size > 0 && status.cc_entries_index == -1
+ return nil
+ end
+
+ src = +''
+ if !status.compile_info.disable_send_cache && !status.compile_info.disable_inlining
+ unless precompile_inlinable_iseqs(src, iseq, status)
+ return nil
+ end
+ end
+
+ src << "VALUE\n#{funcname}(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)\n{\n"
+ success = compile_body(src, iseq, status)
+ src << "\n} // end of #{funcname}\n"
+
+ return success ? src : nil
+ rescue Exception => e # should we use rb_rescue in C instead?
+ if C.mjit_opts.warnings || C.mjit_opts.verbose > 0
+ $stderr.puts "MJIT error: #{e.full_message}"
+ end
+ return nil
+ end
+
+ private
+
+ def compile_body(src, iseq, status)
+ status.success = true
+ status.local_stack_p = !iseq.body.catch_except_p
+
+ if status.local_stack_p
+ src << " VALUE stack[#{iseq.body.stack_max}];\n"
+ else
+ src << " VALUE *stack = reg_cfp->sp;\n"
+ end
+
+ unless status.inlined_iseqs.nil? # i.e. compile root
+ src << " static const rb_iseq_t *original_iseq = (const rb_iseq_t *)#{iseq};\n"
+ end
+ src << " static const VALUE *const original_body_iseq = (VALUE *)#{iseq.body.iseq_encoded};\n"
+
+ src << " VALUE cfp_self = reg_cfp->self;\n" # cache self across the method
+ src << "#undef GET_SELF\n"
+ src << "#define GET_SELF() cfp_self\n"
+
+ # Generate merged ivar guards first if needed
+ if !status.compile_info.disable_ivar_cache && using_ivar?(iseq.body)
+ src << " if (UNLIKELY(!RB_TYPE_P(GET_SELF(), T_OBJECT))) {"
+ src << " goto ivar_cancel;\n"
+ src << " }\n"
+ end
+
+ # Simulate `opt_pc` in setup_parameters_complex. Other PCs which may be passed by catch tables
+ # are not considered since vm_exec doesn't call jit_exec for catch tables.
+ if iseq.body.param.flags.has_opt
+ src << "\n"
+ src << " switch (reg_cfp->pc - ISEQ_BODY(reg_cfp->iseq)->iseq_encoded) {\n"
+ (0..iseq.body.param.opt_num).each do |i|
+ pc_offset = iseq.body.param.opt_table[i]
+ src << " case #{pc_offset}:\n"
+ src << " goto label_#{pc_offset};\n"
+ end
+ src << " }\n"
+ end
+
+ compile_insns(0, 0, status, iseq.body, src)
+ compile_cancel_handler(src, iseq.body, status)
+ src << "#undef GET_SELF\n"
+ return status.success
+ end
+
+ # Compile one conditional branch. If it has branchXXX insn, this should be
+ # called multiple times for each branch.
+ def compile_insns(stack_size, pos, status, body, src)
+ branch = C.compile_branch.new # not freed for now
+ branch.stack_size = stack_size
+ branch.finish_p = false
+
+ while pos < body.iseq_size && !already_compiled?(status, pos) && !branch.finish_p
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ status.stack_size_for_pos[pos] = branch.stack_size
+
+ src << "\nlabel_#{pos}: /* #{insn.name} */\n"
+ pos = compile_insn(insn, pos, status, body.iseq_encoded + (pos+1), body, branch, src)
+ if status.success && branch.stack_size > body.stack_max
+ if mjit_opts.warnings || mjit_opts.verbose > 0
+ $stderr.puts "MJIT warning: JIT stack size (#{branch.stack_size}) exceeded its max size (#{body.stack_max})"
+ end
+ status.success = false
+ end
+ break unless status.success
+ end
+ end
+
+ # Main function of JIT compilation, vm_exec_core counterpart for JIT. Compile one insn to `f`, may modify
+ # b->stack_size and return next position.
+ #
+ # When you add a new instruction to insns.def, it would be nice to have JIT compilation support here but
+ # it's optional. This JIT compiler just ignores ISeq which includes unknown instruction, and ISeq which
+ # does not have it can be compiled as usual.
+ def compile_insn(insn, pos, status, operands, body, b, src)
+ sp_inc = C.mjit_call_attribute_sp_inc(insn.bin, operands)
+ next_pos = pos + insn.len
+
+ result = compile_insn_entry(insn, b.stack_size, sp_inc, status.local_stack_p, pos, next_pos, insn.len,
+ status.inlined_iseqs.nil?, status, operands, body)
+ if result.nil?
+ if C.mjit_opts.warnings || C.mjit_opts.verbose > 0
+ $stderr.puts "MJIT warning: Skipped to compile unsupported instruction: #{insn.name}"
+ end
+ status.success = false
+ else
+ result_src, next_pos, finish_p, compile_insns_p = result
+
+ src << result_src
+ b.stack_size += sp_inc
+
+ if finish_p
+ b.finish_p = true
+ end
+ if compile_insns_p
+ if already_compiled?(status, pos + insn.len)
+ src << "goto label_#{pos + insn.len};\n"
+ else
+ compile_insns(b.stack_size, pos + insn.len, status, body, src)
+ end
+ end
+ end
+
+ # If next_pos is already compiled and this branch is not finished yet,
+ # next instruction won't be compiled in C code next and will need `goto`.
+ if !b.finish_p && next_pos < body.iseq_size && already_compiled?(status, next_pos)
+ src << "goto label_#{next_pos};\n"
+
+ # Verify stack size assumption is the same among multiple branches
+ if status.stack_size_for_pos[next_pos] != b.stack_size
+ if mjit_opts.warnings || mjit_opts.verbose > 0
+ $stderr.puts "MJIT warning: JIT stack assumption is not the same between branches (#{status.stack_size_for_pos[next_pos]} != #{b.stack_size})\n"
+ end
+ status.success = false
+ end
+ end
+
+ return next_pos
+ end
+
+ def compile_insn_entry(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, insn_len, inlined_iseq_p, status, operands, body)
+ finish_p = false
+ compile_insns = false
+
+ # TODO: define this outside this method, or at least cache it
+ opt_send_without_block = INSNS.values.find { |i| i.name == :opt_send_without_block }
+ if opt_send_without_block.nil?
+ raise 'opt_send_without_block not found'
+ end
+ send_compatible_opt_insns = INSNS.values.select do |insn|
+ insn.name.start_with?('opt_') && opt_send_without_block.opes == insn.opes &&
+ insn.expr.lines.any? { |l| l.match(/\A\s+CALL_SIMPLE_METHOD\(\);\s+\z/) }
+ end.map(&:name)
+
+ case insn.name
+ when *UNSUPPORTED_INSNS
+ return nil
+ when :opt_send_without_block, :send
+ if src = compile_send(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, status, operands, body)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when *send_compatible_opt_insns
+ if C.has_cache_for_send(captured_cc_entries(status)[call_data_index(C.CALL_DATA.new(operands[0]), body)], insn.bin) &&
+ src = compile_send(opt_send_without_block, stack_size, sp_inc, local_stack_p, pos, next_pos, status, operands, body)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :getinstancevariable, :setinstancevariable
+ if src = compile_ivar(insn.name, stack_size, pos, status, operands, body)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :opt_getconstant_path
+ if src = compile_getconstant_path(stack_size, pos, insn_len, operands, status)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :invokebuiltin, :opt_invokebuiltin_delegate, :opt_invokebuiltin_delegate_leave
+ if src = compile_invokebuiltin(insn, stack_size, sp_inc, body, operands)
+ if insn.name == :opt_invokebuiltin_delegate_leave
+ src << compile_leave(stack_size, pos, inlined_iseq_p)
+ finish_p = true
+ end
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :leave
+ if stack_size != 1
+ raise "Unexpected JIT stack_size on leave: #{stack_size}"
+ end
+ src = compile_leave(stack_size, pos, inlined_iseq_p)
+ finish_p = true
+ return src, next_pos, finish_p, compile_insns
+ end
+
+ return compile_insn_default(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, insn_len, inlined_iseq_p, operands)
+ end
+
+ # Optimized case of send / opt_send_without_block instructions.
+ def compile_send(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, status, operands, body)
+ # compiler: Use captured cc to avoid race condition
+ cd = C.CALL_DATA.new(operands[0])
+ cd_index = call_data_index(cd, body)
+ captured_cc = captured_cc_entries(status)[cd_index]
+
+ # compiler: Inline send insn where some supported fastpath is used.
+ ci = cd.ci
+ kw_splat = (C.vm_ci_flag(ci) & C.VM_CALL_KW_SPLAT) > 0
+ if !status.compile_info.disable_send_cache && has_valid_method_type?(captured_cc) && (
+ # `CC_SET_FASTPATH(cd->cc, vm_call_cfunc_with_frame, ...)` in `vm_call_cfunc`
+ (vm_cc_cme(captured_cc).def.type == C.VM_METHOD_TYPE_CFUNC && !C.rb_splat_or_kwargs_p(ci) && !kw_splat) ||
+ # `CC_SET_FASTPATH(cc, vm_call_iseq_setup_func(...), vm_call_iseq_optimizable_p(...))` in `vm_callee_setup_arg`,
+ # and support only non-VM_CALL_TAILCALL path inside it
+ (vm_cc_cme(captured_cc).def.type == C.VM_METHOD_TYPE_ISEQ &&
+ C.fastpath_applied_iseq_p(ci, captured_cc, iseq = def_iseq_ptr(vm_cc_cme(captured_cc).def)) &&
+ (C.vm_ci_flag(ci) & C.VM_CALL_TAILCALL) == 0)
+ )
+ src = +"{\n"
+
+ # JIT: Invalidate call cache if it requires vm_search_method. This allows to inline some of following things.
+ src << " const struct rb_callcache *cc = (struct rb_callcache *)#{captured_cc};\n"
+ src << " const rb_callable_method_entry_t *cc_cme = (rb_callable_method_entry_t *)#{vm_cc_cme(captured_cc)};\n"
+ src << " const VALUE recv = stack[#{stack_size + sp_inc - 1}];\n"
+ # If opt_class_of is true, use RBASIC_CLASS instead of CLASS_OF to reduce code size
+ opt_class_of = !maybe_special_const?(captured_cc.klass)
+ src << " if (UNLIKELY(#{opt_class_of ? 'RB_SPECIAL_CONST_P(recv)' : 'false'} || !vm_cc_valid_p(cc, cc_cme, #{opt_class_of ? 'RBASIC_CLASS' : 'CLASS_OF'}(recv)))) {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto send_cancel;\n"
+ src << " }\n"
+
+ # JIT: move sp and pc if necessary
+ pc_moved_p = compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: If ISeq is inlinable, call the inlined method without pushing a frame.
+ if iseq && status.inlined_iseqs && iseq.body.to_i == status.inlined_iseqs[pos]&.to_i
+ src << " {\n"
+ src << " VALUE orig_self = reg_cfp->self;\n"
+ src << " reg_cfp->self = stack[#{stack_size + sp_inc - 1}];\n"
+ src << " stack[#{stack_size + sp_inc - 1}] = _mjit#{status.compiled_id}_inlined_#{pos}(ec, reg_cfp, orig_self, original_iseq);\n"
+ src << " reg_cfp->self = orig_self;\n"
+ src << " }\n"
+ else
+ # JIT: Forked `vm_sendish` (except method_explorer = vm_search_method_wrap) to inline various things
+ src << " {\n"
+ src << " VALUE val;\n"
+ src << " struct rb_calling_info calling;\n"
+ if insn.name == :send
+ src << " calling.block_handler = vm_caller_setup_arg_block(ec, reg_cfp, (const struct rb_callinfo *)#{ci}, (rb_iseq_t *)0x#{operands[1].to_s(16)}, FALSE);\n"
+ else
+ src << " calling.block_handler = VM_BLOCK_HANDLER_NONE;\n"
+ end
+ src << " calling.kw_splat = #{kw_splat ? 1 : 0};\n"
+ src << " calling.recv = stack[#{stack_size + sp_inc - 1}];\n"
+ src << " calling.argc = #{C.vm_ci_argc(ci)};\n"
+
+ if vm_cc_cme(captured_cc).def.type == C.VM_METHOD_TYPE_CFUNC
+ # TODO: optimize this more
+ src << " calling.ci = (const struct rb_callinfo *)#{ci};\n" # creating local cd here because operand's cd->cc may not be the same as inlined cc.
+ src << " calling.cc = cc;"
+ src << " val = vm_call_cfunc_with_frame(ec, reg_cfp, &calling);\n"
+ else # :iseq
+ # fastpath_applied_iseq_p checks rb_simple_iseq_p, which ensures has_opt == FALSE
+ src << " vm_call_iseq_setup_normal(ec, reg_cfp, &calling, cc_cme, 0, #{iseq.body.param.size}, #{iseq.body.local_table_size});\n"
+ if iseq.body.catch_except_p
+ src << " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n"
+ src << " val = vm_exec(ec, true);\n"
+ else
+ src << " if ((val = jit_exec(ec)) == Qundef) {\n"
+ src << " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n" # This is vm_call0_body's code after vm_call_iseq_setup
+ src << " val = vm_exec(ec, false);\n"
+ src << " }\n"
+ end
+ end
+ src << " stack[#{stack_size + sp_inc - 1}] = val;\n"
+ src << " }\n"
+
+ # JIT: We should evaluate ISeq modified for TracePoint if it's enabled. Note: This is slow.
+ src << " if (UNLIKELY(!mjit_call_p)) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size + sp_inc};\n"
+ if !pc_moved_p
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n"
+ end
+ src << " goto cancel;\n"
+ src << " }\n"
+ end
+
+ src << "}\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_ivar(insn_name, stack_size, pos, status, operands, body)
+ iv_cache = C.iseq_inline_storage_entry.new(operands[1]).iv_cache
+ dest_shape_id = iv_cache.value >> C.SHAPE_FLAG_SHIFT
+ source_shape_id = parent_shape_id(dest_shape_id)
+ attr_index = iv_cache.value & ((1 << C.SHAPE_FLAG_SHIFT) - 1)
+
+ src = +''
+ if !status.compile_info.disable_ivar_cache && source_shape_id != C.INVALID_SHAPE_ID
+ # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`.
+ # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: prepare vm_getivar/vm_setivar arguments and variables
+ src << "{\n"
+ src << " VALUE obj = GET_SELF();\n" # T_OBJECT guaranteed by compile_body
+ # JIT: cache hit path of vm_getivar/vm_setivar, or cancel JIT (recompile it with exivar)
+ if insn_name == :setinstancevariable
+ src << " const uint32_t index = #{attr_index - 1};\n"
+ src << " const shape_id_t dest_shape_id = (shape_id_t)#{dest_shape_id};\n"
+ src << " if (dest_shape_id == ROBJECT_SHAPE_ID(obj)) {\n"
+ src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n"
+ src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n"
+ src << " }\n"
+ else
+ src << " const shape_id_t source_shape_id = (shape_id_t)#{dest_shape_id};\n"
+ if attr_index == 0 # cache hit, but uninitialized iv
+ src << " /* Uninitialized instance variable */\n"
+ src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n"
+ src << " stack[#{stack_size}] = Qnil;\n"
+ src << " }\n"
+ else
+ src << " const uint32_t index = #{attr_index - 1};\n"
+ src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n"
+ src << " stack[#{stack_size}] = ROBJECT_IVPTR(obj)[index];\n"
+ src << " }\n"
+ end
+ end
+ src << " else {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto ivar_cancel;\n"
+ src << " }\n"
+ src << "}\n"
+ return src
+ elsif insn_name == :getinstancevariable && !status.compile_info.disable_exivar_cache && source_shape_id != C.INVALID_SHAPE_ID
+ # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`.
+ # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: prepare vm_getivar's arguments and variables
+ src << "{\n"
+ src << " VALUE obj = GET_SELF();\n"
+ src << " const shape_id_t source_shape_id = (shape_id_t)#{dest_shape_id};\n"
+ src << " const uint32_t index = #{attr_index - 1};\n"
+ # JIT: cache hit path of vm_getivar, or cancel JIT (recompile it without any ivar optimization)
+ src << " struct gen_ivtbl *ivtbl;\n"
+ src << " if (LIKELY(FL_TEST_RAW(GET_SELF(), FL_EXIVAR) && source_shape_id == rb_shape_get_shape_id(obj) && rb_ivar_generic_ivtbl_lookup(obj, &ivtbl))) {\n"
+ src << " stack[#{stack_size}] = ivtbl->ivptr[index];\n"
+ src << " }\n"
+ src << " else {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto exivar_cancel;\n"
+ src << " }\n"
+ src << "}\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_invokebuiltin(insn, stack_size, sp_inc, body, operands)
+ bf = C.RB_BUILTIN.new(operands[0])
+ if bf.compiler > 0
+ index = (insn.name == :invokebuiltin ? -1 : operands[1])
+ src = +"{\n"
+ src << " VALUE val;\n"
+ C.builtin_compiler(src, bf, index, stack_size, body.builtin_inline_p)
+ src << " stack[#{stack_size + sp_inc - 1}] = val;\n"
+ src << "}\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_leave(stack_size, pos, inlined_iseq_p)
+ src = +''
+ # Skip vm_pop_frame for inlined call
+ unless inlined_iseq_p
+ # Cancel on interrupts to make leave insn leaf
+ src << " if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " rb_threadptr_execute_interrupts(rb_ec_thread_ptr(ec), 0);\n"
+ src << " }\n"
+ src << " ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(reg_cfp);\n" # vm_pop_frame
+ end
+ src << " return stack[0];\n"
+ end
+
+ def compile_getconstant_path(stack_size, pos, insn_len, operands, status)
+ ice = C.IC.new(operands[0]).entry
+ if !status.compile_info.disable_const_cache && ice
+ # JIT: Inline everything in IC, and cancel the slow path
+ src = +" if (vm_inlined_ic_hit_p(#{ice.flags}, #{ice.value}, (const rb_cref_t *)#{to_addr(ice.ic_cref)}, reg_cfp->ep)) {\n"
+ src << " stack[#{stack_size}] = #{ice.value};\n"
+ src << " }\n"
+ src << " else {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " goto const_cancel;\n"
+ src << " }\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_insn_default(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, insn_len, inlined_iseq_p, operands)
+ src = +''
+ finish_p = false
+ compile_insns = false
+
+ # JIT: Declare stack_size to be used in some macro of _mjit_compile_insn_body.erb
+ src << "{\n"
+ if local_stack_p
+ src << " MAYBE_UNUSED(unsigned int) stack_size = #{stack_size};\n"
+ end
+
+ # JIT: Declare variables for operands, popped values and return values
+ insn.declarations.each do |decl|
+ src << " #{decl};\n"
+ end
+
+ # JIT: Set const expressions for `RubyVM::OperandsUnifications` insn
+ insn.preamble.each do |amble|
+ src << "#{amble.sub(/const \S+\s+/, '')}\n"
+ end
+
+ # JIT: Initialize operands
+ insn.opes.each_with_index do |ope, i|
+ src << " #{ope.fetch(:name)} = (#{ope.fetch(:type)})#{operands[i]};\n"
+ # TODO: resurrect comment_id
+ end
+
+ # JIT: Initialize popped values
+ insn.pops.reverse_each.with_index.reverse_each do |pop, i|
+ src << " #{pop.fetch(:name)} = stack[#{stack_size - (i + 1)}];\n"
+ end
+
+ # JIT: move sp and pc if necessary
+ pc_moved_p = compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: Print insn body in insns.def
+ next_pos = compile_insn_body(src, insn, pos, next_pos, insn_len, local_stack_p, stack_size, sp_inc, operands)
+
+ # JIT: Set return values
+ insn.rets.reverse_each.with_index do |ret, i|
+ # TOPN(n) = ...
+ src << " stack[#{stack_size + sp_inc - (i + 1)}] = #{ret.fetch(:name)};\n"
+ end
+
+ # JIT: We should evaluate ISeq modified for TracePoint if it's enabled. Note: This is slow.
+ # leaf insn may not cancel JIT. leaf_without_check_ints is covered in RUBY_VM_CHECK_INTS of _mjit_compile_insn_body.erb.
+ unless insn.always_leaf? || insn.leaf_without_check_ints?
+ src << " if (UNLIKELY(!mjit_call_p)) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size + sp_inc};\n"
+ if !pc_moved_p
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n"
+ end
+ src << " goto cancel;\n"
+ src << " }\n"
+ end
+
+ src << "}\n"
+
+ # compiler: If insn has conditional JUMP, the code should go to the branch not targeted by JUMP next.
+ if insn.expr.match?(/if\s+\([^{}]+\)\s+\{[^{}]+JUMP\([^)]+\);[^{}]+\}/)
+ compile_insns = true
+ end
+
+ # compiler: If insn returns (leave) or does longjmp (throw), the branch should no longer be compiled. TODO: create attr for it?
+ if insn.expr.match?(/\sTHROW_EXCEPTION\([^)]+\);/) || insn.expr.match?(/\bvm_pop_frame\(/)
+ finish_p = true
+ end
+
+ return src, next_pos, finish_p, compile_insns
+ end
+
+ def compile_insn_body(src, insn, pos, next_pos, insn_len, local_stack_p, stack_size, sp_inc, operands)
+ # Print a body of insn, but with macro expansion.
+ expand_simple_macros(insn.expr).each_line do |line|
+ # Expand dynamic macro here
+ # TODO: support combination of following macros in the same line
+ case line
+ when /\A\s+RUBY_VM_CHECK_INTS\(ec\);\s+\z/
+ if insn.leaf_without_check_ints? # lazily move PC and optionalize mjit_call_p here
+ src << " if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n" # ADD_PC(INSN_ATTR(width));
+ src << " rb_threadptr_execute_interrupts(rb_ec_thread_ptr(ec), 0);\n"
+ src << " if (UNLIKELY(!mjit_call_p)) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto cancel;\n"
+ src << " }\n"
+ src << " }\n"
+ else
+ src << to_cstr(line)
+ end
+ when /\A\s+JUMP\((?<dest>[^)]+)\);\s+\z/
+ dest = Regexp.last_match[:dest]
+ if insn.name == :opt_case_dispatch # special case... TODO: use another macro to avoid checking name
+ hash_offsets = C.rb_hash_values(operands[0]).uniq
+ else_offset = cast_offset(operands[1])
+ base_pos = pos + insn_len
+
+ src << " switch (#{dest}) {\n"
+ hash_offsets.each do |offset|
+ src << " case #{offset}:\n"
+ src << " goto label_#{base_pos + offset};\n"
+ end
+ src << " case #{else_offset}:\n"
+ src << " goto label_#{base_pos + else_offset};\n"
+ src << " }\n"
+ else
+ # Before we `goto` next insn, we need to set return values, especially for getinlinecache
+ insn.rets.reverse_each.with_index do |ret, i|
+ # TOPN(n) = ...
+ src << " stack[#{stack_size + sp_inc - (i + 1)}] = #{ret.fetch(:name)};\n"
+ end
+
+ next_pos = pos + insn_len + cast_offset(operands[0]) # workaround: assuming dest == operands[0]. TODO: avoid relying on it
+ src << " goto label_#{next_pos};\n"
+ end
+ when /\A\s+CALL_SIMPLE_METHOD\(\);\s+\z/
+ # For `opt_xxx`'s fallbacks.
+ if local_stack_p
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ end
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " goto cancel;\n"
+ when /\A(?<prefix>.+\b)INSN_LABEL\((?<name>[^)]+)\)(?<suffix>.+)\z/m
+ prefix, name, suffix = Regexp.last_match[:prefix], Regexp.last_match[:name], Regexp.last_match[:suffix]
+ src << "#{prefix}INSN_LABEL(#{name}_#{pos})#{suffix}"
+ else
+ if insn.handles_sp?
+ # If insn.handles_sp? is true, cfp->sp might be changed inside insns (like vm_caller_setup_arg_block)
+ # and thus we need to use cfp->sp, even when local_stack_p is TRUE. When insn.handles_sp? is true,
+ # cfp->sp should be available too because _mjit_compile_pc_and_sp.erb sets it.
+ src << to_cstr(line)
+ else
+ # If local_stack_p is TRUE and insn.handles_sp? is false, stack values are only available in local variables
+ # for stack. So we need to replace those macros if local_stack_p is TRUE here.
+ case line
+ when /\bGET_SP\(\)/
+ # reg_cfp->sp
+ src << to_cstr(line.sub(/\bGET_SP\(\)/, local_stack_p ? '(stack + stack_size)' : 'GET_SP()'))
+ when /\bSTACK_ADDR_FROM_TOP\((?<num>[^)]+)\)/
+ # #define STACK_ADDR_FROM_TOP(n) (GET_SP()-(n))
+ num = Regexp.last_match[:num]
+ src << to_cstr(line.sub(/\bSTACK_ADDR_FROM_TOP\(([^)]+)\)/, local_stack_p ? "(stack + (stack_size - (#{num})))" : "STACK_ADDR_FROM_TOP(#{num})"))
+ when /\bTOPN\((?<num>[^)]+)\)/
+ # #define TOPN(n) (*(GET_SP()-(n)-1))
+ num = Regexp.last_match[:num]
+ src << to_cstr(line.sub(/\bTOPN\(([^)]+)\)/, local_stack_p ? "*(stack + (stack_size - (#{num}) - 1))" : "TOPN(#{num})"))
+ else
+ src << to_cstr(line)
+ end
+ end
+ end
+ end
+ return next_pos
+ end
+
+ def compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+ # JIT: When an insn is leaf, we don't need to Move pc for a catch table on catch_except_p, #caller_locations,
+ # and rb_profile_frames. For check_ints, we lazily move PC when we have interruptions.
+ pc_moved_p = false
+ unless insn.always_leaf? || insn.leaf_without_check_ints?
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n" # ADD_PC(INSN_ATTR(width));
+ pc_moved_p = true
+ end
+
+ # JIT: move sp to use or preserve stack variables
+ if local_stack_p
+ # sp motion is optimized away for `handles_sp? #=> false` case.
+ # Thus sp should be set properly before `goto cancel`.
+ if insn.handles_sp?
+ # JIT-only behavior (pushing JIT's local variables to VM's stack):
+ push_size = -sp_inc + insn.rets.size - insn.pops.size
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{push_size};\n"
+ push_size.times do |i|
+ src << " *(reg_cfp->sp + #{i - push_size}) = stack[#{stack_size - push_size + i}];\n"
+ end
+ end
+ else
+ if insn.handles_sp?
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size - insn.pops.size};\n" # POPN(INSN_ATTR(popn));
+ else
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ end
+ end
+ return pc_moved_p
+ end
+
+ # Print the block to cancel inlined method call. It's supporting only `opt_send_without_block` for now.
+ def compile_inlined_cancel_handler(src, body, inline_context)
+ src << "\ncancel:\n"
+ src << " rb_mjit_recompile_inlining(original_iseq);\n"
+
+ # Swap pc/sp set on cancel with original pc/sp.
+ src << " const VALUE *current_pc = reg_cfp->pc;\n"
+ src << " VALUE *current_sp = reg_cfp->sp;\n"
+ src << " reg_cfp->pc = orig_pc;\n"
+ src << " reg_cfp->sp = orig_sp;\n\n"
+
+ # Lazily push the current call frame.
+ src << " struct rb_calling_info calling;\n"
+ src << " calling.block_handler = VM_BLOCK_HANDLER_NONE;\n" # assumes `opt_send_without_block`
+ src << " calling.argc = #{inline_context.orig_argc};\n"
+ src << " calling.recv = reg_cfp->self;\n"
+ src << " reg_cfp->self = orig_self;\n"
+ # fastpath_applied_iseq_p checks rb_simple_iseq_p, which ensures has_opt == FALSE
+ src << " vm_call_iseq_setup_normal(ec, reg_cfp, &calling, (const rb_callable_method_entry_t *)#{inline_context.me}, 0, #{inline_context.param_size}, #{inline_context.local_size});\n\n"
+
+ # Start usual cancel from here.
+ src << " reg_cfp = ec->cfp;\n" # work on the new frame
+ src << " reg_cfp->pc = current_pc;\n"
+ src << " reg_cfp->sp = current_sp;\n"
+ (0...body.stack_max).each do |i| # should be always `status->local_stack_p`
+ src << " *(vm_base_ptr(reg_cfp) + #{i}) = stack[#{i}];\n"
+ end
+ # We're not just returning Qundef here so that caller's normal cancel handler can
+ # push back `stack` to `cfp->sp`.
+ src << " return vm_exec(ec, false);\n"
+ end
+
+ # Print the block to cancel JIT execution.
+ def compile_cancel_handler(src, body, status)
+ if status.inlined_iseqs.nil? # the current ISeq is being inlined
+ compile_inlined_cancel_handler(src, body, status.inline_context)
+ return
+ end
+
+ src << "\nsend_cancel:\n"
+ src << " rb_mjit_recompile_send(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\nivar_cancel:\n"
+ src << " rb_mjit_recompile_ivar(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\nexivar_cancel:\n"
+ src << " rb_mjit_recompile_exivar(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\nconst_cancel:\n"
+ src << " rb_mjit_recompile_const(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\ncancel:\n"
+ if status.local_stack_p
+ (0...body.stack_max).each do |i|
+ src << " *(vm_base_ptr(reg_cfp) + #{i}) = stack[#{i}];\n"
+ end
+ end
+ src << " return Qundef;\n"
+ end
+
+ def precompile_inlinable_child_iseq(src, child_iseq, status, ci, cc, pos)
+ child_status = C.compile_status.new # not freed for now
+ child_status.compiled_iseq = status.compiled_iseq
+ child_status.compiled_id = status.compiled_id
+ init_compile_status(child_status, child_iseq.body, false) # not freed for now
+ child_status.inline_context.orig_argc = C.vm_ci_argc(ci)
+ child_status.inline_context.me = vm_cc_cme(cc).to_i
+ child_status.inline_context.param_size = child_iseq.body.param.size
+ child_status.inline_context.local_size = child_iseq.body.local_table_size
+ if child_iseq.body.ci_size > 0 && child_status.cc_entries_index == -1
+ return false
+ end
+
+ src << "ALWAYS_INLINE(static VALUE _mjit#{status.compiled_id}_inlined_#{pos}(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VALUE orig_self, const rb_iseq_t *original_iseq));\n"
+ src << "static inline VALUE\n_mjit#{status.compiled_id}_inlined_#{pos}(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VALUE orig_self, const rb_iseq_t *original_iseq)\n{\n"
+ src << " const VALUE *orig_pc = reg_cfp->pc;\n"
+ src << " VALUE *orig_sp = reg_cfp->sp;\n"
+
+ success = compile_body(src, child_iseq, child_status)
+
+ src << "\n} /* end of _mjit#{status.compiled_id}_inlined_#{pos} */\n\n"
+
+ return success;
+ end
+
+ def precompile_inlinable_iseqs(src, iseq, status)
+ body = iseq.body
+ pos = 0
+ while pos < body.iseq_size
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ if insn.name == :opt_send_without_block || insn.name == :opt_size # `compile_inlined_cancel_handler` supports only `opt_send_without_block`
+ cd = C.CALL_DATA.new(body.iseq_encoded[pos + 1])
+ ci = cd.ci
+ cc = captured_cc_entries(status)[call_data_index(cd, body)] # use copy to avoid race condition
+
+ if (child_iseq = rb_mjit_inlinable_iseq(ci, cc)) != nil
+ status.inlined_iseqs[pos] = child_iseq.body
+
+ if C.mjit_opts.verbose >= 1 # print beforehand because ISeq may be GCed during copy job.
+ child_location = child_iseq.body.location
+ $stderr.puts "JIT inline: #{child_location.label}@#{C.rb_iseq_path(child_iseq)}:#{C.rb_iseq_first_lineno(child_iseq)} " \
+ "=> #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{C.rb_iseq_first_lineno(iseq)}"
+ end
+ if !precompile_inlinable_child_iseq(src, child_iseq, status, ci, cc, pos)
+ return false
+ end
+ end
+ end
+ pos += insn.len
+ end
+ return true
+ end
+
+ def init_compile_status(status, body, compile_root_p)
+ status.stack_size_for_pos = Fiddle.malloc(Fiddle::SIZEOF_INT * body.iseq_size)
+ body.iseq_size.times do |i|
+ status.stack_size_for_pos[i] = C.NOT_COMPILED_STACK_SIZE
+ end
+ if compile_root_p
+ status.inlined_iseqs = Fiddle.malloc(Fiddle::SIZEOF_VOIDP * body.iseq_size)
+ body.iseq_size.times do |i|
+ status.inlined_iseqs[i] = nil
+ end
+ end
+ if body.ci_size > 0
+ status.cc_entries_index = C.mjit_capture_cc_entries(status.compiled_iseq, body)
+ else
+ status.cc_entries_index = -1
+ end
+ if compile_root_p
+ status.compile_info = rb_mjit_iseq_compile_info(body)
+ else
+ status.compile_info = Fiddle.malloc(C.rb_mjit_compile_info.sizeof)
+ status.compile_info.disable_ivar_cache = false
+ status.compile_info.disable_exivar_cache = false
+ status.compile_info.disable_send_cache = false
+ status.compile_info.disable_inlining = false
+ status.compile_info.disable_const_cache = false
+ end
+ end
+
+ def using_ivar?(body)
+ pos = 0
+ while pos < body.iseq_size
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ case insn.name
+ when :getinstancevariable, :setinstancevariable
+ return true
+ end
+ pos += insn.len
+ end
+ return false
+ end
+
+ # Expand simple macro that doesn't require dynamic C code.
+ def expand_simple_macros(arg_expr)
+ arg_expr.dup.tap do |expr|
+ # For `leave`. We can't proceed next ISeq in the same JIT function.
+ expr.gsub!(/^(?<indent>\s*)RESTORE_REGS\(\);\n/) do
+ indent = Regexp.last_match[:indent]
+ <<-end.gsub(/^ {12}/, '')
+ #if OPT_CALL_THREADED_CODE
+ #{indent}rb_ec_thread_ptr(ec)->retval = val;
+ #{indent}return 0;
+ #else
+ #{indent}return val;
+ #endif
+ end
+ end
+ expr.gsub!(/^(?<indent>\s*)NEXT_INSN\(\);\n/) do
+ indent = Regexp.last_match[:indent]
+ <<-end.gsub(/^ {12}/, '')
+ #{indent}UNREACHABLE_RETURN(Qundef);
+ end
+ end
+ end
+ end
+
+ def to_cstr(expr)
+ expr.gsub(/^(?!#)/, ' ') # indent everything but preprocessor lines
+ end
+
+ # Interpret unsigned long as signed long (VALUE -> OFFSET)
+ def cast_offset(offset)
+ if offset >= 1 << 8 * Fiddle::SIZEOF_VOIDP - 1 # negative
+ offset -= 1 << 8 * Fiddle::SIZEOF_VOIDP
+ end
+ offset
+ end
+
+ def captured_cc_entries(status)
+ status.compiled_iseq.mjit_unit.cc_entries + status.cc_entries_index
+ end
+
+ def call_data_index(cd, body)
+ cd - body.call_data
+ end
+
+ def vm_cc_cme(cc)
+ # TODO: add VM_ASSERT like actual vm_cc_cme
+ cc.cme_
+ end
+
+ def def_iseq_ptr(method_def)
+ C.rb_iseq_check(method_def.body.iseq.iseqptr)
+ end
+
+ def rb_mjit_iseq_compile_info(body)
+ body.mjit_unit.compile_info
+ end
+
+ def ISEQ_IS_SIZE(body)
+ body.ic_size + body.ivc_size + body.ise_size + body.icvarc_size
+ end
+
+ # Return true if an object of the class may be a special const (immediate).
+ # It's "maybe" because Integer and Float are not guaranteed to be an immediate.
+ # If this returns false, rb_class_of could be optimzied to RBASIC_CLASS.
+ def maybe_special_const?(klass)
+ [
+ C.rb_cFalseClass,
+ C.rb_cNilClass,
+ C.rb_cTrueClass,
+ C.rb_cInteger,
+ C.rb_cSymbol,
+ C.rb_cFloat,
+ ].include?(klass)
+ end
+
+ def has_valid_method_type?(cc)
+ vm_cc_cme(cc) != nil
+ end
+
+ def already_compiled?(status, pos)
+ status.stack_size_for_pos[pos] != C.NOT_COMPILED_STACK_SIZE
+ end
+
+ # Return an iseq pointer if cc has inlinable iseq.
+ def rb_mjit_inlinable_iseq(ci, cc)
+ if has_valid_method_type?(cc) &&
+ C.vm_ci_flag(ci) & C.VM_CALL_TAILCALL == 0 && # inlining only non-tailcall path
+ vm_cc_cme(cc).def.type == C.VM_METHOD_TYPE_ISEQ &&
+ C.fastpath_applied_iseq_p(ci, cc, iseq = def_iseq_ptr(vm_cc_cme(cc).def)) &&
+ inlinable_iseq_p(iseq.body) # CC_SET_FASTPATH in vm_callee_setup_arg
+ return iseq
+ end
+ return nil
+ end
+
+ # Return true if the ISeq can be inlined without pushing a new control frame.
+ def inlinable_iseq_p(body)
+ # 1) If catch_except_p, caller frame should be preserved when callee catches an exception.
+ # Then we need to wrap `vm_exec()` but then we can't inline the call inside it.
+ #
+ # 2) If `body->catch_except_p` is false and `handles_sp?` of an insn is false,
+ # sp is not moved as we assume `status->local_stack_p = !body->catch_except_p`.
+ #
+ # 3) If `body->catch_except_p` is false and `always_leaf?` of an insn is true,
+ # pc is not moved.
+ if body.catch_except_p
+ return false
+ end
+
+ pos = 0
+ while pos < body.iseq_size
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ # All insns in the ISeq except `leave` (to be overridden in the inlined code)
+ # should meet following strong assumptions:
+ # * Do not require `cfp->sp` motion
+ # * Do not move `cfp->pc`
+ # * Do not read any `cfp->pc`
+ if insn.name == :invokebuiltin || insn.name == :opt_invokebuiltin_delegate || insn.name == :opt_invokebuiltin_delegate_leave
+ # builtin insn's inlinability is handled by `Primitive.attr! 'inline'` per iseq
+ if !body.builtin_inline_p
+ return false;
+ end
+ elsif insn.name != :leave && C.insn_may_depend_on_sp_or_pc(insn.bin, body.iseq_encoded + (pos + 1))
+ return false
+ end
+ # At this moment, `cfp->ep` in an inlined method is not working.
+ case insn.name
+ when :getlocal,
+ :getlocal_WC_0,
+ :getlocal_WC_1,
+ :setlocal,
+ :setlocal_WC_0,
+ :setlocal_WC_1,
+ :getblockparam,
+ :getblockparamproxy,
+ :setblockparam
+ return false
+ end
+ pos += insn.len
+ end
+ return true
+ end
+
+ # CPointer::Struct could be nil on field reference, and this is a helper to
+ # handle that case while using CPointer::Struct#to_s in most cases.
+ # @param struct [RubyVM::MJIT::CPointer::Struct]
+ def to_addr(struct)
+ struct&.to_s || 'NULL'
+ end
+
+ def parent_shape_id(shape_id)
+ return shape_id if shape_id == C.INVALID_SHAPE_ID
+
+ parent_id = C.rb_shape_get_shape_by_id(shape_id).parent_id
+ parent = C.rb_shape_get_shape_by_id(parent_id)
+
+ if parent.type == C.SHAPE_CAPACITY_CHANGE
+ parent.parent_id
+ else
+ parent_id
+ end
+ end
+end
diff --git a/lib/ruby_vm/mjit/hooks.rb b/lib/ruby_vm/mjit/hooks.rb
new file mode 100644
index 0000000000..3fb1004111
--- /dev/null
+++ b/lib/ruby_vm/mjit/hooks.rb
@@ -0,0 +1,32 @@
+module RubyVM::MJIT::Hooks # :nodoc: all
+ C = RubyVM::MJIT.const_get(:C, false)
+
+ def self.on_bop_redefined(_redefined_flag, _bop)
+ C.mjit_cancel_all("BOP is redefined")
+ end
+
+ def self.on_cme_invalidate(_cme)
+ # to be used later
+ end
+
+ def self.on_ractor_spawn
+ C.mjit_cancel_all("Ractor is spawned")
+ end
+
+ def self.on_constant_state_changed(_id)
+ # to be used later
+ end
+
+ def self.on_constant_ic_update(_iseq, _ic, _insn_idx)
+ # to be used later
+ end
+
+ def self.on_tracing_invalidate_all(new_iseq_events)
+ # Stop calling all JIT-ed code. We can't rewrite existing JIT-ed code to trace_ insns for now.
+ # :class events are triggered only in ISEQ_TYPE_CLASS, but mjit_target_iseq_p ignores such iseqs.
+ # Thus we don't need to cancel JIT-ed code for :class events.
+ if new_iseq_events != C.RUBY_EVENT_CLASS
+ C.mjit_cancel_all("TracePoint is enabled")
+ end
+ end
+end
diff --git a/lib/ruby_vm/rjit/assembler.rb b/lib/ruby_vm/rjit/assembler.rb
deleted file mode 100644
index 64f663ec0e..0000000000
--- a/lib/ruby_vm/rjit/assembler.rb
+++ /dev/null
@@ -1,1129 +0,0 @@
-# frozen_string_literal: true
-module RubyVM::RJIT
- # 8-bit memory access
- class BytePtr < Data.define(:reg, :disp); end
-
- # 32-bit memory access
- class DwordPtr < Data.define(:reg, :disp); end
-
- # 64-bit memory access
- QwordPtr = Array
-
- # SystemV x64 calling convention
- C_ARGS = [:rdi, :rsi, :rdx, :rcx, :r8, :r9]
- C_RET = :rax
-
- # https://cdrdv2.intel.com/v1/dl/getContent/671110
- # Mostly an x86_64 assembler, but this also has some stuff that is useful for any architecture.
- class Assembler
- # rel8 jumps are made with labels
- class Label < Data.define(:id, :name); end
-
- # rel32 is inserted as [Rel32, Rel32Pad..] and converted on #resolve_rel32
- class Rel32 < Data.define(:addr); end
- Rel32Pad = Object.new
-
- # A set of ModR/M values encoded on #insn
- class ModRM < Data.define(:mod, :reg, :rm); end
- Mod00 = 0b00 # Mod 00: [reg]
- Mod01 = 0b01 # Mod 01: [reg]+disp8
- Mod10 = 0b10 # Mod 10: [reg]+disp32
- Mod11 = 0b11 # Mod 11: reg
-
- # REX = 0100WR0B
- REX_B = 0b01000001
- REX_R = 0b01000100
- REX_W = 0b01001000
-
- # Operand matchers
- R32 = -> (op) { op.is_a?(Symbol) && r32?(op) }
- R64 = -> (op) { op.is_a?(Symbol) && r64?(op) }
- IMM8 = -> (op) { op.is_a?(Integer) && imm8?(op) }
- IMM32 = -> (op) { op.is_a?(Integer) && imm32?(op) }
- IMM64 = -> (op) { op.is_a?(Integer) && imm64?(op) }
-
- def initialize
- @bytes = []
- @labels = {}
- @label_id = 0
- @comments = Hash.new { |h, k| h[k] = [] }
- @blocks = Hash.new { |h, k| h[k] = [] }
- @stub_starts = Hash.new { |h, k| h[k] = [] }
- @stub_ends = Hash.new { |h, k| h[k] = [] }
- @pos_markers = Hash.new { |h, k| h[k] = [] }
- end
-
- def assemble(addr)
- set_code_addrs(addr)
- resolve_rel32(addr)
- resolve_labels
-
- write_bytes(addr)
-
- @pos_markers.each do |write_pos, markers|
- markers.each { |marker| marker.call(addr + write_pos) }
- end
- @bytes.size
- ensure
- @bytes.clear
- end
-
- def size
- @bytes.size
- end
-
- #
- # Instructions
- #
-
- def add(dst, src)
- case [dst, src]
- # ADD r/m64, imm8 (Mod 00: [reg])
- in [QwordPtr[R64 => dst_reg], IMM8 => src_imm]
- # REX.W + 83 /0 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod00, reg: 0, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # ADD r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /0 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # ADD r/m64 imm32 (Mod 11: reg)
- in [R64 => dst_reg, IMM32 => src_imm]
- # REX.W + 81 /0 id
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # ADD r/m64, r64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 01 /r
- # MR: Operand 1: ModRM:r/m (r, w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x01,
- mod_rm: ModRM[mod: Mod11, reg: src_reg, rm: dst_reg],
- )
- end
- end
-
- def and(dst, src)
- case [dst, src]
- # AND r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /4 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # AND r/m64, imm32 (Mod 11: reg)
- in [R64 => dst_reg, IMM32 => src_imm]
- # REX.W + 81 /4 id
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # AND r64, r/m64 (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 23 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x23,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- end
- end
-
- def call(dst)
- case dst
- # CALL rel32
- in Integer => dst_addr
- # E8 cd
- # D: Operand 1: Offset
- insn(opcode: 0xe8, imm: rel32(dst_addr))
- # CALL r/m64 (Mod 11: reg)
- in R64 => dst_reg
- # FF /2
- # M: Operand 1: ModRM:r/m (r)
- insn(
- opcode: 0xff,
- mod_rm: ModRM[mod: Mod11, reg: 2, rm: dst_reg],
- )
- end
- end
-
- def cmove(dst, src)
- case [dst, src]
- # CMOVE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 44 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x44],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovg(dst, src)
- case [dst, src]
- # CMOVG r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4F /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4f],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovge(dst, src)
- case [dst, src]
- # CMOVGE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4D /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4d],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovl(dst, src)
- case [dst, src]
- # CMOVL r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4C /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4c],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovle(dst, src)
- case [dst, src]
- # CMOVLE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4E /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4e],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovne(dst, src)
- case [dst, src]
- # CMOVNE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 45 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x45],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovnz(dst, src)
- case [dst, src]
- # CMOVNZ r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 45 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x45],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovz(dst, src)
- case [dst, src]
- # CMOVZ r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 44 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x44],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- # CMOVZ r64, r/m64 (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 0F 44 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x44],
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- end
- end
-
- def cmp(left, right)
- case [left, right]
- # CMP r/m8, imm8 (Mod 01: [reg]+disp8)
- in [BytePtr[R64 => left_reg, IMM8 => left_disp], IMM8 => right_imm]
- # 80 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- opcode: 0x80,
- mod_rm: ModRM[mod: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm8(right_imm),
- )
- # CMP r/m32, imm32 (Mod 01: [reg]+disp8)
- in [DwordPtr[R64 => left_reg, IMM8 => left_disp], IMM32 => right_imm]
- # 81 /7 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm32(right_imm),
- )
- # CMP r/m64, imm8 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], IMM8 => right_imm]
- # REX.W + 83 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm8(right_imm),
- )
- # CMP r/m64, imm8 (Mod 10: [reg]+disp32)
- in [QwordPtr[R64 => left_reg, IMM32 => left_disp], IMM8 => right_imm]
- # REX.W + 83 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod10, reg: 7, rm: left_reg],
- disp: imm32(left_disp),
- imm: imm8(right_imm),
- )
- # CMP r/m64, imm8 (Mod 11: reg)
- in [R64 => left_reg, IMM8 => right_imm]
- # REX.W + 83 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 7, rm: left_reg],
- imm: imm8(right_imm),
- )
- # CMP r/m64, imm32 (Mod 11: reg)
- in [R64 => left_reg, IMM32 => right_imm]
- # REX.W + 81 /7 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 7, rm: left_reg],
- imm: imm32(right_imm),
- )
- # CMP r/m64, r64 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], R64 => right_reg]
- # REX.W + 39 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x39,
- mod_rm: ModRM[mod: Mod01, reg: right_reg, rm: left_reg],
- disp: left_disp,
- )
- # CMP r/m64, r64 (Mod 10: [reg]+disp32)
- in [QwordPtr[R64 => left_reg, IMM32 => left_disp], R64 => right_reg]
- # REX.W + 39 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x39,
- mod_rm: ModRM[mod: Mod10, reg: right_reg, rm: left_reg],
- disp: imm32(left_disp),
- )
- # CMP r/m64, r64 (Mod 11: reg)
- in [R64 => left_reg, R64 => right_reg]
- # REX.W + 39 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x39,
- mod_rm: ModRM[mod: Mod11, reg: right_reg, rm: left_reg],
- )
- end
- end
-
- def jbe(dst)
- case dst
- # JBE rel8
- in Label => dst_label
- # 76 cb
- insn(opcode: 0x76, imm: dst_label)
- # JBE rel32
- in Integer => dst_addr
- # 0F 86 cd
- insn(opcode: [0x0f, 0x86], imm: rel32(dst_addr))
- end
- end
-
- def je(dst)
- case dst
- # JE rel8
- in Label => dst_label
- # 74 cb
- insn(opcode: 0x74, imm: dst_label)
- # JE rel32
- in Integer => dst_addr
- # 0F 84 cd
- insn(opcode: [0x0f, 0x84], imm: rel32(dst_addr))
- end
- end
-
- def jl(dst)
- case dst
- # JL rel32
- in Integer => dst_addr
- # 0F 8C cd
- insn(opcode: [0x0f, 0x8c], imm: rel32(dst_addr))
- end
- end
-
- def jmp(dst)
- case dst
- # JZ rel8
- in Label => dst_label
- # EB cb
- insn(opcode: 0xeb, imm: dst_label)
- # JMP rel32
- in Integer => dst_addr
- # E9 cd
- insn(opcode: 0xe9, imm: rel32(dst_addr))
- # JMP r/m64 (Mod 01: [reg]+disp8)
- in QwordPtr[R64 => dst_reg, IMM8 => dst_disp]
- # FF /4
- insn(opcode: 0xff, mod_rm: ModRM[mod: Mod01, reg: 4, rm: dst_reg], disp: dst_disp)
- # JMP r/m64 (Mod 11: reg)
- in R64 => dst_reg
- # FF /4
- insn(opcode: 0xff, mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg])
- end
- end
-
- def jne(dst)
- case dst
- # JNE rel8
- in Label => dst_label
- # 75 cb
- insn(opcode: 0x75, imm: dst_label)
- # JNE rel32
- in Integer => dst_addr
- # 0F 85 cd
- insn(opcode: [0x0f, 0x85], imm: rel32(dst_addr))
- end
- end
-
- def jnz(dst)
- case dst
- # JE rel8
- in Label => dst_label
- # 75 cb
- insn(opcode: 0x75, imm: dst_label)
- # JNZ rel32
- in Integer => dst_addr
- # 0F 85 cd
- insn(opcode: [0x0f, 0x85], imm: rel32(dst_addr))
- end
- end
-
- def jo(dst)
- case dst
- # JO rel32
- in Integer => dst_addr
- # 0F 80 cd
- insn(opcode: [0x0f, 0x80], imm: rel32(dst_addr))
- end
- end
-
- def jz(dst)
- case dst
- # JZ rel8
- in Label => dst_label
- # 74 cb
- insn(opcode: 0x74, imm: dst_label)
- # JZ rel32
- in Integer => dst_addr
- # 0F 84 cd
- insn(opcode: [0x0f, 0x84], imm: rel32(dst_addr))
- end
- end
-
- def lea(dst, src)
- case [dst, src]
- # LEA r64,m (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 8D /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8d,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- # LEA r64,m (Mod 10: [reg]+disp32)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM32 => src_disp]]
- # REX.W + 8D /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8d,
- mod_rm: ModRM[mod: Mod10, reg: dst_reg, rm: src_reg],
- disp: imm32(src_disp),
- )
- end
- end
-
- def mov(dst, src)
- case dst
- in R32 => dst_reg
- case src
- # MOV r32 r/m32 (Mod 01: [reg]+disp8)
- in DwordPtr[R64 => src_reg, IMM8 => src_disp]
- # 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: src_disp,
- )
- # MOV r32, imm32 (Mod 11: reg)
- in IMM32 => src_imm
- # B8+ rd id
- # OI: Operand 1: opcode + rd (w), Operand 2: imm8/16/32/64
- insn(
- opcode: 0xb8,
- rd: dst_reg,
- imm: imm32(src_imm),
- )
- end
- in R64 => dst_reg
- case src
- # MOV r64, r/m64 (Mod 00: [reg])
- in QwordPtr[R64 => src_reg]
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod00, reg: dst_reg, rm: src_reg],
- )
- # MOV r64, r/m64 (Mod 01: [reg]+disp8)
- in QwordPtr[R64 => src_reg, IMM8 => src_disp]
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: src_disp,
- )
- # MOV r64, r/m64 (Mod 10: [reg]+disp32)
- in QwordPtr[R64 => src_reg, IMM32 => src_disp]
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod10, reg: dst_reg, rm: src_reg],
- disp: imm32(src_disp),
- )
- # MOV r64, r/m64 (Mod 11: reg)
- in R64 => src_reg
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- # MOV r/m64, imm32 (Mod 11: reg)
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # MOV r64, imm64
- in IMM64 => src_imm
- # REX.W + B8+ rd io
- # OI: Operand 1: opcode + rd (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xb8,
- rd: dst_reg,
- imm: imm64(src_imm),
- )
- end
- in DwordPtr[R64 => dst_reg, IMM8 => dst_disp]
- case src
- # MOV r/m32, imm32 (Mod 01: [reg]+disp8)
- in IMM32 => src_imm
- # C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: dst_reg],
- disp: dst_disp,
- imm: imm32(src_imm),
- )
- end
- in QwordPtr[R64 => dst_reg]
- case src
- # MOV r/m64, imm32 (Mod 00: [reg])
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod00, reg: 0, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # MOV r/m64, r64 (Mod 00: [reg])
- in R64 => src_reg
- # REX.W + 89 /r
- # MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x89,
- mod_rm: ModRM[mod: Mod00, reg: src_reg, rm: dst_reg],
- )
- end
- in QwordPtr[R64 => dst_reg, IMM8 => dst_disp]
- # Optimize encoding when disp is 0
- return mov([dst_reg], src) if dst_disp == 0
-
- case src
- # MOV r/m64, imm32 (Mod 01: [reg]+disp8)
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: dst_reg],
- disp: dst_disp,
- imm: imm32(src_imm),
- )
- # MOV r/m64, r64 (Mod 01: [reg]+disp8)
- in R64 => src_reg
- # REX.W + 89 /r
- # MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x89,
- mod_rm: ModRM[mod: Mod01, reg: src_reg, rm: dst_reg],
- disp: dst_disp,
- )
- end
- in QwordPtr[R64 => dst_reg, IMM32 => dst_disp]
- case src
- # MOV r/m64, imm32 (Mod 10: [reg]+disp32)
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod10, reg: 0, rm: dst_reg],
- disp: imm32(dst_disp),
- imm: imm32(src_imm),
- )
- # MOV r/m64, r64 (Mod 10: [reg]+disp32)
- in R64 => src_reg
- # REX.W + 89 /r
- # MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x89,
- mod_rm: ModRM[mod: Mod10, reg: src_reg, rm: dst_reg],
- disp: imm32(dst_disp),
- )
- end
- end
- end
-
- def or(dst, src)
- case [dst, src]
- # OR r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /1 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 1, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # OR r/m64, imm32 (Mod 11: reg)
- in [R64 => dst_reg, IMM32 => src_imm]
- # REX.W + 81 /1 id
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 1, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # OR r64, r/m64 (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 0B /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x0b,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- end
- end
-
- def push(src)
- case src
- # PUSH r64
- in R64 => src_reg
- # 50+rd
- # O: Operand 1: opcode + rd (r)
- insn(opcode: 0x50, rd: src_reg)
- end
- end
-
- def pop(dst)
- case dst
- # POP r64
- in R64 => dst_reg
- # 58+ rd
- # O: Operand 1: opcode + rd (r)
- insn(opcode: 0x58, rd: dst_reg)
- end
- end
-
- def ret
- # RET
- # Near return: A return to a procedure within the current code segment
- insn(opcode: 0xc3)
- end
-
- def sar(dst, src)
- case [dst, src]
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + C1 /7 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8
- insn(
- prefix: REX_W,
- opcode: 0xc1,
- mod_rm: ModRM[mod: Mod11, reg: 7, rm: dst_reg],
- imm: imm8(src_imm),
- )
- end
- end
-
- def sub(dst, src)
- case [dst, src]
- # SUB r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /5 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 5, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # SUB r/m64, r64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 29 /r
- # MR: Operand 1: ModRM:r/m (r, w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x29,
- mod_rm: ModRM[mod: Mod11, reg: src_reg, rm: dst_reg],
- )
- end
- end
-
- def test(left, right)
- case [left, right]
- # TEST r/m8*, imm8 (Mod 01: [reg]+disp8)
- in [BytePtr[R64 => left_reg, IMM8 => left_disp], IMM8 => right_imm]
- # REX + F6 /0 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- opcode: 0xf6,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: left_reg],
- disp: left_disp,
- imm: imm8(right_imm),
- )
- # TEST r/m64, imm32 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], IMM32 => right_imm]
- # REX.W + F7 /0 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0xf7,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: left_reg],
- disp: left_disp,
- imm: imm32(right_imm),
- )
- # TEST r/m64, imm32 (Mod 10: [reg]+disp32)
- in [QwordPtr[R64 => left_reg, IMM32 => left_disp], IMM32 => right_imm]
- # REX.W + F7 /0 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0xf7,
- mod_rm: ModRM[mod: Mod10, reg: 0, rm: left_reg],
- disp: imm32(left_disp),
- imm: imm32(right_imm),
- )
- # TEST r/m64, imm32 (Mod 11: reg)
- in [R64 => left_reg, IMM32 => right_imm]
- # REX.W + F7 /0 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0xf7,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: left_reg],
- imm: imm32(right_imm),
- )
- # TEST r/m32, r32 (Mod 11: reg)
- in [R32 => left_reg, R32 => right_reg]
- # 85 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- opcode: 0x85,
- mod_rm: ModRM[mod: Mod11, reg: right_reg, rm: left_reg],
- )
- # TEST r/m64, r64 (Mod 11: reg)
- in [R64 => left_reg, R64 => right_reg]
- # REX.W + 85 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x85,
- mod_rm: ModRM[mod: Mod11, reg: right_reg, rm: left_reg],
- )
- end
- end
-
- def xor(dst, src)
- case [dst, src]
- # XOR r/m64, r64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 31 /r
- # MR: Operand 1: ModRM:r/m (r, w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x31,
- mod_rm: ModRM[mod: Mod11, reg: src_reg, rm: dst_reg],
- )
- end
- end
-
- #
- # Utilities
- #
-
- attr_reader :comments
-
- def comment(message)
- @comments[@bytes.size] << message
- end
-
- # Mark the starting address of a block
- def block(block)
- @blocks[@bytes.size] << block
- end
-
- # Mark the starting/ending addresses of a stub
- def stub(stub)
- @stub_starts[@bytes.size] << stub
- yield
- ensure
- @stub_ends[@bytes.size] << stub
- end
-
- def pos_marker(&block)
- @pos_markers[@bytes.size] << block
- end
-
- def new_label(name)
- Label.new(id: @label_id += 1, name:)
- end
-
- # @param [RubyVM::RJIT::Assembler::Label] label
- def write_label(label)
- @labels[label] = @bytes.size
- end
-
- def incr_counter(name)
- if C.rjit_opts.stats
- comment("increment counter #{name}")
- mov(:rax, C.rb_rjit_counters[name].to_i)
- add([:rax], 1) # TODO: lock
- end
- end
-
- private
-
- def insn(prefix: 0, opcode:, rd: nil, mod_rm: nil, disp: nil, imm: nil)
- # Determine prefix
- if rd
- prefix |= REX_B if extended_reg?(rd)
- opcode += reg_code(rd)
- end
- if mod_rm
- prefix |= REX_R if mod_rm.reg.is_a?(Symbol) && extended_reg?(mod_rm.reg)
- prefix |= REX_B if mod_rm.rm.is_a?(Symbol) && extended_reg?(mod_rm.rm)
- end
-
- # Encode insn
- if prefix > 0
- @bytes.push(prefix)
- end
- @bytes.push(*Array(opcode))
- if mod_rm
- mod_rm_byte = encode_mod_rm(
- mod: mod_rm.mod,
- reg: mod_rm.reg.is_a?(Symbol) ? reg_code(mod_rm.reg) : mod_rm.reg,
- rm: mod_rm.rm.is_a?(Symbol) ? reg_code(mod_rm.rm) : mod_rm.rm,
- )
- @bytes.push(mod_rm_byte)
- end
- if disp
- @bytes.push(*Array(disp))
- end
- if imm
- @bytes.push(*imm)
- end
- end
-
- def reg_code(reg)
- reg_code_extended(reg).first
- end
-
- # Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte
- #
- # 7 6 5 4 3 2 1 0
- # +--+--+--+--+--+--+--+--+
- # | Mod | Reg/ | R/M |
- # | | Opcode | |
- # +--+--+--+--+--+--+--+--+
- #
- # The r/m field can specify a register as an operand or it can be combined
- # with the mod field to encode an addressing mode.
- #
- # /0: R/M is 0 (not used)
- # /r: R/M is a register
- def encode_mod_rm(mod:, reg: 0, rm: 0)
- if mod > 0b11
- raise ArgumentError, "too large Mod: #{mod}"
- end
- if reg > 0b111
- raise ArgumentError, "too large Reg/Opcode: #{reg}"
- end
- if rm > 0b111
- raise ArgumentError, "too large R/M: #{rm}"
- end
- (mod << 6) + (reg << 3) + rm
- end
-
- # ib: 1 byte
- def imm8(imm)
- unless imm8?(imm)
- raise ArgumentError, "unexpected imm8: #{imm}"
- end
- [imm].pack('c').unpack('c*') # TODO: consider uimm
- end
-
- # id: 4 bytes
- def imm32(imm)
- unless imm32?(imm)
- raise ArgumentError, "unexpected imm32: #{imm}"
- end
- [imm].pack('l').unpack('c*') # TODO: consider uimm
- end
-
- # io: 8 bytes
- def imm64(imm)
- unless imm64?(imm)
- raise ArgumentError, "unexpected imm64: #{imm}"
- end
- imm_bytes(imm, 8)
- end
-
- def imm_bytes(imm, num_bytes)
- bytes = []
- bits = imm
- num_bytes.times do
- bytes << (bits & 0xff)
- bits >>= 8
- end
- if bits != 0
- raise ArgumentError, "unexpected imm with #{num_bytes} bytes: #{imm}"
- end
- bytes
- end
-
- def rel32(addr)
- [Rel32.new(addr), Rel32Pad, Rel32Pad, Rel32Pad]
- end
-
- def set_code_addrs(write_addr)
- (@bytes.size + 1).times do |index|
- @blocks.fetch(index, []).each do |block|
- block.start_addr = write_addr + index
- end
- @stub_starts.fetch(index, []).each do |stub|
- stub.start_addr = write_addr + index
- end
- @stub_ends.fetch(index, []).each do |stub|
- stub.end_addr = write_addr + index
- end
- end
- end
-
- def resolve_rel32(write_addr)
- @bytes.each_with_index do |byte, index|
- if byte.is_a?(Rel32)
- src_addr = write_addr + index + 4 # offset 4 bytes for rel32 itself
- dst_addr = byte.addr
- rel32 = dst_addr - src_addr
- raise "unexpected offset: #{rel32}" unless imm32?(rel32)
- imm32(rel32).each_with_index do |rel_byte, rel_index|
- @bytes[index + rel_index] = rel_byte
- end
- end
- end
- end
-
- def resolve_labels
- @bytes.each_with_index do |byte, index|
- if byte.is_a?(Label)
- src_index = index + 1 # offset 1 byte for rel8 itself
- dst_index = @labels.fetch(byte)
- rel8 = dst_index - src_index
- raise "unexpected offset: #{rel8}" unless imm8?(rel8)
- @bytes[index] = rel8
- end
- end
- end
-
- def write_bytes(addr)
- Fiddle::Pointer.new(addr)[0, @bytes.size] = @bytes.pack('c*')
- end
- end
-
- module OperandMatcher
- def imm8?(imm)
- (-0x80..0x7f).include?(imm)
- end
-
- def imm32?(imm)
- (-0x8000_0000..0x7fff_ffff).include?(imm) # TODO: consider uimm
- end
-
- def imm64?(imm)
- (-0x8000_0000_0000_0000..0xffff_ffff_ffff_ffff).include?(imm)
- end
-
- def r32?(reg)
- if extended_reg?(reg)
- reg.end_with?('d')
- else
- reg.start_with?('e')
- end
- end
-
- def r64?(reg)
- if extended_reg?(reg)
- reg.match?(/\Ar\d+\z/)
- else
- reg.start_with?('r')
- end
- end
-
- def extended_reg?(reg)
- reg_code_extended(reg).last
- end
-
- def reg_code_extended(reg)
- case reg
- # Not extended
- when :al, :ax, :eax, :rax then [0, false]
- when :cl, :cx, :ecx, :rcx then [1, false]
- when :dl, :dx, :edx, :rdx then [2, false]
- when :bl, :bx, :ebx, :rbx then [3, false]
- when :ah, :sp, :esp, :rsp then [4, false]
- when :ch, :bp, :ebp, :rbp then [5, false]
- when :dh, :si, :esi, :rsi then [6, false]
- when :bh, :di, :edi, :rdi then [7, false]
- # Extended
- when :r8b, :r8w, :r8d, :r8 then [0, true]
- when :r9b, :r9w, :r9d, :r9 then [1, true]
- when :r10b, :r10w, :r10d, :r10 then [2, true]
- when :r11b, :r11w, :r11d, :r11 then [3, true]
- when :r12b, :r12w, :r12d, :r12 then [4, true]
- when :r13b, :r13w, :r13d, :r13 then [5, true]
- when :r14b, :r14w, :r14d, :r14 then [6, true]
- when :r15b, :r15w, :r15d, :r15 then [7, true]
- else raise ArgumentError, "unexpected reg: #{reg.inspect}"
- end
- end
- end
-
- class Assembler
- include OperandMatcher
- extend OperandMatcher
- end
-end
diff --git a/lib/ruby_vm/rjit/block.rb b/lib/ruby_vm/rjit/block.rb
deleted file mode 100644
index cfdaade8b1..0000000000
--- a/lib/ruby_vm/rjit/block.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class RubyVM::RJIT::Block < Struct.new(
- :iseq, # @param ``
- :pc, # @param [Integer] Starting PC
- :ctx, # @param [RubyVM::RJIT::Context] **Starting** Context (TODO: freeze?)
- :start_addr, # @param [Integer] Starting address of this block's JIT code
- :entry_exit, # @param [Integer] Address of entry exit (optional)
- :incoming, # @param [Array<RubyVM::RJIT::BranchStub>] Incoming branches
- :invalidated, # @param [TrueClass,FalseClass] true if already invalidated
-)
- def initialize(incoming: [], invalidated: false, **) = super
-end
diff --git a/lib/ruby_vm/rjit/branch_stub.rb b/lib/ruby_vm/rjit/branch_stub.rb
deleted file mode 100644
index b9fe78b744..0000000000
--- a/lib/ruby_vm/rjit/branch_stub.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-module RubyVM::RJIT
- # Branch shapes
- Next0 = :Next0 # target0 is a fallthrough
- Next1 = :Next1 # target1 is a fallthrough
- Default = :Default # neither targets is a fallthrough
-
- class BranchStub < Struct.new(
- :iseq, # @param [RubyVM::RJIT::CPointer::Struct_rb_iseq_struct] Branch target ISEQ
- :shape, # @param [Symbol] Next0, Next1, or Default
- :target0, # @param [RubyVM::RJIT::BranchTarget] First branch target
- :target1, # @param [RubyVM::RJIT::BranchTarget,NilClass] Second branch target (optional)
- :compile, # @param [Proc] A callback to (re-)generate this branch stub
- :start_addr, # @param [Integer] Stub source start address to be re-generated
- :end_addr, # @param [Integer] Stub source end address to be re-generated
- )
- end
-
- class BranchTarget < Struct.new(
- :pc,
- :ctx,
- :address,
- )
- end
-end
diff --git a/lib/ruby_vm/rjit/c_pointer.rb b/lib/ruby_vm/rjit/c_pointer.rb
deleted file mode 100644
index d65d5a93a5..0000000000
--- a/lib/ruby_vm/rjit/c_pointer.rb
+++ /dev/null
@@ -1,360 +0,0 @@
-module RubyVM::RJIT
- # Every class under this namespace is a pointer. Even if the type is
- # immediate, it shouldn't be dereferenced until `*` is called.
- module CPointer
- # Note: We'd like to avoid alphabetic method names to avoid a conflict
- # with member methods. to_i and to_s are considered an exception.
- class Struct
- # @param name [String]
- # @param sizeof [Integer]
- # @param members [Hash{ Symbol => [RubyVM::RJIT::CType::*, Integer, TrueClass] }]
- def initialize(addr, sizeof, members)
- @addr = addr
- @sizeof = sizeof
- @members = members
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- # Serialized address for generated code
- def to_s
- "0x#{@addr.to_s(16)}"
- end
-
- # Pointer diff
- def -(struct)
- raise ArgumentError if self.class != struct.class
- (@addr - struct.to_i) / @sizeof
- end
-
- # Primitive API that does no automatic dereference
- # TODO: remove this?
- # @param member [Symbol]
- def [](member)
- type, offset = @members.fetch(member)
- type.new(@addr + offset / 8)
- end
-
- private
-
- # @param member [Symbol]
- # @param value [Object]
- def []=(member, value)
- type, offset = @members.fetch(member)
- type[@addr + offset / 8] = value
- end
-
- # @param size [Integer]
- # @param members [Hash{ Symbol => [Integer, RubyVM::RJIT::CType::*] }]
- def self.define(size, members)
- Class.new(self) do
- # Return the size of this type
- define_singleton_method(:size) { size }
-
- # Return the offset to a field
- define_singleton_method(:offsetof) do |field, *fields|
- member, offset = members.fetch(field)
- offset /= 8
- unless fields.empty?
- offset += member.offsetof(*fields)
- end
- offset
- end
-
- # Return member names
- define_singleton_method(:members) { members.keys }
-
- define_method(:initialize) do |addr = nil|
- if addr.nil? # TODO: get rid of this feature later
- addr = Fiddle.malloc(size)
- end
- super(addr, size, members)
- end
-
- members.each do |member, (type, offset, to_ruby)|
- # Intelligent API that does automatic dereference
- define_method(member) do
- value = self[member]
- if value.respond_to?(:*)
- value = value.*
- end
- if to_ruby
- value = C.to_ruby(value)
- end
- value
- end
-
- define_method("#{member}=") do |value|
- if to_ruby
- value = C.to_value(value)
- end
- self[member] = value
- end
- end
- end
- end
- end
-
- # Note: We'd like to avoid alphabetic method names to avoid a conflict
- # with member methods. to_i is considered an exception.
- class Union
- # @param _name [String] To be used when it starts defining a union pointer class
- # @param sizeof [Integer]
- # @param members [Hash{ Symbol => RubyVM::RJIT::CType::* }]
- def initialize(addr, sizeof, members)
- @addr = addr
- @sizeof = sizeof
- @members = members
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- # Move addr to access this pointer like an array
- def +(index)
- raise ArgumentError unless index.is_a?(Integer)
- self.class.new(@addr + index * @sizeof)
- end
-
- # Pointer diff
- def -(union)
- raise ArgumentError if self.class != union.class
- (@addr - union.instance_variable_get(:@addr)) / @sizeof
- end
-
- # @param sizeof [Integer]
- # @param members [Hash{ Symbol => RubyVM::RJIT::CType::* }]
- def self.define(sizeof, members)
- Class.new(self) do
- # Return the size of this type
- define_singleton_method(:sizeof) { sizeof }
-
- # Part of Struct's offsetof implementation
- define_singleton_method(:offsetof) do |field, *fields|
- member = members.fetch(field)
- offset = 0
- unless fields.empty?
- offset += member.offsetof(*fields)
- end
- offset
- end
-
- define_method(:initialize) do |addr|
- super(addr, sizeof, members)
- end
-
- members.each do |member, type|
- # Intelligent API that does automatic dereference
- define_method(member) do
- value = type.new(@addr)
- if value.respond_to?(:*)
- value = value.*
- end
- value
- end
- end
- end
- end
- end
-
- class Immediate
- # @param addr [Integer]
- # @param size [Integer]
- # @param pack [String]
- def initialize(addr, size, pack)
- @addr = addr
- @size = size
- @pack = pack
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- # Move addr to addess this pointer like an array
- def +(index)
- Immediate.new(@addr + index * @size, @size, @pack)
- end
-
- # Dereference
- def *
- self[0]
- end
-
- # Array access
- def [](index)
- return nil if @addr == 0
- Fiddle::Pointer.new(@addr + index * @size)[0, @size].unpack1(@pack)
- end
-
- # Array set
- def []=(index, value)
- Fiddle::Pointer.new(@addr + index * @size)[0, @size] = [value].pack(@pack)
- end
-
- # Serialized address for generated code. Used for embedding things like body->iseq_encoded.
- def to_s
- "0x#{Integer(@addr).to_s(16)}"
- end
-
- # @param fiddle_type [Integer] Fiddle::TYPE_*
- def self.define(fiddle_type)
- size = Fiddle::PackInfo::SIZE_MAP.fetch(fiddle_type)
- pack = Fiddle::PackInfo::PACK_MAP.fetch(fiddle_type)
-
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, size, pack)
- end
-
- define_singleton_method(:size) do
- size
- end
-
- # Type-level []=: Used by struct fields
- define_singleton_method(:[]=) do |addr, value|
- Fiddle::Pointer.new(addr)[0, size] = [value].pack(pack)
- end
- end
- end
- end
-
- # -Fiddle::TYPE_CHAR Immediate with special handling of true/false
- class Bool < Immediate.define(-Fiddle::TYPE_CHAR)
- # Dereference
- def *
- return nil if @addr == 0
- super != 0
- end
-
- def self.[]=(addr, value)
- super(addr, value ? 1 : 0)
- end
- end
-
- class Pointer
- attr_reader :type
-
- # @param addr [Integer]
- # @param type [Class] RubyVM::RJIT::CType::*
- def initialize(addr, type)
- @addr = addr
- @type = type
- end
-
- # Move addr to addess this pointer like an array
- def +(index)
- raise ArgumentError unless index.is_a?(Integer)
- Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP, @type)
- end
-
- # Dereference
- def *
- return nil if dest_addr == 0
- @type.new(dest_addr)
- end
-
- # Array access
- def [](index)
- (self + index).*
- end
-
- # Array set
- # @param index [Integer]
- # @param value [Integer, RubyVM::RJIT::CPointer::Struct] an address itself or an object that return an address with to_i
- def []=(index, value)
- Fiddle::Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP)[0, Fiddle::SIZEOF_VOIDP] =
- [value.to_i].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- private
-
- def dest_addr
- Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_VOIDP].unpack1(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
- end
-
- def self.define(block)
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, block.call)
- end
-
- # Type-level []=: Used by struct fields
- # @param addr [Integer]
- # @param value [Integer, RubyVM::RJIT::CPointer::Struct] an address itself, or an object that return an address with to_i
- define_singleton_method(:[]=) do |addr, value|
- value = value.to_i
- Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP] = [value].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
- end
- end
- end
- end
-
- class BitField
- # @param addr [Integer]
- # @param width [Integer]
- # @param offset [Integer]
- def initialize(addr, width, offset)
- @addr = addr
- @width = width
- @offset = offset
- end
-
- # Dereference
- def *
- byte = Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_CHAR].unpack('c').first
- if @width == 1
- bit = (1 & (byte >> @offset))
- bit == 1
- elsif @width <= 8 && @offset == 0
- bitmask = @width.times.map { |i| 1 << i }.sum
- byte & bitmask
- else
- raise NotImplementedError.new("not-implemented bit field access: width=#{@width} offset=#{@offset}")
- end
- end
-
- # @param width [Integer]
- # @param offset [Integer]
- def self.define(width, offset)
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, width, offset)
- end
- end
- end
- end
-
- # Give a name to a dynamic CPointer class to see it on inspect
- def self.with_class_name(prefix, name, cache: false, &block)
- return block.call if name.empty?
-
- # Use a cached result only if cache: true
- class_name = "#{prefix}_#{name}"
- klass =
- if cache && self.const_defined?(class_name)
- self.const_get(class_name)
- else
- block.call
- end
-
- # Give it a name unless it's already defined
- unless self.const_defined?(class_name)
- self.const_set(class_name, klass)
- end
-
- klass
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/c_type.rb b/lib/ruby_vm/rjit/c_type.rb
deleted file mode 100644
index bec7e21c38..0000000000
--- a/lib/ruby_vm/rjit/c_type.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require 'fiddle'
-require 'fiddle/pack'
-require_relative 'c_pointer'
-
-module RubyVM::RJIT
- module CType
- module Struct
- # @param name [String]
- # @param members [Hash{ Symbol => [Integer, RubyVM::RJIT::CType::*] }]
- def self.new(name, sizeof, **members)
- name = members.keys.join('_') if name.empty?
- CPointer.with_class_name('Struct', name) do
- CPointer::Struct.define(sizeof, members)
- end
- end
- end
-
- module Union
- # @param name [String]
- # @param members [Hash{ Symbol => RubyVM::RJIT::CType::* }]
- def self.new(name, sizeof, **members)
- name = members.keys.join('_') if name.empty?
- CPointer.with_class_name('Union', name) do
- CPointer::Union.define(sizeof, members)
- end
- end
- end
-
- module Immediate
- # @param fiddle_type [Integer]
- def self.new(fiddle_type)
- name = Fiddle.constants.find do |const|
- const.start_with?('TYPE_') && Fiddle.const_get(const) == fiddle_type.abs
- end&.to_s
- name.delete_prefix!('TYPE_')
- if fiddle_type.negative?
- name.prepend('U')
- end
- CPointer.with_class_name('Immediate', name, cache: true) do
- CPointer::Immediate.define(fiddle_type)
- end
- end
-
- # @param type [String]
- def self.parse(ctype)
- new(Fiddle::Importer.parse_ctype(ctype))
- end
-
- def self.find(size, signed)
- fiddle_type = TYPE_MAP.fetch(size)
- fiddle_type = -fiddle_type unless signed
- new(fiddle_type)
- end
-
- TYPE_MAP = Fiddle::PackInfo::SIZE_MAP.map { |type, size| [size, type.abs] }.to_h
- private_constant :TYPE_MAP
- end
-
- module Bool
- def self.new
- CPointer::Bool
- end
- end
-
- class Pointer
- # This takes a block to avoid "stack level too deep" on a cyclic reference
- # @param block [Proc]
- def self.new(&block)
- CPointer.with_class_name('Pointer', block.object_id.to_s) do
- CPointer::Pointer.define(block)
- end
- end
- end
-
- module BitField
- # @param width [Integer]
- # @param offset [Integer]
- def self.new(width, offset)
- CPointer.with_class_name('BitField', "#{offset}_#{width}") do
- CPointer::BitField.define(width, offset)
- end
- end
- end
-
- # Types that are referenced but not part of code generation targets
- Stub = ::Struct.new(:name)
-
- # Types that it failed to figure out from the header
- Unknown = Module.new
- end
-end
diff --git a/lib/ruby_vm/rjit/code_block.rb b/lib/ruby_vm/rjit/code_block.rb
deleted file mode 100644
index 6260ec8b4b..0000000000
--- a/lib/ruby_vm/rjit/code_block.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-module RubyVM::RJIT
- class CodeBlock
- # @param mem_block [Integer] JIT buffer address
- # @param mem_size [Integer] JIT buffer size
- # @param outliend [TrueClass,FalseClass] true for outlined CodeBlock
- def initialize(mem_block:, mem_size:, outlined: false)
- @comments = Hash.new { |h, k| h[k] = [] }
- @mem_block = mem_block
- @mem_size = mem_size
- @write_pos = 0
- @outlined = outlined
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- def write(asm)
- return 0 if @write_pos + asm.size >= @mem_size
-
- start_addr = write_addr
-
- # Write machine code
- C.mprotect_write(@mem_block, @mem_size)
- @write_pos += asm.assemble(start_addr)
- C.mprotect_exec(@mem_block, @mem_size)
-
- end_addr = write_addr
-
- # Convert comment indexes to addresses
- asm.comments.each do |index, comments|
- @comments[start_addr + index] += comments
- end
- asm.comments.clear
-
- # Dump disasm if --rjit-dump-disasm
- if C.rjit_opts.dump_disasm && start_addr < end_addr
- dump_disasm(start_addr, end_addr)
- end
- start_addr
- end
-
- def set_write_addr(addr)
- @write_pos = addr - @mem_block
- @comments.delete(addr) # TODO: clean up old comments for all the overwritten range?
- end
-
- def with_write_addr(addr)
- old_write_pos = @write_pos
- set_write_addr(addr)
- yield
- ensure
- @write_pos = old_write_pos
- end
-
- def write_addr
- @mem_block + @write_pos
- end
-
- def include?(addr)
- (@mem_block...(@mem_block + @mem_size)).include?(addr)
- end
-
- def dump_disasm(from, to, io: STDOUT, color: true, test: false)
- C.dump_disasm(from, to, test:).each do |address, mnemonic, op_str|
- @comments.fetch(address, []).each do |comment|
- io.puts colorize(" # #{comment}", bold: true, color:)
- end
- io.puts colorize(" 0x#{format("%x", address)}: #{mnemonic} #{op_str}", color:)
- end
- io.puts
- end
-
- private
-
- def colorize(text, bold: false, color:)
- return text unless color
- buf = +''
- buf << "\e[1m" if bold
- buf << "\e[34m" if @outlined
- buf << text
- buf << "\e[0m"
- buf
- end
-
- def bold(text)
- "\e[1m#{text}\e[0m"
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/compiler.rb b/lib/ruby_vm/rjit/compiler.rb
deleted file mode 100644
index 9ae528a0e9..0000000000
--- a/lib/ruby_vm/rjit/compiler.rb
+++ /dev/null
@@ -1,509 +0,0 @@
-require 'ruby_vm/rjit/assembler'
-require 'ruby_vm/rjit/block'
-require 'ruby_vm/rjit/branch_stub'
-require 'ruby_vm/rjit/code_block'
-require 'ruby_vm/rjit/context'
-require 'ruby_vm/rjit/entry_stub'
-require 'ruby_vm/rjit/exit_compiler'
-require 'ruby_vm/rjit/insn_compiler'
-require 'ruby_vm/rjit/instruction'
-require 'ruby_vm/rjit/invariants'
-require 'ruby_vm/rjit/jit_state'
-require 'ruby_vm/rjit/type'
-
-module RubyVM::RJIT
- # Compilation status
- KeepCompiling = :KeepCompiling
- CantCompile = :CantCompile
- EndBlock = :EndBlock
-
- # Ruby constants
- Qtrue = Fiddle::Qtrue
- Qfalse = Fiddle::Qfalse
- Qnil = Fiddle::Qnil
- Qundef = Fiddle::Qundef
-
- # Callee-saved registers
- # TODO: support using r12/r13 here
- EC = :r14
- CFP = :r15
- SP = :rbx
-
- # Scratch registers: rax, rcx, rdx
-
- # Mark objects in this Array during GC
- GC_REFS = []
-
- # Maximum number of versions per block
- # 1 means always create generic versions
- MAX_VERSIONS = 4
-
- class Compiler
- attr_accessor :write_pos
-
- def self.decode_insn(encoded)
- INSNS.fetch(C.rb_vm_insn_decode(encoded))
- end
-
- def initialize
- mem_size = C.rjit_opts.exec_mem_size * 1024 * 1024
- mem_block = C.mmap(mem_size)
- @cb = CodeBlock.new(mem_block: mem_block, mem_size: mem_size / 2)
- @ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2, outlined: true)
- @exit_compiler = ExitCompiler.new
- @insn_compiler = InsnCompiler.new(@cb, @ocb, @exit_compiler)
- Invariants.initialize(@cb, @ocb, self, @exit_compiler)
- end
-
- # Compile an ISEQ from its entry point.
- # @param iseq `RubyVM::RJIT::CPointer::Struct_rb_iseq_t`
- # @param cfp `RubyVM::RJIT::CPointer::Struct_rb_control_frame_t`
- def compile(iseq, cfp)
- pc = cfp.pc.to_i
- jit = JITState.new(iseq:, cfp:)
- asm = Assembler.new
- compile_prologue(asm, iseq, pc)
- compile_block(asm, jit:, pc:)
- iseq.body.jit_entry = @cb.write(asm)
- rescue Exception => e
- $stderr.puts e.full_message
- exit 1
- end
-
- # Compile an entry.
- # @param entry [RubyVM::RJIT::EntryStub]
- def entry_stub_hit(entry_stub, cfp)
- # Compile a new entry guard as a next entry
- pc = cfp.pc.to_i
- next_entry = Assembler.new.then do |asm|
- compile_entry_chain_guard(asm, cfp.iseq, pc)
- @cb.write(asm)
- end
-
- # Try to find an existing compiled version of this block
- ctx = Context.new
- block = find_block(cfp.iseq, pc, ctx)
- if block
- # If an existing block is found, generate a jump to the block.
- asm = Assembler.new
- asm.jmp(block.start_addr)
- @cb.write(asm)
- else
- # If this block hasn't yet been compiled, generate blocks after the entry guard.
- asm = Assembler.new
- jit = JITState.new(iseq: cfp.iseq, cfp:)
- compile_block(asm, jit:, pc:, ctx:)
- @cb.write(asm)
-
- block = jit.block
- end
-
- # Regenerate the previous entry
- @cb.with_write_addr(entry_stub.start_addr) do
- # The last instruction of compile_entry_chain_guard is jne
- asm = Assembler.new
- asm.jne(next_entry)
- @cb.write(asm)
- end
-
- return block.start_addr
- rescue Exception => e
- $stderr.puts e.full_message
- exit 1
- end
-
- # Compile a branch stub.
- # @param branch_stub [RubyVM::RJIT::BranchStub]
- # @param cfp `RubyVM::RJIT::CPointer::Struct_rb_control_frame_t`
- # @param target0_p [TrueClass,FalseClass]
- # @return [Integer] The starting address of the compiled branch stub
- def branch_stub_hit(branch_stub, cfp, target0_p)
- # Update cfp->pc for `jit.at_current_insn?`
- target = target0_p ? branch_stub.target0 : branch_stub.target1
- cfp.pc = target.pc
-
- # Reuse an existing block if it already exists
- block = find_block(branch_stub.iseq, target.pc, target.ctx)
-
- # If the branch stub's jump is the last code, allow overwriting part of
- # the old branch code with the new block code.
- fallthrough = block.nil? && @cb.write_addr == branch_stub.end_addr
- if fallthrough
- # If the branch stub's jump is the last code, allow overwriting part of
- # the old branch code with the new block code.
- @cb.set_write_addr(branch_stub.start_addr)
- branch_stub.shape = target0_p ? Next0 : Next1
- Assembler.new.tap do |branch_asm|
- branch_stub.compile.call(branch_asm)
- @cb.write(branch_asm)
- end
- end
-
- # Reuse or generate a block
- if block
- target.address = block.start_addr
- else
- jit = JITState.new(iseq: branch_stub.iseq, cfp:)
- target.address = Assembler.new.then do |asm|
- compile_block(asm, jit:, pc: target.pc, ctx: target.ctx.dup)
- @cb.write(asm)
- end
- block = jit.block
- end
- block.incoming << branch_stub # prepare for invalidate_block
-
- # Re-generate the branch code for non-fallthrough cases
- unless fallthrough
- @cb.with_write_addr(branch_stub.start_addr) do
- branch_asm = Assembler.new
- branch_stub.compile.call(branch_asm)
- @cb.write(branch_asm)
- end
- end
-
- return target.address
- rescue Exception => e
- $stderr.puts e.full_message
- exit 1
- end
-
- # @param iseq `RubyVM::RJIT::CPointer::Struct_rb_iseq_t`
- # @param pc [Integer]
- def invalidate_blocks(iseq, pc)
- list_blocks(iseq, pc).each do |block|
- invalidate_block(block)
- end
-
- # If they were the ISEQ's first blocks, re-compile RJIT entry as well
- if iseq.body.iseq_encoded.to_i == pc
- iseq.body.jit_entry = 0
- iseq.body.jit_entry_calls = 0
- end
- end
-
- def invalidate_block(block)
- iseq = block.iseq
- # Avoid touching GCed ISEQs. We assume it won't be re-entered.
- return unless C.imemo_type_p(iseq, C.imemo_iseq)
-
- # Remove this block from the version array
- remove_block(iseq, block)
-
- # Invalidate the block with entry exit
- unless block.invalidated
- @cb.with_write_addr(block.start_addr) do
- asm = Assembler.new
- asm.comment('invalidate_block')
- asm.jmp(block.entry_exit)
- @cb.write(asm)
- end
- block.invalidated = true
- end
-
- # Re-stub incoming branches
- block.incoming.each do |branch_stub|
- target = [branch_stub.target0, branch_stub.target1].compact.find do |target|
- target.pc == block.pc && target.ctx == block.ctx
- end
- next if target.nil?
- # TODO: Could target.address be a stub address? Is invalidation not needed in that case?
-
- # If the target being re-generated is currently a fallthrough block,
- # the fallthrough code must be rewritten with a jump to the stub.
- if target.address == branch_stub.end_addr
- branch_stub.shape = Default
- end
-
- target.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(block.ctx, ocb_asm, branch_stub, target == branch_stub.target0)
- @ocb.write(ocb_asm)
- end
- @cb.with_write_addr(branch_stub.start_addr) do
- branch_asm = Assembler.new
- branch_stub.compile.call(branch_asm)
- @cb.write(branch_asm)
- end
- end
- end
-
- private
-
- # Callee-saved: rbx, rsp, rbp, r12, r13, r14, r15
- # Caller-saved: rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11
- #
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_prologue(asm, iseq, pc)
- asm.comment('RJIT entry point')
-
- # Save callee-saved registers used by JITed code
- asm.push(CFP)
- asm.push(EC)
- asm.push(SP)
-
- # Move arguments EC and CFP to dedicated registers
- asm.mov(EC, :rdi)
- asm.mov(CFP, :rsi)
-
- # Load sp to a dedicated register
- asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
-
- # Setup cfp->jit_return
- asm.mov(:rax, leave_exit)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:jit_return)], :rax)
-
- # We're compiling iseqs that we *expect* to start at `insn_idx`. But in
- # the case of optional parameters, the interpreter can set the pc to a
- # different location depending on the optional parameters. If an iseq
- # has optional parameters, we'll add a runtime check that the PC we've
- # compiled for is the same PC that the interpreter wants us to run with.
- # If they don't match, then we'll take a side exit.
- if iseq.body.param.flags.has_opt
- compile_entry_chain_guard(asm, iseq, pc)
- end
- end
-
- def compile_entry_chain_guard(asm, iseq, pc)
- entry_stub = EntryStub.new
- stub_addr = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_entry_stub(ocb_asm, entry_stub)
- @ocb.write(ocb_asm)
- end
-
- asm.comment('guard expected PC')
- asm.mov(:rax, pc)
- asm.cmp([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax)
-
- asm.stub(entry_stub) do
- asm.jne(stub_addr)
- end
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- def compile_block(asm, jit:, pc:, ctx: Context.new)
- # Mark the block start address and prepare an exit code storage
- ctx = limit_block_versions(jit.iseq, pc, ctx)
- block = Block.new(iseq: jit.iseq, pc:, ctx: ctx.dup)
- jit.block = block
- asm.block(block)
-
- iseq = jit.iseq
- asm.comment("Block: #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{iseq_lineno(iseq, pc)}")
-
- # Compile each insn
- index = (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size
- while index < iseq.body.iseq_size
- # Set the current instruction
- insn = self.class.decode_insn(iseq.body.iseq_encoded[index])
- jit.pc = (iseq.body.iseq_encoded + index).to_i
- jit.stack_size_for_pc = ctx.stack_size
- jit.side_exit_for_pc.clear
-
- # If previous instruction requested to record the boundary
- if jit.record_boundary_patch_point
- # Generate an exit to this instruction and record it
- exit_pos = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_side_exit(jit.pc, ctx, ocb_asm)
- @ocb.write(ocb_asm)
- end
- Invariants.record_global_inval_patch(asm, exit_pos)
- jit.record_boundary_patch_point = false
- end
-
- # In debug mode, verify our existing assumption
- if C.rjit_opts.verify_ctx && jit.at_current_insn?
- verify_ctx(jit, ctx)
- end
-
- case status = @insn_compiler.compile(jit, ctx, asm, insn)
- when KeepCompiling
- # For now, reset the chain depth after each instruction as only the
- # first instruction in the block can concern itself with the depth.
- ctx.chain_depth = 0
-
- index += insn.len
- when EndBlock
- # TODO: pad nops if entry exit exists (not needed for x86_64?)
- break
- when CantCompile
- # Rewind stack_size using ctx.with_stack_size to allow stack_size changes
- # before you return CantCompile.
- @exit_compiler.compile_side_exit(jit.pc, ctx.with_stack_size(jit.stack_size_for_pc), asm)
-
- # If this is the first instruction, this block never needs to be invalidated.
- if block.pc == iseq.body.iseq_encoded.to_i + index * C.VALUE.size
- block.invalidated = true
- end
-
- break
- else
- raise "compiling #{insn.name} returned unexpected status: #{status.inspect}"
- end
- end
-
- incr_counter(:compiled_block_count)
- add_block(iseq, block)
- end
-
- def leave_exit
- @leave_exit ||= Assembler.new.then do |asm|
- @exit_compiler.compile_leave_exit(asm)
- @ocb.write(asm)
- end
- end
-
- def incr_counter(name)
- if C.rjit_opts.stats
- C.rb_rjit_counters[name][0] += 1
- end
- end
-
- # Produce a generic context when the block version limit is hit for the block
- def limit_block_versions(iseq, pc, ctx)
- # Guard chains implement limits separately, do nothing
- if ctx.chain_depth > 0
- return ctx.dup
- end
-
- # If this block version we're about to add will hit the version limit
- if list_blocks(iseq, pc).size + 1 >= MAX_VERSIONS
- # Produce a generic context that stores no type information,
- # but still respects the stack_size and sp_offset constraints.
- # This new context will then match all future requests.
- generic_ctx = Context.new
- generic_ctx.stack_size = ctx.stack_size
- generic_ctx.sp_offset = ctx.sp_offset
-
- if ctx.diff(generic_ctx) == TypeDiff::Incompatible
- raise 'should substitute a compatible context'
- end
-
- return generic_ctx
- end
-
- return ctx.dup
- end
-
- def list_blocks(iseq, pc)
- rjit_blocks(iseq)[pc]
- end
-
- # @param [Integer] pc
- # @param [RubyVM::RJIT::Context] ctx
- # @return [RubyVM::RJIT::Block,NilClass]
- def find_block(iseq, pc, ctx)
- versions = rjit_blocks(iseq)[pc]
-
- best_version = nil
- best_diff = Float::INFINITY
-
- versions.each do |block|
- # Note that we always prefer the first matching
- # version found because of inline-cache chains
- case ctx.diff(block.ctx)
- in TypeDiff::Compatible[diff] if diff < best_diff
- best_version = block
- best_diff = diff
- else
- end
- end
-
- return best_version
- end
-
- # @param [RubyVM::RJIT::Block] block
- def add_block(iseq, block)
- rjit_blocks(iseq)[block.pc] << block
- end
-
- # @param [RubyVM::RJIT::Block] block
- def remove_block(iseq, block)
- rjit_blocks(iseq)[block.pc].delete(block)
- end
-
- def rjit_blocks(iseq)
- # Guard against ISEQ GC at random moments
-
- unless C.imemo_type_p(iseq, C.imemo_iseq)
- return Hash.new { |h, k| h[k] = [] }
- end
-
- unless iseq.body.rjit_blocks
- iseq.body.rjit_blocks = Hash.new { |blocks, pc| blocks[pc] = [] }
- # For some reason, rb_rjit_iseq_mark didn't protect this Hash
- # from being freed. So we rely on GC_REFS to keep the Hash.
- GC_REFS << iseq.body.rjit_blocks
- end
- iseq.body.rjit_blocks
- end
-
- def iseq_lineno(iseq, pc)
- C.rb_iseq_line_no(iseq, (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size)
- rescue RangeError # bignum too big to convert into `unsigned long long' (RangeError)
- -1
- end
-
- # Verify the ctx's types and mappings against the compile-time stack, self, and locals.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- def verify_ctx(jit, ctx)
- # Only able to check types when at current insn
- assert(jit.at_current_insn?)
-
- self_val = jit.peek_at_self
- self_val_type = Type.from(self_val)
-
- # Verify self operand type
- assert_compatible(self_val_type, ctx.get_opnd_type(SelfOpnd))
-
- # Verify stack operand types
- [ctx.stack_size, MAX_TEMP_TYPES].min.times do |i|
- learned_mapping, learned_type = ctx.get_opnd_mapping(StackOpnd[i])
- stack_val = jit.peek_at_stack(i)
- val_type = Type.from(stack_val)
-
- case learned_mapping
- in MapToSelf
- if C.to_value(self_val) != C.to_value(stack_val)
- raise "verify_ctx: stack value was mapped to self, but values did not match:\n"\
- "stack: #{stack_val.inspect}, self: #{self_val.inspect}"
- end
- in MapToLocal[local_idx]
- local_val = jit.peek_at_local(local_idx)
- if C.to_value(local_val) != C.to_value(stack_val)
- raise "verify_ctx: stack value was mapped to local, but values did not match:\n"\
- "stack: #{stack_val.inspect}, local: #{local_val.inspect}"
- end
- in MapToStack
- # noop
- end
-
- # If the actual type differs from the learned type
- assert_compatible(val_type, learned_type)
- end
-
- # Verify local variable types
- local_table_size = jit.iseq.body.local_table_size
- [local_table_size, MAX_TEMP_TYPES].min.times do |i|
- learned_type = ctx.get_local_type(i)
- local_val = jit.peek_at_local(i)
- local_type = Type.from(local_val)
-
- assert_compatible(local_type, learned_type)
- end
- end
-
- def assert_compatible(actual_type, ctx_type)
- if actual_type.diff(ctx_type) == TypeDiff::Incompatible
- raise "verify_ctx: ctx type (#{ctx_type.type.inspect}) is incompatible with actual type (#{actual_type.type.inspect})"
- end
- end
-
- def assert(cond)
- unless cond
- raise "'#{cond.inspect}' was not true"
- end
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/context.rb b/lib/ruby_vm/rjit/context.rb
deleted file mode 100644
index 66da478c7f..0000000000
--- a/lib/ruby_vm/rjit/context.rb
+++ /dev/null
@@ -1,377 +0,0 @@
-module RubyVM::RJIT
- # Maximum number of temp value types we keep track of
- MAX_TEMP_TYPES = 8
- # Maximum number of local variable types we keep track of
- MAX_LOCAL_TYPES = 8
-
- # Operand to a YARV bytecode instruction
- SelfOpnd = :SelfOpnd # The value is self
- StackOpnd = Data.define(:index) # Temporary stack operand with stack index
-
- # Potential mapping of a value on the temporary stack to self,
- # a local variable, or constant so that we can track its type
- MapToStack = :MapToStack # Normal stack value
- MapToSelf = :MapToSelf # Temp maps to the self operand
- MapToLocal = Data.define(:local_index) # Temp maps to a local variable with index
-
- class Context < Struct.new(
- :stack_size, # @param [Integer] The number of values on the stack
- :sp_offset, # @param [Integer] JIT sp offset relative to the interpreter's sp
- :chain_depth, # @param [Integer] jit_chain_guard depth
- :local_types, # @param [Array<RubyVM::RJIT::Type>] Local variable types we keep track of
- :temp_types, # @param [Array<RubyVM::RJIT::Type>] Temporary variable types we keep track of
- :self_type, # @param [RubyVM::RJIT::Type] Type we track for self
- :temp_mapping, # @param [Array<Symbol>] Mapping of temp stack entries to types we track
- )
- def initialize(
- stack_size: 0,
- sp_offset: 0,
- chain_depth: 0,
- local_types: [Type::Unknown] * MAX_LOCAL_TYPES,
- temp_types: [Type::Unknown] * MAX_TEMP_TYPES,
- self_type: Type::Unknown,
- temp_mapping: [MapToStack] * MAX_TEMP_TYPES
- ) = super
-
- # Deep dup by default for safety
- def dup
- ctx = super
- ctx.local_types = ctx.local_types.dup
- ctx.temp_types = ctx.temp_types.dup
- ctx.temp_mapping = ctx.temp_mapping.dup
- ctx
- end
-
- # Create a new Context instance with a given stack_size and sp_offset adjusted
- # accordingly. This is useful when you want to virtually rewind a stack_size for
- # generating a side exit while considering past sp_offset changes on gen_save_sp.
- def with_stack_size(stack_size)
- ctx = self.dup
- ctx.sp_offset -= ctx.stack_size - stack_size
- ctx.stack_size = stack_size
- ctx
- end
-
- def stack_opnd(depth_from_top)
- [SP, C.VALUE.size * (self.sp_offset - 1 - depth_from_top)]
- end
-
- def sp_opnd(offset_bytes = 0)
- [SP, (C.VALUE.size * self.sp_offset) + offset_bytes]
- end
-
- # Push one new value on the temp stack with an explicit mapping
- # Return a pointer to the new stack top
- def stack_push_mapping(mapping_temp_type)
- stack_size = self.stack_size
-
- # Keep track of the type and mapping of the value
- if stack_size < MAX_TEMP_TYPES
- mapping, temp_type = mapping_temp_type
- self.temp_mapping[stack_size] = mapping
- self.temp_types[stack_size] = temp_type
-
- case mapping
- in MapToLocal[idx]
- assert(idx < MAX_LOCAL_TYPES)
- else
- end
- end
-
- self.stack_size += 1
- self.sp_offset += 1
-
- return self.stack_opnd(0)
- end
-
- # Push one new value on the temp stack
- # Return a pointer to the new stack top
- def stack_push(val_type)
- return self.stack_push_mapping([MapToStack, val_type])
- end
-
- # Push the self value on the stack
- def stack_push_self
- return self.stack_push_mapping([MapToStack, Type::Unknown])
- end
-
- # Push a local variable on the stack
- def stack_push_local(local_idx)
- if local_idx >= MAX_LOCAL_TYPES
- return self.stack_push(Type::Unknown)
- end
-
- return self.stack_push_mapping([MapToLocal[local_idx], Type::Unknown])
- end
-
- # Pop N values off the stack
- # Return a pointer to the stack top before the pop operation
- def stack_pop(n = 1)
- assert(n <= self.stack_size)
-
- top = self.stack_opnd(0)
-
- # Clear the types of the popped values
- n.times do |i|
- idx = self.stack_size - i - 1
-
- if idx < MAX_TEMP_TYPES
- self.temp_types[idx] = Type::Unknown
- self.temp_mapping[idx] = MapToStack
- end
- end
-
- self.stack_size -= n
- self.sp_offset -= n
-
- return top
- end
-
- def shift_stack(argc)
- assert(argc < self.stack_size)
-
- method_name_index = self.stack_size - argc - 1
-
- (method_name_index...(self.stack_size - 1)).each do |i|
- if i + 1 < MAX_TEMP_TYPES
- self.temp_types[i] = self.temp_types[i + 1]
- self.temp_mapping[i] = self.temp_mapping[i + 1]
- end
- end
- self.stack_pop(1)
- end
-
- # Get the type of an instruction operand
- def get_opnd_type(opnd)
- case opnd
- in SelfOpnd
- self.self_type
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- # If outside of tracked range, do nothing
- if stack_idx >= MAX_TEMP_TYPES
- return Type::Unknown
- end
-
- mapping = self.temp_mapping[stack_idx]
-
- case mapping
- in MapToSelf
- self.self_type
- in MapToStack
- self.temp_types[self.stack_size - 1 - idx]
- in MapToLocal[idx]
- assert(idx < MAX_LOCAL_TYPES)
- self.local_types[idx]
- end
- end
- end
-
- # Get the currently tracked type for a local variable
- def get_local_type(idx)
- self.local_types[idx] || Type::Unknown
- end
-
- # Upgrade (or "learn") the type of an instruction operand
- # This value must be compatible and at least as specific as the previously known type.
- # If this value originated from self, or an lvar, the learned type will be
- # propagated back to its source.
- def upgrade_opnd_type(opnd, opnd_type)
- case opnd
- in SelfOpnd
- self.self_type = self.self_type.upgrade(opnd_type)
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- # If outside of tracked range, do nothing
- if stack_idx >= MAX_TEMP_TYPES
- return
- end
-
- mapping = self.temp_mapping[stack_idx]
-
- case mapping
- in MapToSelf
- self.self_type = self.self_type.upgrade(opnd_type)
- in MapToStack
- self.temp_types[stack_idx] = self.temp_types[stack_idx].upgrade(opnd_type)
- in MapToLocal[idx]
- assert(idx < MAX_LOCAL_TYPES)
- self.local_types[idx] = self.local_types[idx].upgrade(opnd_type)
- end
- end
- end
-
- # Get both the type and mapping (where the value originates) of an operand.
- # This is can be used with stack_push_mapping or set_opnd_mapping to copy
- # a stack value's type while maintaining the mapping.
- def get_opnd_mapping(opnd)
- opnd_type = self.get_opnd_type(opnd)
-
- case opnd
- in SelfOpnd
- return [MapToSelf, opnd_type]
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- if stack_idx < MAX_TEMP_TYPES
- return [self.temp_mapping[stack_idx], opnd_type]
- else
- # We can't know the source of this stack operand, so we assume it is
- # a stack-only temporary. type will be UNKNOWN
- assert(opnd_type == Type::Unknown)
- return [MapToStack, opnd_type]
- end
- end
- end
-
- # Overwrite both the type and mapping of a stack operand.
- def set_opnd_mapping(opnd, mapping_opnd_type)
- case opnd
- in SelfOpnd
- raise 'self always maps to self'
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- # If outside of tracked range, do nothing
- if stack_idx >= MAX_TEMP_TYPES
- return
- end
-
- mapping, opnd_type = mapping_opnd_type
- self.temp_mapping[stack_idx] = mapping
-
- # Only used when mapping == MAP_STACK
- self.temp_types[stack_idx] = opnd_type
- end
- end
-
- # Set the type of a local variable
- def set_local_type(local_idx, local_type)
- if local_idx >= MAX_LOCAL_TYPES
- return
- end
-
- # If any values on the stack map to this local we must detach them
- MAX_TEMP_TYPES.times do |stack_idx|
- case self.temp_mapping[stack_idx]
- in MapToStack
- # noop
- in MapToSelf
- # noop
- in MapToLocal[local_idx]
- if stack_idx == local_idx
- self.temp_types[stack_idx] = self.local_types[local_idx];
- self.temp_mapping[stack_idx] = MapToStack
- else
- # noop
- end
- end
- end
-
- self.local_types[local_idx] = local_type
- end
-
- # Erase local variable type information
- # eg: because of a call we can't track
- def clear_local_types
- # When clearing local types we must detach any stack mappings to those
- # locals. Even if local values may have changed, stack values will not.
- MAX_TEMP_TYPES.times do |stack_idx|
- case self.temp_mapping[stack_idx]
- in MapToStack
- # noop
- in MapToSelf
- # noop
- in MapToLocal[local_idx]
- self.temp_types[stack_idx] = self.local_types[local_idx]
- self.temp_mapping[stack_idx] = MapToStack
- end
- end
-
- # Clear the local types
- self.local_types = [Type::Unknown] * MAX_LOCAL_TYPES
- end
-
- # Compute a difference score for two context objects
- def diff(dst)
- # Self is the source context (at the end of the predecessor)
- src = self
-
- # Can only lookup the first version in the chain
- if dst.chain_depth != 0
- return TypeDiff::Incompatible
- end
-
- # Blocks with depth > 0 always produce new versions
- # Sidechains cannot overlap
- if src.chain_depth != 0
- return TypeDiff::Incompatible
- end
-
- if dst.stack_size != src.stack_size
- return TypeDiff::Incompatible
- end
-
- if dst.sp_offset != src.sp_offset
- return TypeDiff::Incompatible
- end
-
- # Difference sum
- diff = 0
-
- # Check the type of self
- diff += case src.self_type.diff(dst.self_type)
- in TypeDiff::Compatible[diff] then diff
- in TypeDiff::Incompatible then return TypeDiff::Incompatible
- end
-
- # For each local type we track
- src.local_types.size.times do |i|
- t_src = src.local_types[i]
- t_dst = dst.local_types[i]
- diff += case t_src.diff(t_dst)
- in TypeDiff::Compatible[diff] then diff
- in TypeDiff::Incompatible then return TypeDiff::Incompatible
- end
- end
-
- # For each value on the temp stack
- src.stack_size.times do |i|
- src_mapping, src_type = src.get_opnd_mapping(StackOpnd[i])
- dst_mapping, dst_type = dst.get_opnd_mapping(StackOpnd[i])
-
- # If the two mappings aren't the same
- if src_mapping != dst_mapping
- if dst_mapping == MapToStack
- # We can safely drop information about the source of the temp
- # stack operand.
- diff += 1
- else
- return TypeDiff::Incompatible
- end
- end
-
- diff += case src_type.diff(dst_type)
- in TypeDiff::Compatible[diff] then diff
- in TypeDiff::Incompatible then return TypeDiff::Incompatible
- end
- end
-
- return TypeDiff::Compatible[diff]
- end
-
- private
-
- def assert(cond)
- unless cond
- raise "'#{cond.inspect}' was not true"
- end
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/entry_stub.rb b/lib/ruby_vm/rjit/entry_stub.rb
deleted file mode 100644
index 9bcef14053..0000000000
--- a/lib/ruby_vm/rjit/entry_stub.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module RubyVM::RJIT
- class EntryStub < Struct.new(
- :start_addr, # @param [Integer] Stub source start address to be re-generated
- :end_addr, # @param [Integer] Stub source end address to be re-generated
- )
- end
-end
diff --git a/lib/ruby_vm/rjit/exit_compiler.rb b/lib/ruby_vm/rjit/exit_compiler.rb
deleted file mode 100644
index 1ced2141a4..0000000000
--- a/lib/ruby_vm/rjit/exit_compiler.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-module RubyVM::RJIT
- class ExitCompiler
- def initialize = freeze
-
- # Used for invalidating a block on entry.
- # @param pc [Integer]
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_entry_exit(pc, ctx, asm, cause:)
- # Fix pc/sp offsets for the interpreter
- save_pc_and_sp(pc, ctx, asm, reset_sp_offset: false)
-
- # Increment per-insn exit counter
- count_insn_exit(pc, asm)
-
- # Restore callee-saved registers
- asm.comment("#{cause}: entry exit")
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- asm.mov(C_RET, Qundef)
- asm.ret
- end
-
- # Set to cfp->jit_return by default for leave insn
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_leave_exit(asm)
- asm.comment('default cfp->jit_return')
-
- # Restore callee-saved registers
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- # :rax is written by #leave
- asm.ret
- end
-
- # Fire cfunc events on invalidation by TracePoint
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_full_cfunc_return(asm)
- # This chunk of code expects REG_EC to be filled properly and
- # RAX to contain the return value of the C method.
-
- asm.comment('full cfunc return')
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rjit_full_cfunc_return)
-
- # TODO: count the exit
-
- # Restore callee-saved registers
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- asm.mov(C_RET, Qundef)
- asm.ret
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_side_exit(pc, ctx, asm)
- # Fix pc/sp offsets for the interpreter
- save_pc_and_sp(pc, ctx.dup, asm) # dup to avoid sp_offset update
-
- # Increment per-insn exit counter
- count_insn_exit(pc, asm)
-
- # Restore callee-saved registers
- asm.comment("exit to interpreter on #{pc_to_insn(pc).name}")
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- asm.mov(C_RET, Qundef)
- asm.ret
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- # @param entry_stub [RubyVM::RJIT::EntryStub]
- def compile_entry_stub(asm, entry_stub)
- # Call rb_rjit_entry_stub_hit
- asm.comment('entry stub hit')
- asm.mov(C_ARGS[0], to_value(entry_stub))
- asm.call(C.rb_rjit_entry_stub_hit)
-
- # Jump to the address returned by rb_rjit_entry_stub_hit
- asm.jmp(:rax)
- end
-
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- # @param branch_stub [RubyVM::RJIT::BranchStub]
- # @param target0_p [TrueClass,FalseClass]
- def compile_branch_stub(ctx, asm, branch_stub, target0_p)
- # Call rb_rjit_branch_stub_hit
- iseq = branch_stub.iseq
- if C.rjit_opts.dump_disasm && C.imemo_type_p(iseq, C.imemo_iseq) # Guard against ISEQ GC at random moments
- asm.comment("branch stub hit: #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{iseq_lineno(iseq, target0_p ? branch_stub.target0.pc : branch_stub.target1.pc)}")
- end
- asm.mov(:rdi, to_value(branch_stub))
- asm.mov(:esi, ctx.sp_offset)
- asm.mov(:edx, target0_p ? 1 : 0)
- asm.call(C.rb_rjit_branch_stub_hit)
-
- # Jump to the address returned by rb_rjit_branch_stub_hit
- asm.jmp(:rax)
- end
-
- private
-
- def pc_to_insn(pc)
- Compiler.decode_insn(C.VALUE.new(pc).*)
- end
-
- # @param pc [Integer]
- # @param asm [RubyVM::RJIT::Assembler]
- def count_insn_exit(pc, asm)
- if C.rjit_opts.stats
- insn = Compiler.decode_insn(C.VALUE.new(pc).*)
- asm.comment("increment insn exit: #{insn.name}")
- asm.mov(:rax, (C.rjit_insn_exits + insn.bin).to_i)
- asm.add([:rax], 1) # TODO: lock
- end
- if C.rjit_opts.trace_exits
- asm.comment('rjit_record_exit_stack')
- asm.mov(C_ARGS[0], pc)
- asm.call(C.rjit_record_exit_stack)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def save_pc_and_sp(pc, ctx, asm, reset_sp_offset: true)
- # Update pc (TODO: manage PC offset?)
- asm.comment("save PC#{' and SP' if ctx.sp_offset != 0} to CFP")
- asm.mov(:rax, pc) # rax = jit.pc
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax
-
- # Update sp
- if ctx.sp_offset != 0
- asm.add(SP, C.VALUE.size * ctx.sp_offset) # sp += stack_size
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP) # cfp->sp = sp
- if reset_sp_offset
- ctx.sp_offset = 0
- end
- end
- end
-
- def to_value(obj)
- GC_REFS << obj
- C.to_value(obj)
- end
-
- def iseq_lineno(iseq, pc)
- C.rb_iseq_line_no(iseq, (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size)
- rescue RangeError # bignum too big to convert into `unsigned long long' (RangeError)
- -1
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/hooks.rb b/lib/ruby_vm/rjit/hooks.rb
deleted file mode 100644
index ea9d7bf5a8..0000000000
--- a/lib/ruby_vm/rjit/hooks.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-module RubyVM::RJIT
- module Hooks # :nodoc: all
- def self.on_bop_redefined(_redefined_flag, _bop)
- # C.rjit_cancel_all("BOP is redefined")
- end
-
- def self.on_cme_invalidate(cme)
- cme = C.rb_callable_method_entry_struct.new(cme)
- Invariants.on_cme_invalidate(cme)
- end
-
- def self.on_ractor_spawn
- # C.rjit_cancel_all("Ractor is spawned")
- end
-
- # Global constant changes like const_set
- def self.on_constant_state_changed(id)
- Invariants.on_constant_state_changed(id)
- end
-
- # ISEQ-specific constant invalidation
- def self.on_constant_ic_update(iseq, ic, insn_idx)
- iseq = C.rb_iseq_t.new(iseq)
- ic = C.IC.new(ic)
- Invariants.on_constant_ic_update(iseq, ic, insn_idx)
- end
-
- def self.on_tracing_invalidate_all(_new_iseq_events)
- Invariants.on_tracing_invalidate_all
- end
-
- def self.on_update_references
- Invariants.on_update_references
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb
deleted file mode 100644
index 74a982e898..0000000000
--- a/lib/ruby_vm/rjit/insn_compiler.rb
+++ /dev/null
@@ -1,5947 +0,0 @@
-module RubyVM::RJIT
- class InsnCompiler
- # struct rb_calling_info. Storing flags instead of ci.
- CallingInfo = Struct.new(:argc, :flags, :kwarg, :ci_addr, :send_shift, :block_handler) do
- def kw_splat = flags & C::VM_CALL_KW_SPLAT != 0
- end
-
- # @param ocb [CodeBlock]
- # @param exit_compiler [RubyVM::RJIT::ExitCompiler]
- def initialize(cb, ocb, exit_compiler)
- @ocb = ocb
- @exit_compiler = exit_compiler
-
- @cfunc_codegen_table = {}
- register_cfunc_codegen_funcs
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- # @param insn `RubyVM::RJIT::Instruction`
- def compile(jit, ctx, asm, insn)
- asm.incr_counter(:rjit_insns_count)
-
- stack = ctx.stack_size.times.map do |stack_idx|
- ctx.get_opnd_type(StackOpnd[ctx.stack_size - stack_idx - 1]).type
- end
- locals = jit.iseq.body.local_table_size.times.map do |local_idx|
- (ctx.local_types[local_idx] || Type::Unknown).type
- end
-
- insn_idx = format('%04d', (jit.pc.to_i - jit.iseq.body.iseq_encoded.to_i) / C.VALUE.size)
- asm.comment("Insn: #{insn_idx} #{insn.name} (stack: [#{stack.join(', ')}], locals: [#{locals.join(', ')}])")
-
- # 83/102
- case insn.name
- when :nop then nop(jit, ctx, asm)
- when :getlocal then getlocal(jit, ctx, asm)
- when :setlocal then setlocal(jit, ctx, asm)
- when :getblockparam then getblockparam(jit, ctx, asm)
- # setblockparam
- when :getblockparamproxy then getblockparamproxy(jit, ctx, asm)
- when :getspecial then getspecial(jit, ctx, asm)
- # setspecial
- when :getinstancevariable then getinstancevariable(jit, ctx, asm)
- when :setinstancevariable then setinstancevariable(jit, ctx, asm)
- when :getclassvariable then getclassvariable(jit, ctx, asm)
- when :setclassvariable then setclassvariable(jit, ctx, asm)
- when :opt_getconstant_path then opt_getconstant_path(jit, ctx, asm)
- when :getconstant then getconstant(jit, ctx, asm)
- # setconstant
- when :getglobal then getglobal(jit, ctx, asm)
- # setglobal
- when :putnil then putnil(jit, ctx, asm)
- when :putself then putself(jit, ctx, asm)
- when :putobject then putobject(jit, ctx, asm)
- when :putspecialobject then putspecialobject(jit, ctx, asm)
- when :putstring then putstring(jit, ctx, asm)
- when :concatstrings then concatstrings(jit, ctx, asm)
- when :anytostring then anytostring(jit, ctx, asm)
- when :toregexp then toregexp(jit, ctx, asm)
- when :intern then intern(jit, ctx, asm)
- when :newarray then newarray(jit, ctx, asm)
- # newarraykwsplat
- when :duparray then duparray(jit, ctx, asm)
- # duphash
- when :expandarray then expandarray(jit, ctx, asm)
- when :concatarray then concatarray(jit, ctx, asm)
- when :splatarray then splatarray(jit, ctx, asm)
- when :newhash then newhash(jit, ctx, asm)
- when :newrange then newrange(jit, ctx, asm)
- when :pop then pop(jit, ctx, asm)
- when :dup then dup(jit, ctx, asm)
- when :dupn then dupn(jit, ctx, asm)
- when :swap then swap(jit, ctx, asm)
- # opt_reverse
- when :topn then topn(jit, ctx, asm)
- when :setn then setn(jit, ctx, asm)
- when :adjuststack then adjuststack(jit, ctx, asm)
- when :defined then defined(jit, ctx, asm)
- when :definedivar then definedivar(jit, ctx, asm)
- # checkmatch
- when :checkkeyword then checkkeyword(jit, ctx, asm)
- # checktype
- # defineclass
- # definemethod
- # definesmethod
- when :send then send(jit, ctx, asm)
- when :opt_send_without_block then opt_send_without_block(jit, ctx, asm)
- when :objtostring then objtostring(jit, ctx, asm)
- when :opt_str_freeze then opt_str_freeze(jit, ctx, asm)
- when :opt_nil_p then opt_nil_p(jit, ctx, asm)
- # opt_str_uminus
- when :opt_newarray_send then opt_newarray_send(jit, ctx, asm)
- when :invokesuper then invokesuper(jit, ctx, asm)
- when :invokeblock then invokeblock(jit, ctx, asm)
- when :leave then leave(jit, ctx, asm)
- when :throw then throw(jit, ctx, asm)
- when :jump then jump(jit, ctx, asm)
- when :branchif then branchif(jit, ctx, asm)
- when :branchunless then branchunless(jit, ctx, asm)
- when :branchnil then branchnil(jit, ctx, asm)
- # once
- when :opt_case_dispatch then opt_case_dispatch(jit, ctx, asm)
- when :opt_plus then opt_plus(jit, ctx, asm)
- when :opt_minus then opt_minus(jit, ctx, asm)
- when :opt_mult then opt_mult(jit, ctx, asm)
- when :opt_div then opt_div(jit, ctx, asm)
- when :opt_mod then opt_mod(jit, ctx, asm)
- when :opt_eq then opt_eq(jit, ctx, asm)
- when :opt_neq then opt_neq(jit, ctx, asm)
- when :opt_lt then opt_lt(jit, ctx, asm)
- when :opt_le then opt_le(jit, ctx, asm)
- when :opt_gt then opt_gt(jit, ctx, asm)
- when :opt_ge then opt_ge(jit, ctx, asm)
- when :opt_ltlt then opt_ltlt(jit, ctx, asm)
- when :opt_and then opt_and(jit, ctx, asm)
- when :opt_or then opt_or(jit, ctx, asm)
- when :opt_aref then opt_aref(jit, ctx, asm)
- when :opt_aset then opt_aset(jit, ctx, asm)
- # opt_aset_with
- # opt_aref_with
- when :opt_length then opt_length(jit, ctx, asm)
- when :opt_size then opt_size(jit, ctx, asm)
- when :opt_empty_p then opt_empty_p(jit, ctx, asm)
- when :opt_succ then opt_succ(jit, ctx, asm)
- when :opt_not then opt_not(jit, ctx, asm)
- when :opt_regexpmatch2 then opt_regexpmatch2(jit, ctx, asm)
- # invokebuiltin
- when :opt_invokebuiltin_delegate then opt_invokebuiltin_delegate(jit, ctx, asm)
- when :opt_invokebuiltin_delegate_leave then opt_invokebuiltin_delegate_leave(jit, ctx, asm)
- when :getlocal_WC_0 then getlocal_WC_0(jit, ctx, asm)
- when :getlocal_WC_1 then getlocal_WC_1(jit, ctx, asm)
- when :setlocal_WC_0 then setlocal_WC_0(jit, ctx, asm)
- when :setlocal_WC_1 then setlocal_WC_1(jit, ctx, asm)
- when :putobject_INT2FIX_0_ then putobject_INT2FIX_0_(jit, ctx, asm)
- when :putobject_INT2FIX_1_ then putobject_INT2FIX_1_(jit, ctx, asm)
- else CantCompile
- end
- end
-
- private
-
- #
- # Insns
- #
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def nop(jit, ctx, asm)
- # Do nothing
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getlocal(jit, ctx, asm)
- idx = jit.operand(0)
- level = jit.operand(1)
- jit_getlocal_generic(jit, ctx, asm, idx:, level:)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getlocal_WC_0(jit, ctx, asm)
- idx = jit.operand(0)
- jit_getlocal_generic(jit, ctx, asm, idx:, level: 0)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getlocal_WC_1(jit, ctx, asm)
- idx = jit.operand(0)
- jit_getlocal_generic(jit, ctx, asm, idx:, level: 1)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setlocal(jit, ctx, asm)
- idx = jit.operand(0)
- level = jit.operand(1)
- jit_setlocal_generic(jit, ctx, asm, idx:, level:)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setlocal_WC_0(jit, ctx, asm)
- idx = jit.operand(0)
- jit_setlocal_generic(jit, ctx, asm, idx:, level: 0)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setlocal_WC_1(jit, ctx, asm)
- idx = jit.operand(0)
- jit_setlocal_generic(jit, ctx, asm, idx:, level: 1)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getblockparam(jit, ctx, asm)
- # EP level
- level = jit.operand(1)
-
- # Save the PC and SP because we might allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- # A mirror of the interpreter code. Checking for the case
- # where it's pushing rb_block_param_proxy.
- side_exit = side_exit(jit, ctx)
-
- # Load environment pointer EP from CFP
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero
- # FIXME: This is testing bits in the same place that the WB check is testing.
- # We should combine these at some point
- asm.test([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)
-
- # If the frame flag has been modified, then the actual proc value is
- # already in the EP and we should just use the value.
- frame_flag_modified = asm.new_label('frame_flag_modified')
- asm.jnz(frame_flag_modified)
-
- # This instruction writes the block handler to the EP. If we need to
- # fire a write barrier for the write, then exit (we'll let the
- # interpreter handle it so it can fire the write barrier).
- # flags & VM_ENV_FLAG_WB_REQUIRED
- asm.test([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], C::VM_ENV_FLAG_WB_REQUIRED)
-
- # if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
- asm.jnz(side_exit)
-
- # Convert the block handler in to a proc
- # call rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler)
- asm.mov(C_ARGS[0], EC)
- # The block handler for the current frame
- # note, VM_ASSERT(VM_ENV_LOCAL_P(ep))
- asm.mov(C_ARGS[1], [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL])
- asm.call(C.rb_vm_bh_to_procval)
-
- # Load environment pointer EP from CFP (again)
- ep_reg = :rcx
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Write the value at the environment pointer
- idx = jit.operand(0)
- offs = -(C.VALUE.size * idx)
- asm.mov([ep_reg, offs], C_RET);
-
- # Set the frame modified flag
- asm.mov(:rax, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS]) # flag_check
- asm.or(:rax, C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) # modified_flag
- asm.mov([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], :rax)
-
- asm.write_label(frame_flag_modified)
-
- # Push the proc on the stack
- stack_ret = ctx.stack_push(Type::Unknown)
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
- asm.mov(:rax, [ep_reg, offs])
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # setblockparam
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getblockparamproxy(jit, ctx, asm)
- # To get block_handler
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- starting_context = ctx.dup # make a copy for use with jit_chain_guard
-
- # A mirror of the interpreter code. Checking for the case
- # where it's pushing rb_block_param_proxy.
- side_exit = side_exit(jit, ctx)
-
- # EP level
- level = jit.operand(1)
-
- # Peek at the block handler so we can check whether it's nil
- comptime_handler = jit.peek_at_block_handler(level)
-
- # When a block handler is present, it should always be a GC-guarded
- # pointer (VM_BH_ISEQ_BLOCK_P)
- if comptime_handler != 0 && comptime_handler & 0x3 != 0x1
- asm.incr_counter(:getblockpp_not_gc_guarded)
- return CantCompile
- end
-
- # Load environment pointer EP from CFP
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero
- asm.test([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)
- asm.jnz(counted_exit(side_exit, :getblockpp_block_param_modified))
-
- # Load the block handler for the current frame
- # note, VM_ASSERT(VM_ENV_LOCAL_P(ep))
- block_handler = :rax
- asm.mov(block_handler, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL])
-
- # Specialize compilation for the case where no block handler is present
- if comptime_handler == 0
- # Bail if there is a block handler
- asm.cmp(block_handler, 0)
-
- jit_chain_guard(:jnz, jit, starting_context, asm, counted_exit(side_exit, :getblockpp_block_handler_none))
-
- putobject(jit, ctx, asm, val: Qnil)
- else
- # Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P().
- asm.and(block_handler, 0x3)
-
- # Bail unless VM_BH_ISEQ_BLOCK_P(bh). This also checks for null.
- asm.cmp(block_handler, 0x1)
-
- jit_chain_guard(:jnz, jit, starting_context, asm, counted_exit(side_exit, :getblockpp_not_iseq_block))
-
- # Push rb_block_param_proxy. It's a root, so no need to use jit_mov_gc_ptr.
- top = ctx.stack_push(Type::BlockParamProxy)
- asm.mov(:rax, C.rb_block_param_proxy)
- asm.mov(top, :rax)
- end
-
- jump_to_next_insn(jit, ctx, asm)
-
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getspecial(jit, ctx, asm)
- # This takes two arguments, key and type
- # key is only used when type == 0
- # A non-zero type determines which type of backref to fetch
- #rb_num_t key = jit.jit_get_arg(0);
- rtype = jit.operand(1)
-
- if rtype == 0
- # not yet implemented
- return CantCompile;
- elsif rtype & 0x01 != 0
- # Fetch a "special" backref based on a char encoded by shifting by 1
-
- # Can raise if matchdata uninitialized
- jit_prepare_routine_call(jit, ctx, asm)
-
- # call rb_backref_get()
- asm.comment('rb_backref_get')
- asm.call(C.rb_backref_get)
-
- asm.mov(C_ARGS[0], C_RET) # backref
- case [rtype >> 1].pack('c')
- in ?&
- asm.comment("rb_reg_last_match")
- asm.call(C.rb_reg_last_match)
- in ?`
- asm.comment("rb_reg_match_pre")
- asm.call(C.rb_reg_match_pre)
- in ?'
- asm.comment("rb_reg_match_post")
- asm.call(C.rb_reg_match_post)
- in ?+
- asm.comment("rb_reg_match_last")
- asm.call(C.rb_reg_match_last)
- end
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- else
- # Fetch the N-th match from the last backref based on type shifted by 1
-
- # Can raise if matchdata uninitialized
- jit_prepare_routine_call(jit, ctx, asm)
-
- # call rb_backref_get()
- asm.comment('rb_backref_get')
- asm.call(C.rb_backref_get)
-
- # rb_reg_nth_match((int)(type >> 1), backref);
- asm.comment('rb_reg_nth_match')
- asm.mov(C_ARGS[0], rtype >> 1)
- asm.mov(C_ARGS[1], C_RET) # backref
- asm.call(C.rb_reg_nth_match)
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
- end
-
- # setspecial
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getinstancevariable(jit, ctx, asm)
- # Specialize on a compile-time receiver, and split a block for chain guards
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- id = jit.operand(0)
- comptime_obj = jit.peek_at_self
-
- jit_getivar(jit, ctx, asm, comptime_obj, id, nil, SelfOpnd)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setinstancevariable(jit, ctx, asm)
- starting_context = ctx.dup # make a copy for use with jit_chain_guard
-
- # Defer compilation so we can specialize on a runtime `self`
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- ivar_name = jit.operand(0)
- comptime_receiver = jit.peek_at_self
-
- # If the comptime receiver is frozen, writing an IV will raise an exception
- # and we don't want to JIT code to deal with that situation.
- if C.rb_obj_frozen_p(comptime_receiver)
- asm.incr_counter(:setivar_frozen)
- return CantCompile
- end
-
- # Check if the comptime receiver is a T_OBJECT
- receiver_t_object = C::BUILTIN_TYPE(comptime_receiver) == C::T_OBJECT
-
- # If the receiver isn't a T_OBJECT, or uses a custom allocator,
- # then just write out the IV write as a function call.
- # too-complex shapes can't use index access, so we use rb_ivar_get for them too.
- if !receiver_t_object || shape_too_complex?(comptime_receiver) || ctx.chain_depth >= 10
- asm.comment('call rb_vm_setinstancevariable')
-
- ic = jit.operand(1)
-
- # The function could raise exceptions.
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- val_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_setinstancevariable(iseq, obj, id, val, ic);
- asm.mov(:rdi, jit.iseq.to_i)
- asm.mov(:rsi, [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(:rdx, ivar_name)
- asm.mov(:rcx, val_opnd)
- asm.mov(:r8, ic)
- asm.call(C.rb_vm_setinstancevariable)
- else
- # Get the iv index
- shape_id = C.rb_shape_get_shape_id(comptime_receiver)
- ivar_index = C.rb_shape_get_iv_index(shape_id, ivar_name)
-
- # Get the receiver
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
-
- # Generate a side exit
- side_exit = side_exit(jit, ctx)
-
- # Upgrade type
- guard_object_is_heap(jit, ctx, asm, :rax, SelfOpnd, :setivar_not_heap)
-
- asm.comment('guard shape')
- asm.cmp(DwordPtr[:rax, C.rb_shape_id_offset], shape_id)
- megamorphic_side_exit = counted_exit(side_exit, :setivar_megamorphic)
- jit_chain_guard(:jne, jit, starting_context, asm, megamorphic_side_exit)
-
- # If we don't have an instance variable index, then we need to
- # transition out of the current shape.
- if ivar_index.nil?
- shape = C.rb_shape_get_shape_by_id(shape_id)
-
- current_capacity = shape.capacity
- dest_shape = C.rb_shape_get_next(shape, comptime_receiver, ivar_name)
- new_shape_id = C.rb_shape_id(dest_shape)
-
- if new_shape_id == C::OBJ_TOO_COMPLEX_SHAPE_ID
- asm.incr_counter(:setivar_too_complex)
- return CantCompile
- end
-
- ivar_index = shape.next_iv_index
-
- # If the new shape has a different capacity, we need to
- # reallocate the object.
- needs_extension = dest_shape.capacity != shape.capacity
-
- if needs_extension
- # Generate the C call so that runtime code will increase
- # the capacity and set the buffer.
- asm.mov(C_ARGS[0], :rax)
- asm.mov(C_ARGS[1], current_capacity)
- asm.mov(C_ARGS[2], dest_shape.capacity)
- asm.call(C.rb_ensure_iv_list_size)
-
- # Load the receiver again after the function call
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
- end
-
- write_val = ctx.stack_pop(1)
- jit_write_iv(asm, comptime_receiver, :rax, :rcx, ivar_index, write_val, needs_extension)
-
- # Store the new shape
- asm.comment('write shape')
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) # reload after jit_write_iv
- asm.mov(DwordPtr[:rax, C.rb_shape_id_offset], new_shape_id)
- else
- # If the iv index already exists, then we don't need to
- # transition to a new shape. The reason is because we find
- # the iv index by searching up the shape tree. If we've
- # made the transition already, then there's no reason to
- # update the shape on the object. Just set the IV.
- write_val = ctx.stack_pop(1)
- jit_write_iv(asm, comptime_receiver, :rax, :rcx, ivar_index, write_val, false)
- end
-
- skip_wb = asm.new_label('skip_wb')
- # If the value we're writing is an immediate, we don't need to WB
- asm.test(write_val, C::RUBY_IMMEDIATE_MASK)
- asm.jnz(skip_wb)
-
- # If the value we're writing is nil or false, we don't need to WB
- asm.cmp(write_val, Qnil)
- asm.jbe(skip_wb)
-
- asm.comment('write barrier')
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:self)]) # reload after jit_write_iv
- asm.mov(C_ARGS[1], write_val)
- asm.call(C.rb_gc_writebarrier)
-
- asm.write_label(skip_wb)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getclassvariable(jit, ctx, asm)
- # rb_vm_getclassvariable can raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:iseq)])
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], jit.operand(0))
- asm.mov(C_ARGS[3], jit.operand(1))
- asm.call(C.rb_vm_getclassvariable)
-
- top = ctx.stack_push(Type::Unknown)
- asm.mov(top, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setclassvariable(jit, ctx, asm)
- # rb_vm_setclassvariable can raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:iseq)])
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], jit.operand(0))
- asm.mov(C_ARGS[3], ctx.stack_pop(1))
- asm.mov(C_ARGS[4], jit.operand(1))
- asm.call(C.rb_vm_setclassvariable)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_getconstant_path(jit, ctx, asm)
- # Cut the block for invalidation
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- ic = C.iseq_inline_constant_cache.new(jit.operand(0))
- idlist = ic.segments
-
- # Make sure there is an exit for this block as the interpreter might want
- # to invalidate this block from rb_rjit_constant_ic_update().
- # For now, we always take an entry exit even if it was a side exit.
- Invariants.ensure_block_entry_exit(jit, cause: 'opt_getconstant_path')
-
- # See vm_ic_hit_p(). The same conditions are checked in yjit_constant_ic_update().
- ice = ic.entry
- if ice.nil?
- # In this case, leave a block that unconditionally side exits
- # for the interpreter to invalidate.
- asm.incr_counter(:optgetconst_not_cached)
- return CantCompile
- end
-
- if ice.ic_cref # with cref
- # Cache is keyed on a certain lexical scope. Use the interpreter's cache.
- side_exit = side_exit(jit, ctx)
-
- # Call function to verify the cache. It doesn't allocate or call methods.
- asm.mov(C_ARGS[0], ic.to_i)
- asm.mov(C_ARGS[1], [CFP, C.rb_control_frame_t.offsetof(:ep)])
- asm.call(C.rb_vm_ic_hit_p)
-
- # Check the result. SysV only specifies one byte for _Bool return values,
- # so it's important we only check one bit to ignore the higher bits in the register.
- asm.test(C_RET, 1)
- asm.jz(counted_exit(side_exit, :optgetconst_cache_miss))
-
- asm.mov(:rax, ic.to_i) # inline_cache
- asm.mov(:rax, [:rax, C.iseq_inline_constant_cache.offsetof(:entry)]) # ic_entry
- asm.mov(:rax, [:rax, C.iseq_inline_constant_cache_entry.offsetof(:value)]) # ic_entry_val
-
- # Push ic->entry->value
- stack_top = ctx.stack_push(Type::Unknown)
- asm.mov(stack_top, :rax)
- else # without cref
- # TODO: implement this
- # Optimize for single ractor mode.
- # if !assume_single_ractor_mode(jit, ocb)
- # return CantCompile
- # end
-
- # Invalidate output code on any constant writes associated with
- # constants referenced within the current block.
- Invariants.assume_stable_constant_names(jit, idlist)
-
- putobject(jit, ctx, asm, val: ice.value)
- end
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getconstant(jit, ctx, asm)
- id = jit.operand(0)
-
- # vm_get_ev_const can raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm)
-
- allow_nil_opnd = ctx.stack_pop(1)
- klass_opnd = ctx.stack_pop(1)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], klass_opnd)
- asm.mov(C_ARGS[2], id)
- asm.mov(C_ARGS[3], allow_nil_opnd)
- asm.call(C.rb_vm_get_ev_const)
-
- top = ctx.stack_push(Type::Unknown)
- asm.mov(top, C_RET)
-
- KeepCompiling
- end
-
- # setconstant
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getglobal(jit, ctx, asm)
- gid = jit.operand(0)
-
- # Save the PC and SP because we might make a Ruby call for warning
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], gid)
- asm.call(C.rb_gvar_get)
-
- top = ctx.stack_push(Type::Unknown)
- asm.mov(top, C_RET)
-
- KeepCompiling
- end
-
- # setglobal
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putnil(jit, ctx, asm)
- putobject(jit, ctx, asm, val: Qnil)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putself(jit, ctx, asm)
- stack_top = ctx.stack_push_self
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(stack_top, :rax)
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putobject(jit, ctx, asm, val: jit.operand(0))
- # Push it to the stack
- val_type = Type.from(C.to_ruby(val))
- stack_top = ctx.stack_push(val_type)
- if asm.imm32?(val)
- asm.mov(stack_top, val)
- else # 64-bit immediates can't be directly written to memory
- asm.mov(:rax, val)
- asm.mov(stack_top, :rax)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putspecialobject(jit, ctx, asm)
- object_type = jit.operand(0)
- if object_type == C::VM_SPECIAL_OBJECT_VMCORE
- stack_top = ctx.stack_push(Type::UnknownHeap)
- asm.mov(:rax, C.rb_mRubyVMFrozenCore)
- asm.mov(stack_top, :rax)
- KeepCompiling
- else
- # TODO: implement for VM_SPECIAL_OBJECT_CBASE and
- # VM_SPECIAL_OBJECT_CONST_BASE
- CantCompile
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putstring(jit, ctx, asm)
- put_val = jit.operand(0, ruby: true)
-
- # Save the PC and SP because the callee will allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], to_value(put_val))
- asm.call(C.rb_ec_str_resurrect)
-
- stack_top = ctx.stack_push(Type::TString)
- asm.mov(stack_top, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def concatstrings(jit, ctx, asm)
- n = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.lea(:rax, ctx.sp_opnd(-C.VALUE.size * n))
-
- # call rb_str_concat_literals(size_t n, const VALUE *strings);
- asm.mov(C_ARGS[0], n)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rb_str_concat_literals)
-
- ctx.stack_pop(n)
- stack_ret = ctx.stack_push(Type::TString)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def anytostring(jit, ctx, asm)
- # Save the PC and SP since we might call #to_s
- jit_prepare_routine_call(jit, ctx, asm)
-
- str = ctx.stack_pop(1)
- val = ctx.stack_pop(1)
-
- asm.mov(C_ARGS[0], str)
- asm.mov(C_ARGS[1], val)
- asm.call(C.rb_obj_as_string_result)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::TString)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def toregexp(jit, ctx, asm)
- opt = jit.operand(0, signed: true)
- cnt = jit.operand(1)
-
- # Save the PC and SP because this allocates an object and could
- # raise an exception.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.lea(:rax, ctx.sp_opnd(-C.VALUE.size * cnt)) # values_ptr
- ctx.stack_pop(cnt)
-
- asm.mov(C_ARGS[0], 0)
- asm.mov(C_ARGS[1], cnt)
- asm.mov(C_ARGS[2], :rax) # values_ptr
- asm.call(C.rb_ary_tmp_new_from_values)
-
- # Save the array so we can clear it later
- asm.push(C_RET)
- asm.push(C_RET) # Alignment
-
- asm.mov(C_ARGS[0], C_RET)
- asm.mov(C_ARGS[1], opt)
- asm.call(C.rb_reg_new_ary)
-
- # The actual regex is in RAX now. Pop the temp array from
- # rb_ary_tmp_new_from_values into C arg regs so we can clear it
- asm.pop(:rcx) # Alignment
- asm.pop(:rcx) # ary
-
- # The value we want to push on the stack is in RAX right now
- stack_ret = ctx.stack_push(Type::UnknownHeap)
- asm.mov(stack_ret, C_RET)
-
- # Clear the temp array.
- asm.mov(C_ARGS[0], :rcx) # ary
- asm.call(C.rb_ary_clear)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def intern(jit, ctx, asm)
- # Save the PC and SP because we might allocate
- jit_prepare_routine_call(jit, ctx, asm);
-
- str = ctx.stack_pop(1)
- asm.mov(C_ARGS[0], str)
- asm.call(C.rb_str_intern)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def newarray(jit, ctx, asm)
- n = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- # If n is 0, then elts is never going to be read, so we can just pass null
- if n == 0
- values_ptr = 0
- else
- asm.comment('load pointer to array elts')
- offset_magnitude = C.VALUE.size * n
- values_opnd = ctx.sp_opnd(-(offset_magnitude))
- asm.lea(:rax, values_opnd)
- values_ptr = :rax
- end
-
- # call rb_ec_ary_new_from_values(struct rb_execution_context_struct *ec, long n, const VALUE *elts);
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], n)
- asm.mov(C_ARGS[2], values_ptr)
- asm.call(C.rb_ec_ary_new_from_values)
-
- ctx.stack_pop(n)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # newarraykwsplat
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def duparray(jit, ctx, asm)
- ary = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- # call rb_ary_resurrect(VALUE ary);
- asm.comment('call rb_ary_resurrect')
- asm.mov(C_ARGS[0], ary)
- asm.call(C.rb_ary_resurrect)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # duphash
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def expandarray(jit, ctx, asm)
- # Both arguments are rb_num_t which is unsigned
- num = jit.operand(0)
- flag = jit.operand(1)
-
- # If this instruction has the splat flag, then bail out.
- if flag & 0x01 != 0
- asm.incr_counter(:expandarray_splat)
- return CantCompile
- end
-
- # If this instruction has the postarg flag, then bail out.
- if flag & 0x02 != 0
- asm.incr_counter(:expandarray_postarg)
- return CantCompile
- end
-
- side_exit = side_exit(jit, ctx)
-
- array_opnd = ctx.stack_opnd(0)
- array_stack_opnd = StackOpnd[0]
-
- # num is the number of requested values. If there aren't enough in the
- # array then we're going to push on nils.
- if ctx.get_opnd_type(array_stack_opnd) == Type::Nil
- ctx.stack_pop(1) # pop after using the type info
- # special case for a, b = nil pattern
- # push N nils onto the stack
- num.times do
- push_opnd = ctx.stack_push(Type::Nil)
- asm.mov(push_opnd, Qnil)
- end
- return KeepCompiling
- end
-
- # Move the array from the stack and check that it's an array.
- asm.mov(:rax, array_opnd)
- guard_object_is_array(jit, ctx, asm, :rax, :rcx, array_stack_opnd, :expandarray_not_array)
- ctx.stack_pop(1) # pop after using the type info
-
- # If we don't actually want any values, then just return.
- if num == 0
- return KeepCompiling
- end
-
- jit_array_len(asm, :rax, :rcx)
-
- # Only handle the case where the number of values in the array is greater
- # than or equal to the number of values requested.
- asm.cmp(:rcx, num)
- asm.jl(counted_exit(side_exit, :expandarray_rhs_too_small))
-
- # Conditionally load the address of the heap array into REG1.
- # (struct RArray *)(obj)->as.heap.ptr
- #asm.mov(:rax, array_opnd)
- asm.mov(:rcx, [:rax, C.RBasic.offsetof(:flags)])
- asm.test(:rcx, C::RARRAY_EMBED_FLAG);
- asm.mov(:rcx, [:rax, C.RArray.offsetof(:as, :heap, :ptr)])
-
- # Load the address of the embedded array into REG1.
- # (struct RArray *)(obj)->as.ary
- asm.lea(:rax, [:rax, C.RArray.offsetof(:as, :ary)])
-
- asm.cmovnz(:rcx, :rax)
-
- # Loop backward through the array and push each element onto the stack.
- (num - 1).downto(0).each do |i|
- top = ctx.stack_push(Type::Unknown)
- asm.mov(:rax, [:rcx, i * C.VALUE.size])
- asm.mov(top, :rax)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def concatarray(jit, ctx, asm)
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- ary2st_opnd = ctx.stack_pop(1)
- ary1_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_concat_array(ary1, ary2st)
- asm.mov(C_ARGS[0], ary1_opnd)
- asm.mov(C_ARGS[1], ary2st_opnd)
- asm.call(C.rb_vm_concat_array)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def splatarray(jit, ctx, asm)
- flag = jit.operand(0)
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- ary_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_splat_array(flag, ary)
- asm.mov(C_ARGS[0], flag)
- asm.mov(C_ARGS[1], ary_opnd)
- asm.call(C.rb_vm_splat_array)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def newhash(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- if num != 0
- # val = rb_hash_new_with_size(num / 2);
- asm.mov(C_ARGS[0], num / 2)
- asm.call(C.rb_hash_new_with_size)
-
- # Save the allocated hash as we want to push it after insertion
- asm.push(C_RET)
- asm.push(C_RET) # x86 alignment
-
- # Get a pointer to the values to insert into the hash
- asm.lea(:rcx, ctx.stack_opnd(num - 1))
-
- # rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
- asm.mov(C_ARGS[0], num)
- asm.mov(C_ARGS[1], :rcx)
- asm.mov(C_ARGS[2], C_RET)
- asm.call(C.rb_hash_bulk_insert)
-
- asm.pop(:rax)
- asm.pop(:rax)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Hash)
- asm.mov(stack_ret, :rax)
- else
- # val = rb_hash_new();
- asm.call(C.rb_hash_new)
- stack_ret = ctx.stack_push(Type::Hash)
- asm.mov(stack_ret, C_RET)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def newrange(jit, ctx, asm)
- flag = jit.operand(0)
-
- # rb_range_new() allocates and can raise
- jit_prepare_routine_call(jit, ctx, asm)
-
- # val = rb_range_new(low, high, (int)flag);
- asm.mov(C_ARGS[0], ctx.stack_opnd(1))
- asm.mov(C_ARGS[1], ctx.stack_opnd(0))
- asm.mov(C_ARGS[2], flag)
- asm.call(C.rb_range_new)
-
- ctx.stack_pop(2)
- stack_ret = ctx.stack_push(Type::UnknownHeap)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def pop(jit, ctx, asm)
- ctx.stack_pop
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def dup(jit, ctx, asm)
- dup_val = ctx.stack_opnd(0)
- mapping, tmp_type = ctx.get_opnd_mapping(StackOpnd[0])
-
- loc0 = ctx.stack_push_mapping([mapping, tmp_type])
- asm.mov(:rax, dup_val)
- asm.mov(loc0, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def dupn(jit, ctx, asm)
- n = jit.operand(0)
-
- # In practice, seems to be only used for n==2
- if n != 2
- return CantCompile
- end
-
- opnd1 = ctx.stack_opnd(1)
- opnd0 = ctx.stack_opnd(0)
-
- mapping1 = ctx.get_opnd_mapping(StackOpnd[1])
- mapping0 = ctx.get_opnd_mapping(StackOpnd[0])
-
- dst1 = ctx.stack_push_mapping(mapping1)
- asm.mov(:rax, opnd1)
- asm.mov(dst1, :rax)
-
- dst0 = ctx.stack_push_mapping(mapping0)
- asm.mov(:rax, opnd0)
- asm.mov(dst0, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def swap(jit, ctx, asm)
- stack_swap(jit, ctx, asm, 0, 1)
- KeepCompiling
- end
-
- # opt_reverse
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def topn(jit, ctx, asm)
- n = jit.operand(0)
-
- top_n_val = ctx.stack_opnd(n)
- mapping = ctx.get_opnd_mapping(StackOpnd[n])
- loc0 = ctx.stack_push_mapping(mapping)
- asm.mov(:rax, top_n_val)
- asm.mov(loc0, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setn(jit, ctx, asm)
- n = jit.operand(0)
-
- top_val = ctx.stack_pop(0)
- dst_opnd = ctx.stack_opnd(n)
- asm.mov(:rax, top_val)
- asm.mov(dst_opnd, :rax)
-
- mapping = ctx.get_opnd_mapping(StackOpnd[0])
- ctx.set_opnd_mapping(StackOpnd[n], mapping)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def adjuststack(jit, ctx, asm)
- n = jit.operand(0)
- ctx.stack_pop(n)
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def defined(jit, ctx, asm)
- op_type = jit.operand(0)
- obj = jit.operand(1, ruby: true)
- pushval = jit.operand(2, ruby: true)
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- v_opnd = ctx.stack_pop(1)
-
- # Call vm_defined(ec, reg_cfp, op_type, obj, v)
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], op_type)
- asm.mov(C_ARGS[3], to_value(obj))
- asm.mov(C_ARGS[4], v_opnd)
- asm.call(C.rb_vm_defined)
-
- asm.test(C_RET, 255)
- asm.mov(:rax, Qnil)
- asm.mov(:rcx, to_value(pushval))
- asm.cmovnz(:rax, :rcx)
-
- # Push the return value onto the stack
- out_type = if C::SPECIAL_CONST_P(pushval)
- Type::UnknownImm
- else
- Type::Unknown
- end
- stack_ret = ctx.stack_push(out_type)
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def definedivar(jit, ctx, asm)
- # Defer compilation so we can specialize base on a runtime receiver
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- ivar_name = jit.operand(0)
- # Value that will be pushed on the stack if the ivar is defined. In practice this is always the
- # string "instance-variable". If the ivar is not defined, nil will be pushed instead.
- pushval = jit.operand(2, ruby: true)
-
- # Get the receiver
- recv = :rcx
- asm.mov(recv, [CFP, C.rb_control_frame_t.offsetof(:self)])
-
- # Specialize base on compile time values
- comptime_receiver = jit.peek_at_self
-
- if shape_too_complex?(comptime_receiver)
- # Fall back to calling rb_ivar_defined
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm) # clobbers :rax
-
- # Call rb_ivar_defined(recv, ivar_name)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], ivar_name)
- asm.call(C.rb_ivar_defined)
-
- # if (rb_ivar_defined(recv, ivar_name)) {
- # val = pushval;
- # }
- asm.test(C_RET, 255)
- asm.mov(:rax, Qnil)
- asm.mov(:rcx, to_value(pushval))
- asm.cmovnz(:rax, :rcx)
-
- # Push the return value onto the stack
- out_type = C::SPECIAL_CONST_P(pushval) ? Type::UnknownImm : Type::Unknown
- stack_ret = ctx.stack_push(out_type)
- asm.mov(stack_ret, :rax)
-
- return KeepCompiling
- end
-
- shape_id = C.rb_shape_get_shape_id(comptime_receiver)
- ivar_exists = C.rb_shape_get_iv_index(shape_id, ivar_name)
-
- side_exit = side_exit(jit, ctx)
-
- # Guard heap object (recv_opnd must be used before stack_pop)
- guard_object_is_heap(jit, ctx, asm, recv, SelfOpnd)
-
- shape_opnd = DwordPtr[recv, C.rb_shape_id_offset]
-
- asm.comment('guard shape')
- asm.cmp(shape_opnd, shape_id)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit)
-
- result = ivar_exists ? C.to_value(pushval) : Qnil
- putobject(jit, ctx, asm, val: result)
-
- # Jump to next instruction. This allows guard chains to share the same successor.
- jump_to_next_insn(jit, ctx, asm)
-
- return EndBlock
- end
-
- # checkmatch
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def checkkeyword(jit, ctx, asm)
- # When a keyword is unspecified past index 32, a hash will be used
- # instead. This can only happen in iseqs taking more than 32 keywords.
- if jit.iseq.body.param.keyword.num >= 32
- return CantCompile
- end
-
- # The EP offset to the undefined bits local
- bits_offset = jit.operand(0)
-
- # The index of the keyword we want to check
- index = jit.operand(1, signed: true)
-
- # Load environment pointer EP
- ep_reg = :rax
- jit_get_ep(asm, 0, reg: ep_reg)
-
- # VALUE kw_bits = *(ep - bits)
- bits_opnd = [ep_reg, C.VALUE.size * -bits_offset]
-
- # unsigned int b = (unsigned int)FIX2ULONG(kw_bits);
- # if ((b & (0x01 << idx))) {
- #
- # We can skip the FIX2ULONG conversion by shifting the bit we test
- bit_test = 0x01 << (index + 1)
- asm.test(bits_opnd, bit_test)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovz(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # checktype
- # defineclass
- # definemethod
- # definesmethod
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def send(jit, ctx, asm)
- # Specialize on a compile-time receiver, and split a block for chain guards
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- cd = C.rb_call_data.new(jit.operand(0))
- blockiseq = jit.operand(1)
-
- # calling->ci
- mid = C.vm_ci_mid(cd.ci)
- calling = build_calling(ci: cd.ci, block_handler: blockiseq)
-
- # vm_sendish
- cme, comptime_recv_klass = jit_search_method(jit, ctx, asm, mid, calling)
- if cme == CantCompile
- return CantCompile
- end
- jit_call_general(jit, ctx, asm, mid, calling, cme, comptime_recv_klass)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_send_without_block(jit, ctx, asm, cd: C.rb_call_data.new(jit.operand(0)))
- # Specialize on a compile-time receiver, and split a block for chain guards
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- # calling->ci
- mid = C.vm_ci_mid(cd.ci)
- calling = build_calling(ci: cd.ci, block_handler: C::VM_BLOCK_HANDLER_NONE)
-
- # vm_sendish
- cme, comptime_recv_klass = jit_search_method(jit, ctx, asm, mid, calling)
- if cme == CantCompile
- return CantCompile
- end
- jit_call_general(jit, ctx, asm, mid, calling, cme, comptime_recv_klass)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def objtostring(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- recv = ctx.stack_opnd(0)
- comptime_recv = jit.peek_at_stack(0)
-
- if C.RB_TYPE_P(comptime_recv, C::RUBY_T_STRING)
- side_exit = side_exit(jit, ctx)
-
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv, StackOpnd[0], comptime_recv, side_exit)
- # No work needed. The string value is already on the top of the stack.
- KeepCompiling
- else
- cd = C.rb_call_data.new(jit.operand(0))
- opt_send_without_block(jit, ctx, asm, cd:)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_str_freeze(jit, ctx, asm)
- unless Invariants.assume_bop_not_redefined(jit, C::STRING_REDEFINED_OP_FLAG, C::BOP_FREEZE)
- return CantCompile;
- end
-
- str = jit.operand(0, ruby: true)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::CString)
- asm.mov(:rax, to_value(str))
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_nil_p(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # opt_str_uminus
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_send(jit, ctx, asm)
- type = C.ID2SYM jit.operand(1)
-
- case type
- when :min then opt_newarray_min(jit, ctx, asm)
- when :max then opt_newarray_max(jit, ctx, asm)
- when :hash then opt_newarray_hash(jit, ctx, asm)
- else
- return CantCompile
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_min(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we may allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- offset_magnitude = C.VALUE.size * num
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- asm.lea(:rax, values_opnd)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], num)
- asm.mov(C_ARGS[2], :rax)
- asm.call(C.rb_vm_opt_newarray_min)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_max(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we may allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- offset_magnitude = C.VALUE.size * num
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- asm.lea(:rax, values_opnd)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], num)
- asm.mov(C_ARGS[2], :rax)
- asm.call(C.rb_vm_opt_newarray_max)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_hash(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we may allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- offset_magnitude = C.VALUE.size * num
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- asm.lea(:rax, values_opnd)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], num)
- asm.mov(C_ARGS[2], :rax)
- asm.call(C.rb_vm_opt_newarray_hash)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def invokesuper(jit, ctx, asm)
- cd = C.rb_call_data.new(jit.operand(0))
- block = jit.operand(1)
-
- # Defer compilation so we can specialize on class of receiver
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- me = C.rb_vm_frame_method_entry(jit.cfp)
- if me.nil?
- return CantCompile
- end
-
- # FIXME: We should track and invalidate this block when this cme is invalidated
- current_defined_class = me.defined_class
- mid = me.def.original_id
-
- if me.to_i != C.rb_callable_method_entry(current_defined_class, me.called_id).to_i
- # Though we likely could generate this call, as we are only concerned
- # with the method entry remaining valid, assume_method_lookup_stable
- # below requires that the method lookup matches as well
- return CantCompile
- end
-
- # vm_search_normal_superclass
- rbasic_klass = C.to_ruby(C.RBasic.new(C.to_value(current_defined_class)).klass)
- if C::BUILTIN_TYPE(current_defined_class) == C::RUBY_T_ICLASS && C::BUILTIN_TYPE(rbasic_klass) == C::RUBY_T_MODULE && \
- C::FL_TEST_RAW(rbasic_klass, C::RMODULE_IS_REFINEMENT)
- return CantCompile
- end
- comptime_superclass = C.rb_class_get_superclass(C.RCLASS_ORIGIN(current_defined_class))
-
- ci = cd.ci
- argc = C.vm_ci_argc(ci)
-
- ci_flags = C.vm_ci_flag(ci)
-
- # Don't JIT calls that aren't simple
- # Note, not using VM_CALL_ARGS_SIMPLE because sometimes we pass a block.
-
- if ci_flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_keywords)
- return CantCompile
- end
- if ci_flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_kw_splat)
- return CantCompile
- end
- if ci_flags & C::VM_CALL_ARGS_BLOCKARG != 0
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- # Ensure we haven't rebound this method onto an incompatible class.
- # In the interpreter we try to avoid making this check by performing some
- # cheaper calculations first, but since we specialize on the method entry
- # and so only have to do this once at compile time this is fine to always
- # check and side exit.
- comptime_recv = jit.peek_at_stack(argc)
- unless C.obj_is_kind_of(comptime_recv, current_defined_class)
- return CantCompile
- end
-
- # Do method lookup
- cme = C.rb_callable_method_entry(comptime_superclass, mid)
-
- if cme.nil?
- return CantCompile
- end
-
- # Check that we'll be able to write this method dispatch before generating checks
- cme_def_type = cme.def.type
- if cme_def_type != C::VM_METHOD_TYPE_ISEQ && cme_def_type != C::VM_METHOD_TYPE_CFUNC
- # others unimplemented
- return CantCompile
- end
-
- asm.comment('guard known me')
- lep_opnd = :rax
- jit_get_lep(jit, asm, reg: lep_opnd)
- ep_me_opnd = [lep_opnd, C.VALUE.size * C::VM_ENV_DATA_INDEX_ME_CREF]
-
- asm.mov(:rcx, me.to_i)
- asm.cmp(ep_me_opnd, :rcx)
- asm.jne(counted_exit(side_exit(jit, ctx), :invokesuper_me_changed))
-
- if block == C::VM_BLOCK_HANDLER_NONE
- # Guard no block passed
- # rb_vm_frame_block_handler(GET_EC()->cfp) == VM_BLOCK_HANDLER_NONE
- # note, we assume VM_ASSERT(VM_ENV_LOCAL_P(ep))
- #
- # TODO: this could properly forward the current block handler, but
- # would require changes to gen_send_*
- asm.comment('guard no block given')
- ep_specval_opnd = [lep_opnd, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]
- asm.cmp(ep_specval_opnd, C::VM_BLOCK_HANDLER_NONE)
- asm.jne(counted_exit(side_exit(jit, ctx), :invokesuper_block))
- end
-
- # We need to assume that both our current method entry and the super
- # method entry we invoke remain stable
- Invariants.assume_method_lookup_stable(jit, me)
- Invariants.assume_method_lookup_stable(jit, cme)
-
- # Method calls may corrupt types
- ctx.clear_local_types
-
- calling = build_calling(ci:, block_handler: block)
- case cme_def_type
- in C::VM_METHOD_TYPE_ISEQ
- iseq = def_iseq_ptr(cme.def)
- frame_type = C::VM_FRAME_MAGIC_METHOD | C::VM_ENV_FLAG_LOCAL
- jit_call_iseq(jit, ctx, asm, cme, calling, iseq, frame_type:)
- in C::VM_METHOD_TYPE_CFUNC
- jit_call_cfunc(jit, ctx, asm, cme, calling)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def invokeblock(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- # Get call info
- cd = C.rb_call_data.new(jit.operand(0))
- calling = build_calling(ci: cd.ci, block_handler: :captured)
-
- # Get block_handler
- cfp = jit.cfp
- lep = C.rb_vm_ep_local_ep(cfp.ep)
- comptime_handler = lep[C::VM_ENV_DATA_INDEX_SPECVAL]
-
- # Handle each block_handler type
- if comptime_handler == C::VM_BLOCK_HANDLER_NONE # no block given
- asm.incr_counter(:invokeblock_none)
- CantCompile
- elsif comptime_handler & 0x3 == 0x1 # VM_BH_ISEQ_BLOCK_P
- asm.comment('get local EP')
- ep_reg = :rax
- jit_get_lep(jit, asm, reg: ep_reg)
- asm.mov(:rax, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler_opnd
-
- asm.comment('guard block_handler type')
- side_exit = side_exit(jit, ctx)
- asm.mov(:rcx, :rax)
- asm.and(:rcx, 0x3) # block_handler is a tagged pointer
- asm.cmp(:rcx, 0x1) # VM_BH_ISEQ_BLOCK_P
- tag_changed_exit = counted_exit(side_exit, :invokeblock_tag_changed)
- jit_chain_guard(:jne, jit, ctx, asm, tag_changed_exit)
-
- comptime_captured = C.rb_captured_block.new(comptime_handler & ~0x3)
- comptime_iseq = comptime_captured.code.iseq
-
- asm.comment('guard known ISEQ')
- asm.and(:rax, ~0x3) # captured
- asm.mov(:rax, [:rax, C.VALUE.size * 2]) # captured->iseq
- asm.mov(:rcx, comptime_iseq.to_i)
- asm.cmp(:rax, :rcx)
- block_changed_exit = counted_exit(side_exit, :invokeblock_iseq_block_changed)
- jit_chain_guard(:jne, jit, ctx, asm, block_changed_exit)
-
- jit_call_iseq(jit, ctx, asm, nil, calling, comptime_iseq, frame_type: C::VM_FRAME_MAGIC_BLOCK)
- elsif comptime_handler & 0x3 == 0x3 # VM_BH_IFUNC_P
- # We aren't handling CALLER_SETUP_ARG and CALLER_REMOVE_EMPTY_KW_SPLAT yet.
- if calling.flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:invokeblock_ifunc_args_splat)
- return CantCompile
- end
- if calling.flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:invokeblock_ifunc_kw_splat)
- return CantCompile
- end
-
- asm.comment('get local EP')
- jit_get_lep(jit, asm, reg: :rax)
- asm.mov(:rcx, [:rax, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler_opnd
-
- asm.comment('guard block_handler type');
- side_exit = side_exit(jit, ctx)
- asm.mov(:rax, :rcx) # block_handler_opnd
- asm.and(:rax, 0x3) # tag_opnd: block_handler is a tagged pointer
- asm.cmp(:rax, 0x3) # VM_BH_IFUNC_P
- tag_changed_exit = counted_exit(side_exit, :invokeblock_tag_changed)
- jit_chain_guard(:jne, jit, ctx, asm, tag_changed_exit)
-
- # The cfunc may not be leaf
- jit_prepare_routine_call(jit, ctx, asm) # clobbers :rax
-
- asm.comment('call ifunc')
- asm.and(:rcx, ~0x3) # captured_opnd
- asm.lea(:rax, ctx.sp_opnd(-calling.argc * C.VALUE.size)) # argv
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], :rcx) # captured_opnd
- asm.mov(C_ARGS[2], calling.argc)
- asm.mov(C_ARGS[3], :rax) # argv
- asm.call(C.rb_vm_yield_with_cfunc)
-
- ctx.stack_pop(calling.argc)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # cfunc calls may corrupt types
- ctx.clear_local_types
-
- # Share the successor with other chains
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- elsif symbol?(comptime_handler)
- asm.incr_counter(:invokeblock_symbol)
- CantCompile
- else # Proc
- asm.incr_counter(:invokeblock_proc)
- CantCompile
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def leave(jit, ctx, asm)
- assert_equal(ctx.stack_size, 1)
-
- jit_check_ints(jit, ctx, asm)
-
- asm.comment('pop stack frame')
- asm.lea(:rax, [CFP, C.rb_control_frame_t.size])
- asm.mov(CFP, :rax)
- asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], :rax)
-
- # Return a value (for compile_leave_exit)
- ret_opnd = ctx.stack_pop
- asm.mov(:rax, ret_opnd)
-
- # Set caller's SP and push a value to its stack (for JIT)
- asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # Note: SP is in the position after popping a receiver and arguments
- asm.mov([SP], :rax)
-
- # Jump to cfp->jit_return
- asm.jmp([CFP, -C.rb_control_frame_t.size + C.rb_control_frame_t.offsetof(:jit_return)])
-
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def throw(jit, ctx, asm)
- throw_state = jit.operand(0)
- asm.mov(:rcx, ctx.stack_pop(1)) # throwobj
-
- # THROW_DATA_NEW allocates. Save SP for GC and PC for allocation tracing as
- # well as handling the catch table. However, not using jit_prepare_routine_call
- # since we don't need a patch point for this implementation.
- jit_save_pc(jit, asm) # clobbers rax
- jit_save_sp(ctx, asm)
-
- # rb_vm_throw verifies it's a valid throw, sets ec->tag->state, and returns throw
- # data, which is throwobj or a vm_throw_data wrapping it. When ec->tag->state is
- # set, JIT code callers will handle the throw with vm_exec_handle_exception.
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], throw_state)
- # asm.mov(C_ARGS[3], :rcx) # same reg
- asm.call(C.rb_vm_throw)
-
- asm.comment('exit from throw')
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- # return C_RET as C_RET
- asm.ret
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jump(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
- jit_direct_jump(jit.iseq, pc, ctx, asm)
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def branchif(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- # Get the branch target instruction offsets
- next_pc = jit.pc + C.VALUE.size * jit.insn.len
- jump_pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
-
- val_type = ctx.get_opnd_type(StackOpnd[0])
- val_opnd = ctx.stack_pop(1)
-
- if (result = val_type.known_truthy) != nil
- target_pc = result ? jump_pc : next_pc
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- else
- # This `test` sets ZF only for Qnil and Qfalse, which let jz jump.
- asm.test(val_opnd, ~Qnil)
-
- # Set stubs
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc: jump_pc), # branch target
- target1: BranchTarget.new(ctx:, pc: next_pc), # fallthrough
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.target1.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
- @ocb.write(ocb_asm)
- end
-
- # Jump to target0 on jnz
- branch_stub.compile = proc do |branch_asm|
- branch_asm.comment("branchif #{branch_stub.shape}")
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.jnz(branch_stub.target0.address)
- branch_asm.jmp(branch_stub.target1.address)
- in Next0
- branch_asm.jz(branch_stub.target1.address)
- in Next1
- branch_asm.jnz(branch_stub.target0.address)
- end
- end
- end
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def branchunless(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- # Get the branch target instruction offsets
- next_pc = jit.pc + C.VALUE.size * jit.insn.len
- jump_pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
-
- val_type = ctx.get_opnd_type(StackOpnd[0])
- val_opnd = ctx.stack_pop(1)
-
- if (result = val_type.known_truthy) != nil
- target_pc = result ? next_pc : jump_pc
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- else
- # This `test` sets ZF only for Qnil and Qfalse, which let jz jump.
- asm.test(val_opnd, ~Qnil)
-
- # Set stubs
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc: jump_pc), # branch target
- target1: BranchTarget.new(ctx:, pc: next_pc), # fallthrough
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.target1.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
- @ocb.write(ocb_asm)
- end
-
- # Jump to target0 on jz
- branch_stub.compile = proc do |branch_asm|
- branch_asm.comment("branchunless #{branch_stub.shape}")
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.jz(branch_stub.target0.address)
- branch_asm.jmp(branch_stub.target1.address)
- in Next0
- branch_asm.jnz(branch_stub.target1.address)
- in Next1
- branch_asm.jz(branch_stub.target0.address)
- end
- end
- end
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def branchnil(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- # Get the branch target instruction offsets
- next_pc = jit.pc + C.VALUE.size * jit.insn.len
- jump_pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
-
- val_type = ctx.get_opnd_type(StackOpnd[0])
- val_opnd = ctx.stack_pop(1)
-
- if (result = val_type.known_nil) != nil
- target_pc = result ? jump_pc : next_pc
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- else
- asm.cmp(val_opnd, Qnil)
-
- # Set stubs
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc: jump_pc), # branch target
- target1: BranchTarget.new(ctx:, pc: next_pc), # fallthrough
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.target1.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
- @ocb.write(ocb_asm)
- end
-
- # Jump to target0 on je
- branch_stub.compile = proc do |branch_asm|
- branch_asm.comment("branchnil #{branch_stub.shape}")
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.je(branch_stub.target0.address)
- branch_asm.jmp(branch_stub.target1.address)
- in Next0
- branch_asm.jne(branch_stub.target1.address)
- in Next1
- branch_asm.je(branch_stub.target0.address)
- end
- end
- end
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- # once
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_case_dispatch(jit, ctx, asm)
- # Normally this instruction would lookup the key in a hash and jump to an
- # offset based on that.
- # Instead we can take the fallback case and continue with the next
- # instruction.
- # We'd hope that our jitted code will be sufficiently fast without the
- # hash lookup, at least for small hashes, but it's worth revisiting this
- # assumption in the future.
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
- starting_context = ctx.dup
-
- case_hash = jit.operand(0, ruby: true)
- else_offset = jit.operand(1)
-
- # Try to reorder case/else branches so that ones that are actually used come first.
- # Supporting only Fixnum for now so that the implementation can be an equality check.
- key_opnd = ctx.stack_pop(1)
- comptime_key = jit.peek_at_stack(0)
-
- # Check that all cases are fixnums to avoid having to register BOP assumptions on
- # all the types that case hashes support. This spends compile time to save memory.
- if fixnum?(comptime_key) && comptime_key <= 2**32 && C.rb_hash_keys(case_hash).all? { |key| fixnum?(key) }
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_EQQ)
- return CantCompile
- end
-
- # Check if the key is the same value
- asm.cmp(key_opnd, comptime_key)
- side_exit = side_exit(jit, starting_context)
- jit_chain_guard(:jne, jit, starting_context, asm, side_exit)
-
- # Get the offset for the compile-time key
- offset = C.rb_hash_stlike_lookup(case_hash, comptime_key)
- # NOTE: If we hit the else branch with various values, it could negatively impact the performance.
- jump_offset = offset || else_offset
-
- # Jump to the offset of case or else
- target_pc = jit.pc + (jit.insn.len + jump_offset) * C.VALUE.size
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- EndBlock
- else
- KeepCompiling # continue with === branches
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_plus(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- if fixnum?(comptime_recv) && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_PLUS)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- obj_opnd = ctx.stack_pop
- recv_opnd = ctx.stack_pop
-
- asm.mov(:rax, recv_opnd)
- asm.sub(:rax, 1) # untag
- asm.mov(:rcx, obj_opnd)
- asm.add(:rax, :rcx)
- asm.jo(side_exit(jit, ctx))
-
- dst_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(dst_opnd, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_minus(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- if fixnum?(comptime_recv) && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_MINUS)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- obj_opnd = ctx.stack_pop
- recv_opnd = ctx.stack_pop
-
- asm.mov(:rax, recv_opnd)
- asm.mov(:rcx, obj_opnd)
- asm.sub(:rax, :rcx)
- asm.jo(side_exit(jit, ctx))
- asm.add(:rax, 1) # re-tag
-
- dst_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(dst_opnd, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_mult(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_div(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_mod(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_MOD)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- # Get the operands and destination from the stack
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
-
- # Check for arg0 % 0
- asm.cmp(arg1, 0)
- asm.je(side_exit(jit, ctx))
-
- # Call rb_fix_mod_fix(VALUE recv, VALUE obj)
- asm.mov(C_ARGS[0], arg0)
- asm.mov(C_ARGS[1], arg1)
- asm.call(C.rb_fix_mod_fix)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::Fixnum)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_eq(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if jit_equality_specialized(jit, ctx, asm, true)
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_neq(jit, ctx, asm)
- # opt_neq is passed two rb_call_data as arguments:
- # first for ==, second for !=
- neq_cd = C.rb_call_data.new(jit.operand(1))
- opt_send_without_block(jit, ctx, asm, cd: neq_cd)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_lt(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovl, bop: C::BOP_LT)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_le(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovle, bop: C::BOP_LE)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_gt(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovg, bop: C::BOP_GT)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_ge(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovge, bop: C::BOP_GE)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_ltlt(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_and(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_AND)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- # Get the operands and destination from the stack
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
-
- asm.comment('bitwise and')
- asm.mov(:rax, arg0)
- asm.and(:rax, arg1)
-
- # Push the return value onto the stack
- dst = ctx.stack_push(Type::Fixnum)
- asm.mov(dst, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_or(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_OR)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- # Get the operands and destination from the stack
- asm.comment('bitwise or')
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
-
- # Do the bitwise or arg0 | arg1
- asm.mov(:rax, arg0)
- asm.or(:rax, arg1)
-
- # Push the return value onto the stack
- dst = ctx.stack_push(Type::Fixnum)
- asm.mov(dst, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_aref(jit, ctx, asm)
- cd = C.rb_call_data.new(jit.operand(0))
- argc = C.vm_ci_argc(cd.ci)
-
- if argc != 1
- asm.incr_counter(:optaref_argc_not_one)
- return CantCompile
- end
-
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- side_exit = side_exit(jit, ctx)
-
- if C.rb_class_of(comptime_recv) == Array && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::ARRAY_REDEFINED_OP_FLAG, C::BOP_AREF)
- return CantCompile
- end
-
- idx_opnd = ctx.stack_opnd(0)
- recv_opnd = ctx.stack_opnd(1)
-
- not_array_exit = counted_exit(side_exit, :optaref_recv_not_array)
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv_opnd, StackOpnd[1], comptime_recv, not_array_exit)
-
- # Bail if idx is not a FIXNUM
- asm.mov(:rax, idx_opnd)
- asm.test(:rax, C::RUBY_FIXNUM_FLAG)
- asm.jz(counted_exit(side_exit, :optaref_arg_not_fixnum))
-
- # Call VALUE rb_ary_entry_internal(VALUE ary, long offset).
- # It never raises or allocates, so we don't need to write to cfp->pc.
- asm.sar(:rax, 1) # Convert fixnum to int
- asm.mov(C_ARGS[0], recv_opnd)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rb_ary_entry_internal)
-
- # Pop the argument and the receiver
- ctx.stack_pop(2)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # Let guard chains share the same successor
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- elsif C.rb_class_of(comptime_recv) == Hash
- unless Invariants.assume_bop_not_redefined(jit, C::HASH_REDEFINED_OP_FLAG, C::BOP_AREF)
- return CantCompile
- end
-
- recv_opnd = ctx.stack_opnd(1)
-
- # Guard that the receiver is a Hash
- not_hash_exit = counted_exit(side_exit, :optaref_recv_not_hash)
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv_opnd, StackOpnd[1], comptime_recv, not_hash_exit)
-
- # Prepare to call rb_hash_aref(). It might call #hash on the key.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.comment('call rb_hash_aref')
- key_opnd = ctx.stack_opnd(0)
- recv_opnd = ctx.stack_opnd(1)
- asm.mov(:rdi, recv_opnd)
- asm.mov(:rsi, key_opnd)
- asm.call(C.rb_hash_aref)
-
- # Pop the key and the receiver
- ctx.stack_pop(2)
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # Let guard chains share the same successor
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_aset(jit, ctx, asm)
- # Defer compilation so we can specialize on a runtime `self`
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(2)
- comptime_key = jit.peek_at_stack(1)
-
- # Get the operands from the stack
- recv = ctx.stack_opnd(2)
- key = ctx.stack_opnd(1)
- _val = ctx.stack_opnd(0)
-
- if C.rb_class_of(comptime_recv) == Array && fixnum?(comptime_key)
- side_exit = side_exit(jit, ctx)
-
- # Guard receiver is an Array
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv, StackOpnd[2], comptime_recv, side_exit)
-
- # Guard key is a fixnum
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_key), key, StackOpnd[1], comptime_key, side_exit)
-
- # We might allocate or raise
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.comment('call rb_ary_store')
- recv = ctx.stack_opnd(2)
- key = ctx.stack_opnd(1)
- val = ctx.stack_opnd(0)
- asm.mov(:rax, key)
- asm.sar(:rax, 1) # FIX2LONG(key)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], :rax)
- asm.mov(C_ARGS[2], val)
- asm.call(C.rb_ary_store)
-
- # rb_ary_store returns void
- # stored value should still be on stack
- val = ctx.stack_opnd(0)
-
- # Push the return value onto the stack
- ctx.stack_pop(3)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(:rax, val)
- asm.mov(stack_ret, :rax)
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- elsif C.rb_class_of(comptime_recv) == Hash
- side_exit = side_exit(jit, ctx)
-
- # Guard receiver is a Hash
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv, StackOpnd[2], comptime_recv, side_exit)
-
- # We might allocate or raise
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Call rb_hash_aset
- recv = ctx.stack_opnd(2)
- key = ctx.stack_opnd(1)
- val = ctx.stack_opnd(0)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], key)
- asm.mov(C_ARGS[2], val)
- asm.call(C.rb_hash_aset)
-
- # Push the return value onto the stack
- ctx.stack_pop(3)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # opt_aset_with
- # opt_aref_with
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_length(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_size(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_empty_p(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_succ(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_not(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_regexpmatch2(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # invokebuiltin
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_invokebuiltin_delegate(jit, ctx, asm)
- bf = C.rb_builtin_function.new(jit.operand(0))
- bf_argc = bf.argc
- start_index = jit.operand(1)
-
- # ec, self, and arguments
- if bf_argc + 2 > C_ARGS.size
- return CantCompile
- end
-
- # If the calls don't allocate, do they need up to date PC, SP?
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Call the builtin func (ec, recv, arg1, arg2, ...)
- asm.comment('call builtin func')
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], [CFP, C.rb_control_frame_t.offsetof(:self)])
-
- # Copy arguments from locals
- if bf_argc > 0
- # Load environment pointer EP from CFP
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:ep)])
-
- bf_argc.times do |i|
- table_size = jit.iseq.body.local_table_size
- offs = -table_size - C::VM_ENV_DATA_SIZE + 1 + start_index + i
- asm.mov(C_ARGS[2 + i], [:rax, offs * C.VALUE.size])
- end
- end
- asm.call(bf.func_ptr)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_invokebuiltin_delegate_leave(jit, ctx, asm)
- opt_invokebuiltin_delegate(jit, ctx, asm)
- # opt_invokebuiltin_delegate is always followed by leave insn
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putobject_INT2FIX_0_(jit, ctx, asm)
- putobject(jit, ctx, asm, val: C.to_value(0))
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putobject_INT2FIX_1_(jit, ctx, asm)
- putobject(jit, ctx, asm, val: C.to_value(1))
- end
-
- #
- # C func
- #
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_true(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- asm.comment('nil? == true')
- ctx.stack_pop(1)
- stack_ret = ctx.stack_push(Type::True)
- asm.mov(stack_ret, Qtrue)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_false(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- asm.comment('nil? == false')
- ctx.stack_pop(1)
- stack_ret = ctx.stack_push(Type::False)
- asm.mov(stack_ret, Qfalse)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_kernel_is_a(jit, ctx, asm, argc, known_recv_class)
- if argc != 1
- return false
- end
-
- # If this is a super call we might not know the class
- if known_recv_class.nil?
- return false
- end
-
- # Important note: The output code will simply `return true/false`.
- # Correctness follows from:
- # - `known_recv_class` implies there is a guard scheduled before here
- # for a particular `CLASS_OF(lhs)`.
- # - We guard that rhs is identical to the compile-time sample
- # - In general, for any two Class instances A, B, `A < B` does not change at runtime.
- # Class#superclass is stable.
-
- sample_rhs = jit.peek_at_stack(0)
- sample_lhs = jit.peek_at_stack(1)
-
- # We are not allowing module here because the module hierachy can change at runtime.
- if C.RB_TYPE_P(sample_rhs, C::RUBY_T_CLASS)
- return false
- end
- sample_is_a = C.obj_is_kind_of(sample_lhs, sample_rhs)
-
- side_exit = side_exit(jit, ctx)
- asm.comment('Kernel#is_a?')
- asm.mov(:rax, to_value(sample_rhs))
- asm.cmp(ctx.stack_opnd(0), :rax)
- asm.jne(counted_exit(side_exit, :send_is_a_class_mismatch))
-
- ctx.stack_pop(2)
-
- if sample_is_a
- stack_ret = ctx.stack_push(Type::True)
- asm.mov(stack_ret, Qtrue)
- else
- stack_ret = ctx.stack_push(Type::False)
- asm.mov(stack_ret, Qfalse)
- end
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_kernel_instance_of(jit, ctx, asm, argc, known_recv_class)
- if argc != 1
- return false
- end
-
- # If this is a super call we might not know the class
- if known_recv_class.nil?
- return false
- end
-
- # Important note: The output code will simply `return true/false`.
- # Correctness follows from:
- # - `known_recv_class` implies there is a guard scheduled before here
- # for a particular `CLASS_OF(lhs)`.
- # - We guard that rhs is identical to the compile-time sample
- # - For a particular `CLASS_OF(lhs)`, `rb_obj_class(lhs)` does not change.
- # (because for any singleton class `s`, `s.superclass.equal?(s.attached_object.class)`)
-
- sample_rhs = jit.peek_at_stack(0)
- sample_lhs = jit.peek_at_stack(1)
-
- # Filters out cases where the C implementation raises
- unless C.RB_TYPE_P(sample_rhs, C::RUBY_T_CLASS) || C.RB_TYPE_P(sample_rhs, C::RUBY_T_MODULE)
- return false
- end
-
- # We need to grab the class here to deal with singleton classes.
- # Instance of grabs the "real class" of the object rather than the
- # singleton class.
- sample_lhs_real_class = C.rb_obj_class(sample_lhs)
-
- sample_instance_of = (sample_lhs_real_class == sample_rhs)
-
- side_exit = side_exit(jit, ctx)
- asm.comment('Kernel#instance_of?')
- asm.mov(:rax, to_value(sample_rhs))
- asm.cmp(ctx.stack_opnd(0), :rax)
- asm.jne(counted_exit(side_exit, :send_instance_of_class_mismatch))
-
- ctx.stack_pop(2)
-
- if sample_instance_of
- stack_ret = ctx.stack_push(Type::True)
- asm.mov(stack_ret, Qtrue)
- else
- stack_ret = ctx.stack_push(Type::False)
- asm.mov(stack_ret, Qfalse)
- end
- return true;
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_obj_not(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- recv_type = ctx.get_opnd_type(StackOpnd[0])
-
- case recv_type.known_truthy
- in false
- asm.comment('rb_obj_not(nil_or_false)')
- ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::True)
- asm.mov(out_opnd, Qtrue)
- in true
- # Note: recv_type != Type::Nil && recv_type != Type::False.
- asm.comment('rb_obj_not(truthy)')
- ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::False)
- asm.mov(out_opnd, Qfalse)
- in nil
- asm.comment('rb_obj_not')
-
- recv = ctx.stack_pop
- # This `test` sets ZF only for Qnil and Qfalse, which let cmovz set.
- asm.test(recv, ~Qnil)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovz(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
- end
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_obj_equal(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- asm.comment('equal?')
- obj1 = ctx.stack_pop(1)
- obj2 = ctx.stack_pop(1)
-
- asm.mov(:rax, obj1)
- asm.mov(:rcx, obj2)
- asm.cmp(:rax, :rcx)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmove(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_obj_not_equal(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- jit_equality_specialized(jit, ctx, asm, false)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_mod_eqq(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
-
- asm.comment('Module#===')
- # By being here, we know that the receiver is a T_MODULE or a T_CLASS, because Module#=== can
- # only live on these objects. With that, we can call rb_obj_is_kind_of() without
- # jit_prepare_routine_call() or a control frame push because it can't raise, allocate, or call
- # Ruby methods with these inputs.
- # Note the difference in approach from Kernel#is_a? because we don't get a free guard for the
- # right hand side.
- lhs = ctx.stack_opnd(1) # the module
- rhs = ctx.stack_opnd(0)
- asm.mov(C_ARGS[0], rhs);
- asm.mov(C_ARGS[1], lhs);
- asm.call(C.rb_obj_is_kind_of)
-
- # Return the result
- ctx.stack_pop(2)
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, C_RET)
-
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_int_equal(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- # Compare the arguments
- asm.comment('rb_int_equal')
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
- asm.mov(:rax, arg1)
- asm.cmp(arg0, :rax)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmove(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_int_mul(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('rb_int_mul')
- y_opnd = ctx.stack_pop
- x_opnd = ctx.stack_pop
- asm.mov(C_ARGS[0], x_opnd)
- asm.mov(C_ARGS[1], y_opnd)
- asm.call(C.rb_fix_mul_fix)
-
- ret_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- def jit_rb_int_div(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('rb_int_div')
- y_opnd = ctx.stack_pop
- x_opnd = ctx.stack_pop
- asm.mov(:rax, y_opnd)
- asm.cmp(:rax, C.to_value(0))
- asm.je(side_exit(jit, ctx))
-
- asm.mov(C_ARGS[0], x_opnd)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rb_fix_div_fix)
-
- ret_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_int_aref(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('rb_int_aref')
- y_opnd = ctx.stack_pop
- x_opnd = ctx.stack_pop
-
- asm.mov(C_ARGS[0], x_opnd)
- asm.mov(C_ARGS[1], y_opnd)
- asm.call(C.rb_fix_aref)
-
- ret_opnd = ctx.stack_push(Type::UnknownImm)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_empty_p(jit, ctx, asm, argc, known_recv_class)
- recv_opnd = ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::UnknownImm)
-
- asm.comment('get string length')
- asm.mov(:rax, recv_opnd)
- str_len_opnd = [:rax, C.RString.offsetof(:len)]
-
- asm.cmp(str_len_opnd, 0)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmove(:rax, :rcx)
- asm.mov(out_opnd, :rax)
-
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_to_s(jit, ctx, asm, argc, known_recv_class)
- return false if argc != 0
- if known_recv_class == String
- asm.comment('to_s on plain string')
- # The method returns the receiver, which is already on the stack.
- # No stack movement.
- return true
- end
- false
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_bytesize(jit, ctx, asm, argc, known_recv_class)
- asm.comment('String#bytesize')
-
- recv = ctx.stack_pop(1)
- asm.mov(C_ARGS[0], recv)
- asm.call(C.rb_str_bytesize)
-
- out_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(out_opnd, C_RET)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_concat(jit, ctx, asm, argc, known_recv_class)
- # The << operator can accept integer codepoints for characters
- # as the argument. We only specially optimise string arguments.
- # If the peeked-at compile time argument is something other than
- # a string, assume it won't be a string later either.
- comptime_arg = jit.peek_at_stack(0)
- unless C.RB_TYPE_P(comptime_arg, C::RUBY_T_STRING)
- return false
- end
-
- # Guard that the concat argument is a string
- asm.mov(:rax, ctx.stack_opnd(0))
- guard_object_is_string(jit, ctx, asm, :rax, :rcx, StackOpnd[0])
-
- # Guard buffers from GC since rb_str_buf_append may allocate. During the VM lock on GC,
- # other Ractors may trigger global invalidation, so we need ctx.clear_local_types.
- # PC is used on errors like Encoding::CompatibilityError raised by rb_str_buf_append.
- jit_prepare_routine_call(jit, ctx, asm)
-
- concat_arg = ctx.stack_pop(1)
- recv = ctx.stack_pop(1)
-
- # Test if string encodings differ. If different, use rb_str_append. If the same,
- # use rb_yjit_str_simple_append, which calls rb_str_cat.
- asm.comment('<< on strings')
-
- # Take receiver's object flags XOR arg's flags. If any
- # string-encoding flags are different between the two,
- # the encodings don't match.
- recv_reg = :rax
- asm.mov(recv_reg, recv)
- concat_arg_reg = :rcx
- asm.mov(concat_arg_reg, concat_arg)
- asm.mov(recv_reg, [recv_reg, C.RBasic.offsetof(:flags)])
- asm.mov(concat_arg_reg, [concat_arg_reg, C.RBasic.offsetof(:flags)])
- asm.xor(recv_reg, concat_arg_reg)
- asm.test(recv_reg, C::RUBY_ENCODING_MASK)
-
- # Push once, use the resulting operand in both branches below.
- stack_ret = ctx.stack_push(Type::TString)
-
- enc_mismatch = asm.new_label('enc_mismatch')
- asm.jnz(enc_mismatch)
-
- # If encodings match, call the simple append function and jump to return
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], concat_arg)
- asm.call(C.rjit_str_simple_append)
- ret_label = asm.new_label('func_return')
- asm.mov(stack_ret, C_RET)
- asm.jmp(ret_label)
-
- # If encodings are different, use a slower encoding-aware concatenate
- asm.write_label(enc_mismatch)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], concat_arg)
- asm.call(C.rb_str_buf_append)
- asm.mov(stack_ret, C_RET)
- # Drop through to return
-
- asm.write_label(ret_label)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_uplus(jit, ctx, asm, argc, _known_recv_class)
- if argc != 0
- return false
- end
-
- # We allocate when we dup the string
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.comment('Unary plus on string')
- asm.mov(:rax, ctx.stack_pop(1)) # recv_opnd
- asm.mov(:rcx, [:rax, C.RBasic.offsetof(:flags)]) # flags_opnd
- asm.test(:rcx, C::RUBY_FL_FREEZE)
-
- ret_label = asm.new_label('stack_ret')
-
- # String#+@ can only exist on T_STRING
- stack_ret = ctx.stack_push(Type::TString)
-
- # If the string isn't frozen, we just return it.
- asm.mov(stack_ret, :rax) # recv_opnd
- asm.jz(ret_label)
-
- # Str is frozen - duplicate it
- asm.mov(C_ARGS[0], :rax) # recv_opnd
- asm.call(C.rb_str_dup)
- asm.mov(stack_ret, C_RET)
-
- asm.write_label(ret_label)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_getbyte(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- asm.comment('rb_str_getbyte')
-
- index_opnd = ctx.stack_pop
- str_opnd = ctx.stack_pop
- asm.mov(C_ARGS[0], str_opnd)
- asm.mov(C_ARGS[1], index_opnd)
- asm.call(C.rb_str_getbyte)
-
- ret_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_ary_empty_p(jit, ctx, asm, argc, _known_recv_class)
- array_reg = :rax
- asm.mov(array_reg, ctx.stack_pop(1))
- jit_array_len(asm, array_reg, :rcx)
-
- asm.test(:rcx, :rcx)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovz(:rax, :rcx)
-
- out_opnd = ctx.stack_push(Type::UnknownImm)
- asm.mov(out_opnd, :rax)
-
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_ary_push(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- asm.comment('rb_ary_push')
-
- jit_prepare_routine_call(jit, ctx, asm)
-
- item_opnd = ctx.stack_pop
- ary_opnd = ctx.stack_pop
- asm.mov(C_ARGS[0], ary_opnd)
- asm.mov(C_ARGS[1], item_opnd)
- asm.call(C.rb_ary_push)
-
- ret_opnd = ctx.stack_push(Type::TArray)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_obj_respond_to(jit, ctx, asm, argc, known_recv_class)
- # respond_to(:sym) or respond_to(:sym, true)
- if argc != 1 && argc != 2
- return false
- end
-
- if known_recv_class.nil?
- return false
- end
-
- recv_class = known_recv_class
-
- # Get the method_id from compile time. We will later add a guard against it.
- mid_sym = jit.peek_at_stack(argc - 1)
- unless static_symbol?(mid_sym)
- return false
- end
- mid = C.rb_sym2id(mid_sym)
-
- # This represents the value of the "include_all" argument and whether it's known
- allow_priv = if argc == 1
- # Default is false
- false
- else
- # Get value from type information (may or may not be known)
- ctx.get_opnd_type(StackOpnd[0]).known_truthy
- end
-
- target_cme = C.rb_callable_method_entry_or_negative(recv_class, mid)
-
- # Should never be null, as in that case we will be returned a "negative CME"
- assert_equal(false, target_cme.nil?)
-
- cme_def_type = C.UNDEFINED_METHOD_ENTRY_P(target_cme) ? C::VM_METHOD_TYPE_UNDEF : target_cme.def.type
-
- if cme_def_type == C::VM_METHOD_TYPE_REFINED
- return false
- end
-
- visibility = if cme_def_type == C::VM_METHOD_TYPE_UNDEF
- C::METHOD_VISI_UNDEF
- else
- C.METHOD_ENTRY_VISI(target_cme)
- end
-
- result =
- case [visibility, allow_priv]
- in C::METHOD_VISI_UNDEF, _ then Qfalse # No method => false
- in C::METHOD_VISI_PUBLIC, _ then Qtrue # Public method => true regardless of include_all
- in _, true then Qtrue # include_all => always true
- else return false # not public and include_all not known, can't compile
- end
-
- if result != Qtrue
- # Only if respond_to_missing? hasn't been overridden
- # In the future, we might want to jit the call to respond_to_missing?
- unless Invariants.assume_method_basic_definition(jit, recv_class, C.idRespond_to_missing)
- return false
- end
- end
-
- # Invalidate this block if method lookup changes for the method being queried. This works
- # both for the case where a method does or does not exist, as for the latter we asked for a
- # "negative CME" earlier.
- Invariants.assume_method_lookup_stable(jit, target_cme)
-
- # Generate a side exit
- side_exit = side_exit(jit, ctx)
-
- if argc == 2
- # pop include_all argument (we only use its type info)
- ctx.stack_pop(1)
- end
-
- sym_opnd = ctx.stack_pop(1)
- _recv_opnd = ctx.stack_pop(1)
-
- # This is necessary because we have no guarantee that sym_opnd is a constant
- asm.comment('guard known mid')
- asm.mov(:rax, to_value(mid_sym))
- asm.cmp(sym_opnd, :rax)
- asm.jne(side_exit)
-
- putobject(jit, ctx, asm, val: result)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_f_block_given_p(jit, ctx, asm, argc, _known_recv_class)
- asm.comment('block_given?')
-
- # Same as rb_vm_frame_block_handler
- jit_get_lep(jit, asm, reg: :rax)
- asm.mov(:rax, [:rax, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler
-
- ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::UnknownImm)
-
- # Return `block_handler != VM_BLOCK_HANDLER_NONE`
- asm.cmp(:rax, C::VM_BLOCK_HANDLER_NONE)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovne(:rax, :rcx) # block_given
- asm.mov(out_opnd, :rax)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_thread_s_current(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- asm.comment('Thread.current')
- ctx.stack_pop(1)
-
- # ec->thread_ptr
- asm.mov(:rax, [EC, C.rb_execution_context_t.offsetof(:thread_ptr)])
-
- # thread->self
- asm.mov(:rax, [:rax, C.rb_thread_struct.offsetof(:self)])
-
- stack_ret = ctx.stack_push(Type::UnknownHeap)
- asm.mov(stack_ret, :rax)
- true
- end
-
- #
- # Helpers
- #
-
- def register_cfunc_codegen_funcs
- # Specialization for C methods. See register_cfunc_method for details.
- register_cfunc_method(BasicObject, :!, :jit_rb_obj_not)
-
- register_cfunc_method(NilClass, :nil?, :jit_rb_true)
- register_cfunc_method(Kernel, :nil?, :jit_rb_false)
- register_cfunc_method(Kernel, :is_a?, :jit_rb_kernel_is_a)
- register_cfunc_method(Kernel, :kind_of?, :jit_rb_kernel_is_a)
- register_cfunc_method(Kernel, :instance_of?, :jit_rb_kernel_instance_of)
-
- register_cfunc_method(BasicObject, :==, :jit_rb_obj_equal)
- register_cfunc_method(BasicObject, :equal?, :jit_rb_obj_equal)
- register_cfunc_method(BasicObject, :!=, :jit_rb_obj_not_equal)
- register_cfunc_method(Kernel, :eql?, :jit_rb_obj_equal)
- register_cfunc_method(Module, :==, :jit_rb_obj_equal)
- register_cfunc_method(Module, :===, :jit_rb_mod_eqq)
- register_cfunc_method(Symbol, :==, :jit_rb_obj_equal)
- register_cfunc_method(Symbol, :===, :jit_rb_obj_equal)
- register_cfunc_method(Integer, :==, :jit_rb_int_equal)
- register_cfunc_method(Integer, :===, :jit_rb_int_equal)
-
- # rb_str_to_s() methods in string.c
- register_cfunc_method(String, :empty?, :jit_rb_str_empty_p)
- register_cfunc_method(String, :to_s, :jit_rb_str_to_s)
- register_cfunc_method(String, :to_str, :jit_rb_str_to_s)
- register_cfunc_method(String, :bytesize, :jit_rb_str_bytesize)
- register_cfunc_method(String, :<<, :jit_rb_str_concat)
- register_cfunc_method(String, :+@, :jit_rb_str_uplus)
-
- # rb_ary_empty_p() method in array.c
- register_cfunc_method(Array, :empty?, :jit_rb_ary_empty_p)
-
- register_cfunc_method(Kernel, :respond_to?, :jit_obj_respond_to)
- register_cfunc_method(Kernel, :block_given?, :jit_rb_f_block_given_p)
-
- # Thread.current
- register_cfunc_method(C.rb_singleton_class(Thread), :current, :jit_thread_s_current)
-
- #---
- register_cfunc_method(Array, :<<, :jit_rb_ary_push)
- register_cfunc_method(Integer, :*, :jit_rb_int_mul)
- register_cfunc_method(Integer, :/, :jit_rb_int_div)
- register_cfunc_method(Integer, :[], :jit_rb_int_aref)
- register_cfunc_method(String, :getbyte, :jit_rb_str_getbyte)
- end
-
- def register_cfunc_method(klass, mid_sym, func)
- mid = C.rb_intern(mid_sym.to_s)
- me = C.rb_method_entry_at(klass, mid)
-
- assert_equal(false, me.nil?)
-
- # Only cfuncs are supported
- method_serial = me.def.method_serial
-
- @cfunc_codegen_table[method_serial] = method(func)
- end
-
- def lookup_cfunc_codegen(cme_def)
- @cfunc_codegen_table[cme_def.method_serial]
- end
-
- def stack_swap(_jit, ctx, asm, offset0, offset1)
- stack0_mem = ctx.stack_opnd(offset0)
- stack1_mem = ctx.stack_opnd(offset1)
-
- mapping0 = ctx.get_opnd_mapping(StackOpnd[offset0])
- mapping1 = ctx.get_opnd_mapping(StackOpnd[offset1])
-
- asm.mov(:rax, stack0_mem)
- asm.mov(:rcx, stack1_mem)
- asm.mov(stack0_mem, :rcx)
- asm.mov(stack1_mem, :rax)
-
- ctx.set_opnd_mapping(StackOpnd[offset0], mapping1)
- ctx.set_opnd_mapping(StackOpnd[offset1], mapping0)
- end
-
- def jit_getlocal_generic(jit, ctx, asm, idx:, level:)
- # Load environment pointer EP (level 0) from CFP
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Load the local from the block
- # val = *(vm_get_ep(GET_EP(), level) - idx);
- asm.mov(:rax, [ep_reg, -idx * C.VALUE.size])
-
- # Write the local at SP
- stack_top = if level == 0
- local_idx = ep_offset_to_local_idx(jit.iseq, idx)
- ctx.stack_push_local(local_idx)
- else
- ctx.stack_push(Type::Unknown)
- end
-
- asm.mov(stack_top, :rax)
- KeepCompiling
- end
-
- def jit_setlocal_generic(jit, ctx, asm, idx:, level:)
- value_type = ctx.get_opnd_type(StackOpnd[0])
-
- # Load environment pointer EP at level
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Write barriers may be required when VM_ENV_FLAG_WB_REQUIRED is set, however write barriers
- # only affect heap objects being written. If we know an immediate value is being written we
- # can skip this check.
- unless value_type.imm?
- # flags & VM_ENV_FLAG_WB_REQUIRED
- flags_opnd = [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS]
- asm.test(flags_opnd, C::VM_ENV_FLAG_WB_REQUIRED)
-
- # if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
- asm.jnz(side_exit(jit, ctx))
- end
-
- if level == 0
- local_idx = ep_offset_to_local_idx(jit.iseq, idx)
- ctx.set_local_type(local_idx, value_type)
- end
-
- # Pop the value to write from the stack
- stack_top = ctx.stack_pop(1)
-
- # Write the value at the environment pointer
- asm.mov(:rcx, stack_top)
- asm.mov([ep_reg, -(C.VALUE.size * idx)], :rcx)
-
- KeepCompiling
- end
-
- # Compute the index of a local variable from its slot index
- def ep_offset_to_local_idx(iseq, ep_offset)
- # Layout illustration
- # This is an array of VALUE
- # | VM_ENV_DATA_SIZE |
- # v v
- # low addr <+-------+-------+-------+-------+------------------+
- # |local 0|local 1| ... |local n| .... |
- # +-------+-------+-------+-------+------------------+
- # ^ ^ ^ ^
- # +-------+---local_table_size----+ cfp->ep--+
- # | |
- # +------------------ep_offset---------------+
- #
- # See usages of local_var_name() from iseq.c for similar calculation.
-
- # Equivalent of iseq->body->local_table_size
- local_table_size = iseq.body.local_table_size
- op = ep_offset - C::VM_ENV_DATA_SIZE
- local_idx = local_table_size - op - 1
- assert_equal(true, local_idx >= 0 && local_idx < local_table_size)
- local_idx
- end
-
- # Compute the index of a local variable from its slot index
- def slot_to_local_idx(iseq, slot_idx)
- # Layout illustration
- # This is an array of VALUE
- # | VM_ENV_DATA_SIZE |
- # v v
- # low addr <+-------+-------+-------+-------+------------------+
- # |local 0|local 1| ... |local n| .... |
- # +-------+-------+-------+-------+------------------+
- # ^ ^ ^ ^
- # +-------+---local_table_size----+ cfp->ep--+
- # | |
- # +------------------slot_idx----------------+
- #
- # See usages of local_var_name() from iseq.c for similar calculation.
-
- local_table_size = iseq.body.local_table_size
- op = slot_idx - C::VM_ENV_DATA_SIZE
- local_table_size - op - 1
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_object_is_heap(jit, ctx, asm, object, object_opnd, counter = nil)
- object_type = ctx.get_opnd_type(object_opnd)
- if object_type.heap?
- return
- end
-
- side_exit = side_exit(jit, ctx)
- side_exit = counted_exit(side_exit, counter) if counter
-
- asm.comment('guard object is heap')
- # Test that the object is not an immediate
- asm.test(object, C::RUBY_IMMEDIATE_MASK)
- asm.jnz(side_exit)
-
- # Test that the object is not false
- asm.cmp(object, Qfalse)
- asm.je(side_exit)
-
- if object_type.diff(Type::UnknownHeap) != TypeDiff::Incompatible
- ctx.upgrade_opnd_type(object_opnd, Type::UnknownHeap)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_object_is_array(jit, ctx, asm, object_reg, flags_reg, object_opnd, counter = nil)
- object_type = ctx.get_opnd_type(object_opnd)
- if object_type.array?
- return
- end
-
- guard_object_is_heap(jit, ctx, asm, object_reg, object_opnd, counter)
-
- side_exit = side_exit(jit, ctx)
- side_exit = counted_exit(side_exit, counter) if counter
-
- asm.comment('guard object is array')
- # Pull out the type mask
- asm.mov(flags_reg, [object_reg, C.RBasic.offsetof(:flags)])
- asm.and(flags_reg, C::RUBY_T_MASK)
-
- # Compare the result with T_ARRAY
- asm.cmp(flags_reg, C::RUBY_T_ARRAY)
- asm.jne(side_exit)
-
- if object_type.diff(Type::TArray) != TypeDiff::Incompatible
- ctx.upgrade_opnd_type(object_opnd, Type::TArray)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_object_is_string(jit, ctx, asm, object_reg, flags_reg, object_opnd, counter = nil)
- object_type = ctx.get_opnd_type(object_opnd)
- if object_type.string?
- return
- end
-
- guard_object_is_heap(jit, ctx, asm, object_reg, object_opnd, counter)
-
- side_exit = side_exit(jit, ctx)
- side_exit = counted_exit(side_exit, counter) if counter
-
- asm.comment('guard object is string')
- # Pull out the type mask
- asm.mov(flags_reg, [object_reg, C.RBasic.offsetof(:flags)])
- asm.and(flags_reg, C::RUBY_T_MASK)
-
- # Compare the result with T_STRING
- asm.cmp(flags_reg, C::RUBY_T_STRING)
- asm.jne(side_exit)
-
- if object_type.diff(Type::TString) != TypeDiff::Incompatible
- ctx.upgrade_opnd_type(object_opnd, Type::TString)
- end
- end
-
- # clobbers object_reg
- def guard_object_is_not_ruby2_keyword_hash(asm, object_reg, flags_reg, side_exit)
- asm.comment('guard object is not ruby2 keyword hash')
-
- not_ruby2_keyword = asm.new_label('not_ruby2_keyword')
- asm.test(object_reg, C::RUBY_IMMEDIATE_MASK)
- asm.jnz(not_ruby2_keyword)
-
- asm.cmp(object_reg, Qfalse)
- asm.je(not_ruby2_keyword)
-
- asm.mov(flags_reg, [object_reg, C.RBasic.offsetof(:flags)])
- type_reg = object_reg
- asm.mov(type_reg, flags_reg)
- asm.and(type_reg, C::RUBY_T_MASK)
-
- asm.cmp(type_reg, C::RUBY_T_HASH)
- asm.jne(not_ruby2_keyword)
-
- asm.test(flags_reg, C::RHASH_PASS_AS_KEYWORDS)
- asm.jnz(side_exit)
-
- asm.write_label(not_ruby2_keyword)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_chain_guard(opcode, jit, ctx, asm, side_exit, limit: 20)
- opcode => :je | :jne | :jnz | :jz
-
- if ctx.chain_depth < limit
- deeper = ctx.dup
- deeper.chain_depth += 1
-
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx: deeper, pc: jit.pc),
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(deeper, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.compile = proc do |branch_asm|
- # Not using `asm.comment` here since it's usually put before cmp/test before this.
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.public_send(opcode, branch_stub.target0.address)
- end
- end
- end
- branch_stub.compile.call(asm)
- else
- asm.public_send(opcode, side_exit)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_guard_known_klass(jit, ctx, asm, known_klass, obj_opnd, insn_opnd, comptime_obj, side_exit, limit: 10)
- # Only memory operand is supported for now
- assert_equal(true, obj_opnd.is_a?(Array))
-
- known_klass = C.to_value(known_klass)
- val_type = ctx.get_opnd_type(insn_opnd)
- if val_type.known_class == known_klass
- # We already know from type information that this is a match
- return
- end
-
- # Touching this as Ruby could crash for FrozenCore
- if known_klass == C.rb_cNilClass
- assert(!val_type.heap?)
- assert(val_type.unknown?)
-
- asm.comment('guard object is nil')
- asm.cmp(obj_opnd, Qnil)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::Nil)
- elsif known_klass == C.rb_cTrueClass
- assert(!val_type.heap?)
- assert(val_type.unknown?)
-
- asm.comment('guard object is true')
- asm.cmp(obj_opnd, Qtrue)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::True)
- elsif known_klass == C.rb_cFalseClass
- assert(!val_type.heap?)
- assert(val_type.unknown?)
-
- asm.comment('guard object is false')
- asm.cmp(obj_opnd, Qfalse)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::False)
- elsif known_klass == C.rb_cInteger && fixnum?(comptime_obj)
- # We will guard fixnum and bignum as though they were separate classes
- # BIGNUM can be handled by the general else case below
- assert(val_type.unknown?)
-
- asm.comment('guard object is fixnum')
- asm.test(obj_opnd, C::RUBY_FIXNUM_FLAG)
- jit_chain_guard(:jz, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::Fixnum)
- elsif known_klass == C.rb_cSymbol && static_symbol?(comptime_obj)
- assert(!val_type.heap?)
- # We will guard STATIC vs DYNAMIC as though they were separate classes
- # DYNAMIC symbols can be handled by the general else case below
- if val_type != Type::ImmSymbol || !val_type.imm?
- assert(val_type.unknown?)
-
- asm.comment('guard object is static symbol')
- assert_equal(8, C::RUBY_SPECIAL_SHIFT)
- asm.cmp(BytePtr[*obj_opnd], C::RUBY_SYMBOL_FLAG)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::ImmSymbol)
- end
- elsif known_klass == C.rb_cFloat && flonum?(comptime_obj)
- assert(!val_type.heap?)
- if val_type != Type::Flonum || !val_type.imm?
- assert(val_type.unknown?)
-
- # We will guard flonum vs heap float as though they were separate classes
- asm.comment('guard object is flonum')
- asm.mov(:rax, obj_opnd)
- asm.and(:rax, C::RUBY_FLONUM_MASK)
- asm.cmp(:rax, C::RUBY_FLONUM_FLAG)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::Flonum)
- end
- elsif C.FL_TEST(known_klass, C::RUBY_FL_SINGLETON) && comptime_obj == C.rb_class_attached_object(known_klass)
- # Singleton classes are attached to one specific object, so we can
- # avoid one memory access (and potentially the is_heap check) by
- # looking for the expected object directly.
- # Note that in case the sample instance has a singleton class that
- # doesn't attach to the sample instance, it means the sample instance
- # has an empty singleton class that hasn't been materialized yet. In
- # this case, comparing against the sample instance doesn't guarantee
- # that its singleton class is empty, so we can't avoid the memory
- # access. As an example, `Object.new.singleton_class` is an object in
- # this situation.
- asm.comment('guard known object with singleton class')
- asm.mov(:rax, to_value(comptime_obj))
- asm.cmp(obj_opnd, :rax)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
- elsif val_type == Type::CString && known_klass == C.rb_cString
- # guard elided because the context says we've already checked
- assert_equal(C.to_value(C.rb_class_of(comptime_obj)), C.rb_cString)
- else
- assert(!val_type.imm?)
-
- # Load memory to a register
- asm.mov(:rax, obj_opnd)
- obj_opnd = :rax
-
- # Check that the receiver is a heap object
- # Note: if we get here, the class doesn't have immediate instances.
- unless val_type.heap?
- asm.comment('guard not immediate')
- asm.test(obj_opnd, C::RUBY_IMMEDIATE_MASK)
- jit_chain_guard(:jnz, jit, ctx, asm, side_exit, limit:)
- asm.cmp(obj_opnd, Qfalse)
- jit_chain_guard(:je, jit, ctx, asm, side_exit, limit:)
- end
-
- # Bail if receiver class is different from known_klass
- klass_opnd = [obj_opnd, C.RBasic.offsetof(:klass)]
- asm.comment("guard known class #{known_klass}")
- asm.mov(:rcx, known_klass)
- asm.cmp(klass_opnd, :rcx)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- if known_klass == C.rb_cString
- # Upgrading to Type::CString here is incorrect.
- # The guard we put only checks RBASIC_CLASS(obj),
- # which adding a singleton class can change. We
- # additionally need to know the string is frozen
- # to claim Type::CString.
- ctx.upgrade_opnd_type(insn_opnd, Type::TString)
- elsif known_klass == C.rb_cArray
- ctx.upgrade_opnd_type(insn_opnd, Type::TArray)
- end
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- def two_fixnums_on_stack?(jit)
- comptime_recv = jit.peek_at_stack(1)
- comptime_arg = jit.peek_at_stack(0)
- return fixnum?(comptime_recv) && fixnum?(comptime_arg)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_two_fixnums(jit, ctx, asm)
- # Get stack operands without popping them
- arg1 = ctx.stack_opnd(0)
- arg0 = ctx.stack_opnd(1)
-
- # Get the stack operand types
- arg1_type = ctx.get_opnd_type(StackOpnd[0])
- arg0_type = ctx.get_opnd_type(StackOpnd[1])
-
- if arg0_type.heap? || arg1_type.heap?
- asm.comment('arg is heap object')
- asm.jmp(side_exit(jit, ctx))
- return
- end
-
- if arg0_type != Type::Fixnum && arg0_type.specific?
- asm.comment('arg0 not fixnum')
- asm.jmp(side_exit(jit, ctx))
- return
- end
-
- if arg1_type != Type::Fixnum && arg1_type.specific?
- asm.comment('arg1 not fixnum')
- asm.jmp(side_exit(jit, ctx))
- return
- end
-
- assert(!arg0_type.heap?)
- assert(!arg1_type.heap?)
- assert(arg0_type == Type::Fixnum || arg0_type.unknown?)
- assert(arg1_type == Type::Fixnum || arg1_type.unknown?)
-
- # If not fixnums at run-time, fall back
- if arg0_type != Type::Fixnum
- asm.comment('guard arg0 fixnum')
- asm.test(arg0, C::RUBY_FIXNUM_FLAG)
- jit_chain_guard(:jz, jit, ctx, asm, side_exit(jit, ctx))
- end
- if arg1_type != Type::Fixnum
- asm.comment('guard arg1 fixnum')
- asm.test(arg1, C::RUBY_FIXNUM_FLAG)
- jit_chain_guard(:jz, jit, ctx, asm, side_exit(jit, ctx))
- end
-
- # Set stack types in context
- ctx.upgrade_opnd_type(StackOpnd[0], Type::Fixnum)
- ctx.upgrade_opnd_type(StackOpnd[1], Type::Fixnum)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_fixnum_cmp(jit, ctx, asm, opcode:, bop:)
- opcode => :cmovl | :cmovle | :cmovg | :cmovge
-
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- if fixnum?(comptime_recv) && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, bop)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- obj_opnd = ctx.stack_pop
- recv_opnd = ctx.stack_pop
-
- asm.mov(:rax, obj_opnd)
- asm.cmp(recv_opnd, :rax)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.public_send(opcode, :rax, :rcx)
-
- dst_opnd = ctx.stack_push(Type::UnknownImm)
- asm.mov(dst_opnd, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_equality_specialized(jit, ctx, asm, gen_eq)
- # Create a side-exit to fall back to the interpreter
- side_exit = side_exit(jit, ctx)
-
- a_opnd = ctx.stack_opnd(1)
- b_opnd = ctx.stack_opnd(0)
-
- comptime_a = jit.peek_at_stack(1)
- comptime_b = jit.peek_at_stack(0)
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_EQ)
- return false
- end
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('check fixnum equality')
- asm.mov(:rax, a_opnd)
- asm.mov(:rcx, b_opnd)
- asm.cmp(:rax, :rcx)
- asm.mov(:rax, gen_eq ? Qfalse : Qtrue)
- asm.mov(:rcx, gen_eq ? Qtrue : Qfalse)
- asm.cmove(:rax, :rcx)
-
- # Push the output on the stack
- ctx.stack_pop(2)
- dst = ctx.stack_push(Type::UnknownImm)
- asm.mov(dst, :rax)
-
- true
- elsif C.rb_class_of(comptime_a) == String && C.rb_class_of(comptime_b) == String
- unless Invariants.assume_bop_not_redefined(jit, C::STRING_REDEFINED_OP_FLAG, C::BOP_EQ)
- # if overridden, emit the generic version
- return false
- end
-
- # Guard that a is a String
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_a), a_opnd, StackOpnd[1], comptime_a, side_exit)
-
- equal_label = asm.new_label(:equal)
- ret_label = asm.new_label(:ret)
-
- # If they are equal by identity, return true
- asm.mov(:rax, a_opnd)
- asm.mov(:rcx, b_opnd)
- asm.cmp(:rax, :rcx)
- asm.je(equal_label)
-
- # Otherwise guard that b is a T_STRING (from type info) or String (from runtime guard)
- btype = ctx.get_opnd_type(StackOpnd[0])
- unless btype.string?
- # Note: any T_STRING is valid here, but we check for a ::String for simplicity
- # To pass a mutable static variable (rb_cString) requires an unsafe block
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_b), b_opnd, StackOpnd[0], comptime_b, side_exit)
- end
-
- asm.comment('call rb_str_eql_internal')
- asm.mov(C_ARGS[0], a_opnd)
- asm.mov(C_ARGS[1], b_opnd)
- asm.call(gen_eq ? C.rb_str_eql_internal : C.rjit_str_neq_internal)
-
- # Push the output on the stack
- ctx.stack_pop(2)
- dst = ctx.stack_push(Type::UnknownImm)
- asm.mov(dst, C_RET)
- asm.jmp(ret_label)
-
- asm.write_label(equal_label)
- asm.mov(dst, gen_eq ? Qtrue : Qfalse)
-
- asm.write_label(ret_label)
-
- true
- else
- false
- end
- end
-
- # NOTE: This clobbers :rax
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_prepare_routine_call(jit, ctx, asm)
- jit.record_boundary_patch_point = true
- jit_save_pc(jit, asm)
- jit_save_sp(ctx, asm)
-
- # In case the routine calls Ruby methods, it can set local variables
- # through Kernel#binding and other means.
- ctx.clear_local_types
- end
-
- # NOTE: This clobbers :rax
- # @param jit [RubyVM::RJIT::JITState]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_save_pc(jit, asm, comment: 'save PC to CFP')
- next_pc = jit.pc + jit.insn.len * C.VALUE.size # Use the next one for backtrace and side exits
- asm.comment(comment)
- asm.mov(:rax, next_pc)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax)
- end
-
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_save_sp(ctx, asm)
- if ctx.sp_offset != 0
- asm.comment('save SP to CFP')
- asm.lea(SP, ctx.sp_opnd)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP)
- ctx.sp_offset = 0
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jump_to_next_insn(jit, ctx, asm)
- reset_depth = ctx.dup
- reset_depth.chain_depth = 0
-
- next_pc = jit.pc + jit.insn.len * C.VALUE.size
-
- # We are at the end of the current instruction. Record the boundary.
- if jit.record_boundary_patch_point
- exit_pos = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_side_exit(next_pc, ctx, ocb_asm)
- @ocb.write(ocb_asm)
- end
- Invariants.record_global_inval_patch(asm, exit_pos)
- jit.record_boundary_patch_point = false
- end
-
- jit_direct_jump(jit.iseq, next_pc, reset_depth, asm, comment: 'jump_to_next_insn')
- end
-
- # rb_vm_check_ints
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_check_ints(jit, ctx, asm)
- asm.comment('RUBY_VM_CHECK_INTS(ec)')
- asm.mov(:eax, DwordPtr[EC, C.rb_execution_context_t.offsetof(:interrupt_flag)])
- asm.test(:eax, :eax)
- asm.jnz(side_exit(jit, ctx))
- end
-
- # See get_lvar_level in compile.c
- def get_lvar_level(iseq)
- level = 0
- while iseq.to_i != iseq.body.local_iseq.to_i
- level += 1
- iseq = iseq.body.parent_iseq
- end
- return level
- end
-
- # GET_LEP
- # @param jit [RubyVM::RJIT::JITState]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_get_lep(jit, asm, reg:)
- level = get_lvar_level(jit.iseq)
- jit_get_ep(asm, level, reg:)
- end
-
- # vm_get_ep
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_get_ep(asm, level, reg:)
- asm.mov(reg, [CFP, C.rb_control_frame_t.offsetof(:ep)])
- level.times do
- # GET_PREV_EP: ep[VM_ENV_DATA_INDEX_SPECVAL] & ~0x03
- asm.mov(reg, [reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL])
- asm.and(reg, ~0x03)
- end
- end
-
- # vm_getivar
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_getivar(jit, ctx, asm, comptime_obj, ivar_id, obj_opnd, obj_yarv_opnd)
- side_exit = side_exit(jit, ctx)
- starting_ctx = ctx.dup # copy for jit_chain_guard
-
- # Guard not special const
- if C::SPECIAL_CONST_P(comptime_obj)
- asm.incr_counter(:getivar_special_const)
- return CantCompile
- end
-
- case C::BUILTIN_TYPE(comptime_obj)
- when C::T_OBJECT
- # This is the only supported case for now (ROBJECT_IVPTR)
- else
- # General case. Call rb_ivar_get().
- # VALUE rb_ivar_get(VALUE obj, ID id)
- asm.comment('call rb_ivar_get()')
- asm.mov(C_ARGS[0], obj_opnd ? obj_opnd : [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(C_ARGS[1], ivar_id)
-
- # The function could raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm) # clobbers obj_opnd and :rax
-
- asm.call(C.rb_ivar_get)
-
- if obj_opnd # attr_reader
- ctx.stack_pop
- end
-
- # Push the ivar on the stack
- out_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(out_opnd, C_RET)
-
- # Jump to next instruction. This allows guard chains to share the same successor.
- jump_to_next_insn(jit, ctx, asm)
- return EndBlock
- end
-
- asm.mov(:rax, obj_opnd ? obj_opnd : [CFP, C.rb_control_frame_t.offsetof(:self)])
- guard_object_is_heap(jit, ctx, asm, :rax, obj_yarv_opnd, :getivar_not_heap)
-
- shape_id = C.rb_shape_get_shape_id(comptime_obj)
- if shape_id == C::OBJ_TOO_COMPLEX_SHAPE_ID
- asm.incr_counter(:getivar_too_complex)
- return CantCompile
- end
-
- asm.comment('guard shape')
- asm.cmp(DwordPtr[:rax, C.rb_shape_id_offset], shape_id)
- jit_chain_guard(:jne, jit, starting_ctx, asm, counted_exit(side_exit, :getivar_megamorphic))
-
- if obj_opnd
- ctx.stack_pop # pop receiver for attr_reader
- end
-
- index = C.rb_shape_get_iv_index(shape_id, ivar_id)
- # If there is no IVAR index, then the ivar was undefined
- # when we entered the compiler. That means we can just return
- # nil for this shape + iv name
- if index.nil?
- stack_opnd = ctx.stack_push(Type::Nil)
- val_opnd = Qnil
- else
- asm.comment('ROBJECT_IVPTR')
- if C::FL_TEST_RAW(comptime_obj, C::ROBJECT_EMBED)
- # Access embedded array
- asm.mov(:rax, [:rax, C.RObject.offsetof(:as, :ary) + (index * C.VALUE.size)])
- else
- # Pull out an ivar table on heap
- asm.mov(:rax, [:rax, C.RObject.offsetof(:as, :heap, :ivptr)])
- # Read the table
- asm.mov(:rax, [:rax, index * C.VALUE.size])
- end
- stack_opnd = ctx.stack_push(Type::Unknown)
- val_opnd = :rax
- end
- asm.mov(stack_opnd, val_opnd)
-
- # Let guard chains share the same successor
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- def jit_write_iv(asm, comptime_receiver, recv_reg, temp_reg, ivar_index, set_value, needs_extension)
- # Compile time self is embedded and the ivar index lands within the object
- embed_test_result = C::FL_TEST_RAW(comptime_receiver, C::ROBJECT_EMBED) && !needs_extension
-
- if embed_test_result
- # Find the IV offset
- offs = C.RObject.offsetof(:as, :ary) + ivar_index * C.VALUE.size
-
- # Write the IV
- asm.comment('write IV')
- asm.mov(temp_reg, set_value)
- asm.mov([recv_reg, offs], temp_reg)
- else
- # Compile time value is *not* embedded.
-
- # Get a pointer to the extended table
- asm.mov(recv_reg, [recv_reg, C.RObject.offsetof(:as, :heap, :ivptr)])
-
- # Write the ivar in to the extended table
- asm.comment("write IV");
- asm.mov(temp_reg, set_value)
- asm.mov([recv_reg, C.VALUE.size * ivar_index], temp_reg)
- end
- end
-
- # vm_caller_setup_arg_block: Handle VM_CALL_ARGS_BLOCKARG cases.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_block_arg(jit, ctx, asm, calling)
- if calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0
- block_arg_type = ctx.get_opnd_type(StackOpnd[0])
- case block_arg_type
- in Type::Nil
- calling.block_handler = C::VM_BLOCK_HANDLER_NONE
- in Type::BlockParamProxy
- calling.block_handler = C.rb_block_param_proxy
- else
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
- end
- end
-
- # vm_search_method
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_search_method(jit, ctx, asm, mid, calling)
- assert_equal(true, jit.at_current_insn?)
-
- # Generate a side exit
- side_exit = side_exit(jit, ctx)
-
- # kw_splat is not supported yet
- if calling.flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_kw_splat)
- return CantCompile
- end
-
- # Get a compile-time receiver and its class
- recv_idx = calling.argc + (calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0 ? 1 : 0) # blockarg is not popped yet
- recv_idx += calling.send_shift
- comptime_recv = jit.peek_at_stack(recv_idx)
- comptime_recv_klass = C.rb_class_of(comptime_recv)
-
- # Guard the receiver class (part of vm_search_method_fastpath)
- recv_opnd = ctx.stack_opnd(recv_idx)
- megamorphic_exit = counted_exit(side_exit, :send_klass_megamorphic)
- jit_guard_known_klass(jit, ctx, asm, comptime_recv_klass, recv_opnd, StackOpnd[recv_idx], comptime_recv, megamorphic_exit)
-
- # Do method lookup (vm_cc_cme(cc) != NULL)
- cme = C.rb_callable_method_entry(comptime_recv_klass, mid)
- if cme.nil?
- asm.incr_counter(:send_missing_cme)
- return CantCompile # We don't support vm_call_method_name
- end
-
- # Invalidate on redefinition (part of vm_search_method_fastpath)
- Invariants.assume_method_lookup_stable(jit, cme)
-
- return cme, comptime_recv_klass
- end
-
- # vm_call_general
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_general(jit, ctx, asm, mid, calling, cme, known_recv_class)
- jit_call_method(jit, ctx, asm, mid, calling, cme, known_recv_class)
- end
-
- # vm_call_method
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- # @param send_shift [Integer] The number of shifts needed for VM_CALL_OPT_SEND
- def jit_call_method(jit, ctx, asm, mid, calling, cme, known_recv_class)
- # The main check of vm_call_method before vm_call_method_each_type
- case C::METHOD_ENTRY_VISI(cme)
- in C::METHOD_VISI_PUBLIC
- # You can always call public methods
- in C::METHOD_VISI_PRIVATE
- # Allow only callsites without a receiver
- if calling.flags & C::VM_CALL_FCALL == 0
- asm.incr_counter(:send_private)
- return CantCompile
- end
- in C::METHOD_VISI_PROTECTED
- # If the method call is an FCALL, it is always valid
- if calling.flags & C::VM_CALL_FCALL == 0
- # otherwise we need an ancestry check to ensure the receiver is valid to be called as protected
- jit_protected_callee_ancestry_guard(asm, cme, side_exit(jit, ctx))
- end
- end
-
- # Get a compile-time receiver
- recv_idx = calling.argc + (calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0 ? 1 : 0) # blockarg is not popped yet
- recv_idx += calling.send_shift
- comptime_recv = jit.peek_at_stack(recv_idx)
- recv_opnd = ctx.stack_opnd(recv_idx)
-
- jit_call_method_each_type(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- end
-
- # Generate ancestry guard for protected callee.
- # Calls to protected callees only go through when self.is_a?(klass_that_defines_the_callee).
- def jit_protected_callee_ancestry_guard(asm, cme, side_exit)
- # See vm_call_method().
- def_class = cme.defined_class
- # Note: PC isn't written to current control frame as rb_is_kind_of() shouldn't raise.
- # VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass);
-
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(C_ARGS[1], to_value(def_class))
- asm.call(C.rb_obj_is_kind_of)
- asm.test(C_RET, C_RET)
- asm.jz(counted_exit(side_exit, :send_protected_check_failed))
- end
-
- # vm_call_method_each_type
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_method_each_type(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- case cme.def.type
- in C::VM_METHOD_TYPE_ISEQ
- iseq = def_iseq_ptr(cme.def)
- jit_call_iseq(jit, ctx, asm, cme, calling, iseq)
- in C::VM_METHOD_TYPE_NOTIMPLEMENTED
- asm.incr_counter(:send_notimplemented)
- return CantCompile
- in C::VM_METHOD_TYPE_CFUNC
- jit_call_cfunc(jit, ctx, asm, cme, calling, known_recv_class:)
- in C::VM_METHOD_TYPE_ATTRSET
- jit_call_attrset(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- in C::VM_METHOD_TYPE_IVAR
- jit_call_ivar(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- in C::VM_METHOD_TYPE_MISSING
- asm.incr_counter(:send_missing)
- return CantCompile
- in C::VM_METHOD_TYPE_BMETHOD
- jit_call_bmethod(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- in C::VM_METHOD_TYPE_ALIAS
- jit_call_alias(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- in C::VM_METHOD_TYPE_OPTIMIZED
- jit_call_optimized(jit, ctx, asm, cme, calling, known_recv_class)
- in C::VM_METHOD_TYPE_UNDEF
- asm.incr_counter(:send_undef)
- return CantCompile
- in C::VM_METHOD_TYPE_ZSUPER
- asm.incr_counter(:send_zsuper)
- return CantCompile
- in C::VM_METHOD_TYPE_REFINED
- asm.incr_counter(:send_refined)
- return CantCompile
- end
- end
-
- # vm_call_iseq_setup
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_iseq(jit, ctx, asm, cme, calling, iseq, frame_type: nil, prev_ep: nil)
- argc = calling.argc
- flags = calling.flags
- send_shift = calling.send_shift
-
- # When you have keyword arguments, there is an extra object that gets
- # placed on the stack the represents a bitmap of the keywords that were not
- # specified at the call site. We need to keep track of the fact that this
- # value is present on the stack in order to properly set up the callee's
- # stack pointer.
- doing_kw_call = iseq.body.param.flags.has_kw
- supplying_kws = flags & C::VM_CALL_KWARG != 0
-
- if flags & C::VM_CALL_TAILCALL != 0
- # We can't handle tailcalls
- asm.incr_counter(:send_tailcall)
- return CantCompile
- end
-
- # No support for callees with these parameters yet as they require allocation
- # or complex handling.
- if iseq.body.param.flags.has_post
- asm.incr_counter(:send_iseq_has_opt)
- return CantCompile
- end
- if iseq.body.param.flags.has_kwrest
- asm.incr_counter(:send_iseq_has_kwrest)
- return CantCompile
- end
-
- # In order to handle backwards compatibility between ruby 3 and 2
- # ruby2_keywords was introduced. It is called only on methods
- # with splat and changes they way they handle them.
- # We are just going to not compile these.
- # https://www.rubydoc.info/stdlib/core/Proc:ruby2_keywords
- if iseq.body.param.flags.ruby2_keywords && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_iseq_ruby2_keywords)
- return CantCompile
- end
-
- iseq_has_rest = iseq.body.param.flags.has_rest
- if iseq_has_rest && calling.block_handler == :captured
- asm.incr_counter(:send_iseq_has_rest_and_captured)
- return CantCompile
- end
-
- if iseq_has_rest && iseq.body.param.flags.has_kw && supplying_kws
- asm.incr_counter(:send_iseq_has_rest_and_kw_supplied)
- return CantCompile
- end
-
- # If we have keyword arguments being passed to a callee that only takes
- # positionals, then we need to allocate a hash. For now we're going to
- # call that too complex and bail.
- if supplying_kws && !iseq.body.param.flags.has_kw
- asm.incr_counter(:send_iseq_has_no_kw)
- return CantCompile
- end
-
- # If we have a method accepting no kwargs (**nil), exit if we have passed
- # it any kwargs.
- if supplying_kws && iseq.body.param.flags.accepts_no_kwarg
- asm.incr_counter(:send_iseq_accepts_no_kwarg)
- return CantCompile
- end
-
- # For computing number of locals to set up for the callee
- num_params = iseq.body.param.size
-
- # Block parameter handling. This mirrors setup_parameters_complex().
- if iseq.body.param.flags.has_block
- if iseq.body.local_iseq.to_i == iseq.to_i
- num_params -= 1
- else
- # In this case (param.flags.has_block && local_iseq != iseq),
- # the block argument is setup as a local variable and requires
- # materialization (allocation). Bail.
- asm.incr_counter(:send_iseq_materialized_block)
- return CantCompile
- end
- end
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && flags & C::VM_CALL_ZSUPER != 0
- # zsuper methods are super calls without any arguments.
- # They are also marked as splat, but don't actually have an array
- # they pull arguments from, instead we need to change to call
- # a different method with the current stack.
- asm.incr_counter(:send_iseq_zsuper)
- return CantCompile
- end
-
- start_pc_offset = 0
- required_num = iseq.body.param.lead_num
-
- # This struct represents the metadata about the caller-specified
- # keyword arguments.
- kw_arg = calling.kwarg
- kw_arg_num = if kw_arg.nil?
- 0
- else
- kw_arg.keyword_len
- end
-
- # Arity handling and optional parameter setup
- opts_filled = argc - required_num - kw_arg_num
- opt_num = iseq.body.param.opt_num
- opts_missing = opt_num - opts_filled
-
- if doing_kw_call && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_iseq_splat_with_kw)
- return CantCompile
- end
-
- if iseq_has_rest && opt_num != 0
- asm.incr_counter(:send_iseq_has_rest_and_optional)
- return CantCompile
- end
-
- if opts_filled < 0 && flags & C::VM_CALL_ARGS_SPLAT == 0
- # Too few arguments and no splat to make up for it
- asm.incr_counter(:send_iseq_arity_error)
- return CantCompile
- end
-
- if opts_filled > opt_num && !iseq_has_rest
- # Too many arguments and no place to put them (i.e. rest arg)
- asm.incr_counter(:send_iseq_arity_error)
- return CantCompile
- end
-
- block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
-
- # Guard block_arg_type
- if guard_block_arg(jit, ctx, asm, calling) == CantCompile
- return CantCompile
- end
-
- # If we have unfilled optional arguments and keyword arguments then we
- # would need to adjust the arguments location to account for that.
- # For now we aren't handling this case.
- if doing_kw_call && opts_missing > 0
- asm.incr_counter(:send_iseq_missing_optional_kw)
- return CantCompile
- end
-
- # We will handle splat case later
- if opt_num > 0 && flags & C::VM_CALL_ARGS_SPLAT == 0
- num_params -= opts_missing
- start_pc_offset = iseq.body.param.opt_table[opts_filled]
- end
-
- if doing_kw_call
- # Here we're calling a method with keyword arguments and specifying
- # keyword arguments at this call site.
-
- # This struct represents the metadata about the callee-specified
- # keyword parameters.
- keyword = iseq.body.param.keyword
- keyword_num = keyword.num
- keyword_required_num = keyword.required_num
-
- required_kwargs_filled = 0
-
- if keyword_num > 30
- # We have so many keywords that (1 << num) encoded as a FIXNUM
- # (which shifts it left one more) no longer fits inside a 32-bit
- # immediate.
- asm.incr_counter(:send_iseq_too_many_kwargs)
- return CantCompile
- end
-
- # Check that the kwargs being passed are valid
- if supplying_kws
- # This is the list of keyword arguments that the callee specified
- # in its initial declaration.
- # SAFETY: see compile.c for sizing of this slice.
- callee_kwargs = keyword_num.times.map { |i| keyword.table[i] }
-
- # Here we're going to build up a list of the IDs that correspond to
- # the caller-specified keyword arguments. If they're not in the
- # same order as the order specified in the callee declaration, then
- # we're going to need to generate some code to swap values around
- # on the stack.
- caller_kwargs = []
- kw_arg.keyword_len.times do |kwarg_idx|
- sym = C.to_ruby(kw_arg[:keywords][kwarg_idx])
- caller_kwargs << C.rb_sym2id(sym)
- end
-
- # First, we're going to be sure that the names of every
- # caller-specified keyword argument correspond to a name in the
- # list of callee-specified keyword parameters.
- caller_kwargs.each do |caller_kwarg|
- search_result = callee_kwargs.map.with_index.find { |kwarg, _| kwarg == caller_kwarg }
-
- case search_result
- in nil
- # If the keyword was never found, then we know we have a
- # mismatch in the names of the keyword arguments, so we need to
- # bail.
- asm.incr_counter(:send_iseq_kwargs_mismatch)
- return CantCompile
- in _, callee_idx if callee_idx < keyword_required_num
- # Keep a count to ensure all required kwargs are specified
- required_kwargs_filled += 1
- else
- end
- end
- end
- assert_equal(true, required_kwargs_filled <= keyword_required_num)
- if required_kwargs_filled != keyword_required_num
- asm.incr_counter(:send_iseq_kwargs_mismatch)
- return CantCompile
- end
- end
-
- # Check if we need the arg0 splat handling of vm_callee_setup_block_arg
- arg_setup_block = (calling.block_handler == :captured) # arg_setup_type: arg_setup_block (invokeblock)
- block_arg0_splat = arg_setup_block && argc == 1 &&
- (iseq.body.param.flags.has_lead || opt_num > 1) &&
- !iseq.body.param.flags.ambiguous_param0
- if block_arg0_splat
- # If block_arg0_splat, we still need side exits after splat, but
- # doing push_splat_args here disallows it. So bail out.
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && !iseq_has_rest
- asm.incr_counter(:invokeblock_iseq_arg0_args_splat)
- return CantCompile
- end
- # The block_arg0_splat implementation is for the rb_simple_iseq_p case,
- # but doing_kw_call means it's not a simple ISEQ.
- if doing_kw_call
- asm.incr_counter(:invokeblock_iseq_arg0_has_kw)
- return CantCompile
- end
- # The block_arg0_splat implementation cannot deal with optional parameters.
- # This is a setup_parameters_complex() situation and interacts with the
- # starting position of the callee.
- if opt_num > 1
- asm.incr_counter(:invokeblock_iseq_arg0_optional)
- return CantCompile
- end
- end
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && !iseq_has_rest
- array = jit.peek_at_stack(block_arg ? 1 : 0)
- splat_array_length = if array.nil?
- 0
- else
- array.length
- end
-
- if opt_num == 0 && required_num != splat_array_length + argc - 1
- asm.incr_counter(:send_iseq_splat_arity_error)
- return CantCompile
- end
- end
-
- # We will not have CantCompile from here.
-
- if block_arg
- ctx.stack_pop(1)
- end
-
- if calling.block_handler == C::VM_BLOCK_HANDLER_NONE && iseq.body.builtin_attrs & C::BUILTIN_ATTR_LEAF != 0
- if jit_leaf_builtin_func(jit, ctx, asm, flags, iseq)
- return KeepCompiling
- end
- end
-
- # Number of locals that are not parameters
- num_locals = iseq.body.local_table_size - num_params
-
- # Stack overflow check
- # Note that vm_push_frame checks it against a decremented cfp, hence the multiply by 2.
- # #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
- asm.comment('stack overflow check')
- locals_offs = C.VALUE.size * (num_locals + iseq.body.stack_max) + 2 * C.rb_control_frame_t.size
- asm.lea(:rax, ctx.sp_opnd(locals_offs))
- asm.cmp(CFP, :rax)
- asm.jbe(counted_exit(side_exit(jit, ctx), :send_stackoverflow))
-
- # push_splat_args does stack manipulation so we can no longer side exit
- if splat_array_length
- remaining_opt = (opt_num + required_num) - (splat_array_length + (argc - 1))
-
- if opt_num > 0
- # We are going to jump to the correct offset based on how many optional
- # params are remaining.
- offset = opt_num - remaining_opt
- start_pc_offset = iseq.body.param.opt_table[offset]
- end
- # We are going to assume that the splat fills
- # all the remaining arguments. In the generated code
- # we test if this is true and if not side exit.
- argc = argc - 1 + splat_array_length + remaining_opt
- push_splat_args(splat_array_length, jit, ctx, asm)
-
- remaining_opt.times do
- # We need to push nil for the optional arguments
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, Qnil)
- end
- end
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- if iseq_has_rest
- # We are going to allocate so setting pc and sp.
- jit_save_pc(jit, asm) # clobbers rax
- jit_save_sp(ctx, asm)
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- non_rest_arg_count = argc - 1
- # We start by dupping the array because someone else might have
- # a reference to it.
- array = ctx.stack_pop(1)
- asm.mov(C_ARGS[0], array)
- asm.call(C.rb_ary_dup)
- array = C_RET
- if non_rest_arg_count > required_num
- # If we have more arguments than required, we need to prepend
- # the items from the stack onto the array.
- diff = (non_rest_arg_count - required_num)
-
- # diff is >0 so no need to worry about null pointer
- asm.comment('load pointer to array elements')
- offset_magnitude = C.VALUE.size * diff
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- values_ptr = :rcx
- asm.lea(values_ptr, values_opnd)
-
- asm.comment('prepend stack values to rest array')
- asm.mov(C_ARGS[0], diff)
- asm.mov(C_ARGS[1], values_ptr)
- asm.mov(C_ARGS[2], array)
- asm.call(C.rb_ary_unshift_m)
- ctx.stack_pop(diff)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
- # We now should have the required arguments
- # and an array of all the rest arguments
- argc = required_num + 1
- elsif non_rest_arg_count < required_num
- # If we have fewer arguments than required, we need to take some
- # from the array and move them to the stack.
- diff = (required_num - non_rest_arg_count)
- # This moves the arguments onto the stack. But it doesn't modify the array.
- move_rest_args_to_stack(array, diff, jit, ctx, asm)
-
- # We will now slice the array to give us a new array of the correct size
- asm.mov(C_ARGS[0], array)
- asm.mov(C_ARGS[1], diff)
- asm.call(C.rjit_rb_ary_subseq_length)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- # We now should have the required arguments
- # and an array of all the rest arguments
- argc = required_num + 1
- else
- # The arguments are equal so we can just push to the stack
- assert_equal(non_rest_arg_count, required_num)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, array)
- end
- else
- assert_equal(true, argc >= required_num)
- n = (argc - required_num)
- argc = required_num + 1
- # If n is 0, then elts is never going to be read, so we can just pass null
- if n == 0
- values_ptr = 0
- else
- asm.comment('load pointer to array elements')
- offset_magnitude = C.VALUE.size * n
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- values_ptr = :rcx
- asm.lea(values_ptr, values_opnd)
- end
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], n)
- asm.mov(C_ARGS[2], values_ptr)
- asm.call(C.rb_ec_ary_new_from_values)
-
- ctx.stack_pop(n)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
- end
- end
-
- if doing_kw_call
- # Here we're calling a method with keyword arguments and specifying
- # keyword arguments at this call site.
-
- # Number of positional arguments the callee expects before the first
- # keyword argument
- args_before_kw = required_num + opt_num
-
- # This struct represents the metadata about the caller-specified
- # keyword arguments.
- ci_kwarg = calling.kwarg
- caller_keyword_len = if ci_kwarg.nil?
- 0
- else
- ci_kwarg.keyword_len
- end
-
- # This struct represents the metadata about the callee-specified
- # keyword parameters.
- keyword = iseq.body.param.keyword
-
- asm.comment('keyword args')
-
- # This is the list of keyword arguments that the callee specified
- # in its initial declaration.
- callee_kwargs = keyword.table
- total_kwargs = keyword.num
-
- # Here we're going to build up a list of the IDs that correspond to
- # the caller-specified keyword arguments. If they're not in the
- # same order as the order specified in the callee declaration, then
- # we're going to need to generate some code to swap values around
- # on the stack.
- caller_kwargs = []
-
- caller_keyword_len.times do |kwarg_idx|
- sym = C.to_ruby(ci_kwarg[:keywords][kwarg_idx])
- caller_kwargs << C.rb_sym2id(sym)
- end
- kwarg_idx = caller_keyword_len
-
- unspecified_bits = 0
-
- keyword_required_num = keyword.required_num
- (keyword_required_num...total_kwargs).each do |callee_idx|
- already_passed = false
- callee_kwarg = callee_kwargs[callee_idx]
-
- caller_keyword_len.times do |caller_idx|
- if caller_kwargs[caller_idx] == callee_kwarg
- already_passed = true
- break
- end
- end
-
- unless already_passed
- # Reserve space on the stack for each default value we'll be
- # filling in (which is done in the next loop). Also increments
- # argc so that the callee's SP is recorded correctly.
- argc += 1
- default_arg = ctx.stack_push(Type::Unknown)
-
- # callee_idx - keyword->required_num is used in a couple of places below.
- req_num = keyword.required_num
- extra_args = callee_idx - req_num
-
- # VALUE default_value = keyword->default_values[callee_idx - keyword->required_num];
- default_value = keyword.default_values[extra_args]
-
- if default_value == Qundef
- # Qundef means that this value is not constant and must be
- # recalculated at runtime, so we record it in unspecified_bits
- # (Qnil is then used as a placeholder instead of Qundef).
- unspecified_bits |= 0x01 << extra_args
- default_value = Qnil
- end
-
- asm.mov(:rax, default_value)
- asm.mov(default_arg, :rax)
-
- caller_kwargs[kwarg_idx] = callee_kwarg
- kwarg_idx += 1
- end
- end
-
- assert_equal(kwarg_idx, total_kwargs)
-
- # Next, we're going to loop through every keyword that was
- # specified by the caller and make sure that it's in the correct
- # place. If it's not we're going to swap it around with another one.
- total_kwargs.times do |kwarg_idx|
- callee_kwarg = callee_kwargs[kwarg_idx]
-
- # If the argument is already in the right order, then we don't
- # need to generate any code since the expected value is already
- # in the right place on the stack.
- if callee_kwarg == caller_kwargs[kwarg_idx]
- next
- end
-
- # In this case the argument is not in the right place, so we
- # need to find its position where it _should_ be and swap with
- # that location.
- ((kwarg_idx + 1)...total_kwargs).each do |swap_idx|
- if callee_kwarg == caller_kwargs[swap_idx]
- # First we're going to generate the code that is going
- # to perform the actual swapping at runtime.
- offset0 = argc - 1 - swap_idx - args_before_kw
- offset1 = argc - 1 - kwarg_idx - args_before_kw
- stack_swap(jit, ctx, asm, offset0, offset1)
-
- # Next we're going to do some bookkeeping on our end so
- # that we know the order that the arguments are
- # actually in now.
- caller_kwargs[kwarg_idx], caller_kwargs[swap_idx] =
- caller_kwargs[swap_idx], caller_kwargs[kwarg_idx]
-
- break
- end
- end
- end
-
- # Keyword arguments cause a special extra local variable to be
- # pushed onto the stack that represents the parameters that weren't
- # explicitly given a value and have a non-constant default.
- asm.mov(ctx.stack_opnd(-1), C.to_value(unspecified_bits))
- end
-
- # Same as vm_callee_setup_block_arg_arg0_check and vm_callee_setup_block_arg_arg0_splat
- # on vm_callee_setup_block_arg for arg_setup_block. This is done after CALLER_SETUP_ARG
- # and CALLER_REMOVE_EMPTY_KW_SPLAT, so this implementation is put here. This may need
- # side exits, so you still need to allow side exits here if block_arg0_splat is true.
- # Note that you can't have side exits after this arg0 splat.
- if block_arg0_splat
- asm.incr_counter(:send_iseq_block_arg0_splat)
- return CantCompile
- end
-
- # Create a context for the callee
- callee_ctx = Context.new
-
- # Set the argument types in the callee's context
- argc.times do |arg_idx|
- stack_offs = argc - arg_idx - 1
- arg_type = ctx.get_opnd_type(StackOpnd[stack_offs])
- callee_ctx.set_local_type(arg_idx, arg_type)
- end
-
- recv_type = if calling.block_handler == :captured
- Type::Unknown # we don't track the type information of captured->self for now
- else
- ctx.get_opnd_type(StackOpnd[argc])
- end
- callee_ctx.upgrade_opnd_type(SelfOpnd, recv_type)
-
- # Setup the new frame
- frame_type ||= C::VM_FRAME_MAGIC_METHOD | C::VM_ENV_FLAG_LOCAL
- jit_push_frame(
- jit, ctx, asm, cme, flags, argc, frame_type, calling.block_handler,
- iseq: iseq,
- local_size: num_locals,
- stack_max: iseq.body.stack_max,
- prev_ep:,
- doing_kw_call:,
- )
-
- # Directly jump to the entry point of the callee
- pc = (iseq.body.iseq_encoded + start_pc_offset).to_i
- jit_direct_jump(iseq, pc, callee_ctx, asm)
-
- EndBlock
- end
-
- def jit_leaf_builtin_func(jit, ctx, asm, flags, iseq)
- builtin_func = builtin_function(iseq)
- if builtin_func.nil?
- return false
- end
-
- # this is a .send call not currently supported for builtins
- if flags & C::VM_CALL_OPT_SEND != 0
- return false
- end
-
- builtin_argc = builtin_func.argc
- if builtin_argc + 1 >= C_ARGS.size
- return false
- end
-
- asm.comment('inlined leaf builtin')
-
- # Skip this if it doesn't trigger GC
- if iseq.body.builtin_attrs & C::BUILTIN_ATTR_NO_GC == 0
- # The callee may allocate, e.g. Integer#abs on a Bignum.
- # Save SP for GC, save PC for allocation tracing, and prepare
- # for global invalidation after GC's VM lock contention.
- jit_prepare_routine_call(jit, ctx, asm)
- end
-
- # Call the builtin func (ec, recv, arg1, arg2, ...)
- asm.mov(C_ARGS[0], EC)
-
- # Copy self and arguments
- (0..builtin_argc).each do |i|
- stack_opnd = ctx.stack_opnd(builtin_argc - i)
- asm.mov(C_ARGS[i + 1], stack_opnd)
- end
- ctx.stack_pop(builtin_argc + 1)
- asm.call(builtin_func.func_ptr)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
- return true
- end
-
- # vm_call_cfunc
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_cfunc(jit, ctx, asm, cme, calling, known_recv_class: nil)
- argc = calling.argc
- flags = calling.flags
-
- cfunc = cme.def.body.cfunc
- cfunc_argc = cfunc.argc
-
- # If the function expects a Ruby array of arguments
- if cfunc_argc < 0 && cfunc_argc != -1
- asm.incr_counter(:send_cfunc_ruby_array_varg)
- return CantCompile
- end
-
- # We aren't handling a vararg cfuncs with splat currently.
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && cfunc_argc == -1
- asm.incr_counter(:send_args_splat_cfunc_var_args)
- return CantCompile
- end
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && flags & C::VM_CALL_ZSUPER != 0
- # zsuper methods are super calls without any arguments.
- # They are also marked as splat, but don't actually have an array
- # they pull arguments from, instead we need to change to call
- # a different method with the current stack.
- asm.incr_counter(:send_args_splat_cfunc_zuper)
- return CantCompile;
- end
-
- # In order to handle backwards compatibility between ruby 3 and 2
- # ruby2_keywords was introduced. It is called only on methods
- # with splat and changes they way they handle them.
- # We are just going to not compile these.
- # https://docs.ruby-lang.org/en/3.2/Module.html#method-i-ruby2_keywords
- if jit.iseq.body.param.flags.ruby2_keywords && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_args_splat_cfunc_ruby2_keywords)
- return CantCompile;
- end
-
- kw_arg = calling.kwarg
- kw_arg_num = if kw_arg.nil?
- 0
- else
- kw_arg.keyword_len
- end
-
- if kw_arg_num != 0 && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_cfunc_splat_with_kw)
- return CantCompile
- end
-
- if c_method_tracing_currently_enabled?
- # Don't JIT if tracing c_call or c_return
- asm.incr_counter(:send_cfunc_tracing)
- return CantCompile
- end
-
- # Delegate to codegen for C methods if we have it.
- if kw_arg.nil? && flags & C::VM_CALL_OPT_SEND == 0 && flags & C::VM_CALL_ARGS_SPLAT == 0 && (cfunc_argc == -1 || argc == cfunc_argc)
- known_cfunc_codegen = lookup_cfunc_codegen(cme.def)
- if known_cfunc_codegen&.call(jit, ctx, asm, argc, known_recv_class)
- # cfunc codegen generated code. Terminate the block so
- # there isn't multiple calls in the same block.
- jump_to_next_insn(jit, ctx, asm)
- return EndBlock
- end
- end
-
- # Check for interrupts
- jit_check_ints(jit, ctx, asm)
-
- # Stack overflow check
- # #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
- # REG_CFP <= REG_SP + 4 * SIZEOF_VALUE + sizeof(rb_control_frame_t)
- asm.comment('stack overflow check')
- asm.lea(:rax, ctx.sp_opnd(C.VALUE.size * 4 + 2 * C.rb_control_frame_t.size))
- asm.cmp(CFP, :rax)
- asm.jbe(counted_exit(side_exit(jit, ctx), :send_stackoverflow))
-
- # Number of args which will be passed through to the callee
- # This is adjusted by the kwargs being combined into a hash.
- passed_argc = if kw_arg.nil?
- argc
- else
- argc - kw_arg_num + 1
- end
-
- # If the argument count doesn't match
- if cfunc_argc >= 0 && cfunc_argc != passed_argc && flags & C::VM_CALL_ARGS_SPLAT == 0
- asm.incr_counter(:send_cfunc_argc_mismatch)
- return CantCompile
- end
-
- # Don't JIT functions that need C stack arguments for now
- if cfunc_argc >= 0 && passed_argc + 1 > C_ARGS.size
- asm.incr_counter(:send_cfunc_toomany_args)
- return CantCompile
- end
-
- block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
-
- # Guard block_arg_type
- if guard_block_arg(jit, ctx, asm, calling) == CantCompile
- return CantCompile
- end
-
- if block_arg
- ctx.stack_pop(1)
- end
-
- # push_splat_args does stack manipulation so we can no longer side exit
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- assert_equal(true, cfunc_argc >= 0)
- required_args = cfunc_argc - (argc - 1)
- # + 1 because we pass self
- if required_args + 1 >= C_ARGS.size
- asm.incr_counter(:send_cfunc_toomany_args)
- return CantCompile
- end
-
- # We are going to assume that the splat fills
- # all the remaining arguments. So the number of args
- # should just equal the number of args the cfunc takes.
- # In the generated code we test if this is true
- # and if not side exit.
- argc = cfunc_argc
- passed_argc = argc
- push_splat_args(required_args, jit, ctx, asm)
- end
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift: calling.send_shift)
- end
-
- # Points to the receiver operand on the stack
-
- # Store incremented PC into current control frame in case callee raises.
- jit_save_pc(jit, asm)
-
- # Increment the stack pointer by 3 (in the callee)
- # sp += 3
-
- frame_type = C::VM_FRAME_MAGIC_CFUNC | C::VM_FRAME_FLAG_CFRAME | C::VM_ENV_FLAG_LOCAL
- if kw_arg
- frame_type |= C::VM_FRAME_FLAG_CFRAME_KW
- end
-
- jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, calling.block_handler)
-
- if kw_arg
- # Build a hash from all kwargs passed
- asm.comment('build_kwhash')
- imemo_ci = calling.ci_addr
- # we assume all callinfos with kwargs are on the GC heap
- assert_equal(true, C.imemo_type_p(imemo_ci, C.imemo_callinfo))
- asm.mov(C_ARGS[0], imemo_ci)
- asm.lea(C_ARGS[1], ctx.sp_opnd(0))
- asm.call(C.rjit_build_kwhash)
-
- # Replace the stack location at the start of kwargs with the new hash
- stack_opnd = ctx.stack_opnd(argc - passed_argc)
- asm.mov(stack_opnd, C_RET)
- end
-
- # Copy SP because REG_SP will get overwritten
- sp = :rax
- asm.lea(sp, ctx.sp_opnd(0))
-
- # Pop the C function arguments from the stack (in the caller)
- ctx.stack_pop(argc + 1)
-
- # Write interpreter SP into CFP.
- # Needed in case the callee yields to the block.
- jit_save_sp(ctx, asm)
-
- # Non-variadic method
- case cfunc_argc
- in (0..) # Non-variadic method
- # Copy the arguments from the stack to the C argument registers
- # self is the 0th argument and is at index argc from the stack top
- (0..passed_argc).each do |i|
- asm.mov(C_ARGS[i], [sp, -(argc + 1 - i) * C.VALUE.size])
- end
- in -1 # Variadic method: rb_f_puts(int argc, VALUE *argv, VALUE recv)
- # The method gets a pointer to the first argument
- # rb_f_puts(int argc, VALUE *argv, VALUE recv)
- asm.mov(C_ARGS[0], passed_argc)
- asm.lea(C_ARGS[1], [sp, -argc * C.VALUE.size]) # argv
- asm.mov(C_ARGS[2], [sp, -(argc + 1) * C.VALUE.size]) # recv
- end
-
- # Call the C function
- # VALUE ret = (cfunc->func)(recv, argv[0], argv[1]);
- # cfunc comes from compile-time cme->def, which we assume to be stable.
- # Invalidation logic is in yjit_method_lookup_change()
- asm.comment('call C function')
- asm.mov(:rax, cfunc.func)
- asm.call(:rax) # TODO: use rel32 if close enough
-
- # Record code position for TracePoint patching. See full_cfunc_return().
- Invariants.record_global_inval_patch(asm, full_cfunc_return)
-
- # Push the return value on the Ruby stack
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # Pop the stack frame (ec->cfp++)
- # Instead of recalculating, we can reuse the previous CFP, which is stored in a callee-saved
- # register
- asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], CFP)
-
- # cfunc calls may corrupt types
- ctx.clear_local_types
-
- # Note: the return block of jit_call_iseq has ctx->sp_offset == 1
- # which allows for sharing the same successor.
-
- # Jump (fall through) to the call continuation block
- # We do this to end the current block after the call
- assert_equal(1, ctx.sp_offset)
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- # vm_call_attrset
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_attrset(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- argc = calling.argc
- flags = calling.flags
- send_shift = calling.send_shift
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_attrset_splat)
- return CantCompile
- end
- if flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_attrset_kwarg)
- return CantCompile
- elsif argc != 1 || !C.RB_TYPE_P(comptime_recv, C::RUBY_T_OBJECT)
- asm.incr_counter(:send_attrset_method)
- return CantCompile
- elsif c_method_tracing_currently_enabled?
- # Can't generate code for firing c_call and c_return events
- # See :attr-tracing:
- asm.incr_counter(:send_c_tracingg)
- return CantCompile
- elsif flags & C::VM_CALL_ARGS_BLOCKARG != 0
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- ivar_name = cme.def.body.attr.id
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- val_opnd = ctx.stack_pop(1)
- recv_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_set_ivar_id with the receiver, the ivar name, and the value
- asm.mov(C_ARGS[0], recv_opnd)
- asm.mov(C_ARGS[1], ivar_name)
- asm.mov(C_ARGS[2], val_opnd)
- asm.call(C.rb_vm_set_ivar_id)
-
- out_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(out_opnd, C_RET)
-
- KeepCompiling
- end
-
- # vm_call_ivar (+ part of vm_call_method_each_type)
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_ivar(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- argc = calling.argc
- flags = calling.flags
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_ivar_splat)
- return CantCompile
- end
-
- if argc != 0
- asm.incr_counter(:send_arity)
- return CantCompile
- end
-
- # We don't support handle_opt_send_shift_stack for this yet.
- if flags & C::VM_CALL_OPT_SEND != 0
- asm.incr_counter(:send_ivar_opt_send)
- return CantCompile
- end
-
- ivar_id = cme.def.body.attr.id
-
- # Not handling block_handler
- if flags & C::VM_CALL_ARGS_BLOCKARG != 0
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- jit_getivar(jit, ctx, asm, comptime_recv, ivar_id, recv_opnd, StackOpnd[0])
- end
-
- # vm_call_bmethod
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_bmethod(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- proc_addr = cme.def.body.bmethod.proc
-
- proc_t = C.rb_yjit_get_proc_ptr(proc_addr)
- proc_block = proc_t.block
-
- if proc_block.type != C.block_type_iseq
- asm.incr_counter(:send_bmethod_not_iseq)
- return CantCompile
- end
-
- capture = proc_block.as.captured
- iseq = capture.code.iseq
-
- # TODO: implement this
- # Optimize for single ractor mode and avoid runtime check for
- # "defined with an un-shareable Proc in a different Ractor"
- # if !assume_single_ractor_mode(jit, ocb)
- # return CantCompile;
- # end
-
- # Passing a block to a block needs logic different from passing
- # a block to a method and sometimes requires allocation. Bail for now.
- if calling.block_handler != C::VM_BLOCK_HANDLER_NONE
- asm.incr_counter(:send_bmethod_blockarg)
- return CantCompile
- end
-
- jit_call_iseq(
- jit, ctx, asm, cme, calling, iseq,
- frame_type: C::VM_FRAME_MAGIC_BLOCK | C::VM_FRAME_FLAG_BMETHOD | C::VM_FRAME_FLAG_LAMBDA,
- prev_ep: capture.ep,
- )
- end
-
- # vm_call_alias
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_alias(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- cme = C.rb_aliased_callable_method_entry(cme)
- jit_call_method_each_type(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- end
-
- # vm_call_optimized
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_optimized(jit, ctx, asm, cme, calling, known_recv_class)
- if calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0
- # Not working yet
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- case cme.def.body.optimized.type
- in C::OPTIMIZED_METHOD_TYPE_SEND
- jit_call_opt_send(jit, ctx, asm, cme, calling, known_recv_class)
- in C::OPTIMIZED_METHOD_TYPE_CALL
- jit_call_opt_call(jit, ctx, asm, cme, calling.flags, calling.argc, calling.block_handler, known_recv_class, send_shift: calling.send_shift)
- in C::OPTIMIZED_METHOD_TYPE_BLOCK_CALL
- asm.incr_counter(:send_optimized_block_call)
- return CantCompile
- in C::OPTIMIZED_METHOD_TYPE_STRUCT_AREF
- jit_call_opt_struct_aref(jit, ctx, asm, cme, calling.flags, calling.argc, calling.block_handler, known_recv_class, send_shift: calling.send_shift)
- in C::OPTIMIZED_METHOD_TYPE_STRUCT_ASET
- asm.incr_counter(:send_optimized_struct_aset)
- return CantCompile
- end
- end
-
- # vm_call_opt_send
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_opt_send(jit, ctx, asm, cme, calling, known_recv_class)
- if jit_caller_setup_arg(jit, ctx, asm, calling.flags) == CantCompile
- return CantCompile
- end
-
- if calling.argc == 0
- asm.incr_counter(:send_optimized_send_no_args)
- return CantCompile
- end
-
- calling.argc -= 1
- # We aren't handling `send(:send, ...)` yet. This might work, but not tested yet.
- if calling.send_shift > 0
- asm.incr_counter(:send_optimized_send_send)
- return CantCompile
- end
- # Lazily handle stack shift in handle_opt_send_shift_stack
- calling.send_shift += 1
-
- jit_call_symbol(jit, ctx, asm, cme, calling, known_recv_class, C::VM_CALL_FCALL)
- end
-
- # vm_call_opt_call
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_opt_call(jit, ctx, asm, cme, flags, argc, block_handler, known_recv_class, send_shift:)
- if block_handler != C::VM_BLOCK_HANDLER_NONE
- asm.incr_counter(:send_optimized_call_block)
- return CantCompile
- end
-
- if flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_optimized_call_kwarg)
- return CantCompile
- end
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_optimized_call_splat)
- return CantCompile
- end
-
- # TODO: implement this
- # Optimize for single ractor mode and avoid runtime check for
- # "defined with an un-shareable Proc in a different Ractor"
- # if !assume_single_ractor_mode(jit, ocb)
- # return CantCompile
- # end
-
- # If this is a .send call we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- # About to reset the SP, need to load this here
- recv_idx = argc # blockarg is not supported. send_shift is already handled.
- asm.mov(:rcx, ctx.stack_opnd(recv_idx)) # recv
-
- # Save the PC and SP because the callee can make Ruby calls
- jit_prepare_routine_call(jit, ctx, asm) # NOTE: clobbers rax
-
- asm.lea(:rax, ctx.sp_opnd(0)) # sp
-
- kw_splat = flags & C::VM_CALL_KW_SPLAT
-
- asm.mov(C_ARGS[0], :rcx)
- asm.mov(C_ARGS[1], EC)
- asm.mov(C_ARGS[2], argc)
- asm.lea(C_ARGS[3], [:rax, -argc * C.VALUE.size]) # stack_argument_pointer. NOTE: C_ARGS[3] is rcx
- asm.mov(C_ARGS[4], kw_splat)
- asm.mov(C_ARGS[5], C::VM_BLOCK_HANDLER_NONE)
- asm.call(C.rjit_optimized_call)
-
- ctx.stack_pop(argc + 1)
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
- return KeepCompiling
- end
-
- # vm_call_opt_struct_aref
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_opt_struct_aref(jit, ctx, asm, cme, flags, argc, block_handler, known_recv_class, send_shift:)
- if argc != 0
- asm.incr_counter(:send_optimized_struct_aref_error)
- return CantCompile
- end
-
- off = cme.def.body.optimized.index
-
- recv_idx = argc # blockarg is not supported
- recv_idx += send_shift
- comptime_recv = jit.peek_at_stack(recv_idx)
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- # All structs from the same Struct class should have the same
- # length. So if our comptime_recv is embedded all runtime
- # structs of the same class should be as well, and the same is
- # true of the converse.
- embedded = C::FL_TEST_RAW(comptime_recv, C::RSTRUCT_EMBED_LEN_MASK)
-
- asm.comment('struct aref')
- asm.mov(:rax, ctx.stack_pop(1)) # recv
-
- if embedded
- asm.mov(:rax, [:rax, C.RStruct.offsetof(:as, :ary) + (C.VALUE.size * off)])
- else
- asm.mov(:rax, [:rax, C.RStruct.offsetof(:as, :heap, :ptr)])
- asm.mov(:rax, [:rax, C.VALUE.size * off])
- end
-
- ret = ctx.stack_push(Type::Unknown)
- asm.mov(ret, :rax)
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- # vm_call_opt_send (lazy part)
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- # We don't support `send(:send, ...)` for now.
- assert_equal(1, send_shift)
-
- asm.comment('shift stack')
- (0...argc).reverse_each do |i|
- opnd = ctx.stack_opnd(i)
- opnd2 = ctx.stack_opnd(i + 1)
- asm.mov(:rax, opnd)
- asm.mov(opnd2, :rax)
- end
-
- ctx.shift_stack(argc)
- end
-
- # vm_call_symbol
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_symbol(jit, ctx, asm, cme, calling, known_recv_class, flags)
- flags |= C::VM_CALL_OPT_SEND | (calling.kw_splat ? C::VM_CALL_KW_SPLAT : 0)
-
- comptime_symbol = jit.peek_at_stack(calling.argc)
- if comptime_symbol.class != String && !static_symbol?(comptime_symbol)
- asm.incr_counter(:send_optimized_send_not_sym_or_str)
- return CantCompile
- end
-
- mid = C.get_symbol_id(comptime_symbol)
- if mid == 0
- asm.incr_counter(:send_optimized_send_null_mid)
- return CantCompile
- end
-
- asm.comment("Guard #{comptime_symbol.inspect} is on stack")
- class_changed_exit = counted_exit(side_exit(jit, ctx), :send_optimized_send_mid_class_changed)
- jit_guard_known_klass(
- jit, ctx, asm, C.rb_class_of(comptime_symbol), ctx.stack_opnd(calling.argc),
- StackOpnd[calling.argc], comptime_symbol, class_changed_exit,
- )
- asm.mov(C_ARGS[0], ctx.stack_opnd(calling.argc))
- asm.call(C.rb_get_symbol_id)
- asm.cmp(C_RET, mid)
- id_changed_exit = counted_exit(side_exit(jit, ctx), :send_optimized_send_mid_id_changed)
- jit_chain_guard(:jne, jit, ctx, asm, id_changed_exit)
-
- # rb_callable_method_entry_with_refinements
- calling.flags = flags
- cme, _ = jit_search_method(jit, ctx, asm, mid, calling)
- if cme == CantCompile
- return CantCompile
- end
-
- if flags & C::VM_CALL_FCALL != 0
- return jit_call_method(jit, ctx, asm, mid, calling, cme, known_recv_class)
- end
-
- raise NotImplementedError # unreachable for now
- end
-
- # vm_push_frame
- #
- # Frame structure:
- # | args | locals | cme/cref | block_handler/prev EP | frame type (EP here) | stack bottom (SP here)
- #
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, block_handler, iseq: nil, local_size: 0, stack_max: 0, prev_ep: nil, doing_kw_call: nil)
- # Save caller SP and PC before pushing a callee frame for backtrace and side exits
- asm.comment('save SP to caller CFP')
- recv_idx = argc # blockarg is already popped
- recv_idx += (block_handler == :captured) ? 0 : 1 # receiver is not on stack when captured->self is used
- if iseq
- # Skip setting this to SP register. This cfp->sp will be copied to SP on leave insn.
- asm.lea(:rax, ctx.sp_opnd(C.VALUE.size * -recv_idx)) # Pop receiver and arguments to prepare for side exits
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], :rax)
- else
- asm.lea(SP, ctx.sp_opnd(C.VALUE.size * -recv_idx))
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP)
- ctx.sp_offset = recv_idx
- end
- jit_save_pc(jit, asm, comment: 'save PC to caller CFP')
-
- sp_offset = ctx.sp_offset + 3 + local_size + (doing_kw_call ? 1 : 0) # callee_sp
- local_size.times do |i|
- asm.comment('set local variables') if i == 0
- local_index = sp_offset + i - local_size - 3
- asm.mov([SP, C.VALUE.size * local_index], Qnil)
- end
-
- asm.comment('set up EP with managing data')
- ep_offset = sp_offset - 1
- # ep[-2]: cref_or_me
- asm.mov(:rax, cme.to_i)
- asm.mov([SP, C.VALUE.size * (ep_offset - 2)], :rax)
- # ep[-1]: block handler or prev env ptr (specval)
- if prev_ep
- asm.mov(:rax, prev_ep.to_i | 1) # tagged prev ep
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
- elsif block_handler == :captured
- # Set captured->ep, saving captured in :rcx for captured->self
- ep_reg = :rcx
- jit_get_lep(jit, asm, reg: ep_reg)
- asm.mov(:rcx, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler
- asm.and(:rcx, ~0x3) # captured
- asm.mov(:rax, [:rcx, C.VALUE.size]) # captured->ep
- asm.or(:rax, 0x1) # GC_GUARDED_PTR
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
- elsif block_handler == C::VM_BLOCK_HANDLER_NONE
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], C::VM_BLOCK_HANDLER_NONE)
- elsif block_handler == C.rb_block_param_proxy
- # vm_caller_setup_arg_block: block_code == rb_block_param_proxy
- jit_get_lep(jit, asm, reg: :rax) # VM_CF_BLOCK_HANDLER: VM_CF_LEP
- asm.mov(:rax, [:rax, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # VM_CF_BLOCK_HANDLER: VM_ENV_BLOCK_HANDLER
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:block_code)], :rax) # reg_cfp->block_code = handler
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax) # return handler;
- else # assume blockiseq
- asm.mov(:rax, block_handler)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:block_code)], :rax)
- asm.lea(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) # VM_CFP_TO_CAPTURED_BLOCK
- asm.or(:rax, 1) # VM_BH_FROM_ISEQ_BLOCK
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
- end
- # ep[-0]: ENV_FLAGS
- asm.mov([SP, C.VALUE.size * (ep_offset - 0)], frame_type)
-
- asm.comment('set up new frame')
- cfp_offset = -C.rb_control_frame_t.size # callee CFP
- # For ISEQ, JIT code will set it as needed. However, C func needs 0 there for svar frame detection.
- if iseq.nil?
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:pc)], 0)
- end
- asm.mov(:rax, iseq.to_i)
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:iseq)], :rax)
- if block_handler == :captured
- asm.mov(:rax, [:rcx]) # captured->self
- else
- self_index = ctx.sp_offset - (1 + argc) # blockarg has been popped
- asm.mov(:rax, [SP, C.VALUE.size * self_index])
- end
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:self)], :rax)
- asm.lea(:rax, [SP, C.VALUE.size * ep_offset])
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:ep)], :rax)
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:block_code)], 0)
- # Update SP register only for ISEQ calls. SP-relative operations should be done above this.
- sp_reg = iseq ? SP : :rax
- asm.lea(sp_reg, [SP, C.VALUE.size * sp_offset])
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:sp)], sp_reg)
-
- # cfp->jit_return is used only for ISEQs
- if iseq
- # The callee might change locals through Kernel#binding and other means.
- ctx.clear_local_types
-
- # Stub cfp->jit_return
- return_ctx = ctx.dup
- return_ctx.stack_pop(argc + ((block_handler == :captured) ? 0 : 1)) # Pop args and receiver. blockarg has been popped
- return_ctx.stack_push(Type::Unknown) # push callee's return value
- return_ctx.sp_offset = 1 # SP is in the position after popping a receiver and arguments
- return_ctx.chain_depth = 0
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx: return_ctx, pc: jit.pc + jit.insn.len * C.VALUE.size),
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(return_ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.compile = proc do |branch_asm|
- branch_asm.comment('set jit_return to callee CFP')
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.mov(:rax, branch_stub.target0.address)
- branch_asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:jit_return)], :rax)
- end
- end
- end
- branch_stub.compile.call(asm)
- end
-
- asm.comment('switch to callee CFP')
- # Update CFP register only for ISEQ calls
- cfp_reg = iseq ? CFP : :rax
- asm.lea(cfp_reg, [CFP, cfp_offset])
- asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], cfp_reg)
- end
-
- # CALLER_SETUP_ARG: Return CantCompile if not supported
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_caller_setup_arg(jit, ctx, asm, flags)
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_args_splat_kw_splat)
- return CantCompile
- elsif flags & C::VM_CALL_ARGS_SPLAT != 0
- # splat is not supported in this path
- asm.incr_counter(:send_args_splat)
- return CantCompile
- elsif flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_args_kw_splat)
- return CantCompile
- elsif flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_kwarg)
- return CantCompile
- end
- end
-
- # Pushes arguments from an array to the stack. Differs from push splat because
- # the array can have items left over.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def move_rest_args_to_stack(array, num_args, jit, ctx, asm)
- side_exit = side_exit(jit, ctx)
-
- asm.comment('move_rest_args_to_stack')
-
- # array is :rax
- array_len_opnd = :rcx
- jit_array_len(asm, array, array_len_opnd)
-
- asm.comment('Side exit if length is less than required')
- asm.cmp(array_len_opnd, num_args)
- asm.jl(counted_exit(side_exit, :send_iseq_has_rest_and_splat_not_equal))
-
- asm.comment('Push arguments from array')
-
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- array_reg = array
-
- # Conditionally load the address of the heap array
- # (struct RArray *)(obj)->as.heap.ptr
- flags_opnd = [array_reg, C.RBasic.offsetof(:flags)]
- asm.test(flags_opnd, C::RARRAY_EMBED_FLAG)
- heap_ptr_opnd = [array_reg, C.RArray.offsetof(:as, :heap, :ptr)]
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- ary_opnd = :rdx # NOTE: array :rax is used after move_rest_args_to_stack too
- asm.lea(:rcx, [array_reg, C.RArray.offsetof(:as, :ary)])
- asm.mov(ary_opnd, heap_ptr_opnd)
- asm.cmovnz(ary_opnd, :rcx)
-
- num_args.times do |i|
- top = ctx.stack_push(Type::Unknown)
- asm.mov(:rcx, [ary_opnd, i * C.VALUE.size])
- asm.mov(top, :rcx)
- end
- end
-
- # vm_caller_setup_arg_splat (+ CALLER_SETUP_ARG):
- # Pushes arguments from an array to the stack that are passed with a splat (i.e. *args).
- # It optimistically compiles to a static size that is the exact number of arguments needed for the function.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def push_splat_args(required_args, jit, ctx, asm)
- side_exit = side_exit(jit, ctx)
-
- asm.comment('push_splat_args')
-
- array_opnd = ctx.stack_opnd(0)
- array_stack_opnd = StackOpnd[0]
- array_reg = :rax
- asm.mov(array_reg, array_opnd)
-
- guard_object_is_array(jit, ctx, asm, array_reg, :rcx, array_stack_opnd, :send_args_splat_not_array)
-
- array_len_opnd = :rcx
- jit_array_len(asm, array_reg, array_len_opnd)
-
- asm.comment('Side exit if length is not equal to remaining args')
- asm.cmp(array_len_opnd, required_args)
- asm.jne(counted_exit(side_exit, :send_args_splat_length_not_equal))
-
- asm.comment('Check last argument is not ruby2keyword hash')
-
- ary_opnd = :rcx
- jit_array_ptr(asm, array_reg, ary_opnd) # clobbers array_reg
-
- last_array_value = :rax
- asm.mov(last_array_value, [ary_opnd, (required_args - 1) * C.VALUE.size])
-
- ruby2_exit = counted_exit(side_exit, :send_args_splat_ruby2_hash);
- guard_object_is_not_ruby2_keyword_hash(asm, last_array_value, :rcx, ruby2_exit) # clobbers :rax
-
- asm.comment('Push arguments from array')
- array_opnd = ctx.stack_pop(1)
-
- if required_args > 0
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- array_reg = :rax
- asm.mov(array_reg, array_opnd)
-
- # Conditionally load the address of the heap array
- # (struct RArray *)(obj)->as.heap.ptr
- flags_opnd = [array_reg, C.RBasic.offsetof(:flags)]
- asm.test(flags_opnd, C::RARRAY_EMBED_FLAG)
- heap_ptr_opnd = [array_reg, C.RArray.offsetof(:as, :heap, :ptr)]
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- asm.lea(:rcx, [array_reg, C.RArray.offsetof(:as, :ary)])
- asm.mov(:rax, heap_ptr_opnd)
- asm.cmovnz(:rax, :rcx)
- ary_opnd = :rax
-
- (0...required_args).each do |i|
- top = ctx.stack_push(Type::Unknown)
- asm.mov(:rcx, [ary_opnd, i * C.VALUE.size])
- asm.mov(top, :rcx)
- end
-
- asm.comment('end push_each')
- end
- end
-
- # Generate RARRAY_LEN. For array_opnd, use Opnd::Reg to reduce memory access,
- # and use Opnd::Mem to save registers.
- def jit_array_len(asm, array_reg, len_reg)
- asm.comment('get array length for embedded or heap')
-
- # Pull out the embed flag to check if it's an embedded array.
- asm.mov(len_reg, [array_reg, C.RBasic.offsetof(:flags)])
-
- # Get the length of the array
- asm.and(len_reg, C::RARRAY_EMBED_LEN_MASK)
- asm.sar(len_reg, C::RARRAY_EMBED_LEN_SHIFT)
-
- # Conditionally move the length of the heap array
- asm.test([array_reg, C.RBasic.offsetof(:flags)], C::RARRAY_EMBED_FLAG)
-
- # Select the array length value
- asm.cmovz(len_reg, [array_reg, C.RArray.offsetof(:as, :heap, :len)])
- end
-
- # Generate RARRAY_CONST_PTR (part of RARRAY_AREF)
- def jit_array_ptr(asm, array_reg, ary_opnd) # clobbers array_reg
- asm.comment('get array pointer for embedded or heap')
-
- flags_opnd = [array_reg, C.RBasic.offsetof(:flags)]
- asm.test(flags_opnd, C::RARRAY_EMBED_FLAG)
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- asm.mov(ary_opnd, [array_reg, C.RArray.offsetof(:as, :heap, :ptr)])
- asm.lea(array_reg, [array_reg, C.RArray.offsetof(:as, :ary)]) # clobbers array_reg
- asm.cmovnz(ary_opnd, array_reg)
- end
-
- def assert(cond)
- assert_equal(cond, true)
- end
-
- def assert_equal(left, right)
- if left != right
- raise "'#{left.inspect}' was not '#{right.inspect}'"
- end
- end
-
- def fixnum?(obj)
- (C.to_value(obj) & C::RUBY_FIXNUM_FLAG) == C::RUBY_FIXNUM_FLAG
- end
-
- def flonum?(obj)
- (C.to_value(obj) & C::RUBY_FLONUM_MASK) == C::RUBY_FLONUM_FLAG
- end
-
- def symbol?(obj)
- static_symbol?(obj) || dynamic_symbol?(obj)
- end
-
- def static_symbol?(obj)
- (C.to_value(obj) & 0xff) == C::RUBY_SYMBOL_FLAG
- end
-
- def dynamic_symbol?(obj)
- return false if C::SPECIAL_CONST_P(obj)
- C.RB_TYPE_P(obj, C::RUBY_T_SYMBOL)
- end
-
- def shape_too_complex?(obj)
- C.rb_shape_get_shape_id(obj) == C::OBJ_TOO_COMPLEX_SHAPE_ID
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def defer_compilation(jit, ctx, asm)
- # Make a stub to compile the current insn
- if ctx.chain_depth != 0
- raise "double defer!"
- end
- ctx.chain_depth += 1
- jit_direct_jump(jit.iseq, jit.pc, ctx, asm, comment: 'defer_compilation')
- end
-
- def jit_direct_jump(iseq, pc, ctx, asm, comment: 'jit_direct_jump')
- branch_stub = BranchStub.new(
- iseq:,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc:),
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.compile = proc do |branch_asm|
- branch_asm.comment(comment)
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.jmp(branch_stub.target0.address)
- in Next0
- # Just write the block without a jump
- end
- end
- end
- branch_stub.compile.call(asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- def side_exit(jit, ctx)
- # We use the latest ctx.sp_offset to generate a side exit to tolerate sp_offset changes by jit_save_sp.
- # However, we want to simulate an old stack_size when we take a side exit. We do that by adjusting the
- # sp_offset because gen_outlined_exit uses ctx.sp_offset to move SP.
- ctx = ctx.with_stack_size(jit.stack_size_for_pc)
-
- jit.side_exit_for_pc[ctx.sp_offset] ||= Assembler.new.then do |asm|
- @exit_compiler.compile_side_exit(jit.pc, ctx, asm)
- @ocb.write(asm)
- end
- end
-
- def counted_exit(side_exit, name)
- asm = Assembler.new
- asm.incr_counter(name)
- asm.jmp(side_exit)
- @ocb.write(asm)
- end
-
- def def_iseq_ptr(cme_def)
- C.rb_iseq_check(cme_def.body.iseq.iseqptr)
- end
-
- def to_value(obj)
- GC_REFS << obj
- C.to_value(obj)
- end
-
- def full_cfunc_return
- @full_cfunc_return ||= Assembler.new.then do |asm|
- @exit_compiler.compile_full_cfunc_return(asm)
- @ocb.write(asm)
- end
- end
-
- def c_method_tracing_currently_enabled?
- C.rb_rjit_global_events & (C::RUBY_EVENT_C_CALL | C::RUBY_EVENT_C_RETURN) != 0
- end
-
- # Return a builtin function if a given iseq consists of only that builtin function
- def builtin_function(iseq)
- opt_invokebuiltin_delegate_leave = INSNS.values.find { |i| i.name == :opt_invokebuiltin_delegate_leave }
- leave = INSNS.values.find { |i| i.name == :leave }
- if iseq.body.iseq_size == opt_invokebuiltin_delegate_leave.len + leave.len &&
- C.rb_vm_insn_decode(iseq.body.iseq_encoded[0]) == opt_invokebuiltin_delegate_leave.bin &&
- C.rb_vm_insn_decode(iseq.body.iseq_encoded[opt_invokebuiltin_delegate_leave.len]) == leave.bin
- C.rb_builtin_function.new(iseq.body.iseq_encoded[1])
- end
- end
-
- def build_calling(ci:, block_handler:)
- CallingInfo.new(
- argc: C.vm_ci_argc(ci),
- flags: C.vm_ci_flag(ci),
- kwarg: C.vm_ci_kwarg(ci),
- ci_addr: ci.to_i,
- send_shift: 0,
- block_handler:,
- )
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/invariants.rb b/lib/ruby_vm/rjit/invariants.rb
deleted file mode 100644
index 5b061d1994..0000000000
--- a/lib/ruby_vm/rjit/invariants.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-require 'set'
-
-module RubyVM::RJIT
- class Invariants
- class << self
- # Called by RubyVM::RJIT::Compiler to lazily initialize this
- # @param cb [CodeBlock]
- # @param ocb [CodeBlock]
- # @param compiler [RubyVM::RJIT::Compiler]
- # @param exit_compiler [RubyVM::RJIT::ExitCompiler]
- def initialize(cb, ocb, compiler, exit_compiler)
- @cb = cb
- @ocb = ocb
- @compiler = compiler
- @exit_compiler = exit_compiler
- @bop_blocks = Set.new # TODO: actually invalidate this
- @cme_blocks = Hash.new { |h, k| h[k] = Set.new }
- @const_blocks = Hash.new { |h, k| h[k] = Set.new }
- @patches = {}
-
- # freeze # workaround a binding.irb issue. TODO: resurrect this
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param klass [Integer]
- # @param op [Integer]
- def assume_bop_not_redefined(jit, klass, op)
- return false unless C.BASIC_OP_UNREDEFINED_P(klass, op)
-
- ensure_block_entry_exit(jit, cause: 'assume_bop_not_redefined')
- @bop_blocks << jit.block
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- def assume_method_lookup_stable(jit, cme)
- ensure_block_entry_exit(jit, cause: 'assume_method_lookup_stable')
- @cme_blocks[cme.to_i] << jit.block
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- def assume_method_basic_definition(jit, klass, mid)
- if C.rb_method_basic_definition_p(klass, mid)
- cme = C.rb_callable_method_entry(klass, mid)
- assume_method_lookup_stable(jit, cme)
- true
- else
- false
- end
- end
-
- def assume_stable_constant_names(jit, idlist)
- (0..).each do |i|
- break if (id = idlist[i]) == 0
- @const_blocks[id] << jit.block
- end
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- def record_global_inval_patch(asm, target)
- asm.pos_marker do |address|
- if @patches.key?(address)
- raise 'multiple patches in the same address'
- end
- @patches[address] = target
- end
- end
-
- def on_cme_invalidate(cme)
- @cme_blocks.fetch(cme.to_i, []).each do |block|
- @cb.with_write_addr(block.start_addr) do
- asm = Assembler.new
- asm.comment('on_cme_invalidate')
- asm.jmp(block.entry_exit)
- @cb.write(asm)
- end
- # TODO: re-generate branches that refer to this block
- end
- @cme_blocks.delete(cme.to_i)
- end
-
- def on_constant_ic_update(iseq, ic, insn_idx)
- # TODO: check multi ractor as well
- if ic.entry.ic_cref
- # No need to recompile the slowpath
- return
- end
-
- pc = iseq.body.iseq_encoded + insn_idx
- insn_name = Compiler.decode_insn(pc.*).name
- if insn_name != :opt_getconstant_path && insn_name != :trace_opt_getconstant_path
- raise 'insn_idx was not at opt_getconstant_path'
- end
- if ic.to_i != pc[1]
- raise 'insn_idx + 1 was not at the updated IC'
- end
- @compiler.invalidate_blocks(iseq, pc.to_i)
- end
-
- def on_constant_state_changed(id)
- @const_blocks.fetch(id, []).each do |block|
- @compiler.invalidate_block(block)
- end
- end
-
- def on_tracing_invalidate_all
- invalidate_all
- end
-
- def on_update_references
- # Give up. In order to support GC.compact, you'd have to update ISEQ
- # addresses in BranchStub, etc. Ideally, we'd need to update moved
- # pointers in JITed code here, but we just invalidate all for now.
- invalidate_all
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param block [RubyVM::RJIT::Block]
- def ensure_block_entry_exit(jit, cause:)
- block = jit.block
- if block.entry_exit.nil?
- block.entry_exit = Assembler.new.then do |asm|
- @exit_compiler.compile_entry_exit(block.pc, block.ctx, asm, cause:)
- @ocb.write(asm)
- end
- end
- end
-
- private
-
- def invalidate_all
- # On-Stack Replacement
- @patches.each do |address, target|
- # TODO: assert patches don't overlap each other
- @cb.with_write_addr(address) do
- asm = Assembler.new
- asm.comment('on_tracing_invalidate_all')
- asm.jmp(target)
- @cb.write(asm)
- end
- end
- @patches.clear
-
- C.rjit_for_each_iseq do |iseq|
- # Avoid entering past code
- iseq.body.jit_entry = 0
- # Avoid reusing past code
- iseq.body.rjit_blocks.clear if iseq.body.rjit_blocks
- # Compile this again if not converted to trace_* insns
- iseq.body.jit_entry_calls = 0
- end
- end
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/jit_state.rb b/lib/ruby_vm/rjit/jit_state.rb
deleted file mode 100644
index 02a713474e..0000000000
--- a/lib/ruby_vm/rjit/jit_state.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-module RubyVM::RJIT
- class JITState < Struct.new(
- :iseq, # @param `RubyVM::RJIT::CPointer::Struct_rb_iseq_t`
- :pc, # @param [Integer] The JIT target PC
- :cfp, # @param `RubyVM::RJIT::CPointer::Struct_rb_control_frame_t` The JIT source CFP (before RJIT is called)
- :block, # @param [RubyVM::RJIT::Block]
- :stack_size_for_pc, # @param [Integer]
- :side_exit_for_pc, # @param [Hash{ Integer => Integer }] { sp_offset => address }
- :record_boundary_patch_point, # @param [TrueClass,FalseClass]
- )
- def initialize(side_exit_for_pc: {}, record_boundary_patch_point: false, **) = super
-
- def insn
- Compiler.decode_insn(C.VALUE.new(pc).*)
- end
-
- def operand(index, signed: false, ruby: false)
- addr = pc + (index + 1) * Fiddle::SIZEOF_VOIDP
- value = Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP].unpack(signed ? 'q' : 'Q')[0]
- if ruby
- value = C.to_ruby(value)
- end
- value
- end
-
- def at_current_insn?
- pc == cfp.pc.to_i
- end
-
- def peek_at_local(n)
- local_table_size = iseq.body.local_table_size
- offset = -C::VM_ENV_DATA_SIZE - local_table_size + n + 1
- value = (cfp.ep + offset).*
- C.to_ruby(value)
- end
-
- def peek_at_stack(depth_from_top)
- raise 'not at current insn' unless at_current_insn?
- offset = -(1 + depth_from_top)
- # rb_rjit_branch_stub_hit updates SP, so you don't need to worry about sp_offset
- value = (cfp.sp + offset).*
- C.to_ruby(value)
- end
-
- def peek_at_self
- C.to_ruby(cfp.self)
- end
-
- def peek_at_block_handler(level)
- ep = ep_at_level(cfp, level:)
- ep[C::VM_ENV_DATA_INDEX_SPECVAL]
- end
-
- private
-
- def ep_at_level(cfp, level:)
- ep = cfp.ep
- level.times do
- # VM_ENV_PREV_EP
- ep = C.VALUE.new(ep[C::VM_ENV_DATA_INDEX_SPECVAL] & ~0x03)
- end
- ep
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/stats.rb b/lib/ruby_vm/rjit/stats.rb
deleted file mode 100644
index 8c4253880a..0000000000
--- a/lib/ruby_vm/rjit/stats.rb
+++ /dev/null
@@ -1,188 +0,0 @@
-# frozen_string_literal: true
-module RubyVM::RJIT
- def self.runtime_stats
- stats = {}
-
- # Insn exits
- INSNS.each_value do |insn|
- exits = C.rjit_insn_exits[insn.bin]
- if exits > 0
- stats[:"exit_#{insn.name}"] = exits
- end
- end
-
- # Runtime stats
- C.rb_rjit_runtime_counters.members.each do |member|
- stats[member] = C.rb_rjit_counters.public_send(member)
- end
-
- # Other stats are calculated here
- stats[:side_exit_count] = stats.select { |name, _count| name.start_with?('exit_') }.sum(&:last)
- if stats[:vm_insns_count] > 0
- retired_in_rjit = stats[:rjit_insns_count] - stats[:side_exit_count]
- stats[:total_insns_count] = retired_in_rjit + stats[:vm_insns_count]
- stats[:ratio_in_rjit] = 100.0 * retired_in_rjit / stats[:total_insns_count]
- else
- stats.delete(:vm_insns_count)
- end
-
- stats
- end
-
- class << self
- private
-
- # --yjit-stats at_exit
- def print_stats
- stats = runtime_stats
- $stderr.puts("***RJIT: Printing RJIT statistics on exit***")
-
- print_counters(stats, prefix: 'send_', prompt: 'method call exit reasons')
- print_counters(stats, prefix: 'invokeblock_', prompt: 'invokeblock exit reasons')
- print_counters(stats, prefix: 'invokesuper_', prompt: 'invokesuper exit reasons')
- print_counters(stats, prefix: 'getblockpp_', prompt: 'getblockparamproxy exit reasons')
- print_counters(stats, prefix: 'getivar_', prompt: 'getinstancevariable exit reasons')
- print_counters(stats, prefix: 'setivar_', prompt: 'setinstancevariable exit reasons')
- print_counters(stats, prefix: 'optaref_', prompt: 'opt_aref exit reasons')
- print_counters(stats, prefix: 'optgetconst_', prompt: 'opt_getconstant_path exit reasons')
- print_counters(stats, prefix: 'expandarray_', prompt: 'expandarray exit reasons')
-
- $stderr.puts "compiled_block_count: #{format_number(13, stats[:compiled_block_count])}"
- $stderr.puts "side_exit_count: #{format_number(13, stats[:side_exit_count])}"
- $stderr.puts "total_insns_count: #{format_number(13, stats[:total_insns_count])}" if stats.key?(:total_insns_count)
- $stderr.puts "vm_insns_count: #{format_number(13, stats[:vm_insns_count])}" if stats.key?(:vm_insns_count)
- $stderr.puts "rjit_insns_count: #{format_number(13, stats[:rjit_insns_count])}"
- $stderr.puts "ratio_in_rjit: #{format('%12.1f', stats[:ratio_in_rjit])}%" if stats.key?(:ratio_in_rjit)
-
- print_exit_counts(stats)
- end
-
- def print_counters(stats, prefix:, prompt:)
- $stderr.puts("#{prompt}: ")
- counters = stats.filter { |key, _| key.start_with?(prefix) }
- counters.filter! { |_, value| value != 0 }
- counters.transform_keys! { |key| key.to_s.delete_prefix(prefix) }
-
- if counters.empty?
- $stderr.puts(" (all relevant counters are zero)")
- return
- end
-
- counters = counters.to_a
- counters.sort_by! { |(_, counter_value)| counter_value }
- longest_name_length = counters.max_by { |(name, _)| name.length }.first.length
- total = counters.sum { |(_, counter_value)| counter_value }
-
- counters.reverse_each do |(name, value)|
- percentage = value.fdiv(total) * 100
- $stderr.printf(" %*s %s (%4.1f%%)\n", longest_name_length, name, format_number(10, value), percentage)
- end
- end
-
- def print_exit_counts(stats, how_many: 20, padding: 2)
- exits = stats.filter_map { |name, count| [name.to_s.delete_prefix('exit_'), count] if name.start_with?('exit_') }.to_h
- return if exits.empty?
-
- top_exits = exits.sort_by { |_name, count| -count }.first(how_many).to_h
- total_exits = exits.values.sum
- $stderr.puts "Top-#{top_exits.size} most frequent exit ops (#{format("%.1f", 100.0 * top_exits.values.sum / total_exits)}% of exits):"
-
- name_width = top_exits.map { |name, _count| name.length }.max + padding
- count_width = top_exits.map { |_name, count| format_number(10, count).length }.max + padding
- top_exits.each do |name, count|
- ratio = 100.0 * count / total_exits
- $stderr.puts "#{format("%#{name_width}s", name)}: #{format_number(count_width, count)} (#{format('%4.1f', ratio)}%)"
- end
- end
-
- # Format large numbers with comma separators for readability
- def format_number(pad, number)
- integer, decimal = number.to_s.split('.')
- d_groups = integer.chars.reverse.each_slice(3)
- with_commas = d_groups.map(&:join).join(',').reverse
- [with_commas, decimal].compact.join('.').rjust(pad, ' ')
- end
-
- # --yjit-trace-exits at_exit
- def dump_trace_exits
- filename = "#{Dir.pwd}/rjit_exit_locations.dump"
- File.binwrite(filename, Marshal.dump(exit_traces))
- $stderr.puts("RJIT exit locations dumped to:\n#{filename}")
- end
-
- # Convert rb_rjit_raw_samples and rb_rjit_line_samples into a StackProf format.
- def exit_traces
- results = C.rjit_exit_traces
- raw_samples = results[:raw].dup
- line_samples = results[:lines].dup
- frames = results[:frames].dup
- samples_count = 0
-
- # Loop through the instructions and set the frame hash with the data.
- # We use nonexistent.def for the file name, otherwise insns.def will be displayed
- # and that information isn't useful in this context.
- RubyVM::INSTRUCTION_NAMES.each_with_index do |name, frame_id|
- frame_hash = { samples: 0, total_samples: 0, edges: {}, name: name, file: "nonexistent.def", line: nil, lines: {} }
- results[:frames][frame_id] = frame_hash
- frames[frame_id] = frame_hash
- end
-
- # Loop through the raw_samples and build the hashes for StackProf.
- # The loop is based off an example in the StackProf documentation and therefore
- # this functionality can only work with that library.
- #
- # Raw Samples:
- # [ length, frame1, frame2, frameN, ..., instruction, count
- #
- # Line Samples
- # [ length, line_1, line_2, line_n, ..., dummy value, count
- i = 0
- while i < raw_samples.length
- stack_length = raw_samples[i] + 1
- i += 1 # consume the stack length
-
- prev_frame_id = nil
- stack_length.times do |idx|
- idx += i
- frame_id = raw_samples[idx]
-
- if prev_frame_id
- prev_frame = frames[prev_frame_id]
- prev_frame[:edges][frame_id] ||= 0
- prev_frame[:edges][frame_id] += 1
- end
-
- frame_info = frames[frame_id]
- frame_info[:total_samples] += 1
-
- frame_info[:lines][line_samples[idx]] ||= [0, 0]
- frame_info[:lines][line_samples[idx]][0] += 1
-
- prev_frame_id = frame_id
- end
-
- i += stack_length # consume the stack
-
- top_frame_id = prev_frame_id
- top_frame_line = 1
-
- sample_count = raw_samples[i]
-
- frames[top_frame_id][:samples] += sample_count
- frames[top_frame_id][:lines] ||= {}
- frames[top_frame_id][:lines][top_frame_line] ||= [0, 0]
- frames[top_frame_id][:lines][top_frame_line][1] += sample_count
-
- samples_count += sample_count
- i += 1
- end
-
- results[:samples] = samples_count
- # Set missed_samples and gc_samples to 0 as their values
- # don't matter to us in this context.
- results[:missed_samples] = 0
- results[:gc_samples] = 0
- results
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/type.rb b/lib/ruby_vm/rjit/type.rb
deleted file mode 100644
index 119692014b..0000000000
--- a/lib/ruby_vm/rjit/type.rb
+++ /dev/null
@@ -1,221 +0,0 @@
-module RubyVM::RJIT
- # Represent the type of a value (local/stack/self) in RJIT
- Type = Data.define(:type) do
- # Check if the type is an immediate
- def imm?
- case self
- in Type::UnknownImm then true
- in Type::Nil then true
- in Type::True then true
- in Type::False then true
- in Type::Fixnum then true
- in Type::Flonum then true
- in Type::ImmSymbol then true
- else false
- end
- end
-
- # Returns true when the type is not specific.
- def unknown?
- case self
- in Type::Unknown | Type::UnknownImm | Type::UnknownHeap then true
- else false
- end
- end
-
- # Returns true when we know the VALUE is a specific handle type,
- # such as a static symbol ([Type::ImmSymbol], i.e. true from RB_STATIC_SYM_P()).
- # Opposite of [Self::is_unknown].
- def specific?
- !self.unknown?
- end
-
- # Check if the type is a heap object
- def heap?
- case self
- in Type::UnknownHeap then true
- in Type::TArray then true
- in Type::Hash then true
- in Type::HeapSymbol then true
- in Type::TString then true
- in Type::CString then true
- in Type::BlockParamProxy then true
- else false
- end
- end
-
- # Check if it's a T_ARRAY object
- def array?
- case self
- in Type::TArray then true
- else false
- end
- end
-
- # Check if it's a T_STRING object (both TString and CString are T_STRING)
- def string?
- case self
- in Type::TString then true
- in Type::CString then true
- else false
- end
- end
-
- # Returns the class if it is known, otherwise nil
- def known_class
- case self
- in Type::Nil then C.rb_cNilClass
- in Type::True then C.rb_cTrueClass
- in Type::False then C.rb_cFalseClass
- in Type::Fixnum then C.rb_cInteger
- in Type::Flonum then C.rb_cFloat
- in Type::ImmSymbol | Type::HeapSymbol then C.rb_cSymbol
- in Type::CString then C.rb_cString
- else nil
- end
- end
-
- # Returns a boolean representing whether the value is truthy if known, otherwise nil
- def known_truthy
- case self
- in Type::Nil then false
- in Type::False then false
- in Type::UnknownHeap then false
- in Type::Unknown | Type::UnknownImm then nil
- else true
- end
- end
-
- # Returns a boolean representing whether the value is equal to nil if known, otherwise nil
- def known_nil
- case [self, self.known_truthy]
- in Type::Nil, _ then true
- in Type::False, _ then false # Qfalse is not nil
- in _, true then false # if truthy, can't be nil
- in _, _ then nil # otherwise unknown
- end
- end
-
- def diff(dst)
- # Perfect match, difference is zero
- if self == dst
- return TypeDiff::Compatible[0]
- end
-
- # Any type can flow into an unknown type
- if dst == Type::Unknown
- return TypeDiff::Compatible[1]
- end
-
- # A CString is also a TString.
- if self == Type::CString && dst == Type::TString
- return TypeDiff::Compatible[1]
- end
-
- # Specific heap type into unknown heap type is imperfect but valid
- if self.heap? && dst == Type::UnknownHeap
- return TypeDiff::Compatible[1]
- end
-
- # Specific immediate type into unknown immediate type is imperfect but valid
- if self.imm? && dst == Type::UnknownImm
- return TypeDiff::Compatible[1]
- end
-
- # Incompatible types
- return TypeDiff::Incompatible
- end
-
- def upgrade(new_type)
- assert(new_type.diff(self) != TypeDiff::Incompatible)
- new_type
- end
-
- private
-
- def assert(cond)
- unless cond
- raise "'#{cond.inspect}' was not true"
- end
- end
- end
-
- # This returns an appropriate Type based on a known value
- class << Type
- def from(val)
- if C::SPECIAL_CONST_P(val)
- if fixnum?(val)
- Type::Fixnum
- elsif val.nil?
- Type::Nil
- elsif val == true
- Type::True
- elsif val == false
- Type::False
- elsif static_symbol?(val)
- Type::ImmSymbol
- elsif flonum?(val)
- Type::Flonum
- else
- raise "Illegal value: #{val.inspect}"
- end
- else
- val_class = C.to_value(C.rb_class_of(val))
- if val_class == C.rb_cString && C.rb_obj_frozen_p(val)
- return Type::CString
- end
- if C.to_value(val) == C.rb_block_param_proxy
- return Type::BlockParamProxy
- end
- case C::BUILTIN_TYPE(val)
- in C::RUBY_T_ARRAY
- Type::TArray
- in C::RUBY_T_HASH
- Type::Hash
- in C::RUBY_T_STRING
- Type::TString
- else
- Type::UnknownHeap
- end
- end
- end
-
- private
-
- def fixnum?(obj)
- (C.to_value(obj) & C::RUBY_FIXNUM_FLAG) == C::RUBY_FIXNUM_FLAG
- end
-
- def flonum?(obj)
- (C.to_value(obj) & C::RUBY_FLONUM_MASK) == C::RUBY_FLONUM_FLAG
- end
-
- def static_symbol?(obj)
- (C.to_value(obj) & 0xff) == C::RUBY_SYMBOL_FLAG
- end
- end
-
- # List of types
- Type::Unknown = Type[:Unknown]
- Type::UnknownImm = Type[:UnknownImm]
- Type::UnknownHeap = Type[:UnknownHeap]
- Type::Nil = Type[:Nil]
- Type::True = Type[:True]
- Type::False = Type[:False]
- Type::Fixnum = Type[:Fixnum]
- Type::Flonum = Type[:Flonum]
- Type::Hash = Type[:Hash]
- Type::ImmSymbol = Type[:ImmSymbol]
- Type::HeapSymbol = Type[:HeapSymbol]
-
- Type::TString = Type[:TString] # An object with the T_STRING flag set, possibly an rb_cString
- Type::CString = Type[:CString] # An un-subclassed string of type rb_cString (can have instance vars in some cases)
- Type::TArray = Type[:TArray] # An object with the T_ARRAY flag set, possibly an rb_cArray
-
- Type::BlockParamProxy = Type[:BlockParamProxy] # A special sentinel value indicating the block parameter should be read from
-
- module TypeDiff
- Compatible = Data.define(:diversion) # The smaller, the more compatible.
- Incompatible = :Incompatible
- end
-end
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index 5657dc3fbf..af86646a82 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -9,7 +9,7 @@
require "rbconfig"
module Gem
- VERSION = "3.5.0.dev"
+ VERSION = "3.4.19"
end
# Must be first since it unloads the prelude from 1.9.2
@@ -211,7 +211,7 @@ module Gem
end
end
- true
+ return true
end
def self.needs
@@ -339,6 +339,16 @@ module Gem
end
##
+ # The path to the data directory specified by the gem name. If the
+ # package is not available as a gem, return nil.
+
+ def self.datadir(gem_name)
+ spec = @loaded_specs[gem_name]
+ return nil if spec.nil?
+ spec.datadir
+ end
+
+ ##
# A Zlib::Deflate.deflate wrapper
def self.deflate(data)
@@ -429,7 +439,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.ensure_subdirectories(dir, mode, subdirs) # :nodoc:
old_umask = File.umask
- File.umask old_umask | 0o002
+ File.umask old_umask | 002
options = {}
@@ -455,7 +465,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# distinction as extensions cannot be shared between the two.
def self.extension_api_version # :nodoc:
- if RbConfig::CONFIG["ENABLE_SHARED"] == "no"
+ if "no" == RbConfig::CONFIG["ENABLE_SHARED"]
"#{ruby_api_version}-static"
else
ruby_api_version
@@ -489,7 +499,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# the spec dirs directly, so we prune.
files.uniq! if check_load_path
- files
+ return files
end
def self.find_files_from_load_path(glob) # :nodoc:
@@ -524,7 +534,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# the spec dirs directly, so we prune.
files.uniq! if check_load_path
- files
+ return files
end
##
@@ -572,7 +582,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
##
# The number of paths in the +$LOAD_PATH+ from activated gems. Used to
- # prioritize +-I+ and <code>ENV['RUBYLIB']</code> entries during +require+.
+ # prioritize +-I+ and +ENV['RUBYLIB']+ entries during +require+.
def self.activated_gem_paths
@activated_gem_paths ||= 0
@@ -604,16 +614,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
@yaml_loaded = true
end
- @safe_marshal_loaded = false
-
- def self.load_safe_marshal
- return if @safe_marshal_loaded
-
- require_relative "rubygems/safe_marshal"
-
- @safe_marshal_loaded = true
- end
-
##
# The file name and line number of the caller of the caller of this method.
#
@@ -742,7 +742,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
if prefix != File.expand_path(RbConfig::CONFIG["sitelibdir"]) &&
prefix != File.expand_path(RbConfig::CONFIG["libdir"]) &&
- File.basename(RUBYGEMS_DIR) == "lib"
+ "lib" == File.basename(RUBYGEMS_DIR)
prefix
end
end
@@ -758,9 +758,13 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Safely read a file in binary mode on all platforms.
def self.read_binary(path)
- open_file(path, "rb+", &:read)
+ open_file(path, "rb+") do |io|
+ io.read
+ end
rescue Errno::EACCES, Errno::EROFS
- open_file(path, "rb", &:read)
+ open_file(path, "rb") do |io|
+ io.read
+ end
end
##
@@ -805,7 +809,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
if @ruby.nil?
@ruby = RbConfig.ruby
- @ruby = "\"#{@ruby}\"" if /\s/.match?(@ruby)
+ @ruby = "\"#{@ruby}\"" if @ruby =~ /\s/
end
@ruby
@@ -862,7 +866,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
return @ruby_version if defined? @ruby_version
version = RUBY_VERSION.dup
- if RUBY_PATCHLEVEL == -1
+ unless defined?(RUBY_PATCHLEVEL) && RUBY_PATCHLEVEL != -1
if RUBY_ENGINE == "ruby"
desc = RUBY_DESCRIPTION[/\Aruby #{Regexp.quote(RUBY_VERSION)}([^ ]+) /, 1]
else
@@ -910,7 +914,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Glob pattern for require-able path suffixes.
def self.suffix_pattern
- @suffix_pattern ||= "{#{suffixes.join(",")}}"
+ @suffix_pattern ||= "{#{suffixes.join(',')}}"
end
##
@@ -944,7 +948,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
val = RbConfig::CONFIG[key]
next unless val && !val.empty?
".#{val}"
- end].compact.uniq
+ end,
+ ].compact.uniq
end
##
@@ -958,7 +963,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
elapsed = Time.now - now
- ui.say format("%2$*1$s: %3$3.3fs", -width, msg, elapsed) if display
+ ui.say "%2$*1$s: %3$3.3fs" % [-width, msg, elapsed] if display
value
end
@@ -990,7 +995,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.win_platform?
if @@win_platform.nil?
ruby_platform = RbConfig::CONFIG["host_os"]
- @@win_platform = !WIN_PATTERNS.find {|r| ruby_platform =~ r }.nil?
+ @@win_platform = !!WIN_PATTERNS.find {|r| ruby_platform =~ r }
end
@@win_platform
@@ -1018,11 +1023,11 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Skip older versions of the GemCutter plugin: Its commands are in
# RubyGems proper now.
- next if /gemcutter-0\.[0-3]/.match?(plugin)
+ next if plugin =~ /gemcutter-0\.[0-3]/
begin
load plugin
- rescue ScriptError, StandardError => e
+ rescue ::Exception => e
details = "#{plugin.inspect}: #{e.message} (#{e.class})"
warn "Error loading RubyGems plugin #{details}"
end
@@ -1097,11 +1102,13 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
require "bundler"
begin
Gem::DefaultUserInteraction.use_ui(ui) do
- Bundler.ui.silence do
- @gemdeps = Bundler.setup
+ begin
+ Bundler.ui.silence do
+ @gemdeps = Bundler.setup
+ end
+ ensure
+ Gem::DefaultUserInteraction.ui.close
end
- ensure
- Gem::DefaultUserInteraction.ui.close
end
rescue Bundler::BundlerError => e
warn e.message
@@ -1147,7 +1154,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# This is used throughout RubyGems for enabling reproducible builds.
def self.source_date_epoch
- Time.at(source_date_epoch_string.to_i).utc.freeze
+ Time.at(self.source_date_epoch_string.to_i).utc.freeze
end
# FIX: Almost everywhere else we use the `def self.` way of defining class
diff --git a/lib/rubygems/available_set.rb b/lib/rubygems/available_set.rb
index 0af80cc3db..2ab3e137da 100644
--- a/lib/rubygems/available_set.rb
+++ b/lib/rubygems/available_set.rb
@@ -27,7 +27,7 @@ class Gem::AvailableSet
s = o.set
when Array
s = o.map do |sp,so|
- if !sp.is_a?(Gem::Specification) || !so.is_a?(Gem::Source)
+ if !sp.kind_of?(Gem::Specification) || !so.kind_of?(Gem::Source)
raise TypeError, "Array must be in [[spec, source], ...] form"
end
@@ -70,7 +70,7 @@ class Gem::AvailableSet
end
def all_specs
- @set.map(&:spec)
+ @set.map {|t| t.spec }
end
def match_platform!
@@ -105,14 +105,14 @@ class Gem::AvailableSet
def to_request_set(development = :none)
request_set = Gem::RequestSet.new
- request_set.development = development == :all
+ request_set.development = :all == development
each_spec do |spec|
request_set.always_install << spec
request_set.gem spec.name, spec.version
request_set.import spec.development_dependencies if
- development == :shallow
+ :shallow == development
end
request_set
@@ -147,7 +147,7 @@ class Gem::AvailableSet
end
def remove_installed!(dep)
- @set.reject! do |_t|
+ @set.reject! do |t|
# already locally installed
Gem::Specification.any? do |installed_spec|
dep.name == installed_spec.name &&
diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb
index 6246737847..5d198114e0 100644
--- a/lib/rubygems/basic_specification.rb
+++ b/lib/rubygems/basic_specification.rb
@@ -76,8 +76,8 @@ class Gem::BasicSpecification
elsif missing_extensions?
@ignored = true
- if platform == Gem::Platform::RUBY || Gem::Platform.local === platform
- warn "Ignoring #{full_name} because its extensions are not built. " \
+ if Gem::Platform::RUBY == platform || Gem::Platform.local === platform
+ warn "Ignoring #{full_name} because its extensions are not built. " +
"Try: gem pristine #{name} --version #{version}"
end
@@ -133,9 +133,9 @@ class Gem::BasicSpecification
def full_name
if platform == Gem::Platform::RUBY || platform.nil?
- (+"#{name}-#{version}").tap(&Gem::UNTAINT)
+ "#{name}-#{version}".dup.tap(&Gem::UNTAINT)
else
- (+"#{name}-#{version}-#{platform}").tap(&Gem::UNTAINT)
+ "#{name}-#{version}-#{platform}".dup.tap(&Gem::UNTAINT)
end
end
@@ -145,15 +145,15 @@ class Gem::BasicSpecification
def full_require_paths
@full_require_paths ||=
- begin
- full_paths = raw_require_paths.map do |path|
- File.join full_gem_path, path.tap(&Gem::UNTAINT)
- end
+ begin
+ full_paths = raw_require_paths.map do |path|
+ File.join full_gem_path, path.tap(&Gem::UNTAINT)
+ end
- full_paths << extension_dir if have_extensions?
+ full_paths << extension_dir if have_extensions?
- full_paths
- end
+ full_paths
+ end
end
##
@@ -171,14 +171,18 @@ class Gem::BasicSpecification
def to_fullpath(path)
if activated?
@paths_map ||= {}
- Gem.suffixes.each do |suf|
- full_require_paths.each do |dir|
- fullpath = "#{dir}/#{path}#{suf}"
- next unless File.file?(fullpath)
- @paths_map[path] ||= fullpath
- end
+ @paths_map[path] ||=
+ begin
+ fullpath = nil
+ suffixes = Gem.suffixes
+ suffixes.find do |suf|
+ full_require_paths.find do |dir|
+ File.file?(fullpath = "#{dir}/#{path}#{suf}")
+ end
+ end ? fullpath : nil
end
- @paths_map[path]
+ else
+ nil
end
end
@@ -268,7 +272,7 @@ class Gem::BasicSpecification
# Return all files in this gem that match for +glob+.
def matches_for_glob(glob) # TODO: rename?
- glob = File.join(lib_dirs_glob, glob)
+ glob = File.join(self.lib_dirs_glob, glob)
Dir[glob].map {|f| f.tap(&Gem::UNTAINT) } # FIX our tests are broken, run w/ SAFE=1
end
@@ -285,17 +289,17 @@ class Gem::BasicSpecification
# for this spec.
def lib_dirs_glob
- dirs = if raw_require_paths
- if raw_require_paths.size > 1
- "{#{raw_require_paths.join(",")}}"
+ dirs = if self.raw_require_paths
+ if self.raw_require_paths.size > 1
+ "{#{self.raw_require_paths.join(',')}}"
else
- raw_require_paths.first
+ self.raw_require_paths.first
end
else
"lib" # default value for require_paths for bundler/inline
end
- "#{full_gem_path}/#{dirs}".dup.tap(&Gem::UNTAINT)
+ "#{self.full_gem_path}/#{dirs}".dup.tap(&Gem::UNTAINT)
end
##
@@ -320,15 +324,11 @@ class Gem::BasicSpecification
raise NotImplementedError
end
- def this
- self
- end
+ def this; self; end
private
- def have_extensions?
- !extensions.empty?
- end
+ def have_extensions?; !extensions.empty?; end
def have_file?(file, suffixes)
return true if raw_require_paths.any? do |path|
diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb
index cd51c37c59..5b34227d3a 100644
--- a/lib/rubygems/bundler_version_finder.rb
+++ b/lib/rubygems/bundler_version_finder.rb
@@ -65,8 +65,8 @@ module Gem::BundlerVersionFinder
return unless gemfile
lockfile = case gemfile
- when "gems.rb" then "gems.locked"
- else "#{gemfile}.lock"
+ when "gems.rb" then "gems.locked"
+ else "#{gemfile}.lock"
end.dup.tap(&Gem::UNTAINT)
return unless File.file?(lockfile)
diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb
index 01deac6890..07cf4e0e81 100644
--- a/lib/rubygems/command.rb
+++ b/lib/rubygems/command.rb
@@ -20,7 +20,9 @@ require_relative "user_interaction"
class Gem::Command
include Gem::UserInteraction
- Gem::OptionParser.accept Symbol, &:to_sym
+ Gem::OptionParser.accept Symbol do |value|
+ value.to_sym
+ end
##
# The name of the command.
@@ -92,7 +94,7 @@ class Gem::Command
# array or a string to be split on white space.
def self.add_specific_extra_args(cmd,args)
- args = args.split(/\s+/) if args.is_a? String
+ args = args.split(/\s+/) if args.kind_of? String
specific_extra_args_hash[cmd] = args
end
@@ -226,7 +228,7 @@ class Gem::Command
if args.size > 1
raise Gem::CommandLineError,
- "Too many gem names (#{args.join(", ")}); please specify only one"
+ "Too many gem names (#{args.join(', ')}); please specify only one"
end
args.first
@@ -314,7 +316,7 @@ class Gem::Command
options[:build_args] = build_args
if options[:silent]
- old_ui = ui
+ old_ui = self.ui
self.ui = ui = Gem::SilentUI.new
end
@@ -323,10 +325,6 @@ class Gem::Command
elsif @when_invoked
@when_invoked.call options
else
- if Gem.paths.auto_user_install && !options[:install_dir] && !options[:user_install]
- self.ui.say "Defaulting to user installation because default installation directory (#{Gem.default_dir}) is not writable."
- end
-
execute
end
ensure
@@ -400,21 +398,22 @@ class Gem::Command
def check_deprecated_options(options)
options.each do |option|
- next unless option_is_deprecated?(option)
- deprecation = @deprecated_options[command][option]
- version_to_expire = deprecation["rg_version_to_expire"]
+ if option_is_deprecated?(option)
+ deprecation = @deprecated_options[command][option]
+ version_to_expire = deprecation["rg_version_to_expire"]
- deprecate_option_msg = if version_to_expire
- "The \"#{option}\" option has been deprecated and will be removed in Rubygems #{version_to_expire}."
- else
- "The \"#{option}\" option has been deprecated and will be removed in future versions of Rubygems."
- end
+ deprecate_option_msg = if version_to_expire
+ "The \"#{option}\" option has been deprecated and will be removed in Rubygems #{version_to_expire}."
+ else
+ "The \"#{option}\" option has been deprecated and will be removed in future versions of Rubygems."
+ end
- extra_msg = deprecation["extra_msg"]
+ extra_msg = deprecation["extra_msg"]
- deprecate_option_msg += " #{extra_msg}" if extra_msg
+ deprecate_option_msg += " #{extra_msg}" if extra_msg
- alert_warning(deprecate_option_msg)
+ alert_warning(deprecate_option_msg)
+ end
end
end
@@ -431,10 +430,12 @@ class Gem::Command
# True if the command handles the given argument list.
def handles?(args)
- parser.parse!(args.dup)
- true
- rescue StandardError
- false
+ begin
+ parser.parse!(args.dup)
+ return true
+ rescue
+ return false
+ end
end
##
@@ -461,7 +462,7 @@ class Gem::Command
until extra.empty? do
ex = []
ex << extra.shift
- ex << extra.shift if /^[^-]/.match?(extra.first.to_s)
+ ex << extra.shift if extra.first.to_s =~ /^[^-]/ # rubocop:disable Performance/StartWith
result << ex if handles?(ex)
end
@@ -477,7 +478,7 @@ class Gem::Command
private
def option_is_deprecated?(option)
- @deprecated_options[command].key?(option)
+ @deprecated_options[command].has_key?(option)
end
def add_parser_description # :nodoc:
@@ -583,12 +584,12 @@ class Gem::Command
# Add the options common to all commands.
add_common_option("-h", "--help",
- "Get help on this command") do |_value, options|
+ "Get help on this command") do |value, options|
options[:help] = true
end
add_common_option("-V", "--[no-]verbose",
- "Set the verbose level of output") do |value, _options|
+ "Set the verbose level of output") do |value, options|
# Set us to "really verbose" so the progress meter works
if Gem.configuration.verbose && value
Gem.configuration.verbose = 1
@@ -597,12 +598,12 @@ class Gem::Command
end
end
- add_common_option("-q", "--quiet", "Silence command progress meter") do |_value, _options|
+ add_common_option("-q", "--quiet", "Silence command progress meter") do |value, options|
Gem.configuration.verbose = false
end
add_common_option("--silent",
- "Silence RubyGems output") do |_value, options|
+ "Silence RubyGems output") do |value, options|
options[:silent] = true
end
diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb
index c53f0231af..b3913d465a 100644
--- a/lib/rubygems/command_manager.rb
+++ b/lib/rubygems/command_manager.rb
@@ -141,7 +141,7 @@ class Gem::CommandManager
# Return a sorted list of all command names as strings.
def command_names
- @commands.keys.collect(&:to_s).sort
+ @commands.keys.collect {|key| key.to_s }.sort
end
##
@@ -201,7 +201,7 @@ class Gem::CommandManager
if possibilities.size > 1
raise Gem::CommandLineError,
- "Ambiguous command #{cmd_name} matches [#{possibilities.join(", ")}]"
+ "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]"
elsif possibilities.empty?
raise Gem::UnknownCommandError.new(cmd_name)
end
@@ -238,7 +238,7 @@ class Gem::CommandManager
load_error = e
end
Gem::Commands.const_get(const_name).new
- rescue StandardError => e
+ rescue Exception => e
e = load_error if load_error
alert_error clean_text("Loading command: #{command_name} (#{e.class})\n\t#{e}")
diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb
index 0ebdec565b..68e020d94a 100644
--- a/lib/rubygems/commands/build_command.rb
+++ b/lib/rubygems/commands/build_command.rb
@@ -12,11 +12,11 @@ class Gem::Commands::BuildCommand < Gem::Command
add_platform_option
- add_option "--force", "skip validation of the spec" do |_value, options|
+ add_option "--force", "skip validation of the spec" do |value, options|
options[:force] = true
end
- add_option "--strict", "consider warnings as errors when validating the spec" do |_value, options|
+ add_option "--strict", "consider warnings as errors when validating the spec" do |value, options|
options[:strict] = true
end
diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb
index 22864a9b29..344f31fba9 100644
--- a/lib/rubygems/commands/cert_command.rb
+++ b/lib/rubygems/commands/cert_command.rb
@@ -136,7 +136,7 @@ class Gem::Commands::CertCommand < Gem::Command
end
def build(email)
- unless valid_email?(email)
+ if !valid_email?(email)
raise Gem::CommandLineError, "Invalid email address #{email}"
end
@@ -178,9 +178,9 @@ class Gem::Commands::CertCommand < Gem::Command
algorithm = options[:key_algorithm] || Gem::Security::DEFAULT_KEY_ALGORITHM
key = Gem::Security.create_key(algorithm)
- key_path = Gem::Security.write key, "gem-private_key.pem", 0o600, passphrase
+ key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase
- [key, key_path]
+ return key, key_path
end
def certificates_matching(filter)
@@ -263,6 +263,7 @@ For further reading on signing gems see `ri Gem::Security`.
key = File.read key_file
passphrase = ENV["GEM_PRIVATE_KEY_PASSPHRASE"]
options[:key] = OpenSSL::PKey.read key, passphrase
+
rescue Errno::ENOENT
alert_error \
"--private-key not specified and ~/.gem/gem-private_key.pem does not exist"
@@ -291,7 +292,7 @@ For further reading on signing gems see `ri Gem::Security`.
cert = File.read cert_file
cert = OpenSSL::X509::Certificate.new cert
- permissions = File.stat(cert_file).mode & 0o777
+ permissions = File.stat(cert_file).mode & 0777
issuer_cert = options[:issuer_cert]
issuer_key = options[:key]
diff --git a/lib/rubygems/commands/check_command.rb b/lib/rubygems/commands/check_command.rb
index 6552258552..b300b4f87a 100644
--- a/lib/rubygems/commands/check_command.rb
+++ b/lib/rubygems/commands/check_command.rb
@@ -41,21 +41,17 @@ class Gem::Commands::CheckCommand < Gem::Command
def check_gems
say "Checking gems..."
say
- gems = begin
- get_all_gem_names
- rescue StandardError
- []
- end
+ gems = get_all_gem_names rescue []
Gem::Validator.new.alien(gems).sort.each do |key, val|
- if val.empty?
- say "#{key} is error-free" if Gem.configuration.verbose
- else
+ unless val.empty?
say "#{key} has #{val.size} problems"
val.each do |error_entry|
say " #{error_entry.path}:"
say " #{error_entry.problem}"
end
+ else
+ say "#{key} is error-free" if Gem.configuration.verbose
end
say
end
diff --git a/lib/rubygems/commands/cleanup_command.rb b/lib/rubygems/commands/cleanup_command.rb
index 26beba48df..ee5e1252b6 100644
--- a/lib/rubygems/commands/cleanup_command.rb
+++ b/lib/rubygems/commands/cleanup_command.rb
@@ -12,12 +12,12 @@ class Gem::Commands::CleanupCommand < Gem::Command
:check_dev => true
add_option("-n", "-d", "--dry-run",
- "Do not uninstall gems") do |_value, options|
+ "Do not uninstall gems") do |value, options|
options[:dryrun] = true
end
add_option(:Deprecated, "--dryrun",
- "Do not uninstall gems") do |_value, options|
+ "Do not uninstall gems") do |value, options|
options[:dryrun] = true
end
deprecate_option("--dryrun", extra_msg: "Use --dry-run instead")
@@ -75,7 +75,7 @@ If no gems are named all gems in GEM_HOME are cleaned.
until done do
clean_gems
- this_set = @gems_to_cleanup.map(&:full_name).sort
+ this_set = @gems_to_cleanup.map {|spec| spec.full_name }.sort
done = this_set.empty? || last_set == this_set
@@ -88,9 +88,9 @@ If no gems are named all gems in GEM_HOME are cleaned.
say "Clean up complete"
verbose do
- skipped = @default_gems.map(&:full_name)
+ skipped = @default_gems.map {|spec| spec.full_name }
- "Skipped default gems: #{skipped.join ", "}"
+ "Skipped default gems: #{skipped.join ', '}"
end
end
@@ -117,12 +117,12 @@ If no gems are named all gems in GEM_HOME are cleaned.
end
def get_candidate_gems
- @candidate_gems = if options[:args].empty?
- Gem::Specification.to_a
- else
+ @candidate_gems = unless options[:args].empty?
options[:args].map do |gem_name|
Gem::Specification.find_all_by_name gem_name
end.flatten
+ else
+ Gem::Specification.to_a
end
end
@@ -131,7 +131,9 @@ If no gems are named all gems in GEM_HOME are cleaned.
@primary_gems[spec.name].version != spec.version
end
- default_gems, gems_to_cleanup = gems_to_cleanup.partition(&:default_gem?)
+ default_gems, gems_to_cleanup = gems_to_cleanup.partition do |spec|
+ spec.default_gem?
+ end
uninstall_from = options[:user_install] ? Gem.user_dir : @original_home
diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb
index f3783468aa..f378441ca4 100644
--- a/lib/rubygems/commands/contents_command.rb
+++ b/lib/rubygems/commands/contents_command.rb
@@ -92,9 +92,9 @@ prefix or only the files that are requireable.
def files_in_gem(spec)
gem_path = spec.full_gem_path
- extra = "/{#{spec.require_paths.join ","}}" if options[:lib_only]
+ extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only]
glob = "#{gem_path}#{extra}/**/*"
- prefix_re = %r{#{Regexp.escape(gem_path)}/}
+ prefix_re = /#{Regexp.escape(gem_path)}\//
Dir[glob].map do |file|
[gem_path, file.sub(prefix_re, "")]
@@ -104,7 +104,7 @@ prefix or only the files that are requireable.
def files_in_default_gem(spec)
spec.files.map do |file|
case file
- when %r{\A#{spec.bindir}/}
+ when /\A#{spec.bindir}\//
# $' is POSTMATCH
[RbConfig::CONFIG["bindir"], $']
when /\.so\z/
@@ -178,7 +178,7 @@ prefix or only the files that are requireable.
@spec_dirs.sort.each {|dir| say dir }
end
- nil
+ return nil
end
def specification_directories # :nodoc:
diff --git a/lib/rubygems/commands/dependency_command.rb b/lib/rubygems/commands/dependency_command.rb
index 109bf03aff..cef98e30d3 100644
--- a/lib/rubygems/commands/dependency_command.rb
+++ b/lib/rubygems/commands/dependency_command.rb
@@ -18,7 +18,8 @@ class Gem::Commands::DependencyCommand < Gem::Command
add_prerelease_option
add_option("-R", "--[no-]reverse-dependencies",
- "Include reverse dependencies in the output") do |value, options|
+ "Include reverse dependencies in the output") do
+ |value, options|
options[:reverse_dependencies] = value
end
@@ -90,9 +91,10 @@ use with other commands.
def display_pipe(specs) # :nodoc:
specs.each do |spec|
- next if spec.dependencies.empty?
- spec.dependencies.sort_by(&:name).each do |dep|
- say "#{dep.name} --version '#{dep.requirement}'"
+ unless spec.dependencies.empty?
+ spec.dependencies.sort_by {|dep| dep.name }.each do |dep|
+ say "#{dep.name} --version '#{dep.requirement}'"
+ end
end
end
end
@@ -152,7 +154,7 @@ use with other commands.
response = String.new
response << " " * level + "Gem #{spec.full_name}\n"
unless spec.dependencies.empty?
- spec.dependencies.sort_by(&:name).each do |dep|
+ spec.dependencies.sort_by {|dep| dep.name }.each do |dep|
response << " " * level + " #{dep}\n"
end
end
diff --git a/lib/rubygems/commands/environment_command.rb b/lib/rubygems/commands/environment_command.rb
index 8ed0996069..28dbf93c50 100644
--- a/lib/rubygems/commands/environment_command.rb
+++ b/lib/rubygems/commands/environment_command.rb
@@ -17,7 +17,7 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
platform display the supported gem platforms
<omitted> display everything
EOF
- args.gsub(/^\s+/, "")
+ return args.gsub(/^\s+/, "")
end
def description # :nodoc:
@@ -108,7 +108,9 @@ lib/rubygems/defaults/operating_system.rb
out << " - RUBYGEMS VERSION: #{Gem::VERSION}\n"
- out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]\n"
+ out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
+ out << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+ out << ") [#{RUBY_PLATFORM}]\n"
out << " - INSTALLATION DIRECTORY: #{Gem.dir}\n"
@@ -171,6 +173,6 @@ lib/rubygems/defaults/operating_system.rb
end
end
- nil
+ return nil
end
end
diff --git a/lib/rubygems/commands/exec_command.rb b/lib/rubygems/commands/exec_command.rb
index d588804290..383c8c5b37 100644
--- a/lib/rubygems/commands/exec_command.rb
+++ b/lib/rubygems/commands/exec_command.rb
@@ -23,7 +23,7 @@ class Gem::Commands::ExecCommand < Gem::Command
add_option(:"Install/Update", "--conservative",
"Prefer the most recent installed version, ",
- "rather than the latest version overall") do |_value, options|
+ "rather than the latest version overall") do |value, options|
options[:conservative] = true
end
end
diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb
index 043e7d3691..20b99fa366 100644
--- a/lib/rubygems/commands/help_command.rb
+++ b/lib/rubygems/commands/help_command.rb
@@ -269,7 +269,7 @@ Gem::Platform::CURRENT. This will correctly mark the gem with your ruby's
platform.
EOF
- # NOTE: when updating also update Gem::Command::HELP
+ # NOTE when updating also update Gem::Command::HELP
SUBCOMMANDS = [
["commands", :show_commands],
@@ -324,11 +324,11 @@ platform.
margin_width = 4
- desc_width = @command_manager.command_names.map(&:size).max + 4
+ desc_width = @command_manager.command_names.map {|n| n.size }.max + 4
summary_width = 80 - margin_width - desc_width
wrap_indent = " " * (margin_width + desc_width)
- format = "#{" " * margin_width}%-#{desc_width}s%s"
+ format = "#{' ' * margin_width}%-#{desc_width}s%s"
@command_manager.command_names.each do |cmd_name|
command = @command_manager[cmd_name]
@@ -343,7 +343,7 @@ platform.
end
summary = wrap(summary, summary_width).split "\n"
- out << format(format, cmd_name, summary.shift)
+ out << sprintf(format, cmd_name, summary.shift)
until summary.empty? do
out << "#{wrap_indent}#{summary.shift}"
end
@@ -367,7 +367,7 @@ platform.
command = @command_manager[possibilities.first]
command.invoke("--help")
elsif possibilities.size > 1
- alert_warning "Ambiguous command #{command_name} (#{possibilities.join(", ")})"
+ alert_warning "Ambiguous command #{command_name} (#{possibilities.join(', ')})"
else
alert_warning "Unknown command #{command_name}. Try: gem help commands"
end
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index 9e59aee1c9..b0bc2908b4 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -48,7 +48,7 @@ class Gem::Commands::InstallCommand < Gem::Command
end
def defaults_str # :nodoc:
- "--both --version '#{Gem::Requirement.default}' --no-force\n" \
+ "--both --version '#{Gem::Requirement.default}' --no-force\n" +
"--install-dir #{Gem.dir} --lock\n" +
install_update_defaults_str
end
@@ -136,6 +136,13 @@ You can use `i` command instead of `install`.
"#{program_name} [options] GEMNAME [GEMNAME ...] -- --build-flags"
end
+ def check_install_dir # :nodoc:
+ if options[:install_dir] && options[:user_install]
+ alert_error "Use --install-dir or --user-install but not both"
+ terminate_interaction 1
+ end
+ end
+
def check_version # :nodoc:
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
@@ -155,6 +162,7 @@ You can use `i` command instead of `install`.
ENV.delete "GEM_PATH" if options[:install_dir].nil?
+ check_install_dir
check_version
load_hooks
@@ -163,7 +171,7 @@ You can use `i` command instead of `install`.
show_installed
- say update_suggestion if eligible_for_update?
+ say update_suggestion if eglible_for_update?
terminate_interaction exit_code
end
@@ -255,7 +263,7 @@ You can use `i` command instead of `install`.
return unless errors
errors.each do |x|
- next unless Gem::SourceFetchProblem === x
+ return unless Gem::SourceFetchProblem === x
require_relative "../uri"
msg = "Unable to pull data from '#{Gem::Uri.redact(x.source.uri)}': #{x.error.message}"
diff --git a/lib/rubygems/commands/open_command.rb b/lib/rubygems/commands/open_command.rb
index f342fa6c6b..5a13074a1d 100644
--- a/lib/rubygems/commands/open_command.rb
+++ b/lib/rubygems/commands/open_command.rb
@@ -70,7 +70,9 @@ class Gem::Commands::OpenCommand < Gem::Command
end
def open_editor(path)
- system(*@editor.split(/\s+/) + [path], { :chdir => path })
+ Dir.chdir(path) do
+ system(*@editor.split(/\s+/) + [path])
+ end
end
def spec_for(name)
diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb
index fce32aca3e..b51c9cf888 100644
--- a/lib/rubygems/commands/owner_command.rb
+++ b/lib/rubygems/commands/owner_command.rb
@@ -79,7 +79,7 @@ permission to.
say "Owners for gem: #{name}"
owners.each do |owner|
- say "- #{owner["email"] || owner["handle"] || owner["id"]}"
+ say "- #{owner['email'] || owner['handle'] || owner['id']}"
end
end
end
@@ -94,14 +94,16 @@ permission to.
def manage_owners(method, name, owners)
owners.each do |owner|
- response = send_owner_request(method, name, owner)
- action = method == :delete ? "Removing" : "Adding"
-
- with_response response, "#{action} #{owner}"
- rescue Gem::WebauthnVerificationError => e
- raise e
- rescue StandardError
- # ignore early exits to allow for completing the iteration of all owners
+ begin
+ response = send_owner_request(method, name, owner)
+ action = method == :delete ? "Removing" : "Adding"
+
+ with_response response, "#{action} #{owner}"
+ rescue Gem::WebauthnVerificationError => e
+ raise e
+ rescue StandardError
+ # ignore early exits to allow for completing the iteration of all owners
+ end
end
end
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 3dbbb3e50c..64608a033f 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -114,14 +114,16 @@ extensions will be restored.
spec.extensions && !spec.extensions.empty?
end
elsif options[:only_missing_extensions]
- Gem::Specification.select(&:missing_extensions?)
+ Gem::Specification.select do |spec|
+ spec.missing_extensions?
+ end
else
get_all_gem_names.sort.map do |gem_name|
Gem::Specification.find_all_by_name(gem_name, options[:version]).reverse
end.flatten
end
- specs = specs.select {|spec| spec.platform == RUBY_ENGINE || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY }
+ specs = specs.select {|spec| RUBY_ENGINE == spec.platform || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY }
if specs.to_a.empty?
raise Gem::Exception,
@@ -136,7 +138,7 @@ extensions will be restored.
next
end
- if options.key? :skip
+ if options.has_key? :skip
if options[:skip].include? spec.name
say "Skipped #{spec.full_name}, it was given through options"
next
diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb
index 418b46acc5..79ca3d59b0 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -30,7 +30,7 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
end
def initialize
- super "push", "Push a gem up to the gem server", :host => host
+ super "push", "Push a gem up to the gem server", :host => self.host
@user_defined_host = false
@@ -75,7 +75,7 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
@host ||= push_host
# Always include @host, even if it's nil
- args += [@host, push_host]
+ args += [ @host, push_host ]
say "Pushing gem to #{@host || Gem.host}..."
diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb
index e7d21f341b..4fa201272e 100644
--- a/lib/rubygems/commands/query_command.rb
+++ b/lib/rubygems/commands/query_command.rb
@@ -10,7 +10,7 @@ class Gem::Commands::QueryCommand < Gem::Command
include Gem::QueryUtils
- alias_method :warning_without_suggested_alternatives, :deprecation_warning
+ alias warning_without_suggested_alternatives deprecation_warning
def deprecation_warning
warning_without_suggested_alternatives
@@ -18,7 +18,8 @@ class Gem::Commands::QueryCommand < Gem::Command
alert_warning message unless Gem::Deprecate.skip
end
- def initialize(name = "query", summary = "Query gem information in local or remote repositories")
+ def initialize(name = "query",
+ summary = "Query gem information in local or remote repositories")
super name, summary,
:domain => :local, :details => false, :versions => true,
:installed => nil, :version => Gem::Requirement.default
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index c35d0f5ccc..df1732b49e 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -7,8 +7,8 @@ require_relative "../command"
# RubyGems checkout or tarball.
class Gem::Commands::SetupCommand < Gem::Command
- HISTORY_HEADER = %r{^#\s*[\d.a-zA-Z]+\s*/\s*\d{4}-\d{2}-\d{2}\s*$}.freeze
- VERSION_MATCHER = %r{^#\s*([\d.a-zA-Z]+)\s*/\s*\d{4}-\d{2}-\d{2}\s*$}.freeze
+ HISTORY_HEADER = /^#\s*[\d.a-zA-Z]+\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
+ VERSION_MATCHER = /^#\s*([\d.a-zA-Z]+)\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
ENV_PATHS = %w[/usr/bin/env /bin/env].freeze
@@ -55,9 +55,9 @@ class Gem::Commands::SetupCommand < Gem::Command
"List the documentation types you wish to",
"generate. For example: rdoc,ri" do |value, options|
options[:document] = case value
- when nil then %w[rdoc ri]
- when false then []
- else value
+ when nil then %w[rdoc ri]
+ when false then []
+ else value
end
end
@@ -134,7 +134,7 @@ prefix and suffix. If ruby was installed as `ruby18`, gem will be
installed as `gem18`.
By default, this RubyGems will install gem as:
- #{Gem.default_exec_format % "gem"}
+ #{Gem.default_exec_format % 'gem'}
EOF
end
@@ -243,7 +243,7 @@ By default, this RubyGems will install gem as:
end
def install_executables(bin_dir)
- prog_mode = options[:prog_mode] || 0o755
+ prog_mode = options[:prog_mode] || 0755
executables = { "gem" => "exe" }
executables.each do |tool, path|
@@ -357,7 +357,7 @@ By default, this RubyGems will install gem as:
say "Set the GEM_HOME environment variable if you want RDoc generated"
end
- false
+ return false
end
def install_default_bundler_gem(bin_dir)
@@ -369,7 +369,7 @@ By default, this RubyGems will install gem as:
File.dirname(loaded_from)
else
target_specs_dir = File.join(default_dir, "specifications", "default")
- mkdir_p target_specs_dir, :mode => 0o755
+ mkdir_p target_specs_dir, :mode => 0755
target_specs_dir
end
@@ -393,7 +393,7 @@ By default, this RubyGems will install gem as:
end
bundler_bin_dir = bundler_spec.bin_dir
- mkdir_p bundler_bin_dir, :mode => 0o755
+ mkdir_p bundler_bin_dir, :mode => 0755
bundler_spec.executables.each do |e|
cp File.join("bundler", bundler_spec.bindir, e), File.join(bundler_bin_dir, e)
end
@@ -430,10 +430,10 @@ By default, this RubyGems will install gem as:
lib_dir, bin_dir = generate_default_dirs
end
- mkdir_p lib_dir, :mode => 0o755
- mkdir_p bin_dir, :mode => 0o755
+ mkdir_p lib_dir, :mode => 0755
+ mkdir_p bin_dir, :mode => 0755
- [lib_dir, bin_dir]
+ return lib_dir, bin_dir
end
def generate_default_man_dir
@@ -639,10 +639,10 @@ abort "#{deprecation_message}"
dest_file = File.join dest_dir, file
dest_dir = File.dirname dest_file
unless File.directory? dest_dir
- mkdir_p dest_dir, :mode => 0o755
+ mkdir_p dest_dir, :mode => 0755
end
- install file, dest_file, :mode => options[:data_mode] || 0o644
+ install file, dest_file, :mode => options[:data_mode] || 0644
end
def remove_file_list(files, dir)
diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb
index c9c6ee80ed..85cc68ac09 100644
--- a/lib/rubygems/commands/sources_command.rb
+++ b/lib/rubygems/commands/sources_command.rb
@@ -71,7 +71,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
def check_typo_squatting(source)
if source.typo_squatting?("rubygems.org")
question = <<-QUESTION.chomp
-#{source.uri} is too similar to https://rubygems.org
+#{source.uri.to_s} is too similar to https://rubygems.org
Do you want to add this source?
QUESTION
@@ -83,8 +83,8 @@ Do you want to add this source?
def check_rubygems_https(source_uri) # :nodoc:
uri = URI source_uri
- if uri.scheme && uri.scheme.casecmp("http").zero? &&
- uri.host.casecmp("rubygems.org").zero?
+ if uri.scheme && uri.scheme.downcase == "http" &&
+ uri.host.downcase == "rubygems.org"
question = <<-QUESTION.chomp
https://rubygems.org is recommended for security over #{uri}
@@ -99,16 +99,16 @@ Do you want to add this insecure source?
path = Gem.spec_cache_dir
FileUtils.rm_rf path
- if File.exist? path
- if File.writable? path
- say "*** Unable to remove source cache ***"
- else
+ unless File.exist? path
+ say "*** Removed specs cache ***"
+ else
+ unless File.writable? path
say "*** Unable to remove source cache (write protected) ***"
+ else
+ say "*** Unable to remove source cache ***"
end
terminate_interaction 1
- else
- say "*** Removed specs cache ***"
end
end
@@ -194,13 +194,13 @@ To remove a source use the --remove argument:
end
def remove_source(source_uri) # :nodoc:
- if Gem.sources.include? source_uri
+ unless Gem.sources.include? source_uri
+ say "source #{source_uri} not present in cache"
+ else
Gem.sources.delete source_uri
Gem.configuration.write
say "#{source_uri} removed from sources"
- else
- say "source #{source_uri} not present in cache"
end
end
diff --git a/lib/rubygems/commands/specification_command.rb b/lib/rubygems/commands/specification_command.rb
index 938b9507f9..ed158506e0 100644
--- a/lib/rubygems/commands/specification_command.rb
+++ b/lib/rubygems/commands/specification_command.rb
@@ -21,19 +21,19 @@ class Gem::Commands::SpecificationCommand < Gem::Command
add_prerelease_option
add_option("--all", "Output specifications for all versions of",
- "the gem") do |_value, options|
+ "the gem") do |value, options|
options[:all] = true
end
- add_option("--ruby", "Output ruby format") do |_value, options|
+ add_option("--ruby", "Output ruby format") do |value, options|
options[:format] = :ruby
end
- add_option("--yaml", "Output YAML format") do |_value, options|
+ add_option("--yaml", "Output YAML format") do |value, options|
options[:format] = :yaml
end
- add_option("--marshal", "Output Marshal format") do |_value, options|
+ add_option("--marshal", "Output Marshal format") do |value, options|
options[:format] = :marshal
end
@@ -107,11 +107,7 @@ Specific fields in the specification can be extracted in YAML format:
if local?
if File.exist? gem
- begin
- specs << Gem::Package.new(gem).spec
- rescue StandardError
- nil
- end
+ specs << Gem::Package.new(gem).spec rescue nil
end
if specs.empty?
@@ -138,16 +134,16 @@ Specific fields in the specification can be extracted in YAML format:
end
unless options[:all]
- specs = [specs.max_by(&:version)]
+ specs = [specs.max_by {|s| s.version }]
end
specs.each do |s|
s = s.send field if field
say case options[:format]
- when :ruby then s.to_ruby
- when :marshal then Marshal.dump s
- else s.to_yaml
+ when :ruby then s.to_ruby
+ when :marshal then Marshal.dump s
+ else s.to_yaml
end
say "\n"
diff --git a/lib/rubygems/commands/stale_command.rb b/lib/rubygems/commands/stale_command.rb
index 0be2b85159..a94d77c193 100644
--- a/lib/rubygems/commands/stale_command.rb
+++ b/lib/rubygems/commands/stale_command.rb
@@ -18,7 +18,7 @@ longer using.
end
def usage # :nodoc:
- program_name.to_s
+ "#{program_name}"
end
def execute
@@ -34,7 +34,7 @@ longer using.
end
gem_to_atime.sort_by {|_, atime| atime }.each do |name, atime|
- say "#{name} at #{atime.strftime "%c"}"
+ say "#{name} at #{atime.strftime '%c'}"
end
end
end
diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb
index 7f6d5a4bb7..feba1c5b7c 100644
--- a/lib/rubygems/commands/uninstall_command.rb
+++ b/lib/rubygems/commands/uninstall_command.rb
@@ -19,7 +19,8 @@ class Gem::Commands::UninstallCommand < Gem::Command
:check_dev => false, :vendor => false
add_option("-a", "--[no-]all",
- "Uninstall all matching versions") do |value, options|
+ "Uninstall all matching versions"
+ ) do |value, options|
options[:all] = value
end
@@ -79,7 +80,7 @@ class Gem::Commands::UninstallCommand < Gem::Command
add_option("--vendor",
"Uninstall gem from the vendor directory.",
- "Only for use by gem repackagers.") do |_value, options|
+ "Only for use by gem repackagers.") do |value, options|
unless Gem.vendor_dir
raise Gem::OptionParser::InvalidOption.new "your platform is not supported"
end
@@ -95,7 +96,7 @@ class Gem::Commands::UninstallCommand < Gem::Command
end
def defaults_str # :nodoc:
- "--version '#{Gem::Requirement.default}' --no-force " \
+ "--version '#{Gem::Requirement.default}' --no-force " +
"--user-install"
end
@@ -138,7 +139,7 @@ that is a dependency of an existing gem. You can use the
end
def uninstall_all
- specs = Gem::Specification.reject(&:default_gem?)
+ specs = Gem::Specification.reject {|spec| spec.default_gem? }
specs.each do |spec|
options[:version] = spec.version
@@ -168,14 +169,15 @@ that is a dependency of an existing gem. You can use the
gems_to_uninstall = {}
deps.each do |dep|
- if original_gem_version[dep.name] == Gem::Requirement.default
- next if gems_to_uninstall[dep.name]
+ unless gems_to_uninstall[dep.name]
gems_to_uninstall[dep.name] = true
- else
- options[:version] = dep.version
- end
- uninstall_gem(dep.name)
+ unless original_gem_version[dep.name] == Gem::Requirement.default
+ options[:version] = dep.version
+ end
+
+ uninstall_gem(dep.name)
+ end
end
end
@@ -183,12 +185,12 @@ that is a dependency of an existing gem. You can use the
uninstall(gem_name)
rescue Gem::GemNotInHomeException => e
spec = e.spec
- alert("In order to remove #{spec.name}, please execute:\n" \
+ alert("In order to remove #{spec.name}, please execute:\n" +
"\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
rescue Gem::UninstallError => e
spec = e.spec
- alert_error("Error: unable to successfully uninstall '#{spec.name}' which is " \
- "located at '#{spec.full_gem_path}'. This is most likely because" \
+ alert_error("Error: unable to successfully uninstall '#{spec.name}' which is " +
+ "located at '#{spec.full_gem_path}'. This is most likely because" +
"the current user does not have the appropriate permissions")
terminate_interaction 1
end
diff --git a/lib/rubygems/commands/unpack_command.rb b/lib/rubygems/commands/unpack_command.rb
index 73eefe153c..1bff53429b 100644
--- a/lib/rubygems/commands/unpack_command.rb
+++ b/lib/rubygems/commands/unpack_command.rb
@@ -29,7 +29,7 @@ class Gem::Commands::UnpackCommand < Gem::Command
options[:target] = value
end
- add_option("--spec", "unpack the gem specification") do |_value, options|
+ add_option("--spec", "unpack the gem specification") do |value, options|
options[:spec] = true
end
@@ -96,10 +96,12 @@ command help for an example.
FileUtils.mkdir_p @options[:target] if @options[:target]
- destination = if @options[:target]
- File.join @options[:target], spec_file
- else
- spec_file
+ destination = begin
+ if @options[:target]
+ File.join @options[:target], spec_file
+ else
+ spec_file
+ end
end
File.open destination, "w" do |io|
@@ -130,7 +132,7 @@ command help for an example.
return this_path if File.exist? this_path
end
- nil
+ return nil
end
##
@@ -151,16 +153,16 @@ command help for an example.
# source directories?
def get_path(dependency)
- return dependency.name if /\.gem$/i.match?(dependency.name)
+ return dependency.name if dependency.name =~ /\.gem$/i
specs = dependency.matching_specs
- selected = specs.max_by(&:version)
+ selected = specs.max_by {|s| s.version }
return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless
selected
- return unless /^#{selected.name}$/i.match?(dependency.name)
+ return unless dependency.name =~ /^#{selected.name}$/i
# We expect to find (basename).gem in the 'cache' directory. Furthermore,
# the name match must be exact (ignoring case).
diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb
index fb27e755bc..6f084d1c38 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -37,10 +37,10 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
add_option("--system [VERSION]", Gem::Version,
- "Update the RubyGems system software") do |value, opts|
- value ||= true
+ "Update the RubyGems system software") do |value, options|
+ value = true unless value
- opts[:system] = value
+ options[:system] = value
end
add_local_remote_options
@@ -120,7 +120,7 @@ command to remove old versions.
updated = update_gems gems_to_update
installed_names = highest_installed_gems.keys
- updated_names = updated.map(&:name)
+ updated_names = updated.map {|spec| spec.name }
not_updated_names = options[:args].uniq - updated_names
not_installed_names = not_updated_names - installed_names
up_to_date_names = not_updated_names - not_installed_names
@@ -128,10 +128,10 @@ command to remove old versions.
if updated.empty?
say "Nothing to update"
else
- say "Gems updated: #{updated_names.join(" ")}"
+ say "Gems updated: #{updated_names.join(' ')}"
end
- say "Gems already up-to-date: #{up_to_date_names.join(" ")}" unless up_to_date_names.empty?
- say "Gems not currently installed: #{not_installed_names.join(" ")}" unless not_installed_names.empty?
+ say "Gems already up-to-date: #{up_to_date_names.join(' ')}" unless up_to_date_names.empty?
+ say "Gems not currently installed: #{not_installed_names.join(' ')}" unless not_installed_names.empty?
end
def fetch_remote_gems(spec) # :nodoc:
@@ -186,9 +186,7 @@ command to remove old versions.
system Gem.ruby, "--disable-gems", "setup.rb", *args
end
- unless options[:silent]
- say "RubyGems system software updated" if installed
- end
+ say "RubyGems system software updated" if installed unless options[:silent]
end
end
@@ -233,7 +231,7 @@ command to remove old versions.
highest_remote_tup = highest_remote_name_tuple(rubygems_update)
target = highest_remote_tup ? highest_remote_tup.version : version
- [target, requirement]
+ return target, requirement
end
def update_gem(name, version = Gem::Requirement.default)
@@ -303,7 +301,7 @@ command to remove old versions.
def which_to_update(highest_installed_gems, gem_names)
result = []
- highest_installed_gems.each do |_l_name, l_spec|
+ highest_installed_gems.each do |l_name, l_spec|
next if !gem_names.empty? &&
gem_names.none? {|name| name == l_spec.name }
diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb
index fbdc262549..d344a020c3 100644
--- a/lib/rubygems/commands/yank_command.rb
+++ b/lib/rubygems/commands/yank_command.rb
@@ -62,7 +62,7 @@ data you will need to change them immediately and yank your gem.
end
def yank_gem(version, platform)
- say "Yanking gem from #{host}..."
+ say "Yanking gem from #{self.host}..."
args = [:delete, version, platform, "api/v1/gems/yank"]
response = yank_api_request(*args)
@@ -89,7 +89,7 @@ data you will need to change them immediately and yank your gem.
def get_version_from_requirements(requirements)
requirements.requirements.first[1].version
- rescue StandardError
+ rescue
nil
end
diff --git a/lib/rubygems/compatibility.rb b/lib/rubygems/compatibility.rb
index 0d9df56f8a..b4c1ef16fa 100644
--- a/lib/rubygems/compatibility.rb
+++ b/lib/rubygems/compatibility.rb
@@ -26,16 +26,17 @@ module Gem
rubylibdir
].freeze
- if defined?(ConfigMap)
- RbConfigPriorities.each do |key|
- ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
- end
- else
+ unless defined?(ConfigMap)
##
# Configuration settings from ::RbConfig
ConfigMap = Hash.new do |cm, key|
cm[key] = RbConfig::CONFIG[key.to_s]
end
deprecate_constant(:ConfigMap)
+ else
+ RbConfigPriorities.each do |key|
+ ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
+ end
end
+
end
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index d90ec9f92c..68c653269e 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -190,8 +190,8 @@ class Gem::ConfigFile
system_config = load_file SYSTEM_WIDE_CONFIG_FILE
user_config = load_file config_file_name.dup.tap(&Gem::UNTAINT)
- environment_config = (ENV["GEMRC"] || "").
- split(File::PATH_SEPARATOR).inject({}) do |result, file|
+ environment_config = (ENV["GEMRC"] || "")
+ .split(File::PATH_SEPARATOR).inject({}) do |result, file|
result.merge load_file file
end
@@ -202,7 +202,7 @@ class Gem::ConfigFile
@hash = @hash.merge environment_config
end
- # HACK: these override command-line args, which is bad
+ # HACK these override command-line args, which is bad
@backtrace = @hash[:backtrace] if @hash.key? :backtrace
@bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
@home = @hash[:gemhome] if @hash.key? :gemhome
@@ -241,9 +241,9 @@ class Gem::ConfigFile
return if Gem.win_platform? # windows doesn't write 0600 as 0600
return unless File.exist? credentials_path
- existing_permissions = File.stat(credentials_path).mode & 0o777
+ existing_permissions = File.stat(credentials_path).mode & 0777
- return if existing_permissions == 0o600
+ return if existing_permissions == 0600
alert_error <<-ERROR
Your gem push credentials file located at:
@@ -324,9 +324,11 @@ if you believe they were disclosed to a third party.
require "fileutils"
FileUtils.mkdir_p(dirname)
- permissions = 0o600 & (~File.umask)
+ Gem.load_yaml
+
+ permissions = 0600 & (~File.umask)
File.open(credentials_path, "w", permissions) do |f|
- f.write self.class.dump_with_rubygems_yaml(config)
+ f.write config.to_yaml
end
load_api_keys # reload
@@ -342,18 +344,20 @@ if you believe they were disclosed to a third party.
end
def load_file(filename)
+ Gem.load_yaml
+
yaml_errors = [ArgumentError]
+ yaml_errors << Psych::SyntaxError if defined?(Psych::SyntaxError)
return {} unless filename && !filename.empty? && File.exist?(filename)
begin
- config = self.class.load_with_rubygems_config_hash(File.read(filename))
- if config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
+ content = Gem::SafeYAML.load(File.read(filename))
+ unless content.kind_of? Hash
warn "Failed to load #{filename} because it doesn't contain valid YAML hash"
return {}
- else
- return config
end
+ return content
rescue *yaml_errors => e
warn "Failed to load #{filename}, #{e}"
rescue Errno::EACCES
@@ -473,17 +477,17 @@ if you believe they were disclosed to a third party.
yaml_hash[:ssl_client_cert] =
@hash[:ssl_client_cert] if @hash.key? :ssl_client_cert
- keys = yaml_hash.keys.map(&:to_s)
+ keys = yaml_hash.keys.map {|key| key.to_s }
keys << "debug"
re = Regexp.union(*keys)
@hash.each do |key, value|
key = key.to_s
- next if key&.match?(re)
+ next if key =~ re
yaml_hash[key.to_s] = value
end
- self.class.dump_with_rubygems_yaml(yaml_hash)
+ yaml_hash.to_yaml
end
# Writes out this config file, replacing its source.
@@ -518,57 +522,6 @@ if you believe they were disclosed to a third party.
attr_reader :hash
protected :hash
- def self.dump_with_rubygems_yaml(content)
- content.transform_keys! do |k|
- k.is_a?(Symbol) ? ":#{k}" : k
- end
-
- require_relative "yaml_serializer"
- Gem::YAMLSerializer.dump(content)
- end
-
- def self.load_with_rubygems_config_hash(yaml)
- require_relative "yaml_serializer"
-
- content = Gem::YAMLSerializer.load(yaml)
-
- content.transform_keys! do |k|
- if k.match?(/\A:(.*)\Z/)
- k[1..-1].to_sym
- elsif k.include?("__") || k.match?(%r{/\Z})
- if k.is_a?(Symbol)
- k.to_s.gsub(/__/,".").gsub(%r{/\Z}, "").to_sym
- else
- k.dup.gsub(/__/,".").gsub(%r{/\Z}, "")
- end
- else
- k
- end
- end
-
- content.transform_values! do |v|
- if v.is_a?(String)
- if v.match?(/\A:(.*)\Z/)
- v[1..-1].to_sym
- elsif v.match?(/\A[+-]?\d+\Z/)
- v.to_i
- elsif v.match?(/\Atrue|false\Z/)
- v == "true"
- elsif v.empty?
- nil
- else
- v
- end
- elsif v.is_a?(Hash) && v.empty?
- nil
- else
- v
- end
- end
-
- content
- end
-
private
def set_config_file_name(args)
@@ -581,7 +534,7 @@ if you believe they were disclosed to a third party.
need_config_file_name = false
elsif arg =~ /^--config-file=(.*)/
@config_file_name = $1
- elsif /^--config-file$/.match?(arg)
+ elsif arg =~ /^--config-file$/
need_config_file_name = true
end
end
diff --git a/lib/rubygems/core_ext/kernel_gem.rb b/lib/rubygems/core_ext/kernel_gem.rb
index 4e09b95c44..b2f97b9ed9 100644
--- a/lib/rubygems/core_ext/kernel_gem.rb
+++ b/lib/rubygems/core_ext/kernel_gem.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
module Kernel
+
##
# Use Kernel#gem to activate a specific version of +gem_name+.
#
@@ -36,9 +37,9 @@ module Kernel
skip_list = (ENV["GEM_SKIP"] || "").split(/:/)
raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name
- if gem_name.is_a? Gem::Dependency
+ if gem_name.kind_of? Gem::Dependency
unless Gem::Deprecate.skip
- warn "#{Gem.location_of_caller.join ":"}:Warning: Kernel.gem no longer "\
+ warn "#{Gem.location_of_caller.join ':'}:Warning: Kernel.gem no longer "\
"accepts a Gem::Dependency object, please pass the name "\
"and requirements directly"
end
@@ -65,4 +66,5 @@ module Kernel
end
private :gem
+
end
diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb
index ddb44276eb..0869c8746f 100644
--- a/lib/rubygems/core_ext/kernel_require.rb
+++ b/lib/rubygems/core_ext/kernel_require.rb
@@ -9,12 +9,13 @@
require "monitor"
module Kernel
+
RUBYGEMS_ACTIVATION_MONITOR = Monitor.new # :nodoc:
# Make sure we have a reference to Ruby's original Kernel#require
unless defined?(gem_original_require)
# :stopdoc:
- alias_method :gem_original_require, :require
+ alias gem_original_require require
private :gem_original_require
# :startdoc:
end
@@ -36,37 +37,53 @@ module Kernel
def require(path) # :doc:
return gem_original_require(path) unless Gem.discover_gems_on_require
- RUBYGEMS_ACTIVATION_MONITOR.synchronize do
- path = File.path(path)
+ begin
+ RUBYGEMS_ACTIVATION_MONITOR.enter
+
+ path = path.to_path if path.respond_to? :to_path
if spec = Gem.find_unresolved_default_spec(path)
# Ensure -I beats a default gem
resolved_path = begin
rp = nil
load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths
- Gem.suffixes.find do |s|
- $LOAD_PATH[0...load_path_check_index].find do |lp|
+ Gem.suffixes.each do |s|
+ $LOAD_PATH[0...load_path_check_index].each do |lp|
safe_lp = lp.dup.tap(&Gem::UNTAINT)
- if File.symlink? safe_lp # for backward compatibility
- next
+ begin
+ if File.symlink? safe_lp # for backward compatibility
+ next
+ end
+ rescue SecurityError
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ raise
end
full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}"))
- rp = full_path if File.file?(full_path)
+ if File.file?(full_path)
+ rp = full_path
+ break
+ end
end
+ break if rp
end
rp
end
- Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease) unless
- resolved_path
+ begin
+ Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease)
+ rescue Exception
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ raise
+ end unless resolved_path
end
# If there are no unresolved deps, then we can use just try
# normal require handle loading a gem from the rescue below.
if Gem::Specification.unresolved_deps.empty?
- next
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ return gem_original_require(path)
end
# If +path+ is for a gem that has already been loaded, don't
@@ -76,7 +93,8 @@ module Kernel
# TODO request access to the C implementation of this to speed up RubyGems
if Gem::Specification.find_active_stub_by_path(path)
- next
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ return gem_original_require(path)
end
# Attempt to find +path+ in any unresolved gems...
@@ -96,7 +114,9 @@ module Kernel
if found_specs.empty?
found_specs = Gem::Specification.find_in_unresolved_tree path
- found_specs.each(&:activate)
+ found_specs.each do |found_spec|
+ found_spec.activate
+ end
# We found +path+ directly in an unresolved gem. Now we figure out, of
# the possible found specs, which one we should activate.
@@ -107,7 +127,8 @@ module Kernel
names = found_specs.map(&:name).uniq
if names.size > 1
- raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ", "}"
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ', '}"
end
# Ok, now find a gem that has no conflicts, starting
@@ -117,20 +138,26 @@ module Kernel
unless valid
le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate"
le.name = names.first
+ RUBYGEMS_ACTIVATION_MONITOR.exit
raise le
end
valid.activate
end
- end
- begin
- gem_original_require(path)
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ return gem_original_require(path)
rescue LoadError => load_error
- if load_error.path == path &&
- RUBYGEMS_ACTIVATION_MONITOR.synchronize { Gem.try_activate(path) }
+ if load_error.path == path
+ RUBYGEMS_ACTIVATION_MONITOR.enter
- return gem_original_require(path)
+ begin
+ require_again = Gem.try_activate(path)
+ ensure
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ end
+
+ return gem_original_require(path) if require_again
end
raise load_error
@@ -138,4 +165,5 @@ module Kernel
end
private :require
+
end
diff --git a/lib/rubygems/core_ext/kernel_warn.rb b/lib/rubygems/core_ext/kernel_warn.rb
index 9dc9f2218c..1f4c77f04b 100644
--- a/lib/rubygems/core_ext/kernel_warn.rb
+++ b/lib/rubygems/core_ext/kernel_warn.rb
@@ -35,10 +35,11 @@ module Kernel
start += 1
- next unless path = loc.path
- unless path.start_with?(rubygems_path, "<internal:")
- # Non-rubygems frames
- uplevel -= 1
+ if path = loc.path
+ unless path.start_with?(rubygems_path) || path.start_with?("<internal:")
+ # Non-rubygems frames
+ uplevel -= 1
+ end
end
end
kw[:uplevel] = start
diff --git a/lib/rubygems/core_ext/tcpsocket_init.rb b/lib/rubygems/core_ext/tcpsocket_init.rb
index 018c49dbeb..451ffa50b2 100644
--- a/lib/rubygems/core_ext/tcpsocket_init.rb
+++ b/lib/rubygems/core_ext/tcpsocket_init.rb
@@ -19,7 +19,7 @@ module CoreExtensions
cond_var = Thread::ConditionVariable.new
Addrinfo.foreach(host, serv, nil, :STREAM) do |addr|
- Thread.report_on_exception = false
+ Thread.report_on_exception = false if defined? Thread.report_on_exception = ()
threads << Thread.new(addr) do
# give head start to ipv6 addresses
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index 7888e8cee5..2b1baa333d 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -80,7 +80,7 @@ module Gem
def self.find_home
Dir.home.dup
- rescue StandardError
+ rescue
if Gem.win_platform?
File.expand_path File.join(ENV["HOMEDRIVE"] || ENV["SystemDrive"], "/")
else
@@ -184,11 +184,7 @@ module Gem
# Deduce Ruby's --program-prefix and --program-suffix from its install name
def self.default_exec_format
- exec_format = begin
- RbConfig::CONFIG["ruby_install_name"].sub("ruby", "%s")
- rescue StandardError
- "%s"
- end
+ exec_format = RbConfig::CONFIG["ruby_install_name"].sub("ruby", "%s") rescue "%s"
unless exec_format.include?("%s")
raise Gem::Exception,
diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb
index 00eff2dfe7..d9e0c07b0f 100644
--- a/lib/rubygems/dependency.rb
+++ b/lib/rubygems/dependency.rb
@@ -46,10 +46,10 @@ class Gem::Dependency
end
type = Symbol === requirements.last ? requirements.pop : :runtime
- requirements = requirements.first if requirements.length == 1 # unpack
+ requirements = requirements.first if 1 == requirements.length # unpack
unless TYPES.include? type
- raise ArgumentError, "Valid types are #{TYPES.inspect}, " \
+ raise ArgumentError, "Valid types are #{TYPES.inspect}, " +
"not #{type.inspect}"
end
@@ -74,9 +74,11 @@ class Gem::Dependency
def inspect # :nodoc:
if prerelease?
- format("<%s type=%p name=%p requirements=%p prerelease=ok>", self.class, type, name, requirement.to_s)
+ "<%s type=%p name=%p requirements=%p prerelease=ok>" %
+ [self.class, self.type, self.name, requirement.to_s]
else
- format("<%s type=%p name=%p requirements=%p>", self.class, type, name, requirement.to_s)
+ "<%s type=%p name=%p requirements=%p>" %
+ [self.class, self.type, self.name, requirement.to_s]
end
end
@@ -167,16 +169,16 @@ class Gem::Dependency
def ==(other) # :nodoc:
Gem::Dependency === other &&
- name == other.name &&
- type == other.type &&
- requirement == other.requirement
+ self.name == other.name &&
+ self.type == other.type &&
+ self.requirement == other.requirement
end
##
# Dependencies are ordered by name.
def <=>(other)
- name <=> other.name
+ self.name <=> other.name
end
##
@@ -203,7 +205,7 @@ class Gem::Dependency
requirement.satisfied_by? version
end
- alias_method :===, :=~
+ alias === =~
##
# :call-seq:
@@ -261,7 +263,7 @@ class Gem::Dependency
end
default = Gem::Requirement.default
- self_req = requirement
+ self_req = self.requirement
other_req = other.requirement
return self.class.new name, self_req if other_req == default
@@ -322,9 +324,9 @@ class Gem::Dependency
end
def to_spec
- matches = to_specs.compact
+ matches = self.to_specs.compact
- active = matches.find(&:activated?)
+ active = matches.find {|spec| spec.activated? }
return active if active
unless prerelease?
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index 56a9309a7e..a8d73e521b 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -19,12 +19,12 @@ class Gem::DependencyInstaller
DEFAULT_OPTIONS = { # :nodoc:
:env_shebang => false,
:document => %w[ri],
- :domain => :both, # HACK: dup
+ :domain => :both, # HACK dup
:force => false,
- :format_executable => false, # HACK: dup
+ :format_executable => false, # HACK dup
:ignore_dependencies => false,
:prerelease => false,
- :security_policy => nil, # HACK: NoSecurity requires OpenSSL. AlmostNo? Low?
+ :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low?
:wrappers => true,
:build_args => nil,
:build_docs_in_background => false,
@@ -66,7 +66,7 @@ class Gem::DependencyInstaller
# :build_args:: See Gem::Installer::new
def initialize(options = {})
- @only_install_dir = !options[:install_dir].nil?
+ @only_install_dir = !!options[:install_dir]
@install_dir = options[:install_dir] || Gem.dir
@build_root = options[:build_root]
@@ -163,11 +163,13 @@ class Gem::DependencyInstaller
specs = []
tuples.each do |tup, source|
- spec = source.fetch_spec(tup)
- rescue Gem::RemoteFetcher::FetchError => e
- errors << Gem::SourceFetchProblem.new(source, e)
- else
- specs << [spec, source]
+ begin
+ spec = source.fetch_spec(tup)
+ rescue Gem::RemoteFetcher::FetchError => e
+ errors << Gem::SourceFetchProblem.new(source, e)
+ else
+ specs << [spec, source]
+ end
end
if @errors
@@ -177,6 +179,7 @@ class Gem::DependencyInstaller
end
set << specs
+
rescue Gem::RemoteFetcher::FetchError => e
# FIX if there is a problem talking to the network, we either need to always tell
# the user (no really_verbose) or fail hard, not silently tell them that we just
@@ -291,11 +294,13 @@ class Gem::DependencyInstaller
src = Gem::Source::SpecificFile.new dep_or_name
installer_set.add_local dep_or_name, src.spec, src
version = src.spec.version if version == Gem::Requirement.default
- elsif dep_or_name =~ /\.gem$/ # rubocop:disable Performance/RegexpMatch
+ elsif dep_or_name =~ /\.gem$/
Dir[dep_or_name].each do |name|
- src = Gem::Source::SpecificFile.new name
- installer_set.add_local dep_or_name, src.spec, src
- rescue Gem::Package::FormatError
+ begin
+ src = Gem::Source::SpecificFile.new name
+ installer_set.add_local dep_or_name, src.spec, src
+ rescue Gem::Package::FormatError
+ end
end
# else This is a dependency. InstallerSet handles this case
end
diff --git a/lib/rubygems/dependency_list.rb b/lib/rubygems/dependency_list.rb
index 30098ff0b5..5820298bb9 100644
--- a/lib/rubygems/dependency_list.rb
+++ b/lib/rubygems/dependency_list.rb
@@ -105,7 +105,7 @@ class Gem::DependencyList
end
def inspect # :nodoc:
- format("%s %p>", super[0..-2], map(&:full_name))
+ "%s %p>" % [super[0..-2], map {|s| s.full_name }]
end
##
diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb
index 58a6c5b7dc..9fff306949 100644
--- a/lib/rubygems/deprecate.rb
+++ b/lib/rubygems/deprecate.rb
@@ -70,6 +70,7 @@
# end
module Gem::Deprecate
+
def self.skip # :nodoc:
@skip ||= false
end
@@ -82,8 +83,7 @@ module Gem::Deprecate
# Temporarily turn off warnings. Intended for tests only.
def skip_during
- original = Gem::Deprecate.skip
- Gem::Deprecate.skip = true
+ Gem::Deprecate.skip, original = true, Gem::Deprecate.skip
yield
ensure
Gem::Deprecate.skip = original
@@ -104,13 +104,12 @@ module Gem::Deprecate
old = "_deprecated_#{name}"
alias_method old, name
define_method name do |*args, &block|
- klass = is_a? Module
+ klass = self.kind_of? Module
target = klass ? "#{self}." : "#{self.class}#"
- msg = [
- "NOTE: #{target}#{name} is deprecated",
- repl == :none ? " with no replacement" : "; use #{repl} instead",
- format(". It will be removed on or after %4d-%02d.", year, month),
- "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
+ msg = [ "NOTE: #{target}#{name} is deprecated",
+ repl == :none ? " with no replacement" : "; use #{repl} instead",
+ ". It will be removed on or after %4d-%02d." % [year, month],
+ "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
]
warn "#{msg.join}." unless Gem::Deprecate.skip
send old, *args, &block
@@ -130,13 +129,12 @@ module Gem::Deprecate
old = "_deprecated_#{name}"
alias_method old, name
define_method name do |*args, &block|
- klass = is_a? Module
+ klass = self.kind_of? Module
target = klass ? "#{self}." : "#{self.class}#"
- msg = [
- "NOTE: #{target}#{name} is deprecated",
- replacement == :none ? " with no replacement" : "; use #{replacement} instead",
- ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
- "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
+ msg = [ "NOTE: #{target}#{name} is deprecated",
+ replacement == :none ? " with no replacement" : "; use #{replacement} instead",
+ ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
+ "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
]
warn "#{msg.join}." unless Gem::Deprecate.skip
send old, *args, &block
@@ -153,15 +151,15 @@ module Gem::Deprecate
end
define_method "deprecation_warning" do
- msg = [
- "#{command} command is deprecated",
- ". It will be removed in Rubygems #{version}.\n",
+ msg = [ "#{self.command} command is deprecated",
+ ". It will be removed in Rubygems #{version}.\n",
]
- alert_warning msg.join.to_s unless Gem::Deprecate.skip
+ alert_warning "#{msg.join}" unless Gem::Deprecate.skip
end
end
end
module_function :rubygems_deprecate, :rubygems_deprecate_command, :skip_during
+
end
diff --git a/lib/rubygems/doctor.rb b/lib/rubygems/doctor.rb
index 56b7c081eb..1d3889af77 100644
--- a/lib/rubygems/doctor.rb
+++ b/lib/rubygems/doctor.rb
@@ -33,7 +33,7 @@ class Gem::Doctor
Gem::REPOSITORY_SUBDIRECTORIES.sort -
REPOSITORY_EXTENSION_MAP.map {|(k,_)| k }.sort
- raise "Update REPOSITORY_EXTENSION_MAP, missing: #{missing.join ", "}" unless
+ raise "Update REPOSITORY_EXTENSION_MAP, missing: #{missing.join ', '}" unless
missing.empty?
##
@@ -53,7 +53,7 @@ class Gem::Doctor
# Specs installed in this gem repository
def installed_specs # :nodoc:
- @installed_specs ||= Gem::Specification.map(&:full_name)
+ @installed_specs ||= Gem::Specification.map {|s| s.full_name }
end
##
@@ -75,7 +75,7 @@ class Gem::Doctor
Gem.use_paths @gem_repository.to_s
unless gem_repository?
- say "This directory does not appear to be a RubyGems repository, " \
+ say "This directory does not appear to be a RubyGems repository, " +
"skipping"
say
return
@@ -104,16 +104,16 @@ class Gem::Doctor
directory = File.join(@gem_repository, sub_directory)
Dir.entries(directory).sort.each do |ent|
- next if [".", ".."].include?(ent)
+ next if ent == "." || ent == ".."
child = File.join(directory, ent)
next unless File.exist?(child)
basename = File.basename(child, extension)
next if installed_specs.include? basename
- next if /^rubygems-\d/.match?(basename)
- next if sub_directory == "specifications" && basename == "default"
- next if sub_directory == "plugins" && Gem.plugin_suffix_regexp =~ (basename)
+ next if /^rubygems-\d/ =~ basename
+ next if "specifications" == sub_directory && "default" == basename
+ next if "plugins" == sub_directory && Gem.plugin_suffix_regexp =~ (basename)
type = File.directory?(child) ? "directory" : "file"
diff --git a/lib/rubygems/errors.rb b/lib/rubygems/errors.rb
index be6c34dc85..b36fabffc2 100644
--- a/lib/rubygems/errors.rb
+++ b/lib/rubygems/errors.rb
@@ -61,7 +61,7 @@ module Gem
def build_message
names = specs.map(&:full_name)
- "Could not find '#{name}' (#{requirement}) - did find: [#{names.join ","}]\n"
+ "Could not find '#{name}' (#{requirement}) - did find: [#{names.join ','}]\n"
end
end
@@ -134,7 +134,11 @@ module Gem
##
# A wordy description of the error.
def wordy
- format("Found %s (%s), but was for platform%s %s", @name, @version, @platforms.size == 1 ? "" : "s", @platforms.join(" ,"))
+ "Found %s (%s), but was for platform%s %s" %
+ [@name,
+ @version,
+ @platforms.size == 1 ? "" : "s",
+ @platforms.join(" ,")]
end
end
@@ -171,6 +175,6 @@ module Gem
##
# The "exception" alias allows you to call raise on a SourceFetchProblem.
- alias_method :exception, :error
+ alias exception error
end
end
diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb
index 65caaab8b1..b92396f0ef 100644
--- a/lib/rubygems/exceptions.rb
+++ b/lib/rubygems/exceptions.rb
@@ -172,7 +172,6 @@ class Gem::ImpossibleDependenciesError < Gem::Exception
end
class Gem::InstallError < Gem::Exception; end
-
class Gem::RuntimeRequirementNotMetError < Gem::InstallError
attr_accessor :suggestion
def message
@@ -232,7 +231,7 @@ class Gem::SystemExitException < SystemExit
##
# The exit code for the process
- alias_method :exit_code, :status
+ alias exit_code status
##
# Creates a new SystemExitException with the given +exit_code+
@@ -265,7 +264,7 @@ class Gem::UnsatisfiableDependencyError < Gem::DependencyError
def initialize(dep, platform_mismatch=nil)
if platform_mismatch && !platform_mismatch.empty?
plats = platform_mismatch.map {|x| x.platform.to_s }.sort.uniq
- super "Unable to resolve dependency: No match for '#{dep}' on this platform. Found: #{plats.join(", ")}"
+ super "Unable to resolve dependency: No match for '#{dep}' on this platform. Found: #{plats.join(', ')}"
else
if dep.explicit?
super "Unable to resolve dependency: user requested '#{dep}'"
diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb
index 242dd0125a..4960ddd7b1 100644
--- a/lib/rubygems/ext/builder.rb
+++ b/lib/rubygems/ext/builder.rb
@@ -27,17 +27,19 @@ class Gem::Ext::Builder
# try to find make program from Ruby configure arguments first
RbConfig::CONFIG["configure_args"] =~ /with-make-prog\=(\w+)/
make_program_name = ENV["MAKE"] || ENV["make"] || $1
- make_program_name ||= RUBY_PLATFORM.include?("mswin") ? "nmake" : "make"
+ unless make_program_name
+ make_program_name = (RUBY_PLATFORM.include?("mswin")) ? "nmake" : "make"
+ end
make_program = Shellwords.split(make_program_name)
# The installation of the bundled gems is failed when DESTDIR is empty in mswin platform.
- destdir = /\bnmake/i !~ make_program_name || ENV["DESTDIR"] && ENV["DESTDIR"] != "" ? format("DESTDIR=%s", ENV["DESTDIR"]) : ""
+ destdir = (/\bnmake/i !~ make_program_name || ENV["DESTDIR"] && ENV["DESTDIR"] != "") ? "DESTDIR=%s" % ENV["DESTDIR"] : ""
env = [destdir]
if sitedir
- env << format("sitearchdir=%s", sitedir)
- env << format("sitelibdir=%s", sitedir)
+ env << "sitearchdir=%s" % sitedir
+ env << "sitelibdir=%s" % sitedir
end
targets.each do |target|
@@ -75,8 +77,7 @@ class Gem::Ext::Builder
verbose = Gem.configuration.really_verbose
begin
- rubygems_gemdeps = ENV["RUBYGEMS_GEMDEPS"]
- ENV["RUBYGEMS_GEMDEPS"] = nil
+ rubygems_gemdeps, ENV["RUBYGEMS_GEMDEPS"] = ENV["RUBYGEMS_GEMDEPS"], nil
if verbose
puts("current directory: #{dir}")
p(command)
@@ -89,7 +90,7 @@ class Gem::Ext::Builder
build_env = { "SOURCE_DATE_EPOCH" => Gem.source_date_epoch_string }.merge(env)
output, status = begin
Open3.capture2e(build_env, *command, :chdir => dir)
- rescue StandardError => error
+ rescue => error
raise Gem::InstallError, "#{command_name || class_name} failed#{error.message}"
end
if verbose
@@ -189,7 +190,7 @@ EOF
verbose { results.join("\n") }
write_gem_make_out results.join "\n"
- rescue StandardError => e
+ rescue => e
results << e.message
build_error(results.join("\n"), $@)
end
@@ -205,7 +206,7 @@ EOF
if @build_args.empty?
say "Building native extensions. This could take a while..."
else
- say "Building native extensions with: '#{@build_args.join " "}'"
+ say "Building native extensions with: '#{@build_args.join ' '}'"
say "This could take a while..."
end
diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb
index 885201e20b..ce3b296f79 100644
--- a/lib/rubygems/ext/cargo_builder.rb
+++ b/lib/rubygems/ext/cargo_builder.rb
@@ -199,7 +199,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
output, status =
begin
Open3.capture2e(cargo, "metadata", "--no-deps", "--format-version", "1", :chdir => cargo_dir)
- rescue StandardError => error
+ rescue => error
raise Gem::InstallError, "cargo metadata failed #{error.message}"
end
@@ -246,10 +246,10 @@ EOF
end
def rustc_dynamic_linker_flags(dest_dir, crate_name)
- split_flags("DLDFLAGS").
- map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir, crate_name) }.
- compact.
- flat_map {|arg| ldflag_to_link_modifier(arg) }
+ split_flags("DLDFLAGS")
+ .map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir, crate_name) }
+ .compact
+ .flat_map {|arg| ldflag_to_link_modifier(arg) }
end
def rustc_lib_flags(dest_dir)
@@ -313,7 +313,7 @@ EOF
deffile_path
end
- # We have to basically reimplement <code>RbConfig::CONFIG['SOEXT']</code> here to support
+ # We have to basically reimplement RbConfig::CONFIG['SOEXT'] here to support
# Ruby < 2.5
#
# @see https://github.com/ruby/ruby/blob/c87c027f18c005460746a74c07cd80ee355b16e4/configure.ac#L3185
diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb
index 7efd4a06b7..9c22329fe3 100644
--- a/lib/rubygems/ext/ext_conf_builder.rb
+++ b/lib/rubygems/ext/ext_conf_builder.rb
@@ -43,7 +43,7 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
full_tmp_dest = File.join(extension_dir, tmp_dest_relative)
- # TODO: remove in RubyGems 4
+ # TODO remove in RubyGems 4
if Gem.install_extension_in_lib && lib_dir
FileUtils.mkdir_p lib_dir
entries = Dir.entries(full_tmp_dest) - %w[. ..]
@@ -66,6 +66,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
FileUtils.rm_rf tmp_dest if tmp_dest
end
+ private
+
def self.get_relative_path(path, base)
path[0..base.length - 1] = "." if path.start_with?(base)
path
diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb
index 0171807b39..8f39a63e11 100644
--- a/lib/rubygems/ext/rake_builder.rb
+++ b/lib/rubygems/ext/rake_builder.rb
@@ -10,7 +10,7 @@ require_relative "../shellwords"
class Gem::Ext::RakeBuilder < Gem::Ext::Builder
def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd)
- if /mkrf_conf/i.match?(File.basename(extension))
+ if File.basename(extension) =~ /mkrf_conf/i
run([Gem.ruby, File.basename(extension), *args], results, class_name, extension_dir)
end
diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb
index 8335a0ad03..d238a5863b 100644
--- a/lib/rubygems/gem_runner.rb
+++ b/lib/rubygems/gem_runner.rb
@@ -33,11 +33,7 @@ class Gem::GemRunner
do_configuration args
- begin
- Gem.load_env_plugins
- rescue StandardError
- nil
- end
+ Gem.load_env_plugins rescue nil
Gem.load_plugins
cmd = @command_manager_class.instance
@@ -45,10 +41,10 @@ class Gem::GemRunner
cmd.command_names.each do |command_name|
config_args = Gem.configuration[command_name]
config_args = case config_args
- when String
- config_args.split " "
- else
- Array(config_args)
+ when String
+ config_args.split " "
+ else
+ Array(config_args)
end
Gem::Command.add_specific_extra_args command_name, config_args
end
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb
index 074a0df334..92739617f6 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -9,8 +9,9 @@ require_relative "gemcutter_utilities/webauthn_poller"
# Utility methods for using the RubyGems API.
module Gem::GemcutterUtilities
+
ERROR_CODE = 1
- API_SCOPES = [:index_rubygems, :push_rubygem, :yank_rubygem, :add_owner, :remove_owner, :access_webhooks, :show_dashboard].freeze
+ API_SCOPES = %i[index_rubygems push_rubygem yank_rubygem add_owner remove_owner access_webhooks show_dashboard].freeze
include Gem::Text
@@ -119,11 +120,11 @@ module Gem::GemcutterUtilities
end
def mfa_unauthorized?(response)
- response.is_a?(Net::HTTPUnauthorized) && response.body.start_with?("You have enabled multifactor authentication")
+ response.kind_of?(Net::HTTPUnauthorized) && response.body.start_with?("You have enabled multifactor authentication")
end
def update_scope(scope)
- sign_in_host = host
+ sign_in_host = self.host
pretty_host = pretty_host(sign_in_host)
update_scope_params = { scope => true }
@@ -139,7 +140,7 @@ module Gem::GemcutterUtilities
request.body = URI.encode_www_form({ :api_key => api_key }.merge(update_scope_params))
end
- with_response response do |_resp|
+ with_response response do |resp|
say "Added #{scope} scope to the existing API key"
end
end
@@ -149,13 +150,13 @@ module Gem::GemcutterUtilities
# key.
def sign_in(sign_in_host = nil, scope: nil)
- sign_in_host ||= host
+ sign_in_host ||= self.host
return if api_key
pretty_host = pretty_host(sign_in_host)
say "Enter your #{pretty_host} credentials."
- say "Don't have an account yet? " \
+ say "Don't have an account yet? " +
"Create one at #{sign_in_host}/sign_up"
email = ask " Email: "
@@ -215,7 +216,7 @@ module Gem::GemcutterUtilities
say clean_text(response.body)
end
when Net::HTTPPermanentRedirect, Net::HTTPRedirection then
- message = "The request has redirected permanently to #{response["location"]}. Please check your defined push host URL."
+ message = "The request has redirected permanently to #{response['location']}. Please check your defined push host URL."
message = "#{error_prefix}: #{message}" if error_prefix
say clean_text(message)
@@ -315,9 +316,9 @@ module Gem::GemcutterUtilities
scope_params = { scope => true }
else
say "Please select scopes you want to enable for the API key (y/n)"
- API_SCOPES.each do |s|
- selected = ask_yes_no(s.to_s, false)
- scope_params[s] = true if selected
+ API_SCOPES.each do |scope|
+ selected = ask_yes_no("#{scope}", false)
+ scope_params[scope] = true if selected
end
say "\n"
end
@@ -326,7 +327,7 @@ module Gem::GemcutterUtilities
end
def default_host?
- host == Gem::DEFAULT_HOST
+ self.host == Gem::DEFAULT_HOST
end
def get_user_profile(email, password)
@@ -337,14 +338,14 @@ module Gem::GemcutterUtilities
end
with_response response do |resp|
- Gem::ConfigFile.load_with_rubygems_config_hash(clean_text(resp.body))
+ Gem::SafeYAML.load clean_text(resp.body)
end
end
def get_mfa_params(profile)
mfa_level = profile["mfa"]
params = {}
- if ["ui_only", "ui_and_gem_signin"].include?(mfa_level)
+ if mfa_level == "ui_only" || mfa_level == "ui_and_gem_signin"
selected = ask_yes_no("Would you like to enable MFA for this key? (strongly recommended)")
params["mfa"] = true if selected
end
@@ -366,6 +367,6 @@ module Gem::GemcutterUtilities
end
def api_key_forbidden?(response)
- response.is_a?(Net::HTTPForbidden) && response.body.start_with?("The API key doesn't have access")
+ response.kind_of?(Net::HTTPForbidden) && response.body.start_with?("The API key doesn't have access")
end
end
diff --git a/lib/rubygems/indexer.rb b/lib/rubygems/indexer.rb
index f4c981b9ef..0935fe8486 100644
--- a/lib/rubygems/indexer.rb
+++ b/lib/rubygems/indexer.rb
@@ -201,7 +201,7 @@ class Gem::Indexer
rescue SignalException
alert_error "Received signal, exiting"
raise
- rescue StandardError => e
+ rescue Exception => e
msg = ["Unable to process #{gemfile}",
"#{e.message} (#{e.class})",
"\t#{e.backtrace.join "\n\t"}"].join("\n")
@@ -309,7 +309,7 @@ class Gem::Indexer
end
files = files.map do |path|
- path.sub(%r{^#{Regexp.escape @directory}/?}, "") # HACK?
+ path.sub(/^#{Regexp.escape @directory}\/?/, "") # HACK?
end
files.each do |file|
@@ -327,7 +327,7 @@ class Gem::Indexer
def make_temp_directories
FileUtils.rm_rf @directory
- FileUtils.mkdir_p @directory, :mode => 0o700
+ FileUtils.mkdir_p @directory, :mode => 0700
FileUtils.mkdir_p @quick_marshal_dir
end
@@ -390,7 +390,7 @@ class Gem::Indexer
files << "#{@prerelease_specs_index}.gz"
files = files.map do |path|
- path.sub(%r{^#{Regexp.escape @directory}/?}, "") # HACK?
+ path.sub(/^#{Regexp.escape @directory}\/?/, "") # HACK?
end
files.each do |file|
@@ -411,8 +411,7 @@ class Gem::Indexer
# +dest+. For a latest index, does not ensure the new file is minimal.
def update_specs_index(index, source, dest)
- Gem.load_safe_marshal
- specs_index = Gem::SafeMarshal.safe_load Gem.read_binary(source)
+ specs_index = Marshal.load Gem.read_binary(source)
index.each do |spec|
platform = spec.original_platform
diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb
index 5c7289426e..e125b3b9b3 100644
--- a/lib/rubygems/install_update_options.rb
+++ b/lib/rubygems/install_update_options.rb
@@ -36,9 +36,9 @@ module Gem::InstallUpdateOptions
"List the documentation types you wish to",
"generate. For example: rdoc,ri") do |value, options|
options[:document] = case value
- when nil then %w[ri]
- when false then []
- else value
+ when nil then %w[ri]
+ when false then []
+ else value
end
end
@@ -50,7 +50,7 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "--vendor",
"Install gem into the vendor directory.",
- "Only for use by gem repackagers.") do |_value, options|
+ "Only for use by gem repackagers.") do |value, options|
unless Gem.vendor_dir
raise Gem::OptionParser::InvalidOption.new "your platform is not supported"
end
@@ -60,7 +60,7 @@ module Gem::InstallUpdateOptions
end
add_option(:"Install/Update", "-N", "--no-document",
- "Disable documentation generation") do |_value, options|
+ "Disable documentation generation") do |value, options|
options[:document] = []
end
@@ -104,21 +104,21 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "--development",
"Install additional development",
- "dependencies") do |_value, options|
+ "dependencies") do |value, options|
options[:development] = true
options[:dev_shallow] = true
end
add_option(:"Install/Update", "--development-all",
"Install development dependencies for all",
- "gems (including dev deps themselves)") do |_value, options|
+ "gems (including dev deps themselves)") do |value, options|
options[:development] = true
options[:dev_shallow] = false
end
add_option(:"Install/Update", "--conservative",
"Don't attempt to upgrade gems already",
- "meeting version requirement") do |_value, options|
+ "meeting version requirement") do |value, options|
options[:conservative] = true
options[:minimal_deps] = true
end
@@ -136,13 +136,13 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "-g", "--file [FILE]",
"Read from a gem dependencies API file and",
- "install the listed gems") do |v,_o|
- v ||= Gem::GEM_DEP_FILES.find do |file|
+ "install the listed gems") do |v,o|
+ v = Gem::GEM_DEP_FILES.find do |file|
File.exist? file
- end
+ end unless v
unless v
- message = v ? v : "(tried #{Gem::GEM_DEP_FILES.join ", "})"
+ message = v ? v : "(tried #{Gem::GEM_DEP_FILES.join ', '})"
raise Gem::OptionParser::InvalidArgument,
"cannot find gem dependencies file #{message}"
@@ -154,29 +154,29 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "--without GROUPS", Array,
"Omit the named groups (comma separated)",
"when installing from a gem dependencies",
- "file") do |v,_o|
- options[:without_groups].concat v.map(&:intern)
+ "file") do |v,o|
+ options[:without_groups].concat v.map {|without| without.intern }
end
add_option(:"Install/Update", "--default",
"Add the gem's full specification to",
- "specifications/default and extract only its bin") do |v,_o|
+ "specifications/default and extract only its bin") do |v,o|
options[:install_as_default] = v
end
add_option(:"Install/Update", "--explain",
"Rather than install the gems, indicate which would",
- "be installed") do |v,_o|
+ "be installed") do |v,o|
options[:explain] = v
end
add_option(:"Install/Update", "--[no-]lock",
- "Create a lock file (when used with -g/--file)") do |v,_o|
+ "Create a lock file (when used with -g/--file)") do |v,o|
options[:lock] = v
end
add_option(:"Install/Update", "--[no-]suggestions",
- "Suggest alternates when gems are not found") do |v,_o|
+ "Suggest alternates when gems are not found") do |v,o|
options[:suggest_alternate] = v
end
end
@@ -196,4 +196,5 @@ module Gem::InstallUpdateOptions
def install_update_defaults_str
"--document=ri"
end
+
end
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 26a69a1f05..1b152aaf1f 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -189,12 +189,10 @@ class Gem::Installer
@package.prog_mode = options[:prog_mode]
@package.data_mode = options[:data_mode]
- if @gem_home == Gem.user_dir
- # If we get here, then one of the following likely happened:
- # - `--user-install` was specified
- # - `Gem::PathSupport#home` fell back to `Gem.user_dir`
- # - GEM_HOME was manually set to `Gem.user_dir`
-
+ if options[:user_install]
+ @gem_home = Gem.user_dir
+ @bin_dir = Gem.bindir gem_home unless options[:bin_dir]
+ @plugins_dir = Gem.plugindir(gem_home)
check_that_user_bin_dir_is_in_path
end
end
@@ -232,23 +230,23 @@ class Gem::Installer
end
end
- next unless line&.match?(shebang)
+ next unless line =~ shebang
io.gets # blankline
- # TODO: detect a specially formatted comment instead of trying
+ # TODO detect a specially formatted comment instead of trying
# to find a string inside Ruby code.
next unless io.gets.to_s.include?("This file was generated by RubyGems")
ruby_executable = true
- existing = io.read.slice(/
+ existing = io.read.slice(%r{
^\s*(
gem \s |
load \s Gem\.bin_path\( |
load \s Gem\.activate_bin_path\(
)
(['"])(.*?)(\2),
- /x, 3)
+ }x, 3)
end
return if spec.name == existing
@@ -318,7 +316,7 @@ class Gem::Installer
FileUtils.rm_rf spec.extension_dir
dir_mode = options[:dir_mode]
- FileUtils.mkdir_p gem_dir, :mode => dir_mode && 0o755
+ FileUtils.mkdir_p gem_dir, :mode => dir_mode && 0755
if @options[:install_as_default]
extract_bin
@@ -350,27 +348,34 @@ class Gem::Installer
run_post_install_hooks
spec
+
+ # TODO This rescue is in the wrong place. What is raising this exception?
+ # move this rescue to around the code that actually might raise it.
+ rescue Zlib::GzipFile::Error
+ raise Gem::InstallError, "gzip error installing #{gem}"
end
def run_pre_install_hooks # :nodoc:
Gem.pre_install_hooks.each do |hook|
- next unless hook.call(self) == false
- location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
+ if hook.call(self) == false
+ location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
- message = "pre-install hook#{location} failed for #{spec.full_name}"
- raise Gem::InstallError, message
+ message = "pre-install hook#{location} failed for #{spec.full_name}"
+ raise Gem::InstallError, message
+ end
end
end
def run_post_build_hooks # :nodoc:
Gem.post_build_hooks.each do |hook|
- next unless hook.call(self) == false
- FileUtils.rm_rf gem_dir
+ if hook.call(self) == false
+ FileUtils.rm_rf gem_dir
- location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
+ location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
- message = "post-build hook#{location} failed for #{spec.full_name}"
- raise Gem::InstallError, message
+ message = "post-build hook#{location} failed for #{spec.full_name}"
+ raise Gem::InstallError, message
+ end
end
end
@@ -460,9 +465,6 @@ class Gem::Installer
##
# Writes the full .gemspec specification (in Ruby) to the gem home's
# specifications/default directory.
- #
- # In contrast to #write_spec, this keeps file lists, so the `gem contents`
- # command works.
def write_default_spec
Gem.write_binary(default_spec_file, spec.to_ruby)
@@ -494,7 +496,7 @@ class Gem::Installer
next unless File.exist? bin_path
mode = File.stat(bin_path).mode
- dir_mode = options[:prog_mode] || (mode | 0o111)
+ dir_mode = options[:prog_mode] || (mode | 0111)
unless dir_mode == mode
require "fileutils"
@@ -522,8 +524,6 @@ class Gem::Installer
else
regenerate_plugins_for(spec, @plugins_dir)
end
- rescue ArgumentError => e
- raise e, "#{latest.name} #{latest.version} #{spec.name} #{spec.version}: #{e.message}"
end
##
@@ -531,7 +531,7 @@ class Gem::Installer
#--
# The Windows script is generated in addition to the regular one due to a
# bug or misfeature in the Windows shell's pipe. See
- # https://blade.ruby-lang.org/ruby-talk/193379
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379
def generate_bin_script(filename, bindir)
bin_script_path = File.join bindir, formatted_program_filename(filename)
@@ -539,9 +539,9 @@ class Gem::Installer
require "fileutils"
FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
- File.open bin_script_path, "wb", 0o755 do |file|
+ File.open bin_script_path, "wb", 0755 do |file|
file.print app_script_text(filename)
- file.chmod(options[:prog_mode] || 0o755)
+ file.chmod(options[:prog_mode] || 0755)
end
verbose bin_script_path
@@ -589,7 +589,7 @@ class Gem::Installer
def shebang(bin_file_name)
path = File.join gem_dir, spec.bindir, bin_file_name
- first_line = File.open(path, "rb", &:gets) || ""
+ first_line = File.open(path, "rb") {|file| file.gets } || ""
if first_line.start_with?("#!")
# Preserve extra words on shebang line, like "-w". Thanks RPA.
@@ -662,26 +662,21 @@ class Gem::Installer
@env_shebang = options[:env_shebang]
@force = options[:force]
@install_dir = options[:install_dir]
+ @gem_home = options[:install_dir] || Gem.dir
+ @plugins_dir = Gem.plugindir(@gem_home)
@ignore_dependencies = options[:ignore_dependencies]
@format_executable = options[:format_executable]
@wrappers = options[:wrappers]
@only_install_dir = options[:only_install_dir]
- @bin_dir = options[:bin_dir]
- @development = options[:development]
- @build_root = options[:build_root]
-
- @build_args = options[:build_args]
-
- @gem_home = @install_dir
- @gem_home ||= options[:user_install] ? Gem.user_dir : Gem.dir
-
# If the user has asked for the gem to be installed in a directory that is
# the system gem directory, then use the system bin directory, else create
# (or use) a new bin dir under the gem_home.
- @bin_dir ||= Gem.bindir(@gem_home)
+ @bin_dir = options[:bin_dir] || Gem.bindir(gem_home)
+ @development = options[:development]
+ @build_root = options[:build_root]
- @plugins_dir = Gem.plugindir(@gem_home)
+ @build_args = options[:build_args]
unless @build_root.nil?
@bin_dir = File.join(@build_root, @bin_dir.gsub(/^[a-zA-Z]:/, ""))
@@ -716,12 +711,12 @@ class Gem::Installer
end
def verify_gem_home # :nodoc:
- FileUtils.mkdir_p gem_home, :mode => options[:dir_mode] && 0o755
+ FileUtils.mkdir_p gem_home, :mode => options[:dir_mode] && 0755
raise Gem::FilePermissionError, gem_home unless File.writable?(gem_home)
end
def verify_spec
- unless Gem::Specification::VALID_NAME_PATTERN.match?(spec.name)
+ unless spec.name =~ Gem::Specification::VALID_NAME_PATTERN
raise Gem::InstallError, "#{spec} has an invalid name"
end
@@ -733,11 +728,11 @@ class Gem::Installer
raise Gem::InstallError, "#{spec} has an invalid extensions"
end
- if /\R/.match?(spec.platform.to_s)
+ if spec.platform.to_s =~ /\R/
raise Gem::InstallError, "#{spec.platform} is an invalid platform"
end
- unless /\A\d+\z/.match?(spec.specification_version.to_s)
+ unless spec.specification_version.to_s =~ /\A\d+\z/
raise Gem::InstallError, "#{spec} has an invalid specification_version"
end
@@ -754,9 +749,9 @@ class Gem::Installer
# Return the text for an application file.
def app_script_text(bin_file_name)
- # NOTE: that the `load` lines cannot be indented, as old RG versions match
+ # note that the `load` lines cannot be indented, as old RG versions match
# against the beginning of the line
- <<-TEXT
+ return <<-TEXT
#{shebang bin_file_name}
#
# This file was generated by RubyGems.
@@ -813,10 +808,10 @@ TEXT
rb_topdir = RbConfig::TOPDIR || File.dirname(rb_config["bindir"])
# get ruby executable file name from RbConfig
- ruby_exe = "#{rb_config["RUBY_INSTALL_NAME"]}#{rb_config["EXEEXT"]}"
+ ruby_exe = "#{rb_config['RUBY_INSTALL_NAME']}#{rb_config['EXEEXT']}"
ruby_exe = "ruby.exe" if ruby_exe.empty?
- if File.exist?(File.join(bindir, ruby_exe))
+ if File.exist?(File.join bindir, ruby_exe)
# stub & ruby.exe within same folder. Portable
<<-TEXT
@ECHO OFF
@@ -938,7 +933,7 @@ TEXT
build_info_dir = File.join gem_home, "build_info"
dir_mode = options[:dir_mode]
- FileUtils.mkdir_p build_info_dir, :mode => dir_mode && 0o755
+ FileUtils.mkdir_p build_info_dir, :mode => dir_mode && 0755
build_info_file = File.join build_info_dir, "#{spec.full_name}.info"
@@ -961,7 +956,7 @@ TEXT
def ensure_writable_dir(dir) # :nodoc:
begin
- Dir.mkdir dir, *[options[:dir_mode] && 0o755].compact
+ Dir.mkdir dir, *[options[:dir_mode] && 0755].compact
rescue SystemCallError
raise unless File.directory? dir
end
@@ -996,7 +991,7 @@ TEXT
bindir="${0%/*}"
EOS
- script << %(exec "$bindir/#{ruby_install_name}" "-x" "$0" "$@"\n)
+ script << %Q(exec "$bindir/#{ruby_install_name}" "-x" "$0" "$@"\n)
<<~EOS
#!/bin/sh
diff --git a/lib/rubygems/installer_uninstaller_utils.rb b/lib/rubygems/installer_uninstaller_utils.rb
index c5c2a52bab..d97b4e29b1 100644
--- a/lib/rubygems/installer_uninstaller_utils.rb
+++ b/lib/rubygems/installer_uninstaller_utils.rb
@@ -4,6 +4,7 @@
# Helper methods for both Gem::Installer and Gem::Uninstaller
module Gem::InstallerUninstallerUtils
+
def regenerate_plugins_for(spec, plugins_dir)
plugins = spec.plugins
return if plugins.empty?
@@ -24,4 +25,5 @@ module Gem::InstallerUninstallerUtils
def remove_plugins_for(spec, plugins_dir)
FileUtils.rm_f Gem::Util.glob_files_in_dir("#{spec.name}#{Gem.plugin_suffix_pattern}", plugins_dir)
end
+
end
diff --git a/lib/rubygems/local_remote_options.rb b/lib/rubygems/local_remote_options.rb
index e2a008fada..3d970ef225 100644
--- a/lib/rubygems/local_remote_options.rb
+++ b/lib/rubygems/local_remote_options.rb
@@ -13,6 +13,7 @@ require_relative "../rubygems"
# Mixin methods for local and remote Gem::Command options.
module Gem::LocalRemoteOptions
+
##
# Allows Gem::OptionParser to handle HTTP URIs.
@@ -39,17 +40,17 @@ module Gem::LocalRemoteOptions
def add_local_remote_options
add_option(:"Local/Remote", "-l", "--local",
- "Restrict operations to the LOCAL domain") do |_value, options|
+ "Restrict operations to the LOCAL domain") do |value, options|
options[:domain] = :local
end
add_option(:"Local/Remote", "-r", "--remote",
- "Restrict operations to the REMOTE domain") do |_value, options|
+ "Restrict operations to the REMOTE domain") do |value, options|
options[:domain] = :remote
end
add_option(:"Local/Remote", "-b", "--both",
- "Allow LOCAL and REMOTE operations") do |_value, options|
+ "Allow LOCAL and REMOTE operations") do |value, options|
options[:domain] = :both
end
@@ -66,7 +67,8 @@ module Gem::LocalRemoteOptions
def add_bulk_threshold_option
add_option(:"Local/Remote", "-B", "--bulk-threshold COUNT",
"Threshold for switching to bulk",
- "synchronization (default #{Gem.configuration.bulk_threshold})") do |value, _options|
+ "synchronization (default #{Gem.configuration.bulk_threshold})") do
+ |value, options|
Gem.configuration.bulk_threshold = value.to_i
end
end
@@ -76,7 +78,7 @@ module Gem::LocalRemoteOptions
def add_clear_sources_option
add_option(:"Local/Remote", "--clear-sources",
- "Clear the gem sources") do |_value, options|
+ "Clear the gem sources") do |value, options|
Gem.sources = nil
options[:sources_cleared] = true
end
@@ -90,7 +92,7 @@ module Gem::LocalRemoteOptions
add_option(:"Local/Remote", "-p", "--[no-]http-proxy [URL]", URI::HTTP,
"Use HTTP proxy for remote operations") do |value, options|
- options[:http_proxy] = value == false ? :no_proxy : value
+ options[:http_proxy] = (value == false) ? :no_proxy : value
Gem.configuration[:http_proxy] = options[:http_proxy]
end
end
@@ -103,7 +105,7 @@ module Gem::LocalRemoteOptions
add_option(:"Local/Remote", "-s", "--source URL", URI::HTTP,
"Append URL to list of remote gem sources") do |source, options|
- source << "/" unless source.end_with?("/")
+ source << "/" if source !~ /\/\z/
if options.delete :sources_cleared
Gem.sources = [source]
@@ -118,7 +120,7 @@ module Gem::LocalRemoteOptions
def add_update_sources_option
add_option(:Deprecated, "-u", "--[no-]update-sources",
- "Update local source cache") do |value, _options|
+ "Update local source cache") do |value, options|
Gem.configuration.update_sources = value
end
end
@@ -143,4 +145,5 @@ module Gem::LocalRemoteOptions
def remote?
options[:domain] == :remote || options[:domain] == :both
end
+
end
diff --git a/lib/rubygems/mock_gem_ui.rb b/lib/rubygems/mock_gem_ui.rb
new file mode 100644
index 0000000000..2dfdc6d523
--- /dev/null
+++ b/lib/rubygems/mock_gem_ui.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require_relative "user_interaction"
+
+##
+# This Gem::StreamUI subclass records input and output to StringIO for
+# retrieval during tests.
+
+class Gem::MockGemUi < Gem::StreamUI
+ ##
+ # Raised when you haven't provided enough input to your MockGemUi
+
+ class InputEOFError < RuntimeError
+ def initialize(question)
+ super "Out of input for MockGemUi on #{question.inspect}"
+ end
+ end
+
+ class TermError < RuntimeError
+ attr_reader :exit_code
+
+ def initialize(exit_code)
+ super
+ @exit_code = exit_code
+ end
+ end
+ class SystemExitException < RuntimeError; end
+
+ module TTY
+
+ attr_accessor :tty
+
+ def tty?()
+ @tty = true unless defined?(@tty)
+ @tty
+ end
+
+ def noecho
+ yield self
+ end
+ end
+
+ def initialize(input = "")
+ require "stringio"
+ ins = StringIO.new input
+ outs = StringIO.new
+ errs = StringIO.new
+
+ ins.extend TTY
+ outs.extend TTY
+ errs.extend TTY
+
+ super ins, outs, errs, true
+
+ @terminated = false
+ end
+
+ def ask(question)
+ raise InputEOFError, question if @ins.eof?
+
+ super
+ end
+
+ def input
+ @ins.string
+ end
+
+ def output
+ @outs.string
+ end
+
+ def error
+ @errs.string
+ end
+
+ def terminated?
+ @terminated
+ end
+
+ def terminate_interaction(status=0)
+ @terminated = true
+
+ raise TermError, status if status != 0
+ raise SystemExitException
+ end
+end
diff --git a/lib/rubygems/name_tuple.rb b/lib/rubygems/name_tuple.rb
index 2a8f397481..c26d0765e6 100644
--- a/lib/rubygems/name_tuple.rb
+++ b/lib/rubygems/name_tuple.rb
@@ -6,12 +6,14 @@
# wrap the data returned from the indexes.
class Gem::NameTuple
- def initialize(name, version, platform=Gem::Platform::RUBY)
+ def initialize(name, version, platform="ruby")
@name = name
@version = version
- platform &&= platform.to_s
- platform = Gem::Platform::RUBY if !platform || platform.empty?
+ unless platform.kind_of? Gem::Platform
+ platform = "ruby" if !platform || platform.empty?
+ end
+
@platform = platform
end
@@ -30,7 +32,7 @@ class Gem::NameTuple
# [name, version, platform] tuples.
def self.to_basic(list)
- list.map(&:to_a)
+ list.map {|t| t.to_a }
end
##
@@ -47,7 +49,7 @@ class Gem::NameTuple
def full_name
case @platform
- when nil, "", Gem::Platform::RUBY
+ when nil, "ruby", ""
"#{@name}-#{@version}"
else
"#{@name}-#{@version}-#{@platform}"
@@ -85,7 +87,7 @@ class Gem::NameTuple
"#<Gem::NameTuple #{@name}, #{@version}, #{@platform}>"
end
- alias_method :to_s, :inspect # :nodoc:
+ alias to_s inspect # :nodoc:
def <=>(other)
[@name, @version, Gem::Platform.sort_priority(@platform)] <=>
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
index 5dcc3ce858..f28d521bdf 100644
--- a/lib/rubygems/package.rb
+++ b/lib/rubygems/package.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#++
require_relative "../rubygems"
require_relative "security"
@@ -61,7 +59,7 @@ class Gem::Package
if source
@path = source.path
- message += " in #{path}" if path
+ message = message + " in #{path}" if path
end
super message
@@ -70,13 +68,15 @@ class Gem::Package
class PathError < Error
def initialize(destination, destination_dir)
- super format("installing into parent path %s of %s is not allowed", destination, destination_dir)
+ super "installing into parent path %s of %s is not allowed" %
+ [destination, destination_dir]
end
end
class SymlinkError < Error
def initialize(name, destination, destination_dir)
- super format("installing symlink '%s' pointing to parent path %s of %s is not allowed", name, destination, destination_dir)
+ super "installing symlink '%s' pointing to parent path %s of %s is not allowed" %
+ [name, destination, destination_dir]
end
end
@@ -155,7 +155,7 @@ class Gem::Package
Gem::Package::FileSource.new gem
end
- return super unless self == Gem::Package
+ return super unless Gem::Package == self
return super unless gem.present?
return super unless gem.start
@@ -187,7 +187,7 @@ class Gem::Package
end
end
- [spec, metadata]
+ return spec, metadata
end
##
@@ -230,7 +230,7 @@ class Gem::Package
end
end
- tar.add_file_signed "checksums.yaml.gz", 0o444, @signer do |io|
+ tar.add_file_signed "checksums.yaml.gz", 0444, @signer do |io|
gzip_to io do |gz_io|
Psych.dump checksums_by_algorithm, gz_io
end
@@ -242,7 +242,7 @@ class Gem::Package
# and adds this file to the +tar+.
def add_contents(tar) # :nodoc:
- digests = tar.add_file_signed "data.tar.gz", 0o444, @signer do |io|
+ digests = tar.add_file_signed "data.tar.gz", 0444, @signer do |io|
gzip_to io do |gz_io|
Gem::Package::TarWriter.new gz_io do |data_tar|
add_files data_tar
@@ -268,7 +268,7 @@ class Gem::Package
tar.add_file_simple file, stat.mode, stat.size do |dst_io|
File.open file, "rb" do |src_io|
- dst_io.write src_io.read 16_384 until src_io.eof?
+ dst_io.write src_io.read 16384 until src_io.eof?
end
end
end
@@ -278,7 +278,7 @@ class Gem::Package
# Adds the package's Gem::Specification to the +tar+ file
def add_metadata(tar) # :nodoc:
- digests = tar.add_file_signed "metadata.gz", 0o444, @signer do |io|
+ digests = tar.add_file_signed "metadata.gz", 0444, @signer do |io|
gzip_to io do |gz_io|
gz_io.write @spec.to_yaml
end
@@ -347,8 +347,6 @@ EOM
return @contents
end
end
- rescue Zlib::GzipFile::Error, EOFError, Gem::Package::TarInvalidError => e
- raise Gem::Package::FormatError.new e.message, @gem
end
##
@@ -365,7 +363,7 @@ EOM
algorithms.each do |algorithm|
digester = Gem::Security.create_digest(algorithm)
- digester << entry.readpartial(16_384) until entry.eof?
+ digester << entry.read(16384) until entry.eof?
entry.rewind
@@ -384,7 +382,7 @@ EOM
def extract_files(destination_dir, pattern = "*")
verify unless @spec
- FileUtils.mkdir_p destination_dir, :mode => dir_mode && 0o755
+ FileUtils.mkdir_p destination_dir, :mode => dir_mode && 0755
@gem.with_read_io do |io|
reader = Gem::Package::TarReader.new io
@@ -394,11 +392,9 @@ EOM
extract_tar_gz entry, destination_dir, pattern
- break # ignore further entries
+ return # ignore further entries
end
end
- rescue Zlib::GzipFile::Error, EOFError, Gem::Package::TarInvalidError => e
- raise Gem::Package::FormatError.new e.message, @gem
end
##
@@ -413,8 +409,6 @@ EOM
# extracted.
def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc:
- destination_dir = File.realpath(destination_dir)
-
directories = []
symlinks = []
@@ -438,7 +432,7 @@ EOM
FileUtils.rm_rf destination
mkdir_options = {}
- mkdir_options[:mode] = dir_mode ? 0o755 : (entry.header.mode if entry.directory?)
+ mkdir_options[:mode] = dir_mode ? 0755 : (entry.header.mode if entry.directory?)
mkdir =
if entry.directory?
destination
@@ -474,7 +468,7 @@ EOM
end
def file_mode(mode) # :nodoc:
- ((mode & 0o111).zero? ? data_mode : prog_mode) ||
+ ((mode & 0111).zero? ? data_mode : prog_mode) ||
# If we're not using one of the default modes, then we're going to fall
# back to the mode from the tarball. In this case we need to mask it down
# to fit into 2^16 bits (the maximum value for a mode in CRuby since it
@@ -578,10 +572,10 @@ EOM
)
@spec.signing_key = nil
- @spec.cert_chain = @signer.cert_chain.map(&:to_s)
+ @spec.cert_chain = @signer.cert_chain.map {|cert| cert.to_s }
else
@signer = Gem::Security::Signer.new nil, nil, passphrase
- @spec.cert_chain = @signer.cert_chain.map(&:to_pem) if
+ @spec.cert_chain = @signer.cert_chain.map {|cert| cert.to_pem } if
@signer.cert_chain
end
end
@@ -632,7 +626,7 @@ EOM
raise
rescue Errno::ENOENT => e
raise Gem::Package::FormatError.new e.message
- rescue Zlib::GzipFile::Error, EOFError, Gem::Package::TarInvalidError => e
+ rescue Gem::Package::TarInvalidError => e
raise Gem::Package::FormatError.new e.message, @gem
end
@@ -676,7 +670,7 @@ EOM
when "data.tar.gz" then
verify_gz entry
end
- rescue StandardError
+ rescue
warn "Exception while verifying #{@gem.path}"
raise
end
@@ -695,11 +689,11 @@ EOM
unless @files.include? "data.tar.gz"
raise Gem::Package::FormatError.new \
- "package content (data.tar.gz) is missing", @gem
+ "package content (data.tar.gz) is missing", @gem
end
- if (duplicates = @files.group_by {|f| f }.select {|_k,v| v.size > 1 }.map(&:first)) && duplicates.any?
- raise Gem::Security::Exception, "duplicate files in the package: (#{duplicates.map(&:inspect).join(", ")})"
+ if (duplicates = @files.group_by {|f| f }.select {|k,v| v.size > 1 }.map(&:first)) && duplicates.any?
+ raise Gem::Security::Exception, "duplicate files in the package: (#{duplicates.map(&:inspect).join(', ')})"
end
end
@@ -708,7 +702,7 @@ EOM
def verify_gz(entry) # :nodoc:
Zlib::GzipReader.wrap entry do |gzio|
- gzio.read 16_384 until gzio.eof? # gzip checksum verification
+ gzio.read 16384 until gzio.eof? # gzip checksum verification
end
rescue Zlib::GzipFile::Error => e
raise Gem::Package::FormatError.new(e.message, entry.full_name)
diff --git a/lib/rubygems/package/digest_io.rb b/lib/rubygems/package/digest_io.rb
index f04ab97462..1572cb9f2c 100644
--- a/lib/rubygems/package/digest_io.rb
+++ b/lib/rubygems/package/digest_io.rb
@@ -36,7 +36,7 @@ class Gem::Package::DigestIO
yield digest_io
- digests
+ return digests
end
##
diff --git a/lib/rubygems/package/old.rb b/lib/rubygems/package/old.rb
index 41f6986b8f..bf0ed61b0a 100644
--- a/lib/rubygems/package/old.rb
+++ b/lib/rubygems/package/old.rb
@@ -78,7 +78,7 @@ class Gem::Package::Old < Gem::Package
FileUtils.rm_rf destination
- FileUtils.mkdir_p File.dirname(destination), :mode => dir_mode && 0o755
+ FileUtils.mkdir_p File.dirname(destination), :mode => dir_mode && 0755
File.open destination, "wb", file_mode(entry["mode"]) do |out|
out.write file_data
diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb
index 6fb5b3b2e3..99bd755f90 100644
--- a/lib/rubygems/package/tar_header.rb
+++ b/lib/rubygems/package/tar_header.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#++
##
#--
@@ -102,7 +100,7 @@ class Gem::Package::TarHeader
def self.from(stream)
header = stream.read 512
- empty = (header == EMPTY_HEADER)
+ empty = (EMPTY_HEADER == header)
fields = header.unpack UNPACK_FORMAT
@@ -127,7 +125,7 @@ class Gem::Package::TarHeader
end
def self.strict_oct(str)
- return str.strip.oct if /\A[0-7]*\z/.match?(str.strip)
+ return str.strip.oct if str.strip =~ /\A[0-7]*\z/
raise ArgumentError, "#{str.inspect} is not an octal string"
end
@@ -137,7 +135,7 @@ class Gem::Package::TarHeader
# \ff flags a negative 256-based number
# In case we have a match, parse it as a signed binary value
# in big-endian order, except that the high-order bit is ignored.
- return str.unpack("N2").last if /\A[\x80\xff]/n.match?(str)
+ return str.unpack("N2").last if str =~ /\A[\x80\xff]/n
strict_oct(str)
end
@@ -241,6 +239,6 @@ class Gem::Package::TarHeader
end
def oct(num, len)
- format("%0#{len}o", num)
+ "%0#{len}o" % num
end
end
diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb
index 25f9b2f945..a8dd39c572 100644
--- a/lib/rubygems/package/tar_reader.rb
+++ b/lib/rubygems/package/tar_reader.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#++
##
# TarReader reads tar files and allows iteration over their items
@@ -14,6 +12,11 @@ class Gem::Package::TarReader
include Enumerable
##
+ # Raised if the tar IO is not seekable
+
+ class UnexpectedEOF < StandardError; end
+
+ ##
# Creates a new TarReader on +io+ and yields it to the block, if given.
def self.new(io)
@@ -52,14 +55,7 @@ class Gem::Package::TarReader
return enum_for __method__ unless block_given?
until @io.eof? do
- begin
- header = Gem::Package::TarHeader.from @io
- rescue ArgumentError => e
- # Specialize only exceptions from Gem::Package::TarHeader.strict_oct
- raise e unless e.message.match?(/ is not an octal string$/)
- raise Gem::Package::TarInvalidError, e.message
- end
-
+ header = Gem::Package::TarHeader.from @io
return if header.empty?
entry = Gem::Package::TarReader::Entry.new header, @io
yield entry
@@ -67,7 +63,7 @@ class Gem::Package::TarReader
end
end
- alias_method :each_entry, :each
+ alias each_entry each
##
# NOTE: Do not call #rewind during #each
@@ -92,7 +88,7 @@ class Gem::Package::TarReader
return unless found
- yield found
+ return yield found
ensure
rewind
end
diff --git a/lib/rubygems/package/tar_reader/entry.rb b/lib/rubygems/package/tar_reader/entry.rb
index 5e9d9af5c6..e770079f41 100644
--- a/lib/rubygems/package/tar_reader/entry.rb
+++ b/lib/rubygems/package/tar_reader/entry.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#--
##
# Class for reading entries out of a tar file
@@ -102,7 +100,9 @@ class Gem::Package::TarReader::Entry
# Read one byte from the tar entry
def getc
- return nil if eof?
+ check_closed
+
+ return nil if @read >= @header.size
ret = @io.getc
@read += 1 if ret
@@ -145,37 +145,40 @@ class Gem::Package::TarReader::Entry
def pos=(new_pos)
seek(new_pos, IO::SEEK_SET)
+ new_pos
end
def size
@header.size
end
- alias_method :length, :size
+ alias length size
##
- # Reads +maxlen+ bytes from the tar file entry, or the rest of the entry if nil
+ # Reads +len+ bytes from the tar file entry, or the rest of the entry if
+ # nil
- def read(maxlen = nil)
- if eof?
- return maxlen.to_i.zero? ? "" : nil
- end
+ def read(len = nil)
+ check_closed
+
+ len ||= @header.size - @read
- max_read = [maxlen, @header.size - @read].compact.min
+ return nil if len > 0 && @read >= @header.size
+
+ max_read = [len, @header.size - @read].min
ret = @io.read max_read
- if ret.nil?
- return maxlen ? nil : "" # IO.read returns nil on EOF with len argument
- end
@read += ret.size
ret
end
- def readpartial(maxlen, outbuf = "".b)
- if eof? && maxlen > 0
- raise EOFError, "end of file reached"
- end
+ def readpartial(maxlen = nil, outbuf = "".b)
+ check_closed
+
+ maxlen ||= @header.size - @read
+
+ raise EOFError if maxlen > 0 && @read >= @header.size
max_read = [maxlen, @header.size - @read].min
@@ -209,8 +212,6 @@ class Gem::Package::TarReader::Entry
pending = new_pos - @io.pos
- return 0 if pending == 0
-
if @io.respond_to?(:seek)
begin
# avoid reading if the @io supports seeking
@@ -228,8 +229,8 @@ class Gem::Package::TarReader::Entry
end
while pending > 0 do
- size_read = @io.read([pending, 4096].min)&.size
- raise(EOFError, "end of file reached") if size_read.nil?
+ size_read = @io.read([pending, 4096].min).size
+ raise UnexpectedEOF if @io.eof?
pending -= size_read
end
diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb
index e06ec25961..32a13e9162 100644
--- a/lib/rubygems/package/tar_writer.rb
+++ b/lib/rubygems/package/tar_writer.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#++
##
# Allows writing of tar files
@@ -192,7 +190,7 @@ class Gem::Package::TarWriter
if signer.key
signature = signer.sign signature_digest.digest
- add_file_simple "#{name}.sig", 0o444, signature.length do |io|
+ add_file_simple "#{name}.sig", 0444, signature.length do |io|
io.write signature
end
end
@@ -326,6 +324,6 @@ class Gem::Package::TarWriter
end
end
- [name, prefix]
+ return name, prefix
end
end
diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb
index b966e15f9c..d9df543ad9 100644
--- a/lib/rubygems/path_support.rb
+++ b/lib/rubygems/path_support.rb
@@ -19,31 +19,19 @@ class Gem::PathSupport
attr_reader :spec_cache_dir # :nodoc:
##
- # Whether `Gem.paths.home` defaulted to a user install or not.
- attr_reader :auto_user_install
-
- ##
#
# Constructor. Takes a single argument which is to be treated like a
# hashtable, or defaults to ENV, the system environment.
#
def initialize(env)
- # Current implementation of @home, which is exposed as `Gem.paths.home`:
- # 1. If `env["GEM_HOME"]` is defined in the environment: `env["GEM_HOME"]`.
- # 2. If `Gem.default_dir` is writable: `Gem.default_dir`.
- # 3. Otherwise: `Gem.user_dir`.
-
- if env.key?("GEM_HOME")
- @home = normalize_home_dir(env["GEM_HOME"])
- elsif File.writable?(Gem.default_dir)
- @home = normalize_home_dir(Gem.default_dir)
- else
- # If `GEM_HOME` is not set AND we can't use `Gem.default_dir`,
- # default to a user installation and set `@auto_user_install`.
- @auto_user_install = true
- @home = normalize_home_dir(Gem.user_dir)
+ @home = env["GEM_HOME"] || Gem.default_dir
+
+ if File::ALT_SEPARATOR
+ @home = @home.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
end
+ @home = expand(@home)
+
@path = split_gem_path env["GEM_PATH"], @home
@spec_cache_dir = env["GEM_SPEC_CACHE"] || Gem.default_spec_cache_dir
@@ -53,14 +41,6 @@ class Gem::PathSupport
private
- def normalize_home_dir(home)
- if File::ALT_SEPARATOR
- home = home.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
- end
-
- expand(home)
- end
-
##
# Split the Gem search path (as reported by Gem.path).
@@ -73,7 +53,7 @@ class Gem::PathSupport
gem_path = gpaths.split(Gem.path_separator)
# Handle the path_separator being set to a regexp, which will cause
# end_with? to error
- if /#{Gem.path_separator}\z/.match?(gpaths)
+ if gpaths =~ /#{Gem.path_separator}\z/
gem_path += default_path
end
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 5c5abdc2e2..b721629b78 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -13,22 +13,15 @@ class Gem::Platform
attr_accessor :cpu, :os, :version
def self.local
- @local ||= begin
- arch = RbConfig::CONFIG["arch"]
- arch = "#{arch}_60" if /mswin(?:32|64)$/.match?(arch)
- new(arch)
- end
+ arch = RbConfig::CONFIG["arch"]
+ arch = "#{arch}_60" if arch =~ /mswin(?:32|64)$/
+ @local ||= new(arch)
end
def self.match(platform)
match_platforms?(platform, Gem.platforms)
end
- class << self
- extend Gem::Deprecate
- rubygems_deprecate :match, "Gem::Platform.match_spec? or match_gem?"
- end
-
def self.match_platforms?(platform, platforms)
platform = Gem::Platform.new(platform) unless platform.is_a?(Gem::Platform)
platforms.any? do |local_platform|
@@ -44,7 +37,7 @@ class Gem::Platform
end
def self.match_gem?(platform, gem_name)
- # NOTE: this method might be redefined by Ruby implementations to
+ # Note: this method might be redefined by Ruby implementations to
# customize behavior per RUBY_ENGINE, gem_name or other criteria.
match_platforms?(platform, Gem.platforms)
end
@@ -87,8 +80,8 @@ class Gem::Platform
cpu = arch.shift
@cpu = case cpu
- when /i\d86/ then "x86"
- else cpu
+ when /i\d86/ then "x86"
+ else cpu
end
if arch.length == 2 && arch.last =~ /^\d+(\.\d+)?$/ # for command-line
@@ -97,36 +90,32 @@ class Gem::Platform
end
os, = arch
- if os.nil?
- @cpu = nil
- os = cpu
- end # legacy jruby
+ @cpu, os = nil, cpu if os.nil? # legacy jruby
@os, @version = case os
- when /aix(\d+)?/ then ["aix", $1]
- when /cygwin/ then ["cygwin", nil]
- when /darwin(\d+)?/ then ["darwin", $1]
- when /^macruby$/ then ["macruby", nil]
- when /freebsd(\d+)?/ then ["freebsd", $1]
- when /^java$/, /^jruby$/ then ["java", nil]
- when /^java([\d.]*)/ then ["java", $1]
- when /^dalvik(\d+)?$/ then ["dalvik", $1]
- when /^dotnet$/ then ["dotnet", nil]
- when /^dotnet([\d.]*)/ then ["dotnet", $1]
- when /linux-?(\w+)?/ then ["linux", $1]
- when /mingw32/ then ["mingw32", nil]
- when /mingw-?(\w+)?/ then ["mingw", $1]
- when /(mswin\d+)(\_(\d+))?/ then
- os = $1
- version = $3
- @cpu = "x86" if @cpu.nil? && os =~ /32$/
- [os, version]
- when /netbsdelf/ then ["netbsdelf", nil]
- when /openbsd(\d+\.\d+)?/ then ["openbsd", $1]
- when /solaris(\d+\.\d+)?/ then ["solaris", $1]
- # test
- when /^(\w+_platform)(\d+)?/ then [$1, $2]
- else ["unknown", nil]
+ when /aix(\d+)?/ then [ "aix", $1 ]
+ when /cygwin/ then [ "cygwin", nil ]
+ when /darwin(\d+)?/ then [ "darwin", $1 ]
+ when /^macruby$/ then [ "macruby", nil ]
+ when /freebsd(\d+)?/ then [ "freebsd", $1 ]
+ when /^java$/, /^jruby$/ then [ "java", nil ]
+ when /^java([\d.]*)/ then [ "java", $1 ]
+ when /^dalvik(\d+)?$/ then [ "dalvik", $1 ]
+ when /^dotnet$/ then [ "dotnet", nil ]
+ when /^dotnet([\d.]*)/ then [ "dotnet", $1 ]
+ when /linux-?(\w+)?/ then [ "linux", $1 ]
+ when /mingw32/ then [ "mingw32", nil ]
+ when /mingw-?(\w+)?/ then [ "mingw", $1 ]
+ when /(mswin\d+)(\_(\d+))?/ then
+ os, version = $1, $3
+ @cpu = "x86" if @cpu.nil? && os =~ /32$/
+ [os, version]
+ when /netbsdelf/ then [ "netbsdelf", nil ]
+ when /openbsd(\d+\.\d+)?/ then [ "openbsd", $1 ]
+ when /solaris(\d+\.\d+)?/ then [ "solaris", $1 ]
+ # test
+ when /^(\w+_platform)(\d+)?/ then [ $1, $2 ]
+ else [ "unknown", nil ]
end
when Gem::Platform then
@cpu = arch.cpu
@@ -153,7 +142,7 @@ class Gem::Platform
self.class === other && to_a == other.to_a
end
- alias_method :eql?, :==
+ alias :eql? :==
def hash # :nodoc:
to_a.hash
@@ -221,18 +210,18 @@ class Gem::Platform
when String then
# This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007
other = case other
- when /^i686-darwin(\d)/ then ["x86", "darwin", $1]
- when /^i\d86-linux/ then ["x86", "linux", nil]
- when "java", "jruby" then [nil, "java", nil]
- when /^dalvik(\d+)?$/ then [nil, "dalvik", $1]
- when /dotnet(\-(\d+\.\d+))?/ then ["universal","dotnet", $2]
- when /mswin32(\_(\d+))?/ then ["x86", "mswin32", $2]
- when /mswin64(\_(\d+))?/ then ["x64", "mswin64", $2]
- when "powerpc-darwin" then ["powerpc", "darwin", nil]
- when /powerpc-darwin(\d)/ then ["powerpc", "darwin", $1]
- when /sparc-solaris2.8/ then ["sparc", "solaris", "2.8"]
- when /universal-darwin(\d)/ then ["universal", "darwin", $1]
- else other
+ when /^i686-darwin(\d)/ then ["x86", "darwin", $1 ]
+ when /^i\d86-linux/ then ["x86", "linux", nil ]
+ when "java", "jruby" then [nil, "java", nil ]
+ when /^dalvik(\d+)?$/ then [nil, "dalvik", $1 ]
+ when /dotnet(\-(\d+\.\d+))?/ then ["universal","dotnet", $2 ]
+ when /mswin32(\_(\d+))?/ then ["x86", "mswin32", $2 ]
+ when /mswin64(\_(\d+))?/ then ["x64", "mswin64", $2 ]
+ when "powerpc-darwin" then ["powerpc", "darwin", nil ]
+ when /powerpc-darwin(\d)/ then ["powerpc", "darwin", $1 ]
+ when /sparc-solaris2.8/ then ["sparc", "solaris", "2.8" ]
+ when /universal-darwin(\d)/ then ["universal", "darwin", $1 ]
+ else other
end
other = Gem::Platform.new other
diff --git a/lib/rubygems/query_utils.rb b/lib/rubygems/query_utils.rb
index a95a759401..c72955f83b 100644
--- a/lib/rubygems/query_utils.rb
+++ b/lib/rubygems/query_utils.rb
@@ -6,6 +6,7 @@ require_relative "version_option"
require_relative "text"
module Gem::QueryUtils
+
include Gem::Text
include Gem::LocalRemoteOptions
include Gem::VersionOption
@@ -16,7 +17,7 @@ module Gem::QueryUtils
options[:installed] = value
end
- add_option("-I", "Equivalent to --no-installed") do |_value, options|
+ add_option("-I", "Equivalent to --no-installed") do |value, options|
options[:installed] = false
end
@@ -84,7 +85,7 @@ module Gem::QueryUtils
installed = !installed unless options[:installed]
say(installed)
- exit_code = 1 unless installed
+ exit_code = 1 if !installed
end
exit_code
@@ -118,7 +119,7 @@ module Gem::QueryUtils
end
end
- # Guts of original execute
+ #Guts of original execute
def show_gems(name)
show_local_gems(name) if local?
show_remote_gems(name) if remote?
@@ -196,7 +197,7 @@ module Gem::QueryUtils
end
def output_versions(output, versions)
- versions.each do |_gem_name, matching_tuples|
+ versions.each do |gem_name, matching_tuples|
matching_tuples = matching_tuples.sort_by {|n,_| n.version }.reverse
platforms = Hash.new {|h,version| h[version] = [] }
@@ -242,7 +243,7 @@ module Gem::QueryUtils
list =
if platforms.empty? || options[:details]
- name_tuples.map(&:version).uniq
+ name_tuples.map {|n| n.version }.uniq
else
platforms.sort.reverse.map do |version, pls|
out = version.to_s
@@ -263,7 +264,7 @@ module Gem::QueryUtils
end
end
- entry << " (#{list.join ", "})"
+ entry << " (#{list.join ', '})"
end
def make_entry(entry_tuples, platforms)
@@ -282,7 +283,7 @@ module Gem::QueryUtils
end
def spec_authors(entry, spec)
- authors = "Author#{spec.authors.length > 1 ? "s" : ""}: ".dup
+ authors = "Author#{spec.authors.length > 1 ? 's' : ''}: ".dup
authors << spec.authors.join(", ")
entry << format_text(authors, 68, 4)
end
@@ -296,7 +297,7 @@ module Gem::QueryUtils
def spec_license(entry, spec)
return if spec.license.nil? || spec.license.empty?
- licenses = "License#{spec.licenses.length > 1 ? "s" : ""}: ".dup
+ licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: ".dup
licenses << spec.licenses.join(", ")
entry << "\n" << format_text(licenses, 68, 4)
end
@@ -311,8 +312,8 @@ module Gem::QueryUtils
label = "Installed at"
specs.each do |s|
version = s.version.to_s
- default = ", default" if s.default_gem?
- entry << "\n" << " #{label} (#{version}#{default}): #{s.base_dir}"
+ version << ", default" if s.default_gem?
+ entry << "\n" << " #{label} (#{version}): #{s.base_dir}"
label = " " * label.length
end
end
@@ -327,11 +328,11 @@ module Gem::QueryUtils
if platforms.length == 1
title = platforms.values.length == 1 ? "Platform" : "Platforms"
- entry << " #{title}: #{platforms.values.sort.join(", ")}\n"
+ entry << " #{title}: #{platforms.values.sort.join(', ')}\n"
else
entry << " Platforms:\n"
- sorted_platforms = platforms.sort
+ sorted_platforms = platforms.sort_by {|version,| version }
sorted_platforms.each do |version, pls|
label = " #{version}: "
@@ -346,4 +347,5 @@ module Gem::QueryUtils
summary = truncate_text(spec.summary, "the summary for #{spec.full_name}")
entry << "\n\n" << format_text(summary, 68, 4)
end
+
end
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index f9f8c45817..1c8a441d0c 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -53,7 +53,7 @@ class Gem::RemoteFetcher
# Cached RemoteFetcher instance.
def self.fetcher
- @fetcher ||= new Gem.configuration[:http_proxy]
+ @fetcher ||= self.new Gem.configuration[:http_proxy]
end
attr_accessor :headers
@@ -115,7 +115,7 @@ class Gem::RemoteFetcher
cache_dir =
if Dir.pwd == install_dir # see fetch_command
install_dir
- elsif File.writable?(install_cache_dir) || (File.writable?(install_dir) && !File.exist?(install_cache_dir))
+ elsif File.writable?(install_cache_dir) || (File.writable?(install_dir) && (!File.exist?(install_cache_dir)))
install_cache_dir
else
File.join Gem.user_dir, "cache"
@@ -125,18 +125,14 @@ class Gem::RemoteFetcher
local_gem_path = File.join cache_dir, gem_file_name
require "fileutils"
- begin
- FileUtils.mkdir_p cache_dir
- rescue StandardError
- nil
- end unless File.exist? cache_dir
+ FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
source_uri = Gem::Uri.new(source_uri)
scheme = source_uri.scheme
# URI.parse gets confused by MS Windows paths with forward slashes.
- scheme = nil if /^[a-z]$/i.match?(scheme)
+ scheme = nil if scheme =~ /^[a-z]$/i
# REFACTOR: split this up and dispatch on scheme (eg download_http)
# REFACTOR: be sure to clean up fake fetcher when you do this... cleaner
@@ -148,7 +144,7 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{gem_file_name}"
- cache_update_path remote_gem_path, local_gem_path
+ self.cache_update_path remote_gem_path, local_gem_path
rescue FetchError
raise if spec.original_platform == spec.platform
@@ -158,7 +154,7 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{alternate_name}"
- cache_update_path remote_gem_path, local_gem_path
+ self.cache_update_path remote_gem_path, local_gem_path
end
end
when "file" then
@@ -174,7 +170,7 @@ class Gem::RemoteFetcher
end
verbose "Using local gem #{local_gem_path}"
- when nil then # TODO: test for local overriding cache
+ when nil then # TODO test for local overriding cache
source_path = if Gem.win_platform? && source_uri.scheme &&
!source_uri.path.include?(":")
"#{source_uri.scheme}:#{source_uri.path}"
@@ -238,7 +234,7 @@ class Gem::RemoteFetcher
end
end
- alias_method :fetch_https, :fetch_http
+ alias :fetch_https :fetch_http
##
# Downloads +uri+ and returns it as a String.
@@ -285,11 +281,7 @@ class Gem::RemoteFetcher
# passes the data.
def cache_update_path(uri, path = nil, update = true)
- mtime = begin
- path && File.stat(path).mtime
- rescue StandardError
- nil
- end
+ mtime = path && File.stat(path).mtime rescue nil
data = fetch_path(uri, mtime)
@@ -321,11 +313,11 @@ class Gem::RemoteFetcher
end
def https?(uri)
- uri.scheme.casecmp("https").zero?
+ uri.scheme.downcase == "https"
end
def close_all
- @pools.each_value(&:close_all)
+ @pools.each_value {|pool| pool.close_all }
end
private
diff --git a/lib/rubygems/request.rb b/lib/rubygems/request.rb
index 619a5934b1..8ea39d9358 100644
--- a/lib/rubygems/request.rb
+++ b/lib/rubygems/request.rb
@@ -36,13 +36,8 @@ class Gem::Request
@connection_pool = pool
end
- def proxy_uri
- @connection_pool.proxy_uri
- end
-
- def cert_files
- @connection_pool.cert_files
- end
+ def proxy_uri; @connection_pool.proxy_uri; end
+ def cert_files; @connection_pool.cert_files; end
def self.get_cert_files
pattern = File.expand_path("./ssl_certs/*/*.pem", __dir__)
@@ -165,22 +160,23 @@ class Gem::Request
# environment variables.
def self.get_proxy_from_env(scheme = "http")
- downcase_scheme = scheme.downcase
- upcase_scheme = scheme.upcase
- env_proxy = ENV["#{downcase_scheme}_proxy"] || ENV["#{upcase_scheme}_PROXY"]
+ _scheme = scheme.downcase
+ _SCHEME = scheme.upcase
+ env_proxy = ENV["#{_scheme}_proxy"] || ENV["#{_SCHEME}_PROXY"]
no_env_proxy = env_proxy.nil? || env_proxy.empty?
if no_env_proxy
- return ["https", "http"].include?(downcase_scheme) ? :no_proxy : get_proxy_from_env("http")
+ return (_scheme == "https" || _scheme == "http") ?
+ :no_proxy : get_proxy_from_env("http")
end
require "uri"
uri = URI(Gem::UriFormatter.new(env_proxy).normalize)
if uri && uri.user.nil? && uri.password.nil?
- user = ENV["#{downcase_scheme}_proxy_user"] || ENV["#{upcase_scheme}_PROXY_USER"]
- password = ENV["#{downcase_scheme}_proxy_pass"] || ENV["#{upcase_scheme}_PROXY_PASS"]
+ user = ENV["#{_scheme}_proxy_user"] || ENV["#{_SCHEME}_PROXY_USER"]
+ password = ENV["#{_scheme}_proxy_pass"] || ENV["#{_SCHEME}_PROXY_PASS"]
uri.user = Gem::UriFormatter.new(user).escape
uri.password = Gem::UriFormatter.new(password).escape
@@ -228,6 +224,7 @@ class Gem::Request
end
verbose "#{response.code} #{response.message}"
+
rescue Net::HTTPBadResponse
verbose "bad response"
@@ -241,7 +238,7 @@ class Gem::Request
verbose "fatal error"
raise Gem::RemoteFetcher::FetchError.new("fatal error", @uri)
- # HACK: work around EOFError bug in Net::HTTP
+ # HACK work around EOFError bug in Net::HTTP
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
# to install gems.
rescue EOFError, Timeout::Error,
@@ -282,7 +279,7 @@ class Gem::Request
ua << " Ruby/#{ruby_version} (#{RUBY_RELEASE_DATE}"
if RUBY_PATCHLEVEL >= 0
ua << " patchlevel #{RUBY_PATCHLEVEL}"
- else
+ elsif defined?(RUBY_REVISION)
ua << " revision #{RUBY_REVISION}"
end
ua << ")"
diff --git a/lib/rubygems/request/connection_pools.rb b/lib/rubygems/request/connection_pools.rb
index b7ad92f5c6..44280489fb 100644
--- a/lib/rubygems/request/connection_pools.rb
+++ b/lib/rubygems/request/connection_pools.rb
@@ -28,7 +28,7 @@ class Gem::Request::ConnectionPools # :nodoc:
end
def close_all
- @pools.each_value(&:close_all)
+ @pools.each_value {|pool| pool.close_all }
end
private
@@ -45,7 +45,7 @@ class Gem::Request::ConnectionPools # :nodoc:
end
def https?(uri)
- uri.scheme.casecmp("https").zero?
+ uri.scheme.downcase == "https"
end
def no_proxy?(host, env_no_proxy)
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
index 46e9cc346c..b6e0995726 100644
--- a/lib/rubygems/request_set.rb
+++ b/lib/rubygems/request_set.rb
@@ -160,7 +160,7 @@ class Gem::RequestSet
end
# Create N threads in a pool, have them download all the gems
- threads = Array.new(Gem.configuration.concurrent_downloads) do
+ threads = Gem.configuration.concurrent_downloads.times.map do
# When a thread pops this item, it knows to stop running. The symbol
# is queued here so that there will be one symbol per thread.
download_queue << :stop
@@ -255,8 +255,7 @@ class Gem::RequestSet
end
def install_into(dir, force = true, options = {})
- gem_home = ENV["GEM_HOME"]
- ENV["GEM_HOME"] = dir
+ gem_home, ENV["GEM_HOME"] = ENV["GEM_HOME"], dir
existing = force ? [] : specs_in(dir)
existing.delete_if {|s| @always_install.include? s }
@@ -376,7 +375,7 @@ class Gem::RequestSet
q.text "sets:"
q.breakable
- q.pp @sets.map(&:class)
+ q.pp @sets.map {|set| set.class }
end
end
@@ -430,7 +429,7 @@ class Gem::RequestSet
end
def specs
- @specs ||= @requests.map(&:full_spec)
+ @specs ||= @requests.map {|r| r.full_spec }
end
def specs_in(dir)
@@ -448,7 +447,7 @@ class Gem::RequestSet
next if dep.type == :development && !@development
match = @requests.find do |r|
- dep.match?(r.spec.name, r.spec.version, r.spec.is_a?(Gem::Resolver::InstalledSpecification) || @prerelease)
+ dep.match? r.spec.name, r.spec.version, r.spec.is_a?(Gem::Resolver::InstalledSpecification) || @prerelease
end
unless match
diff --git a/lib/rubygems/request_set/gem_dependency_api.rb b/lib/rubygems/request_set/gem_dependency_api.rb
index 28e232cfd3..2fd0da340a 100644
--- a/lib/rubygems/request_set/gem_dependency_api.rb
+++ b/lib/rubygems/request_set/gem_dependency_api.rb
@@ -262,7 +262,7 @@ class Gem::RequestSet::GemDependencyAPI
raise ArgumentError, "no gemspecs found at #{Dir.pwd}"
else
raise ArgumentError,
- "found multiple gemspecs at #{Dir.pwd}, " \
+ "found multiple gemspecs at #{Dir.pwd}, " +
"use the name: option to specify the one you want"
end
end
@@ -357,7 +357,7 @@ class Gem::RequestSet::GemDependencyAPI
# Use the given tag for git:, gist: and github: dependencies.
def gem(name, *requirements)
- options = requirements.pop if requirements.last.is_a?(Hash)
+ options = requirements.pop if requirements.last.kind_of?(Hash)
options ||= {}
options[:git] = @current_repository if @current_repository
@@ -533,8 +533,8 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
# platform matches the current platform.
def gem_platforms(name, options) # :nodoc:
- platform_names = Array(options.delete(:platform))
- platform_names.concat Array(options.delete(:platforms))
+ platform_names = Array(options.delete :platform)
+ platform_names.concat Array(options.delete :platforms)
platform_names.concat @current_platforms if @current_platforms
return true if platform_names.empty?
@@ -593,6 +593,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
@current_repository = repository
yield
+
ensure
@current_repository = nil
end
@@ -684,6 +685,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
@current_groups = groups
yield
+
ensure
@current_groups = nil
end
@@ -758,6 +760,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
@current_platforms = platforms
yield
+
ensure
@current_platforms = nil
end
@@ -768,7 +771,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
# Block form for restricting gems to a particular set of platforms. See
# #platform.
- alias_method :platforms, :platform
+ alias :platforms :platform
##
# :category: Gem Dependencies DSL
@@ -790,15 +793,15 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
return true if @installing
- unless version == RUBY_VERSION
- message = "Your Ruby version is #{RUBY_VERSION}, " \
+ unless RUBY_VERSION == version
+ message = "Your Ruby version is #{RUBY_VERSION}, " +
"but your #{gem_deps_file} requires #{version}"
raise Gem::RubyVersionMismatch, message
end
if engine && engine != Gem.ruby_engine
- message = "Your Ruby engine is #{Gem.ruby_engine}, " \
+ message = "Your Ruby engine is #{Gem.ruby_engine}, " +
"but your #{gem_deps_file} requires #{engine}"
raise Gem::RubyVersionMismatch, message
@@ -807,14 +810,14 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
if engine_version
if engine_version != RUBY_ENGINE_VERSION
message =
- "Your Ruby engine version is #{Gem.ruby_engine} #{RUBY_ENGINE_VERSION}, " \
+ "Your Ruby engine version is #{Gem.ruby_engine} #{RUBY_ENGINE_VERSION}, " +
"but your #{gem_deps_file} requires #{engine} #{engine_version}"
raise Gem::RubyVersionMismatch, message
end
end
- true
+ return true
end
##
diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb
index 7b115fe59b..9523fa7786 100644
--- a/lib/rubygems/request_set/lockfile.rb
+++ b/lib/rubygems/request_set/lockfile.rb
@@ -87,7 +87,7 @@ class Gem::RequestSet::Lockfile
def add_DEPENDENCIES(out) # :nodoc:
out << "DEPENDENCIES"
- out.concat @dependencies.sort.map {|name, requirement|
+ out.concat @dependencies.sort_by {|name,| name }.map {|name, requirement|
" #{name}#{requirement.for_lockfile}"
}
@@ -106,10 +106,10 @@ class Gem::RequestSet::Lockfile
out << " remote: #{group}"
out << " specs:"
- requests.sort_by(&:name).each do |request|
+ requests.sort_by {|request| request.name }.each do |request|
next if request.spec.name == "bundler"
platform = "-#{request.spec.platform}" unless
- request.spec.platform == Gem::Platform::RUBY
+ Gem::Platform::RUBY == request.spec.platform
out << " #{request.name} (#{request.version}#{platform})"
@@ -138,10 +138,10 @@ class Gem::RequestSet::Lockfile
out << " revision: #{revision}"
out << " specs:"
- requests.sort_by(&:name).each do |request|
+ requests.sort_by {|request| request.name }.each do |request|
out << " #{request.name} (#{request.version})"
- dependencies = request.spec.dependencies.sort_by(&:name)
+ dependencies = request.spec.dependencies.sort_by {|dep| dep.name }
dependencies.each do |dep|
out << " #{dep.name}#{dep.requirement.for_lockfile}"
end
@@ -185,7 +185,7 @@ class Gem::RequestSet::Lockfile
platforms = requests.map {|request| request.spec.platform }.uniq
- platforms = platforms.sort_by(&:to_s)
+ platforms = platforms.sort_by {|platform| platform.to_s }
platforms.each do |platform|
out << " #{platform}"
diff --git a/lib/rubygems/request_set/lockfile/parser.rb b/lib/rubygems/request_set/lockfile/parser.rb
index e751a1445e..1daec1fabd 100644
--- a/lib/rubygems/request_set/lockfile/parser.rb
+++ b/lib/rubygems/request_set/lockfile/parser.rb
@@ -48,7 +48,7 @@ class Gem::RequestSet::Lockfile::Parser
if expected_types && !Array(expected_types).include?(token.type)
unget token
- message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " \
+ message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " +
"expected #{expected_types.inspect}"
raise Gem::RequestSet::Lockfile::ParseError.new message, token.column, token.line, @filename
@@ -57,8 +57,8 @@ class Gem::RequestSet::Lockfile::Parser
if expected_value && expected_value != token.value
unget token
- message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " \
- "expected [#{expected_types.inspect}, " \
+ message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " +
+ "expected [#{expected_types.inspect}, " +
"#{expected_value.inspect}]"
raise Gem::RequestSet::Lockfile::ParseError.new message, token.column, token.line, @filename
@@ -68,7 +68,7 @@ class Gem::RequestSet::Lockfile::Parser
end
def parse_DEPENDENCIES # :nodoc:
- while !@tokens.empty? && peek.type == :text do
+ while !@tokens.empty? && :text == peek.type do
token = get :text
requirements = []
@@ -111,7 +111,7 @@ class Gem::RequestSet::Lockfile::Parser
def parse_GEM # :nodoc:
sources = []
- while peek.first(2) == [:entry, "remote"] do
+ while [:entry, "remote"] == peek.first(2) do
get :entry, "remote"
data = get(:text).value
skip :newline
@@ -128,7 +128,7 @@ class Gem::RequestSet::Lockfile::Parser
set = Gem::Resolver::LockSet.new sources
last_specs = nil
- while !@tokens.empty? && peek.type == :text do
+ while !@tokens.empty? && :text == peek.type do
token = get :text
name = token.value
column = token.column
@@ -200,7 +200,7 @@ class Gem::RequestSet::Lockfile::Parser
last_spec = nil
- while !@tokens.empty? && peek.type == :text do
+ while !@tokens.empty? && :text == peek.type do
token = get :text
name = token.value
column = token.column
@@ -247,7 +247,7 @@ class Gem::RequestSet::Lockfile::Parser
set = Gem::Resolver::VendorSet.new
last_spec = nil
- while !@tokens.empty? && peek.first == :text do
+ while !@tokens.empty? && :text == peek.first do
token = get :text
name = token.value
column = token.column
@@ -282,7 +282,7 @@ class Gem::RequestSet::Lockfile::Parser
end
def parse_PLATFORMS # :nodoc:
- while !@tokens.empty? && peek.first == :text do
+ while !@tokens.empty? && :text == peek.first do
name = get(:text).value
@platforms << name
diff --git a/lib/rubygems/request_set/lockfile/tokenizer.rb b/lib/rubygems/request_set/lockfile/tokenizer.rb
index 65cef3baa0..e91a11ca93 100644
--- a/lib/rubygems/request_set/lockfile/tokenizer.rb
+++ b/lib/rubygems/request_set/lockfile/tokenizer.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# ) frozen_string_literal: true
+#) frozen_string_literal: true
require_relative "parser"
class Gem::RequestSet::Lockfile::Tokenizer
@@ -50,7 +50,7 @@ class Gem::RequestSet::Lockfile::Tokenizer
def next_token
@tokens.shift
end
- alias_method :shift, :next_token
+ alias :shift :next_token
def peek
@tokens.first || EOF
@@ -75,14 +75,13 @@ class Gem::RequestSet::Lockfile::Tokenizer
end
@tokens <<
- if s.scan(/\r?\n/)
-
+ case
+ when s.scan(/\r?\n/) then
token = Token.new(:newline, nil, *token_pos(pos))
@line_pos = s.pos
@line += 1
token
- elsif s.scan(/[A-Z]+/)
-
+ when s.scan(/[A-Z]+/) then
if leading_whitespace
text = s.matched
text += s.scan(/[^\s)]*/).to_s # in case of no match
@@ -90,27 +89,20 @@ class Gem::RequestSet::Lockfile::Tokenizer
else
Token.new(:section, s.matched, *token_pos(pos))
end
- elsif s.scan(/([a-z]+):\s/)
-
+ when s.scan(/([a-z]+):\s/) then
s.pos -= 1 # rewind for possible newline
Token.new(:entry, s[1], *token_pos(pos))
- elsif s.scan(/\(/)
-
+ when s.scan(/\(/) then
Token.new(:l_paren, nil, *token_pos(pos))
- elsif s.scan(/\)/)
-
+ when s.scan(/\)/) then
Token.new(:r_paren, nil, *token_pos(pos))
- elsif s.scan(/<=|>=|=|~>|<|>|!=/)
-
+ when s.scan(/<=|>=|=|~>|<|>|!=/) then
Token.new(:requirement, s.matched, *token_pos(pos))
- elsif s.scan(/,/)
-
+ when s.scan(/,/) then
Token.new(:comma, nil, *token_pos(pos))
- elsif s.scan(/!/)
-
+ when s.scan(/!/) then
Token.new(:bang, nil, *token_pos(pos))
- elsif s.scan(/[^\s),!]*/)
-
+ when s.scan(/[^\s),!]*/) then
Token.new(:text, s.matched, *token_pos(pos))
else
raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb
index 09497f1a2e..eed12c4914 100644
--- a/lib/rubygems/requirement.rb
+++ b/lib/rubygems/requirement.rb
@@ -10,7 +10,7 @@ require_relative "version"
# together in RubyGems.
class Gem::Requirement
- OPS = { # :nodoc:
+ OPS = { #:nodoc:
"=" => lambda {|v, r| v == r },
"!=" => lambda {|v, r| v != r },
">" => lambda {|v, r| v > r },
@@ -120,7 +120,7 @@ class Gem::Requirement
# An array of requirement pairs. The first element of the pair is
# the op, and the second is the Gem::Version.
- attr_reader :requirements # :nodoc:
+ attr_reader :requirements #:nodoc:
##
# Constructs a requirement from +requirements+. Requirements can be
@@ -156,7 +156,7 @@ class Gem::Requirement
# Formats this requirement for use in a Gem::RequestSet::Lockfile.
def for_lockfile # :nodoc:
- return if @requirements == [DefaultRequirement]
+ return if [DefaultRequirement] == @requirements
list = requirements.sort_by do |_, version|
version
@@ -164,7 +164,7 @@ class Gem::Requirement
"#{op} #{version}"
end.uniq
- " (#{list.join ", "})"
+ " (#{list.join ', '})"
end
##
@@ -245,8 +245,8 @@ class Gem::Requirement
requirements.all? {|op, rv| OPS[op].call version, rv }
end
- alias_method :===, :satisfied_by?
- alias_method :=~, :satisfied_by?
+ alias :=== :satisfied_by?
+ alias :=~ :satisfied_by?
##
# True if the requirement will not always match the latest version.
diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb
index 620ba921bc..a912729b37 100644
--- a/lib/rubygems/resolver.rb
+++ b/lib/rubygems/resolver.rb
@@ -38,6 +38,8 @@ class Gem::Resolver
##
# List of dependencies that could not be found in the configured sources.
+ attr_reader :missing
+
attr_reader :stats
##
@@ -47,7 +49,8 @@ class Gem::Resolver
attr_accessor :skip_gems
##
- #
+ # When a missing dependency, don't stop. Just go on and record what was
+ # missing.
attr_accessor :soft_missing
@@ -103,6 +106,7 @@ class Gem::Resolver
@development = false
@development_shallow = false
@ignore_dependencies = false
+ @missing = []
@skip_gems = {}
@soft_missing = false
@stats = Gem::Resolver::Stats.new
@@ -111,7 +115,7 @@ class Gem::Resolver
def explain(stage, *data) # :nodoc:
return unless DEBUG_RESOLVER
- d = data.map(&:pretty_inspect).join(", ")
+ d = data.map {|x| x.pretty_inspect }.join(", ")
$stderr.printf "%10s %s\n", stage.to_s.upcase, d
end
@@ -141,7 +145,7 @@ class Gem::Resolver
activation_request =
Gem::Resolver::ActivationRequest.new spec, dep, possible
- [spec, activation_request]
+ return spec, activation_request
end
def requests(s, act, reqs=[]) # :nodoc:
@@ -183,7 +187,8 @@ class Gem::Resolver
# Proceed with resolution! Returns an array of ActivationRequest objects.
def resolve
- Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }).tsort.map(&:payload).compact
+ locking_dg = Molinillo::DependencyGraph.new
+ Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }, locking_dg).tsort.map(&:payload).compact
rescue Molinillo::VersionConflict => e
conflict = e.conflicts.values.first
raise Gem::DependencyResolutionError, Conflict.new(conflict.requirement_trees.first.first, conflict.existing, conflict.requirement)
@@ -208,7 +213,7 @@ class Gem::Resolver
matching_platform = select_local_platforms all
- [matching_platform, all]
+ return matching_platform, all
end
##
@@ -223,6 +228,7 @@ class Gem::Resolver
def search_for(dependency)
possibles, all = find_possible(dependency)
if !@soft_missing && possibles.empty?
+ @missing << dependency
exc = Gem::UnsatisfiableDependencyError.new dependency, all
exc.errors = @set.errors
raise exc
@@ -241,7 +247,7 @@ class Gem::Resolver
sources.each do |source|
groups[source].
- sort_by {|spec| [spec.version, spec.platform =~ Gem::Platform.local ? 1 : 0] }. # rubocop:disable Performance/RegexpMatch
+ sort_by {|spec| [spec.version, spec.platform =~ Gem::Platform.local ? 1 : 0] }.
map {|spec| ActivationRequest.new spec, dependency }.
each {|activation_request| activation_requests << activation_request }
end
@@ -269,6 +275,7 @@ class Gem::Resolver
end
def allow_missing?(dependency)
+ @missing << dependency
@soft_missing
end
diff --git a/lib/rubygems/resolver/activation_request.rb b/lib/rubygems/resolver/activation_request.rb
index fc9ff58f57..d59859c102 100644
--- a/lib/rubygems/resolver/activation_request.rb
+++ b/lib/rubygems/resolver/activation_request.rb
@@ -59,8 +59,10 @@ class Gem::Resolver::ActivationRequest
if @spec.respond_to? :sources
exception = nil
path = @spec.sources.find do |source|
- source.download full_spec, path
- rescue exception
+ begin
+ source.download full_spec, path
+ rescue exception
+ end
end
return path if path
raise exception if exception
@@ -92,7 +94,9 @@ class Gem::Resolver::ActivationRequest
end
def inspect # :nodoc:
- format("#<%s for %p from %s>", self.class, @spec, @request)
+ "#<%s for %p from %s>" % [
+ self.class, @spec, @request
+ ]
end
##
diff --git a/lib/rubygems/resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb
index e8e3747361..9b57b03192 100644
--- a/lib/rubygems/resolver/api_set.rb
+++ b/lib/rubygems/resolver/api_set.rb
@@ -76,8 +76,7 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
end
def prefetch_now # :nodoc:
- needed = @to_fetch
- @to_fetch = []
+ needed, @to_fetch = @to_fetch, []
needed.sort.each do |name|
versions(name)
diff --git a/lib/rubygems/resolver/api_set/gem_parser.rb b/lib/rubygems/resolver/api_set/gem_parser.rb
index 643b857107..685c39558d 100644
--- a/lib/rubygems/resolver/api_set/gem_parser.rb
+++ b/lib/rubygems/resolver/api_set/gem_parser.rb
@@ -1,15 +1,12 @@
# frozen_string_literal: true
class Gem::Resolver::APISet::GemParser
- EMPTY_ARRAY = [].freeze
- private_constant :EMPTY_ARRAY
-
def parse(line)
version_and_platform, rest = line.split(" ", 2)
version, platform = version_and_platform.split("-", 2)
- dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
- dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
- requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
+ dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
+ dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
+ requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
[version, platform, dependencies, requirements]
end
@@ -18,7 +15,6 @@ class Gem::Resolver::APISet::GemParser
def parse_dependency(string)
dependency = string.split(":")
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
- dependency[0] = -dependency[0]
dependency
end
end
diff --git a/lib/rubygems/resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb
index a14bcbfeb1..f26f82757e 100644
--- a/lib/rubygems/resolver/api_specification.rb
+++ b/lib/rubygems/resolver/api_specification.rb
@@ -22,7 +22,7 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
# Creates an APISpecification for the given +set+ from the rubygems.org
# +api_data+.
#
- # See https://guides.rubygems.org/rubygems-org-api/#misc-methods for the
+ # See https://guides.rubygems.org/rubygems-org-api/#misc_methods for the
# format of the +api_data+.
def initialize(set, api_data)
diff --git a/lib/rubygems/resolver/best_set.rb b/lib/rubygems/resolver/best_set.rb
index c2e8982047..d75fa7c00a 100644
--- a/lib/rubygems/resolver/best_set.rb
+++ b/lib/rubygems/resolver/best_set.rb
@@ -61,7 +61,7 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
def replace_failed_api_set(error) # :nodoc:
uri = error.original_uri
uri = URI uri unless URI === uri
- uri += "."
+ uri = uri + "."
raise error unless api_set = @sets.find do |set|
Gem::Resolver::APISet === set && set.dep_uri == uri
diff --git a/lib/rubygems/resolver/composed_set.rb b/lib/rubygems/resolver/composed_set.rb
index 8a714ad447..0991f0713e 100644
--- a/lib/rubygems/resolver/composed_set.rb
+++ b/lib/rubygems/resolver/composed_set.rb
@@ -44,7 +44,7 @@ class Gem::Resolver::ComposedSet < Gem::Resolver::Set
end
def errors
- @errors + @sets.map(&:errors).flatten
+ @errors + @sets.map {|set| set.errors }.flatten
end
##
diff --git a/lib/rubygems/resolver/conflict.rb b/lib/rubygems/resolver/conflict.rb
index 367a36b43d..dca41da51f 100644
--- a/lib/rubygems/resolver/conflict.rb
+++ b/lib/rubygems/resolver/conflict.rb
@@ -55,7 +55,7 @@ class Gem::Resolver::Conflict
activated = @activated.spec.full_name
dependency = @failed_dep.dependency
requirement = dependency.requirement
- alternates = dependency.matching_specs.map(&:full_name)
+ alternates = dependency.matching_specs.map {|spec| spec.full_name }
unless alternates.empty?
matching = <<-MATCHING.chomp
@@ -64,7 +64,10 @@ class Gem::Resolver::Conflict
%s
MATCHING
- matching = format(matching, dependency, alternates.join(", "))
+ matching = matching % [
+ dependency,
+ alternates.join(", "),
+ ]
end
explanation = <<-EXPLANATION
@@ -79,7 +82,12 @@ class Gem::Resolver::Conflict
%s
EXPLANATION
- format(explanation, activated, requirement, request_path(@activated).reverse.join(", depends on\n "), request_path(@failed_dep).reverse.join(", depends on\n "), matching)
+ explanation % [
+ activated, requirement,
+ request_path(@activated).reverse.join(", depends on\n "),
+ request_path(@failed_dep).reverse.join(", depends on\n "),
+ matching
+ ]
end
##
@@ -124,7 +132,7 @@ class Gem::Resolver::Conflict
current = current.parent
when Gem::Resolver::DependencyRequest then
- path << current.dependency.to_s
+ path << "#{current.dependency}"
current = current.requester
else
diff --git a/lib/rubygems/resolver/index_set.rb b/lib/rubygems/resolver/index_set.rb
index 0b4f376452..5e8632c7d8 100644
--- a/lib/rubygems/resolver/index_set.rb
+++ b/lib/rubygems/resolver/index_set.rb
@@ -44,10 +44,10 @@ class Gem::Resolver::IndexSet < Gem::Resolver::Set
name = req.dependency.name
@all[name].each do |uri, n|
- next unless req.match? n, @prerelease
- res << Gem::Resolver::IndexSpecification.new(
- self, n.name, n.version, uri, n.platform
- )
+ if req.match? n, @prerelease
+ res << Gem::Resolver::IndexSpecification.new(
+ self, n.name, n.version, uri, n.platform)
+ end
end
res
diff --git a/lib/rubygems/resolver/index_specification.rb b/lib/rubygems/resolver/index_specification.rb
index 7b95608071..6fac8c1487 100644
--- a/lib/rubygems/resolver/index_specification.rb
+++ b/lib/rubygems/resolver/index_specification.rb
@@ -68,7 +68,7 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
end
def inspect # :nodoc:
- format("#<%s %s source %s>", self.class, full_name, @source)
+ "#<%s %s source %s>" % [self.class, full_name, @source]
end
def pretty_print(q) # :nodoc:
@@ -76,7 +76,7 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
q.breakable
q.text full_name
- unless @platform == Gem::Platform::RUBY
+ unless Gem::Platform::RUBY == @platform
q.breakable
q.text @platform.to_s
end
diff --git a/lib/rubygems/resolver/installed_specification.rb b/lib/rubygems/resolver/installed_specification.rb
index 8280ae4672..b80f882c77 100644
--- a/lib/rubygems/resolver/installed_specification.rb
+++ b/lib/rubygems/resolver/installed_specification.rb
@@ -25,7 +25,7 @@ class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification
def installable_platform?
# BACKCOMPAT If the file is coming out of a specified file, then we
# ignore the platform. This code can be removed in RG 3.0.
- return true if @source.is_a? Gem::Source::SpecificFile
+ return true if @source.kind_of? Gem::Source::SpecificFile
super
end
diff --git a/lib/rubygems/resolver/installer_set.rb b/lib/rubygems/resolver/installer_set.rb
index d9fe36c589..521d241fd5 100644
--- a/lib/rubygems/resolver/installer_set.rb
+++ b/lib/rubygems/resolver/installer_set.rb
@@ -163,8 +163,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
if local_spec = @local_source.find_gem(name, dep.requirement)
res << Gem::Resolver::IndexSpecification.new(
self, local_spec.name, local_spec.version,
- @local_source, local_spec.platform
- )
+ @local_source, local_spec.platform)
end
rescue Gem::Package::FormatError
# ignore
@@ -187,9 +186,11 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
end
def inspect # :nodoc:
- always_install = @always_install.map(&:full_name)
+ always_install = @always_install.map {|s| s.full_name }
- format("#<%s domain: %s specs: %p always install: %p>", self.class, @domain, @specs.keys, always_install)
+ "#<%s domain: %s specs: %p always install: %p>" % [
+ self.class, @domain, @specs.keys, always_install
+ ]
end
##
@@ -263,7 +264,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
unless rrgv.satisfied_by? Gem.rubygems_version
rg_version = Gem::VERSION
raise Gem::RuntimeRequirementNotMetError,
- "#{spec.full_name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " \
+ "#{spec.full_name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " +
"Try 'gem update --system' to update RubyGems itself."
end
end
diff --git a/lib/rubygems/resolver/local_specification.rb b/lib/rubygems/resolver/local_specification.rb
index b57d40e795..50bf276345 100644
--- a/lib/rubygems/resolver/local_specification.rb
+++ b/lib/rubygems/resolver/local_specification.rb
@@ -8,7 +8,7 @@ class Gem::Resolver::LocalSpecification < Gem::Resolver::SpecSpecification
# Returns +true+ if this gem is installable for the current platform.
def installable_platform?
- return true if @source.is_a? Gem::Source::SpecificFile
+ return true if @source.kind_of? Gem::Source::SpecificFile
super
end
diff --git a/lib/rubygems/resolver/lock_set.rb b/lib/rubygems/resolver/lock_set.rb
index e5ee32a9a6..8eec041bdc 100644
--- a/lib/rubygems/resolver/lock_set.rb
+++ b/lib/rubygems/resolver/lock_set.rb
@@ -75,7 +75,7 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
q.text "specs:"
q.breakable
- q.pp @specs.map(&:full_name)
+ q.pp @specs.map {|spec| spec.full_name }
end
end
end
diff --git a/lib/rubygems/s3_uri_signer.rb b/lib/rubygems/s3_uri_signer.rb
index 20e95345d1..5161e43ebb 100644
--- a/lib/rubygems/s3_uri_signer.rb
+++ b/lib/rubygems/s3_uri_signer.rb
@@ -12,7 +12,7 @@ class Gem::S3URISigner
end
def to_s # :nodoc:
- super.to_s
+ "#{super}"
end
end
@@ -22,7 +22,7 @@ class Gem::S3URISigner
end
def to_s # :nodoc:
- super.to_s
+ "#{super}"
end
end
@@ -34,7 +34,7 @@ class Gem::S3URISigner
##
# Signs S3 URI using query-params according to the reference: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
- def sign(expiration = 86_400)
+ def sign(expiration = 86400)
s3_config = fetch_s3_config
current_time = Time.now.utc
@@ -136,7 +136,7 @@ class Gem::S3URISigner
end
def base64_uri_escape(str)
- str.gsub(%r{[\+/=\n]}, BASE64_URI_TRANSLATE)
+ str.gsub(/[\+\/=\n]/, BASE64_URI_TRANSLATE)
end
def ec2_metadata_credentials_json
diff --git a/lib/rubygems/safe_marshal.rb b/lib/rubygems/safe_marshal.rb
deleted file mode 100644
index b81d1a0a47..0000000000
--- a/lib/rubygems/safe_marshal.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require "stringio"
-
-require_relative "safe_marshal/reader"
-require_relative "safe_marshal/visitors/to_ruby"
-
-module Gem
- ###
- # This module is used for safely loading Marshal specs from a gem. The
- # `safe_load` method defined on this module is specifically designed for
- # loading Gem specifications.
-
- module SafeMarshal
- PERMITTED_CLASSES = %w[
- Date
- Time
- Rational
-
- Gem::Dependency
- Gem::NameTuple
- Gem::Platform
- Gem::Requirement
- Gem::Specification
- Gem::Version
- Gem::Version::Requirement
-
- YAML::Syck::DefaultKey
- YAML::PrivateType
- ].freeze
- private_constant :PERMITTED_CLASSES
-
- PERMITTED_SYMBOLS = %w[
- development
- runtime
-
- name
- number
- platform
- dependencies
- ].freeze
- private_constant :PERMITTED_SYMBOLS
-
- PERMITTED_IVARS = {
- "String" => %w[E encoding @taguri @debug_created_info],
- "Time" => %w[
- offset zone nano_num nano_den submicro
- @_zone @marshal_with_utc_coercion
- ],
- "Gem::Dependency" => %w[
- @name @requirement @prerelease @version_requirement @version_requirements @type
- @force_ruby_platform
- ],
- "Gem::NameTuple" => %w[@name @version @platform],
- "Gem::Platform" => %w[@os @cpu @version],
- "Psych::PrivateType" => %w[@value @type_id],
- }.freeze
- private_constant :PERMITTED_IVARS
-
- def self.safe_load(input)
- load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, permitted_ivars: PERMITTED_IVARS)
- end
-
- def self.load(input, permitted_classes: [::Symbol], permitted_symbols: [], permitted_ivars: {})
- root = Reader.new(StringIO.new(input, "r").binmode).read!
-
- Visitors::ToRuby.new(
- permitted_classes: permitted_classes,
- permitted_symbols: permitted_symbols,
- permitted_ivars: permitted_ivars,
- ).visit(root)
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/elements.rb b/lib/rubygems/safe_marshal/elements.rb
deleted file mode 100644
index 067ab59d19..0000000000
--- a/lib/rubygems/safe_marshal/elements.rb
+++ /dev/null
@@ -1,138 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- module SafeMarshal
- module Elements
- class Element
- end
-
- class Symbol < Element
- def initialize(name)
- @name = name
- end
- attr_reader :name
- end
-
- class UserDefined < Element
- def initialize(name, binary_string)
- @name = name
- @binary_string = binary_string
- end
-
- attr_reader :name, :binary_string
- end
-
- class UserMarshal < Element
- def initialize(name, data)
- @name = name
- @data = data
- end
-
- attr_reader :name, :data
- end
-
- class String < Element
- def initialize(str)
- @str = str
- end
-
- attr_reader :str
- end
-
- class Hash < Element
- def initialize(pairs)
- @pairs = pairs
- end
-
- attr_reader :pairs
- end
-
- class HashWithDefaultValue < Hash
- def initialize(pairs, default)
- super(pairs)
- @default = default
- end
-
- attr_reader :default
- end
-
- class Array < Element
- def initialize(elements)
- @elements = elements
- end
-
- attr_reader :elements
- end
-
- class Integer < Element
- def initialize(int)
- @int = int
- end
-
- attr_reader :int
- end
-
- class True < Element
- def initialize
- end
- TRUE = new.freeze
- end
-
- class False < Element
- def initialize
- end
-
- FALSE = new.freeze
- end
-
- class WithIvars < Element
- def initialize(object, ivars)
- @object = object
- @ivars = ivars
- end
-
- attr_reader :object, :ivars
- end
-
- class Object < Element
- def initialize(name)
- @name = name
- end
- attr_reader :name
- end
-
- class Nil < Element
- NIL = new.freeze
- end
-
- class ObjectLink < Element
- def initialize(offset)
- @offset = offset
- end
- attr_reader :offset
- end
-
- class SymbolLink < Element
- def initialize(offset)
- @offset = offset
- end
- attr_reader :offset
- end
-
- class Float < Element
- def initialize(string)
- @string = string
- end
- attr_reader :string
- end
-
- class Bignum < Element # rubocop:disable Lint/UnifiedInteger
- def initialize(sign, data)
- @sign = sign
- @data = data
- end
- attr_reader :sign, :data
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/reader.rb b/lib/rubygems/safe_marshal/reader.rb
deleted file mode 100644
index 7c3a703475..0000000000
--- a/lib/rubygems/safe_marshal/reader.rb
+++ /dev/null
@@ -1,306 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "elements"
-
-module Gem
- module SafeMarshal
- class Reader
- class Error < StandardError
- end
-
- class UnsupportedVersionError < Error
- end
-
- class UnconsumedBytesError < Error
- end
-
- class NotImplementedError < Error
- end
-
- class EOFError < Error
- end
-
- def initialize(io)
- @io = io
- end
-
- def read!
- read_header
- root = read_element
- raise UnconsumedBytesError unless @io.eof?
- root
- end
-
- private
-
- MARSHAL_VERSION = [Marshal::MAJOR_VERSION, Marshal::MINOR_VERSION].map(&:chr).join.freeze
- private_constant :MARSHAL_VERSION
-
- def read_header
- v = @io.read(2)
- raise UnsupportedVersionError, "Unsupported marshal version #{v.bytes.map(&:ord).join(".")}, expected #{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" unless v == MARSHAL_VERSION
- end
-
- def read_byte
- @io.getbyte
- end
-
- def read_integer
- b = read_byte
-
- case b
- when 0x00
- 0
- when 0x01
- read_byte
- when 0x02
- read_byte | (read_byte << 8)
- when 0x03
- read_byte | (read_byte << 8) | (read_byte << 16)
- when 0x04
- read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24)
- when 0xFC
- read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24) | -0x100000000
- when 0xFD
- read_byte | (read_byte << 8) | (read_byte << 16) | -0x1000000
- when 0xFE
- read_byte | (read_byte << 8) | -0x10000
- when 0xFF
- read_byte | -0x100
- when nil
- raise EOFError, "Unexpected EOF"
- else
- signed = (b ^ 128) - 128
- if b >= 128
- signed + 5
- else
- signed - 5
- end
- end
- end
-
- def read_element
- type = read_byte
- case type
- when 34 then read_string # ?"
- when 48 then read_nil # ?0
- when 58 then read_symbol # ?:
- when 59 then read_symbol_link # ?;
- when 64 then read_object_link # ?@
- when 70 then read_false # ?F
- when 73 then read_object_with_ivars # ?I
- when 84 then read_true # ?T
- when 85 then read_user_marshal # ?U
- when 91 then read_array # ?[
- when 102 then read_float # ?f
- when 105 then Elements::Integer.new(read_integer) # ?i
- when 108 then read_bignum # ?l
- when 111 then read_object # ?o
- when 117 then read_user_defined # ?u
- when 123 then read_hash # ?{
- when 125 then read_hash_with_default_value # ?}
- when 101 then read_extended_object # ?e
- when 99 then read_class # ?c
- when 109 then read_module # ?m
- when 77 then read_class_or_module # ?M
- when 100 then read_data # ?d
- when 47 then read_regexp # ?/
- when 83 then read_struct # ?S
- when 67 then read_user_class # ?C
- when nil
- raise EOFError, "Unexpected EOF"
- else
- raise Error, "Unknown marshal type discriminator #{type.chr.inspect} (#{type})"
- end
- end
-
- STRING_E_SYMBOL = Elements::Symbol.new("E").freeze
- private_constant :STRING_E_SYMBOL
-
- def read_symbol
- len = read_integer
- if len == 1
- byte = read_byte
- if byte == 69 # ?E
- STRING_E_SYMBOL
- else
- Elements::Symbol.new(byte.chr)
- end
- else
- name = -@io.read(len)
- Elements::Symbol.new(name)
- end
- end
-
- EMPTY_STRING = Elements::String.new("".b.freeze).freeze
- private_constant :EMPTY_STRING
-
- def read_string
- length = read_integer
- return EMPTY_STRING if length == 0
- str = @io.read(length)
- Elements::String.new(str)
- end
-
- def read_true
- Elements::True::TRUE
- end
-
- def read_false
- Elements::False::FALSE
- end
-
- def read_user_defined
- name = read_element
- binary_string = @io.read(read_integer)
- Elements::UserDefined.new(name, binary_string)
- end
-
- EMPTY_ARRAY = Elements::Array.new([].freeze).freeze
- private_constant :EMPTY_ARRAY
-
- def read_array
- length = read_integer
- return EMPTY_ARRAY if length == 0
- elements = Array.new(length) do
- read_element
- end
- Elements::Array.new(elements)
- end
-
- def read_object_with_ivars
- object = read_element
- ivars = Array.new(read_integer) do
- [read_element, read_element]
- end
- Elements::WithIvars.new(object, ivars)
- end
-
- def read_symbol_link
- offset = read_integer
- Elements::SymbolLink.new(offset)
- end
-
- def read_user_marshal
- name = read_element
- data = read_element
- Elements::UserMarshal.new(name, data)
- end
-
- # profiling bundle install --full-index shows that
- # offset 6 is by far the most common object link,
- # so we special case it to avoid allocating a new
- # object a third of the time.
- # the following are all the object links that
- # appear more than 10000 times in my profiling
-
- OBJECT_LINKS = {
- 6 => Elements::ObjectLink.new(6).freeze,
- 30 => Elements::ObjectLink.new(30).freeze,
- 81 => Elements::ObjectLink.new(81).freeze,
- 34 => Elements::ObjectLink.new(34).freeze,
- 38 => Elements::ObjectLink.new(38).freeze,
- 50 => Elements::ObjectLink.new(50).freeze,
- 91 => Elements::ObjectLink.new(91).freeze,
- 42 => Elements::ObjectLink.new(42).freeze,
- 46 => Elements::ObjectLink.new(46).freeze,
- 150 => Elements::ObjectLink.new(150).freeze,
- 100 => Elements::ObjectLink.new(100).freeze,
- 104 => Elements::ObjectLink.new(104).freeze,
- 108 => Elements::ObjectLink.new(108).freeze,
- 242 => Elements::ObjectLink.new(242).freeze,
- 246 => Elements::ObjectLink.new(246).freeze,
- 139 => Elements::ObjectLink.new(139).freeze,
- 143 => Elements::ObjectLink.new(143).freeze,
- 114 => Elements::ObjectLink.new(114).freeze,
- 308 => Elements::ObjectLink.new(308).freeze,
- 200 => Elements::ObjectLink.new(200).freeze,
- 54 => Elements::ObjectLink.new(54).freeze,
- 62 => Elements::ObjectLink.new(62).freeze,
- 1_286_245 => Elements::ObjectLink.new(1_286_245).freeze,
- }.freeze
- private_constant :OBJECT_LINKS
-
- def read_object_link
- offset = read_integer
- OBJECT_LINKS[offset] || Elements::ObjectLink.new(offset)
- end
-
- EMPTY_HASH = Elements::Hash.new([].freeze).freeze
- private_constant :EMPTY_HASH
-
- def read_hash
- length = read_integer
- return EMPTY_HASH if length == 0
- pairs = Array.new(length) do
- [read_element, read_element]
- end
- Elements::Hash.new(pairs)
- end
-
- def read_hash_with_default_value
- pairs = Array.new(read_integer) do
- [read_element, read_element]
- end
- default = read_element
- Elements::HashWithDefaultValue.new(pairs, default)
- end
-
- def read_object
- name = read_element
- object = Elements::Object.new(name)
- ivars = Array.new(read_integer) do
- [read_element, read_element]
- end
- Elements::WithIvars.new(object, ivars)
- end
-
- def read_nil
- Elements::Nil::NIL
- end
-
- def read_float
- string = @io.read(read_integer)
- Elements::Float.new(string)
- end
-
- def read_bignum
- sign = read_byte
- data = @io.read(read_integer * 2)
- Elements::Bignum.new(sign, data)
- end
-
- def read_extended_object
- raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented"
- end
-
- def read_class
- raise NotImplementedError, "Reading Marshal objects of type class is not implemented"
- end
-
- def read_module
- raise NotImplementedError, "Reading Marshal objects of type module is not implemented"
- end
-
- def read_class_or_module
- raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented"
- end
-
- def read_data
- raise NotImplementedError, "Reading Marshal objects of type data is not implemented"
- end
-
- def read_regexp
- raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented"
- end
-
- def read_struct
- raise NotImplementedError, "Reading Marshal objects of type struct is not implemented"
- end
-
- def read_user_class
- raise NotImplementedError, "Reading Marshal objects of type user_class is not implemented"
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/visitors/stream_printer.rb b/lib/rubygems/safe_marshal/visitors/stream_printer.rb
deleted file mode 100644
index 162b36ad05..0000000000
--- a/lib/rubygems/safe_marshal/visitors/stream_printer.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "visitor"
-
-module Gem::SafeMarshal
- module Visitors
- class StreamPrinter < Visitor
- def initialize(io, indent: "")
- @io = io
- @indent = indent
- @level = 0
- end
-
- def visit(target)
- @io.write("#{@indent * @level}#{target.class}")
- target.instance_variables.each do |ivar|
- value = target.instance_variable_get(ivar)
- next if Elements::Element === value || Array === value
- @io.write(" #{ivar}=#{value.inspect}")
- end
- @io.write("\n")
- begin
- @level += 1
- super
- ensure
- @level -= 1
- end
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/visitors/to_ruby.rb b/lib/rubygems/safe_marshal/visitors/to_ruby.rb
deleted file mode 100644
index 58c44fa8bf..0000000000
--- a/lib/rubygems/safe_marshal/visitors/to_ruby.rb
+++ /dev/null
@@ -1,385 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "visitor"
-
-module Gem::SafeMarshal
- module Visitors
- class ToRuby < Visitor
- def initialize(permitted_classes:, permitted_symbols:, permitted_ivars:)
- @permitted_classes = permitted_classes
- @permitted_symbols = ["E"].concat(permitted_symbols).concat(permitted_classes)
- @permitted_ivars = permitted_ivars
-
- @objects = []
- @symbols = []
- @class_cache = {}
-
- @stack = ["root"]
- @stack_idx = 1
- end
-
- def inspect # :nodoc:
- format("#<%s permitted_classes: %p permitted_symbols: %p permitted_ivars: %p>",
- self.class, @permitted_classes, @permitted_symbols, @permitted_ivars)
- end
-
- def visit(target)
- stack_idx = @stack_idx
- super
- ensure
- @stack_idx = stack_idx - 1
- end
-
- private
-
- def push_stack(element)
- @stack[@stack_idx] = element
- @stack_idx += 1
- end
-
- def visit_Gem_SafeMarshal_Elements_Array(a)
- array = register_object([])
-
- elements = a.elements
- size = elements.size
- idx = 0
- # not idiomatic, but there's a huge number of IMEMOs allocated here, so we avoid the block
- # because this is such a hot path when doing a bundle install with the full index
- until idx == size
- push_stack idx
- array << visit(elements[idx])
- idx += 1
- end
-
- array
- end
-
- def visit_Gem_SafeMarshal_Elements_Symbol(s)
- name = s.name
- raise UnpermittedSymbolError.new(symbol: name, stack: formatted_stack) unless @permitted_symbols.include?(name)
- visit_symbol_type(s)
- end
-
- def map_ivars(klass, ivars)
- stack_idx = @stack_idx
- ivars.map.with_index do |(k, v), i|
- @stack_idx = stack_idx
-
- push_stack "ivar_"
- push_stack i
- k = resolve_ivar(klass, k)
-
- @stack_idx = stack_idx
- push_stack k
-
- next k, visit(v)
- end
- end
-
- def visit_Gem_SafeMarshal_Elements_WithIvars(e)
- object_offset = @objects.size
- push_stack "object"
- object = visit(e.object)
- ivars = map_ivars(object.class, e.ivars)
-
- case e.object
- when Elements::UserDefined
- if object.class == ::Time
- internal = []
-
- ivars.reject! do |k, v|
- case k
- when :offset, :zone, :nano_num, :nano_den, :submicro
- internal << [k, v]
- true
- else
- false
- end
- end
-
- s = e.object.binary_string
-
- marshal_string = "\x04\bIu:\tTime".b
- marshal_string.concat(s.size + 5)
- marshal_string << s
- marshal_string.concat(internal.size + 5)
-
- internal.each do |k, v|
- marshal_string.concat(":")
- marshal_string.concat(k.size + 5)
- marshal_string.concat(k.to_s)
- dumped = Marshal.dump(v)
- dumped[0, 2] = ""
- marshal_string.concat(dumped)
- end
-
- object = @objects[object_offset] = Marshal.load(marshal_string)
- end
- when Elements::String
- enc = nil
-
- ivars.reject! do |k, v|
- case k
- when :E
- case v
- when TrueClass
- enc = "UTF-8"
- when FalseClass
- enc = "US-ASCII"
- else
- raise FormatError, "Unexpected value for String :E #{v.inspect}"
- end
- when :encoding
- enc = v
- else
- next false
- end
- true
- end
-
- object.force_encoding(enc) if enc
- end
-
- ivars.each do |k, v|
- object.instance_variable_set k, v
- end
- object
- end
-
- def visit_Gem_SafeMarshal_Elements_Hash(o)
- hash = register_object({})
-
- o.pairs.each_with_index do |(k, v), i|
- push_stack i
- k = visit(k)
- push_stack k
- hash[k] = visit(v)
- end
-
- hash
- end
-
- def visit_Gem_SafeMarshal_Elements_HashWithDefaultValue(o)
- hash = visit_Gem_SafeMarshal_Elements_Hash(o)
- push_stack :default
- hash.default = visit(o.default)
- hash
- end
-
- def visit_Gem_SafeMarshal_Elements_Object(o)
- register_object(resolve_class(o.name).allocate)
- end
-
- def visit_Gem_SafeMarshal_Elements_ObjectLink(o)
- @objects[o.offset]
- end
-
- def visit_Gem_SafeMarshal_Elements_SymbolLink(o)
- @symbols[o.offset]
- end
-
- def visit_Gem_SafeMarshal_Elements_UserDefined(o)
- register_object(call_method(resolve_class(o.name), :_load, o.binary_string))
- end
-
- def visit_Gem_SafeMarshal_Elements_UserMarshal(o)
- klass = resolve_class(o.name)
- compat = COMPAT_CLASSES.fetch(klass, nil)
- idx = @objects.size
- object = register_object(call_method(compat || klass, :allocate))
-
- push_stack :data
- ret = call_method(object, :marshal_load, visit(o.data))
-
- if compat
- object = @objects[idx] = ret
- end
-
- object
- end
-
- def visit_Gem_SafeMarshal_Elements_Integer(i)
- i.int
- end
-
- def visit_Gem_SafeMarshal_Elements_Nil(_)
- nil
- end
-
- def visit_Gem_SafeMarshal_Elements_True(_)
- true
- end
-
- def visit_Gem_SafeMarshal_Elements_False(_)
- false
- end
-
- def visit_Gem_SafeMarshal_Elements_String(s)
- register_object(+s.str)
- end
-
- def visit_Gem_SafeMarshal_Elements_Float(f)
- case f.string
- when "inf"
- ::Float::INFINITY
- when "-inf"
- -::Float::INFINITY
- when "nan"
- ::Float::NAN
- else
- f.string.to_f
- end
- end
-
- def visit_Gem_SafeMarshal_Elements_Bignum(b)
- result = 0
- b.data.each_byte.with_index do |byte, exp|
- result += (byte * 2**(exp * 8))
- end
-
- case b.sign
- when 43 # ?+
- result
- when 45 # ?-
- -result
- else
- raise FormatError, "Unexpected sign for Bignum #{b.sign.chr.inspect} (#{b.sign})"
- end
- end
-
- def resolve_class(n)
- @class_cache[n] ||= begin
- to_s = resolve_symbol_name(n)
- raise UnpermittedClassError.new(name: to_s, stack: formatted_stack) unless @permitted_classes.include?(to_s)
- visit_symbol_type(n)
- begin
- ::Object.const_get(to_s)
- rescue NameError
- raise ArgumentError, "Undefined class #{to_s.inspect}"
- end
- end
- end
-
- class RationalCompat
- def marshal_load(s)
- num, den = s
- raise ArgumentError, "Expected 2 ints" unless s.size == 2 && num.is_a?(Integer) && den.is_a?(Integer)
- Rational(num, den)
- end
- end
- private_constant :RationalCompat
-
- COMPAT_CLASSES = {}.tap do |h|
- h[Rational] = RationalCompat
- end.compare_by_identity.freeze
- private_constant :COMPAT_CLASSES
-
- def resolve_ivar(klass, name)
- to_s = resolve_symbol_name(name)
-
- raise UnpermittedIvarError.new(symbol: to_s, klass: klass, stack: formatted_stack) unless @permitted_ivars.fetch(klass.name, [].freeze).include?(to_s)
-
- visit_symbol_type(name)
- end
-
- def visit_symbol_type(element)
- case element
- when Elements::Symbol
- sym = element.name.to_sym
- @symbols << sym
- sym
- when Elements::SymbolLink
- visit_Gem_SafeMarshal_Elements_SymbolLink(element)
- end
- end
-
- # This is a hot method, so avoid respond_to? checks on every invocation
- if :read.respond_to?(:name)
- def resolve_symbol_name(element)
- case element
- when Elements::Symbol
- element.name
- when Elements::SymbolLink
- visit_Gem_SafeMarshal_Elements_SymbolLink(element).name
- else
- raise FormatError, "Expected symbol or symbol link, got #{element.inspect} @ #{formatted_stack.join(".")}"
- end
- end
- else
- def resolve_symbol_name(element)
- case element
- when Elements::Symbol
- element.name
- when Elements::SymbolLink
- visit_Gem_SafeMarshal_Elements_SymbolLink(element).to_s
- else
- raise FormatError, "Expected symbol or symbol link, got #{element.inspect} @ #{formatted_stack.join(".")}"
- end
- end
- end
-
- def register_object(o)
- @objects << o
- o
- end
-
- def call_method(receiver, method, *args)
- receiver.__send__(method, *args)
- rescue NoMethodError => e
- raise unless e.receiver == receiver
-
- raise MethodCallError, "Unable to call #{method.inspect} on #{receiver.inspect}, perhaps it is a class using marshal compat, which is not visible in ruby? #{e}"
- end
-
- def formatted_stack
- formatted = []
- @stack[0, @stack_idx].each do |e|
- if e.is_a?(Integer)
- if formatted.last == "ivar_"
- formatted[-1] = "ivar_#{e}"
- else
- formatted << "[#{e}]"
- end
- else
- formatted << e
- end
- end
- formatted
- end
-
- class Error < StandardError
- end
-
- class UnpermittedSymbolError < Error
- def initialize(symbol:, stack:)
- @symbol = symbol
- @stack = stack
- super "Attempting to load unpermitted symbol #{symbol.inspect} @ #{stack.join "."}"
- end
- end
-
- class UnpermittedIvarError < Error
- def initialize(symbol:, klass:, stack:)
- @symbol = symbol
- @klass = klass
- @stack = stack
- super "Attempting to set unpermitted ivar #{symbol.inspect} on object of class #{klass} @ #{stack.join "."}"
- end
- end
-
- class UnpermittedClassError < Error
- def initialize(name:, stack:)
- @name = name
- @stack = stack
- super "Attempting to load unpermitted class #{name.inspect} @ #{stack.join "."}"
- end
- end
-
- class FormatError < Error
- end
-
- class MethodCallError < Error
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/visitors/visitor.rb b/lib/rubygems/safe_marshal/visitors/visitor.rb
deleted file mode 100644
index c9a079dc0e..0000000000
--- a/lib/rubygems/safe_marshal/visitors/visitor.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::SafeMarshal::Visitors
- class Visitor
- def visit(target)
- send DISPATCH.fetch(target.class), target
- end
-
- private
-
- DISPATCH = Gem::SafeMarshal::Elements.constants.each_with_object({}) do |c, h|
- next if c == :Element
-
- klass = Gem::SafeMarshal::Elements.const_get(c)
- h[klass] = :"visit_#{klass.name.gsub("::", "_")}"
- h.default = :visit_unknown_element
- end.compare_by_identity.freeze
- private_constant :DISPATCH
-
- def visit_unknown_element(e)
- raise ArgumentError, "Attempting to visit unknown element #{e.inspect}"
- end
-
- def visit_Gem_SafeMarshal_Elements_Array(target)
- target.elements.each {|e| visit(e) }
- end
-
- def visit_Gem_SafeMarshal_Elements_Bignum(target); end
- def visit_Gem_SafeMarshal_Elements_False(target); end
- def visit_Gem_SafeMarshal_Elements_Float(target); end
-
- def visit_Gem_SafeMarshal_Elements_Hash(target)
- target.pairs.each do |k, v|
- visit(k)
- visit(v)
- end
- end
-
- def visit_Gem_SafeMarshal_Elements_HashWithDefaultValue(target)
- visit_Gem_SafeMarshal_Elements_Hash(target)
- visit(target.default)
- end
-
- def visit_Gem_SafeMarshal_Elements_Integer(target); end
- def visit_Gem_SafeMarshal_Elements_Nil(target); end
-
- def visit_Gem_SafeMarshal_Elements_Object(target)
- visit(target.name)
- end
-
- def visit_Gem_SafeMarshal_Elements_ObjectLink(target); end
- def visit_Gem_SafeMarshal_Elements_String(target); end
- def visit_Gem_SafeMarshal_Elements_Symbol(target); end
- def visit_Gem_SafeMarshal_Elements_SymbolLink(target); end
- def visit_Gem_SafeMarshal_Elements_True(target); end
-
- def visit_Gem_SafeMarshal_Elements_UserDefined(target)
- visit(target.name)
- end
-
- def visit_Gem_SafeMarshal_Elements_UserMarshal(target)
- visit(target.name)
- visit(target.data)
- end
-
- def visit_Gem_SafeMarshal_Elements_WithIvars(target)
- visit(target.object)
- target.ivars.each do |k, v|
- visit(k)
- visit(v)
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_yaml.rb b/lib/rubygems/safe_yaml.rb
index dba3cfb16d..74ad25ca15 100644
--- a/lib/rubygems/safe_yaml.rb
+++ b/lib/rubygems/safe_yaml.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
module Gem
+
###
# This module is used for safely loading YAML specs from a gem. The
# `safe_load` method defined on this module is specifically designed for
@@ -25,12 +26,34 @@ module Gem
runtime
].freeze
- def self.safe_load(input)
- ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, aliases: true)
- end
+ if ::Psych.respond_to? :safe_load
+ def self.safe_load(input)
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0.pre1")
+ ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, aliases: true)
+ else
+ ::Psych.safe_load(input, PERMITTED_CLASSES, PERMITTED_SYMBOLS, true)
+ end
+ end
+
+ def self.load(input)
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0.pre1")
+ ::Psych.safe_load(input, permitted_classes: [::Symbol])
+ else
+ ::Psych.safe_load(input, [::Symbol])
+ end
+ end
+ else
+ unless Gem::Deprecate.skip
+ warn "Psych safe loading is not available. Please upgrade psych to a version that supports safe loading (>= 2.0)."
+ end
+
+ def self.safe_load(input, *args)
+ ::Psych.load input
+ end
- def self.load(input)
- ::Psych.safe_load(input, permitted_classes: [::Symbol])
+ def self.load(input)
+ ::Psych.load input
+ end
end
end
end
diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb
index 1e8e57b5a9..73ee1e4bb9 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -326,6 +326,7 @@ require_relative "openssl"
# http://pablotron.org/
module Gem::Security
+
##
# Gem::Security default exception type
@@ -360,7 +361,7 @@ module Gem::Security
##
# One day in seconds
- ONE_DAY = 86_400
+ ONE_DAY = 86400
##
# One year in seconds
@@ -398,7 +399,8 @@ module Gem::Security
#
# The +extensions+ restrict the key to the indicated uses.
- def self.create_cert(subject, key, age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
+ def self.create_cert(subject, key, age = ONE_YEAR, extensions = EXTENSIONS,
+ serial = 1)
cert = OpenSSL::X509::Certificate.new
cert.public_key = get_public_key(key)
@@ -449,7 +451,8 @@ module Gem::Security
# Creates a self-signed certificate with an issuer and subject of +subject+
# and the given +extensions+ for the +key+.
- def self.create_cert_self_signed(subject, key, age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
+ def self.create_cert_self_signed(subject, key, age = ONE_YEAR,
+ extensions = EXTENSIONS, serial = 1)
certificate = create_cert subject, key, age, extensions
sign certificate, key, certificate, age, extensions, serial
@@ -459,8 +462,16 @@ module Gem::Security
# Creates a new digest instance using the specified +algorithm+. The default
# is SHA256.
- def self.create_digest(algorithm = DIGEST_NAME)
- OpenSSL::Digest.new(algorithm)
+ if defined?(OpenSSL::Digest)
+ def self.create_digest(algorithm = DIGEST_NAME)
+ OpenSSL::Digest.new(algorithm)
+ end
+ else
+ require "digest"
+
+ def self.create_digest(algorithm = DIGEST_NAME)
+ Digest.const_get(algorithm).new
+ end
end
##
@@ -505,10 +516,11 @@ module Gem::Security
#--
# TODO increment serial
- def self.re_sign(expired_certificate, private_key, age = ONE_YEAR, extensions = EXTENSIONS)
+ def self.re_sign(expired_certificate, private_key, age = ONE_YEAR,
+ extensions = EXTENSIONS)
raise Gem::Security::Exception,
"incorrect signing key for re-signing " +
- expired_certificate.subject.to_s unless
+ "#{expired_certificate.subject}" unless
expired_certificate.check_private_key(private_key)
unless expired_certificate.subject.to_s ==
@@ -517,7 +529,7 @@ module Gem::Security
issuer = alt_name_or_x509_entry expired_certificate, :issuer
raise Gem::Security::Exception,
- "#{subject} is not self-signed, contact #{issuer} " \
+ "#{subject} is not self-signed, contact #{issuer} " +
"to obtain a valid certificate"
end
@@ -541,7 +553,8 @@ module Gem::Security
#
# Returns the newly signed certificate.
- def self.sign(certificate, signing_key, signing_cert, age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
+ def self.sign(certificate, signing_key, signing_cert,
+ age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
signee_subject = certificate.subject
signee_key = certificate.public_key
@@ -589,7 +602,7 @@ module Gem::Security
# +permissions+. If passed +cipher+ and +passphrase+ those arguments will be
# passed to +to_pem+.
- def self.write(pemmable, path, permissions = 0o600, passphrase = nil, cipher = KEY_CIPHER)
+ def self.write(pemmable, path, permissions = 0600, passphrase = nil, cipher = KEY_CIPHER)
path = File.expand_path path
File.open path, "wb", permissions do |io|
@@ -604,6 +617,7 @@ module Gem::Security
end
reset
+
end
if Gem::HAVE_OPENSSL
diff --git a/lib/rubygems/security/policies.rb b/lib/rubygems/security/policies.rb
index 4180832d85..bdfe9ed43f 100644
--- a/lib/rubygems/security/policies.rb
+++ b/lib/rubygems/security/policies.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
module Gem::Security
+
##
# No security policy: all package signature checks are disabled.
@@ -111,4 +112,5 @@ module Gem::Security
"HighSecurity" => HighSecurity,
# SigningPolicy is not intended for use by `gem -P` so do not list it
}.freeze
+
end
diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb
index 7b86ac5763..9b9eac46bf 100644
--- a/lib/rubygems/security/policy.rb
+++ b/lib/rubygems/security/policy.rb
@@ -135,7 +135,7 @@ class Gem::Security::Policy
raise Gem::Security::Exception, "missing root certificate" unless root
raise Gem::Security::Exception,
- "root certificate #{root.subject} is not self-signed " \
+ "root certificate #{root.subject} is not self-signed " +
"(issuer #{root.issuer})" if
root.issuer != root.subject
@@ -171,7 +171,7 @@ class Gem::Security::Policy
cert_dgst = digester.digest pkey_str
raise Gem::Security::Exception,
- "trusted root certificate #{root.subject} checksum " \
+ "trusted root certificate #{root.subject} checksum " +
"does not match signing root certificate checksum" unless
save_dgst == cert_dgst
@@ -192,8 +192,11 @@ class Gem::Security::Policy
end
def inspect # :nodoc:
- format("[Policy: %s - data: %p signer: %p chain: %p root: %p " \
- "signed-only: %p trusted-only: %p]", @name, @verify_chain, @verify_data, @verify_root, @verify_signer, @only_signed, @only_trusted)
+ ("[Policy: %s - data: %p signer: %p chain: %p root: %p " +
+ "signed-only: %p trusted-only: %p]") % [
+ @name, @verify_chain, @verify_data, @verify_root, @verify_signer,
+ @only_signed, @only_trusted
+ ]
end
##
@@ -203,7 +206,8 @@ class Gem::Security::Policy
#
# If +key+ is given it is used to validate the signing certificate.
- def verify(chain, key = nil, digests = {}, signatures = {}, full_name = "(unknown)")
+ def verify(chain, key = nil, digests = {}, signatures = {},
+ full_name = "(unknown)")
if signatures.empty?
if @only_signed
raise Gem::Security::Exception,
@@ -222,7 +226,7 @@ class Gem::Security::Policy
trust_dir = opt[:trust_dir]
time = Time.now
- _, signer_digests = digests.find do |_algorithm, file_digests|
+ _, signer_digests = digests.find do |algorithm, file_digests|
file_digests.values.first.name == Gem::Security::DIGEST_NAME
end
@@ -284,5 +288,5 @@ class Gem::Security::Policy
true
end
- alias_method :to_s, :name # :nodoc:
+ alias to_s name # :nodoc:
end
diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb
index 5732fb57fd..d76af03eb8 100644
--- a/lib/rubygems/security/signer.rb
+++ b/lib/rubygems/security/signer.rb
@@ -106,7 +106,7 @@ class Gem::Security::Signer
# this value is preferred, otherwise the subject is used.
def extract_name(cert) # :nodoc:
- subject_alt_name = cert.extensions.find {|e| e.oid == "subjectAltName" }
+ subject_alt_name = cert.extensions.find {|e| "subjectAltName" == e.oid }
if subject_alt_name
/\Aemail:/ =~ subject_alt_name.value # rubocop:disable Performance/StartWith
@@ -175,18 +175,10 @@ class Gem::Security::Signer
old_cert = @cert_chain.last
disk_cert_path = File.join(Gem.default_cert_path)
- disk_cert = begin
- File.read(disk_cert_path)
- rescue StandardError
- nil
- end
+ disk_cert = File.read(disk_cert_path) rescue nil
disk_key_path = File.join(Gem.default_key_path)
- disk_key = begin
- OpenSSL::PKey.read(File.read(disk_key_path), @passphrase)
- rescue StandardError
- nil
- end
+ disk_key = OpenSSL::PKey.read(File.read(disk_key_path), @passphrase) rescue nil
return unless disk_key
diff --git a/lib/rubygems/security/trust_dir.rb b/lib/rubygems/security/trust_dir.rb
index ea011e6d65..4de33068f9 100644
--- a/lib/rubygems/security/trust_dir.rb
+++ b/lib/rubygems/security/trust_dir.rb
@@ -9,8 +9,8 @@ class Gem::Security::TrustDir
# Default permissions for the trust directory and its contents
DEFAULT_PERMISSIONS = {
- :trust_dir => 0o700,
- :trusted_cert => 0o600,
+ :trust_dir => 0700,
+ :trusted_cert => 0600,
}.freeze
##
@@ -45,11 +45,13 @@ class Gem::Security::TrustDir
glob = File.join @dir, "*.pem"
Dir[glob].each do |certificate_file|
- certificate = load_certificate certificate_file
+ begin
+ certificate = load_certificate certificate_file
- yield certificate, certificate_file
- rescue OpenSSL::X509::CertificateError
- next # HACK: warn
+ yield certificate, certificate_file
+ rescue OpenSSL::X509::CertificateError
+ next # HACK warn
+ end
end
end
@@ -91,7 +93,7 @@ class Gem::Security::TrustDir
destination = cert_path certificate
- File.open destination, "wb", 0o600 do |io|
+ File.open destination, "wb", 0600 do |io|
io.write certificate.to_pem
io.chmod(@permissions[:trusted_cert])
end
@@ -109,7 +111,7 @@ class Gem::Security::TrustDir
"trust directory #{@dir} is not a directory" unless
File.directory? @dir
- FileUtils.chmod 0o700, @dir
+ FileUtils.chmod 0700, @dir
else
FileUtils.mkdir_p @dir, :mode => @permissions[:trust_dir]
end
diff --git a/lib/rubygems/security_option.rb b/lib/rubygems/security_option.rb
index 3a101fe9db..f288ebd047 100644
--- a/lib/rubygems/security_option.rb
+++ b/lib/rubygems/security_option.rb
@@ -29,7 +29,7 @@ module Gem::SecurityOption
policy = Gem::Security::Policies[value]
unless policy
valid = Gem::Security::Policies.keys.sort
- raise Gem::OptionParser::InvalidArgument, "#{value} (#{valid.join ", "} are valid)"
+ raise Gem::OptionParser::InvalidArgument, "#{value} (#{valid.join ', '} are valid)"
end
policy
end
diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb
index 7c5b746a43..aa0cbc1641 100644
--- a/lib/rubygems/source.rb
+++ b/lib/rubygems/source.rb
@@ -44,18 +44,20 @@ class Gem::Source
Gem::Source::Vendor then
-1
when Gem::Source then
- unless @uri
+ if !@uri
return 0 unless other.uri
return 1
end
- return -1 unless other.uri
+ return -1 if !other.uri
# Returning 1 here ensures that when sorting a list of sources, the
# original ordering of sources supplied by the user is preserved.
return 1 unless @uri.to_s == other.uri.to_s
0
+ else
+ nil
end
end
@@ -69,7 +71,7 @@ class Gem::Source
# Returns a Set that can fetch specifications from this source.
def dependency_resolver_set # :nodoc:
- return Gem::Resolver::IndexSet.new self if uri.scheme == "file"
+ return Gem::Resolver::IndexSet.new self if "file" == uri.scheme
fetch_uri = if uri.host == "rubygems.org"
index_uri = uri.dup
@@ -100,7 +102,7 @@ class Gem::Source
def cache_dir(uri)
# Correct for windows paths
- escaped_path = uri.path.sub(%r{^/([a-z]):/}i, '/\\1-/')
+ escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/')
escaped_path.tap(&Gem::UNTAINT)
File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
@@ -135,12 +137,7 @@ class Gem::Source
if File.exist? local_spec
spec = Gem.read_binary local_spec
- Gem.load_safe_marshal
- spec = begin
- Gem::SafeMarshal.safe_load(spec)
- rescue StandardError
- nil
- end
+ spec = Marshal.load(spec) rescue nil
return spec if spec
end
@@ -158,9 +155,8 @@ class Gem::Source
end
end
- Gem.load_safe_marshal
# TODO: Investigate setting Gem::Specification#loaded_from to a URI
- Gem::SafeMarshal.safe_load spec
+ Marshal.load spec
end
##
@@ -190,9 +186,8 @@ class Gem::Source
spec_dump = fetcher.cache_update_path spec_path, local_file, update_cache?
- Gem.load_safe_marshal
begin
- Gem::NameTuple.from_list Gem::SafeMarshal.safe_load(spec_dump)
+ Gem::NameTuple.from_list Marshal.load(spec_dump)
rescue ArgumentError
if update_cache? && !retried
FileUtils.rm local_file
@@ -234,7 +229,7 @@ class Gem::Source
private
def enforce_trailing_slash(uri)
- uri.merge(uri.path.gsub(%r{/+$}, "") + "/")
+ uri.merge(uri.path.gsub(/\/+$/, "") + "/")
end
end
diff --git a/lib/rubygems/source/git.rb b/lib/rubygems/source/git.rb
index 70e8d1b06e..7ac685f978 100644
--- a/lib/rubygems/source/git.rb
+++ b/lib/rubygems/source/git.rb
@@ -70,6 +70,8 @@ class Gem::Source::Git < Gem::Source
-1
when Gem::Source then
1
+ else
+ nil
end
end
diff --git a/lib/rubygems/source/installed.rb b/lib/rubygems/source/installed.rb
index cbe12a0516..f5d3f06d6a 100644
--- a/lib/rubygems/source/installed.rb
+++ b/lib/rubygems/source/installed.rb
@@ -21,6 +21,8 @@ class Gem::Source::Installed < Gem::Source
0
when Gem::Source then
1
+ else
+ nil
end
end
diff --git a/lib/rubygems/source/local.rb b/lib/rubygems/source/local.rb
index d81d8343a8..5068b0b906 100644
--- a/lib/rubygems/source/local.rb
+++ b/lib/rubygems/source/local.rb
@@ -24,12 +24,14 @@ class Gem::Source::Local < Gem::Source
0
when Gem::Source then
1
+ else
+ nil
end
end
def inspect # :nodoc:
keys = @specs ? @specs.keys.sort : "NOT LOADED"
- format("#<%s specs: %p>", self.class, keys)
+ "#<%s specs: %p>" % [self.class, keys]
end
def load_specs(type) # :nodoc:
@@ -39,35 +41,36 @@ class Gem::Source::Local < Gem::Source
@specs = {}
Dir["*.gem"].each do |file|
- pkg = Gem::Package.new(file)
- spec = pkg.spec
- rescue SystemCallError, Gem::Package::FormatError
- # ignore
- else
- tup = spec.name_tuple
- @specs[tup] = [File.expand_path(file), pkg]
-
- case type
- when :released
- unless pkg.spec.version.prerelease?
- names << pkg.spec.name_tuple
- end
- when :prerelease
- if pkg.spec.version.prerelease?
- names << pkg.spec.name_tuple
- end
- when :latest
+ begin
+ pkg = Gem::Package.new(file)
+ rescue SystemCallError, Gem::Package::FormatError
+ # ignore
+ else
tup = pkg.spec.name_tuple
-
- cur = names.find {|x| x.name == tup.name }
- if !cur
- names << tup
- elsif cur.version < tup.version
- names.delete cur
- names << tup
+ @specs[tup] = [File.expand_path(file), pkg]
+
+ case type
+ when :released
+ unless pkg.spec.version.prerelease?
+ names << pkg.spec.name_tuple
+ end
+ when :prerelease
+ if pkg.spec.version.prerelease?
+ names << pkg.spec.name_tuple
+ end
+ when :latest
+ tup = pkg.spec.name_tuple
+
+ cur = names.find {|x| x.name == tup.name }
+ if !cur
+ names << tup
+ elsif cur.version < tup.version
+ names.delete cur
+ names << tup
+ end
+ else
+ names << pkg.spec.name_tuple
end
- else
- names << pkg.spec.name_tuple
end
end
@@ -75,25 +78,27 @@ class Gem::Source::Local < Gem::Source
end
end
- def find_gem(gem_name, version = Gem::Requirement.default, prerelease = false) # :nodoc:
+ def find_gem(gem_name, version = Gem::Requirement.default, # :nodoc:
+ prerelease = false)
load_specs :complete
found = []
@specs.each do |n, data|
- next unless n.name == gem_name
- s = data[1].spec
-
- if version.satisfied_by?(s.version)
- if prerelease
- found << s
- elsif !s.version.prerelease? || version.prerelease?
- found << s
+ if n.name == gem_name
+ s = data[1].spec
+
+ if version.satisfied_by?(s.version)
+ if prerelease
+ found << s
+ elsif !s.version.prerelease? || version.prerelease?
+ found << s
+ end
end
end
end
- found.max_by(&:version)
+ found.max_by {|s| s.version }
end
def fetch_spec(name) # :nodoc:
@@ -109,7 +114,7 @@ class Gem::Source::Local < Gem::Source
def download(spec, cache_dir = nil) # :nodoc:
load_specs :complete
- @specs.each do |_name, data|
+ @specs.each do |name, data|
return data[0] if data[1].spec == spec
end
diff --git a/lib/rubygems/source/lock.rb b/lib/rubygems/source/lock.rb
index 70849210bd..f9388bbd61 100644
--- a/lib/rubygems/source/lock.rb
+++ b/lib/rubygems/source/lock.rb
@@ -25,11 +25,13 @@ class Gem::Source::Lock < Gem::Source
@wrapped <=> other.wrapped
when Gem::Source then
1
+ else
+ nil
end
end
def ==(other) # :nodoc:
- (self <=> other) == 0
+ 0 == (self <=> other)
end
def hash # :nodoc:
diff --git a/lib/rubygems/source/specific_file.rb b/lib/rubygems/source/specific_file.rb
index e9b2753646..61965c2644 100644
--- a/lib/rubygems/source/specific_file.rb
+++ b/lib/rubygems/source/specific_file.rb
@@ -34,6 +34,7 @@ class Gem::Source::SpecificFile < Gem::Source
def fetch_spec(name) # :nodoc:
return @spec if name == @name
raise Gem::Exception, "Unable to find '#{name}'"
+ @spec
end
def download(spec, dir = nil) # :nodoc:
diff --git a/lib/rubygems/source/vendor.rb b/lib/rubygems/source/vendor.rb
index 44ef614441..12161b8cf5 100644
--- a/lib/rubygems/source/vendor.rb
+++ b/lib/rubygems/source/vendor.rb
@@ -19,6 +19,8 @@ class Gem::Source::Vendor < Gem::Source::Installed
0
when Gem::Source then
1
+ else
+ nil
end
end
end
diff --git a/lib/rubygems/source_list.rb b/lib/rubygems/source_list.rb
index 9e8a9e16ef..7abe796409 100644
--- a/lib/rubygems/source_list.rb
+++ b/lib/rubygems/source_list.rb
@@ -36,7 +36,7 @@ class Gem::SourceList
list.replace ary
- list
+ return list
end
def initialize_copy(other) # :nodoc:
@@ -49,10 +49,10 @@ class Gem::SourceList
def <<(obj)
src = case obj
- when Gem::Source
- obj
- else
- Gem::Source.new(obj)
+ when Gem::Source
+ obj
+ else
+ Gem::Source.new(obj)
end
@sources << src unless @sources.include?(src)
@@ -126,7 +126,7 @@ class Gem::SourceList
# Gem::Source or a source URI.
def include?(other)
- if other.is_a? Gem::Source
+ if other.kind_of? Gem::Source
@sources.include? other
else
@sources.find {|x| x.uri.to_s == other.to_s }
@@ -137,7 +137,7 @@ class Gem::SourceList
# Deletes +source+ from the source list which may be a Gem::Source or a URI.
def delete(source)
- if source.is_a? Gem::Source
+ if source.kind_of? Gem::Source
@sources.delete source
else
@sources.delete_if {|x| x.uri.to_s == source.to_s }
diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb
index 34e6d7638c..a5a4fa0c0f 100644
--- a/lib/rubygems/spec_fetcher.rb
+++ b/lib/rubygems/spec_fetcher.rb
@@ -92,9 +92,9 @@ class Gem::SpecFetcher
list.each do |source, specs|
if dependency.name.is_a?(String) && specs.respond_to?(:bsearch)
- start_index = (0...specs.length).bsearch {|i| specs[i].name >= dependency.name }
- end_index = (0...specs.length).bsearch {|i| specs[i].name > dependency.name }
- specs = specs[start_index...end_index] if start_index && end_index
+ start_index = (0 ... specs.length).bsearch {|i| specs[i].name >= dependency.name }
+ end_index = (0 ... specs.length).bsearch {|i| specs[i].name > dependency.name }
+ specs = specs[start_index ... end_index] if start_index && end_index
end
found[source] = specs.select do |tup|
@@ -124,7 +124,7 @@ class Gem::SpecFetcher
tuples = tuples.sort_by {|x| x[0].version }
- [tuples, errors]
+ return [tuples, errors]
end
##
@@ -155,14 +155,16 @@ class Gem::SpecFetcher
specs = []
tuples.each do |tup, source|
- spec = source.fetch_spec(tup)
- rescue Gem::RemoteFetcher::FetchError => e
- errors << Gem::SourceFetchProblem.new(source, e)
- else
- specs << [spec, source]
+ begin
+ spec = source.fetch_spec(tup)
+ rescue Gem::RemoteFetcher::FetchError => e
+ errors << Gem::SourceFetchProblem.new(source, e)
+ else
+ specs << [spec, source]
+ end
end
- [specs, errors]
+ return [specs, errors]
end
##
@@ -192,10 +194,10 @@ class Gem::SpecFetcher
matches = if matches.empty? && type != :prerelease
suggest_gems_from_name gem_name, :prerelease
else
- matches.uniq.sort_by {|_name, dist| dist }
+ matches.uniq.sort_by {|name, dist| dist }
end
- matches.map {|name, _dist| name }.uniq.first(num_results)
+ matches.map {|name, dist| name }.uniq.first(num_results)
end
##
@@ -213,32 +215,34 @@ class Gem::SpecFetcher
list = {}
@sources.each_source do |source|
- names = case type
- when :latest
- tuples_for source, :latest
- when :released
- tuples_for source, :released
- when :complete
- names =
- tuples_for(source, :prerelease, true) +
- tuples_for(source, :released)
-
- names.sort
- when :abs_latest
- names =
- tuples_for(source, :prerelease, true) +
- tuples_for(source, :latest)
-
- names.sort
- when :prerelease
- tuples_for(source, :prerelease)
- else
- raise Gem::Exception, "Unknown type - :#{type}"
+ begin
+ names = case type
+ when :latest
+ tuples_for source, :latest
+ when :released
+ tuples_for source, :released
+ when :complete
+ names =
+ tuples_for(source, :prerelease, true) +
+ tuples_for(source, :released)
+
+ names.sort
+ when :abs_latest
+ names =
+ tuples_for(source, :prerelease, true) +
+ tuples_for(source, :latest)
+
+ names.sort
+ when :prerelease
+ tuples_for(source, :prerelease)
+ else
+ raise Gem::Exception, "Unknown type - :#{type}"
+ end
+ rescue Gem::RemoteFetcher::FetchError => e
+ errors << Gem::SourceFetchProblem.new(source, e)
+ else
+ list[source] = names
end
- rescue Gem::RemoteFetcher::FetchError => e
- errors << Gem::SourceFetchProblem.new(source, e)
- else
- list[source] = names
end
[list, errors]
@@ -250,7 +254,7 @@ class Gem::SpecFetcher
def tuples_for(source, type, gracefully_ignore=false) # :nodoc:
@caches[type][source.uri] ||=
- source.load_specs(type).sort_by(&:name)
+ source.load_specs(type).sort_by {|tup| tup.name }
rescue Gem::RemoteFetcher::FetchError
raise unless gracefully_ignore
[]
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 31ef29f02f..7611e1ba1f 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -13,8 +13,6 @@ require_relative "stub_specification"
require_relative "platform"
require_relative "util/list"
-require "rbconfig"
-
##
# The Specification class contains the information for a gem. Typically
# defined in a .gemspec file or a Rakefile, and looks like this:
@@ -164,17 +162,19 @@ class Gem::Specification < Gem::BasicSpecification
@@default_value.each do |k,v|
INITIALIZE_CODE_FOR_DEFAULTS[k] = case v
- when [], {}, true, false, nil, Numeric, Symbol
- v.inspect
- when String
- v.dump
- else
- "default_value(:#{k}).dup"
+ when [], {}, true, false, nil, Numeric, Symbol
+ v.inspect
+ when String
+ v.dump
+ when Numeric
+ "default_value(:#{k})"
+ else
+ "default_value(:#{k}).dup"
end
end
- @@attributes = @@default_value.keys.sort_by(&:to_s)
- @@array_attributes = @@default_value.reject {|_k,v| v != [] }.keys
+ @@attributes = @@default_value.keys.sort_by {|s| s.to_s }
+ @@array_attributes = @@default_value.reject {|k,v| v != [] }.keys
@@nil_attributes, @@non_nil_attributes = @@default_value.keys.partition do |k|
@@default_value[k].nil?
end
@@ -263,7 +263,8 @@ class Gem::Specification < Gem::BasicSpecification
@test_files,
add_bindir(@executables),
@extra_rdoc_files,
- @extensions].flatten.compact.uniq.sort
+ @extensions,
+ ].flatten.compact.uniq.sort
end
##
@@ -426,11 +427,11 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # The path in the gem for executable scripts. Usually 'exe'
+ # The path in the gem for executable scripts. Usually 'bin'
#
# Usage:
#
- # spec.bindir = 'exe'
+ # spec.bindir = 'bin'
attr_accessor :bindir
@@ -502,6 +503,8 @@ class Gem::Specification < Gem::BasicSpecification
@platform = @new_platform.to_s
invalidate_memoized_attributes
+
+ @new_platform
end
##
@@ -531,6 +534,13 @@ class Gem::Specification < Gem::BasicSpecification
attr_reader :required_rubygems_version
##
+ # The version of RubyGems used to create this gem.
+ #
+ # Do not set this, it is set automatically when the gem is packaged.
+
+ attr_accessor :rubygems_version
+
+ ##
# The key used to sign this gem. See Gem::Security for details.
attr_accessor :signing_key
@@ -568,7 +578,7 @@ class Gem::Specification < Gem::BasicSpecification
##
# Executables included in the gem.
#
- # For example, the rake gem has rake as an executable. You don't specify the
+ # For example, the rake gem has rake as an executable. You don’t specify the
# full path (as in bin/rake); all application-style files are expected to be
# found in bindir. These files must be executable Ruby files. Files that
# use bash or other interpreters will not work.
@@ -589,7 +599,7 @@ class Gem::Specification < Gem::BasicSpecification
# extconf.rb-style files used to compile extensions.
#
# These files will be run when the gem is installed, causing the C (or
- # whatever) code to be compiled on the user's machine.
+ # whatever) code to be compiled on the user’s machine.
#
# Usage:
#
@@ -718,21 +728,6 @@ class Gem::Specification < Gem::BasicSpecification
end
######################################################################
- # :section: Read-only attributes
-
- ##
- # The version of RubyGems used to create this gem.
-
- attr_accessor :rubygems_version
-
- ##
- # The path where this gem installs its extensions.
-
- def extensions_dir
- @extensions_dir ||= super
- end
-
- ######################################################################
# :section: Specification internals
##
@@ -740,7 +735,7 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :activated
- alias_method :activated?, :activated
+ alias :activated? :activated
##
# Autorequire was used by old RubyGems to automatically require a file.
@@ -862,7 +857,7 @@ class Gem::Specification < Gem::BasicSpecification
installed_stubs = installed_stubs(Gem::Specification.dirs, pattern)
installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
stubs = installed_stubs + default_stubs(pattern)
- stubs = stubs.uniq(&:full_name)
+ stubs = stubs.uniq {|stub| stub.full_name }
_resort!(stubs)
stubs
end
@@ -943,7 +938,7 @@ class Gem::Specification < Gem::BasicSpecification
# Return full names of all specs in sorted order.
def self.all_names
- _all.map(&:full_name)
+ self._all.map(&:full_name)
end
##
@@ -978,7 +973,7 @@ class Gem::Specification < Gem::BasicSpecification
# this resets the list of known specs.
def self.dirs=(dirs)
- reset
+ self.reset
@@dirs = Array(dirs).map {|dir| File.join dir, "specifications" }
end
@@ -992,7 +987,7 @@ class Gem::Specification < Gem::BasicSpecification
def self.each
return enum_for(:each) unless block_given?
- _all.each do |x|
+ self._all.each do |x|
yield x
end
end
@@ -1038,10 +1033,9 @@ class Gem::Specification < Gem::BasicSpecification
def self.find_by_path(path)
path = path.dup.freeze
- spec = @@spec_with_requirable_file[path] ||= stubs.find do |s|
+ spec = @@spec_with_requirable_file[path] ||= (stubs.find do |s|
s.contains_requirable_file? path
- end || NOT_FOUND
-
+ end || NOT_FOUND)
spec.to_spec
end
@@ -1058,10 +1052,9 @@ class Gem::Specification < Gem::BasicSpecification
end
def self.find_active_stub_by_path(path)
- stub = @@active_stub_with_requirable_file[path] ||= stubs.find do |s|
+ stub = @@active_stub_with_requirable_file[path] ||= (stubs.find do |s|
s.activated? && s.contains_requirable_file?(path)
- end || NOT_FOUND
-
+ end || NOT_FOUND)
stub.this
end
@@ -1078,7 +1071,7 @@ class Gem::Specification < Gem::BasicSpecification
def self.find_in_unresolved_tree(path)
unresolved_specs.each do |spec|
- spec.traverse do |_from_spec, _dep, to_spec, trail|
+ spec.traverse do |from_spec, dep, to_spec, trail|
if to_spec.has_conflicts? || to_spec.conficts_when_loaded_with?(trail)
:next
else
@@ -1091,7 +1084,7 @@ class Gem::Specification < Gem::BasicSpecification
end
def self.unresolved_specs
- unresolved_deps.values.map(&:to_specs).flatten
+ unresolved_deps.values.map {|dep| dep.to_specs }.flatten
end
private_class_method :unresolved_specs
@@ -1143,14 +1136,12 @@ class Gem::Specification < Gem::BasicSpecification
result = {}
specs.reverse_each do |spec|
- unless prerelease
- next if spec.version.prerelease?
- end
+ next if spec.version.prerelease? unless prerelease
result[spec.name] = spec
end
- result.map(&:last).flatten.sort_by(&:name)
+ result.map(&:last).flatten.sort_by {|tup| tup.name }
end
##
@@ -1159,8 +1150,8 @@ class Gem::Specification < Gem::BasicSpecification
def self.load(file)
return unless file
- spec = @load_cache_mutex.synchronize { @load_cache[file] }
- return spec if spec
+ _spec = @load_cache_mutex.synchronize { @load_cache[file] }
+ return _spec if _spec
file = file.dup.tap(&Gem::UNTAINT)
return unless File.file?(file)
@@ -1170,25 +1161,25 @@ class Gem::Specification < Gem::BasicSpecification
code.tap(&Gem::UNTAINT)
begin
- spec = eval code, binding, file
+ _spec = eval code, binding, file
- if Gem::Specification === spec
- spec.loaded_from = File.expand_path file.to_s
+ if Gem::Specification === _spec
+ _spec.loaded_from = File.expand_path file.to_s
@load_cache_mutex.synchronize do
prev = @load_cache[file]
if prev
- spec = prev
+ _spec = prev
else
- @load_cache[file] = spec
+ @load_cache[file] = _spec
end
end
- return spec
+ return _spec
end
- warn "[#{file}] isn't a Gem::Specification (#{spec.class} instead)."
+ warn "[#{file}] isn't a Gem::Specification (#{_spec.class} instead)."
rescue SignalException, SystemExit
raise
- rescue SyntaxError, StandardError => e
+ rescue SyntaxError, Exception => e
warn "Invalid gemspec in [#{file}]: #{e}"
end
@@ -1276,7 +1267,7 @@ class Gem::Specification < Gem::BasicSpecification
def self.reset
@@dirs = nil
- Gem.pre_reset_hooks.each(&:call)
+ Gem.pre_reset_hooks.each {|hook| hook.call }
clear_specs
clear_load_cache
unresolved = unresolved_deps
@@ -1295,7 +1286,7 @@ class Gem::Specification < Gem::BasicSpecification
warn "Please report a bug if this causes problems."
unresolved.clear
end
- Gem.post_reset_hooks.each(&:call)
+ Gem.post_reset_hooks.each {|hook| hook.call }
end
# DOC: This method needs documented or nodoc'd
@@ -1308,23 +1299,12 @@ class Gem::Specification < Gem::BasicSpecification
def self._load(str)
Gem.load_yaml
- Gem.load_safe_marshal
yaml_set = false
- retry_count = 0
array = begin
- Gem::SafeMarshal.safe_load str
+ Marshal.load str
rescue ArgumentError => e
- # Avoid an infinite retry loop when the argument error has nothing to do
- # with the classes not being defined.
- # 1 retry each allowed in case all 3 of
- # - YAML
- # - YAML::Syck::DefaultKey
- # - YAML::PrivateType
- # need to be defined
- raise if retry_count >= 3
-
#
# Some very old marshaled specs included references to `YAML::PrivateType`
# and `YAML::Syck::DefaultKey` constants due to bugs in the old emitter
@@ -1342,12 +1322,11 @@ class Gem::Specification < Gem::BasicSpecification
if message.include?("YAML::Syck::")
YAML.const_set "Syck", YAML unless YAML.const_defined?(:Syck)
- YAML::Syck.const_set "DefaultKey", Class.new if message.include?("YAML::Syck::DefaultKey") && !YAML::Syck.const_defined?(:DefaultKey)
- elsif message.include?("YAML::PrivateType") && !YAML.const_defined?(:PrivateType)
+ YAML::Syck.const_set "DefaultKey", Class.new if message.include?("YAML::Syck::DefaultKey")
+ elsif message.include?("YAML::PrivateType")
YAML.const_set "PrivateType", Class.new
end
- retry_count += 1
retry
ensure
Object.__send__(:remove_const, "YAML") if yaml_set
@@ -1444,7 +1423,7 @@ class Gem::Specification < Gem::BasicSpecification
# there are conflicts upon activation.
def activate
- other = Gem.loaded_specs[name]
+ other = Gem.loaded_specs[self.name]
if other
check_version_conflict other
return false
@@ -1455,11 +1434,11 @@ class Gem::Specification < Gem::BasicSpecification
activate_dependencies
add_self_to_load_path
- Gem.loaded_specs[name] = self
+ Gem.loaded_specs[self.name] = self
@activated = true
@loaded = true
- true
+ return true
end
##
@@ -1470,7 +1449,7 @@ class Gem::Specification < Gem::BasicSpecification
def activate_dependencies
unresolved = Gem::Specification.unresolved_deps
- runtime_dependencies.each do |spec_dep|
+ self.runtime_dependencies.each do |spec_dep|
if loaded = Gem.loaded_specs[spec_dep.name]
next if spec_dep.matches_spec? loaded
@@ -1484,7 +1463,7 @@ class Gem::Specification < Gem::BasicSpecification
begin
specs = spec_dep.to_specs
rescue Gem::MissingSpecError => e
- raise Gem::MissingSpecError.new(e.name, e.requirement, "at: #{spec_file}")
+ raise Gem::MissingSpecError.new(e.name, e.requirement, "at: #{self.spec_file}")
end
if specs.size == 1
@@ -1530,7 +1509,7 @@ class Gem::Specification < Gem::BasicSpecification
def sanitize_string(string)
return string unless string
- # HACK: the #to_s is in here because RSpec has an Array of Arrays of
+ # HACK the #to_s is in here because RSpec has an Array of Arrays of
# Strings for authors. Need a way to disallow bad values on gemspec
# generation. (Probably won't happen.)
string.to_s
@@ -1548,8 +1527,8 @@ class Gem::Specification < Gem::BasicSpecification
else
executables
end
- rescue StandardError
- nil
+ rescue
+ return nil
end
##
@@ -1574,7 +1553,7 @@ class Gem::Specification < Gem::BasicSpecification
private :add_dependency_with_type
- alias_method :add_dependency, :add_runtime_dependency
+ alias add_dependency add_runtime_dependency
##
# Adds this spec's require paths to LOAD_PATH, in the proper location.
@@ -1626,7 +1605,7 @@ class Gem::Specification < Gem::BasicSpecification
def build_args
if File.exist? build_info_file
build_info = File.readlines build_info_file
- build_info = build_info.map(&:strip)
+ build_info = build_info.map {|x| x.strip }
build_info.delete ""
build_info
else
@@ -1644,8 +1623,8 @@ class Gem::Specification < Gem::BasicSpecification
# we need to fresh build when same name and version of default gems
return if self.class.find_by_full_name(full_name)&.default_gem?
return if File.exist? gem_build_complete_path
- return unless File.writable?(base_dir)
- return unless File.exist?(File.join(base_dir, "extensions"))
+ return if !File.writable?(base_dir)
+ return if !File.exist?(File.join(base_dir, "extensions"))
begin
# We need to require things in $LOAD_PATH without looking for the
@@ -1703,7 +1682,7 @@ class Gem::Specification < Gem::BasicSpecification
def conflicts
conflicts = {}
- runtime_dependencies.each do |dep|
+ self.runtime_dependencies.each do |dep|
spec = Gem.loaded_specs[dep.name]
if spec && !spec.satisfies_requirement?(dep)
(conflicts[spec] ||= []) << dep
@@ -1719,7 +1698,7 @@ class Gem::Specification < Gem::BasicSpecification
def conficts_when_loaded_with?(list_of_specs) # :nodoc:
result = list_of_specs.any? do |spec|
- spec.runtime_dependencies.any? {|dep| (dep.name == name) && !satisfies_requirement?(dep) }
+ spec.dependencies.any? {|dep| dep.runtime? && (dep.name == name) && !satisfies_requirement?(dep) }
end
result
end
@@ -1729,12 +1708,14 @@ class Gem::Specification < Gem::BasicSpecification
def has_conflicts?
return true unless Gem.env_requirement(name).satisfied_by?(version)
- runtime_dependencies.any? do |dep|
- spec = Gem.loaded_specs[dep.name]
- spec && !spec.satisfies_requirement?(dep)
+ self.dependencies.any? do |dep|
+ if dep.runtime?
+ spec = Gem.loaded_specs[dep.name]
+ spec && !spec.satisfies_requirement?(dep)
+ else
+ false
+ end
end
- rescue ArgumentError => e
- raise e, "#{name} #{version}: #{e.message}"
end
# The date this gem was created.
@@ -1770,17 +1751,17 @@ class Gem::Specification < Gem::BasicSpecification
# This is the cleanest, most-readable, faster-than-using-Date
# way to do it.
@date = case date
- when String then
- if DateTimeFormat =~ date
- Time.utc($1.to_i, $2.to_i, $3.to_i)
- else
- raise(Gem::InvalidSpecificationException,
- "invalid date format in specification: #{date.inspect}")
- end
- when Time, DateLike then
- Time.utc(date.year, date.month, date.day)
- else
- TODAY
+ when String then
+ if DateTimeFormat =~ date
+ Time.utc($1.to_i, $2.to_i, $3.to_i)
+ else
+ raise(Gem::InvalidSpecificationException,
+ "invalid date format in specification: #{date.inspect}")
+ end
+ when Time, DateLike then
+ Time.utc(date.year, date.month, date.day)
+ else
+ TODAY
end
end
@@ -1830,12 +1811,13 @@ class Gem::Specification < Gem::BasicSpecification
Gem::Specification.each do |spec|
deps = check_dev ? spec.dependencies : spec.runtime_dependencies
deps.each do |dep|
- next unless satisfies_requirement?(dep)
- sats = []
- find_all_satisfiers(dep) do |sat|
- sats << sat
+ if self.satisfies_requirement?(dep)
+ sats = []
+ find_all_satisfiers(dep) do |sat|
+ sats << sat
+ end
+ out << [spec, dep, sats]
end
- out << [spec, dep, sats]
end
end
out
@@ -1845,7 +1827,7 @@ class Gem::Specification < Gem::BasicSpecification
# Returns all specs that matches this spec's runtime dependencies.
def dependent_specs
- runtime_dependencies.map(&:to_specs).flatten
+ runtime_dependencies.map {|dep| dep.to_specs }.flatten
end
##
@@ -1886,12 +1868,12 @@ class Gem::Specification < Gem::BasicSpecification
coder.add "name", @name
coder.add "version", @version
platform = case @original_platform
- when nil, "" then
- "ruby"
- when String then
- @original_platform
- else
- @original_platform.to_s
+ when nil, "" then
+ "ruby"
+ when String then
+ @original_platform
+ else
+ @original_platform.to_s
end
coder.add "platform", platform
@@ -2014,7 +1996,7 @@ class Gem::Specification < Gem::BasicSpecification
end
rubygems_deprecate :has_rdoc=
- alias_method :has_rdoc?, :has_rdoc # :nodoc:
+ alias :has_rdoc? :has_rdoc # :nodoc:
rubygems_deprecate :has_rdoc?
##
@@ -2025,7 +2007,7 @@ class Gem::Specification < Gem::BasicSpecification
end
# :stopdoc:
- alias_method :has_test_suite?, :has_unit_tests?
+ alias has_test_suite? has_unit_tests?
# :startdoc:
def hash # :nodoc:
@@ -2272,22 +2254,23 @@ class Gem::Specification < Gem::BasicSpecification
attributes.unshift :name
attributes.each do |attr_name|
- current_value = send attr_name
- current_value = current_value.sort if [:files, :test_files].include? attr_name
- next unless current_value != default_value(attr_name) ||
- self.class.required_attribute?(attr_name)
+ current_value = self.send attr_name
+ current_value = current_value.sort if %i[files test_files].include? attr_name
+ if current_value != default_value(attr_name) ||
+ self.class.required_attribute?(attr_name)
- q.text "s.#{attr_name} = "
+ q.text "s.#{attr_name} = "
- if attr_name == :date
- current_value = current_value.utc
+ if attr_name == :date
+ current_value = current_value.utc
- q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
- else
- q.pp current_value
- end
+ q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
+ else
+ q.pp current_value
+ end
- q.breakable
+ q.breakable
+ end
end
end
end
@@ -2297,7 +2280,7 @@ class Gem::Specification < Gem::BasicSpecification
# that is already loaded (+other+)
def check_version_conflict(other) # :nodoc:
- return if version == other.version
+ return if self.version == other.version
# This gem is already loaded. If the currently loaded gem is not in the
# list of candidate gems, then we have a version conflict.
@@ -2305,7 +2288,7 @@ class Gem::Specification < Gem::BasicSpecification
msg = "can't activate #{full_name}, already activated #{other.full_name}"
e = Gem::LoadError.new msg
- e.name = name
+ e.name = self.name
raise e
end
@@ -2370,13 +2353,13 @@ class Gem::Specification < Gem::BasicSpecification
when Array then "[" + obj.map {|x| ruby_code x }.join(", ") + "]"
when Hash then
seg = obj.keys.sort.map {|k| "#{k.to_s.dump} => #{obj[k].to_s.dump}" }
- "{ #{seg.join(", ")} }"
- when Gem::Version then ruby_code(obj.to_s)
+ "{ #{seg.join(', ')} }"
+ when Gem::Version then obj.to_s.dump
when DateLike then obj.strftime("%Y-%m-%d").dump
when Time then obj.strftime("%Y-%m-%d").dump
when Numeric then obj.inspect
when true, false, nil then obj.inspect
- when Gem::Platform then "Gem::Platform.new(#{ruby_code obj.to_a})"
+ when Gem::Platform then "Gem::Platform.new(#{obj.to_a.inspect})"
when Gem::Requirement then
list = obj.as_list
"Gem::Requirement.new(#{ruby_code(list.size == 1 ? obj.to_s : list)})"
@@ -2397,7 +2380,7 @@ class Gem::Specification < Gem::BasicSpecification
# True if this gem has the same attributes as +other+.
def same_attributes?(spec)
- @@attributes.all? {|name, _default| send(name) == spec.send(name) }
+ @@attributes.all? {|name, default| self.send(name) == spec.send(name) }
end
private :same_attributes?
@@ -2406,8 +2389,8 @@ class Gem::Specification < Gem::BasicSpecification
# Checks if this specification meets the requirement of +dependency+.
def satisfies_requirement?(dependency)
- @name == dependency.name &&
- dependency.requirement.satisfied_by?(@version)
+ return @name == dependency.name &&
+ dependency.requirement.satisfied_by?(@version)
end
##
@@ -2534,19 +2517,19 @@ class Gem::Specification < Gem::BasicSpecification
@@attributes.each do |attr_name|
next if handled.include? attr_name
- current_value = send(attr_name)
+ current_value = self.send(attr_name)
if current_value != default_value(attr_name) || self.class.required_attribute?(attr_name)
result << " s.#{attr_name} = #{ruby_code current_value}"
end
end
if String === signing_key
- result << " s.signing_key = #{ruby_code signing_key}"
+ result << " s.signing_key = #{signing_key.dump}.freeze"
end
if @installed_by_version
result << nil
- result << " s.installed_by_version = #{ruby_code Gem::VERSION} if s.respond_to? :installed_by_version"
+ result << " s.installed_by_version = \"#{Gem::VERSION}\" if s.respond_to? :installed_by_version"
end
unless dependencies.empty?
@@ -2555,8 +2538,9 @@ class Gem::Specification < Gem::BasicSpecification
result << nil
dependencies.each do |dep|
+ req = dep.requirements_list.inspect
dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
- result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>.freeze, #{ruby_code dep.requirements_list})"
+ result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>.freeze, #{req})"
end
end
@@ -2617,9 +2601,10 @@ class Gem::Specification < Gem::BasicSpecification
def traverse(trail = [], visited = {}, &block)
trail.push(self)
begin
- runtime_dependencies.each do |dep|
+ dependencies.each do |dep|
+ next unless dep.runtime?
dep.matching_specs(true).each do |dep_spec|
- next if visited.key?(dep_spec)
+ next if visited.has_key?(dep_spec)
visited[dep_spec] = true
trail.push(dep_spec)
begin
@@ -2627,10 +2612,11 @@ class Gem::Specification < Gem::BasicSpecification
ensure
trail.pop
end
- next if result == :next
- spec_name = dep_spec.name
- dep_spec.traverse(trail, visited, &block) unless
- trail.any? {|s| s.name == spec_name }
+ unless result == :next
+ spec_name = dep_spec.name
+ dep_spec.traverse(trail, visited, &block) unless
+ trail.any? {|s| s.name == spec_name }
+ end
end
end
ensure
@@ -2691,6 +2677,8 @@ class Gem::Specification < Gem::BasicSpecification
self.required_rubygems_version = "> 1.3.1"
end
invalidate_memoized_attributes
+
+ return @version
end
def stubbed?
@@ -2721,11 +2709,11 @@ class Gem::Specification < Gem::BasicSpecification
end
nil_attributes.each do |attribute|
- default = default_value attribute
+ default = self.default_value attribute
value = case default
- when Time, Numeric, Symbol, true, false, nil then default
- else default.dup
+ when Time, Numeric, Symbol, true, false, nil then default
+ else default.dup
end
instance_variable_set "@#{attribute}", value
diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb
index c43f6d963a..cee7eb3fdc 100644
--- a/lib/rubygems/specification_policy.rb
+++ b/lib/rubygems/specification_policy.rb
@@ -127,7 +127,7 @@ class Gem::SpecificationPolicy
metadata.each do |key, value|
entry = "metadata['#{key}']"
- unless key.is_a?(String)
+ if !key.kind_of?(String)
error "metadata keys must be a String"
end
@@ -135,7 +135,7 @@ class Gem::SpecificationPolicy
error "metadata key is too large (#{key.size} > 128)"
end
- unless value.is_a?(String)
+ if !value.kind_of?(String)
error "#{entry} value must be a String"
end
@@ -143,9 +143,10 @@ class Gem::SpecificationPolicy
error "#{entry} value is too large (#{value.size} > 1024)"
end
- next unless METADATA_LINK_KEYS.include? key
- unless VALID_URI_PATTERN.match?(value)
- error "#{entry} has invalid link: #{value.inspect}"
+ if METADATA_LINK_KEYS.include? key
+ if value !~ VALID_URI_PATTERN
+ error "#{entry} has invalid link: #{value.inspect}"
+ end
end
end
end
@@ -162,7 +163,7 @@ class Gem::SpecificationPolicy
if prev = seen[dep.type][dep.name]
error_messages << <<-MESSAGE
duplicate dependency on #{dep}, (#{prev.requirement}) use:
- add_#{dep.type}_dependency \"#{dep.name}\", \"#{dep.requirement}\", \"#{prev.requirement}\"
+ add_#{dep.type}_dependency '#{dep.name}', '#{dep.requirement}', '#{prev.requirement}'
MESSAGE
end
@@ -194,30 +195,31 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
prerelease_dep && !@specification.version.prerelease?
open_ended = dep.requirement.requirements.all? do |op, version|
- !version.prerelease? && [">", ">="].include?(op)
+ !version.prerelease? && (op == ">" || op == ">=")
end
- next unless open_ended
- op, dep_version = dep.requirement.requirements.first
+ if open_ended
+ op, dep_version = dep.requirement.requirements.first
- segments = dep_version.segments
+ segments = dep_version.segments
- base = segments.first 2
+ base = segments.first 2
- recommendation = if [">", ">="].include?(op) && segments == [0]
- " use a bounded requirement, such as \"~> x.y\""
- else
- bugfix = if op == ">"
- ", \"> #{dep_version}\""
- elsif op == ">=" && base != segments
- ", \">= #{dep_version}\""
+ recommendation = if (op == ">" || op == ">=") && segments == [0]
+ " use a bounded requirement, such as '~> x.y'"
+ else
+ bugfix = if op == ">"
+ ", '> #{dep_version}'"
+ elsif op == ">=" && base != segments
+ ", '>= #{dep_version}'"
+ end
+
+ " if #{dep.name} is semantically versioned, use:\n" \
+ " add_#{dep.type}_dependency '#{dep.name}', '~> #{base.join '.'}'#{bugfix}"
end
- " if #{dep.name} is semantically versioned, use:\n" \
- " add_#{dep.type}_dependency \"#{dep.name}\", \"~> #{base.join "."}\"#{bugfix}"
+ warning_messages << ["open-ended dependency on #{dep} is not recommended", recommendation].join("\n") + "\n"
end
-
- warning_messages << ["open-ended dependency on #{dep} is not recommended", recommendation].join("\n") + "\n"
end
if warning_messages.any?
warning_messages.each {|warning_message| warning warning_message }
@@ -234,7 +236,7 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
@specification.files.each do |file|
next unless File.file?(file)
- next if File.stat(file).mode & 0o444 == 0o444
+ next if File.stat(file).mode & 0444 == 0444
warning "#{file} is not world-readable"
end
@@ -253,7 +255,7 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
@specification.instance_variable_get("@#{attrname}").nil?
end
return if nil_attributes.empty?
- error "#{nil_attributes.join ", "} must not be nil"
+ error "#{nil_attributes.join ', '} must not be nil"
end
def validate_rubygems_version
@@ -279,11 +281,11 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
if !name.is_a?(String)
error "invalid value for attribute name: \"#{name.inspect}\" must be a string"
- elsif !/[a-zA-Z]/.match?(name)
+ elsif name !~ /[a-zA-Z]/
error "invalid value for attribute name: #{name.dump} must include at least one letter"
- elsif !VALID_NAME_PATTERN.match?(name)
+ elsif name !~ VALID_NAME_PATTERN
error "invalid value for attribute name: #{name.dump} can only include letters, numbers, dashes, and underscores"
- elsif SPECIAL_CHARACTERS.match?(name)
+ elsif name =~ SPECIAL_CHARACTERS
error "invalid value for attribute name: #{name.dump} can not begin with a period, dash, or underscore"
end
end
@@ -337,13 +339,13 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
def validate_array_attribute(field)
val = @specification.send(field)
klass = case field
- when :dependencies then
- Gem::Dependency
- else
- String
+ when :dependencies then
+ Gem::Dependency
+ else
+ String
end
- unless Array === val && val.all? {|x| x.is_a?(klass) || (field == :licenses && x.nil?) }
+ unless Array === val && val.all? {|x| x.kind_of?(klass) }
error "#{field} must be an Array of #{klass}"
end
end
@@ -358,8 +360,6 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
licenses = @specification.licenses
licenses.each do |license|
- next if license.nil?
-
if license.length > 64
error "each license must be 64 characters or less"
end
@@ -370,32 +370,20 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
licenses = @specification.licenses
licenses.each do |license|
- next if Gem::Licenses.match?(license) || license.nil?
- license_id_deprecated = Gem::Licenses.deprecated_license_id?(license)
- exception_id_deprecated = Gem::Licenses.deprecated_exception_id?(license)
- suggestions = Gem::Licenses.suggestions(license)
-
- if license_id_deprecated
- main_message = "License identifier '#{license}' is deprecated"
- elsif exception_id_deprecated
- main_message = "Exception identifier at '#{license}' is deprecated"
- else
- main_message = "License identifier '#{license}' is invalid"
+ if !Gem::Licenses.match?(license)
+ suggestions = Gem::Licenses.suggestions(license)
+ message = <<-WARNING
+license value '#{license}' is invalid. Use a license identifier from
+http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license.
+ WARNING
+ message += "Did you mean #{suggestions.map {|s| "'#{s}'" }.join(', ')}?\n" unless suggestions.nil?
+ warning(message)
end
-
- message = <<-WARNING
-#{main_message}. Use an identifier from
-https://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license,
-or set it to nil if you don't want to specify a license.
- WARNING
- message += "Did you mean #{suggestions.map {|s| "'#{s}'" }.join(", ")}?\n" unless suggestions.nil?
- warning(message)
end
warning <<-WARNING if licenses.empty?
-licenses is empty, but is recommended. Use an license identifier from
-https://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license,
-or set it to nil if you don't want to specify a license.
+licenses is empty, but is recommended. Use a license identifier from
+http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license.
WARNING
end
@@ -412,11 +400,11 @@ or set it to nil if you don't want to specify a license.
error "#{LAZY} is not an email"
end
- if LAZY_PATTERN.match?(@specification.description)
+ if @specification.description =~ LAZY_PATTERN
error "#{LAZY} is not a description"
end
- if LAZY_PATTERN.match?(@specification.summary)
+ if @specification.summary =~ LAZY_PATTERN
error "#{LAZY} is not a summary"
end
diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb
index 5953db0d64..d64d611f48 100644
--- a/lib/rubygems/stub_specification.rb
+++ b/lib/rubygems/stub_specification.rb
@@ -35,7 +35,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
def initialize(data, extensions)
parts = data[PREFIX.length..-1].split(" ", 4)
- @name = -parts[0]
+ @name = parts[0].freeze
@version = if Gem::Version.correct?(parts[1])
Gem::Version.new(parts[1])
else
@@ -85,10 +85,10 @@ class Gem::StubSpecification < Gem::BasicSpecification
def activated?
@activated ||=
- begin
- loaded = Gem.loaded_specs[name]
- loaded && loaded.version == version
- end
+ begin
+ loaded = Gem.loaded_specs[name]
+ loaded && loaded.version == version
+ end
end
def default_gem?
@@ -112,23 +112,20 @@ class Gem::StubSpecification < Gem::BasicSpecification
saved_lineno = $.
Gem.open_file loaded_from, OPEN_MODE do |file|
- file.readline # discard encoding line
- stubline = file.readline
- if stubline.start_with?(PREFIX)
- extline = file.readline
-
- extensions =
- if extline.delete_prefix!(PREFIX)
- extline.chomp!
- extline.split "\0"
+ begin
+ file.readline # discard encoding line
+ stubline = file.readline.chomp
+ if stubline.start_with?(PREFIX)
+ extensions = if /\A#{PREFIX}/ =~ file.readline.chomp
+ $'.split "\0"
else
StubLine::NO_EXTENSIONS
end
- stubline.chomp! # readline(chomp: true) allocates 3x as much as .readline.chomp!
- @data = StubLine.new stubline, extensions
+ @data = StubLine.new stubline, extensions
+ end
+ rescue EOFError
end
- rescue EOFError
end
ensure
$. = saved_lineno
diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb
index da0795b771..be811525f2 100644
--- a/lib/rubygems/text.rb
+++ b/lib/rubygems/text.rb
@@ -4,6 +4,7 @@
# A collection of text-wrangling methods
module Gem::Text
+
##
# Remove any non-printable characters and make the text suitable for
# printing.
@@ -66,7 +67,7 @@ module Gem::Text
str1.each_codepoint.with_index(1) do |char1, i|
j = 0
while j < m
- cost = char1 == str2_codepoints[j] ? 0 : 1
+ cost = (char1 == str2_codepoints[j]) ? 0 : 1
x = min3(
d[j + 1] + 1, # insertion
i + 1, # deletion
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index c96df2a085..f678f960f0 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -46,7 +46,7 @@ class Gem::Uninstaller
# Constructs an uninstaller that will uninstall +gem+
def initialize(gem, options = {})
- # TODO: document the valid options
+ # TODO document the valid options
@gem = gem
@version = options[:version] || Gem::Requirement.default
@gem_home = File.realpath(options[:install_dir] || Gem.dir)
@@ -99,7 +99,9 @@ class Gem::Uninstaller
raise Gem::InstallError, "gem #{@gem.inspect} is not installed"
end
- default_specs, list = list.partition(&:default_gem?)
+ default_specs, list = list.partition do |spec|
+ spec.default_gem?
+ end
warn_cannot_uninstall_default_gems(default_specs - list)
@default_specs_matching_uninstall_params = default_specs
@@ -113,7 +115,7 @@ class Gem::Uninstaller
if list.empty?
return unless other_repo_specs.any?
- other_repos = other_repo_specs.map(&:base_dir).uniq
+ other_repos = other_repo_specs.map {|spec| spec.base_dir }.uniq
message = ["#{@gem} is not installed in GEM_HOME, try:"]
message.concat other_repos.map {|repo|
@@ -125,7 +127,7 @@ class Gem::Uninstaller
remove_all list
elsif list.size > 1
- gem_names = list.map(&:full_name)
+ gem_names = list.map {|gem| gem.full_name }
gem_names << "All versions"
say
@@ -133,7 +135,7 @@ class Gem::Uninstaller
if index == list.size
remove_all list
- elsif index && index >= 0 && index < list.size
+ elsif index >= 0 && index < list.size
uninstall_gem list[index]
else
say "Error: must enter a number [1-#{list.size + 1}]"
@@ -199,8 +201,8 @@ class Gem::Uninstaller
executables = executables.map {|exec| formatted_program_filename exec }
remove = if @force_executables.nil?
- ask_yes_no("Remove executables:\n" \
- "\t#{executables.join ", "}\n\n" \
+ ask_yes_no("Remove executables:\n" +
+ "\t#{executables.join ', '}\n\n" +
"in addition to the gem?",
true)
else
@@ -241,7 +243,7 @@ class Gem::Uninstaller
unless path_ok?(@gem_home, spec) ||
(@user_install && path_ok?(Gem.user_dir, spec))
e = Gem::GemNotInHomeException.new \
- "Gem '#{spec.full_name}' is not installed in directory #{@gem_home}"
+ "Gem '#{spec.full_name}' is not installed in directory #{@gem_home}"
e.spec = spec
raise e
@@ -340,7 +342,7 @@ class Gem::Uninstaller
s.name == spec.name && s.full_name != spec.full_name
end
- spec.dependent_gems(@check_dev).each do |dep_spec, dep, _satlist|
+ spec.dependent_gems(@check_dev).each do |dep_spec, dep, satlist|
unless siblings.any? {|s| s.satisfies_requirement? dep }
msg << "#{dep_spec.name}-#{dep_spec.version} depends on #{dep}"
end
@@ -348,7 +350,7 @@ class Gem::Uninstaller
msg << "If you remove this gem, these dependencies will not be met."
msg << "Continue with Uninstall?"
- ask_yes_no(msg.join("\n"), false)
+ return ask_yes_no(msg.join("\n"), false)
end
##
diff --git a/lib/rubygems/update_suggestion.rb b/lib/rubygems/update_suggestion.rb
index af7067f9b3..c2e81b2374 100644
--- a/lib/rubygems/update_suggestion.rb
+++ b/lib/rubygems/update_suggestion.rb
@@ -28,9 +28,9 @@ Run `gem update --system #{Gem.latest_rubygems_version}` to update your installa
end
##
- # Determines if current environment is eligible for update suggestion.
+ # Determines if current environment is eglible for update suggestion.
- def eligible_for_update?
+ def eglible_for_update?
# explicit opt-out
return false if Gem.configuration[:prevent_update_suggestion]
return false if ENV["RUBYGEMS_PREVENT_UPDATE_SUGGESTION"]
@@ -53,13 +53,13 @@ Run `gem update --system #{Gem.latest_rubygems_version}` to update your installa
# compare current and latest version, this is the part where
# latest rubygems spec is fetched from remote
- (Gem.rubygems_version < Gem.latest_rubygems_version).tap do |eligible|
+ (Gem.rubygems_version < Gem.latest_rubygems_version).tap do |eglible|
# store the time of last successful check into state file
Gem.configuration.last_update_check = check_time
- return eligible
+ return eglible
end
- rescue StandardError # don't block install command on any problem
+ rescue # don't block install command on any problem
false
end
diff --git a/lib/rubygems/uri_formatter.rb b/lib/rubygems/uri_formatter.rb
index 517ce33637..3f1d02d774 100644
--- a/lib/rubygems/uri_formatter.rb
+++ b/lib/rubygems/uri_formatter.rb
@@ -34,7 +34,7 @@ class Gem::UriFormatter
# Normalize the URI by adding "http://" if it is missing.
def normalize
- /^(https?|ftp|file):/i.match?(@uri) ? @uri : "http://#{@uri}"
+ (@uri =~ /^(https?|ftp|file):/i) ? @uri : "http://#{@uri}"
end
##
diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb
index 1cee1555a0..451dba070f 100644
--- a/lib/rubygems/user_interaction.rb
+++ b/lib/rubygems/user_interaction.rb
@@ -14,6 +14,7 @@ require_relative "text"
# module will have access to the +ui+ method that returns the default UI.
module Gem::DefaultUserInteraction
+
include Gem::Text
##
@@ -68,6 +69,7 @@ module Gem::DefaultUserInteraction
def use_ui(new_ui, &block)
Gem::DefaultUserInteraction.use_ui(new_ui, &block)
end
+
end
##
@@ -90,6 +92,7 @@ end
# end
module Gem::UserInteraction
+
include Gem::DefaultUserInteraction
##
@@ -238,7 +241,7 @@ class Gem::StreamUI
result = result.strip.to_i - 1
return nil, nil unless (0...list.size) === result
- [list[result], result]
+ return list[result], result
end
##
@@ -257,32 +260,33 @@ class Gem::StreamUI
end
default_answer = case default
- when nil
- "yn"
- when true
- "Yn"
- else
- "yN"
+ when nil
+ "yn"
+ when true
+ "Yn"
+ else
+ "yN"
end
result = nil
while result.nil? do
result = case ask "#{question} [#{default_answer}]"
- when /^y/i then true
- when /^n/i then false
- when /^$/ then default
+ when /^y/i then true
+ when /^n/i then false
+ when /^$/ then default
+ else nil
end
end
- result
+ return result
end
##
# Ask a question. Returns an answer if connected to a tty, nil otherwise.
def ask(question)
- return nil unless tty?
+ return nil if !tty?
@outs.print(question + " ")
@outs.flush
@@ -296,7 +300,7 @@ class Gem::StreamUI
# Ask for a password. Does not echo response to terminal.
def ask_for_password(question)
- return nil unless tty?
+ return nil if !tty?
@outs.print(question, " ")
@outs.flush
@@ -426,7 +430,8 @@ class Gem::StreamUI
# +size+ items. Shows the given +initial_message+ when progress starts
# and the +terminal_message+ when it is complete.
- def initialize(out_stream, size, initial_message, terminal_message = "complete")
+ def initialize(out_stream, size, initial_message,
+ terminal_message = "complete")
@out = out_stream
@total = size
@count = 0
@@ -468,7 +473,8 @@ class Gem::StreamUI
# +size+ items. Shows the given +initial_message+ when progress starts
# and the +terminal_message+ when it is complete.
- def initialize(out_stream, size, initial_message, terminal_message = "complete")
+ def initialize(out_stream, size, initial_message,
+ terminal_message = "complete")
@out = out_stream
@total = size
@count = 0
diff --git a/lib/rubygems/util.rb b/lib/rubygems/util.rb
index 5c65dcc424..bd6ea92cc9 100644
--- a/lib/rubygems/util.rb
+++ b/lib/rubygems/util.rb
@@ -6,6 +6,7 @@ require_relative "deprecate"
# This module contains various utility methods as module methods.
module Gem::Util
+
##
# Zlib::GzipReader wrapper that unzips +data+.
@@ -84,11 +85,7 @@ module Gem::Util
here = File.expand_path directory
loop do
- begin
- Dir.chdir here, &block
- rescue StandardError
- Errno::EACCES
- end
+ Dir.chdir here, &block rescue Errno::EACCES
new_here = File.expand_path("..", here)
return if new_here == here # toplevel
@@ -115,4 +112,5 @@ module Gem::Util
path
end
end
+
end
diff --git a/lib/rubygems/util/licenses.rb b/lib/rubygems/util/licenses.rb
index 7dfeb2c697..1d5efde576 100644
--- a/lib/rubygems/util/licenses.rb
+++ b/lib/rubygems/util/licenses.rb
@@ -1,8 +1,5 @@
# frozen_string_literal: true
-# This is generated by generate_spdx_license_list.rb, any edits to this
-# file will be discarded.
-
require_relative "../text"
class Gem::Licenses
@@ -22,8 +19,10 @@ class Gem::Licenses
AFL-2.0
AFL-2.1
AFL-3.0
+ AGPL-1.0
AGPL-1.0-only
AGPL-1.0-or-later
+ AGPL-3.0
AGPL-3.0-only
AGPL-3.0-or-later
AMDPLPA
@@ -37,32 +36,27 @@ class Gem::Licenses
APSL-1.1
APSL-1.2
APSL-2.0
- ASWF-Digital-Assets-1.0
- ASWF-Digital-Assets-1.1
Abstyles
- AdaCore-doc
Adobe-2006
Adobe-Glyph
- Adobe-Utopia
Afmparse
Aladdin
Apache-1.0
Apache-1.1
Apache-2.0
- App-s2p
- Arphic-1999
Artistic-1.0
Artistic-1.0-Perl
Artistic-1.0-cl8
Artistic-2.0
BSD-1-Clause
BSD-2-Clause
+ BSD-2-Clause-FreeBSD
+ BSD-2-Clause-NetBSD
BSD-2-Clause-Patent
BSD-2-Clause-Views
BSD-3-Clause
BSD-3-Clause-Attribution
BSD-3-Clause-Clear
- BSD-3-Clause-HP
BSD-3-Clause-LBNL
BSD-3-Clause-Modification
BSD-3-Clause-No-Military-License
@@ -70,33 +64,20 @@ class Gem::Licenses
BSD-3-Clause-No-Nuclear-License-2014
BSD-3-Clause-No-Nuclear-Warranty
BSD-3-Clause-Open-MPI
- BSD-3-Clause-Sun
- BSD-3-Clause-flex
BSD-4-Clause
BSD-4-Clause-Shortened
BSD-4-Clause-UC
- BSD-4.3RENO
- BSD-4.3TAHOE
- BSD-Advertising-Acknowledgement
- BSD-Attribution-HPND-disclaimer
- BSD-Inferno-Nettverk
BSD-Protection
BSD-Source-Code
- BSD-Systemics
BSL-1.0
BUSL-1.1
- Baekmuk
Bahyph
Barr
Beerware
BitTorrent-1.0
BitTorrent-1.1
- Bitstream-Charter
- Bitstream-Vera
BlueOak-1.0.0
- Boehm-GC
Borceux
- Brian-Gladman-3-Clause
C-UDA-1.0
CAL-1.0
CAL-1.0-Combined-Work-Exception
@@ -104,42 +85,30 @@ class Gem::Licenses
CC-BY-1.0
CC-BY-2.0
CC-BY-2.5
- CC-BY-2.5-AU
CC-BY-3.0
CC-BY-3.0-AT
- CC-BY-3.0-DE
- CC-BY-3.0-IGO
- CC-BY-3.0-NL
CC-BY-3.0-US
CC-BY-4.0
CC-BY-NC-1.0
CC-BY-NC-2.0
CC-BY-NC-2.5
CC-BY-NC-3.0
- CC-BY-NC-3.0-DE
CC-BY-NC-4.0
CC-BY-NC-ND-1.0
CC-BY-NC-ND-2.0
CC-BY-NC-ND-2.5
CC-BY-NC-ND-3.0
- CC-BY-NC-ND-3.0-DE
CC-BY-NC-ND-3.0-IGO
CC-BY-NC-ND-4.0
CC-BY-NC-SA-1.0
CC-BY-NC-SA-2.0
- CC-BY-NC-SA-2.0-DE
- CC-BY-NC-SA-2.0-FR
- CC-BY-NC-SA-2.0-UK
CC-BY-NC-SA-2.5
CC-BY-NC-SA-3.0
- CC-BY-NC-SA-3.0-DE
- CC-BY-NC-SA-3.0-IGO
CC-BY-NC-SA-4.0
CC-BY-ND-1.0
CC-BY-ND-2.0
CC-BY-ND-2.5
CC-BY-ND-3.0
- CC-BY-ND-3.0-DE
CC-BY-ND-4.0
CC-BY-SA-1.0
CC-BY-SA-2.0
@@ -148,8 +117,6 @@ class Gem::Licenses
CC-BY-SA-2.5
CC-BY-SA-3.0
CC-BY-SA-3.0-AT
- CC-BY-SA-3.0-DE
- CC-BY-SA-3.0-IGO
CC-BY-SA-4.0
CC-PDDC
CC0-1.0
@@ -157,7 +124,6 @@ class Gem::Licenses
CDDL-1.1
CDL-1.0
CDLA-Permissive-1.0
- CDLA-Permissive-2.0
CDLA-Sharing-1.0
CECILL-1.0
CECILL-1.1
@@ -170,29 +136,20 @@ class Gem::Licenses
CERN-OHL-P-2.0
CERN-OHL-S-2.0
CERN-OHL-W-2.0
- CFITSIO
- CMU-Mach
CNRI-Jython
CNRI-Python
CNRI-Python-GPL-Compatible
- COIL-1.0
CPAL-1.0
CPL-1.0
CPOL-1.02
CUA-OPL-1.0
Caldera
ClArtistic
- Clips
- Community-Spec-1.0
Condor-1.1
- Cornell-Lossless-JPEG
- Cronyx
Crossword
CrystalStacker
Cube
D-FSL-1.0
- DL-DE-BY-2.0
- DL-DE-ZERO-2.0
DOC
DRL-1.0
DSDP
@@ -208,36 +165,33 @@ class Gem::Licenses
EUPL-1.0
EUPL-1.1
EUPL-1.2
- Elastic-2.0
Entessa
ErlPL-1.1
Eurosym
- FBM
- FDK-AAC
FSFAP
FSFUL
FSFULLR
- FSFULLRWD
FTL
Fair
- Ferguson-Twofish
Frameworx-1.0
FreeBSD-DOC
FreeImage
- Furuseth
GD
+ GFDL-1.1
GFDL-1.1-invariants-only
GFDL-1.1-invariants-or-later
GFDL-1.1-no-invariants-only
GFDL-1.1-no-invariants-or-later
GFDL-1.1-only
GFDL-1.1-or-later
+ GFDL-1.2
GFDL-1.2-invariants-only
GFDL-1.2-invariants-or-later
GFDL-1.2-no-invariants-only
GFDL-1.2-no-invariants-or-later
GFDL-1.2-only
GFDL-1.2-or-later
+ GFDL-1.3
GFDL-1.3-invariants-only
GFDL-1.3-invariants-or-later
GFDL-1.3-no-invariants-only
@@ -246,66 +200,63 @@ class Gem::Licenses
GFDL-1.3-or-later
GL2PS
GLWTPL
+ GPL-1.0
+ GPL-1.0+
GPL-1.0-only
GPL-1.0-or-later
+ GPL-2.0
+ GPL-2.0+
GPL-2.0-only
GPL-2.0-or-later
+ GPL-2.0-with-GCC-exception
+ GPL-2.0-with-autoconf-exception
+ GPL-2.0-with-bison-exception
+ GPL-2.0-with-classpath-exception
+ GPL-2.0-with-font-exception
+ GPL-3.0
+ GPL-3.0+
GPL-3.0-only
GPL-3.0-or-later
+ GPL-3.0-with-GCC-exception
+ GPL-3.0-with-autoconf-exception
Giftware
Glide
Glulxe
- Graphics-Gems
- HP-1986
- HP-1989
HPND
- HPND-DEC
- HPND-Markus-Kuhn
- HPND-Pbmplus
- HPND-UC
- HPND-doc
- HPND-doc-sell
- HPND-export-US
- HPND-export-US-modify
- HPND-sell-regexpr
HPND-sell-variant
- HPND-sell-variant-MIT-disclaimer
HTMLTIDY
HaskellReport
Hippocratic-2.1
IBM-pibs
ICU
- IEC-Code-Components-EULA
IJG
- IJG-short
IPA
IPL-1.0
ISC
ImageMagick
Imlib2
Info-ZIP
- Inner-Net-2.0
Intel
Intel-ACPI
Interbase-1.0
- JPL-image
JPNIC
JSON
- Jam
JasPer-2.0
- Kastrup
- Kazlib
- Knuth-CTAN
LAL-1.2
LAL-1.3
+ LGPL-2.0
+ LGPL-2.0+
LGPL-2.0-only
LGPL-2.0-or-later
+ LGPL-2.1
+ LGPL-2.1+
LGPL-2.1-only
LGPL-2.1-or-later
+ LGPL-3.0
+ LGPL-3.0+
LGPL-3.0-only
LGPL-3.0-or-later
LGPLLR
- LOOP
LPL-1.0
LPL-1.02
LPPL-1.0
@@ -313,47 +264,30 @@ class Gem::Licenses
LPPL-1.2
LPPL-1.3a
LPPL-1.3c
- LZMA-SDK-9.11-to-9.20
- LZMA-SDK-9.22
Latex2e
- Latex2e-translated-notice
Leptonica
LiLiQ-P-1.1
LiLiQ-R-1.1
LiLiQ-Rplus-1.1
Libpng
Linux-OpenIB
- Linux-man-pages-1-para
- Linux-man-pages-copyleft
- Linux-man-pages-copyleft-2-para
- Linux-man-pages-copyleft-var
- Lucida-Bitmap-Fonts
MIT
MIT-0
MIT-CMU
- MIT-Festival
MIT-Modern-Variant
- MIT-Wu
MIT-advertising
MIT-enna
MIT-feh
MIT-open-group
- MIT-testregex
MITNFA
- MMIXware
- MPEG-SSG
MPL-1.0
MPL-1.1
MPL-2.0
MPL-2.0-no-copyleft-exception
- MS-LPL
MS-PL
MS-RL
MTLL
MakeIndex
- Martin-Birgmeier
- McPhee-slideshow
- Minpack
MirOS
Motosoto
MulanPSL-1.0
@@ -366,12 +300,9 @@ class Gem::Licenses
NCGL-UK-2.0
NCSA
NGPL
- NICTA-1.0
NIST-PD
NIST-PD-fallback
- NIST-Software
NLOD-1.0
- NLOD-2.0
NLPL
NOSL
NPL-1.0
@@ -386,12 +317,12 @@ class Gem::Licenses
Newsletr
Nokia
Noweb
+ Nunit
O-UDA-1.0
OCCT-PL
OCLC-2.0
ODC-By-1.0
ODbL-1.0
- OFFIS
OFL-1.0
OFL-1.0-RFN
OFL-1.0-no-RFN
@@ -421,20 +352,15 @@ class Gem::Licenses
OLDAP-2.6
OLDAP-2.7
OLDAP-2.8
- OLFL-1.3
OML
OPL-1.0
- OPL-UK-3.0
- OPUBL-1.0
OSET-PL-2.1
OSL-1.0
OSL-1.1
OSL-2.0
OSL-2.1
OSL-3.0
- OpenPBS-2.3
OpenSSL
- PADL
PDDL-1.0
PHP-3.0
PHP-3.01
@@ -446,9 +372,7 @@ class Gem::Licenses
PolyForm-Small-Business-1.0.0
PostgreSQL
Python-2.0
- Python-2.0.1
QPL-1.0
- QPL-1.0-INRIA-2004
Qhull
RHeCos-1.1
RPL-1.1
@@ -463,13 +387,10 @@ class Gem::Licenses
SGI-B-1.0
SGI-B-1.1
SGI-B-2.0
- SGI-OpenGL
- SGP4
SHL-0.5
SHL-0.51
SISSL
SISSL-1.2
- SL
SMLNJ
SMPPL
SNIA
@@ -479,39 +400,28 @@ class Gem::Licenses
SSPL-1.0
SWL
Saxpath
- SchemeReport
Sendmail
Sendmail-8.23
SimPL-2.0
Sleepycat
- Soundex
Spencer-86
Spencer-94
Spencer-99
+ StandardML-NJ
SugarCRM-1.1.3
- SunPro
- Symlinks
TAPR-OHL-1.0
TCL
TCP-wrappers
TMate
TORQUE-1.1
TOSL
- TPDL
- TPL-1.0
- TTWL
- TTYP0
TU-Berlin-1.0
TU-Berlin-2.0
- TermReadKey
- UCAR
UCL-1.0
UPL-1.0
- URT-RLE
Unicode-DFS-2015
Unicode-DFS-2016
Unicode-TOU
- UnixCrypt
Unlicense
VOSTROM
VSL-1.0
@@ -521,15 +431,11 @@ class Gem::Licenses
W3C-20150513
WTFPL
Watcom-1.0
- Widget-Workshop
Wsuipa
X11
- X11-distribute-modifications-variant
XFree86-1.1
XSkat
- Xdebug-1.03
Xerox
- Xfig
Xnet
YPL-1.0
YPL-1.1
@@ -537,95 +443,41 @@ class Gem::Licenses
ZPL-2.0
ZPL-2.1
Zed
- Zeeff
Zend-2.0
Zimbra-1.3
Zimbra-1.4
Zlib
blessing
+ bzip2-1.0.5
bzip2-1.0.6
- check-cvs
- checkmk
copyleft-next-0.3.0
copyleft-next-0.3.1
curl
diffmark
- dtoa
dvipdfm
+ eCos-2.0
eGenix
etalab-2.0
- fwlw
gSOAP-1.3b
gnuplot
iMatix
libpng-2.0
libselinux-1.0
libtiff
- libutil-David-Nugent
- lsof
- magaz
- metamail
- mpi-permissive
mpich2
- mplus
- pnmstitch
psfrag
psutils
- python-ldap
- snprintf
- ssh-keyscan
- swrule
- ulem
- w3m
+ wxWindows
xinetd
- xlock
xpp
zlib-acknowledgement
].freeze
- DEPRECATED_LICENSE_IDENTIFIERS = %w[
- AGPL-1.0
- AGPL-3.0
- BSD-2-Clause-FreeBSD
- BSD-2-Clause-NetBSD
- GFDL-1.1
- GFDL-1.2
- GFDL-1.3
- GPL-1.0
- GPL-1.0+
- GPL-2.0
- GPL-2.0+
- GPL-2.0-with-GCC-exception
- GPL-2.0-with-autoconf-exception
- GPL-2.0-with-bison-exception
- GPL-2.0-with-classpath-exception
- GPL-2.0-with-font-exception
- GPL-3.0
- GPL-3.0+
- GPL-3.0-with-GCC-exception
- GPL-3.0-with-autoconf-exception
- LGPL-2.0
- LGPL-2.0+
- LGPL-2.1
- LGPL-2.1+
- LGPL-3.0
- LGPL-3.0+
- Nunit
- StandardML-NJ
- bzip2-1.0.5
- eCos-2.0
- wxWindows
- ].freeze
-
# exception identifiers
EXCEPTION_IDENTIFIERS = %w[
389-exception
- Asterisk-exception
Autoconf-exception-2.0
Autoconf-exception-3.0
- Autoconf-exception-generic
- Autoconf-exception-generic-3.0
- Autoconf-exception-macro
Bison-exception-2.2
Bootloader-exception
CLISP-exception-2.0
@@ -635,59 +487,38 @@ class Gem::Licenses
Fawkes-Runtime-exception
Font-exception-2.0
GCC-exception-2.0
- GCC-exception-2.0-note
GCC-exception-3.1
- GNAT-exception
- GNU-compiler-exception
- GPL-3.0-interface-exception
GPL-3.0-linking-exception
GPL-3.0-linking-source-exception
GPL-CC-1.0
- GStreamer-exception-2005
- GStreamer-exception-2008
- KiCad-libraries-exception
LGPL-3.0-linking-exception
- LLGPL
LLVM-exception
LZMA-exception
Libtool-exception
Linux-syscall-note
+ Nokia-Qt-exception-1.1
OCCT-exception-1.0
OCaml-LGPL-linking-exception
OpenJDK-assembly-exception-1.0
PS-or-PDF-font-exception-20170817
- QPL-1.0-INRIA-2004-exception
Qt-GPL-exception-1.0
Qt-LGPL-exception-1.1
Qwt-exception-1.0
- SANE-exception
SHL-2.0
SHL-2.1
- SWI-exception
Swift-exception
- Texinfo-exception
- UBDL-exception
Universal-FOSS-exception-1.0
WxWindows-exception-3.1
- cryptsetup-OpenSSL-exception
eCos-exception-2.0
freertos-exception-2.0
gnu-javamail-exception
i2p-gpl-java-exception
- libpri-OpenH323-exception
mif-exception
openvpn-openssl-exception
- stunnel-exception
u-boot-exception-2.0
- vsftpd-openssl-exception
- x11vnc-openssl-exception
].freeze
- DEPRECATED_EXCEPTION_IDENTIFIERS = %w[
- Nokia-Qt-exception-1.1
- ].freeze
-
- VALID_REGEXP = /
+ REGEXP = %r{
\A
(?:
#{Regexp.union(LICENSE_IDENTIFIERS)}
@@ -697,34 +528,10 @@ class Gem::Licenses
| #{LICENSE_REF}
)
\Z
- /ox.freeze
-
- DEPRECATED_LICENSE_REGEXP = /
- \A
- #{Regexp.union(DEPRECATED_LICENSE_IDENTIFIERS)}
- \+?
- (?:\s WITH \s .+?)?
- \Z
- /ox.freeze
-
- DEPRECATED_EXCEPTION_REGEXP = /
- \A
- .+?
- \+?
- (?:\s WITH \s #{Regexp.union(DEPRECATED_EXCEPTION_IDENTIFIERS)})
- \Z
- /ox.freeze
+ }ox.freeze
def self.match?(license)
- VALID_REGEXP.match?(license)
- end
-
- def self.deprecated_license_id?(license)
- DEPRECATED_LICENSE_REGEXP.match?(license)
- end
-
- def self.deprecated_exception_id?(license)
- DEPRECATED_EXCEPTION_REGEXP.match?(license)
+ !REGEXP.match(license).nil?
end
def self.suggestions(license)
diff --git a/lib/rubygems/util/list.rb b/lib/rubygems/util/list.rb
index 2899e8a2b9..acb6c73ddb 100644
--- a/lib/rubygems/util/list.rb
+++ b/lib/rubygems/util/list.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module Gem
- # The Gem::List class is currently unused and will be removed in the next major rubygems version
- class List # :nodoc:
+ class List
include Enumerable
attr_accessor :value, :tail
@@ -36,5 +35,4 @@ module Gem
List.new value, list
end
end
- deprecate_constant :List
end
diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb
index 57e0747eb4..63493638b6 100644
--- a/lib/rubygems/validator.rb
+++ b/lib/rubygems/validator.rb
@@ -25,7 +25,7 @@ class Gem::Validator
installed_files = []
Find.find gem_directory do |file_name|
- fn = file_name[gem_directory.size..file_name.size - 1].sub(%r{^/}, "")
+ fn = file_name[gem_directory.size..file_name.size - 1].sub(/^\//, "")
installed_files << fn unless
fn.empty? || fn.include?("CVS") || File.directory?(file_name)
end
@@ -63,9 +63,7 @@ class Gem::Validator
errors = Hash.new {|h,k| h[k] = {} }
Gem::Specification.each do |spec|
- unless gems.empty?
- next unless gems.include? spec.name
- end
+ next unless gems.include? spec.name unless gems.empty?
next if spec.default_gem?
gem_name = spec.file_name
@@ -90,7 +88,7 @@ class Gem::Validator
good, gone, unreadable = nil, nil, nil, nil
- File.open gem_path, Gem.binary_mode do |_file|
+ File.open gem_path, Gem.binary_mode do |file|
package = Gem::Package.new gem_path
good, gone = package.contents.partition do |file_name|
@@ -110,13 +108,15 @@ class Gem::Validator
end
good.each do |entry, data|
- next unless data # HACK: `gem check -a mkrf`
+ begin
+ next unless data # HACK `gem check -a mkrf`
- source = File.join gem_directory, entry["path"]
+ source = File.join gem_directory, entry["path"]
- File.open source, Gem.binary_mode do |f|
- unless f.read == data
- errors[gem_name][entry["path"]] = "Modified from original"
+ File.open source, Gem.binary_mode do |f|
+ unless f.read == data
+ errors[gem_name][entry["path"]] = "Modified from original"
+ end
end
end
end
diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb
index 828a4ca1e0..c319e1f820 100644
--- a/lib/rubygems/version.rb
+++ b/lib/rubygems/version.rb
@@ -131,7 +131,7 @@ require_relative "deprecate"
#
# == Preventing Version Catastrophe:
#
-# From: https://www.zenspider.com/ruby/2008/10/rubygems-how-to-preventing-catastrophe.html
+# From: http://blog.zenspider.com/2008/10/rubygems-howto-preventing-cata.html
#
# Let's say you're depending on the fnord gem version 2.y.z. If you
# specify your dependency as ">= 2.0.0" then, you're good, right? What
@@ -162,10 +162,10 @@ class Gem::Version
# A string representation of this Version.
def version
- @version
+ @version.dup
end
- alias_method :to_s, :version
+ alias to_s version
##
# True if the +version+ string matches RubyGems' requirements.
@@ -173,7 +173,7 @@ class Gem::Version
def self.correct?(version)
nil_versions_are_discouraged! if version.nil?
- ANCHORED_VERSION_PATTERN.match?(version.to_s)
+ !!(version.to_s =~ ANCHORED_VERSION_PATTERN)
end
##
@@ -201,7 +201,7 @@ class Gem::Version
@@release = {}
def self.new(version) # :nodoc:
- return super unless self == Gem::Version
+ return super unless Gem::Version == self
@@all[version] ||= super
end
@@ -224,17 +224,9 @@ class Gem::Version
end
# If version is an empty string convert it to 0
- version = 0 if version.is_a?(String) && /\A\s*\Z/.match?(version)
-
- @version = version.to_s
+ version = 0 if version.is_a?(String) && version =~ /\A\s*\Z/
- # optimization to avoid allocation when given an integer, since we know
- # it's to_s won't have any spaces or dashes
- unless version.is_a?(Integer)
- @version = @version.strip
- @version.gsub!("-",".pre.")
- end
- @version = -@version
+ @version = version.to_s.strip.gsub("-",".pre.")
@segments = nil
end
@@ -260,7 +252,7 @@ class Gem::Version
# same precision. Version "1.0" is not the same as version "1".
def eql?(other)
- self.class === other && @version == other.version
+ self.class === other && @version == other._version
end
def hash # :nodoc:
@@ -292,7 +284,7 @@ class Gem::Version
end
def yaml_initialize(tag, map) # :nodoc:
- @version = -map["version"]
+ @version = map["version"]
@segments = nil
@hash = nil
end
@@ -310,7 +302,7 @@ class Gem::Version
def prerelease?
unless instance_variable_defined? :@prerelease
- @prerelease = /[a-zA-Z]/.match?(version)
+ @prerelease = !!(@version =~ /[a-zA-Z]/)
end
@prerelease
end
@@ -362,7 +354,7 @@ class Gem::Version
return self <=> self.class.new(other) if (String === other) && self.class.correct?(other)
return unless Gem::Version === other
- return 0 if @version == other.version || canonical_segments == other.canonical_segments
+ return 0 if @version == other._version || canonical_segments == other.canonical_segments
lhsegments = canonical_segments
rhsegments = other.canonical_segments
@@ -374,8 +366,7 @@ class Gem::Version
i = 0
while i <= limit
- lhs = lhsegments[i] || 0
- rhs = rhsegments[i] || 0
+ lhs, rhs = lhsegments[i] || 0, rhsegments[i] || 0
i += 1
next if lhs == rhs
@@ -385,40 +376,42 @@ class Gem::Version
return lhs <=> rhs
end
- 0
+ return 0
end
- # remove trailing zeros segments before first letter or at the end of the version
def canonical_segments
- @canonical_segments ||= begin
- # remove trailing 0 segments, using dot or letter as anchor
- # may leave a trailing dot which will be ignored by partition_segments
- canonical_version = @version.sub(/(?<=[a-zA-Z.])[.0]+\z/, "")
- # remove 0 segments before the first letter in a prerelease version
- canonical_version.sub!(/(?<=\.|\A)[0.]+(?=[a-zA-Z])/, "") if prerelease?
- partition_segments(canonical_version)
- end
+ @canonical_segments ||=
+ _split_segments.map! do |segments|
+ segments.reverse_each.drop_while {|s| s == 0 }.reverse
+ end.reduce(&:concat)
end
def freeze
prerelease?
- _segments
canonical_segments
super
end
protected
+ def _version
+ @version
+ end
+
def _segments
# segments is lazy so it can pick up version values that come from
# old marshaled versions, which don't go through marshal_load.
# since this version object is cached in @@all, its @segments should be frozen
- @segments ||= partition_segments(@version)
- end
- def partition_segments(ver)
- ver.scan(/\d+|[a-z]+/i).map! do |s|
- /\A\d/.match?(s) ? s.to_i : -s
+ @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
+ /^\d+$/ =~ s ? s.to_i : s
end.freeze
end
+
+ def _split_segments
+ string_start = _segments.index {|s| s.is_a?(String) }
+ string_segments = segments
+ numeric_segments = string_segments.slice!(0, string_start || string_segments.size)
+ return numeric_segments, string_segments
+ end
end
diff --git a/lib/rubygems/version_option.rb b/lib/rubygems/version_option.rb
index 7910fd3d1b..d83a69cf0d 100644
--- a/lib/rubygems/version_option.rb
+++ b/lib/rubygems/version_option.rb
@@ -12,6 +12,7 @@ require_relative "../rubygems"
# Mixin methods for --version and --platform Gem::Command options.
module Gem::VersionOption
+
##
# Add the --platform option to the option parser.
@@ -25,7 +26,8 @@ module Gem::VersionOption
end
add_option("--platform PLATFORM", Gem::Platform,
- "Specify the platform of gem to #{task}", *wrap) do |value, options|
+ "Specify the platform of gem to #{task}", *wrap) do
+ |value, options|
unless options[:added_platform]
Gem.platforms = [Gem::Platform::RUBY]
options[:added_platform] = true
@@ -55,7 +57,8 @@ module Gem::VersionOption
end
add_option("-v", "--version VERSION", Gem::Requirement,
- "Specify version of gem to #{task}", *wrap) do |value, options|
+ "Specify version of gem to #{task}", *wrap) do
+ |value, options|
# Allow handling for multiple --version operators
if options[:version] && !options[:version].none?
options[:version].concat([value])
diff --git a/lib/rubygems/yaml_serializer.rb b/lib/rubygems/yaml_serializer.rb
deleted file mode 100644
index 209bc4718b..0000000000
--- a/lib/rubygems/yaml_serializer.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- # A stub yaml serializer that can handle only hashes and strings (as of now).
- module YAMLSerializer
- module_function
-
- def dump(hash)
- yaml = String.new("---")
- yaml << dump_hash(hash)
- end
-
- def dump_hash(hash)
- yaml = String.new("\n")
- hash.each do |k, v|
- yaml << k << ":"
- if v.is_a?(Hash)
- yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines
- elsif v.is_a?(Array) # Expected to be array of strings
- if v.empty?
- yaml << " []\n"
- else
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
- end
- else
- yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
- end
- end
- yaml
- end
-
- ARRAY_REGEX = /
- ^
- (?:[ ]*-[ ]) # '- ' before array items
- (['"]?) # optional opening quote
- (.*) # value
- \1 # matching closing quote
- $
- /xo.freeze
-
- HASH_REGEX = /
- ^
- ([ ]*) # indentations
- (.+) # key
- (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value)
- [ ]?
- (['"]?) # optional opening quote
- (.*) # value
- \3 # matching closing quote
- $
- /xo.freeze
-
- def load(str)
- res = {}
- stack = [res]
- last_hash = nil
- last_empty_key = nil
- str.split(/\r?\n/).each do |line|
- if match = HASH_REGEX.match(line)
- indent, key, quote, val = match.captures
- convert_to_backward_compatible_key!(key)
- depth = indent.size / 2
- if quote.empty? && val.empty?
- new_hash = {}
- stack[depth][key] = new_hash
- stack[depth + 1] = new_hash
- last_empty_key = key
- last_hash = stack[depth]
- else
- val = [] if val == "[]" # empty array
- stack[depth][key] = val
- end
- elsif match = ARRAY_REGEX.match(line)
- _, val = match.captures
- last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array)
-
- last_hash[last_empty_key].push(val)
- end
- end
- res
- end
-
- # for settings' keys
- def convert_to_backward_compatible_key!(key)
- key << "/" if /https?:/i.match?(key) && !%r{/\Z}.match?(key)
- key.gsub!(".", "__")
- end
-
- class << self
- private :dump_hash, :convert_to_backward_compatible_key!
- end
- end
-end
diff --git a/lib/securerandom.gemspec b/lib/securerandom.gemspec
index f42ddbcc97..e095244ce9 100644
--- a/lib/securerandom.gemspec
+++ b/lib/securerandom.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "securerandom"
+ spec.version = "0.2.2"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/securerandom.rb b/lib/securerandom.rb
index 9afd8a0716..07ae048634 100644
--- a/lib/securerandom.rb
+++ b/lib/securerandom.rb
@@ -39,9 +39,6 @@ require 'random/formatter'
# +NotImplementedError+ is raised.
module SecureRandom
-
- VERSION = "0.3.0"
-
class << self
def bytes(n)
return gen_random(n)
@@ -50,6 +47,17 @@ module SecureRandom
private
def gen_random_openssl(n)
+ @pid = 0 unless defined?(@pid)
+ pid = $$
+ unless @pid == pid
+ now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
+ OpenSSL::Random.random_add([now, @pid, pid].join(""), 0.0)
+ seed = Random.urandom(16)
+ if (seed)
+ OpenSSL::Random.random_add(seed, 16)
+ end
+ @pid = pid
+ end
return OpenSSL::Random.random_bytes(n)
end
diff --git a/lib/set.rb b/lib/set.rb
index 5ac37dbf3c..df1e68d081 100644
--- a/lib/set.rb
+++ b/lib/set.rb
@@ -12,12 +12,16 @@
##
-# This library provides the Set class, which implements a collection
-# of unordered values with no duplicates. It is a hybrid of Array's
+# This library provides the Set class, which deals with a collection
+# of unordered values with no duplicates. It is a hybrid of Array's
# intuitive inter-operation facilities and Hash's fast lookup.
#
# The method `to_set` is added to Enumerable for convenience.
#
+# Set implements a collection of unordered values with no duplicates.
+# This is a hybrid of Array's intuitive inter-operation facilities and
+# Hash's fast lookup.
+#
# Set is easy to use with Enumerable objects (implementing `each`).
# Most of the initializer methods and binary operators accept generic
# Enumerable objects besides sets and arrays. An Enumerable object
@@ -152,7 +156,7 @@
# If the given object is not an element in the set,
# adds it and returns +self+; otherwise, returns +nil+.
# - \#merge:
-# Merges the elements of each given enumerable object to the set; returns +self+.
+# Adds each given object to the set; returns +self+.
# - \#replace:
# Replaces the contents of the set with the contents
# of a given enumerable.
@@ -216,8 +220,6 @@
# has been modified while an element in the set.
#
class Set
- VERSION = "1.0.3"
-
include Enumerable
# Creates a new set containing the given objects.
@@ -505,7 +507,7 @@ class Set
# the element as parameter. Returns an enumerator if no block is
# given.
def each(&block)
- block_given? or return enum_for(__method__) { size }
+ block or return enum_for(__method__) { size }
@hash.each_key(&block)
self
end
@@ -580,7 +582,7 @@ class Set
# Equivalent to Set#delete_if, but returns nil if no changes were
# made. Returns an enumerator if no block is given.
def reject!(&block)
- block_given? or return enum_for(__method__) { size }
+ block or return enum_for(__method__) { size }
n = size
delete_if(&block)
self if size != n
@@ -589,7 +591,7 @@ class Set
# Equivalent to Set#keep_if, but returns nil if no changes were
# made. Returns an enumerator if no block is given.
def select!(&block)
- block_given? or return enum_for(__method__) { size }
+ block or return enum_for(__method__) { size }
n = size
keep_if(&block)
self if size != n
@@ -598,15 +600,13 @@ class Set
# Equivalent to Set#select!
alias filter! select!
- # Merges the elements of the given enumerable objects to the set and
+ # Merges the elements of the given enumerable object to the set and
# returns self.
- def merge(*enums, **nil)
- enums.each do |enum|
- if enum.instance_of?(self.class)
- @hash.update(enum.instance_variable_get(:@hash))
- else
- do_with_enum(enum) { |o| add(o) }
- end
+ def merge(enum)
+ if enum.instance_of?(self.class)
+ @hash.update(enum.instance_variable_get(:@hash))
+ else
+ do_with_enum(enum) { |o| add(o) }
end
self
diff --git a/lib/set/set.gemspec b/lib/set/set.gemspec
index c415fac99c..0def52e859 100644
--- a/lib/set/set.gemspec
+++ b/lib/set/set.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "set"
+ spec.version = "1.0.3"
spec.authors = ["Akinori MUSHA"]
spec.email = ["knu@idaemons.org"]
@@ -15,7 +8,7 @@ Gem::Specification.new do |spec|
spec.description = %q{Provides a class to deal with collections of unordered, unique values}
spec.homepage = "https://github.com/ruby/set"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
diff --git a/lib/shellwords.gemspec b/lib/shellwords.gemspec
index d60ab5f650..8ae87b230e 100644
--- a/lib/shellwords.gemspec
+++ b/lib/shellwords.gemspec
@@ -1,14 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "shellwords"
+ spec.version = "0.1.0"
spec.authors = ["Akinori MUSHA"]
spec.email = ["knu@idaemons.org"]
diff --git a/lib/shellwords.rb b/lib/shellwords.rb
index 067432e374..4368a53ea8 100644
--- a/lib/shellwords.rb
+++ b/lib/shellwords.rb
@@ -68,8 +68,6 @@
# 1: {IEEE Std 1003.1-2008, 2016 Edition, the Shell & Utilities volume}[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html]
module Shellwords
- VERSION = "0.2.0"
-
# Splits a string into an array of tokens in the same way the UNIX
# Bourne shell does.
#
diff --git a/lib/singleton.gemspec b/lib/singleton.gemspec
deleted file mode 100644
index 7646914905..0000000000
--- a/lib/singleton.gemspec
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{The Singleton module implements the Singleton pattern.}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/singleton"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-end
diff --git a/lib/singleton.rb b/lib/singleton.rb
index 6da939124e..07420d2ea2 100644
--- a/lib/singleton.rb
+++ b/lib/singleton.rb
@@ -92,7 +92,7 @@
# p a.strip # => nil
#
module Singleton
- VERSION = "0.2.0"
+ VERSION = "0.1.1"
# Raises a TypeError to prevent cloning.
def clone
@@ -121,7 +121,12 @@ module Singleton
end
def instance # :nodoc:
- @singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new }
+ return @singleton__instance__ if @singleton__instance__
+ @singleton__mutex__.synchronize {
+ return @singleton__instance__ if @singleton__instance__
+ @singleton__instance__ = new()
+ }
+ @singleton__instance__
end
private
diff --git a/lib/singleton/singleton.gemspec b/lib/singleton/singleton.gemspec
new file mode 100644
index 0000000000..88d3111b65
--- /dev/null
+++ b/lib/singleton/singleton.gemspec
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{The Singleton module implements the Singleton pattern.}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/singleton"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/syntax_suggest/core_ext.rb b/lib/syntax_suggest/core_ext.rb
index c299627bb7..e0fd62b81c 100644
--- a/lib/syntax_suggest/core_ext.rb
+++ b/lib/syntax_suggest/core_ext.rb
@@ -21,7 +21,7 @@ if SyntaxError.method_defined?(:detailed_message)
attr_reader :string
end
- # SyntaxSuggest.module_for_detailed_message [Private]
+ # SyntaxSuggest.record_dir [Private]
#
# Used to monkeypatch SyntaxError via Module.prepend
def self.module_for_detailed_message
diff --git a/lib/syntax_suggest/pathname_from_message.rb b/lib/syntax_suggest/pathname_from_message.rb
index ab90227427..b6fe1617be 100644
--- a/lib/syntax_suggest/pathname_from_message.rb
+++ b/lib/syntax_suggest/pathname_from_message.rb
@@ -13,7 +13,7 @@ module SyntaxSuggest
# # => "/tmp/scratch.rb"
#
class PathnameFromMessage
- EVAL_RE = /^\(eval.*\):\d+/
+ EVAL_RE = /^\(eval\):\d+/
STREAMING_RE = /^-:\d+/
attr_reader :name
diff --git a/lib/tempfile.gemspec b/lib/tempfile.gemspec
index a3cb11296d..acb26b68db 100644
--- a/lib/tempfile.gemspec
+++ b/lib/tempfile.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "tempfile"
+ spec.version = "0.1.3"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -23,7 +16,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.require_paths = ["lib"]
end
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
index 43174082a0..c3263ed3c6 100644
--- a/lib/tempfile.rb
+++ b/lib/tempfile.rb
@@ -57,7 +57,7 @@ require 'tmpdir'
# Note that Tempfile.create returns a File instance instead of a Tempfile, which
# also avoids the overhead and complications of delegation.
#
-# Tempfile.create('foo') do |file|
+# Tempfile.open('foo') do |file|
# # ...do something with file...
# end
#
@@ -88,8 +88,6 @@ require 'tmpdir'
# mutex.
class Tempfile < DelegateClass(File)
- VERSION = "0.2.0"
-
# Creates a file in the underlying file system;
# returns a new \Tempfile object based on that file.
#
@@ -152,50 +150,26 @@ class Tempfile < DelegateClass(File)
@unlinked = false
@mode = mode|File::RDWR|File::CREAT|File::EXCL
- @finalizer_obj = Object.new
- tmpfile = nil
::Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
opts[:perm] = 0600
- tmpfile = File.open(tmpname, @mode, **opts)
+ @tmpfile = File.open(tmpname, @mode, **opts)
@opts = opts.freeze
end
- ObjectSpace.define_finalizer(@finalizer_obj, Remover.new(tmpfile.path))
- ObjectSpace.define_finalizer(self, Closer.new(tmpfile))
-
- super(tmpfile)
- end
-
- def initialize_dup(other)
- initialize_copy_iv(other)
- super(other)
- ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
- end
-
- def initialize_clone(other)
- initialize_copy_iv(other)
- super(other)
- ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
- end
+ ObjectSpace.define_finalizer(self, Remover.new(@tmpfile))
- private def initialize_copy_iv(other)
- @unlinked = other.unlinked
- @mode = other.mode
- @opts = other.opts
- @finalizer_obj = other.finalizer_obj
+ super(@tmpfile)
end
# Opens or reopens the file with mode "r+".
def open
_close
- ObjectSpace.undefine_finalizer(self)
mode = @mode & ~(File::CREAT|File::EXCL)
- __setobj__(File.open(__getobj__.path, mode, **@opts))
- ObjectSpace.define_finalizer(self, Closer.new(__getobj__))
- __getobj__
+ @tmpfile = File.open(@tmpfile.path, mode, **@opts)
+ __setobj__(@tmpfile)
end
def _close # :nodoc:
- __getobj__.close
+ @tmpfile.close
end
protected :_close
@@ -252,13 +226,13 @@ class Tempfile < DelegateClass(File)
def unlink
return if @unlinked
begin
- File.unlink(__getobj__.path)
+ File.unlink(@tmpfile.path)
rescue Errno::ENOENT
rescue Errno::EACCES
# may not be able to unlink on Windows; just ignore
return
end
- ObjectSpace.undefine_finalizer(@finalizer_obj)
+ ObjectSpace.undefine_finalizer(self)
@unlinked = true
end
alias delete unlink
@@ -266,56 +240,43 @@ class Tempfile < DelegateClass(File)
# Returns the full path name of the temporary file.
# This will be nil if #unlink has been called.
def path
- @unlinked ? nil : __getobj__.path
+ @unlinked ? nil : @tmpfile.path
end
# Returns the size of the temporary file. As a side effect, the IO
# buffer is flushed before determining the size.
def size
- if !__getobj__.closed?
- __getobj__.size # File#size calls rb_io_flush_raw()
+ if !@tmpfile.closed?
+ @tmpfile.size # File#size calls rb_io_flush_raw()
else
- File.size(__getobj__.path)
+ File.size(@tmpfile.path)
end
end
alias length size
# :stopdoc:
def inspect
- if __getobj__.closed?
+ if @tmpfile.closed?
"#<#{self.class}:#{path} (closed)>"
else
"#<#{self.class}:#{path}>"
end
end
- protected
-
- attr_reader :unlinked, :mode, :opts, :finalizer_obj
-
- class Closer # :nodoc:
- def initialize(tmpfile)
- @tmpfile = tmpfile
- end
-
- def call(*args)
- @tmpfile.close
- end
- end
-
class Remover # :nodoc:
- def initialize(path)
+ def initialize(tmpfile)
@pid = Process.pid
- @path = path
+ @tmpfile = tmpfile
end
def call(*args)
return if @pid != Process.pid
- $stderr.puts "removing #{@path}..." if $DEBUG
+ $stderr.puts "removing #{@tmpfile.path}..." if $DEBUG
+ @tmpfile.close
begin
- File.unlink(@path)
+ File.unlink(@tmpfile.path)
rescue Errno::ENOENT
end
diff --git a/lib/time.gemspec b/lib/time.gemspec
index a9349a253f..bada91a30b 100644
--- a/lib/time.gemspec
+++ b/lib/time.gemspec
@@ -1,20 +1,13 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "time"
+ spec.version = "0.2.2"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
spec.summary = %q{Extends the Time class with methods for parsing and conversion.}
spec.description = %q{Extends the Time class with methods for parsing and conversion.}
spec.homepage = "https://github.com/ruby/time"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.metadata["homepage_uri"] = spec.homepage
diff --git a/lib/time.rb b/lib/time.rb
index 2bfbd57642..6a13212a49 100644
--- a/lib/time.rb
+++ b/lib/time.rb
@@ -25,9 +25,6 @@ require 'date'
# :startdoc:
class Time
-
- VERSION = "0.3.0"
-
class << Time
#
diff --git a/lib/timeout.gemspec b/lib/timeout.gemspec
deleted file mode 100644
index 258517c5f8..0000000000
--- a/lib/timeout.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Auto-terminate potentially long-running operations in Ruby.}
- spec.description = %q{Auto-terminate potentially long-running operations in Ruby.}
- spec.homepage = "https://github.com/ruby/timeout"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- spec.required_ruby_version = '>= 2.6.0'
-
- spec.files = Dir.chdir(__dir__) do
- `git ls-files -z`.split("\x0").reject do |f|
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)})
- end
- end
- spec.require_paths = ["lib"]
-end
diff --git a/lib/timeout.rb b/lib/timeout.rb
index d8806e22b3..7f40bafa4d 100644
--- a/lib/timeout.rb
+++ b/lib/timeout.rb
@@ -23,26 +23,29 @@
# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
module Timeout
- VERSION = "0.4.1"
-
- # Internal error raised to when a timeout is triggered.
- class ExitException < Exception
- def exception(*)
- self
- end
- end
+ VERSION = "0.3.1"
# Raised by Timeout.timeout when the block times out.
class Error < RuntimeError
- def self.handle_timeout(message)
- exc = ExitException.new(message)
+ attr_reader :thread
- begin
- yield exc
- rescue ExitException => e
- raise new(message) if exc.equal?(e)
- raise
+ def self.catch(*args)
+ exc = new(*args)
+ exc.instance_variable_set(:@thread, Thread.current)
+ exc.instance_variable_set(:@catch_value, exc)
+ ::Kernel.catch(exc) {yield exc}
+ end
+
+ def exception(*)
+ # TODO: use Fiber.current to see if self can be thrown
+ if self.thread == Thread.current
+ bt = caller
+ begin
+ throw(@catch_value, bt)
+ rescue UncaughtThrowError
+ end
end
+ super
end
end
@@ -117,7 +120,7 @@ module Timeout
requests.reject!(&:done?)
end
end
- ThreadGroup::Default.add(watcher) unless watcher.group.enclosed?
+ ThreadGroup::Default.add(watcher)
watcher.name = "Timeout stdlib thread"
watcher.thread_variable_set(:"\0__detached_thread__", true)
watcher
@@ -192,7 +195,8 @@ module Timeout
if klass
perform.call(klass)
else
- Error.handle_timeout(message, &perform)
+ backtrace = Error.catch(&perform)
+ raise Error, message, backtrace
end
end
module_function :timeout
diff --git a/lib/timeout/timeout.gemspec b/lib/timeout/timeout.gemspec
new file mode 100644
index 0000000000..7449ae1980
--- /dev/null
+++ b/lib/timeout/timeout.gemspec
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Auto-terminate potentially long-running operations in Ruby.}
+ spec.description = %q{Auto-terminate potentially long-running operations in Ruby.}
+ spec.homepage = "https://github.com/ruby/timeout"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(__dir__) do
+ `git ls-files -z`.split("\x0").reject do |f|
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)})
+ end
+ end
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/tmpdir.gemspec b/lib/tmpdir.gemspec
index a7463105fa..e42662ea3b 100644
--- a/lib/tmpdir.gemspec
+++ b/lib/tmpdir.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "tmpdir"
- spec.version = "0.2.0"
+ spec.version = "0.1.3"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/tmpdir.rb b/lib/tmpdir.rb
index db5ed978cd..55920a4a74 100644
--- a/lib/tmpdir.rb
+++ b/lib/tmpdir.rb
@@ -13,20 +13,15 @@ end
class Dir
- # Class variables are inaccessible from non-main Ractor.
- # And instance variables too, in Ruby 3.0.
-
- # System-wide temporary directory path
- SYSTMPDIR = (defined?(Etc.systmpdir) ? Etc.systmpdir.freeze : '/tmp')
- private_constant :SYSTMPDIR
+ @@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
##
# Returns the operating system's temporary file path.
def self.tmpdir
- ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', SYSTMPDIR], ['/tmp']*2, ['.']*2].find do |name, dir|
+ ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @@systmpdir], ['/tmp']*2, ['.']*2].find do |name, dir|
unless dir
- next if !(dir = ENV[name] rescue next) or dir.empty?
+ next if !(dir = ENV[name]) or dir.empty?
end
dir = File.expand_path(dir)
stat = File.stat(dir) rescue next
@@ -123,17 +118,16 @@ class Dir
UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~"
# Dedicated random number generator
- RANDOM = Object.new
+ RANDOM = Random.new
class << RANDOM # :nodoc:
# Maximum random number
MAX = 36**6 # < 0x100000000
# Returns new random string upto 6 bytes
def next
- (::Random.urandom(4).unpack1("L")%MAX).to_s(36)
+ rand(MAX).to_s(36)
end
end
- RANDOM.freeze
private_constant :RANDOM
# Generates and yields random names to create a temporary name
diff --git a/lib/tsort.gemspec b/lib/tsort.gemspec
index 0e2f110a53..a82393b70b 100644
--- a/lib/tsort.gemspec
+++ b/lib/tsort.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "tsort"
+ spec.version = "0.1.1"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/tsort.rb b/lib/tsort.rb
index dbaed45415..00ee609d64 100644
--- a/lib/tsort.rb
+++ b/lib/tsort.rb
@@ -122,9 +122,6 @@
#
module TSort
-
- VERSION = "0.2.0"
-
class Cyclic < StandardError
end
diff --git a/lib/un.gemspec b/lib/un.gemspec
index 2ed49511cc..1a466fdebe 100644
--- a/lib/un.gemspec
+++ b/lib/un.gemspec
@@ -1,15 +1,8 @@
# frozen_string_literal: true
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "un"
+ spec.version = "0.2.1"
spec.authors = ["WATANABE Hirofumi"]
spec.email = ["eban@ruby-lang.org"]
diff --git a/lib/un.rb b/lib/un.rb
index 8fb3c61a93..796b36fbab 100644
--- a/lib/un.rb
+++ b/lib/un.rb
@@ -30,6 +30,7 @@ require "fileutils"
require "optparse"
module FileUtils
+# @fileutils_label = ""
@fileutils_output = $stdout
end
@@ -411,9 +412,6 @@ def help
end
module UN # :nodoc:
-
- VERSION = "0.3.0"
-
module_function
def help(argv, output: $stdout)
all = argv.empty?
diff --git a/lib/uri/common.rb b/lib/uri/common.rb
index dce09fbc1e..0c4064a67a 100644
--- a/lib/uri/common.rb
+++ b/lib/uri/common.rb
@@ -19,6 +19,8 @@ module URI
Parser = RFC2396_Parser
RFC3986_PARSER = RFC3986_Parser.new
Ractor.make_shareable(RFC3986_PARSER) if defined?(Ractor)
+ RFC2396_PARSER = RFC2396_Parser.new
+ Ractor.make_shareable(RFC2396_PARSER) if defined?(Ractor)
# URI::Parser.new
DEFAULT_PARSER = Parser.new
@@ -68,32 +70,16 @@ module URI
end
private_constant :Schemes
- # Registers the given +klass+ as the class to be instantiated
- # when parsing a \URI with the given +scheme+:
#
- # URI.register_scheme('MS_SEARCH', URI::Generic) # => URI::Generic
- # URI.scheme_list['MS_SEARCH'] # => URI::Generic
+ # Register the given +klass+ to be instantiated when parsing URLs with the given +scheme+.
+ # Note that currently only schemes which after .upcase are valid constant names
+ # can be registered (no -/+/. allowed).
#
- # Note that after calling String#upcase on +scheme+, it must be a valid
- # constant name.
def self.register_scheme(scheme, klass)
Schemes.const_set(scheme.to_s.upcase, klass)
end
- # Returns a hash of the defined schemes:
- #
- # URI.scheme_list
- # # =>
- # {"MAILTO"=>URI::MailTo,
- # "LDAPS"=>URI::LDAPS,
- # "WS"=>URI::WS,
- # "HTTP"=>URI::HTTP,
- # "HTTPS"=>URI::HTTPS,
- # "LDAP"=>URI::LDAP,
- # "FILE"=>URI::File,
- # "FTP"=>URI::FTP}
- #
- # Related: URI.register_scheme.
+ # Returns a Hash of the defined schemes.
def self.scheme_list
Schemes.constants.map { |name|
[name.to_s.upcase, Schemes.const_get(name)]
@@ -104,21 +90,9 @@ module URI
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
- # Returns a new object constructed from the given +scheme+, +arguments+,
- # and +default+:
- #
- # - The new object is an instance of <tt>URI.scheme_list[scheme.upcase]</tt>.
- # - The object is initialized by calling the class initializer
- # using +scheme+ and +arguments+.
- # See URI::Generic.new.
- #
- # Examples:
#
- # values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
- # URI.for('https', *values)
- # # => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # URI.for('foo', *values, default: URI::HTTP)
- # # => #<URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # Construct a URI instance, using the scheme to detect the appropriate class
+ # from +URI.scheme_list+.
#
def self.for(scheme, *arguments, default: Generic)
const_name = scheme.to_s.upcase
@@ -149,49 +123,95 @@ module URI
#
class BadURIError < Error; end
- # Returns a 9-element array representing the parts of the \URI
- # formed from the string +uri+;
- # each array element is a string or +nil+:
- #
- # names = %w[scheme userinfo host port registry path opaque query fragment]
- # values = URI.split('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # names.zip(values)
- # # =>
- # [["scheme", "https"],
- # ["userinfo", "john.doe"],
- # ["host", "www.example.com"],
- # ["port", "123"],
- # ["registry", nil],
- # ["path", "/forum/questions/"],
- # ["opaque", nil],
- # ["query", "tag=networking&order=newest"],
- # ["fragment", "top"]]
+ #
+ # == Synopsis
+ #
+ # URI::split(uri)
+ #
+ # == Args
+ #
+ # +uri+::
+ # String with URI.
+ #
+ # == Description
+ #
+ # Splits the string on following parts and returns array with result:
+ #
+ # * Scheme
+ # * Userinfo
+ # * Host
+ # * Port
+ # * Registry
+ # * Path
+ # * Opaque
+ # * Query
+ # * Fragment
+ #
+ # == Usage
+ #
+ # require 'uri'
+ #
+ # URI.split("http://www.ruby-lang.org/")
+ # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil]
#
def self.split(uri)
RFC3986_PARSER.split(uri)
end
- # Returns a new \URI object constructed from the given string +uri+:
#
- # URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # == Synopsis
+ #
+ # URI::parse(uri_str)
+ #
+ # == Args
+ #
+ # +uri_str+::
+ # String with URI.
+ #
+ # == Description
+ #
+ # Creates one of the URI's subclasses instance from the string.
+ #
+ # == Raises
+ #
+ # URI::InvalidURIError::
+ # Raised if URI given is not a correct one.
#
- # It's recommended to first ::escape string +uri+
- # if it may contain invalid URI characters.
+ # == Usage
+ #
+ # require 'uri'
+ #
+ # uri = URI.parse("http://www.ruby-lang.org/")
+ # # => #<URI::HTTP http://www.ruby-lang.org/>
+ # uri.scheme
+ # # => "http"
+ # uri.host
+ # # => "www.ruby-lang.org"
+ #
+ # It's recommended to first ::escape the provided +uri_str+ if there are any
+ # invalid URI characters.
#
def self.parse(uri)
RFC3986_PARSER.parse(uri)
end
- # Merges the given URI strings +str+
- # per {RFC 2396}[https://www.rfc-editor.org/rfc/rfc2396.html].
#
- # Each string in +str+ is converted to an
- # {RFC3986 URI}[https://www.rfc-editor.org/rfc/rfc3986.html] before being merged.
+ # == Synopsis
+ #
+ # URI::join(str[, str, ...])
#
- # Examples:
+ # == Args
+ #
+ # +str+::
+ # String(s) to work with, will be converted to RFC3986 URIs before merging.
+ #
+ # == Description
+ #
+ # Joins URIs.
+ #
+ # == Usage
+ #
+ # require 'uri'
#
# URI.join("http://example.com/","main.rbx")
# # => #<URI::HTTP http://example.com/main.rbx>
@@ -236,7 +256,7 @@ module URI
# URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.")
# # => ["http://foo.example.com/bla", "mailto:test@example.com"]
#
- def self.extract(str, schemes = nil, &block) # :nodoc:
+ def self.extract(str, schemes = nil, &block)
warn "URI.extract is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.extract(str, schemes, &block)
end
@@ -273,7 +293,7 @@ module URI
# p $&
# end
#
- def self.regexp(schemes = nil)# :nodoc:
+ def self.regexp(schemes = nil)
warn "URI.regexp is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.make_regexp(schemes)
end
@@ -296,86 +316,40 @@ module URI
TBLDECWWWCOMP_['+'] = ' '
TBLDECWWWCOMP_.freeze
- # Returns a URL-encoded string derived from the given string +str+.
- #
- # The returned string:
- #
- # - Preserves:
- #
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
- #
- # Example:
+ # Encodes given +str+ to URL-encoded form data.
#
- # URI.encode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
+ # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
+ # (ASCII space) to + and converts others to %XX.
#
- # - Converts:
+ # If +enc+ is given, convert +str+ to the encoding before percent encoding.
#
- # - Character <tt>' '</tt> to character <tt>'+'</tt>.
- # - Any other character to "percent notation";
- # the percent notation for character <i>c</i> is <tt>'%%%X' % c.ord</tt>.
+ # This is an implementation of
+ # https://www.w3.org/TR/2013/CR-html5-20130806/forms.html#url-encoded-form-data.
#
- # Example:
- #
- # URI.encode_www_form_component('Here are some punctuation characters: ,;?:')
- # # => "Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A"
- #
- # Encoding:
- #
- # - If +str+ has encoding Encoding::ASCII_8BIT, argument +enc+ is ignored.
- # - Otherwise +str+ is converted first to Encoding::UTF_8
- # (with suitable character replacements),
- # and then to encoding +enc+.
- #
- # In either case, the returned string has forced encoding Encoding::US_ASCII.
- #
- # Related: URI.encode_uri_component (encodes <tt>' '</tt> as <tt>'%20'</tt>).
+ # See URI.decode_www_form_component, URI.encode_www_form.
def self.encode_www_form_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc)
end
- # Returns a string decoded from the given \URL-encoded string +str+.
- #
- # The given string is first encoded as Encoding::ASCII-8BIT (using String#b),
- # then decoded (as below), and finally force-encoded to the given encoding +enc+.
- #
- # The returned string:
- #
- # - Preserves:
- #
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
- #
- # Example:
- #
- # URI.decode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
- #
- # - Converts:
- #
- # - Character <tt>'+'</tt> to character <tt>' '</tt>.
- # - Each "percent notation" to an ASCII character.
+ # Decodes given +str+ of URL-encoded form data.
#
- # Example:
+ # This decodes + to SP.
#
- # URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A')
- # # => "Here are some punctuation characters: ,;?:"
- #
- # Related: URI.decode_uri_component (preserves <tt>'+'</tt>).
+ # See URI.encode_www_form_component, URI.decode_www_form.
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/\+|%\h\h/, str, enc)
end
- # Like URI.encode_www_form_component, except that <tt>' '</tt> (space)
- # is encoded as <tt>'%20'</tt> (instead of <tt>'+'</tt>).
+ # Encodes +str+ using URL encoding
+ #
+ # This encodes SP to %20 instead of +.
def self.encode_uri_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
end
- # Like URI.decode_www_form_component, except that <tt>'+'</tt> is preserved.
+ # Decodes given +str+ of URL-encoded data.
+ #
+ # This does not decode + to SP.
def self.decode_uri_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/%\h\h/, str, enc)
end
@@ -400,104 +374,33 @@ module URI
end
private_class_method :_decode_uri_component
- # Returns a URL-encoded string derived from the given
- # {Enumerable}[rdoc-ref:Enumerable@Enumerable+in+Ruby+Classes]
- # +enum+.
- #
- # The result is suitable for use as form data
- # for an \HTTP request whose <tt>Content-Type</tt> is
- # <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The returned string consists of the elements of +enum+,
- # each converted to one or more URL-encoded strings,
- # and all joined with character <tt>'&'</tt>.
- #
- # Simple examples:
- #
- # URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
- # # => "foo=0&bar=1&baz=2"
- # URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The returned string is formed using method URI.encode_www_form_component,
- # which converts certain characters:
- #
- # URI.encode_www_form('f#o': '/', 'b-r': '$', 'b z': '@')
- # # => "f%23o=%2F&b-r=%24&b+z=%40"
- #
- # When +enum+ is Array-like, each element +ele+ is converted to a field:
- #
- # - If +ele+ is an array of two or more elements,
- # the field is formed from its first two elements
- # (and any additional elements are ignored):
- #
- # name = URI.encode_www_form_component(ele[0], enc)
- # value = URI.encode_www_form_component(ele[1], enc)
- # "#{name}=#{value}"
+ # Generates URL-encoded form data from given +enum+.
#
- # Examples:
+ # This generates application/x-www-form-urlencoded data defined in HTML5
+ # from given an Enumerable object.
#
- # URI.encode_www_form([%w[foo bar], %w[baz bat bah]])
- # # => "foo=bar&baz=bat"
- # URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']])
- # # => "foo=0&bar=baz"
+ # This internally uses URI.encode_www_form_component(str).
#
- # - If +ele+ is an array of one element,
- # the field is formed from <tt>ele[0]</tt>:
+ # This method doesn't convert the encoding of given items, so convert them
+ # before calling this method if you want to send data as other than original
+ # encoding or mixed encoding data. (Strings which are encoded in an HTML5
+ # ASCII incompatible encoding are converted to UTF-8.)
#
- # URI.encode_www_form_component(ele[0])
+ # This method doesn't handle files. When you send a file, use
+ # multipart/form-data.
#
- # Example:
+ # This refers https://url.spec.whatwg.org/#concept-urlencoded-serializer
#
- # URI.encode_www_form([['foo'], [:bar], [0]])
- # # => "foo&bar&0"
- #
- # - Otherwise the field is formed from +ele+:
- #
- # URI.encode_www_form_component(ele)
- #
- # Example:
- #
- # URI.encode_www_form(['foo', :bar, 0])
- # # => "foo&bar&0"
- #
- # The elements of an Array-like +enum+ may be mixture:
- #
- # URI.encode_www_form([['foo', 0], ['bar', 1, 2], ['baz'], :bat])
- # # => "foo=0&bar=1&baz&bat"
- #
- # When +enum+ is Hash-like,
- # each +key+/+value+ pair is converted to one or more fields:
- #
- # - If +value+ is
- # {Array-convertible}[rdoc-ref:implicit_conversion.rdoc@Array-Convertible+Objects],
- # each element +ele+ in +value+ is paired with +key+ to form a field:
- #
- # name = URI.encode_www_form_component(key, enc)
- # value = URI.encode_www_form_component(ele, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]})
- # # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2"
- #
- # - Otherwise, +key+ and +value+ are paired to form a field:
- #
- # name = URI.encode_www_form_component(key, enc)
- # value = URI.encode_www_form_component(value, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The elements of a Hash-like +enum+ may be mixture:
- #
- # URI.encode_www_form({foo: [0, 1], bar: 2})
- # # => "foo=0&foo=1&bar=2"
+ # URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
+ # #=> "q=ruby&lang=en"
+ # URI.encode_www_form("q" => "ruby", "lang" => "en")
+ # #=> "q=ruby&lang=en"
+ # URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
+ # #=> "q=ruby&q=perl&lang=en"
+ # URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
+ # #=> "q=ruby&q=perl&lang=en"
#
+ # See URI.encode_www_form_component, URI.decode_www_form.
def self.encode_www_form(enum, enc=nil)
enum.map do |k,v|
if v.nil?
@@ -518,39 +421,22 @@ module URI
end.join('&')
end
- # Returns name/value pairs derived from the given string +str+,
- # which must be an ASCII string.
- #
- # The method may be used to decode the body of Net::HTTPResponse object +res+
- # for which <tt>res['Content-Type']</tt> is <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The returned data is an array of 2-element subarrays;
- # each subarray is a name/value pair (both are strings).
- # Each returned string has encoding +enc+,
- # and has had invalid characters removed via
- # {String#scrub}[rdoc-ref:String#scrub].
+ # Decodes URL-encoded form data from given +str+.
#
- # A simple example:
+ # This decodes application/x-www-form-urlencoded data
+ # and returns an array of key-value arrays.
#
- # URI.decode_www_form('foo=0&bar=1&baz')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
+ # This refers http://url.spec.whatwg.org/#concept-urlencoded-parser,
+ # so this supports only &-separator, and doesn't support ;-separator.
#
- # The returned strings have certain conversions,
- # similar to those performed in URI.decode_www_form_component:
- #
- # URI.decode_www_form('f%23o=%2F&b-r=%24&b+z=%40')
- # # => [["f#o", "/"], ["b-r", "$"], ["b z", "@"]]
- #
- # The given string may contain consecutive separators:
- #
- # URI.decode_www_form('foo=0&&bar=1&&baz=2')
- # # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
- #
- # A different separator may be specified:
- #
- # URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
+ # ary = URI.decode_www_form("a=1&a=2&b=3")
+ # ary #=> [['a', '1'], ['a', '2'], ['b', '3']]
+ # ary.assoc('a').last #=> '1'
+ # ary.assoc('b').last #=> '3'
+ # ary.rassoc('a').last #=> '2'
+ # Hash[ary] #=> {"a"=>"2", "b"=>"3"}
#
+ # See URI.decode_www_form_component, URI.encode_www_form.
def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false)
raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only?
ary = []
@@ -829,15 +715,7 @@ end # module URI
module Kernel
#
- # Returns a \URI object derived from the given +uri+,
- # which may be a \URI string or an existing \URI object:
- #
- # # Returns a new URI.
- # uri = URI('http://github.com/ruby/ruby')
- # # => #<URI::HTTP http://github.com/ruby/ruby>
- # # Returns the given URI.
- # URI(uri)
- # # => #<URI::HTTP http://github.com/ruby/ruby>
+ # Returns +uri+ converted to an URI object.
#
def URI(uri)
if uri.is_a?(URI::Generic)
diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb
index f3540a24bb..f7eed57924 100644
--- a/lib/uri/generic.rb
+++ b/lib/uri/generic.rb
@@ -1133,17 +1133,16 @@ module URI
base.fragment=(nil)
# RFC2396, Section 5.2, 4)
- if !authority
- base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path
- else
- # RFC2396, Section 5.2, 4)
- base.set_path(rel.path) if rel.path
+ if authority
+ base.set_userinfo(rel.userinfo)
+ base.set_host(rel.host)
+ base.set_port(rel.port || base.default_port)
+ base.set_path(rel.path)
+ elsif base.path && rel.path
+ base.set_path(merge_path(base.path, rel.path))
end
# RFC2396, Section 5.2, 7)
- base.set_userinfo(rel.userinfo) if rel.userinfo
- base.set_host(rel.host) if rel.host
- base.set_port(rel.port) if rel.port
base.query = rel.query if rel.query
base.fragment=(rel.fragment) if rel.fragment
@@ -1376,7 +1375,6 @@ module URI
end
str
end
- alias to_str to_s
#
# Compares two URIs.
diff --git a/lib/uri/rfc3986_parser.rb b/lib/uri/rfc3986_parser.rb
index 092a1ac89d..9b1663dbb6 100644
--- a/lib/uri/rfc3986_parser.rb
+++ b/lib/uri/rfc3986_parser.rb
@@ -1,73 +1,9 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
module URI
class RFC3986_Parser # :nodoc:
# URI defined in RFC3986
- HOST = %r[
- (?<IP-literal>\[(?:
- (?<IPv6address>
- (?:\h{1,4}:){6}
- (?<ls32>\h{1,4}:\h{1,4}
- | (?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)
- \.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>)
- )
- | ::(?:\h{1,4}:){5}\g<ls32>
- | \h{1,4}?::(?:\h{1,4}:){4}\g<ls32>
- | (?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>
- | (?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>
- | (?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>
- | (?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>
- | (?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}
- | (?:(?:\h{1,4}:){,6}\h{1,4})?::
- )
- | (?<IPvFuture>v\h++\.[!$&-.0-9:;=A-Z_a-z~]++)
- )\])
- | \g<IPv4address>
- | (?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+)
- ]x
-
- USERINFO = /(?:%\h\h|[!$&-.0-9:;=A-Z_a-z~])*+/
-
- SCHEME = %r[[A-Za-z][+\-.0-9A-Za-z]*+].source
- SEG = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/])].source
- SEG_NC = %r[(?:%\h\h|[!$&-.0-9;=@A-Z_a-z~])].source
- FRAGMENT = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+].source
-
- RFC3986_URI = %r[\A
- (?<seg>#{SEG}){0}
- (?<URI>
- (?<scheme>#{SCHEME}):
- (?<hier-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")})
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/((?!/)\g<seg>++)?)
- | (?<path-rootless>(?!/)\g<seg>++)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^\#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
-
- RFC3986_relative_ref = %r[\A
- (?<seg>#{SEG}){0}
- (?<relative-ref>
- (?<relative-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")}(?<!/))?
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/\g<seg>*+)
- | (?<path-noscheme>#{SEG_NC}++(?:/\g<seg>*+)?)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
+ RFC3986_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*+):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+))(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
+ RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])++))?(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])++)(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
attr_reader :regexp
def initialize
@@ -83,9 +19,9 @@ module URI
uri.ascii_only? or
raise InvalidURIError, "URI must be ascii only #{uri.dump}"
if m = RFC3986_URI.match(uri)
- query = m["query"]
- scheme = m["scheme"]
- opaque = m["path-rootless"]
+ query = m["query".freeze]
+ scheme = m["scheme".freeze]
+ opaque = m["path-rootless".freeze]
if opaque
opaque << "?#{query}" if query
[ scheme,
@@ -96,35 +32,35 @@ module URI
nil, # path
opaque,
nil, # query
- m["fragment"]
+ m["fragment".freeze]
]
else # normal
[ scheme,
- m["userinfo"],
- m["host"],
- m["port"],
+ m["userinfo".freeze],
+ m["host".freeze],
+ m["port".freeze],
nil, # registry
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-empty"]),
+ (m["path-abempty".freeze] ||
+ m["path-absolute".freeze] ||
+ m["path-empty".freeze]),
nil, # opaque
query,
- m["fragment"]
+ m["fragment".freeze]
]
end
elsif m = RFC3986_relative_ref.match(uri)
[ nil, # scheme
- m["userinfo"],
- m["host"],
- m["port"],
+ m["userinfo".freeze],
+ m["host".freeze],
+ m["port".freeze],
nil, # registry,
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-noscheme"] ||
- m["path-empty"]),
+ (m["path-abempty".freeze] ||
+ m["path-absolute".freeze] ||
+ m["path-noscheme".freeze] ||
+ m["path-empty".freeze]),
nil, # opaque
- m["query"],
- m["fragment"]
+ m["query".freeze],
+ m["fragment".freeze]
]
else
raise InvalidURIError, "bad URI(is not URI?): #{uri.inspect}"
@@ -156,14 +92,14 @@ module URI
def default_regexp # :nodoc:
{
- SCHEME: %r[\A#{SCHEME}\z]o,
- USERINFO: %r[\A#{USERINFO}\z]o,
- HOST: %r[\A#{HOST}\z]o,
- ABS_PATH: %r[\A/#{SEG}*+\z]o,
- REL_PATH: %r[\A(?!/)#{SEG}++\z]o,
- QUERY: %r[\A(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+\z],
- FRAGMENT: %r[\A#{FRAGMENT}\z]o,
- OPAQUE: %r[\A(?:[^/].*)?\z],
+ SCHEME: /\A[A-Za-z][A-Za-z0-9+\-.]*\z/,
+ USERINFO: /\A(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*\z/,
+ HOST: /\A(?:(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{,4}::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))\z/,
+ ABS_PATH: /\A\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
+ REL_PATH: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
+ QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
+ FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
+ OPAQUE: /\A(?:[^\/].*)?\z/,
PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
}
end
diff --git a/lib/uri/uri.gemspec b/lib/uri/uri.gemspec
index 9cf0a71196..584a4faa11 100644
--- a/lib/uri/uri.gemspec
+++ b/lib/uri/uri.gemspec
@@ -12,26 +12,18 @@ Gem::Specification.new do |spec|
spec.summary = %q{URI is a module providing classes to handle Uniform Resource Identifiers}
spec.description = spec.summary
-
- github_link = "https://github.com/ruby/uri"
-
- spec.homepage = github_link
+ spec.homepage = "https://github.com/ruby/uri"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = '>= 2.5'
+ spec.required_ruby_version = '>= 2.4'
- spec.metadata = {
- "bug_tracker_uri" => "#{github_link}/issues",
- "changelog_uri" => "#{github_link}/releases",
- "documentation_uri" => "https://ruby.github.io/uri/",
- "homepage_uri" => spec.homepage,
- "source_code_uri" => github_link
- }
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/uri/version.rb b/lib/uri/version.rb
index 2dafa57d59..c93c97cf6f 100644
--- a/lib/uri/version.rb
+++ b/lib/uri/version.rb
@@ -1,6 +1,6 @@
module URI
# :stopdoc:
- VERSION_CODE = '001300'.freeze
+ VERSION_CODE = '001204'.freeze
VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
# :startdoc:
end
diff --git a/lib/weakref.gemspec b/lib/weakref.gemspec
deleted file mode 100644
index 03893f77e6..0000000000
--- a/lib/weakref.gemspec
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Allows a referenced object to be garbage-collected.}
- spec.description = %q{Allows a referenced object to be garbage-collected.}
- spec.homepage = "https://github.com/ruby/weakref"
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = "https://github.com/ruby/weakref"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-
- spec.add_dependency "delegate"
-end
diff --git a/lib/weakref.rb b/lib/weakref.rb
index a8da39a26a..2bbadf68f9 100644
--- a/lib/weakref.rb
+++ b/lib/weakref.rb
@@ -17,7 +17,7 @@ require "delegate"
#
class WeakRef < Delegator
- VERSION = "0.1.3"
+ VERSION = "0.1.2"
##
# RefError is raised when a referenced object has been recycled by the
diff --git a/lib/weakref/weakref.gemspec b/lib/weakref/weakref.gemspec
new file mode 100644
index 0000000000..96a9765079
--- /dev/null
+++ b/lib/weakref/weakref.gemspec
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Allows a referenced object to be garbage-collected.}
+ spec.description = %q{Allows a referenced object to be garbage-collected.}
+ spec.homepage = "https://github.com/ruby/weakref"
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = "https://github.com/ruby/weakref"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+
+ spec.add_dependency "delegate"
+end
diff --git a/lib/yaml.rb b/lib/yaml.rb
index b2669899dd..6d5d5ebd4c 100644
--- a/lib/yaml.rb
+++ b/lib/yaml.rb
@@ -66,5 +66,4 @@ YAML = Psych # :nodoc:
#
# Syck can also be found on github: https://github.com/ruby/syck
module YAML
- LOADER_VERSION = "0.3.0"
end
diff --git a/lib/yaml/store.rb b/lib/yaml/store.rb
index 88dd1b978c..f8650b942f 100644
--- a/lib/yaml/store.rb
+++ b/lib/yaml/store.rb
@@ -65,7 +65,7 @@ class YAML::Store < PStore
end
def load(content)
- table = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(content) : YAML.load(content)
+ table = YAML.unsafe_load(content)
if table == false
{}
else
diff --git a/lib/yaml/yaml.gemspec b/lib/yaml/yaml.gemspec
index 17e1ce89e0..80554d8a7a 100644
--- a/lib/yaml/yaml.gemspec
+++ b/lib/yaml/yaml.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*LOADER_VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "yaml"
+ spec.version = "0.2.1"
spec.authors = ["Aaron Patterson", "SHIBATA Hiroshi"]
spec.email = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org"]
@@ -22,7 +15,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/libexec/irb b/libexec/irb
index 12f41e4f0a..c64ee85fbd 100755
--- a/libexec/irb
+++ b/libexec/irb
@@ -1,6 +1,8 @@
#!/usr/bin/env ruby
#
# irb.rb - interactive ruby
+# $Release Version: 0.9.6 $
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
diff --git a/libexec/racc b/libexec/racc
new file mode 100755
index 0000000000..4507d04962
--- /dev/null
+++ b/libexec/racc
@@ -0,0 +1,320 @@
+#!/usr/bin/env ruby
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+
+require 'racc/static'
+require 'optparse'
+
+def main
+ output = nil
+ debug_parser = false
+ make_logfile = false
+ logfilename = nil
+ make_executable = false
+ rubypath = nil
+ embed_runtime = false
+ debug_flags = Racc::DebugFlags.new
+ line_convert = true
+ line_convert_all = false
+ omit_action_call = true
+ superclass = nil
+ check_only = false
+ verbose = false
+ profiler = RaccProfiler.new(false)
+
+ parser = OptionParser.new
+ parser.banner = "Usage: #{File.basename($0)} [options] <input>"
+ parser.on('-o', '--output-file=PATH',
+ 'output file name [<input>.tab.rb]') {|name|
+ output = name
+ }
+ parser.on('-t', '--debug', 'Outputs debugging parser.') {|fl|
+ debug_parser = fl
+ }
+ parser.on('-g', 'Equivalent to -t (obsolete).') {|fl|
+ $stderr.puts "racc -g is obsolete. Use racc -t instead." if $VERBOSE
+ debug_parser = fl
+ }
+ parser.on('-v', '--verbose',
+ 'Creates <filename>.output log file.') {|fl|
+ make_logfile = fl
+ }
+ parser.on('-O', '--log-file=PATH',
+ 'Log file name [<input>.output]') {|path|
+ make_logfile = true
+ logfilename = path
+ }
+ parser.on('-e', '--executable [RUBYPATH]', 'Makes executable parser.') {|path|
+ make_executable = true
+ rubypath = (path == 'ruby' ? nil : path)
+ }
+ parser.on('-E', '--embedded', "Embeds Racc runtime in output.") {
+ embed_runtime = true
+ }
+ parser.on('--line-convert-all', 'Converts line numbers of user codes.') {
+ line_convert_all = true
+ }
+ parser.on('-l', '--no-line-convert', 'Never convert line numbers.') {
+ line_convert = false
+ line_convert_all = false
+ }
+ parser.on('-a', '--no-omit-actions', 'Never omit actions.') {
+ omit_action_call = false
+ }
+ parser.on('--superclass=CLASSNAME',
+ 'Uses CLASSNAME instead of Racc::Parser.') {|name|
+ superclass = name
+ }
+ parser.on('-C', '--check-only', 'Checks syntax and quit immediately.') {|fl|
+ check_only = fl
+ }
+ parser.on('-S', '--output-status', 'Outputs internal status time to time.') {
+ verbose = true
+ }
+ parser.on('-P', 'Enables generator profile') {
+ profiler = RaccProfiler.new(true)
+ }
+ parser.on('-D flags', "Flags for Racc debugging (do not use).") {|flags|
+ debug_flags = Racc::DebugFlags.parse_option_string(flags)
+ }
+ #parser.on('--no-extensions', 'Run Racc without any Ruby extension.') {
+ # Racc.const_set :Racc_No_Extensions, true
+ #}
+ parser.on('--version', 'Prints version and quit.') {
+ puts "racc version #{Racc::Version}"
+ exit 0
+ }
+ parser.on('--runtime-version', 'Prints runtime version and quit.') {
+ printf "racc runtime version %s; %s\n",
+ Racc::Parser::Racc_Runtime_Version,
+ if Racc::Parser.racc_runtime_type == 'ruby'
+ sprintf('ruby core version %s',
+ Racc::Parser::Racc_Runtime_Core_Version_R)
+ else
+ sprintf('c core version %s',
+ Racc::Parser::Racc_Runtime_Core_Version_C)
+ end
+ exit 0
+ }
+ parser.on('--copyright', 'Prints copyright and quit.') {
+ puts Racc::Copyright
+ exit 0
+ }
+ parser.on('--help', 'Prints this message and quit.') {
+ puts parser.help
+ exit 1
+ }
+ begin
+ parser.parse!
+ rescue OptionParser::ParseError => err
+ $stderr.puts err.message
+ $stderr.puts parser.help
+ exit 1
+ end
+ if ARGV.empty?
+ $stderr.puts 'no input'
+ exit 1
+ end
+ if ARGV.size > 1
+ $stderr.puts 'too many input'
+ exit 1
+ end
+ input = ARGV[0]
+
+ begin
+ $stderr.puts 'Parsing grammar file...' if verbose
+ result = profiler.section('parse') {
+ parser = Racc::GrammarFileParser.new(debug_flags)
+ parser.parse(File.read(input), File.basename(input))
+ }
+ if check_only
+ $stderr.puts 'syntax ok'
+ exit 0
+ end
+
+ $stderr.puts 'Generating LALR states...' if verbose
+ states = profiler.section('nfa') {
+ Racc::States.new(result.grammar).nfa
+ }
+
+ $stderr.puts "Resolving #{states.size} states..." if verbose
+ profiler.section('dfa') {
+ states.dfa
+ }
+
+ $stderr.puts 'Creating parser file...' if verbose
+ params = result.params.dup
+ # Overwrites parameters given by a grammar file with command line options.
+ params.superclass = superclass if superclass
+ params.omit_action_call = true if omit_action_call
+ # From command line option
+ if make_executable
+ params.make_executable = true
+ params.interpreter = rubypath
+ end
+ params.debug_parser = debug_parser
+ params.convert_line = line_convert
+ params.convert_line_all = line_convert_all
+ params.embed_runtime = embed_runtime
+ profiler.section('generation') {
+ generator = Racc::ParserFileGenerator.new(states, params)
+ generator.generate_parser_file(output || make_filename(input, '.tab.rb'))
+ }
+
+ if make_logfile
+ profiler.section('logging') {
+ $stderr.puts 'Creating log file...' if verbose
+ logfilename ||= make_filename(output || File.basename(input), '.output')
+ File.open(logfilename, 'w') {|f|
+ Racc::LogFileGenerator.new(states, debug_flags).output f
+ }
+ }
+ end
+ if debug_flags.status_logging
+ log_useless states.grammar
+ log_conflict states
+ else
+ has_useless = report_useless states.grammar
+ has_conflicts = report_conflict states
+ if has_useless || has_conflicts
+ preamble = make_logfile ? 'C' : 'Turn on logging with "-v" and c'
+ $stderr.puts %Q{#{preamble}heck ".output" file for details}
+ end
+ end
+
+ profiler.report
+ rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err
+ raise if $DEBUG or debug_flags.any?
+ lineno = err.message.slice(/\A\d+:/).to_s
+ $stderr.puts "#{File.basename $0}: #{input}:#{lineno} #{err.message.strip}"
+ exit 1
+ end
+end
+
+def make_filename(path, suffix)
+ path.sub(/(?:\..*?)?\z/, suffix)
+end
+
+LIST_LIMIT = 10
+def report_list(enum, label)
+ c = enum.count
+ if c > 0
+ $stderr.puts "#{c} #{label}:"
+ enum.first(LIST_LIMIT).each do |item|
+ $stderr.puts " #{yield item}"
+ end
+ $stderr.puts " ..." if c > LIST_LIMIT
+ end
+end
+
+# @return [Boolean] if anything was reported
+def report_conflict(states)
+ if states.should_report_srconflict?
+ reported = true
+ $stderr.puts "#{states.n_srconflicts} shift/reduce conflicts"
+ end
+ if states.rrconflict_exist?
+ reported = true
+ $stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts"
+ end
+ reported
+end
+
+def log_conflict(states)
+ logging('w') {|f|
+ f.puts "ex#{states.grammar.n_expected_srconflicts}"
+ if states.should_report_srconflict?
+ f.puts "sr#{states.n_srconflicts}"
+ end
+ if states.rrconflict_exist?
+ f.puts "rr#{states.n_rrconflicts}"
+ end
+ }
+end
+
+# @return [Boolean] if anything was reported
+def report_useless(grammar)
+ reported = report_list(grammar.each_useless_nonterminal, 'useless nonterminals', &:to_s)
+
+ reported ||= report_list(grammar.each_useless_rule, 'useless rules') { |r| "##{r.ident} (#{r.target})" }
+
+ if grammar.start.useless?
+ $stderr.puts 'fatal: start symbol does not derive any sentence'
+ reported = true
+ end
+ reported
+end
+
+def log_useless(grammar)
+ logging('a') {|f|
+ if grammar.useless_nonterminal_exist?
+ f.puts "un#{grammar.n_useless_nonterminals}"
+ end
+ if grammar.useless_rule_exist?
+ f.puts "ur#{grammar.n_useless_rules}"
+ end
+ }
+end
+
+def logging(mode, &block)
+ File.open("log/#{File.basename(ARGV[0])}", mode, &block)
+end
+
+class RaccProfiler
+ def initialize(really)
+ @really = really
+ @log = []
+ unless ::Process.respond_to?(:times)
+ # Ruby 1.6
+ @class = ::Time
+ else
+ @class = ::Process
+ end
+ end
+
+ def section(name)
+ if @really
+ t1 = @class.times.utime
+ result = yield
+ t2 = @class.times.utime
+ @log.push [name, t2 - t1]
+ result
+ else
+ yield
+ end
+ end
+
+ def report
+ return unless @really
+ f = $stderr
+ total = cumulative_time()
+ f.puts '--task-----------+--sec------+---%-'
+ @log.each do |name, time|
+ f.printf "%-19s %s %3d%%\n", name, pjust(time,4,4), (time/total*100).to_i
+ end
+ f.puts '-----------------+-----------+-----'
+ f.printf "%-20s%s\n", 'total', pjust(total,4,4)
+ end
+
+ private
+
+ def cumulative_time
+ t = @log.inject(0) {|sum, (name, time)| sum + time }
+ t == 0 ? 0.01 : t
+ end
+
+ def pjust(num, i, j)
+ m = /(\d+)(\.\d+)?/.match(num.to_s)
+ str = m[1].rjust(i)
+ str.concat m[2].ljust(j+1)[0,j+1] if m[2]
+ str
+ end
+end
+
+main
diff --git a/load.c b/load.c
index 3dd5f04411..ecb21faa72 100644
--- a/load.c
+++ b/load.c
@@ -9,7 +9,7 @@
#include "internal/error.h"
#include "internal/file.h"
#include "internal/load.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "iseq.h"
@@ -24,11 +24,6 @@ static VALUE ruby_dln_librefs;
#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
-enum {
- loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
- 1) /* offset by rb_find_file_ext() */
-};
-
static const char *const loadable_ext[] = {
".rb", DLEXT,
0
@@ -381,7 +376,7 @@ get_loaded_features_index(rb_vm_t *vm)
VALUE entry, as_str;
as_str = entry = rb_ary_entry(features, i);
StringValue(as_str);
- as_str = rb_fstring(as_str);
+ as_str = rb_fstring(rb_str_freeze(as_str));
if (as_str != entry)
rb_ary_store(features, i, as_str);
features_index_add(vm, as_str, INT2FIX(i));
@@ -480,12 +475,6 @@ loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
return ST_STOP;
}
-/*
- * Returns the type of already provided feature.
- * 'r': ruby script (".rb")
- * 's': shared object (".so"/"."DLEXT)
- * 'u': unsuffixed
- */
static int
rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{
@@ -578,7 +567,7 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
loading_tbl = get_loading_table(vm);
f = 0;
- if (!expanded) {
+ if (!expanded && !rb_is_absolute_path(feature)) {
struct loaded_feature_searching fs;
fs.name = feature;
fs.len = len;
@@ -680,14 +669,14 @@ rb_provide_feature(rb_vm_t *vm, VALUE feature)
rb_raise(rb_eRuntimeError,
"$LOADED_FEATURES is frozen; cannot append feature");
}
- feature = rb_fstring(feature);
+ rb_str_freeze(feature);
get_loaded_features_index(vm);
// If loaded_features and loaded_features_snapshot share the same backing
// array, pushing into it would cause the whole array to be copied.
// To avoid this we first clear loaded_features_snapshot.
rb_ary_clear(vm->loaded_features_snapshot);
- rb_ary_push(features, feature);
+ rb_ary_push(features, rb_fstring(feature));
features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
reset_loaded_features_snapshot(vm);
}
@@ -700,19 +689,6 @@ rb_provide(const char *feature)
NORETURN(static void load_failed(VALUE));
-static inline VALUE
-realpath_internal_cached(VALUE hash, VALUE path)
-{
- VALUE ret = rb_hash_aref(hash, path);
- if(RTEST(ret)) {
- return ret;
- }
-
- VALUE realpath = rb_realpath_internal(Qnil, path, 1);
- rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
- return realpath;
-}
-
static inline void
load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
{
@@ -725,12 +701,8 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
VALUE parser = rb_parser_new();
rb_parser_set_context(parser, NULL, FALSE);
ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
-
- rb_thread_t *th = rb_ec_thread_ptr(ec);
- VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
-
iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
- fname, realpath_internal_cached(realpath_map, fname), NULL);
+ fname, rb_realpath_internal(Qnil, fname, 1), NULL);
rb_ast_dispose(ast);
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
@@ -1008,7 +980,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
{
VALUE tmp;
char *ext, *ftptr;
- int ft = 0;
+ int type, ft = 0;
const char *loading;
*path = 0;
@@ -1060,11 +1032,11 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
return 'r';
}
tmp = fname;
- const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
+ type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
// Check if it's a statically linked extension when
// not already a feature and not found as a dynamic library.
- if (!ft && type != loadable_ext_rb && vm->static_ext_inits) {
+ if (!ft && type != 1 && vm->static_ext_inits) {
VALUE lookup_name = tmp;
// Append ".so" if not already present so for example "etc" can find "etc.so".
// We always register statically linked extensions with a ".so" extension.
@@ -1092,13 +1064,13 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
goto feature_present;
}
/* fall through */
- case loadable_ext_rb:
+ case 1:
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
+ if (rb_feature_p(vm, ftptr, ext, !--type, TRUE, &loading) && !loading)
break;
*path = tmp;
}
- return type > loadable_ext_rb ? 's' : 'r';
+ return type ? 's' : 'r';
feature_present:
if (loading) *path = rb_filesystem_str_new_cstr(loading);
@@ -1196,10 +1168,8 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
rb_thread_t *th = rb_ec_thread_ptr(ec);
volatile const struct {
VALUE wrapper, self, errinfo;
- rb_execution_context_t *ec;
} saved = {
th->top_wrapper, th->top_self, ec->errinfo,
- ec,
};
enum ruby_tag_type state;
char *volatile ftptr = 0;
@@ -1238,7 +1208,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
result = TAG_RETURN;
}
else if (RTEST(rb_hash_aref(realpaths,
- realpath = realpath_internal_cached(realpath_map, path)))) {
+ realpath = rb_realpath_internal(Qnil, path, 1)))) {
result = 0;
}
else {
@@ -1261,7 +1231,6 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
}
EC_POP_TAG();
- ec = saved.ec;
rb_thread_t *th2 = rb_ec_thread_ptr(ec);
th2->top_self = saved.self;
th2->top_wrapper = saved.wrapper;
@@ -1299,6 +1268,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
if (real) {
real = rb_fstring(real);
rb_hash_aset(realpaths, real, Qtrue);
+ rb_hash_aset(realpath_map, path, real);
}
}
ec->errinfo = saved.errinfo;
diff --git a/main.c b/main.c
index 072dc56dd5..c87355e46e 100644
--- a/main.c
+++ b/main.c
@@ -23,7 +23,6 @@
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
-
#if defined RUBY_DEVEL && !defined RUBY_DEBUG_ENV
# define RUBY_DEBUG_ENV 1
#endif
@@ -44,10 +43,16 @@ int rb_wasm_rt_start(int (main)(int argc, char **argv), int argc, char **argv);
#define rb_main(argc, argv) rb_wasm_rt_start(rb_main, argc, argv)
#endif
+#ifdef _WIN32
+#define main(argc, argv) w32_main(argc, argv)
+static int main(int argc, char **argv);
+int wmain(void) {return main(0, NULL);}
+#endif
+
int
main(int argc, char **argv)
{
-#if defined(RUBY_DEBUG_ENV) || USE_RUBY_DEBUG_LOG
+#ifdef RUBY_DEBUG_ENV
ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
diff --git a/man/irb.1 b/man/irb.1
index 93ef9b8f66..c589c99c78 100644
--- a/man/irb.1
+++ b/man/irb.1
@@ -140,13 +140,6 @@ Use autocompletion.
Don't use autocompletion.
.Pp
.Pp
-.It Fl -regexp-completor
-Use regexp based completion.
-.Pp
-.It Fl -type-completor
-Use type based completion.
-.Pp
-.Pp
.It Fl -verbose
Show details.
.Pp
diff --git a/man/ruby.1 b/man/ruby.1
index a2b69c3cd6..86ad73c2ab 100644
--- a/man/ruby.1
+++ b/man/ruby.1
@@ -25,7 +25,6 @@
.Op Fl - Ns Bro Cm enable Ns | Ns Cm disable Brc Ns - Ns Ar FEATURE
.Op Fl -dump Ns = Ns Ar target
.Op Fl -verbose
-.Op Fl -crash-report Ns = Ns Ar template
.Op Fl -
.Op Ar program_file
.Op Ar argument ...
@@ -272,11 +271,6 @@ In auto-split mode, Ruby executes
.Dl $F = $_.split
at beginning of each loop.
.Pp
-.It Fl -backtrace-limit Ns = Ns Ar num
-Limits the maximum length of backtraces to
-.Ar num
-lines (default -1, meaning no limit).
-.Pp
.It Fl c
Causes Ruby to check the syntax of the script and exit without
executing. If there are no syntax errors, Ruby will print
@@ -394,7 +388,7 @@ before executing script.
.Pp
.It Fl y
.It Fl -yydebug
-This option is not guaranteed to be compatible.
+DO NOT USE.
.Pp
Turns on compiler debug mode. Ruby will print a bunch of internal
state messages during compilation. Only specify this switch you are going to
@@ -470,12 +464,6 @@ variable to true.
If this switch is given, and no script arguments (script file or
.Fl e
options) are present, Ruby quits immediately.
-.Pp
-.It Fl -crash-report Ns = Ns Ar template
-Sets the template of path name to save crash report.
-See
-.Ev RUBY_CRASH_REPORT
-environment variable for details.
.El
.Pp
.Sh ENVIRONMENT
@@ -562,12 +550,7 @@ There are currently 4 possible areas where the GC may be tuned by
the following 11 environment variables:
.Bl -hang -compact -width "RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR"
.It Ev RUBY_GC_HEAP_INIT_SLOTS
-Initial allocation slots. Applies to all slot sizes. Introduced in Ruby 2.1, default: 10000.
-.Pp
-.It Ev RUBY_GC_HEAP_%d_INIT_SLOTS
-Initial allocation of slots in a specific heap.
-The available heaps can be found in the keys of `GC.stat_heap`.
-Introduced in Ruby 3.3.
+Initial allocation slots. Introduced in Ruby 2.1, default: 10000.
.Pp
.It Ev RUBY_GC_HEAP_FREE_SLOTS
Prepare at least this amount of slots after GC.
@@ -652,61 +635,6 @@ Machine stack size used at fiber creation.
default: 262144 or 524288
.Pp
.El
-.Sh CRASH REPORT ENVIRONMENT
-.Pp
-.Bl -tag -compact -width "RUBY_CRASH_REPORT"
-.It Ev RUBY_CRASH_REPORT
-The template of path name to save crash report.
-default: none
-.El
-.Ss Naming crash report files
-The template can contain
-.Li \fB%\fP
-specifiers which are substituted by the following values when a crash
-report file is created:
-.Pp
-.Bl -hang -compact -width "%NNN"
-.It Li \fB%%\fP
-A single
-.Li \fB%\fP
-character.
-.It Li \fB%e\fP
-Basename of executable.
-.It Li \fB%E\fP
-Pathname of executable,
-with slashes (\fB/\fP) replaced by exclamation marks (\fB!\fP).
-.It Li \fB%f\fP
-Basename of the program name,
-.Li "$0" .
-.It Li \fB%F\fP
-Pathname of the program name,
-.Li "$0",
-with slashes (\fB/\fP) replaced by exclamation marks (\fB!\fP).
-.It Li \fB%p\fP
-PID of dumped process.
-.It Li \fB%t\fP
-Time of dump, expressed as seconds since the
-Epoch, 1970-01-01 00:00:00 +0000 (UTC).
-.It Li \fB%NNN\fP
-A character code in octal.
-.El
-.Pp
-A single
-.Li \fB%\fP
-at the end of the template is dropped from the core filename, as is
-the combination of a
-.Li \fB%\fP
-followed by any character other than those listed above. All other
-characters in the template become a literal part of the core filename.
-The template may include \(aq/\(aq characters, which are interpreted
-as delimiters for directory names.
-.Ss Piping crash reports to a program
-If the first character of this file is a pipe symbol (\fB|\fP),
-then the remainder of the line is interpreted as the command-line for
-a program (or script) that is to be executed.
-.Pp
-The pipe template is split on spaces into an argument list before the
-template parameters are expanded.
.Sh SEE ALSO
.Bl -hang -compact -width "https://www.ruby-toolbox.com/"
.It Lk https://www.ruby-lang.org/
@@ -734,5 +662,5 @@ Ruby is designed and implemented by
.An Yukihiro Matsumoto Aq matz@netlab.jp .
.Pp
See
-.Aq Lk https://github.com/ruby/ruby/graphs/contributors
+.Aq Lk https://bugs.ruby-lang.org/projects/ruby/wiki/Contributors
for contributors to Ruby.
diff --git a/marshal.c b/marshal.c
index ec38c2188a..4ea4255971 100644
--- a/marshal.c
+++ b/marshal.c
@@ -40,6 +40,7 @@
#include "ruby/util.h"
#include "builtin.h"
#include "shape.h"
+#include "ruby/internal/attr/nonstring.h"
#define BITSPERSHORT (2*CHAR_BIT)
#define SHORTMASK ((1<<BITSPERSHORT)-1)
@@ -173,7 +174,7 @@ struct dump_arg {
st_table *data;
st_table *compat_tbl;
st_table *encodings;
- st_index_t num_entries;
+ unsigned long num_entries;
};
struct dump_call_arg {
@@ -523,7 +524,7 @@ hash_each(VALUE key, VALUE value, VALUE v)
#define SINGLETON_DUMP_UNABLE_P(klass) \
(rb_id_table_size(RCLASS_M_TBL(klass)) > 0 || \
- rb_ivar_count(klass) > 0)
+ rb_ivar_count(klass) > 1)
static void
w_extended(VALUE klass, struct dump_arg *arg, int check)
@@ -1501,7 +1502,7 @@ name_equal(const char *name, size_t nlen, const char *p, long l)
static int
sym2encidx(VALUE sym, VALUE val)
{
- static const char name_encoding[8] = "encoding";
+ RBIMPL_ATTR_NONSTRING() static const char name_encoding[8] = "encoding";
const char *p;
long l;
if (rb_enc_get_index(sym) != ENCINDEX_US_ASCII) return -1;
@@ -1803,6 +1804,20 @@ r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
return r_object_for(arg, partial, ivp, extmod, type);
}
+static int
+r_move_ivar(st_data_t k, st_data_t v, st_data_t d)
+{
+ ID key = (ID)k;
+ VALUE value = (VALUE)v;
+ VALUE dest = (VALUE)d;
+
+ if (rb_is_instance_id(key)) {
+ rb_ivar_set(dest, key, value);
+ return ST_DELETE;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type)
{
@@ -1864,7 +1879,6 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
rb_extend_object(v, m);
}
}
- v = r_leave(v, arg, partial);
}
break;
@@ -2020,7 +2034,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
rb_str_set_len(str, dst - ptr);
}
VALUE regexp = rb_reg_new_str(str, options);
- r_copy_ivar(regexp, str);
+ rb_ivar_foreach(str, r_move_ivar, regexp);
v = r_entry0(regexp, idx, arg);
v = r_leave(v, arg, partial);
@@ -2141,12 +2155,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
marshal_compat_t *compat = (marshal_compat_t*)d;
v = compat->loader(klass, v);
}
- if (!partial) {
- if (arg->freeze) {
- OBJ_FREEZE(v);
- }
- v = r_post_proc(v, arg);
- }
+ if (!partial) v = r_post_proc(v, arg);
}
break;
@@ -2171,9 +2180,6 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
load_funcall(arg, v, s_mload, 1, &data);
v = r_fixup_compat(v, arg);
v = r_copy_ivar(v, data);
- if (arg->freeze) {
- OBJ_FREEZE(v);
- }
v = r_post_proc(v, arg);
if (!NIL_P(extmod)) {
if (oldclass) append_extmod(v, extmod);
diff --git a/math.c b/math.c
index 2394fe9f58..67bf8b7b63 100644
--- a/math.c
+++ b/math.c
@@ -170,12 +170,6 @@ math_tan(VALUE unused_obj, VALUE x)
return DBL2NUM(tan(Get_Double(x)));
}
-#define math_arc(num, func) \
- double d; \
- d = Get_Double((num)); \
- domain_check_range(d, -1.0, 1.0, #func); \
- return DBL2NUM(func(d));
-
/*
* call-seq:
* Math.acos(x) -> float
@@ -196,7 +190,11 @@ math_tan(VALUE unused_obj, VALUE x)
static VALUE
math_acos(VALUE unused_obj, VALUE x)
{
- math_arc(x, acos)
+ double d;
+
+ d = Get_Double(x);
+ domain_check_range(d, -1.0, 1.0, "acos");
+ return DBL2NUM(acos(d));
}
/*
@@ -219,7 +217,11 @@ math_acos(VALUE unused_obj, VALUE x)
static VALUE
math_asin(VALUE unused_obj, VALUE x)
{
- math_arc(x, asin)
+ double d;
+
+ d = Get_Double(x);
+ domain_check_range(d, -1.0, 1.0, "asin");
+ return DBL2NUM(asin(d));
}
/*
@@ -474,6 +476,7 @@ math_exp(VALUE unused_obj, VALUE x)
# define M_LN10 2.30258509299404568401799145468436421
#endif
+static double math_log1(VALUE x);
FUNC_MINIMIZED(static VALUE math_log(int, const VALUE *, VALUE));
/*
@@ -508,6 +511,20 @@ math_log(int argc, const VALUE *argv, VALUE unused_obj)
return rb_math_log(argc, argv);
}
+VALUE
+rb_math_log(int argc, const VALUE *argv)
+{
+ VALUE x, base;
+ double d;
+
+ rb_scan_args(argc, argv, "11", &x, &base);
+ d = math_log1(x);
+ if (argc == 2) {
+ d /= math_log1(base);
+ }
+ return DBL2NUM(d);
+}
+
static double
get_double_rshift(VALUE x, size_t *pnumbits)
{
@@ -526,51 +543,16 @@ get_double_rshift(VALUE x, size_t *pnumbits)
}
static double
-math_log_split(VALUE x, size_t *numbits)
+math_log1(VALUE x)
{
- double d = get_double_rshift(x, numbits);
+ size_t numbits;
+ double d = get_double_rshift(x, &numbits);
domain_check_min(d, 0.0, "log");
- return d;
-}
-
-#if defined(log2) || defined(HAVE_LOG2)
-# define log_intermediate log2
-#else
-# define log_intermediate log10
-double log2(double x);
-#endif
-
-VALUE
-rb_math_log(int argc, const VALUE *argv)
-{
- VALUE x, base;
- double d;
- size_t numbits;
+ /* check for pole error */
+ if (d == 0.0) return -HUGE_VAL;
- argc = rb_scan_args(argc, argv, "11", &x, &base);
- d = math_log_split(x, &numbits);
- if (argc == 2) {
- size_t numbits_2;
- double b = math_log_split(base, &numbits_2);
- /* check for pole error */
- if (d == 0.0) {
- // Already DomainError if b < 0.0
- return b ? DBL2NUM(-HUGE_VAL) : DBL2NUM(NAN);
- }
- else if (b == 0.0) {
- return DBL2NUM(-0.0);
- }
- d = log_intermediate(d) / log_intermediate(b);
- d += (numbits - numbits_2) / log2(b);
- }
- else {
- /* check for pole error */
- if (d == 0.0) return DBL2NUM(-HUGE_VAL);
- d = log(d);
- d += numbits * M_LN2;
- }
- return DBL2NUM(d);
+ return log(d) + numbits * M_LN2; /* log(d * 2 ** numbits) */
}
#ifndef log2
@@ -731,7 +713,7 @@ rb_math_sqrt(VALUE x)
* cbrt(1.0) # => 1.0
* cbrt(0.0) # => 0.0
* cbrt(1.0) # => 1.0
- * cbrt(2.0) # => 1.2599210498948732
+ cbrt(2.0) # => 1.2599210498948732
* cbrt(8.0) # => 2.0
* cbrt(27.0) # => 3.0
* cbrt(INFINITY) # => Infinity
diff --git a/method.h b/method.h
index fece2e54c3..ec89bf26bb 100644
--- a/method.h
+++ b/method.h
@@ -200,7 +200,7 @@ struct rb_method_definition_struct {
struct rb_id_table;
typedef struct rb_method_definition_struct rb_method_definition_t;
-STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body) <= 8);
+STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body)==8);
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
#define UNDEFINED_REFINED_METHOD_P(def) \
@@ -250,6 +250,6 @@ void rb_scope_visibility_set(rb_method_visibility_t);
VALUE rb_unnamed_parameters(int arity);
void rb_clear_method_cache(VALUE klass_or_module, ID mid);
-void rb_clear_all_refinement_method_cache(void);
+void rb_clear_method_cache_all(void);
#endif /* RUBY_METHOD_H */
diff --git a/mini_builtin.c b/mini_builtin.c
index a0bb46c54c..c263d1ee71 100644
--- a/mini_builtin.c
+++ b/mini_builtin.c
@@ -21,22 +21,18 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
rb_ast_t *ast = rb_builtin_ast(feature_name, &name_str);
rb_vm_t *vm = GET_VM();
- if (!ast) {
- rb_fatal("builtin_iseq_load: can not find %s; "
- "probably miniprelude.c is out of date",
- feature_name);
- }
vm->builtin_function_table = table;
vm->builtin_inline_index = 0;
static const rb_compile_option_t optimization = {
- TRUE, /* unsigned int inline_const_cache; */
- TRUE, /* unsigned int peephole_optimization; */
- FALSE,/* unsigned int tailcall_optimization; */
- TRUE, /* unsigned int specialized_instruction; */
- TRUE, /* unsigned int operands_unification; */
- TRUE, /* unsigned int instructions_unification; */
- TRUE, /* unsigned int frozen_string_literal; */
- FALSE, /* unsigned int debug_frozen_string_literal; */
+ TRUE, /* int inline_const_cache; */
+ TRUE, /* int peephole_optimization; */
+ FALSE,/* int tailcall_optimization; */
+ TRUE, /* int specialized_instruction; */
+ TRUE, /* int operands_unification; */
+ TRUE, /* int instructions_unification; */
+ TRUE, /* int stack_caching; */
+ TRUE, /* int frozen_string_literal; */
+ FALSE, /* int debug_frozen_string_literal; */
FALSE, /* unsigned int coverage_enabled; */
0, /* int debug_level; */
};
diff --git a/misc/.vscode/launch.json b/misc/.vscode/launch.json
deleted file mode 100644
index 51bfef09d7..0000000000
--- a/misc/.vscode/launch.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "type": "lldb",
- "name": "Run ruby",
- "request": "launch",
- "program": "${workspaceFolder}/ruby",
- "args": ["test.rb"],
- "preLaunchTask": "${defaultBuildTask}"
- }
- ]
-}
diff --git a/misc/.vscode/settings.json b/misc/.vscode/settings.json
deleted file mode 100644
index 7b1a38c536..0000000000
--- a/misc/.vscode/settings.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "rust-analyzer.cargo.features": [
- "disasm",
- ],
- "rust-analyzer.cargo.unsetTest": [
- "yjit",
- ],
-}
diff --git a/misc/.vscode/tasks.json b/misc/.vscode/tasks.json
deleted file mode 100644
index 045fe7e5c0..0000000000
--- a/misc/.vscode/tasks.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "build",
- "type": "shell",
- "command": "make -j",
- "group": {
- "kind": "build",
- "isDefault": true
- }
- }
- ]
-}
diff --git a/misc/README b/misc/README
index 86b680e724..1728b42700 100644
--- a/misc/README
+++ b/misc/README
@@ -4,4 +4,3 @@ rb_optparse.zsh zsh completion script
ruby-style.el Ruby's C/C++ mode style for emacs
lldb_cruby.py LLDB port of debug utility
test_lldb_cruby.rb test file for LLDB port
-.vscode example VSCode config to debug Ruby
diff --git a/misc/gdb.py b/misc/gdb.py
deleted file mode 100644
index 6034a389bb..0000000000
--- a/misc/gdb.py
+++ /dev/null
@@ -1,181 +0,0 @@
-import argparse
-import textwrap
-
-# usage: [-h] [-a | --all | --no-all] [-s STACK_SIZE] [uplevel]
-#
-# Dump a control frame
-#
-# positional arguments:
-# uplevel CFP offset from the stack top
-#
-# options:
-# -h, --help show this help message and exit
-# -a, --all, --no-all dump all frames
-# -s STACK_SIZE, --stack-size STACK_SIZE
-# override stack_size (useful for JIT frames)
-class CFP(gdb.Command):
- FRAME_MAGICS = [
- # frame types
- 'VM_FRAME_MAGIC_METHOD',
- 'VM_FRAME_MAGIC_BLOCK',
- 'VM_FRAME_MAGIC_CLASS',
- 'VM_FRAME_MAGIC_TOP',
- 'VM_FRAME_MAGIC_CFUNC',
- 'VM_FRAME_MAGIC_IFUNC',
- 'VM_FRAME_MAGIC_EVAL',
- 'VM_FRAME_MAGIC_RESCUE',
- 'VM_FRAME_MAGIC_DUMMY',
- ]
- FRAME_FLAGS = [
- # frame flag
- 'VM_FRAME_FLAG_FINISH',
- 'VM_FRAME_FLAG_BMETHOD',
- 'VM_FRAME_FLAG_CFRAME',
- 'VM_FRAME_FLAG_LAMBDA',
- 'VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM',
- 'VM_FRAME_FLAG_CFRAME_KW',
- 'VM_FRAME_FLAG_PASSED',
- # env flag
- 'VM_ENV_FLAG_LOCAL',
- 'VM_ENV_FLAG_ESCAPED',
- 'VM_ENV_FLAG_WB_REQUIRED',
- 'VM_ENV_FLAG_ISOLATED',
- ]
-
- def __init__(self):
- super(CFP, self).__init__('cfp', gdb.COMMAND_USER)
-
- self.parser = argparse.ArgumentParser(description='Dump a control frame')
- self.parser.add_argument('uplevel', type=int, nargs='?', default=0, help='CFP offset from the stack top')
- self.parser.add_argument('-a', '--all', action=argparse.BooleanOptionalAction, help='dump all frames')
- self.parser.add_argument('-s', '--stack-size', type=int, help='override stack_size (useful for JIT frames)')
-
- def invoke(self, args, from_tty):
- try:
- args = self.parser.parse_args(args.split())
- except SystemExit:
- return
- cfp = f'(ruby_current_ec->cfp + ({args.uplevel}))'
- end_cfp = self.get_int('ruby_current_ec->vm_stack + ruby_current_ec->vm_stack_size')
- cfp_index = int((end_cfp - self.get_int(cfp) - 1) / self.get_int('sizeof(rb_control_frame_t)'))
-
- if args.all:
- cfp_count = int((end_cfp - self.get_int('ruby_current_ec->cfp')) / self.get_int('sizeof(rb_control_frame_t)')) - 1 # exclude dummy CFP
- for i in range(cfp_count):
- print('-' * 80)
- self.invoke(str(cfp_count - i - 1), from_tty)
- return
-
- print('CFP (addr=0x{:x}, index={}):'.format(self.get_int(cfp), cfp_index))
- gdb.execute(f'p *({cfp})')
- print()
-
- if self.get_int(f'{cfp}->iseq'):
- local_size = self.get_int(f'{cfp}->iseq->body->local_table_size - {cfp}->iseq->body->param.size')
- param_size = self.get_int(f'{cfp}->iseq->body->param.size')
-
- if local_size:
- print(f'Params (size={param_size}):')
- for i in range(-3 - local_size - param_size, -3 - local_size):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print()
-
- if param_size:
- print(f'Locals (size={local_size}):')
- for i in range(-3 - local_size, -3):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print()
-
- print('Env:')
- self.print_env(cfp, -3, self.rp_env(cfp, -3))
- self.print_env(cfp, -2, self.specval(cfp, -2))
- self.print_env(cfp, -1, self.frame_types(cfp, -1))
- print()
-
- # We can't calculate BP for the first frame.
- # vm_base_ptr doesn't work for C frames either.
- if cfp_index > 0 and self.get_int(f'{cfp}->iseq'):
- if args.stack_size is not None:
- stack_size = args.stack_size
- else:
- stack_size = int((self.get_int(f'{cfp}->sp') - self.get_int(f'vm_base_ptr({cfp})')) / 8)
- print(f'Stack (size={stack_size}):')
- for i in range(0, stack_size):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print(self.regs(cfp, stack_size))
-
- def print_env(self, cfp, bp_index, content):
- ep_index = bp_index + 1
- address = self.get_int(f'((rb_control_frame_t *){cfp})->ep + {ep_index}')
- value = self.get_env(cfp, bp_index)
- regs = self.regs(cfp, bp_index)
- if content:
- content = textwrap.indent(content, ' ' * 3).lstrip() # Leave the regs column empty
- content = f'{content} '
- print('{:2} 0x{:x} [{}] {}(0x{:x})'.format(regs, address, bp_index, content, value))
-
- def print_stack(self, cfp, bp_index, content):
- address = self.get_int(f'vm_base_ptr({cfp}) + {bp_index}')
- value = self.get_value(cfp, bp_index)
- regs = self.regs(cfp, bp_index)
- if content:
- content = textwrap.indent(content, ' ' * 3).lstrip() # Leave the regs column empty
- content = f'{content} '
- print('{:2} 0x{:x} [{}] {}(0x{:x})'.format(regs, address, bp_index, content, value))
-
- def regs(self, cfp, bp_index):
- address = self.get_int(f'vm_base_ptr({cfp}) + {bp_index}')
- regs = []
- for reg, field in { 'EP': 'ep', 'SP': 'sp' }.items():
- if address == self.get_int(f'{cfp}->{field}'):
- regs.append(reg)
- return ' '.join(regs)
-
- def rp(self, cfp, bp_index):
- value = self.get_value(cfp, bp_index)
- return self.get_string(f'rp {value}').rstrip()
-
- def rp_env(self, cfp, bp_index):
- value = self.get_env(cfp, bp_index)
- return self.get_string(f'rp {value}').rstrip()
-
- # specval: block_handler or previous EP
- def specval(self, cfp, bp_index):
- value = self.get_env(cfp, bp_index)
- if value == 0:
- return 'VM_BLOCK_HANDLER_NONE'
- if value == self.get_int('rb_block_param_proxy'):
- return 'rb_block_param_proxy'
- return ''
-
- def frame_types(self, cfp, bp_index):
- types = []
- value = self.get_env(cfp, bp_index)
-
- magic_mask = self.get_int('VM_FRAME_MAGIC_MASK')
- for magic in self.FRAME_MAGICS:
- magic_value = self.get_int(magic)
- if value & magic_mask == magic_value:
- types.append(magic)
-
- for flag in self.FRAME_FLAGS:
- flag_value = self.get_int(flag)
- if value & flag_value:
- types.append(flag)
-
- return ' | '.join(types)
-
- def get_env(self, cfp, bp_index):
- ep_index = bp_index + 1
- return self.get_int(f'((rb_control_frame_t *){cfp})->ep[{ep_index}]')
-
- def get_value(self, cfp, bp_index):
- return self.get_int(f'vm_base_ptr({cfp})[{bp_index}]')
-
- def get_int(self, expr):
- return int(self.get_string(f'printf "%ld", ({expr})'))
-
- def get_string(self, expr):
- return gdb.execute(expr, to_string=True)
-
-CFP()
diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py
index 400ccb45b9..9ef9d3967b 100755
--- a/misc/lldb_cruby.py
+++ b/misc/lldb_cruby.py
@@ -197,16 +197,18 @@ def string2cstr(rstring):
flags = rstring.GetValueForExpressionPath(".basic->flags").unsigned
if flags & RUBY_T_MASK != RUBY_T_STRING:
raise TypeError("not a string")
- clen = int(rstring.GetValueForExpressionPath(".len").value, 0)
if flags & RUBY_FL_USER1:
cptr = int(rstring.GetValueForExpressionPath(".as.heap.ptr").value, 0)
+ clen = int(rstring.GetValueForExpressionPath(".as.heap.len").value, 0)
else:
cptr = int(rstring.GetValueForExpressionPath(".as.embed.ary").location, 0)
+ clen = int(rstring.GetValueForExpressionPath(".as.embed.len").value, 0)
return cptr, clen
def output_string(debugger, result, rstring):
cptr, clen = string2cstr(rstring)
- append_expression(debugger, "*(const char (*)[%d])%0#x" % (clen, cptr), result)
+ expr = "print *(const char (*)[%d])%0#x" % (clen, cptr)
+ append_command_output(debugger, expr, result)
def fixnum_p(x):
return x & RUBY_FIXNUM_FLAG != 0
@@ -225,9 +227,6 @@ def append_command_output(debugger, command, result):
result.write(output1)
result.write(output2)
-def append_expression(debugger, expression, result):
- append_command_output(debugger, "expression " + expression, result)
-
def lldb_rp(debugger, command, result, internal_dict):
if not ('RUBY_Qfalse' in globals()):
lldb_init(debugger)
@@ -259,13 +258,13 @@ def lldb_inspect(debugger, target, result, val):
elif fixnum_p(num):
print(num >> 1, file=result)
elif flonum_p(num):
- append_expression(debugger, "rb_float_value(%0#x)" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print rb_float_value(%0#x)" % val.GetValueAsUnsigned(), result)
elif static_sym_p(num):
if num < 128:
print("T_SYMBOL: %c" % num, file=result)
else:
print("T_SYMBOL: (%x)" % num, file=result)
- append_expression(debugger, "rb_id2name(%0#x)" % (num >> 8), result)
+ append_command_output(debugger, "p rb_id2name(%0#x)" % (num >> 8), result)
elif num & RUBY_IMMEDIATE_MASK:
print('immediate(%x)' % num, file=result)
else:
@@ -293,13 +292,13 @@ def lldb_inspect(debugger, target, result, val):
print('T_NIL: %s%s' % (flaginfo, val.Dereference()), file=result)
elif flType == RUBY_T_OBJECT:
result.write('T_OBJECT: %s' % flaginfo)
- append_expression(debugger, "*(struct RObject*)%0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print *(struct RObject*)%0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_CLASS or flType == RUBY_T_MODULE or flType == RUBY_T_ICLASS:
result.write('T_%s: %s' % ('CLASS' if flType == RUBY_T_CLASS else 'MODULE' if flType == RUBY_T_MODULE else 'ICLASS', flaginfo))
- append_expression(debugger, "*(struct RClass*)%0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print *(struct RClass*)%0#x" % val.GetValueAsUnsigned(), result)
tRClass = target.FindFirstType("struct RClass")
if not val.Cast(tRClass).GetChildMemberWithName("ptr").IsValid():
- append_expression(debugger, "*(struct rb_classext_struct*)%0#x" % (val.GetValueAsUnsigned() + tRClass.GetByteSize()), result)
+ append_command_output(debugger, "print *(struct rb_classext_struct*)%0#x" % (val.GetValueAsUnsigned() + tRClass.GetByteSize()), result)
elif flType == RUBY_T_STRING:
result.write('T_STRING: %s' % flaginfo)
encidx = ((flags & RUBY_ENCODING_MASK)>>RUBY_ENCODING_SHIFT)
@@ -313,12 +312,12 @@ def lldb_inspect(debugger, target, result, val):
if len == 0:
result.write("(empty)\n")
else:
- append_expression(debugger, "*(const char (*)[%d])%0#x" % (len, ptr), result)
+ append_command_output(debugger, "print *(const char (*)[%d])%0#x" % (len, ptr), result)
elif flType == RUBY_T_SYMBOL:
result.write('T_SYMBOL: %s' % flaginfo)
tRSymbol = target.FindFirstType("struct RSymbol").GetPointerType()
val = val.Cast(tRSymbol)
- append_expression(debugger, '(ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned(), result)
+ append_command_output(debugger, 'print (ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned(), result)
tRString = target.FindFirstType("struct RString").GetPointerType()
output_string(debugger, result, val.GetValueForExpressionPath("->fstr").Cast(tRString))
elif flType == RUBY_T_ARRAY:
@@ -344,12 +343,12 @@ def lldb_inspect(debugger, target, result, val):
else:
result.write("\n")
if ptr.GetValueAsSigned() == 0:
- append_expression(debugger, "-fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "expression -fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned(), result)
else:
- append_expression(debugger, "-Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()), result)
+ append_command_output(debugger, "expression -Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()), result)
elif flType == RUBY_T_HASH:
result.write("T_HASH: %s" % flaginfo)
- append_expression(debugger, "*(struct RHash *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RHash *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_BIGNUM:
tRBignum = target.FindFirstType("struct RBignum").GetPointerType()
val = val.Cast(tRBignum)
@@ -357,15 +356,15 @@ def lldb_inspect(debugger, target, result, val):
if flags & RUBY_FL_USER2:
len = ((flags & (RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5)) >> (RUBY_FL_USHIFT+3))
print("T_BIGNUM: sign=%s len=%d (embed)" % (sign, len), file=result)
- append_expression(debugger, "((struct RBignum *) %0#x)->as.ary" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print ((struct RBignum *) %0#x)->as.ary" % val.GetValueAsUnsigned(), result)
else:
len = val.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()
print("T_BIGNUM: sign=%s len=%d" % (sign, len), file=result)
print(val.Dereference(), file=result)
- append_expression(debugger, "-Z %x -fx -- (const BDIGIT*)((struct RBignum*)%d)->as.heap.digits" % (len, val.GetValueAsUnsigned()), result)
- # append_expression(debugger, "((struct RBignum *) %0#x)->as.heap.digits / %d" % (val.GetValueAsUnsigned(), len), result)
+ append_command_output(debugger, "expression -Z %x -fx -- (const BDIGIT*)((struct RBignum*)%d)->as.heap.digits" % (len, val.GetValueAsUnsigned()), result)
+ # append_command_output(debugger, "x ((struct RBignum *) %0#x)->as.heap.digits / %d" % (val.GetValueAsUnsigned(), len), result)
elif flType == RUBY_T_FLOAT:
- append_expression(debugger, "((struct RFloat *)%d)->float_value" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print ((struct RFloat *)%d)->float_value" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_RATIONAL:
tRRational = target.FindFirstType("struct RRational").GetPointerType()
val = val.Cast(tRRational)
@@ -398,39 +397,39 @@ def lldb_inspect(debugger, target, result, val):
flag = val.GetValueForExpressionPath("->typed_flag")
if flag.GetValueAsUnsigned() == 1:
print("T_DATA: %s" % val.GetValueForExpressionPath("->type->wrap_struct_name"), file=result)
- append_expression(debugger, "*(struct RTypedData *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RTypedData *) %0#x" % val.GetValueAsUnsigned(), result)
else:
print("T_DATA:", file=result)
- append_expression(debugger, "*(struct RData *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RData *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_NODE:
tRTypedData = target.FindFirstType("struct RNode").GetPointerType()
nd_type = (flags & RUBY_NODE_TYPEMASK) >> RUBY_NODE_TYPESHIFT
- append_expression(debugger, "(node_type) %d" % nd_type, result)
+ append_command_output(debugger, "p (node_type) %d" % nd_type, result)
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RNode *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RNode *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_MOVED:
tRTypedData = target.FindFirstType("struct RMoved").GetPointerType()
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RMoved *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RMoved *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_MATCH:
tRTypedData = target.FindFirstType("struct RMatch").GetPointerType()
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RMatch *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RMatch *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_IMEMO:
# I'm not sure how to get IMEMO_MASK out of lldb. It's not in globals()
imemo_type = (flags >> RUBY_FL_USHIFT) & 0x0F # IMEMO_MASK
print("T_IMEMO: ", file=result)
- append_expression(debugger, "(enum imemo_type) %d" % imemo_type, result)
- append_expression(debugger, "*(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p (enum imemo_type) %d" % imemo_type, result)
+ append_command_output(debugger, "p *(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_STRUCT:
tRTypedData = target.FindFirstType("struct RStruct").GetPointerType()
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RStruct *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RStruct *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_ZOMBIE:
tRZombie = target.FindFirstType("struct RZombie").GetPointerType()
val = val.Cast(tRZombie)
- append_expression(debugger, "*(struct RZombie *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RZombie *) %0#x" % val.GetValueAsUnsigned(), result)
else:
print("Not-handled type %0#x" % flType, file=result)
print(val, file=result)
@@ -728,13 +727,13 @@ def __lldb_init_module(debugger, internal_dict):
# Register all classes that subclass RbBaseCommand
for memname, mem in inspect.getmembers(sys.modules["lldb_rb.rb_base_command"]):
- if memname == "RbBaseCommand":
+ if inspect.isclass(mem):
for sclass in mem.__subclasses__():
sclass.register_lldb_command(debugger, f"{__name__}.{sclass.__module__}")
## FUNCTION INITS - These should be removed when converted to class commands
- debugger.HandleCommand("command script add -f lldb_cruby.lldb_rp old_rp")
+ debugger.HandleCommand("command script add -f lldb_cruby.lldb_rp rp")
debugger.HandleCommand("command script add -f lldb_cruby.count_objects rb_count_objects")
debugger.HandleCommand("command script add -f lldb_cruby.stack_dump_raw SDR")
debugger.HandleCommand("command script add -f lldb_cruby.dump_node dump_node")
@@ -742,7 +741,7 @@ def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("command script add -f lldb_cruby.rb_backtrace rbbt")
debugger.HandleCommand("command script add -f lldb_cruby.dump_page dump_page")
debugger.HandleCommand("command script add -f lldb_cruby.dump_page_rvalue dump_page_rvalue")
- debugger.HandleCommand("command script add -f lldb_cruby.rb_id2str old_rb_id2str")
+ debugger.HandleCommand("command script add -f lldb_cruby.rb_id2str rb_id2str")
lldb_rb.rb_base_command.RbBaseCommand.lldb_init(debugger)
diff --git a/misc/lldb_rb/commands/heap_page_command.py b/misc/lldb_rb/commands/heap_page_command.py
index b56a3eae4e..edb74a415b 100644
--- a/misc/lldb_rb/commands/heap_page_command.py
+++ b/misc/lldb_rb/commands/heap_page_command.py
@@ -14,8 +14,8 @@ class HeapPageCommand(RbBaseCommand):
page = self._get_page(self.frame.EvaluateExpression(command))
page.Cast(self.t_heap_page_ptr)
- self._append_expression(debugger, "(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
- self._append_expression(debugger, "*(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
+ self._append_command_output(debugger, "p (struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
+ self._append_command_output(debugger, "p *(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
def _get_page(self, val):
addr = val.GetValueAsUnsigned()
diff --git a/misc/lldb_rb/commands/print_flags_command.py b/misc/lldb_rb/commands/print_flags_command.py
deleted file mode 100644
index 00da4834bf..0000000000
--- a/misc/lldb_rb/commands/print_flags_command.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import lldb
-import re
-
-from lldb_rb.constants import *
-from lldb_rb.rb_base_command import RbBaseCommand
-
-class PrintFlagsCommand(RbBaseCommand):
- program = "print_flags"
-
- help_string = "Print out the individial flags of an RVALUE object in human readable format"
-
- # call is where our command logic will be implemented
- def call(self, debugger, command, exe_ctx, result):
- rclass_t = self.target.FindFirstType("struct RBasic")
- rcass_ptr = self.target.EvaluateExpression(command).Cast(rclass_t.GetPointerType())
- obj_flags = rcass_ptr.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
-
- flags = [
- "RUBY_FL_WB_PROTECTED", "RUBY_FL_PROMOTED0", "RUBY_FL_PROMOTED1", "RUBY_FL_FINALIZE",
- "RUBY_FL_SHAREABLE", "RUBY_FL_EXIVAR", "RUBY_FL_FREEZE",
- "RUBY_FL_USER0", "RUBY_FL_USER1", "RUBY_FL_USER2", "RUBY_FL_USER3", "RUBY_FL_USER4",
- "RUBY_FL_USER5", "RUBY_FL_USER6", "RUBY_FL_USER7", "RUBY_FL_USER8", "RUBY_FL_USER9",
- "RUBY_FL_USER10", "RUBY_FL_USER11", "RUBY_FL_USER12", "RUBY_FL_USER13", "RUBY_FL_USER14",
- "RUBY_FL_USER15", "RUBY_FL_USER16", "RUBY_FL_USER17", "RUBY_FL_USER18"
- ]
-
- types_index = {v: k for k, v in self.ruby_globals.items() if re.match(r'RUBY_T_', k)}
- print("TYPE: {}".format(types_index[obj_flags & self.ruby_globals["RUBY_T_MASK"]]))
- for flag in flags:
- output = "{} : {}".format(flag, "1" if (obj_flags & self.ruby_globals[flag]) else "0")
- print(output, file=result)
diff --git a/misc/lldb_rb/commands/rb_id2str_command.py b/misc/lldb_rb/commands/rb_id2str_command.py
deleted file mode 100644
index 6ee859ebf6..0000000000
--- a/misc/lldb_rb/commands/rb_id2str_command.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import lldb
-
-from lldb_rb.constants import *
-from lldb_rb.utils import *
-from lldb_rb.rb_base_command import RbBaseCommand
-
-class RbID2StrCommand(RbBaseCommand):
- program = "rb_id2str"
-
- help_string = "convert and print a Ruby ID to a C string and print it to the LLDB console"
-
- def call(self, debugger, command, exe_ctx, result):
- global_symbols = self.target.FindFirstGlobalVariable("ruby_global_symbols")
-
- id_val = self.frame.EvaluateExpression(command).GetValueAsUnsigned()
- num = self.rb_id_to_serial(id_val)
-
- last_id = global_symbols.GetChildMemberWithName("last_id").GetValueAsUnsigned()
- ID_ENTRY_SIZE = 2
- ID_ENTRY_UNIT = int(self.target.FindFirstGlobalVariable("ID_ENTRY_UNIT").GetValue())
-
- ids = global_symbols.GetChildMemberWithName("ids")
-
- if num <= last_id:
- idx = num // ID_ENTRY_UNIT
- ary = self.rb_ary_entry(ids, idx, result)
- pos = (num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE
- id_str = self.rb_ary_entry(ary, pos, result)
-
- RbInspector(debugger, result, self.ruby_globals).inspect(id_str)
-
- def rb_id_to_serial(self, id_val):
- if id_val > self.ruby_globals["tLAST_OP_ID"]:
- return id_val >> self.ruby_globals["RUBY_ID_SCOPE_SHIFT"]
- else:
- return id_val
-
- def rb_ary_entry(self, ary, idx, result):
- tRArray = self.target.FindFirstType("struct RArray").GetPointerType()
- ary = ary.Cast(tRArray)
- flags = ary.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
-
- if flags & self.ruby_globals["RUBY_FL_USER1"]:
- ptr = ary.GetValueForExpressionPath("->as.ary")
- else:
- ptr = ary.GetValueForExpressionPath("->as.heap.ptr")
-
- ptr_addr = ptr.GetValueAsUnsigned() + (idx * ptr.GetType().GetByteSize())
- return self.target.CreateValueFromAddress("ary_entry[%d]" % idx, lldb.SBAddress(ptr_addr, self.target), ptr.GetType().GetPointeeType())
diff --git a/misc/lldb_rb/commands/rp_command.py b/misc/lldb_rb/commands/rp_command.py
deleted file mode 100644
index 06b2516d50..0000000000
--- a/misc/lldb_rb/commands/rp_command.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import lldb
-
-from lldb_rb.constants import *
-from lldb_rb.utils import *
-from lldb_rb.rb_base_command import RbBaseCommand
-
-class RbID2StrCommand(RbBaseCommand):
- program = "rp"
-
- help_string = "convert and print a Ruby ID to a C string and print it to the LLDB console"
-
- def call(self, debugger, command, exe_ctx, result):
- val = self.frame.EvaluateExpression(command)
- inspector = RbInspector(debugger, result, self.ruby_globals)
- inspector.inspect(val)
diff --git a/misc/lldb_rb/constants.py b/misc/lldb_rb/constants.py
index 9cd56eccb0..ec3050a399 100644
--- a/misc/lldb_rb/constants.py
+++ b/misc/lldb_rb/constants.py
@@ -2,5 +2,3 @@ HEAP_PAGE_ALIGN_LOG = 16
HEAP_PAGE_ALIGN_MASK = (~(~0 << HEAP_PAGE_ALIGN_LOG))
HEAP_PAGE_ALIGN = (1 << HEAP_PAGE_ALIGN_LOG)
HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN
-
-IMEMO_MASK = 0x0F
diff --git a/misc/lldb_rb/lldb_interface.py b/misc/lldb_rb/lldb_interface.py
deleted file mode 100644
index 785a54b3e3..0000000000
--- a/misc/lldb_rb/lldb_interface.py
+++ /dev/null
@@ -1,7 +0,0 @@
-class LLDBInterface:
- def build_environment(self, debugger):
- self.debugger = debugger
- self.target = debugger.GetSelectedTarget()
- self.process = self.target.GetProcess()
- self.thread = self.process.GetSelectedThread()
- self.frame = self.thread.GetSelectedFrame()
diff --git a/misc/lldb_rb/rb_base_command.py b/misc/lldb_rb/rb_base_command.py
index 70a5addd6d..de90a1617c 100644
--- a/misc/lldb_rb/rb_base_command.py
+++ b/misc/lldb_rb/rb_base_command.py
@@ -1,9 +1,7 @@
import lldb
from pydoc import locate
-from lldb_rb.constants import *
-from lldb_rb.utils import *
-class RbBaseCommand(LLDBInterface):
+class RbBaseCommand:
@classmethod
def register_lldb_command(cls, debugger, module_name):
# Add any commands contained in this module to LLDB
@@ -36,14 +34,14 @@ class RbBaseCommand(LLDBInterface):
if name.startswith("RUBY_T_"):
value_types.append(name)
g["value_types"] = value_types
- return g
def __init__(self, debugger, _internal_dict):
- self.ruby_globals = RbBaseCommand.lldb_init(debugger)
self.internal_dict = _internal_dict
def __call__(self, debugger, command, exe_ctx, result):
- self.ruby_globals = RbBaseCommand.lldb_init(debugger)
+ if not ("RUBY_Qfalse" in globals()):
+ RbBaseCommand.lldb_init(debugger)
+
self.build_environment(debugger)
self.call(debugger, command, exe_ctx, result)
@@ -55,3 +53,17 @@ class RbBaseCommand(LLDBInterface):
def get_long_help(self):
return self.__class__.help_string
+
+ def build_environment(self, debugger):
+ self.target = debugger.GetSelectedTarget()
+ self.process = self.target.GetProcess()
+ self.thread = self.process.GetSelectedThread()
+ self.frame = self.thread.GetSelectedFrame()
+
+ def _append_command_output(self, debugger, command, result):
+ output1 = result.GetOutput()
+ debugger.GetCommandInterpreter().HandleCommand(command, result)
+ output2 = result.GetOutput()
+ result.Clear()
+ result.write(output1)
+ result.write(output2)
diff --git a/misc/lldb_rb/rb_heap_structs.py b/misc/lldb_rb/rb_heap_structs.py
deleted file mode 100644
index 86b38dbbbd..0000000000
--- a/misc/lldb_rb/rb_heap_structs.py
+++ /dev/null
@@ -1,143 +0,0 @@
-import lldb
-from lldb_rb.lldb_interface import LLDBInterface
-from lldb_rb.constants import *
-
-class HeapPage(LLDBInterface):
- def __init__(self, debugger, val):
- self.build_environment(debugger)
- self.page_type = self.target.FindFirstType("struct heap_page").GetPointerType()
- self.val = val
-
- def heap_page_body(self, command, ctx, result, internal_dict):
- process = self.target.GetProcess()
- thread = process.GetSelectedThread()
- frame = thread.GetSelectedFrame()
-
- val = frame.EvaluateExpression(command)
- page = self.get_page_body(val)
- print("Page body address: ", page.GetAddress(), file=result)
- print(page, file=result)
-
- def get_page_body(self, val):
- tHeapPageBody = self.target.FindFirstType("struct heap_page_body")
- addr = val.GetValueAsUnsigned()
- page_addr = addr & ~(HEAP_PAGE_ALIGN_MASK)
- address = lldb.SBAddress(page_addr, self.target)
- return self.target.CreateValueFromAddress("page", address, tHeapPageBody)
-
- def get_page_raw(self, val):
- body = self.get_page_body(val)
- return body.GetValueForExpressionPath("->header.page")
-
- def to_heap_page_struct(self):
- pagePtr = self.get_page_raw(self.val)
- return pagePtr.Cast(self.page_type)
-
-
-class RbObject(LLDBInterface):
- def __init__(self, ptr, debugger, ruby_globals):
- self.build_environment(debugger)
- self.ruby_globals = ruby_globals
-
- self.flUser1 = self.ruby_globals["RUBY_FL_USER1"]
- self.flUser2 = self.ruby_globals["RUBY_FL_USER2"]
- self.flUser3 = self.ruby_globals["RUBY_FL_USER3"]
- self.flUser4 = self.ruby_globals["RUBY_FL_USER4"]
- self.flUser5 = self.ruby_globals["RUBY_FL_USER5"]
- self.flUser6 = self.ruby_globals["RUBY_FL_USER6"]
- self.flUser7 = self.ruby_globals["RUBY_FL_USER7"]
- self.flUser8 = self.ruby_globals["RUBY_FL_USER8"]
- self.flUser9 = self.ruby_globals["RUBY_FL_USER9"]
- self.flUshift = self.ruby_globals["RUBY_FL_USHIFT"]
-
- self.tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
- self.tRValue = self.target.FindFirstType("struct RVALUE")
-
- self.val = ptr.Cast(self.tRBasic)
- self.page = HeapPage(self.debugger, self.val)
- self.flags = self.val.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
-
- self.type = None
- self.type_name = ""
-
- def check_bits(self, bitmap_name, bitmap_index, bitmap_bit, v):
- page = self.page.to_heap_page_struct()
- bits = page.GetChildMemberWithName(bitmap_name)
- plane = bits.GetChildAtIndex(bitmap_index).GetValueAsUnsigned()
- if (plane & bitmap_bit) != 0:
- return v
- else:
- return ' '
-
- def dump_bits(self, result, end = "\n"):
- tRValue = self.target.FindFirstType("struct RVALUE")
- tUintPtr = self.target.FindFirstType("uintptr_t") # bits_t
-
- num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
- bits_bitlength = tUintPtr.GetByteSize() * 8
- bitmap_index = num_in_page // bits_bitlength
- bitmap_offset = num_in_page & (bits_bitlength - 1)
- bitmap_bit = 1 << bitmap_offset
-
- page = self.page.to_heap_page_struct()
- print("bits: [%s%s%s%s%s]" % (
- self.check_bits("uncollectible_bits", bitmap_index, bitmap_bit, "L"),
- self.check_bits("mark_bits", bitmap_index, bitmap_bit, "M"),
- self.check_bits("pinned_bits", bitmap_index, bitmap_bit, "P"),
- self.check_bits("marking_bits", bitmap_index, bitmap_bit, "R"),
- self.check_bits("wb_unprotected_bits", bitmap_index, bitmap_bit, "U"),
- ), end=end, file=result)
-
- def promoted_p(self):
- rbFlPromoted = self.ruby_globals["RUBY_FL_PROMOTED"]
- return (self.flags & rbFlPromoted) == rbFlPromoted
-
- def frozen_p(self):
- rbFlFreeze = self.ruby_globals["RUBY_FL_FREEZE"]
- return (self.flags & rbFlFreeze) == rbFlFreeze
-
- def is_type(self, type_name):
- if self.type is None:
- flTMask = self.ruby_globals["RUBY_T_MASK"]
- flType = self.flags & flTMask
- self.type = flType
-
- if self.type == self.ruby_globals[type_name]:
- self.type_name = type_name
- return True
- else:
- return False
-
- def as_type(self, type_name):
- return self.val.Cast(self.tRValue.GetPointerType()).GetValueForExpressionPath("->as."+type_name)
-
- def ary_ptr(self):
- rval = self.as_type("array")
- if self.flags & self.ruby_globals["RUBY_FL_USER1"]:
- ptr = rval.GetValueForExpressionPath("->as.ary")
- else:
- ptr = rval.GetValueForExpressionPath("->as.heap.ptr")
- return ptr
-
- def ary_len(self):
- if self.flags & self.flUser1:
- len = ((self.flags &
- (self.flUser3 | self.flUser4 | self.flUser5 | self.flUser6 |
- self.flUser7 | self.flUser8 | self.flUser9)
- ) >> (self.flUshift + 3))
- else:
- rval = self.as_type("array")
- len = rval.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()
-
- return len
-
- def bignum_len(self):
- if self.flags & self.flUser2:
- len = ((self.flags &
- (self.flUser3 | self.flUser4 | self.flUser5)
- ) >> (self.flUshift + 3))
- else:
- len = (self.as_type("bignum").GetValueForExpressionPath("->as.heap.len").
- GetValueAsUnsigned())
-
- return len
diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py
deleted file mode 100644
index 26517b7fee..0000000000
--- a/misc/lldb_rb/utils.py
+++ /dev/null
@@ -1,490 +0,0 @@
-from lldb_rb.lldb_interface import LLDBInterface
-from lldb_rb.rb_heap_structs import HeapPage, RbObject
-from lldb_rb.constants import *
-
-class RbInspector(LLDBInterface):
- def __init__(self, debugger, result, ruby_globals):
- self.build_environment(debugger)
- self.result = result
- self.ruby_globals = ruby_globals
-
- def _append_command_output(self, command):
- output1 = self.result.GetOutput()
- self.debugger.GetCommandInterpreter().HandleCommand(command, self.result)
- output2 = self.result.GetOutput()
- self.result.Clear()
- self.result.write(output1)
- self.result.write(output2)
-
- def _append_expression(self, expression):
- self._append_command_output("expression " + expression)
-
- def string2cstr(self, rstring):
- """Returns the pointer to the C-string in the given String object"""
- if rstring.TypeIsPointerType():
- rstring = rstring.Dereference()
-
- flags = rstring.GetValueForExpressionPath(".basic->flags").unsigned
- clen = int(rstring.GetValueForExpressionPath(".len").value, 0)
- if flags & self.ruby_globals["RUBY_FL_USER1"]:
- cptr = int(rstring.GetValueForExpressionPath(".as.heap.ptr").value, 0)
- else:
- cptr = int(rstring.GetValueForExpressionPath(".as.embed.ary").location, 0)
-
- return cptr, clen
-
- def output_string(self, rstring):
- cptr, clen = self.string2cstr(rstring)
- self._append_expression("*(const char (*)[%d])%0#x" % (clen, cptr))
-
- def fixnum_p(self, x):
- return x & self.ruby_globals["RUBY_FIXNUM_FLAG"] != 0
-
- def flonum_p(self, x):
- return (x & self.ruby_globals["RUBY_FLONUM_MASK"]) == self.ruby_globals["RUBY_FLONUM_FLAG"]
-
- def static_sym_p(self, x):
- special_shift = self.ruby_globals["RUBY_SPECIAL_SHIFT"]
- symbol_flag = self.ruby_globals["RUBY_SYMBOL_FLAG"]
- return (x & ~(~0 << special_shift)) == symbol_flag
-
- def generic_inspect(self, val, rtype):
- tRType = self.target.FindFirstType("struct %s" % rtype).GetPointerType()
- val = val.Cast(tRType)
- self._append_expression("*(struct %s *) %0#x" % (rtype, val.GetValueAsUnsigned()))
-
- def inspect(self, val):
- rbTrue = self.ruby_globals["RUBY_Qtrue"]
- rbFalse = self.ruby_globals["RUBY_Qfalse"]
- rbNil = self.ruby_globals["RUBY_Qnil"]
- rbUndef = self.ruby_globals["RUBY_Qundef"]
- rbImmediateMask = self.ruby_globals["RUBY_IMMEDIATE_MASK"]
-
- num = val.GetValueAsSigned()
- if num == rbFalse:
- print('false', file=self.result)
- elif num == rbTrue:
- print('true', file=self.result)
- elif num == rbNil:
- print('nil', file=self.result)
- elif num == rbUndef:
- print('undef', file=self.result)
- elif self.fixnum_p(num):
- print(num >> 1, file=self.result)
- elif self.flonum_p(num):
- self._append_expression("rb_float_value(%0#x)" % val.GetValueAsUnsigned())
- elif self.static_sym_p(num):
- if num < 128:
- print("T_SYMBOL: %c" % num, file=self.result)
- else:
- print("T_SYMBOL: (%x)" % num, file=self.result)
- self._append_expression("rb_id2name(%0#x)" % (num >> 8))
-
- elif num & rbImmediateMask:
- print('immediate(%x)' % num, file=self.result)
- else:
- rval = RbObject(val, self.debugger, self.ruby_globals)
- rval.dump_bits(self.result)
-
- flaginfo = ""
- if rval.promoted_p():
- flaginfo += "[PROMOTED] "
- if rval.frozen_p():
- flaginfo += "[FROZEN] "
-
- if rval.is_type("RUBY_T_NONE"):
- print('T_NONE: %s%s' % (flaginfo, val.Dereference()), file=self.result)
-
- elif rval.is_type("RUBY_T_NIL"):
- print('T_NIL: %s%s' % (flaginfo, val.Dereference()), file=self.result)
-
- elif rval.is_type("RUBY_T_OBJECT"):
- self.result.write('T_OBJECT: %s' % flaginfo)
- self._append_expression("*(struct RObject*)%0#x" % val.GetValueAsUnsigned())
-
- elif (rval.is_type("RUBY_T_CLASS") or
- rval.is_type("RUBY_T_MODULE") or
- rval.is_type("RUBY_T_ICLASS")):
- self.result.write('T_%s: %s' % (rval.type_name.split('_')[-1], flaginfo))
- tRClass = self.target.FindFirstType("struct RClass")
-
- self._append_expression("*(struct RClass*)%0#x" % val.GetValueAsUnsigned())
- if not val.Cast(tRClass).GetChildMemberWithName("ptr").IsValid():
- self._append_command_expression(
- "*(struct rb_classext_struct*)%0#x" %
- (val.GetValueAsUnsigned() + tRClass.GetByteSize())
- )
-
- elif rval.is_type("RUBY_T_STRING"):
- self.result.write('T_STRING: %s' % flaginfo)
- tRString = self.target.FindFirstType("struct RString").GetPointerType()
-
- rb_enc_mask = self.ruby_globals["RUBY_ENCODING_MASK"]
- rb_enc_shift = self.ruby_globals["RUBY_ENCODING_SHIFT"]
- encidx = ((rval.flags & rb_enc_mask) >> rb_enc_shift)
- encname = self.target.FindFirstType("enum ruby_preserved_encindex") \
- .GetEnumMembers().GetTypeEnumMemberAtIndex(encidx) \
- .GetName()
-
- if encname is not None:
- self.result.write('[%s] ' % encname[14:])
- else:
- self.result.write('[enc=%d] ' % encidx)
-
- ptr, len = self.string2cstr(val.Cast(tRString))
- if len == 0:
- self.result.write("(empty)\n")
- else:
- self._append_expression("*(const char (*)[%d])%0#x" % (len, ptr))
-
- elif rval.is_type("RUBY_T_SYMBOL"):
- self.result.write('T_SYMBOL: %s' % flaginfo)
- tRSymbol = self.target.FindFirstType("struct RSymbol").GetPointerType()
- tRString = self.target.FindFirstType("struct RString").GetPointerType()
-
- val = val.Cast(tRSymbol)
- self._append_expression('(ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned())
- self.output_string(val.GetValueForExpressionPath("->fstr").Cast(tRString))
-
- elif rval.is_type("RUBY_T_ARRAY"):
- len = rval.ary_len()
- ptr = rval.ary_ptr()
-
- self.result.write("T_ARRAY: %slen=%d" % (flaginfo, len))
-
- if rval.flags & self.ruby_globals["RUBY_FL_USER1"]:
- self.result.write(" (embed)")
- elif rval.flags & self.ruby_globals["RUBY_FL_USER2"]:
- shared = val.GetValueForExpressionPath("->as.heap.aux.shared").GetValueAsUnsigned()
- self.result.write(" (shared) shared=%016x" % shared)
- else:
- capa = val.GetValueForExpressionPath("->as.heap.aux.capa").GetValueAsSigned()
- self.result.write(" (ownership) capa=%d" % capa)
- if len == 0:
- self.result.write(" {(empty)}\n")
- else:
- self.result.write("\n")
- if ptr.GetValueAsSigned() == 0:
- self._append_expression("-fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned())
- else:
- self._append_expression("-Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()))
-
- elif rval.is_type("RUBY_T_HASH"):
- self.result.write("T_HASH: %s" % flaginfo)
- ptr = val.GetValueAsUnsigned()
- self._append_expression("*(struct RHash *) %0#x" % ptr)
- if rval.flags & self.ruby_globals["RUBY_FL_USER3"]:
- self._append_expression("*(struct st_table *) (%0#x + sizeof(struct RHash))" % ptr)
- else:
- self._append_expression("*(struct ar_table *) (%0#x + sizeof(struct RHash))" % ptr)
-
- elif rval.is_type("RUBY_T_BIGNUM"):
- sign = '-'
- if (rval.flags & self.ruby_globals["RUBY_FL_USER1"]) != 0:
- sign = '+'
- len = rval.bignum_len()
-
- if rval.flags & self.ruby_globals["RUBY_FL_USER2"]:
- print("T_BIGNUM: sign=%s len=%d (embed)" % (sign, len), file=self.result)
- self._append_expression("((struct RBignum *) %0#x)->as.ary"
- % val.GetValueAsUnsigned())
- else:
- print("T_BIGNUM: sign=%s len=%d" % (sign, len), file=self.result)
- print(rval.as_type("bignum"), file=self.result)
- self._append_expression("-Z %d -fx -- ((struct RBignum*)%d)->as.heap.digits" %
- (len, val.GetValueAsUnsigned()))
-
- elif rval.is_type("RUBY_T_FLOAT"):
- self._append_expression("((struct RFloat *)%d)->float_value"
- % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_RATIONAL"):
- tRRational = self.target.FindFirstType("struct RRational").GetPointerType()
- val = val.Cast(tRRational)
- self.inspect(val.GetValueForExpressionPath("->num"))
- output = self.result.GetOutput()
- self.result.Clear()
- self.result.write("(Rational) " + output.rstrip() + " / ")
- self.inspect(val.GetValueForExpressionPath("->den"))
-
- elif rval.is_type("RUBY_T_COMPLEX"):
- tRComplex = self.target.FindFirstType("struct RComplex").GetPointerType()
- val = val.Cast(tRComplex)
- self.inspect(val.GetValueForExpressionPath("->real"))
- real = self.result.GetOutput().rstrip()
- self.result.Clear()
- self.inspect(val.GetValueForExpressionPath("->imag"))
- imag = self.result.GetOutput().rstrip()
- self.result.Clear()
- if not imag.startswith("-"):
- imag = "+" + imag
- print("(Complex) " + real + imag + "i", file=self.result)
-
- elif rval.is_type("RUBY_T_REGEXP"):
- tRRegex = self.target.FindFirstType("struct RRegexp").GetPointerType()
- val = val.Cast(tRRegex)
- print("(Regex) ->src {", file=self.result)
- self.inspect(val.GetValueForExpressionPath("->src"))
- print("}", file=self.result)
-
- elif rval.is_type("RUBY_T_DATA"):
- tRTypedData = self.target.FindFirstType("struct RTypedData").GetPointerType()
- val = val.Cast(tRTypedData)
- flag = val.GetValueForExpressionPath("->typed_flag")
-
- if flag.GetValueAsUnsigned() == 1:
- print("T_DATA: %s" %
- val.GetValueForExpressionPath("->type->wrap_struct_name"),
- file=self.result)
- self._append_expression("*(struct RTypedData *) %0#x" % val.GetValueAsUnsigned())
- else:
- print("T_DATA:", file=self.result)
- self._append_expression("*(struct RData *) %0#x" % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_NODE"):
- tRNode = self.target.FindFirstType("struct RNode").GetPointerType()
- rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
- rbNodeTypeShift = self.ruby_globals["RUBY_NODE_TYPESHIFT"]
-
- nd_type = (rval.flags & rbNodeTypeMask) >> rbNodeTypeShift
- val = val.Cast(tRNode)
-
- self._append_expression("(node_type) %d" % nd_type)
-
- if nd_type == self.ruby_globals["NODE_SCOPE"]:
- self._append_expression("*(struct RNode_SCOPE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BLOCK"]:
- self._append_expression("*(struct RNode_BLOCK *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IF"]:
- self._append_expression("*(struct RNode_IF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNLESS"]:
- self._append_expression("*(struct RNode_UNLESS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE"]:
- self._append_expression("*(struct RNode_CASE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE2"]:
- self._append_expression("*(struct RNode_CASE2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE3"]:
- self._append_expression("*(struct RNode_CASE3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHEN"]:
- self._append_expression("*(struct RNode_WHEN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IN"]:
- self._append_expression("*(struct RNode_IN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHILE"]:
- self._append_expression("*(struct RNode_WHILE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNTIL"]:
- self._append_expression("*(struct RNode_UNTIL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ITER"]:
- self._append_expression("*(struct RNode_ITER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR"]:
- self._append_expression("*(struct RNode_FOR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR_MASGN"]:
- self._append_expression("*(struct RNode_FOR_MASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BREAK"]:
- self._append_expression("*(struct RNode_BREAK *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NEXT"]:
- self._append_expression("*(struct RNode_NEXT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_REDO"]:
- self._append_expression("*(struct RNode_REDO *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETRY"]:
- self._append_expression("*(struct RNode_RETRY *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BEGIN"]:
- self._append_expression("*(struct RNode_BEGIN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESCUE"]:
- self._append_expression("*(struct RNode_RESCUE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESBODY"]:
- self._append_expression("*(struct RNode_RESBODY *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ENSURE"]:
- self._append_expression("*(struct RNode_ENSURE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_AND"]:
- self._append_expression("*(struct RNode_AND *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OR"]:
- self._append_expression("*(struct RNode_OR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MASGN"]:
- self._append_expression("*(struct RNode_MASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LASGN"]:
- self._append_expression("*(struct RNode_LASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DASGN"]:
- self._append_expression("*(struct RNode_DASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GASGN"]:
- self._append_expression("*(struct RNode_GASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IASGN"]:
- self._append_expression("*(struct RNode_IASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CDECL"]:
- self._append_expression("*(struct RNode_CDECL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVASGN"]:
- self._append_expression("*(struct RNode_CVASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN1"]:
- self._append_expression("*(struct RNode_OP_ASGN1 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN2"]:
- self._append_expression("*(struct RNode_OP_ASGN2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_AND"]:
- self._append_expression("*(struct RNode_OP_ASGN_AND *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_OR"]:
- self._append_expression("*(struct RNode_OP_ASGN_OR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_CDECL"]:
- self._append_expression("*(struct RNode_OP_CDECL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CALL"]:
- self._append_expression("*(struct RNode_CALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPCALL"]:
- self._append_expression("*(struct RNode_OPCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FCALL"]:
- self._append_expression("*(struct RNode_FCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VCALL"]:
- self._append_expression("*(struct RNode_VCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_QCALL"]:
- self._append_expression("*(struct RNode_QCALL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SUPER"]:
- self._append_expression("*(struct RNode_SUPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZSUPER"]:
- self._append_expression("*(struct RNode_ZSUPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LIST"]:
- self._append_expression("*(struct RNode_LIST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZLIST"]:
- self._append_expression("*(struct RNode_ZLIST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HASH"]:
- self._append_expression("*(struct RNode_HASH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETURN"]:
- self._append_expression("*(struct RNode_RETURN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_YIELD"]:
- self._append_expression("*(struct RNode_YIELD *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LVAR"]:
- self._append_expression("*(struct RNode_LVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DVAR"]:
- self._append_expression("*(struct RNode_DVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GVAR"]:
- self._append_expression("*(struct RNode_GVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CONST"]:
- self._append_expression("*(struct RNode_CONST *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVAR"]:
- self._append_expression("*(struct RNode_CVAR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NTH_REF"]:
- self._append_expression("*(struct RNode_NTH_REF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BACK_REF"]:
- self._append_expression("*(struct RNode_BACK_REF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH"]:
- self._append_expression("*(struct RNode_MATCH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH2"]:
- self._append_expression("*(struct RNode_MATCH2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH3"]:
- self._append_expression("*(struct RNode_MATCH3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LIT"]:
- self._append_expression("*(struct RNode_LIT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_STR"]:
- self._append_expression("*(struct RNode_STR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSTR"]:
- self._append_expression("*(struct RNode_DSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_XSTR"]:
- self._append_expression("*(struct RNode_XSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DXSTR"]:
- self._append_expression("*(struct RNode_DXSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_EVSTR"]:
- self._append_expression("*(struct RNode_EVSTR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DREGX"]:
- self._append_expression("*(struct RNode_DREGX *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ONCE"]:
- self._append_expression("*(struct RNode_ONCE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS"]:
- self._append_expression("*(struct RNode_ARGS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS_AUX"]:
- self._append_expression("*(struct RNode_ARGS_AUX *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPT_ARG"]:
- self._append_expression("*(struct RNode_OPT_ARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_KW_ARG"]:
- self._append_expression("*(struct RNode_KW_ARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTARG"]:
- self._append_expression("*(struct RNode_POSTARG *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSCAT"]:
- self._append_expression("*(struct RNode_ARGSCAT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSPUSH"]:
- self._append_expression("*(struct RNode_ARGSPUSH *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SPLAT"]:
- self._append_expression("*(struct RNode_SPLAT *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFN"]:
- self._append_expression("*(struct RNode_DEFN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFS"]:
- self._append_expression("*(struct RNode_DEFS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ALIAS"]:
- self._append_expression("*(struct RNode_ALIAS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VALIAS"]:
- self._append_expression("*(struct RNode_VALIAS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNDEF"]:
- self._append_expression("*(struct RNode_UNDEF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CLASS"]:
- self._append_expression("*(struct RNode_CLASS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MODULE"]:
- self._append_expression("*(struct RNode_MODULE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SCLASS"]:
- self._append_expression("*(struct RNode_SCLASS *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON2"]:
- self._append_expression("*(struct RNode_COLON2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON3"]:
- self._append_expression("*(struct RNode_COLON3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT2"]:
- self._append_expression("*(struct RNode_DOT2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT3"]:
- self._append_expression("*(struct RNode_DOT3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP2"]:
- self._append_expression("*(struct RNode_FLIP2 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP3"]:
- self._append_expression("*(struct RNode_FLIP3 *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SELF"]:
- self._append_expression("*(struct RNode_SELF *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NIL"]:
- self._append_expression("*(struct RNode_NIL *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_TRUE"]:
- self._append_expression("*(struct RNode_TRUE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FALSE"]:
- self._append_expression("*(struct RNode_FALSE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERRINFO"]:
- self._append_expression("*(struct RNode_ERRINFO *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFINED"]:
- self._append_expression("*(struct RNode_DEFINED *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTEXE"]:
- self._append_expression("*(struct RNode_POSTEXE *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSYM"]:
- self._append_expression("*(struct RNode_DSYM *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ATTRASGN"]:
- self._append_expression("*(struct RNode_ATTRASGN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LAMBDA"]:
- self._append_expression("*(struct RNode_LAMBDA *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARYPTN"]:
- self._append_expression("*(struct RNode_ARYPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HSHPTN"]:
- self._append_expression("*(struct RNode_HSHPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FNDPTN"]:
- self._append_expression("*(struct RNode_FNDPTN *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERROR"]:
- self._append_expression("*(struct RNode_ERROR *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RIPPER"]:
- self._append_expression("*(struct RNode_RIPPER *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RIPPER_VALUES"]:
- self._append_expression("*(struct RNode_RIPPER_VALUES *) %0#x" % val.GetValueAsUnsigned())
- else:
- self._append_expression("*(struct RNode *) %0#x" % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_IMEMO"):
- imemo_type = ((rval.flags >> self.ruby_globals["RUBY_FL_USHIFT"])
- & IMEMO_MASK)
- print("T_IMEMO: ", file=self.result)
-
- self._append_expression("(enum imemo_type) %d" % imemo_type)
- self._append_expression("*(struct MEMO *) %0#x" % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_FILE"):
- self.generic_inspect(val, "RFile")
-
- elif rval.is_type("RUBY_T_MOVED"):
- self.generic_inspect(val, "RMoved")
-
- elif rval.is_type("RUBY_T_MATCH"):
- self.generic_inspect(val, "RMatch")
-
- elif rval.is_type("RUBY_T_STRUCT"):
- self.generic_inspect(val, "RStruct")
-
- elif rval.is_type("RUBY_T_ZOMBIE"):
- self.generic_inspect(val, "RZombie")
-
- else:
- print("Not-handled type %0#x" % rval.type, file=self.result)
- print(val, file=self.result)
diff --git a/missing/dtoa.c b/missing/dtoa.c
index bce2cb22a1..b7a8302875 100644
--- a/missing/dtoa.c
+++ b/missing/dtoa.c
@@ -183,10 +183,7 @@
#undef Long
#undef ULong
-#include <assert.h>
#include <limits.h>
-#include <stddef.h>
-#include <stdint.h>
#if (INT_MAX >> 30) && !(INT_MAX >> 31)
#define Long int
@@ -198,7 +195,7 @@
#error No 32bit integer
#endif
-#if defined(HAVE_LONG_LONG) && (HAVE_LONG_LONG)
+#if HAVE_LONG_LONG
#define Llong LONG_LONG
#else
#define NO_LONG_LONG
@@ -224,12 +221,12 @@
#ifdef MALLOC
extern void *MALLOC(size_t);
#else
-#define MALLOC malloc
+#define MALLOC xmalloc
#endif
#ifdef FREE
extern void FREE(void*);
#else
-#define FREE free
+#define FREE xfree
#endif
#ifndef NO_SANITIZE
#define NO_SANITIZE(x, y) y
@@ -505,7 +502,7 @@ extern double rnd_prod(double, double), rnd_quot(double, double);
#endif
#ifndef ATOMIC_PTR_CAS
-#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (void *)(old))
+#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (old))
#endif
#ifndef LIKELY
#define LIKELY(x) (x)
diff --git a/missing/explicit_bzero.c b/missing/explicit_bzero.c
index 59417e158e..1220e5f9ad 100644
--- a/missing/explicit_bzero.c
+++ b/missing/explicit_bzero.c
@@ -1,9 +1,12 @@
#ifndef __STDC_WANT_LIB_EXT1__
-#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s() */
+#define __STDC_WANT_LIB_EXT1__ 1
#endif
#include "ruby/missing.h"
#include <string.h>
+#ifdef HAVE_MEMSET_S
+# include <string.h>
+#endif
#ifdef _WIN32
#include <windows.h>
diff --git a/missing/procstat_vm.c b/missing/procstat_vm.c
index 155ee355d1..76fd8f61ba 100644
--- a/missing/procstat_vm.c
+++ b/missing/procstat_vm.c
@@ -6,7 +6,7 @@
# define KVME_TYPE_MGTDEVICE 8
# endif
void
-procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
+procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp)
{
struct kinfo_vmentry *freep, *kve;
int ptrwidth;
@@ -17,7 +17,7 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
#else
ptrwidth = 2*sizeof(void *) + 2;
#endif
- fprintf(errout, "%*s %*s %3s %4s %4s %3s %3s %4s %-2s %-s\n",
+ fprintf(stderr, "%*s %*s %3s %4s %4s %3s %3s %4s %-2s %-s\n",
ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
"P""RES", "REF", "SHD", "FL", "TP", "PATH");
@@ -30,20 +30,20 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
return;
for (i = 0; i < cnt; i++) {
kve = &freep[i];
- fprintf(errout, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_start);
- fprintf(errout, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_end);
- fprintf(errout, "%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
- fprintf(errout, "%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
- fprintf(errout, "%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
- fprintf(errout, "%4d ", kve->kve_resident);
- fprintf(errout, "%4d ", kve->kve_private_resident);
- fprintf(errout, "%3d ", kve->kve_ref_count);
- fprintf(errout, "%3d ", kve->kve_shadow_count);
- fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-");
- fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" :
+ fprintf(stderr, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_start);
+ fprintf(stderr, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_end);
+ fprintf(stderr, "%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
+ fprintf(stderr, "%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
+ fprintf(stderr, "%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
+ fprintf(stderr, "%4d ", kve->kve_resident);
+ fprintf(stderr, "%4d ", kve->kve_private_resident);
+ fprintf(stderr, "%3d ", kve->kve_ref_count);
+ fprintf(stderr, "%3d ", kve->kve_shadow_count);
+ fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-");
+ fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" :
"-");
- fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_SUPER ? "S" : "-");
- fprintf(errout, "%-1s ", kve->kve_flags & KVME_FLAG_GROWS_UP ? "U" :
+ fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_SUPER ? "S" : "-");
+ fprintf(stderr, "%-1s ", kve->kve_flags & KVME_FLAG_GROWS_UP ? "U" :
kve->kve_flags & KVME_FLAG_GROWS_DOWN ? "D" : "-");
switch (kve->kve_type) {
case KVME_TYPE_NONE:
@@ -78,8 +78,8 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
str = "??";
break;
}
- fprintf(errout, "%-2s ", str);
- fprintf(errout, "%-s\n", kve->kve_path);
+ fprintf(stderr, "%-2s ", str);
+ fprintf(stderr, "%-s\n", kve->kve_path);
}
free(freep);
}
diff --git a/mjit.c b/mjit.c
new file mode 100644
index 0000000000..3200ee2621
--- /dev/null
+++ b/mjit.c
@@ -0,0 +1,1999 @@
+/**********************************************************************
+
+ mjit.c - MRI method JIT compiler functions
+
+ Copyright (C) 2017 Vladimir Makarov <vmakarov@redhat.com>.
+ Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
+
+**********************************************************************/
+
+/* We utilize widely used C compilers (GCC and LLVM Clang) to
+ implement MJIT. We feed them a C code generated from ISEQ. The
+ industrial C compilers are slower than regular JIT engines.
+ Generated code performance of the used C compilers has a higher
+ priority over the compilation speed.
+
+ So our major goal is to minimize the ISEQ compilation time when we
+ use widely optimization level (-O2). It is achieved by
+
+ o Using a precompiled version of the header
+ o Keeping all files in `/tmp`. On modern Linux `/tmp` is a file
+ system in memory. So it is pretty fast
+ o Implementing MJIT as a multi-threaded code because we want to
+ compile ISEQs in parallel with iseq execution to speed up Ruby
+ code execution. MJIT has one thread (*worker*) to do
+ parallel compilations:
+ o It prepares a precompiled code of the minimized header.
+ It starts at the MRI execution start
+ o It generates PIC object files of ISEQs
+ o It takes one JIT unit from a priority queue unless it is empty.
+ o It translates the JIT unit ISEQ into C-code using the precompiled
+ header, calls CC and load PIC code when it is ready
+ o Currently MJIT put ISEQ in the queue when ISEQ is called
+ o MJIT can reorder ISEQs in the queue if some ISEQ has been called
+ many times and its compilation did not start yet
+ o MRI reuses the machine code if it already exists for ISEQ
+ o The machine code we generate can stop and switch to the ISEQ
+ interpretation if some condition is not satisfied as the machine
+ code can be speculative or some exception raises
+ o Speculative machine code can be canceled.
+
+ Here is a diagram showing the MJIT organization:
+
+ _______
+ |header |
+ |_______|
+ | MRI building
+ --------------|----------------------------------------
+ | MRI execution
+ |
+ _____________|_____
+ | | |
+ | ___V__ | CC ____________________
+ | | |----------->| precompiled header |
+ | | | | |____________________|
+ | | | | |
+ | | MJIT | | |
+ | | | | |
+ | | | | ____V___ CC __________
+ | |______|----------->| C code |--->| .so file |
+ | | |________| |__________|
+ | | |
+ | | |
+ | MRI machine code |<-----------------------------
+ |___________________| loading
+
+*/
+
+#include "ruby/internal/config.h" // defines USE_MJIT
+
+#if USE_MJIT
+
+#include "constant.h"
+#include "id_table.h"
+#include "internal.h"
+#include "internal/class.h"
+#include "internal/cmdlineopt.h"
+#include "internal/cont.h"
+#include "internal/file.h"
+#include "internal/hash.h"
+#include "internal/process.h"
+#include "internal/warnings.h"
+#include "vm_sync.h"
+#include "ractor_core.h"
+
+#ifdef __sun
+#define __EXTENSIONS__ 1
+#endif
+
+#include "vm_core.h"
+#include "vm_callinfo.h"
+#include "mjit.h"
+#include "mjit_c.h"
+#include "gc.h"
+#include "ruby_assert.h"
+#include "ruby/debug.h"
+#include "ruby/thread.h"
+#include "ruby/version.h"
+#include "builtin.h"
+#include "insns.inc"
+#include "insns_info.inc"
+#include "internal/compile.h"
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <dlfcn.h>
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#include "dln.h"
+
+#include "ruby/util.h"
+#undef strdup // ruby_strdup may trigger GC
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+// Atomically set function pointer if possible.
+#define MJIT_ATOMIC_SET(var, val) (void)ATOMIC_PTR_EXCHANGE(var, val)
+
+#define MJIT_TMP_PREFIX "_ruby_mjit_"
+
+extern void rb_native_mutex_lock(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_unlock(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_initialize(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_destroy(rb_nativethread_lock_t *lock);
+
+// process.c
+extern void mjit_add_waiting_pid(rb_vm_t *vm, rb_pid_t pid);
+
+// A copy of MJIT portion of MRI options since MJIT initialization. We
+// need them as MJIT threads still can work when the most MRI data were
+// freed.
+struct mjit_options mjit_opts;
+
+// true if MJIT is enabled.
+bool mjit_enabled = false;
+// true if JIT-ed code should be called. When `ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS`
+// and `mjit_call_p == false`, any JIT-ed code execution is cancelled as soon as possible.
+bool mjit_call_p = false;
+// A flag to communicate that mjit_call_p should be disabled while it's temporarily false.
+bool mjit_cancel_p = false;
+// There's an ISEQ in unit_queue whose total_calls reached 2 * call_threshold.
+// If this is true, check_unit_queue will start compiling ISEQs in unit_queue.
+static bool mjit_compile_p = false;
+// The actual number of units in active_units
+static int active_units_length = 0;
+// The actual number of units in compact_units
+static int compact_units_length = 0;
+
+// Priority queue of iseqs waiting for JIT compilation.
+// This variable is a pointer to head unit of the queue.
+static struct rb_mjit_unit_list unit_queue = { CCAN_LIST_HEAD_INIT(unit_queue.head) };
+// List of units which are successfully compiled.
+static struct rb_mjit_unit_list active_units = { CCAN_LIST_HEAD_INIT(active_units.head) };
+// List of compacted so files which will be cleaned up by `free_list()` in `mjit_finish()`.
+static struct rb_mjit_unit_list compact_units = { CCAN_LIST_HEAD_INIT(compact_units.head) };
+// List of units before recompilation and just waiting for dlclose().
+static struct rb_mjit_unit_list stale_units = { CCAN_LIST_HEAD_INIT(stale_units.head) };
+// The number of so far processed ISEQs, used to generate unique id.
+static int current_unit_num;
+// A mutex for conitionals and critical sections.
+static rb_nativethread_lock_t mjit_engine_mutex;
+// Set to true to stop worker.
+static bool stop_worker_p;
+// Set to true if worker is stopped.
+static bool worker_stopped = true;
+
+// Path of "/tmp", which is different on Windows or macOS. See: system_default_tmpdir()
+static char *tmp_dir;
+
+// Used C compiler path.
+static const char *cc_path;
+// Used C compiler flags.
+static const char **cc_common_args;
+// Used C compiler flags added by --mjit-debug=...
+static char **cc_added_args;
+// Name of the precompiled header file.
+static char *pch_file;
+// The process id which should delete the pch_file on mjit_finish.
+static rb_pid_t pch_owner_pid;
+// Status of the precompiled header creation. The status is
+// shared by the workers and the pch thread.
+static enum {PCH_NOT_READY, PCH_FAILED, PCH_SUCCESS} pch_status;
+
+// The start timestamp of current compilation
+static double current_cc_ms = 0.0; // TODO: make this part of unit?
+// Currently compiling MJIT unit
+static struct rb_mjit_unit *current_cc_unit = NULL;
+// PID of currently running C compiler process. 0 if nothing is running.
+static pid_t current_cc_pid = 0; // TODO: make this part of unit?
+
+// Name of the header file.
+static char *header_file;
+
+#include "mjit_config.h"
+
+#if defined(__GNUC__) && \
+ (!defined(__clang__) || \
+ (defined(__clang__) && (defined(__FreeBSD__) || defined(__GLIBC__))))
+# define GCC_PIC_FLAGS "-Wfatal-errors", "-fPIC", "-shared", "-w", "-pipe",
+# define MJIT_CFLAGS_PIPE 1
+#else
+# define GCC_PIC_FLAGS /* empty */
+# define MJIT_CFLAGS_PIPE 0
+#endif
+
+// Use `-nodefaultlibs -nostdlib` for GCC where possible, which does not work on cygwin, AIX, and OpenBSD.
+// This seems to improve MJIT performance on GCC.
+#if defined __GNUC__ && !defined __clang__ && !defined(__CYGWIN__) && !defined(_AIX) && !defined(__OpenBSD__)
+# define GCC_NOSTDLIB_FLAGS "-nodefaultlibs", "-nostdlib",
+#else
+# define GCC_NOSTDLIB_FLAGS // empty
+#endif
+
+static const char *const CC_COMMON_ARGS[] = {
+ MJIT_CC_COMMON MJIT_CFLAGS GCC_PIC_FLAGS
+ NULL
+};
+
+static const char *const CC_DEBUG_ARGS[] = {MJIT_DEBUGFLAGS NULL};
+static const char *const CC_OPTIMIZE_ARGS[] = {MJIT_OPTFLAGS NULL};
+
+static const char *const CC_LDSHARED_ARGS[] = {MJIT_LDSHARED MJIT_CFLAGS GCC_PIC_FLAGS NULL};
+static const char *const CC_DLDFLAGS_ARGS[] = {MJIT_DLDFLAGS NULL};
+// `CC_LINKER_ARGS` are linker flags which must be passed to `-c` as well.
+static const char *const CC_LINKER_ARGS[] = {
+#if defined __GNUC__ && !defined __clang__ && !defined(__OpenBSD__)
+ "-nostartfiles",
+#endif
+ GCC_NOSTDLIB_FLAGS NULL
+};
+
+static const char *const CC_LIBS[] = {
+#if defined(__CYGWIN__)
+ MJIT_LIBS // mswin, cygwin
+#endif
+#if defined __GNUC__ && !defined __clang__
+ "-lgcc", // cygwin, and GCC platforms using `-nodefaultlibs -nostdlib`
+#endif
+#if defined __ANDROID__
+ "-lm", // to avoid 'cannot locate symbol "modf" referenced by .../_ruby_mjit_XXX.so"'
+#endif
+ NULL
+};
+
+#define CC_CODEFLAG_ARGS (mjit_opts.debug ? CC_DEBUG_ARGS : CC_OPTIMIZE_ARGS)
+
+// Print the arguments according to FORMAT to stderr only if MJIT
+// verbose option value is more or equal to LEVEL.
+PRINTF_ARGS(static void, 2, 3)
+verbose(int level, const char *format, ...)
+{
+ if (mjit_opts.verbose >= level) {
+ va_list args;
+ size_t len = strlen(format);
+ char *full_format = alloca(sizeof(char) * (len + 2));
+
+ // Creating `format + '\n'` to atomically print format and '\n'.
+ memcpy(full_format, format, len);
+ full_format[len] = '\n';
+ full_format[len+1] = '\0';
+
+ va_start(args, format);
+ vfprintf(stderr, full_format, args);
+ va_end(args);
+ }
+}
+
+PRINTF_ARGS(static void, 1, 2)
+mjit_warning(const char *format, ...)
+{
+ if (mjit_opts.warnings || mjit_opts.verbose) {
+ va_list args;
+
+ fprintf(stderr, "MJIT warning: ");
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+}
+
+// Add unit node to the tail of doubly linked `list`. It should be not in
+// the list before.
+static void
+add_to_list(struct rb_mjit_unit *unit, struct rb_mjit_unit_list *list)
+{
+ ccan_list_add_tail(&list->head, &unit->unode);
+ list->length++;
+}
+
+static void
+remove_from_list(struct rb_mjit_unit *unit, struct rb_mjit_unit_list *list)
+{
+ ccan_list_del(&unit->unode);
+ list->length--;
+}
+
+static void
+remove_file(const char *filename)
+{
+ if (remove(filename)) {
+ mjit_warning("failed to remove \"%s\": %s", filename, strerror(errno));
+ }
+}
+
+// This is called in the following situations:
+// 1) On dequeue or `unload_units()`, associated ISeq is already GCed.
+// 2) The unit is not called often and unloaded by `unload_units()`.
+// 3) Freeing lists on `mjit_finish()`.
+//
+// `jit_func` value does not matter for 1 and 3 since the unit won't be used anymore.
+// For the situation 2, this sets the ISeq's JIT state to MJIT_FUNC_FAILED
+// to prevent the situation that the same methods are continuously compiled.
+static void
+free_unit(struct rb_mjit_unit *unit)
+{
+ if (unit->iseq) { // ISeq is not GCed
+ ISEQ_BODY(unit->iseq)->jit_func = (jit_func_t)MJIT_FUNC_FAILED;
+ ISEQ_BODY(unit->iseq)->mjit_unit = NULL;
+ }
+ if (unit->cc_entries) {
+ void *entries = (void *)unit->cc_entries;
+ free(entries);
+ }
+ if (unit->handle && dlclose(unit->handle)) { // handle is NULL if it's in queue
+ mjit_warning("failed to close handle for u%d: %s", unit->id, dlerror());
+ }
+ xfree(unit);
+}
+
+// Start a critical section. Use message `msg` to print debug info at `level`.
+static inline void
+CRITICAL_SECTION_START(int level, const char *msg)
+{
+ verbose(level, "Locking %s", msg);
+ rb_native_mutex_lock(&mjit_engine_mutex);
+ verbose(level, "Locked %s", msg);
+}
+
+// Finish the current critical section. Use message `msg` to print
+// debug info at `level`.
+static inline void
+CRITICAL_SECTION_FINISH(int level, const char *msg)
+{
+ verbose(level, "Unlocked %s", msg);
+ rb_native_mutex_unlock(&mjit_engine_mutex);
+}
+
+static pid_t mjit_pid = 0;
+
+static int
+sprint_uniq_filename(char *str, size_t size, unsigned long id, const char *prefix, const char *suffix)
+{
+ return snprintf(str, size, "%s/%sp%"PRI_PIDT_PREFIX"uu%lu%s", tmp_dir, prefix, mjit_pid, id, suffix);
+}
+
+// Return time in milliseconds as a double.
+#ifdef __APPLE__
+double ruby_real_ms_time(void);
+# define real_ms_time() ruby_real_ms_time()
+#else
+static double
+real_ms_time(void)
+{
+# ifdef HAVE_CLOCK_GETTIME
+ struct timespec tv;
+# ifdef CLOCK_MONOTONIC
+ const clockid_t c = CLOCK_MONOTONIC;
+# else
+ const clockid_t c = CLOCK_REALTIME;
+# endif
+
+ clock_gettime(c, &tv);
+ return tv.tv_nsec / 1000000.0 + tv.tv_sec * 1000.0;
+# else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return tv.tv_usec / 1000.0 + tv.tv_sec * 1000.0;
+# endif
+}
+#endif
+
+// Return the best unit from list. The best is the first
+// high priority unit or the unit whose iseq has the biggest number
+// of calls so far.
+static struct rb_mjit_unit *
+get_from_list(struct rb_mjit_unit_list *list)
+{
+ // Find iseq with max total_calls
+ struct rb_mjit_unit *unit = NULL, *next, *best = NULL;
+ ccan_list_for_each_safe(&list->head, unit, next, unode) {
+ if (unit->iseq == NULL) { // ISeq is GCed.
+ remove_from_list(unit, list);
+ free_unit(unit);
+ continue;
+ }
+
+ if (best == NULL || ISEQ_BODY(best->iseq)->total_calls < ISEQ_BODY(unit->iseq)->total_calls) {
+ best = unit;
+ }
+ }
+
+ if (best) {
+ remove_from_list(best, list);
+ }
+ return best;
+}
+
+// Return length of NULL-terminated array `args` excluding the NULL marker.
+static size_t
+args_len(char *const *args)
+{
+ size_t i;
+
+ for (i = 0; (args[i]) != NULL;i++)
+ ;
+ return i;
+}
+
+// Concatenate `num` passed NULL-terminated arrays of strings, put the
+// result (with NULL end marker) into the heap, and return the result.
+static char **
+form_args(int num, ...)
+{
+ va_list argp;
+ size_t len, n;
+ int i;
+ char **args, **res, **tmp;
+
+ va_start(argp, num);
+ res = NULL;
+ for (i = len = 0; i < num; i++) {
+ args = va_arg(argp, char **);
+ n = args_len(args);
+ if ((tmp = (char **)realloc(res, sizeof(char *) * (len + n + 1))) == NULL) {
+ free(res);
+ res = NULL;
+ break;
+ }
+ res = tmp;
+ MEMCPY(res + len, args, char *, n + 1);
+ len += n;
+ }
+ va_end(argp);
+ return res;
+}
+
+COMPILER_WARNING_PUSH
+#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
+COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
+#endif
+// Start an OS process of absolute executable path with arguments `argv`.
+// Return PID of the process.
+static pid_t
+start_process(const char *abspath, char *const *argv)
+{
+ // Not calling non-async-signal-safe functions between vfork
+ // and execv for safety
+ int dev_null = rb_cloexec_open(ruby_null_device, O_WRONLY, 0);
+ if (dev_null < 0) {
+ verbose(1, "MJIT: Failed to open a null device: %s", strerror(errno));
+ return -1;
+ }
+ if (mjit_opts.verbose >= 2) {
+ const char *arg;
+ fprintf(stderr, "Starting process: %s", abspath);
+ for (int i = 0; (arg = argv[i]) != NULL; i++)
+ fprintf(stderr, " %s", arg);
+ fprintf(stderr, "\n");
+ }
+
+ pid_t pid;
+ if ((pid = vfork()) == 0) { /* TODO: reuse some function in process.c */
+ umask(0077);
+ if (mjit_opts.verbose == 0) {
+ // CC can be started in a thread using a file which has been
+ // already removed while MJIT is finishing. Discard the
+ // messages about missing files.
+ dup2(dev_null, STDERR_FILENO);
+ dup2(dev_null, STDOUT_FILENO);
+ }
+ (void)close(dev_null);
+ pid = execv(abspath, argv); // Pid will be negative on an error
+ // Even if we successfully found CC to compile PCH we still can
+ // fail with loading the CC in very rare cases for some reasons.
+ // Stop the forked process in this case.
+ verbose(1, "MJIT: Error in execv: %s", abspath);
+ _exit(1);
+ }
+ (void)close(dev_null);
+ return pid;
+}
+COMPILER_WARNING_POP
+
+// Execute an OS process of executable PATH with arguments ARGV.
+// Return -1 or -2 if failed to execute, otherwise exit code of the process.
+// TODO: Use a similar function in process.c
+static int
+exec_process(const char *path, char *const argv[])
+{
+ int stat, exit_code = -2;
+ pid_t pid = start_process(path, argv);
+ for (;pid > 0;) {
+ pid_t r = waitpid(pid, &stat, 0);
+ if (r == -1) {
+ if (errno == EINTR) continue;
+ fprintf(stderr, "[%"PRI_PIDT_PREFIX"d] waitpid(%lu): %s (SIGCHLD=%d,%u)\n",
+ getpid(), (unsigned long)pid, strerror(errno),
+ RUBY_SIGCHLD, SIGCHLD_LOSSY);
+ break;
+ }
+ else if (r == pid) {
+ if (WIFEXITED(stat)) {
+ exit_code = WEXITSTATUS(stat);
+ break;
+ }
+ else if (WIFSIGNALED(stat)) {
+ exit_code = -1;
+ break;
+ }
+ }
+ }
+ return exit_code;
+}
+
+static void
+remove_so_file(const char *so_file, struct rb_mjit_unit *unit)
+{
+ remove_file(so_file);
+}
+
+// Print _mjitX, but make a human-readable funcname when --mjit-debug is used
+static void
+sprint_funcname(char *funcname, size_t funcname_size, const struct rb_mjit_unit *unit)
+{
+ const rb_iseq_t *iseq = unit->iseq;
+ if (iseq == NULL || (!mjit_opts.debug && !mjit_opts.debug_flags)) {
+ snprintf(funcname, funcname_size, "_mjit%d", unit->id);
+ return;
+ }
+
+ // Generate a short path
+ const char *path = RSTRING_PTR(rb_iseq_path(iseq));
+ const char *lib = "/lib/";
+ const char *version = "/" STRINGIZE(RUBY_API_VERSION_MAJOR) "." STRINGIZE(RUBY_API_VERSION_MINOR) "." STRINGIZE(RUBY_API_VERSION_TEENY) "/";
+ while (strstr(path, lib)) // skip "/lib/"
+ path = strstr(path, lib) + strlen(lib);
+ while (strstr(path, version)) // skip "/x.y.z/"
+ path = strstr(path, version) + strlen(version);
+
+ // Annotate all-normalized method names
+ const char *method = RSTRING_PTR(ISEQ_BODY(iseq)->location.label);
+ if (!strcmp(method, "[]")) method = "AREF";
+ if (!strcmp(method, "[]=")) method = "ASET";
+
+ // Print and normalize
+ snprintf(funcname, funcname_size, "_mjit%d_%s_%s", unit->id, path, method);
+ for (size_t i = 0; i < strlen(funcname); i++) {
+ char c = funcname[i];
+ if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_')) {
+ funcname[i] = '_';
+ }
+ }
+}
+
+static const int c_file_access_mode =
+#ifdef O_BINARY
+ O_BINARY|
+#endif
+ O_WRONLY|O_EXCL|O_CREAT;
+
+#define append_str2(p, str, len) ((char *)memcpy((p), str, (len))+(len))
+#define append_str(p, str) append_str2(p, str, sizeof(str)-1)
+#define append_lit(p, str) append_str2(p, str, rb_strlen_lit(str))
+
+// The function producing the pre-compiled header.
+static void
+make_pch(void)
+{
+ const char *rest_args[] = {
+# ifdef __clang__
+ "-Xclang",
+ "-emit-pch",
+ "-c",
+# endif
+ // -nodefaultlibs is a linker flag, but it may affect cc1 behavior on Gentoo, which should NOT be changed on pch:
+ // https://gitweb.gentoo.org/proj/gcc-patches.git/tree/7.3.0/gentoo/13_all_default-ssp-fix.patch
+ GCC_NOSTDLIB_FLAGS
+ "-o", pch_file, header_file,
+ NULL,
+ };
+
+ verbose(2, "Creating precompiled header");
+ char **args = form_args(4, cc_common_args, CC_CODEFLAG_ARGS, cc_added_args, rest_args);
+ if (args == NULL) {
+ mjit_warning("making precompiled header failed on forming args");
+ pch_status = PCH_FAILED;
+ return;
+ }
+
+ int exit_code = exec_process(cc_path, args);
+ free(args);
+
+ if (exit_code == 0) {
+ pch_status = PCH_SUCCESS;
+ }
+ else {
+ mjit_warning("Making precompiled header failed on compilation. Stopping MJIT worker...");
+ pch_status = PCH_FAILED;
+ }
+}
+
+static int
+c_compile(const char *c_file, const char *so_file)
+{
+ const char *so_args[] = {
+ "-o", so_file,
+# ifdef __clang__
+ "-include-pch", pch_file,
+# endif
+ c_file, NULL
+ };
+
+# if defined(__MACH__)
+ extern VALUE rb_libruby_selfpath;
+ const char *loader_args[] = {"-bundle_loader", StringValuePtr(rb_libruby_selfpath), NULL};
+# else
+ const char *loader_args[] = {NULL};
+# endif
+
+ char **args = form_args(8, CC_LDSHARED_ARGS, CC_CODEFLAG_ARGS, cc_added_args,
+ so_args, loader_args, CC_LIBS, CC_DLDFLAGS_ARGS, CC_LINKER_ARGS);
+ if (args == NULL) return 1;
+
+ int exit_code = exec_process(cc_path, args);
+ if (!mjit_opts.save_temps)
+ remove_file(c_file);
+
+ free(args);
+ return exit_code;
+}
+
+static int
+c_compile_unit(struct rb_mjit_unit *unit)
+{
+ static const char c_ext[] = ".c";
+ static const char so_ext[] = DLEXT;
+ char c_file[MAXPATHLEN], so_file[MAXPATHLEN];
+
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), unit->id, MJIT_TMP_PREFIX, c_ext);
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), unit->id, MJIT_TMP_PREFIX, so_ext);
+
+ return c_compile(c_file, so_file);
+}
+
+static void compile_prelude(FILE *f);
+
+static bool
+mjit_batch(struct rb_mjit_unit *unit)
+{
+ VM_ASSERT(unit->type == MJIT_UNIT_BATCH);
+ static const char c_ext[] = ".c";
+ static const char so_ext[] = DLEXT;
+ char c_file[MAXPATHLEN], so_file[MAXPATHLEN];
+
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), unit->id, MJIT_TMP_PREFIX, c_ext);
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), unit->id, MJIT_TMP_PREFIX, so_ext);
+
+ FILE *f;
+ int fd = rb_cloexec_open(c_file, c_file_access_mode, 0600);
+ if (fd < 0 || (f = fdopen(fd, "w")) == NULL) {
+ int e = errno;
+ if (fd >= 0) (void)close(fd);
+ verbose(1, "Failed to fopen '%s', giving up JIT for it (%s)", c_file, strerror(e));
+ return false;
+ }
+
+ compile_prelude(f);
+
+ bool success = true;
+ struct rb_mjit_unit *child_unit = 0;
+ ccan_list_for_each(&unit->units.head, child_unit, unode) {
+ if (!success) continue;
+ if (child_unit->iseq == NULL) continue; // ISEQ is GCed
+
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ int iseq_lineno = ISEQ_BODY(child_unit->iseq)->location.first_lineno;
+ const char *sep = "@";
+ const char *iseq_label = RSTRING_PTR(ISEQ_BODY(child_unit->iseq)->location.label);
+ const char *iseq_path = RSTRING_PTR(rb_iseq_path(child_unit->iseq));
+ if (!iseq_label) iseq_label = sep = "";
+ fprintf(f, "\n/* %s%s%s:%d */\n", iseq_label, sep, iseq_path, iseq_lineno);
+ success &= mjit_compile(f, child_unit->iseq, funcname, child_unit->id);
+ }
+
+ fclose(f);
+ return success;
+}
+
+// Compile all cached .c files and build a single .so file. Reload all JIT func from it.
+// This improves the code locality for better performance in terms of iTLB and iCache.
+static bool
+mjit_compact(struct rb_mjit_unit *unit)
+{
+ VM_ASSERT(unit->type == MJIT_UNIT_COMPACT);
+ static const char c_ext[] = ".c";
+ static const char so_ext[] = DLEXT;
+ char c_file[MAXPATHLEN], so_file[MAXPATHLEN];
+
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), unit->id, MJIT_TMP_PREFIX, c_ext);
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), unit->id, MJIT_TMP_PREFIX, so_ext);
+
+ FILE *f;
+ int fd = rb_cloexec_open(c_file, c_file_access_mode, 0600);
+ if (fd < 0 || (f = fdopen(fd, "w")) == NULL) {
+ int e = errno;
+ if (fd >= 0) (void)close(fd);
+ verbose(1, "Failed to fopen '%s', giving up JIT for it (%s)", c_file, strerror(e));
+ return false;
+ }
+
+ compile_prelude(f);
+
+ bool success = true;
+ compact_units_length = 0;
+ struct rb_mjit_unit *batch_unit = 0, *child_unit = 0;
+ ccan_list_for_each(&active_units.head, batch_unit, unode) {
+ ccan_list_for_each(&batch_unit->units.head, child_unit, unode) {
+ if (!success) continue;
+ if (child_unit->iseq == NULL) continue; // ISEQ is GCed
+
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ int iseq_lineno = ISEQ_BODY(child_unit->iseq)->location.first_lineno;
+ const char *sep = "@";
+ const char *iseq_label = RSTRING_PTR(ISEQ_BODY(child_unit->iseq)->location.label);
+ const char *iseq_path = RSTRING_PTR(rb_iseq_path(child_unit->iseq));
+ if (!iseq_label) iseq_label = sep = "";
+ fprintf(f, "\n/* %s%s%s:%d */\n", iseq_label, sep, iseq_path, iseq_lineno);
+ success &= mjit_compile(f, child_unit->iseq, funcname, child_unit->id);
+ compact_units_length++;
+ }
+ }
+
+ fclose(f);
+ return success;
+}
+
+static void
+load_batch_funcs_from_so(struct rb_mjit_unit *unit, char *c_file, char *so_file)
+{
+ double end_time = real_ms_time();
+
+ void *handle = dlopen(so_file, RTLD_NOW);
+ if (handle == NULL) {
+ mjit_warning("failure in loading code from batched '%s': %s", so_file, dlerror());
+ xfree(unit);
+ return;
+ }
+ unit->handle = handle;
+
+ // lazily dlclose handle on `mjit_finish()`.
+ add_to_list(unit, &active_units);
+ active_units_length += unit->units.length;
+
+ if (!mjit_opts.save_temps)
+ remove_so_file(so_file, unit);
+
+ struct rb_mjit_unit *child_unit = 0;
+ ccan_list_for_each(&unit->units.head, child_unit, unode) {
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ void *func;
+ if ((func = dlsym(handle, funcname)) == NULL) {
+ mjit_warning("skipping to load '%s' from '%s': %s", funcname, so_file, dlerror());
+ continue;
+ }
+
+ if (child_unit->iseq) { // Check whether GCed or not
+ // Usage of jit_code might be not in a critical section.
+ const rb_iseq_t *iseq = child_unit->iseq;
+ MJIT_ATOMIC_SET(ISEQ_BODY(iseq)->jit_func, (jit_func_t)func);
+
+ verbose(1, "JIT success: %s@%s:%d",
+ RSTRING_PTR(ISEQ_BODY(iseq)->location.label),
+ RSTRING_PTR(rb_iseq_path(iseq)), ISEQ_BODY(iseq)->location.first_lineno);
+ }
+ else {
+ verbose(1, "JIT skip: A compiled method has been GCed");
+ }
+ }
+ verbose(1, "JIT batch (%.1fms): Batched %d methods %s -> %s", end_time - current_cc_ms, unit->units.length, c_file, so_file);
+}
+
+static void
+load_compact_funcs_from_so(struct rb_mjit_unit *unit, char *c_file, char *so_file)
+{
+ double end_time = real_ms_time();
+
+ void *handle = dlopen(so_file, RTLD_NOW);
+ if (handle == NULL) {
+ mjit_warning("failure in loading code from compacted '%s': %s", so_file, dlerror());
+ xfree(unit);
+ return;
+ }
+ unit->handle = handle;
+
+ // lazily dlclose handle on `mjit_finish()`.
+ add_to_list(unit, &compact_units);
+
+ if (!mjit_opts.save_temps)
+ remove_so_file(so_file, unit);
+
+ struct rb_mjit_unit *batch_unit = 0, *child_unit = 0;
+ ccan_list_for_each(&active_units.head, batch_unit, unode) {
+ ccan_list_for_each(&batch_unit->units.head, child_unit, unode) {
+ if (child_unit->iseq == NULL) continue; // ISEQ is GCed
+
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ void *func;
+ if ((func = dlsym(handle, funcname)) == NULL) {
+ mjit_warning("skipping to reload '%s' from '%s': %s", funcname, so_file, dlerror());
+ continue;
+ }
+
+ if (child_unit->iseq) { // Check whether GCed or not
+ // Usage of jit_code might be not in a critical section.
+ MJIT_ATOMIC_SET(ISEQ_BODY(child_unit->iseq)->jit_func, (jit_func_t)func);
+ }
+ }
+ }
+ verbose(1, "JIT compaction (%.1fms): Compacted %d methods %s -> %s", end_time - current_cc_ms, active_units_length, c_file, so_file);
+}
+
+#ifndef __clang__
+static const char *
+header_name_end(const char *s)
+{
+ const char *e = s + strlen(s);
+# ifdef __GNUC__ // don't chomp .pch for mswin
+ static const char suffix[] = ".gch";
+
+ // chomp .gch suffix
+ if (e > s+sizeof(suffix)-1 && strcmp(e-sizeof(suffix)+1, suffix) == 0) {
+ e -= sizeof(suffix)-1;
+ }
+# endif
+ return e;
+}
+#endif
+
+// Print platform-specific prerequisites in generated code.
+static void
+compile_prelude(FILE *f)
+{
+#ifndef __clang__ // -include-pch is used for Clang
+ const char *s = pch_file;
+ const char *e = header_name_end(s);
+
+ fprintf(f, "#include \"");
+ // print pch_file except .gch for gcc, but keep .pch for mswin
+ for (; s < e; s++) {
+ switch (*s) {
+ case '\\': case '"':
+ fputc('\\', f);
+ }
+ fputc(*s, f);
+ }
+ fprintf(f, "\"\n");
+#endif
+}
+
+static pid_t
+start_c_compile_unit(struct rb_mjit_unit *unit)
+{
+ extern pid_t rb_mjit_fork();
+ pid_t pid = rb_mjit_fork();
+ if (pid == 0) {
+ int exit_code = c_compile_unit(unit);
+ exit(exit_code);
+ }
+ else {
+ return pid;
+ }
+}
+
+// Capture cc entries of `captured_iseq` and append them to `compiled_iseq->mjit_unit->cc_entries`.
+// This is needed when `captured_iseq` is inlined by `compiled_iseq` and GC needs to mark inlined cc.
+//
+// Index to refer to `compiled_iseq->mjit_unit->cc_entries` is returned instead of the address
+// because old addresses may be invalidated by `realloc` later. -1 is returned on failure.
+//
+// This assumes that it's safe to reference cc without acquiring GVL.
+int
+mjit_capture_cc_entries(const struct rb_iseq_constant_body *compiled_iseq, const struct rb_iseq_constant_body *captured_iseq)
+{
+ VM_ASSERT(compiled_iseq != NULL);
+ VM_ASSERT(compiled_iseq->mjit_unit != NULL);
+ VM_ASSERT(captured_iseq != NULL);
+
+ struct rb_mjit_unit *unit = compiled_iseq->mjit_unit;
+ unsigned int new_entries_size = unit->cc_entries_size + captured_iseq->ci_size;
+ VM_ASSERT(captured_iseq->ci_size > 0);
+
+ // Allocate new cc_entries and append them to unit->cc_entries
+ const struct rb_callcache **cc_entries;
+ int cc_entries_index = unit->cc_entries_size;
+ if (unit->cc_entries_size == 0) {
+ VM_ASSERT(unit->cc_entries == NULL);
+ unit->cc_entries = cc_entries = malloc(sizeof(struct rb_callcache *) * new_entries_size);
+ if (cc_entries == NULL) return -1;
+ }
+ else {
+ void *cc_ptr = (void *)unit->cc_entries; // get rid of bogus warning by VC
+ cc_entries = realloc(cc_ptr, sizeof(struct rb_callcache *) * new_entries_size);
+ if (cc_entries == NULL) return -1;
+ unit->cc_entries = cc_entries;
+ cc_entries += cc_entries_index;
+ }
+ unit->cc_entries_size = new_entries_size;
+
+ // Capture cc to cc_enties
+ for (unsigned int i = 0; i < captured_iseq->ci_size; i++) {
+ cc_entries[i] = captured_iseq->call_data[i].cc;
+ }
+
+ return cc_entries_index;
+}
+
+static void mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info);
+
+// Return an unique file name in /tmp with PREFIX and SUFFIX and
+// number ID. Use getpid if ID == 0. The return file name exists
+// until the next function call.
+static char *
+get_uniq_filename(unsigned long id, const char *prefix, const char *suffix)
+{
+ char buff[70], *str = buff;
+ int size = sprint_uniq_filename(buff, sizeof(buff), id, prefix, suffix);
+ str = 0;
+ ++size;
+ str = xmalloc(size);
+ if (size <= (int)sizeof(buff)) {
+ memcpy(str, buff, size);
+ }
+ else {
+ sprint_uniq_filename(str, size, id, prefix, suffix);
+ }
+ return str;
+}
+
+// Prohibit calling JIT-ed code and let existing JIT-ed frames exit before the next insn.
+void
+mjit_cancel_all(const char *reason)
+{
+ if (!mjit_enabled)
+ return;
+
+ mjit_call_p = false;
+ mjit_cancel_p = true;
+ if (mjit_opts.warnings || mjit_opts.verbose) {
+ fprintf(stderr, "JIT cancel: Disabled JIT-ed code because %s\n", reason);
+ }
+}
+
+// Deal with ISeq movement from compactor
+void
+mjit_update_references(const rb_iseq_t *iseq)
+{
+ if (!mjit_enabled)
+ return;
+
+ CRITICAL_SECTION_START(4, "mjit_update_references");
+ if (ISEQ_BODY(iseq)->mjit_unit) {
+ ISEQ_BODY(iseq)->mjit_unit->iseq = (rb_iseq_t *)rb_gc_location((VALUE)ISEQ_BODY(iseq)->mjit_unit->iseq);
+ // We need to invalidate JIT-ed code for the ISeq because it embeds pointer addresses.
+ // To efficiently do that, we use the same thing as TracePoint and thus everything is cancelled for now.
+ // See mjit.h and tool/ruby_vm/views/_mjit_compile_insn.erb for how `mjit_call_p` is used.
+ mjit_cancel_all("GC.compact is used"); // TODO: instead of cancelling all, invalidate only this one and recompile it with some threshold.
+ }
+
+ // Units in stale_units (list of over-speculated and invalidated code) are not referenced from
+ // `ISEQ_BODY(iseq)->mjit_unit` anymore (because new one replaces that). So we need to check them too.
+ // TODO: we should be able to reduce the number of units checked here.
+ struct rb_mjit_unit *unit = NULL;
+ ccan_list_for_each(&stale_units.head, unit, unode) {
+ if (unit->iseq == iseq) {
+ unit->iseq = (rb_iseq_t *)rb_gc_location((VALUE)unit->iseq);
+ }
+ }
+ CRITICAL_SECTION_FINISH(4, "mjit_update_references");
+}
+
+// Iseqs can be garbage collected. This function should call when it
+// happens. It removes iseq from the unit.
+void
+mjit_free_iseq(const rb_iseq_t *iseq)
+{
+ if (!mjit_enabled)
+ return;
+
+ if (ISEQ_BODY(iseq)->mjit_unit) {
+ // mjit_unit is not freed here because it may be referred by multiple
+ // lists of units. `get_from_list` and `mjit_finish` do the job.
+ ISEQ_BODY(iseq)->mjit_unit->iseq = NULL;
+ }
+ // Units in stale_units (list of over-speculated and invalidated code) are not referenced from
+ // `ISEQ_BODY(iseq)->mjit_unit` anymore (because new one replaces that). So we need to check them too.
+ // TODO: we should be able to reduce the number of units checked here.
+ struct rb_mjit_unit *unit = NULL;
+ ccan_list_for_each(&stale_units.head, unit, unode) {
+ if (unit->iseq == iseq) {
+ unit->iseq = NULL;
+ }
+ }
+}
+
+// Free unit list. This should be called only when worker is finished
+// because node of unit_queue and one of active_units may have the same unit
+// during proceeding unit.
+static void
+free_list(struct rb_mjit_unit_list *list, bool close_handle_p)
+{
+ struct rb_mjit_unit *unit = 0, *next;
+
+ ccan_list_for_each_safe(&list->head, unit, next, unode) {
+ ccan_list_del(&unit->unode);
+ if (!close_handle_p) unit->handle = NULL; /* Skip dlclose in free_unit() */
+
+ if (list == &stale_units) { // `free_unit(unit)` crashes after GC.compact on `stale_units`
+ /*
+ * TODO: REVERT THIS BRANCH
+ * Debug the crash on stale_units w/ GC.compact and just use `free_unit(unit)`!!
+ */
+ if (unit->handle && dlclose(unit->handle)) {
+ mjit_warning("failed to close handle for u%d: %s", unit->id, dlerror());
+ }
+ xfree(unit);
+ }
+ else {
+ free_unit(unit);
+ }
+ }
+ list->length = 0;
+}
+
+static struct rb_mjit_unit*
+create_unit(enum rb_mjit_unit_type type)
+{
+ struct rb_mjit_unit *unit = ZALLOC_N(struct rb_mjit_unit, 1);
+ unit->id = current_unit_num++;
+ unit->type = type;
+ if (type == MJIT_UNIT_BATCH) {
+ ccan_list_head_init(&unit->units.head);
+ }
+ return unit;
+}
+
+static struct rb_mjit_unit*
+create_iseq_unit(const rb_iseq_t *iseq)
+{
+ struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_ISEQ);
+ unit->iseq = (rb_iseq_t *)iseq;
+ ISEQ_BODY(iseq)->mjit_unit = unit;
+ return unit;
+}
+
+static void mjit_wait(struct rb_mjit_unit *unit);
+
+// Check the unit queue and start mjit_compile if nothing is in progress.
+static void
+check_unit_queue(void)
+{
+ if (mjit_opts.custom) return; // Custom RubyVM::MJIT.compile is in use
+ if (worker_stopped) return;
+ if (current_cc_pid != 0) return; // still compiling
+
+ // TODO: resurrect unload_units
+ if (active_units_length >= mjit_opts.max_cache_size) return; // wait until unload_units makes a progress
+
+ // No ISEQ in unit_queue has enough calls to trigger JIT
+ if (!mjit_compile_p) return;
+ mjit_compile_p = false;
+
+ // Compile all ISEQs in unit_queue together
+ struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_BATCH);
+ struct rb_mjit_unit *child_unit = NULL;
+ VM_ASSERT(unit_queue.length > 0);
+ while ((child_unit = get_from_list(&unit_queue)) != NULL && (active_units_length + unit->units.length) < mjit_opts.max_cache_size) {
+ add_to_list(child_unit, &unit->units);
+ ISEQ_BODY(child_unit->iseq)->jit_func = (jit_func_t)MJIT_FUNC_COMPILING;
+ }
+
+ // Run the MJIT compiler synchronously
+ current_cc_ms = real_ms_time();
+ current_cc_unit = unit;
+ bool success = mjit_batch(unit);
+ if (!success) {
+ mjit_notify_waitpid(1);
+ return;
+ }
+
+ // Run the C compiler asynchronously (unless --mjit-wait)
+ if (mjit_opts.wait) {
+ int exit_code = c_compile_unit(unit);
+ mjit_notify_waitpid(exit_code);
+ }
+ else {
+ current_cc_pid = start_c_compile_unit(unit);
+ if (current_cc_pid == -1) { // JIT failure
+ mjit_notify_waitpid(1);
+ }
+ }
+}
+
+// Check if it should compact all JIT code and start it as needed
+static void
+check_compaction(void)
+{
+ // Allow only `max_cache_size / 100` times (default: 100) of compaction.
+ // Note: GC of compacted code has not been implemented yet.
+ int max_compact_size = mjit_opts.max_cache_size / 100;
+ if (max_compact_size < 10) max_compact_size = 10;
+
+ // Run JIT compaction only when it's going to add 10%+ units.
+ int throttle_threshold = active_units_length / 10;
+
+ if (compact_units.length < max_compact_size
+ && active_units_length - compact_units_length > throttle_threshold
+ && ((!mjit_opts.wait && unit_queue.length == 0 && active_units.length > 1)
+ || (active_units_length == mjit_opts.max_cache_size))) {
+ struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_COMPACT);
+
+ // Run the MJIT compiler synchronously
+ current_cc_ms = real_ms_time();
+ current_cc_unit = unit;
+ bool success = mjit_compact(unit);
+ if (!success) {
+ mjit_notify_waitpid(1);
+ return;
+ }
+
+ // Run the C compiler asynchronously (unless --mjit-wait)
+ if (mjit_opts.wait) {
+ int exit_code = c_compile_unit(unit);
+ mjit_notify_waitpid(exit_code);
+ }
+ else {
+ current_cc_pid = start_c_compile_unit(unit);
+ if (current_cc_pid == -1) { // JIT failure
+ mjit_notify_waitpid(1);
+ }
+ }
+ }
+}
+
+// Check the current CC process if any, and start a next C compiler process as needed.
+void
+mjit_notify_waitpid(int exit_code)
+{
+ VM_ASSERT(mjit_opts.wait || current_cc_pid != 0);
+ current_cc_pid = 0;
+
+ // Delete .c file
+ char c_file[MAXPATHLEN];
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), current_cc_unit->id, MJIT_TMP_PREFIX, ".c");
+
+ // Check the result
+ if (exit_code != 0) {
+ verbose(2, "Failed to generate so");
+ // TODO: set MJIT_FUNC_FAILED to unit->units
+ // TODO: free list of unit->units
+ free_unit(current_cc_unit);
+ current_cc_unit = NULL;
+ return;
+ }
+
+ // Load .so file
+ char so_file[MAXPATHLEN];
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), current_cc_unit->id, MJIT_TMP_PREFIX, DLEXT);
+ switch (current_cc_unit->type) {
+ case MJIT_UNIT_ISEQ:
+ rb_bug("unreachable: current_cc_unit->type must not be MJIT_UNIT_ISEQ");
+ case MJIT_UNIT_BATCH:
+ load_batch_funcs_from_so(current_cc_unit, c_file, so_file);
+ current_cc_unit = NULL;
+
+ // Run compaction if it should
+ if (!stop_worker_p) {
+ check_compaction();
+ }
+ break;
+ case MJIT_UNIT_COMPACT:
+ load_compact_funcs_from_so(current_cc_unit, c_file, so_file);
+ current_cc_unit = NULL;
+ break;
+ }
+
+ // Skip further compilation if mjit_finish is trying to stop it
+ if (!stop_worker_p) {
+ // Start the next one as needed
+ check_unit_queue();
+ }
+}
+
+// Return true if given ISeq body should be compiled by MJIT
+static inline int
+mjit_target_iseq_p(const rb_iseq_t *iseq)
+{
+ struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+ return (body->type == ISEQ_TYPE_METHOD || body->type == ISEQ_TYPE_BLOCK)
+ && !body->builtin_inline_p
+ && strcmp("<internal:mjit>", RSTRING_PTR(rb_iseq_path(iseq))) != 0;
+}
+
+// RubyVM::MJIT
+static VALUE rb_mMJIT = 0;
+// RubyVM::MJIT::C
+static VALUE rb_mMJITC = 0;
+// RubyVM::MJIT::Compiler
+static VALUE rb_cMJITCompiler = 0;
+// RubyVM::MJIT::CPointer::Struct_rb_iseq_t
+static VALUE rb_cMJITIseqPtr = 0;
+// RubyVM::MJIT::CPointer::Struct_IC
+static VALUE rb_cMJITICPtr = 0;
+// RubyVM::MJIT::Compiler
+static VALUE rb_mMJITHooks = 0;
+
+#define WITH_MJIT_DISABLED(stmt) do { \
+ bool original_call_p = mjit_call_p; \
+ mjit_call_p = false; \
+ stmt; \
+ mjit_call_p = original_call_p; \
+ if (mjit_cancel_p) mjit_call_p = false; \
+} while (0);
+
+// Hook MJIT when BOP is redefined.
+MJIT_FUNC_EXPORTED void
+rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_bop_redefined"), 2, INT2NUM(redefined_flag), INT2NUM((int)bop));
+ });
+}
+
+// Hook MJIT when CME is invalidated.
+MJIT_FUNC_EXPORTED void
+rb_mjit_cme_invalidate(rb_callable_method_entry_t *cme)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ VALUE cme_klass = rb_funcall(rb_mMJITC, rb_intern("rb_callable_method_entry_struct"), 0);
+ VALUE cme_ptr = rb_funcall(cme_klass, rb_intern("new"), 1, SIZET2NUM((size_t)cme));
+ rb_funcall(rb_mMJITHooks, rb_intern("on_cme_invalidate"), 1, cme_ptr);
+ });
+}
+
+// Hook MJIT when Ractor is spawned.
+void
+rb_mjit_before_ractor_spawn(void)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_ractor_spawn"), 0);
+ });
+}
+
+static void
+mjit_constant_state_changed(void *data)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ ID id = (ID)data;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_constant_state_changed"), 1, ID2SYM(id));
+ });
+}
+
+// Hook MJIT when constant state is changed.
+MJIT_FUNC_EXPORTED void
+rb_mjit_constant_state_changed(ID id)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ // Asynchronously hook the Ruby code since this is hooked during a "Ruby critical section".
+ extern int rb_workqueue_register(unsigned flags, rb_postponed_job_func_t func, void *data);
+ rb_workqueue_register(0, mjit_constant_state_changed, (void *)id);
+}
+
+// Hook MJIT when constant IC is updated.
+MJIT_FUNC_EXPORTED void
+rb_mjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ VALUE iseq_ptr = rb_funcall(rb_cMJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
+ VALUE ic_ptr = rb_funcall(rb_cMJITICPtr, rb_intern("new"), 1, SIZET2NUM((size_t)ic));
+ rb_funcall(rb_mMJITHooks, rb_intern("on_constant_ic_update"), 3, iseq_ptr, ic_ptr, UINT2NUM(insn_idx));
+ });
+}
+
+// Hook MJIT when TracePoint is enabled.
+MJIT_FUNC_EXPORTED void
+rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_tracing_invalidate_all"), 1, UINT2NUM(new_iseq_events));
+ });
+}
+
+// [experimental] Call custom RubyVM::MJIT.compile if defined
+static void
+mjit_hook_custom_compile(const rb_iseq_t *iseq)
+{
+ WITH_MJIT_DISABLED({
+ VALUE iseq_class = rb_funcall(rb_mMJITC, rb_intern("rb_iseq_t"), 0);
+ VALUE iseq_ptr = rb_funcall(iseq_class, rb_intern("new"), 1, ULONG2NUM((size_t)iseq));
+ VALUE jit_func = rb_funcall(rb_mMJIT, rb_intern("compile"), 1, iseq_ptr);
+ ISEQ_BODY(iseq)->jit_func = (jit_func_t)NUM2ULONG(jit_func);
+ });
+}
+
+static void
+mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info)
+{
+ if (!mjit_enabled) return;
+ if (mjit_opts.custom) { // Hook custom RubyVM::MJIT.compile if defined
+ mjit_hook_custom_compile(iseq);
+ return;
+ }
+ if (pch_status != PCH_SUCCESS || !rb_ractor_main_p()) // TODO: Support non-main Ractors
+ return;
+ if (!mjit_target_iseq_p(iseq)) {
+ ISEQ_BODY(iseq)->jit_func = (jit_func_t)MJIT_FUNC_FAILED; // skip mjit_wait
+ return;
+ }
+
+ // For batching multiple ISEQs, we only enqueue ISEQs when total_calls reaches call_threshold,
+ // and compile all enqueued ISEQs when any ISEQ reaches call_threshold * 2.
+ bool recompile_p = !MJIT_FUNC_STATE_P(ISEQ_BODY(iseq)->jit_func);
+ if (!ISEQ_BODY(iseq)->mjit_unit || recompile_p) { // call_threshold, or recompile
+ // Discard an old unit with recompile_p
+ if (recompile_p) {
+ ISEQ_BODY(iseq)->mjit_unit->iseq = NULL; // Ignore this from compaction
+ ISEQ_BODY(iseq)->jit_func = (jit_func_t)MJIT_FUNC_NOT_COMPILED;
+ active_units_length--;
+ }
+
+ // Create a new unit and enqueue it
+ struct rb_mjit_unit *unit = create_iseq_unit(iseq);
+ if (recompile_p) {
+ VM_ASSERT(compile_info != NULL);
+ unit->compile_info = *compile_info;
+ }
+ add_to_list(unit, &unit_queue);
+ ISEQ_BODY(iseq)->total_calls = 0; // come here again :)
+ }
+ else { // call_threshold * 2
+ VM_ASSERT(compile_info == NULL);
+ mjit_compile_p = true; // compile all ISEQs in unit_queue
+ }
+}
+
+// Add ISEQ to be JITed in parallel with the current thread.
+// Unload some JIT codes if there are too many of them.
+void
+rb_mjit_add_iseq_to_process(const rb_iseq_t *iseq)
+{
+ mjit_add_iseq_to_process(iseq, NULL);
+ check_unit_queue();
+}
+
+// For this timeout seconds, mjit_finish will wait for JIT compilation finish.
+#define MJIT_WAIT_TIMEOUT_SECONDS 5
+
+static void
+mjit_wait(struct rb_mjit_unit *unit)
+{
+ pid_t initial_pid = current_cc_pid;
+ if (initial_pid == 0) {
+ mjit_warning("initial_pid was 0 on mjit_wait");
+ return;
+ }
+ if (pch_status == PCH_FAILED) return;
+
+ int tries = 0;
+ struct timeval tv = { .tv_sec = 0, .tv_usec = 1000 };
+ while (current_cc_pid == initial_pid) {
+ tries++;
+ if (tries / 1000 > MJIT_WAIT_TIMEOUT_SECONDS) {
+ if (unit->type == MJIT_UNIT_ISEQ) {
+ unit->iseq->body->jit_func = (jit_func_t)MJIT_FUNC_FAILED; // C compiler was too slow. Give up.
+ }
+ mjit_warning("timed out to wait for JIT finish");
+ break;
+ }
+
+ rb_thread_wait_for(tv);
+ }
+}
+
+struct rb_mjit_compile_info*
+rb_mjit_iseq_compile_info(const struct rb_iseq_constant_body *body)
+{
+ VM_ASSERT(body->mjit_unit != NULL);
+ return &body->mjit_unit->compile_info;
+}
+
+static void
+mjit_recompile(const rb_iseq_t *iseq)
+{
+ if (MJIT_FUNC_STATE_P(ISEQ_BODY(iseq)->jit_func))
+ return;
+
+ verbose(1, "JIT recompile: %s@%s:%d", RSTRING_PTR(ISEQ_BODY(iseq)->location.label),
+ RSTRING_PTR(rb_iseq_path(iseq)), ISEQ_BODY(iseq)->location.first_lineno);
+ VM_ASSERT(ISEQ_BODY(iseq)->mjit_unit != NULL);
+
+ mjit_add_iseq_to_process(iseq, &ISEQ_BODY(iseq)->mjit_unit->compile_info);
+ check_unit_queue();
+}
+
+// Recompile iseq, disabling send optimization
+void
+rb_mjit_recompile_send(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_send_cache = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling ivar optimization
+void
+rb_mjit_recompile_ivar(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_ivar_cache = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling exivar optimization
+void
+rb_mjit_recompile_exivar(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_exivar_cache = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling method inlining
+void
+rb_mjit_recompile_inlining(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_inlining = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling getconstant inlining
+void
+rb_mjit_recompile_const(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_const_cache = true;
+ mjit_recompile(iseq);
+}
+
+extern VALUE ruby_archlibdir_path, ruby_prefix_path;
+
+// Initialize header_file, pch_file, libruby_pathflag. Return true on success.
+static bool
+init_header_filename(void)
+{
+ int fd;
+#ifdef LOAD_RELATIVE
+ // Root path of the running ruby process. Equal to RbConfig::TOPDIR.
+ VALUE basedir_val;
+#endif
+ const char *basedir = "";
+ size_t baselen = 0;
+ char *p;
+
+#ifdef LOAD_RELATIVE
+ basedir_val = ruby_prefix_path;
+ basedir = StringValuePtr(basedir_val);
+ baselen = RSTRING_LEN(basedir_val);
+#else
+ if (getenv("MJIT_SEARCH_BUILD_DIR")) {
+ // This path is not intended to be used on production, but using build directory's
+ // header file here because people want to run `make test-all` without running
+ // `make install`. Don't use $MJIT_SEARCH_BUILD_DIR except for test-all.
+
+ struct stat st;
+ const char *hdr = dlsym(RTLD_DEFAULT, "MJIT_HEADER");
+ if (!hdr) {
+ verbose(1, "No MJIT_HEADER");
+ }
+ else if (hdr[0] != '/') {
+ verbose(1, "Non-absolute header file path: %s", hdr);
+ }
+ else if (stat(hdr, &st) || !S_ISREG(st.st_mode)) {
+ verbose(1, "Non-file header file path: %s", hdr);
+ }
+ else if ((st.st_uid != getuid()) || (st.st_mode & 022) ||
+ !rb_path_check(hdr)) {
+ verbose(1, "Unsafe header file: uid=%ld mode=%#o %s",
+ (long)st.st_uid, (unsigned)st.st_mode, hdr);
+ return FALSE;
+ }
+ else {
+ // Do not pass PRELOADENV to child processes, on
+ // multi-arch environment
+ verbose(3, "PRELOADENV("PRELOADENV")=%s", getenv(PRELOADENV));
+ // assume no other PRELOADENV in test-all
+ unsetenv(PRELOADENV);
+ verbose(3, "MJIT_HEADER: %s", hdr);
+ header_file = ruby_strdup(hdr);
+ if (!header_file) return false;
+ }
+ }
+ else
+#endif
+ {
+ // A name of the header file included in any C file generated by MJIT for iseqs.
+ static const char header_name[] = MJIT_HEADER_INSTALL_DIR "/" MJIT_MIN_HEADER_NAME;
+ const size_t header_name_len = sizeof(header_name) - 1;
+
+ header_file = xmalloc(baselen + header_name_len + 1);
+ p = append_str2(header_file, basedir, baselen);
+ p = append_str2(p, header_name, header_name_len + 1);
+
+ if ((fd = rb_cloexec_open(header_file, O_RDONLY, 0)) < 0) {
+ verbose(1, "Cannot access header file: %s", header_file);
+ xfree(header_file);
+ header_file = NULL;
+ return false;
+ }
+ (void)close(fd);
+ }
+
+ pch_file = get_uniq_filename(0, MJIT_TMP_PREFIX "h", ".h.gch");
+
+ return true;
+}
+
+static char *
+system_default_tmpdir(void)
+{
+ // c.f. ext/etc/etc.c:etc_systmpdir()
+#if defined _CS_DARWIN_USER_TEMP_DIR
+ char path[MAXPATHLEN];
+ size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
+ if (len > 0) {
+ char *tmpdir = xmalloc(len);
+ if (len > sizeof(path)) {
+ confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir, len);
+ }
+ else {
+ memcpy(tmpdir, path, len);
+ }
+ return tmpdir;
+ }
+#endif
+ return 0;
+}
+
+static int
+check_tmpdir(const char *dir)
+{
+ struct stat st;
+
+ if (!dir) return FALSE;
+ if (stat(dir, &st)) return FALSE;
+#ifndef S_ISDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+ if (!S_ISDIR(st.st_mode)) return FALSE;
+#ifndef S_IWOTH
+# define S_IWOTH 002
+#endif
+ if (st.st_mode & S_IWOTH) {
+#ifdef S_ISVTX
+ if (!(st.st_mode & S_ISVTX)) return FALSE;
+#else
+ return FALSE;
+#endif
+ }
+ if (access(dir, W_OK)) return FALSE;
+ return TRUE;
+}
+
+static char *
+system_tmpdir(void)
+{
+ char *tmpdir;
+# define RETURN_ENV(name) \
+ if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
+ RETURN_ENV("TMPDIR");
+ RETURN_ENV("TMP");
+ tmpdir = system_default_tmpdir();
+ if (check_tmpdir(tmpdir)) return tmpdir;
+ return ruby_strdup("/tmp");
+# undef RETURN_ENV
+}
+
+// Minimum value for JIT cache size.
+#define MIN_CACHE_SIZE 10
+// Default permitted number of units with a JIT code kept in memory.
+#define DEFAULT_MAX_CACHE_SIZE 100
+// A default threshold used to add iseq to JIT.
+#define DEFAULT_CALL_THRESHOLD 10000
+
+// Start MJIT worker. Return TRUE if worker is successfully started.
+static bool
+start_worker(void)
+{
+ stop_worker_p = false;
+ worker_stopped = false;
+ return true;
+}
+
+// There's no strndup on Windows
+static char*
+ruby_strndup(const char *str, size_t n)
+{
+ char *ret = xmalloc(n + 1);
+ memcpy(ret, str, n);
+ ret[n] = '\0';
+ return ret;
+}
+
+// Convert "foo bar" to {"foo", "bar", NULL} array. Caller is responsible for
+// freeing a returned buffer and its elements.
+static char **
+split_flags(const char *flags)
+{
+ char *buf[MAXPATHLEN];
+ int i = 0;
+ char *next;
+ for (; flags != NULL; flags = next) {
+ next = strchr(flags, ' ');
+ if (next == NULL) {
+ if (strlen(flags) > 0)
+ buf[i++] = strdup(flags);
+ }
+ else {
+ if (next > flags)
+ buf[i++] = ruby_strndup(flags, next - flags);
+ next++; // skip space
+ }
+ }
+
+ char **ret = xmalloc(sizeof(char *) * (i + 1));
+ memcpy(ret, buf, sizeof(char *) * i);
+ ret[i] = NULL;
+ return ret;
+}
+
+#define opt_match_noarg(s, l, name) \
+ opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --mjit-" name " is ignored"), 1) : 1)
+#define opt_match_arg(s, l, name) \
+ opt_match(s, l, name) && (*(s) ? 1 : (rb_raise(rb_eRuntimeError, "--mjit-" name " needs an argument"), 0))
+
+void
+mjit_setup_options(const char *s, struct mjit_options *mjit_opt)
+{
+ const size_t l = strlen(s);
+ if (l == 0) {
+ return;
+ }
+ else if (opt_match_noarg(s, l, "warnings")) {
+ mjit_opt->warnings = true;
+ }
+ else if (opt_match(s, l, "debug")) {
+ if (*s)
+ mjit_opt->debug_flags = strdup(s + 1);
+ else
+ mjit_opt->debug = true;
+ }
+ else if (opt_match_noarg(s, l, "wait")) {
+ mjit_opt->wait = true;
+ }
+ else if (opt_match_noarg(s, l, "save-temps")) {
+ mjit_opt->save_temps = true;
+ }
+ else if (opt_match(s, l, "verbose")) {
+ mjit_opt->verbose = *s ? atoi(s + 1) : 1;
+ }
+ else if (opt_match_arg(s, l, "max-cache")) {
+ mjit_opt->max_cache_size = atoi(s + 1);
+ }
+ else if (opt_match_arg(s, l, "call-threshold")) {
+ mjit_opt->call_threshold = atoi(s + 1);
+ }
+ // --mjit=pause is an undocumented feature for experiments
+ else if (opt_match_noarg(s, l, "pause")) {
+ mjit_opt->pause = true;
+ }
+ else {
+ rb_raise(rb_eRuntimeError,
+ "invalid MJIT option `%s' (--help will show valid MJIT options)", s);
+ }
+}
+
+#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
+const struct ruby_opt_message mjit_option_messages[] = {
+ M("--mjit-warnings", "", "Enable printing JIT warnings"),
+ M("--mjit-debug", "", "Enable JIT debugging (very slow), or add cflags if specified"),
+ M("--mjit-wait", "", "Wait until JIT compilation finishes every time (for testing)"),
+ M("--mjit-save-temps", "", "Save JIT temporary files in $TMP or /tmp (for testing)"),
+ M("--mjit-verbose=num", "", "Print JIT logs of level num or less to stderr (default: 0)"),
+ M("--mjit-max-cache=num", "", "Max number of methods to be JIT-ed in a cache (default: "
+ STRINGIZE(DEFAULT_MAX_CACHE_SIZE) ")"),
+ M("--mjit-call-threshold=num", "", "Number of calls to trigger JIT (for testing, default: "
+ STRINGIZE(DEFAULT_CALL_THRESHOLD) ")"),
+ {0}
+};
+#undef M
+
+// Initialize MJIT. Start a thread creating the precompiled header and
+// processing ISeqs. The function should be called first for using MJIT.
+// If everything is successful, MJIT_INIT_P will be TRUE.
+void
+mjit_init(const struct mjit_options *opts)
+{
+ VM_ASSERT(mjit_enabled);
+ mjit_opts = *opts;
+
+ // MJIT doesn't support miniruby, but it might reach here by MJIT_FORCE_ENABLE.
+ rb_mMJIT = rb_const_get(rb_cRubyVM, rb_intern("MJIT"));
+ if (!rb_const_defined(rb_mMJIT, rb_intern("Compiler"))) {
+ verbose(1, "Disabling MJIT because RubyVM::MJIT::Compiler is not defined");
+ mjit_enabled = false;
+ return;
+ }
+ rb_mMJITC = rb_const_get(rb_mMJIT, rb_intern("C"));
+ rb_cMJITCompiler = rb_funcall(rb_const_get(rb_mMJIT, rb_intern("Compiler")), rb_intern("new"), 0);
+ rb_cMJITIseqPtr = rb_funcall(rb_mMJITC, rb_intern("rb_iseq_t"), 0);
+ rb_cMJITICPtr = rb_funcall(rb_mMJITC, rb_intern("IC"), 0);
+ rb_funcall(rb_cMJITICPtr, rb_intern("new"), 1, SIZET2NUM(0)); // Trigger no-op constant events before enabling hooks
+ rb_mMJITHooks = rb_const_get(rb_mMJIT, rb_intern("Hooks"));
+
+ mjit_call_p = true;
+ mjit_pid = getpid();
+
+ // Normalize options
+ if (mjit_opts.call_threshold == 0)
+ mjit_opts.call_threshold = DEFAULT_CALL_THRESHOLD;
+ if (mjit_opts.call_threshold % 2 == 1) {
+ mjit_opts.call_threshold += 1;
+ mjit_warning("--mjit-call-threshold must be an even number. Using %d instead.", mjit_opts.call_threshold);
+ }
+ mjit_opts.call_threshold /= 2; // Half for enqueue, half for trigger
+ if (mjit_opts.max_cache_size <= 0)
+ mjit_opts.max_cache_size = DEFAULT_MAX_CACHE_SIZE;
+ if (mjit_opts.max_cache_size < MIN_CACHE_SIZE)
+ mjit_opts.max_cache_size = MIN_CACHE_SIZE;
+
+ // Initialize variables for compilation
+ pch_status = PCH_NOT_READY;
+ cc_path = CC_COMMON_ARGS[0];
+ verbose(2, "MJIT: CC defaults to %s", cc_path);
+ cc_common_args = xmalloc(sizeof(CC_COMMON_ARGS));
+ memcpy((void *)cc_common_args, CC_COMMON_ARGS, sizeof(CC_COMMON_ARGS));
+ cc_added_args = split_flags(opts->debug_flags);
+ xfree(opts->debug_flags);
+#if MJIT_CFLAGS_PIPE
+ // Filter out `-save-temps`. It's a C compiler flag used by update-deps and not compatible with `-pipe`.
+ for (size_t i = 0, j = 0; i < sizeof(CC_COMMON_ARGS) / sizeof(char *); i++) {
+ if (CC_COMMON_ARGS[i] && strncmp("-save-temps", CC_COMMON_ARGS[i], strlen("-save-temps")) == 0)
+ continue; // Skip `-save-temps`
+ cc_common_args[j] = CC_COMMON_ARGS[i];
+ j++;
+ }
+#endif
+
+ tmp_dir = system_tmpdir();
+ verbose(2, "MJIT: tmp_dir is %s", tmp_dir);
+
+ if (!init_header_filename()) {
+ mjit_enabled = false;
+ verbose(1, "Failure in MJIT header file name initialization\n");
+ return;
+ }
+ pch_owner_pid = getpid();
+
+ // Initialize mutex
+ rb_native_mutex_initialize(&mjit_engine_mutex);
+
+ // If --mjit=pause is given, lazily start MJIT when RubyVM::MJIT.resume is called.
+ // You can use it to control MJIT warmup, or to customize the JIT implementation.
+ if (!mjit_opts.pause) {
+ // TODO: Consider running C compiler asynchronously
+ make_pch();
+
+ // Enable MJIT compilation
+ start_worker();
+ }
+}
+
+static void
+stop_worker(void)
+{
+ stop_worker_p = true;
+ if (current_cc_unit != NULL) {
+ mjit_wait(current_cc_unit);
+ }
+ worker_stopped = true;
+}
+
+// Stop JIT-compiling methods but compiled code is kept available.
+VALUE
+mjit_pause(bool wait_p)
+{
+ if (!mjit_enabled) {
+ rb_raise(rb_eRuntimeError, "MJIT is not enabled");
+ }
+ if (worker_stopped) {
+ return Qfalse;
+ }
+
+ // Flush all queued units with no option or `wait: true`
+ if (wait_p) {
+ while (current_cc_unit != NULL) {
+ mjit_wait(current_cc_unit);
+ }
+ }
+
+ stop_worker();
+ return Qtrue;
+}
+
+// Restart JIT-compiling methods after mjit_pause.
+VALUE
+mjit_resume(void)
+{
+ if (!mjit_enabled) {
+ rb_raise(rb_eRuntimeError, "MJIT is not enabled");
+ }
+ if (!worker_stopped) {
+ return Qfalse;
+ }
+
+ // Lazily prepare PCH when --mjit=pause is given
+ if (pch_status == PCH_NOT_READY) {
+ if (rb_respond_to(rb_mMJIT, rb_intern("compile"))) {
+ // [experimental] defining RubyVM::MJIT.compile allows you to replace JIT
+ mjit_opts.custom = true;
+ pch_status = PCH_SUCCESS;
+ }
+ else {
+ // Lazy MJIT boot
+ make_pch();
+ }
+ }
+
+ if (!start_worker()) {
+ rb_raise(rb_eRuntimeError, "Failed to resume MJIT worker");
+ }
+ return Qtrue;
+}
+
+// This is called after fork initiated by Ruby's method to launch MJIT worker thread
+// for child Ruby process.
+//
+// In multi-process Ruby applications, child Ruby processes do most of the jobs.
+// Thus we want child Ruby processes to enqueue ISeqs to MJIT worker's queue and
+// call the JIT-ed code.
+//
+// But unfortunately current MJIT-generated code is process-specific. After the fork,
+// JIT-ed code created by parent Ruby process cannot be used in child Ruby process
+// because the code could rely on inline cache values (ivar's IC, send's CC) which
+// may vary between processes after fork or embed some process-specific addresses.
+//
+// So child Ruby process can't request parent process to JIT an ISeq and use the code.
+// Instead of that, MJIT worker thread is created for all child Ruby processes, even
+// while child processes would end up with compiling the same ISeqs.
+void
+mjit_child_after_fork(void)
+{
+ if (!mjit_enabled)
+ return;
+
+ /* MJIT worker thread is not inherited on fork. Start it for this child process. */
+ start_worker();
+}
+
+// Finish the threads processing units and creating PCH, finalize
+// and free MJIT data. It should be called last during MJIT
+// life.
+//
+// If close_handle_p is true, it calls dlclose() for JIT-ed code. So it should be false
+// if the code can still be on stack. ...But it means to leak JIT-ed handle forever (FIXME).
+void
+mjit_finish(bool close_handle_p)
+{
+ if (!mjit_enabled)
+ return;
+
+ // Stop worker
+ verbose(2, "Stopping worker thread");
+ stop_worker();
+
+ rb_native_mutex_destroy(&mjit_engine_mutex);
+
+ if (!mjit_opts.save_temps && getpid() == pch_owner_pid && pch_status == PCH_SUCCESS && !mjit_opts.custom)
+ remove_file(pch_file);
+
+ xfree(header_file); header_file = NULL;
+ xfree((void *)cc_common_args); cc_common_args = NULL;
+ for (char **flag = cc_added_args; *flag != NULL; flag++)
+ xfree(*flag);
+ xfree((void *)cc_added_args); cc_added_args = NULL;
+ xfree(tmp_dir); tmp_dir = NULL;
+ xfree(pch_file); pch_file = NULL;
+
+ mjit_call_p = false;
+ free_list(&unit_queue, close_handle_p);
+ free_list(&active_units, close_handle_p);
+ free_list(&compact_units, close_handle_p);
+ free_list(&stale_units, close_handle_p);
+
+ mjit_enabled = false;
+ verbose(1, "Successful MJIT finish");
+}
+
+// Called by rb_vm_mark().
+//
+// Mark active_units so that we do not GC ISeq which may still be
+// referenced by mjit_recompile() or mjit_compact().
+void
+mjit_mark(void)
+{
+ if (!mjit_enabled)
+ return;
+ RUBY_MARK_ENTER("mjit");
+
+ // Mark objects used by the MJIT compiler
+ rb_gc_mark(rb_cMJITCompiler);
+ rb_gc_mark(rb_cMJITIseqPtr);
+ rb_gc_mark(rb_cMJITICPtr);
+ rb_gc_mark(rb_mMJITHooks);
+
+ // Mark JIT-compiled ISEQs
+ struct rb_mjit_unit *unit = NULL;
+ ccan_list_for_each(&active_units.head, unit, unode) {
+ rb_gc_mark((VALUE)unit->iseq);
+ }
+
+ RUBY_MARK_LEAVE("mjit");
+}
+
+// Called by rb_iseq_mark() to mark cc_entries captured for MJIT
+void
+mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body)
+{
+ const struct rb_callcache **cc_entries;
+ if (body->mjit_unit && (cc_entries = body->mjit_unit->cc_entries) != NULL) {
+ // It must be `body->mjit_unit->cc_entries_size` instead of `body->ci_size` to mark children's cc_entries
+ for (unsigned int i = 0; i < body->mjit_unit->cc_entries_size; i++) {
+ const struct rb_callcache *cc = cc_entries[i];
+ if (cc != NULL && vm_cc_markable(cc)) {
+ // Pin `cc` and `cc->cme` against GC.compact as their addresses may be written in JIT-ed code.
+ rb_gc_mark((VALUE)cc);
+ rb_gc_mark((VALUE)vm_cc_cme(cc));
+ }
+ }
+ }
+}
+
+// Compile ISeq to C code in `f`. It returns true if it succeeds to compile.
+bool
+mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id)
+{
+ bool original_call_p = mjit_call_p;
+ mjit_call_p = false; // Avoid impacting JIT metrics by itself
+
+ VALUE iseq_ptr = rb_funcall(rb_cMJITIseqPtr, rb_intern("new"), 1, ULONG2NUM((size_t)iseq));
+ VALUE src = rb_funcall(rb_cMJITCompiler, rb_intern("compile"), 3,
+ iseq_ptr, rb_str_new_cstr(funcname), INT2NUM(id));
+ if (!NIL_P(src)) {
+ fprintf(f, "%s", RSTRING_PTR(src));
+ }
+
+ mjit_call_p = original_call_p;
+ return !NIL_P(src);
+}
+
+#include "mjit.rbinc"
+
+#endif // USE_MJIT
diff --git a/mjit.h b/mjit.h
new file mode 100644
index 0000000000..260cf4af78
--- /dev/null
+++ b/mjit.h
@@ -0,0 +1,145 @@
+#ifndef RUBY_MJIT_H
+#define RUBY_MJIT_H 1
+/**********************************************************************
+
+ mjit.h - Interface to MRI method JIT compiler
+
+ Copyright (C) 2017 Vladimir Makarov <vmakarov@redhat.com>.
+ Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
+
+**********************************************************************/
+
+#include "ruby/internal/config.h" // defines USE_MJIT
+#include "ruby/internal/stdbool.h"
+#include "vm_core.h"
+
+# if USE_MJIT
+
+#include "ruby.h"
+#include "vm_core.h"
+
+// Special address values of a function generated from the
+// corresponding iseq by MJIT:
+enum rb_mjit_func_state {
+ // ISEQ has not been compiled yet
+ MJIT_FUNC_NOT_COMPILED = 0,
+ // ISEQ is already queued for the machine code generation but the
+ // code is not ready yet for the execution
+ MJIT_FUNC_COMPILING = 1,
+ // ISEQ included not compilable insn, some internal assertion failed
+ // or the unit is unloaded
+ MJIT_FUNC_FAILED = 2,
+};
+// Return true if jit_func is part of enum rb_mjit_func_state
+#define MJIT_FUNC_STATE_P(jit_func) ((uintptr_t)(jit_func) <= (uintptr_t)MJIT_FUNC_FAILED)
+
+// MJIT options which can be defined on the MRI command line.
+struct mjit_options {
+ // Converted from "jit" feature flag to tell the enablement
+ // information to ruby_show_version().
+ bool on;
+ // Save temporary files after MRI finish. The temporary files
+ // include the pre-compiled header, C code file generated for ISEQ,
+ // and the corresponding object file.
+ bool save_temps;
+ // Print MJIT warnings to stderr.
+ bool warnings;
+ // Disable compiler optimization and add debug symbols. It can be
+ // very slow.
+ bool debug;
+ // Add arbitrary cflags.
+ char* debug_flags;
+ // If true, all ISeqs are synchronously compiled. For testing.
+ bool wait;
+ // Number of calls to trigger JIT compilation. For testing.
+ unsigned int call_threshold;
+ // Force printing info about MJIT work of level VERBOSE or
+ // less. 0=silence, 1=medium, 2=verbose.
+ int verbose;
+ // Maximal permitted number of iseq JIT codes in a MJIT memory
+ // cache.
+ int max_cache_size;
+ // [experimental] Do not start MJIT until MJIT.resume is called.
+ bool pause;
+ // [experimental] Call custom RubyVM::MJIT.compile instead of MJIT.
+ bool custom;
+};
+
+// State of optimization switches
+struct rb_mjit_compile_info {
+ // Disable getinstancevariable/setinstancevariable optimizations based on inline cache (T_OBJECT)
+ bool disable_ivar_cache;
+ // Disable getinstancevariable/setinstancevariable optimizations based on inline cache (FL_EXIVAR)
+ bool disable_exivar_cache;
+ // Disable send/opt_send_without_block optimizations based on inline cache
+ bool disable_send_cache;
+ // Disable method inlining
+ bool disable_inlining;
+ // Disable opt_getinlinecache inlining
+ bool disable_const_cache;
+};
+
+typedef VALUE (*jit_func_t)(rb_execution_context_t *, rb_control_frame_t *);
+
+RUBY_SYMBOL_EXPORT_BEGIN
+RUBY_EXTERN struct mjit_options mjit_opts;
+RUBY_EXTERN bool mjit_call_p;
+
+extern void rb_mjit_add_iseq_to_process(const rb_iseq_t *iseq);
+extern struct rb_mjit_compile_info* rb_mjit_iseq_compile_info(const struct rb_iseq_constant_body *body);
+extern void rb_mjit_recompile_send(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_ivar(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_exivar(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_inlining(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_const(const rb_iseq_t *iseq);
+RUBY_SYMBOL_EXPORT_END
+
+extern void mjit_cancel_all(const char *reason);
+extern bool mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id);
+extern void mjit_init(const struct mjit_options *opts);
+extern void mjit_free_iseq(const rb_iseq_t *iseq);
+extern void mjit_update_references(const rb_iseq_t *iseq);
+extern void mjit_mark(void);
+extern void mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body);
+extern void mjit_notify_waitpid(int exit_code);
+
+extern void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
+extern void rb_mjit_cme_invalidate(rb_callable_method_entry_t *cme);
+extern void rb_mjit_before_ractor_spawn(void);
+extern void rb_mjit_constant_state_changed(ID id);
+extern void rb_mjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx);
+extern void rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events);
+
+void mjit_child_after_fork(void);
+
+# ifdef MJIT_HEADER
+#define mjit_enabled true
+# else // MJIT_HEADER
+extern bool mjit_enabled;
+# endif // MJIT_HEADER
+VALUE mjit_pause(bool wait_p);
+VALUE mjit_resume(void);
+void mjit_finish(bool close_handle_p);
+
+# else // USE_MJIT
+
+static inline void mjit_cancel_all(const char *reason){}
+static inline void mjit_free_iseq(const rb_iseq_t *iseq){}
+static inline void mjit_mark(void){}
+static inline VALUE jit_exec(rb_execution_context_t *ec) { return Qundef; /* unreachable */ }
+static inline void mjit_child_after_fork(void){}
+
+static inline void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
+static inline void rb_mjit_cme_invalidate(rb_callable_method_entry_t *cme) {}
+static inline void rb_mjit_before_ractor_spawn(void) {}
+static inline void rb_mjit_constant_state_changed(ID id) {}
+static inline void rb_mjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx) {}
+static inline void rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events) {}
+
+#define mjit_enabled false
+static inline VALUE mjit_pause(bool wait_p){ return Qnil; } // unreachable
+static inline VALUE mjit_resume(void){ return Qnil; } // unreachable
+static inline void mjit_finish(bool close_handle_p){}
+
+# endif // USE_MJIT
+#endif // RUBY_MJIT_H
diff --git a/mjit.rb b/mjit.rb
new file mode 100644
index 0000000000..717ab832a4
--- /dev/null
+++ b/mjit.rb
@@ -0,0 +1,37 @@
+module RubyVM::MJIT
+ # Return true if MJIT is enabled.
+ def self.enabled?
+ Primitive.cexpr! 'RBOOL(mjit_enabled)'
+ end
+
+ # Stop generating JITed code.
+ def self.pause(wait: true)
+ Primitive.cexpr! 'mjit_pause(RTEST(wait))'
+ end
+
+ # Start generating JITed code again after pause.
+ def self.resume
+ Primitive.cexpr! 'mjit_resume()'
+ end
+end
+
+if RubyVM::MJIT.enabled?
+ begin
+ require 'fiddle'
+ require 'fiddle/import'
+ rescue LoadError
+ return # miniruby doesn't support MJIT
+ end
+
+ # forward declaration for ruby_vm/mjit/compiler
+ RubyVM::MJIT::C = Object.new # :nodoc:
+
+ require 'ruby_vm/mjit/c_type'
+ require 'ruby_vm/mjit/instruction'
+ require 'ruby_vm/mjit/compiler'
+ require 'ruby_vm/mjit/hooks'
+
+ module RubyVM::MJIT
+ private_constant(*constants)
+ end
+end
diff --git a/mjit_c.c b/mjit_c.c
new file mode 100644
index 0000000000..9ba023e84b
--- /dev/null
+++ b/mjit_c.c
@@ -0,0 +1,43 @@
+/**********************************************************************
+
+ mjit_c.c - C helpers for MJIT
+
+ Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
+
+**********************************************************************/
+
+#include "ruby/internal/config.h" // defines USE_MJIT
+
+#if USE_MJIT
+
+#include "mjit.h"
+#include "mjit_c.h"
+#include "internal.h"
+#include "internal/compile.h"
+#include "internal/hash.h"
+#include "yjit.h"
+#include "vm_insnhelper.h"
+
+#include "insns.inc"
+#include "insns_info.inc"
+
+#include "mjit_sp_inc.inc"
+
+#if SIZEOF_LONG == SIZEOF_VOIDP
+#define NUM2PTR(x) NUM2ULONG(x)
+#define PTR2NUM(x) ULONG2NUM(x)
+#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
+#define NUM2PTR(x) NUM2ULL(x)
+#define PTR2NUM(x) ULL2NUM(x)
+#endif
+
+// An offsetof implementation that works for unnamed struct and union.
+// Multiplying 8 for compatibility with libclang's offsetof.
+#define OFFSETOF(ptr, member) RB_SIZE2NUM(((char *)&ptr.member - (char*)&ptr) * 8)
+
+#define SIZEOF(type) RB_SIZE2NUM(sizeof(type))
+#define SIGNED_TYPE_P(type) RBOOL((type)(-1) < (type)(1))
+
+#include "mjit_c.rbinc"
+
+#endif // USE_MJIT
diff --git a/mjit_c.h b/mjit_c.h
new file mode 100644
index 0000000000..cc4040c9df
--- /dev/null
+++ b/mjit_c.h
@@ -0,0 +1,97 @@
+// This file is parsed by tool/mjit/generate.rb to generate mjit_c.rb
+#ifndef MJIT_C_H
+#define MJIT_C_H
+
+#include "ruby/internal/config.h"
+#include "vm_core.h"
+#include "vm_callinfo.h"
+#include "builtin.h"
+#include "ccan/list/list.h"
+#include "mjit.h"
+#include "shape.h"
+
+// Macros to check if a position is already compiled using compile_status.stack_size_for_pos
+#define NOT_COMPILED_STACK_SIZE -1
+#define ALREADY_COMPILED_P(status, pos) (status->stack_size_for_pos[pos] != NOT_COMPILED_STACK_SIZE)
+
+// Linked list of struct rb_mjit_unit.
+struct rb_mjit_unit_list {
+ struct ccan_list_head head;
+ int length; // the list length
+};
+
+enum rb_mjit_unit_type {
+ // Single-ISEQ unit for unit_queue
+ MJIT_UNIT_ISEQ = 0,
+ // Multi-ISEQ unit for mjit_batch
+ MJIT_UNIT_BATCH = 1,
+ // All-ISEQ unit for mjit_compact
+ MJIT_UNIT_COMPACT = 2,
+};
+
+// The unit structure that holds metadata of ISeq for MJIT.
+// TODO: Use different structs for ISEQ and BATCH/COMPACT
+struct rb_mjit_unit {
+ struct ccan_list_node unode;
+ // Unique order number of unit.
+ int id;
+ // Type of this unit
+ enum rb_mjit_unit_type type;
+
+ /* MJIT_UNIT_ISEQ */
+ // ISEQ for a non-batch unit
+ rb_iseq_t *iseq;
+ // Only used by unload_units. Flag to check this unit is currently on stack or not.
+ bool used_code_p;
+ // mjit_compile's optimization switches
+ struct rb_mjit_compile_info compile_info;
+ // captured CC values, they should be marked with iseq.
+ const struct rb_callcache **cc_entries;
+ // ISEQ_BODY(iseq)->ci_size + ones of inlined iseqs
+ unsigned int cc_entries_size;
+
+ /* MJIT_UNIT_BATCH, MJIT_UNIT_COMPACT */
+ // Dlopen handle of the loaded object file.
+ void *handle;
+ // Units compacted by this batch
+ struct rb_mjit_unit_list units; // MJIT_UNIT_BATCH only
+};
+
+// Storage to keep data which is consistent in each conditional branch.
+// This is created and used for one `compile_insns` call and its values
+// should be copied for extra `compile_insns` call.
+struct compile_branch {
+ unsigned int stack_size; // this simulates sp (stack pointer) of YARV
+ bool finish_p; // if true, compilation in this branch should stop and let another branch to be compiled
+};
+
+// For propagating information needed for lazily pushing a frame.
+struct inlined_call_context {
+ int orig_argc; // ci->orig_argc
+ VALUE me; // vm_cc_cme(cc)
+ int param_size; // def_iseq_ptr(vm_cc_cme(cc)->def)->body->param.size
+ int local_size; // def_iseq_ptr(vm_cc_cme(cc)->def)->body->local_table_size
+};
+
+// Storage to keep compiler's status. This should have information
+// which is global during one `mjit_compile` call. Ones conditional
+// in each branch should be stored in `compile_branch`.
+struct compile_status {
+ bool success; // has true if compilation has had no issue
+ int *stack_size_for_pos; // stack_size_for_pos[pos] has stack size for the position (otherwise -1)
+ // If true, JIT-ed code will use local variables to store pushed values instead of
+ // using VM's stack and moving stack pointer.
+ bool local_stack_p;
+ // Index of call cache entries captured to compiled_iseq to be marked on GC
+ int cc_entries_index;
+ // A pointer to root (i.e. not inlined) iseq being compiled.
+ const struct rb_iseq_constant_body *compiled_iseq;
+ int compiled_id; // Just a copy of compiled_iseq->jit_unit->id
+ // Mutated optimization levels
+ struct rb_mjit_compile_info *compile_info;
+ // If `inlined_iseqs[pos]` is not NULL, `mjit_compile_body` tries to inline ISeq there.
+ const struct rb_iseq_constant_body **inlined_iseqs;
+ struct inlined_call_context inline_context;
+};
+
+#endif /* MJIT_C_H */
diff --git a/mjit_c.rb b/mjit_c.rb
new file mode 100644
index 0000000000..966289c5ab
--- /dev/null
+++ b/mjit_c.rb
@@ -0,0 +1,807 @@
+# frozen_string_literal: true
+# Part of this file is generated by tool/mjit/bindgen.rb.
+# Run `make mjit-bindgen` to update code between "MJIT bindgen begin" and "MJIT bindgen end".
+module RubyVM::MJIT # :nodoc: all
+ # This `class << C` section is for calling C functions. For importing variables
+ # or macros as is, please consider using tool/mjit/bindgen.rb instead.
+ class << C
+ def rb_hash_values(cdhash_addr)
+ Primitive.cexpr! 'rb_hash_values((VALUE)NUM2PTR(cdhash_addr))'
+ end
+
+ def builtin_compiler(buf, bf_ptr, index, stack_size, builtin_inline_p)
+ _bf_addr = bf_ptr.to_i
+ # Call "mjit_compile_invokebuiltin_for_#{func}" in mk_builtin_loader.rb
+ Primitive.cstmt! %{
+ RB_BUILTIN bf = (RB_BUILTIN)NUM2PTR(_bf_addr);
+ bf->compiler(buf, NIL_P(index) ? -1 : NUM2LONG(index), NUM2UINT(stack_size), RTEST(builtin_inline_p));
+ return Qnil;
+ }
+ end
+
+ def has_cache_for_send(cc_ptr, insn)
+ _cc_addr = cc_ptr.to_i
+ Primitive.cstmt! %{
+ extern bool rb_vm_opt_cfunc_p(CALL_CACHE cc, int insn);
+ CALL_CACHE cc = (CALL_CACHE)NUM2PTR(_cc_addr);
+ bool has_cache = vm_cc_cme(cc) != NULL &&
+ !(vm_cc_cme(cc)->def->type == VM_METHOD_TYPE_CFUNC && rb_vm_opt_cfunc_p(cc, NUM2INT(insn)));
+ return RBOOL(has_cache);
+ }
+ end
+
+ def rb_shape_get_shape_by_id(shape_id)
+ _shape_id = shape_id.to_i
+ shape_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_shape_get_shape_by_id((shape_id_t)NUM2UINT(_shape_id)))'
+ rb_shape_t.new(shape_addr)
+ end
+
+ def rb_iseq_check(iseq)
+ _iseq_addr = iseq.to_i
+ iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseq_check((rb_iseq_t *)NUM2PTR(_iseq_addr)))'
+ rb_iseq_t.new(iseq_addr)
+ end
+
+ def rb_iseq_path(iseq)
+ _iseq_addr = iseq.to_i
+ Primitive.cexpr! 'rb_iseq_path((rb_iseq_t *)NUM2PTR(_iseq_addr))'
+ end
+
+ def rb_iseq_first_lineno(iseq)
+ _iseq_addr = iseq.to_i
+ Primitive.cexpr! 'rb_iseq_first_lineno((rb_iseq_t *)NUM2PTR(_iseq_addr))'
+ end
+
+ def vm_ci_argc(ci)
+ _ci_addr = ci.to_i
+ Primitive.cexpr! 'UINT2NUM(vm_ci_argc((CALL_INFO)NUM2PTR(_ci_addr)))'
+ end
+
+ def vm_ci_flag(ci)
+ _ci_addr = ci.to_i
+ Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2PTR(_ci_addr)))'
+ end
+
+ def rb_splat_or_kwargs_p(ci)
+ _ci_addr = ci.to_i
+ Primitive.cstmt! %{
+ extern bool rb_splat_or_kwargs_p(const struct rb_callinfo *restrict ci);
+ return RBOOL(rb_splat_or_kwargs_p((CALL_INFO)NUM2PTR(_ci_addr)));
+ }
+ end
+
+ # Returns true if iseq can use fastpath for setup, otherwise NULL. This becomes true in the same condition
+ # as CC_SET_FASTPATH (in vm_callee_setup_arg) is called from vm_call_iseq_setup.
+ def fastpath_applied_iseq_p(ci_ptr, cc_ptr, iseq_ptr)
+ _ci_addr = ci_ptr.to_i
+ _cc_addr = cc_ptr.to_i
+ _iseq_addr = iseq_ptr.to_i
+ Primitive.cstmt! %q{
+ extern bool rb_simple_iseq_p(const rb_iseq_t *iseq);
+ CALL_INFO ci = (CALL_INFO)NUM2PTR(_ci_addr);
+ CALL_CACHE cc = (CALL_CACHE)NUM2PTR(_cc_addr);
+ const rb_iseq_t *iseq = (rb_iseq_t *)NUM2PTR(_iseq_addr);
+
+ bool result = iseq != NULL
+ && !(vm_ci_flag(ci) & VM_CALL_KW_SPLAT) && rb_simple_iseq_p(iseq) // Top of vm_callee_setup_arg. In this case, opt_pc is 0.
+ && vm_ci_argc(ci) == (unsigned int)ISEQ_BODY(iseq)->param.lead_num // exclude argument_arity_error (assumption: `calling->argc == ci->orig_argc` in send insns)
+ && vm_call_iseq_optimizable_p(ci, cc); // CC_SET_FASTPATH condition
+ return RBOOL(result);
+ }
+ end
+
+ def mjit_opts
+ addr = Primitive.cexpr! 'PTR2NUM((VALUE)&mjit_opts)'
+ mjit_options.new(addr)
+ end
+
+ def mjit_call_attribute_sp_inc(insn, operands)
+ _operands_addr = operands.to_i
+ Primitive.cexpr! 'LONG2NUM(mjit_call_attribute_sp_inc(NUM2INT(insn), (VALUE *)NUM2PTR(_operands_addr)))'
+ end
+
+ def mjit_capture_cc_entries(compiled_body, captured_body)
+ _compiled_body_addr = compiled_body.to_i
+ _captured_body_addr = captured_body.to_i
+ Primitive.cstmt! %{
+ extern int mjit_capture_cc_entries(const struct rb_iseq_constant_body *compiled_iseq, const struct rb_iseq_constant_body *captured_iseq);
+ return INT2NUM(mjit_capture_cc_entries((struct rb_iseq_constant_body *)NUM2PTR(_compiled_body_addr), (struct rb_iseq_constant_body *)NUM2PTR(_captured_body_addr)));
+ }
+ end
+
+ def mjit_cancel_all(reason)
+ Primitive.cstmt! %{
+ mjit_cancel_all(RSTRING_PTR(reason));
+ return Qnil;
+ }
+ end
+
+ # Convert encoded VM pointers to insn BINs.
+ def rb_vm_insn_decode(encoded)
+ Primitive.cexpr! 'INT2NUM(rb_vm_insn_decode(NUM2PTR(encoded)))'
+ end
+
+ # Convert insn BINs to encoded VM pointers. This one is not used by the compiler, but useful for debugging.
+ def rb_vm_insn_encode(bin)
+ Primitive.cexpr! 'PTR2NUM((VALUE)rb_vm_get_insns_address_table()[NUM2INT(bin)])'
+ end
+
+ def insn_may_depend_on_sp_or_pc(insn, opes)
+ _opes_addr = opes.to_i
+ Primitive.cexpr! 'RBOOL(insn_may_depend_on_sp_or_pc(NUM2INT(insn), (VALUE *)NUM2PTR(_opes_addr)))'
+ end
+
+ # Convert Integer VALUE to an actual Ruby object
+ def to_ruby(value)
+ Primitive.cexpr! '(VALUE)NUM2PTR(value)'
+ end
+
+ # Convert RubyVM::InstructionSequence to C.rb_iseq_t. Not used by the compiler, but useful for debugging.
+ def rb_iseqw_to_iseq(iseqw)
+ iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseqw_to_iseq(iseqw))'
+ rb_iseq_t.new(iseq_addr)
+ end
+ end
+
+ ### MJIT bindgen begin ###
+
+ def C.USE_LAZY_LOAD
+ Primitive.cexpr! %q{ RBOOL(USE_LAZY_LOAD != 0) }
+ end
+
+ def C.NOT_COMPILED_STACK_SIZE
+ Primitive.cexpr! %q{ INT2NUM(NOT_COMPILED_STACK_SIZE) }
+ end
+
+ def C.VM_CALL_KW_SPLAT
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT) }
+ end
+
+ def C.VM_CALL_KW_SPLAT_bit
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT_bit) }
+ end
+
+ def C.VM_CALL_TAILCALL
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL) }
+ end
+
+ def C.VM_CALL_TAILCALL_bit
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL_bit) }
+ end
+
+ def C.VM_METHOD_TYPE_CFUNC
+ Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_CFUNC) }
+ end
+
+ def C.VM_METHOD_TYPE_ISEQ
+ Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_ISEQ) }
+ end
+
+ def C.RUBY_EVENT_CLASS
+ Primitive.cexpr! %q{ UINT2NUM(RUBY_EVENT_CLASS) }
+ end
+
+ def C.SHAPE_CAPACITY_CHANGE
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_CAPACITY_CHANGE) }
+ end
+
+ def C.SHAPE_FLAG_SHIFT
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_FLAG_SHIFT) }
+ end
+
+ def C.SHAPE_FROZEN
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_FROZEN) }
+ end
+
+ def C.SHAPE_ID_NUM_BITS
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_ID_NUM_BITS) }
+ end
+
+ def C.SHAPE_INITIAL_CAPACITY
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_INITIAL_CAPACITY) }
+ end
+
+ def C.SHAPE_IVAR
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_IVAR) }
+ end
+
+ def C.SHAPE_ROOT
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_ROOT) }
+ end
+
+ def C.INVALID_SHAPE_ID
+ Primitive.cexpr! %q{ ULONG2NUM(INVALID_SHAPE_ID) }
+ end
+
+ def C.SHAPE_MASK
+ Primitive.cexpr! %q{ ULONG2NUM(SHAPE_MASK) }
+ end
+
+ def C.rb_cFalseClass
+ Primitive.cexpr! %q{ PTR2NUM(rb_cFalseClass) }
+ end
+
+ def C.rb_cFloat
+ Primitive.cexpr! %q{ PTR2NUM(rb_cFloat) }
+ end
+
+ def C.rb_cInteger
+ Primitive.cexpr! %q{ PTR2NUM(rb_cInteger) }
+ end
+
+ def C.rb_cNilClass
+ Primitive.cexpr! %q{ PTR2NUM(rb_cNilClass) }
+ end
+
+ def C.rb_cSymbol
+ Primitive.cexpr! %q{ PTR2NUM(rb_cSymbol) }
+ end
+
+ def C.rb_cTrueClass
+ Primitive.cexpr! %q{ PTR2NUM(rb_cTrueClass) }
+ end
+
+ def C.CALL_DATA
+ @CALL_DATA ||= self.rb_call_data
+ end
+
+ def C.IC
+ @IC ||= self.iseq_inline_constant_cache
+ end
+
+ def C.IVC
+ @IVC ||= self.iseq_inline_iv_cache_entry
+ end
+
+ def C.RB_BUILTIN
+ @RB_BUILTIN ||= self.rb_builtin_function
+ end
+
+ def C.attr_index_t
+ @attr_index_t ||= CType::Immediate.parse("uint32_t")
+ end
+
+ def C.compile_branch
+ @compile_branch ||= CType::Struct.new(
+ "compile_branch", Primitive.cexpr!("SIZEOF(struct compile_branch)"),
+ stack_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct compile_branch *)NULL)), stack_size)")],
+ finish_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_branch *)NULL)), finish_p)")],
+ )
+ end
+
+ def C.compile_status
+ @compile_status ||= CType::Struct.new(
+ "compile_status", Primitive.cexpr!("SIZEOF(struct compile_status)"),
+ success: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), success)")],
+ stack_size_for_pos: [CType::Pointer.new { CType::Immediate.parse("int") }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), stack_size_for_pos)")],
+ local_stack_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), local_stack_p)")],
+ cc_entries_index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), cc_entries_index)")],
+ compiled_iseq: [CType::Pointer.new { self.rb_iseq_constant_body }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compiled_iseq)")],
+ compiled_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compiled_id)")],
+ compile_info: [CType::Pointer.new { self.rb_mjit_compile_info }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compile_info)")],
+ inlined_iseqs: [CType::Pointer.new { CType::Pointer.new { self.rb_iseq_constant_body } }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inlined_iseqs)")],
+ inline_context: [self.inlined_call_context, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inline_context)")],
+ )
+ end
+
+ def C.inlined_call_context
+ @inlined_call_context ||= CType::Struct.new(
+ "inlined_call_context", Primitive.cexpr!("SIZEOF(struct inlined_call_context)"),
+ orig_argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), orig_argc)")],
+ me: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), me)")],
+ param_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), param_size)")],
+ local_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), local_size)")],
+ )
+ end
+
+ def C.iseq_inline_constant_cache
+ @iseq_inline_constant_cache ||= CType::Struct.new(
+ "iseq_inline_constant_cache", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache)"),
+ entry: [CType::Pointer.new { self.iseq_inline_constant_cache_entry }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), entry)")],
+ segments: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), segments)")],
+ )
+ end
+
+ def C.iseq_inline_constant_cache_entry
+ @iseq_inline_constant_cache_entry ||= CType::Struct.new(
+ "iseq_inline_constant_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache_entry)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), flags)")],
+ value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), value)")],
+ _unused1: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused1)")],
+ _unused2: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused2)")],
+ ic_cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), ic_cref)")],
+ )
+ end
+
+ def C.iseq_inline_iv_cache_entry
+ @iseq_inline_iv_cache_entry ||= CType::Struct.new(
+ "iseq_inline_iv_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_iv_cache_entry)"),
+ value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), value)")],
+ iv_set_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), iv_set_name)")],
+ )
+ end
+
+ def C.iseq_inline_storage_entry
+ @iseq_inline_storage_entry ||= CType::Union.new(
+ "iseq_inline_storage_entry", Primitive.cexpr!("SIZEOF(union iseq_inline_storage_entry)"),
+ once: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((union iseq_inline_storage_entry *)NULL)->once)"),
+ running_thread: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, running_thread)")],
+ value: [self.VALUE, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, value)")],
+ ),
+ ic_cache: self.iseq_inline_constant_cache,
+ iv_cache: self.iseq_inline_iv_cache_entry,
+ )
+ end
+
+ def C.mjit_options
+ @mjit_options ||= CType::Struct.new(
+ "mjit_options", Primitive.cexpr!("SIZEOF(struct mjit_options)"),
+ on: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), on)")],
+ save_temps: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), save_temps)")],
+ warnings: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), warnings)")],
+ debug: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), debug)")],
+ debug_flags: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), debug_flags)")],
+ wait: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), wait)")],
+ call_threshold: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), call_threshold)")],
+ verbose: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), verbose)")],
+ max_cache_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), max_cache_size)")],
+ pause: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), pause)")],
+ custom: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), custom)")],
+ )
+ end
+
+ def C.rb_builtin_function
+ @rb_builtin_function ||= CType::Struct.new(
+ "rb_builtin_function", Primitive.cexpr!("SIZEOF(struct rb_builtin_function)"),
+ func_ptr: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), func_ptr)")],
+ argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), argc)")],
+ index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), index)")],
+ name: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), name)")],
+ compiler: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), compiler)")],
+ )
+ end
+
+ def C.rb_call_data
+ @rb_call_data ||= CType::Struct.new(
+ "rb_call_data", Primitive.cexpr!("SIZEOF(struct rb_call_data)"),
+ ci: [CType::Pointer.new { self.rb_callinfo }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), ci)")],
+ cc: [CType::Pointer.new { self.rb_callcache }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), cc)")],
+ )
+ end
+
+ def C.rb_callable_method_entry_struct
+ @rb_callable_method_entry_struct ||= CType::Struct.new(
+ "rb_callable_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_callable_method_entry_struct)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), flags)")],
+ defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), defined_class)")],
+ def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), def)")],
+ called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), called_id)")],
+ owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), owner)")],
+ )
+ end
+
+ def C.rb_callcache
+ @rb_callcache ||= CType::Struct.new(
+ "rb_callcache", Primitive.cexpr!("SIZEOF(struct rb_callcache)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), flags)")],
+ klass: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), klass)")],
+ cme_: [CType::Pointer.new { self.rb_callable_method_entry_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), cme_)")],
+ call_: [self.vm_call_handler, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), call_)")],
+ aux_: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_)"),
+ attr: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_.attr)"),
+ value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF(((struct rb_callcache *)NULL)->aux_.attr, value)")],
+ ),
+ method_missing_reason: self.method_missing_reason,
+ v: self.VALUE,
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), aux_)")],
+ )
+ end
+
+ def C.rb_callinfo
+ @rb_callinfo ||= CType::Struct.new(
+ "rb_callinfo", Primitive.cexpr!("SIZEOF(struct rb_callinfo)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flags)")],
+ kwarg: [CType::Pointer.new { self.rb_callinfo_kwarg }, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), kwarg)")],
+ mid: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), mid)")],
+ flag: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flag)")],
+ argc: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), argc)")],
+ )
+ end
+
+ def C.rb_control_frame_t
+ @rb_control_frame_t ||= CType::Struct.new(
+ "rb_control_frame_struct", Primitive.cexpr!("SIZEOF(struct rb_control_frame_struct)"),
+ pc: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), pc)")],
+ sp: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), sp)")],
+ iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), iseq)")],
+ self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), self)")],
+ ep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), ep)")],
+ block_code: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), block_code)")],
+ __bp__: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), __bp__)")],
+ jit_return: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), jit_return)")],
+ )
+ end
+
+ def C.rb_cref_t
+ @rb_cref_t ||= CType::Struct.new(
+ "rb_cref_struct", Primitive.cexpr!("SIZEOF(struct rb_cref_struct)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), flags)")],
+ refinements: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), refinements)")],
+ klass_or_self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), klass_or_self)")],
+ next: [CType::Pointer.new { self.rb_cref_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), next)")],
+ scope_visi: [self.rb_scope_visibility_t, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), scope_visi)")],
+ )
+ end
+
+ def C.rb_execution_context_struct
+ @rb_execution_context_struct ||= CType::Struct.new(
+ "rb_execution_context_struct", Primitive.cexpr!("SIZEOF(struct rb_execution_context_struct)"),
+ vm_stack: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack)")],
+ vm_stack_size: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack_size)")],
+ cfp: [CType::Pointer.new { self.rb_control_frame_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), cfp)")],
+ tag: [CType::Pointer.new { self.rb_vm_tag }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), tag)")],
+ interrupt_flag: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_flag)")],
+ interrupt_mask: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_mask)")],
+ fiber_ptr: [CType::Pointer.new { self.rb_fiber_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), fiber_ptr)")],
+ thread_ptr: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), thread_ptr)")],
+ local_storage: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage)")],
+ local_storage_recursive_hash: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash)")],
+ local_storage_recursive_hash_for_trace: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash_for_trace)")],
+ storage: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), storage)")],
+ root_lep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_lep)")],
+ root_svar: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_svar)")],
+ ensure_list: [CType::Pointer.new { self.rb_ensure_list_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), ensure_list)")],
+ trace_arg: [CType::Pointer.new { self.rb_trace_arg_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), trace_arg)")],
+ errinfo: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), errinfo)")],
+ passed_block_handler: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), passed_block_handler)")],
+ raised_flag: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), raised_flag)")],
+ private_const_reference: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), private_const_reference)")],
+ machine: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_execution_context_struct *)NULL)->machine)"),
+ stack_start: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_start)")],
+ stack_end: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_end)")],
+ stack_maxsize: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_maxsize)")],
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), machine)")],
+ )
+ end
+
+ def C.rb_execution_context_t
+ @rb_execution_context_t ||= self.rb_execution_context_struct
+ end
+
+ def C.rb_iseq_constant_body
+ @rb_iseq_constant_body ||= CType::Struct.new(
+ "rb_iseq_constant_body", Primitive.cexpr!("SIZEOF(struct rb_iseq_constant_body)"),
+ type: [self.rb_iseq_type, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), type)")],
+ iseq_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_size)")],
+ iseq_encoded: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_encoded)")],
+ param: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param)"),
+ flags: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param.flags)"),
+ has_lead: [CType::BitField.new(1, 0), 0],
+ has_opt: [CType::BitField.new(1, 1), 1],
+ has_rest: [CType::BitField.new(1, 2), 2],
+ has_post: [CType::BitField.new(1, 3), 3],
+ has_kw: [CType::BitField.new(1, 4), 4],
+ has_kwrest: [CType::BitField.new(1, 5), 5],
+ has_block: [CType::BitField.new(1, 6), 6],
+ ambiguous_param0: [CType::BitField.new(1, 7), 7],
+ accepts_no_kwarg: [CType::BitField.new(1, 0), 8],
+ ruby2_keywords: [CType::BitField.new(1, 1), 9],
+ ), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, flags)")],
+ size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, size)")],
+ lead_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, lead_num)")],
+ opt_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_num)")],
+ rest_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, rest_start)")],
+ post_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_start)")],
+ post_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_num)")],
+ block_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, block_start)")],
+ opt_table: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_table)")],
+ keyword: [CType::Pointer.new { self.rb_iseq_param_keyword }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, keyword)")],
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), param)")],
+ location: [self.rb_iseq_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), location)")],
+ insns_info: [self.iseq_insn_info, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), insns_info)")],
+ local_table: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table)")],
+ catch_table: [CType::Pointer.new { self.iseq_catch_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), catch_table)")],
+ parent_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), parent_iseq)")],
+ local_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_iseq)")],
+ is_entries: [CType::Pointer.new { self.iseq_inline_storage_entry }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), is_entries)")],
+ call_data: [CType::Pointer.new { self.rb_call_data }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), call_data)")],
+ variable: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->variable)"),
+ flip_count: [self.rb_snum_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, flip_count)")],
+ script_lines: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, script_lines)")],
+ coverage: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, coverage)")],
+ pc2branchindex: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, pc2branchindex)")],
+ original_iseq: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, original_iseq)")],
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), variable)")],
+ local_table_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table_size)")],
+ ic_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ic_size)")],
+ ise_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ise_size)")],
+ ivc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ivc_size)")],
+ icvarc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), icvarc_size)")],
+ ci_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ci_size)")],
+ stack_max: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), stack_max)")],
+ catch_except_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), catch_except_p)")],
+ builtin_inline_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), builtin_inline_p)")],
+ mark_bits: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->mark_bits)"),
+ list: CType::Pointer.new { self.iseq_bits_t },
+ single: self.iseq_bits_t,
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mark_bits)")],
+ outer_variables: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), outer_variables)")],
+ mandatory_only_iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mandatory_only_iseq)")],
+ jit_func: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_func)")],
+ total_calls: [CType::Immediate.parse("unsigned long"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), total_calls)")],
+ mjit_unit: [CType::Pointer.new { self.rb_mjit_unit }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mjit_unit)")],
+ )
+ end
+
+ def C.rb_iseq_location_t
+ @rb_iseq_location_t ||= CType::Struct.new(
+ "rb_iseq_location_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_location_struct)"),
+ pathobj: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), pathobj)"), true],
+ base_label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), base_label)"), true],
+ label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), label)"), true],
+ first_lineno: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), first_lineno)"), true],
+ node_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), node_id)")],
+ code_location: [self.rb_code_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), code_location)")],
+ )
+ end
+
+ def C.rb_iseq_struct
+ @rb_iseq_struct ||= CType::Struct.new(
+ "rb_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_struct)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), flags)")],
+ wrapper: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), wrapper)")],
+ body: [CType::Pointer.new { self.rb_iseq_constant_body }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), body)")],
+ aux: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux)"),
+ compile_data: CType::Pointer.new { self.iseq_compile_data },
+ loader: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.loader)"),
+ obj: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, obj)")],
+ index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, index)")],
+ ),
+ exec: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.exec)"),
+ local_hooks: [CType::Pointer.new { self.rb_hook_list_struct }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, local_hooks)")],
+ global_trace_events: [self.rb_event_flag_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, global_trace_events)")],
+ ),
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), aux)")],
+ )
+ end
+
+ def C.rb_iseq_t
+ @rb_iseq_t ||= self.rb_iseq_struct
+ end
+
+ def C.rb_method_definition_struct
+ @rb_method_definition_struct ||= CType::Struct.new(
+ "rb_method_definition_struct", Primitive.cexpr!("SIZEOF(struct rb_method_definition_struct)"),
+ type: [CType::BitField.new(4, 0), 0],
+ iseq_overload: [CType::BitField.new(1, 4), 4],
+ no_redef_warning: [CType::BitField.new(1, 5), 5],
+ aliased: [CType::BitField.new(1, 6), 6],
+ reference_count: [CType::BitField.new(28, 0), 32],
+ body: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_method_definition_struct *)NULL)->body)"),
+ iseq: self.rb_method_iseq_t,
+ cfunc: self.rb_method_cfunc_t,
+ attr: self.rb_method_attr_t,
+ alias: self.rb_method_alias_t,
+ refined: self.rb_method_refined_t,
+ bmethod: self.rb_method_bmethod_t,
+ optimized: self.rb_method_optimized_t,
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), body)")],
+ original_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), original_id)")],
+ method_serial: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), method_serial)")],
+ )
+ end
+
+ def C.rb_method_iseq_t
+ @rb_method_iseq_t ||= CType::Struct.new(
+ "rb_method_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_method_iseq_struct)"),
+ iseqptr: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), iseqptr)")],
+ cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), cref)")],
+ )
+ end
+
+ def C.rb_method_type_t
+ @rb_method_type_t ||= CType::Immediate.parse("int")
+ end
+
+ def C.rb_mjit_compile_info
+ @rb_mjit_compile_info ||= CType::Struct.new(
+ "rb_mjit_compile_info", Primitive.cexpr!("SIZEOF(struct rb_mjit_compile_info)"),
+ disable_ivar_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_ivar_cache)")],
+ disable_exivar_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_exivar_cache)")],
+ disable_send_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_send_cache)")],
+ disable_inlining: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_inlining)")],
+ disable_const_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_const_cache)")],
+ )
+ end
+
+ def C.rb_mjit_unit
+ @rb_mjit_unit ||= CType::Struct.new(
+ "rb_mjit_unit", Primitive.cexpr!("SIZEOF(struct rb_mjit_unit)"),
+ unode: [self.ccan_list_node, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), unode)")],
+ id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), id)")],
+ type: [self.rb_mjit_unit_type, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), type)")],
+ iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), iseq)")],
+ used_code_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), used_code_p)")],
+ compile_info: [self.rb_mjit_compile_info, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), compile_info)")],
+ cc_entries: [CType::Pointer.new { CType::Pointer.new { self.rb_callcache } }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries)")],
+ cc_entries_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries_size)")],
+ handle: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), handle)")],
+ units: [self.rb_mjit_unit_list, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), units)")],
+ )
+ end
+
+ def C.rb_serial_t
+ @rb_serial_t ||= CType::Immediate.parse("unsigned long long")
+ end
+
+ def C.rb_shape
+ @rb_shape ||= CType::Struct.new(
+ "rb_shape", Primitive.cexpr!("SIZEOF(struct rb_shape)"),
+ edges: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edges)")],
+ edge_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edge_name)")],
+ next_iv_index: [self.attr_index_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), next_iv_index)")],
+ capacity: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), capacity)")],
+ type: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), type)")],
+ size_pool_index: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), size_pool_index)")],
+ parent_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), parent_id)")],
+ )
+ end
+
+ def C.rb_shape_t
+ @rb_shape_t ||= self.rb_shape
+ end
+
+ def C.VALUE
+ @VALUE ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(VALUE)"), Primitive.cexpr!("SIGNED_TYPE_P(VALUE)"))
+ end
+
+ def C.shape_id_t
+ @shape_id_t ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(shape_id_t)"), Primitive.cexpr!("SIGNED_TYPE_P(shape_id_t)"))
+ end
+
+ def C._Bool
+ CType::Bool.new
+ end
+
+ def C.ID
+ CType::Stub.new(:ID)
+ end
+
+ def C.rb_thread_struct
+ CType::Stub.new(:rb_thread_struct)
+ end
+
+ def C.vm_call_handler
+ CType::Stub.new(:vm_call_handler)
+ end
+
+ def C.method_missing_reason
+ CType::Stub.new(:method_missing_reason)
+ end
+
+ def C.rb_callinfo_kwarg
+ CType::Stub.new(:rb_callinfo_kwarg)
+ end
+
+ def C.rb_cref_struct
+ CType::Stub.new(:rb_cref_struct)
+ end
+
+ def C.rb_scope_visibility_t
+ CType::Stub.new(:rb_scope_visibility_t)
+ end
+
+ def C.rb_vm_tag
+ CType::Stub.new(:rb_vm_tag)
+ end
+
+ def C.rb_atomic_t
+ CType::Stub.new(:rb_atomic_t)
+ end
+
+ def C.rb_fiber_t
+ CType::Stub.new(:rb_fiber_t)
+ end
+
+ def C.rb_id_table
+ CType::Stub.new(:rb_id_table)
+ end
+
+ def C.rb_ensure_list_t
+ CType::Stub.new(:rb_ensure_list_t)
+ end
+
+ def C.rb_trace_arg_struct
+ CType::Stub.new(:rb_trace_arg_struct)
+ end
+
+ def C.rb_iseq_type
+ CType::Stub.new(:rb_iseq_type)
+ end
+
+ def C.rb_iseq_param_keyword
+ CType::Stub.new(:rb_iseq_param_keyword)
+ end
+
+ def C.iseq_insn_info
+ CType::Stub.new(:iseq_insn_info)
+ end
+
+ def C.iseq_catch_table
+ CType::Stub.new(:iseq_catch_table)
+ end
+
+ def C.rb_snum_t
+ CType::Stub.new(:rb_snum_t)
+ end
+
+ def C.iseq_bits_t
+ CType::Stub.new(:iseq_bits_t)
+ end
+
+ def C.rb_code_location_t
+ CType::Stub.new(:rb_code_location_t)
+ end
+
+ def C.iseq_compile_data
+ CType::Stub.new(:iseq_compile_data)
+ end
+
+ def C.rb_hook_list_struct
+ CType::Stub.new(:rb_hook_list_struct)
+ end
+
+ def C.rb_event_flag_t
+ CType::Stub.new(:rb_event_flag_t)
+ end
+
+ def C.rb_method_cfunc_t
+ CType::Stub.new(:rb_method_cfunc_t)
+ end
+
+ def C.rb_method_attr_t
+ CType::Stub.new(:rb_method_attr_t)
+ end
+
+ def C.rb_method_alias_t
+ CType::Stub.new(:rb_method_alias_t)
+ end
+
+ def C.rb_method_refined_t
+ CType::Stub.new(:rb_method_refined_t)
+ end
+
+ def C.rb_method_bmethod_t
+ CType::Stub.new(:rb_method_bmethod_t)
+ end
+
+ def C.rb_method_optimized_t
+ CType::Stub.new(:rb_method_optimized_t)
+ end
+
+ def C.ccan_list_node
+ CType::Stub.new(:ccan_list_node)
+ end
+
+ def C.rb_mjit_unit_type
+ CType::Stub.new(:rb_mjit_unit_type)
+ end
+
+ def C.rb_mjit_unit_list
+ CType::Stub.new(:rb_mjit_unit_list)
+ end
+
+ ### MJIT bindgen end ###
+end if RubyVM::MJIT.enabled? && RubyVM::MJIT.const_defined?(:C) # not defined for miniruby
diff --git a/node.c b/node.c
index 1f10258343..a6cb498778 100644
--- a/node.c
+++ b/node.c
@@ -9,96 +9,1119 @@
**********************************************************************/
-#ifdef UNIVERSAL_PARSER
-
-#include <stddef.h>
-#include "node.h"
-#include "rubyparser.h"
-#include "internal/parse.h"
-#define T_NODE 0x1b
-
-#else
-
#include "internal.h"
#include "internal/hash.h"
#include "internal/variable.h"
#include "ruby/ruby.h"
#include "vm_core.h"
-#endif
+#define NODE_BUF_DEFAULT_LEN 16
+
+#define A(str) rb_str_cat2(buf, (str))
+#define AR(str) rb_str_concat(buf, (str))
+
+#define A_INDENT add_indent(buf, indent)
+#define D_INDENT rb_str_cat2(indent, next_indent)
+#define D_DEDENT rb_str_resize(indent, RSTRING_LEN(indent) - 4)
+#define A_ID(id) add_id(buf, (id))
+#define A_INT(val) rb_str_catf(buf, "%d", (val))
+#define A_LONG(val) rb_str_catf(buf, "%ld", (val))
+#define A_LIT(lit) AR(rb_dump_literal(lit))
+#define A_NODE_HEADER(node, term) \
+ rb_str_catf(buf, "@ %s (id: %d, line: %d, location: (%d,%d)-(%d,%d))%s"term, \
+ ruby_node_name(nd_type(node)), nd_node_id(node), nd_line(node), \
+ nd_first_lineno(node), nd_first_column(node), \
+ nd_last_lineno(node), nd_last_column(node), \
+ (node->flags & NODE_FL_NEWLINE ? "*" : ""))
+#define A_FIELD_HEADER(len, name, term) \
+ rb_str_catf(buf, "+- %.*s:"term, (len), (name))
+#define D_FIELD_HEADER(len, name, term) (A_INDENT, A_FIELD_HEADER(len, name, term))
+
+#define D_NULL_NODE (A_INDENT, A("(null node)\n"))
+#define D_NODE_HEADER(node) (A_INDENT, A_NODE_HEADER(node, "\n"))
+
+#define COMPOUND_FIELD(len, name) \
+ FIELD_BLOCK((D_FIELD_HEADER((len), (name), "\n"), D_INDENT), D_DEDENT)
+
+#define COMPOUND_FIELD1(name, ann) \
+ COMPOUND_FIELD(FIELD_NAME_LEN(name, ann), \
+ FIELD_NAME_DESC(name, ann))
+
+#define FIELD_NAME_DESC(name, ann) name " (" ann ")"
+#define FIELD_NAME_LEN(name, ann) (int)( \
+ comment ? \
+ rb_strlen_lit(FIELD_NAME_DESC(name, ann)) : \
+ rb_strlen_lit(name))
+#define SIMPLE_FIELD(len, name) \
+ FIELD_BLOCK(D_FIELD_HEADER((len), (name), " "), A("\n"))
+
+#define FIELD_BLOCK(init, reset) \
+ for (init, field_flag = 1; \
+ field_flag; /* should be optimized away */ \
+ reset, field_flag = 0)
+
+#define SIMPLE_FIELD1(name, ann) SIMPLE_FIELD(FIELD_NAME_LEN(name, ann), FIELD_NAME_DESC(name, ann))
+#define F_CUSTOM1(name, ann) SIMPLE_FIELD1(#name, ann)
+#define F_ID(name, ann) SIMPLE_FIELD1(#name, ann) A_ID(node->name)
+#define F_GENTRY(name, ann) SIMPLE_FIELD1(#name, ann) A_ID(node->name)
+#define F_INT(name, ann) SIMPLE_FIELD1(#name, ann) A_INT(node->name)
+#define F_LONG(name, ann) SIMPLE_FIELD1(#name, ann) A_LONG(node->name)
+#define F_LIT(name, ann) SIMPLE_FIELD1(#name, ann) A_LIT(node->name)
+#define F_MSG(name, ann, desc) SIMPLE_FIELD1(#name, ann) A(desc)
+
+#define F_NODE(name, ann) \
+ COMPOUND_FIELD1(#name, ann) {dump_node(buf, indent, comment, node->name);}
+
+#define ANN(ann) \
+ if (comment) { \
+ A_INDENT; A("| # " ann "\n"); \
+ }
+
+#define LAST_NODE (next_indent = " ")
-#define NODE_BUF_DEFAULT_SIZE (sizeof(struct RNode) * 16)
+VALUE
+rb_dump_literal(VALUE lit)
+{
+ if (!RB_SPECIAL_CONST_P(lit)) {
+ VALUE str;
+ switch (RB_BUILTIN_TYPE(lit)) {
+ case T_CLASS: case T_MODULE: case T_ICLASS:
+ str = rb_class_path(lit);
+ if (FL_TEST(lit, FL_SINGLETON)) {
+ str = rb_sprintf("<%"PRIsVALUE">", str);
+ }
+ return str;
+ default:
+ break;
+ }
+ }
+ return rb_inspect(lit);
+}
static void
-init_node_buffer_elem(node_buffer_elem_t *nbe, size_t allocated, void *xmalloc(size_t))
+add_indent(VALUE buf, VALUE indent)
{
- nbe->allocated = allocated;
- nbe->used = 0;
- nbe->len = 0;
- nbe->nodes = xmalloc(allocated / sizeof(struct RNode) * sizeof(struct RNode *)); /* All node requires at least RNode */
+ AR(indent);
}
static void
-init_node_buffer_list(node_buffer_list_t * nb, node_buffer_elem_t *head, void *xmalloc(size_t))
+add_id(VALUE buf, ID id)
{
- init_node_buffer_elem(head, NODE_BUF_DEFAULT_SIZE, xmalloc);
- nb->head = nb->last = head;
- nb->head->next = NULL;
+ if (id == 0) {
+ A("(null)");
+ }
+ else {
+ VALUE str = rb_id2str(id);
+ if (str) {
+ A(":"); AR(str);
+ }
+ else {
+ rb_str_catf(buf, "(internal variable: 0x%"PRIsVALUE")", id);
+ }
+ }
}
-#ifdef UNIVERSAL_PARSER
-#define ruby_xmalloc config->malloc
-#define Qnil config->qnil
-#endif
+struct add_option_arg {
+ VALUE buf, indent;
+ st_index_t count;
+};
-#ifdef UNIVERSAL_PARSER
-static node_buffer_t *
-rb_node_buffer_new(rb_parser_config_t *config)
-#else
-static node_buffer_t *
-rb_node_buffer_new(void)
-#endif
+static void dump_node(VALUE, VALUE, int, const NODE *);
+static const char default_indent[] = "| ";
+
+static void
+dump_array(VALUE buf, VALUE indent, int comment, const NODE *node)
{
- const size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE;
- const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size * 2);
- STATIC_ASSERT(
- integer_overflow,
- offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE
- > sizeof(node_buffer_t) + 2 * sizeof(node_buffer_elem_t));
- node_buffer_t *nb = ruby_xmalloc(alloc_size);
- init_node_buffer_list(&nb->unmarkable, (node_buffer_elem_t*)&nb[1], ruby_xmalloc);
- init_node_buffer_list(&nb->markable, (node_buffer_elem_t*)((size_t)nb->unmarkable.head + bucket_size), ruby_xmalloc);
- nb->local_tables = 0;
- nb->mark_hash = Qnil;
- nb->tokens = Qnil;
-#ifdef UNIVERSAL_PARSER
- nb->config = config;
-#endif
- return nb;
+ int field_flag;
+ const char *next_indent = default_indent;
+ F_LONG(nd_alen, "length");
+ F_NODE(nd_head, "element");
+ while (node->nd_next && nd_type_p(node->nd_next, NODE_LIST)) {
+ node = node->nd_next;
+ F_NODE(nd_head, "element");
+ }
+ LAST_NODE;
+ F_NODE(nd_next, "next element");
}
-#ifdef UNIVERSAL_PARSER
-#undef ruby_xmalloc
-#define ruby_xmalloc ast->node_buffer->config->malloc
-#undef xfree
-#define xfree ast->node_buffer->config->free
-#define rb_ident_hash_new ast->node_buffer->config->ident_hash_new
-#define rb_xmalloc_mul_add ast->node_buffer->config->xmalloc_mul_add
-#define ruby_xrealloc(var,size) (ast->node_buffer->config->realloc_n((void *)var, 1, size))
-#define rb_gc_mark ast->node_buffer->config->gc_mark
-#define rb_gc_location ast->node_buffer->config->gc_location
-#define rb_gc_mark_movable ast->node_buffer->config->gc_mark_movable
-#undef Qnil
-#define Qnil ast->node_buffer->config->qnil
-#define Qtrue ast->node_buffer->config->qtrue
-#define NIL_P ast->node_buffer->config->nil_p
-#define rb_hash_aset ast->node_buffer->config->hash_aset
-#define rb_hash_delete ast->node_buffer->config->hash_delete
-#define RB_OBJ_WRITE(old, slot, young) ast->node_buffer->config->obj_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young))
-#endif
-
-typedef void node_itr_t(rb_ast_t *ast, void *ctx, NODE *node);
-static void iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx);
+static void
+dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
+{
+ int field_flag;
+ int i;
+ const char *next_indent = default_indent;
+ enum node_type type;
+
+ if (!node) {
+ D_NULL_NODE;
+ return;
+ }
+
+ D_NODE_HEADER(node);
+
+ type = nd_type(node);
+ switch (type) {
+ case NODE_BLOCK:
+ ANN("statement sequence");
+ ANN("format: [nd_head]; ...; [nd_next]");
+ ANN("example: foo; bar");
+ i = 0;
+ do {
+ A_INDENT;
+ rb_str_catf(buf, "+- nd_head (%s%d):\n",
+ comment ? "statement #" : "", ++i);
+ if (!node->nd_next) LAST_NODE;
+ D_INDENT;
+ dump_node(buf, indent, comment, node->nd_head);
+ D_DEDENT;
+ } while (node->nd_next &&
+ nd_type_p(node->nd_next, NODE_BLOCK) &&
+ (node = node->nd_next, 1));
+ if (node->nd_next) {
+ LAST_NODE;
+ F_NODE(nd_next, "next block");
+ }
+ return;
+
+ case NODE_IF:
+ ANN("if statement");
+ ANN("format: if [nd_cond] then [nd_body] else [nd_else] end");
+ ANN("example: if x == 1 then foo else bar end");
+ F_NODE(nd_cond, "condition expr");
+ F_NODE(nd_body, "then clause");
+ LAST_NODE;
+ F_NODE(nd_else, "else clause");
+ return;
+
+ case NODE_UNLESS:
+ ANN("unless statement");
+ ANN("format: unless [nd_cond] then [nd_body] else [nd_else] end");
+ ANN("example: unless x == 1 then foo else bar end");
+ F_NODE(nd_cond, "condition expr");
+ F_NODE(nd_body, "then clause");
+ LAST_NODE;
+ F_NODE(nd_else, "else clause");
+ return;
+
+ case NODE_CASE:
+ ANN("case statement");
+ ANN("format: case [nd_head]; [nd_body]; end");
+ ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
+ F_NODE(nd_head, "case expr");
+ LAST_NODE;
+ F_NODE(nd_body, "when clauses");
+ return;
+ case NODE_CASE2:
+ ANN("case statement with no head");
+ ANN("format: case; [nd_body]; end");
+ ANN("example: case; when 1; foo; when 2; bar; else baz; end");
+ F_NODE(nd_head, "case expr");
+ LAST_NODE;
+ F_NODE(nd_body, "when clauses");
+ return;
+ case NODE_CASE3:
+ ANN("case statement (pattern matching)");
+ ANN("format: case [nd_head]; [nd_body]; end");
+ ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
+ F_NODE(nd_head, "case expr");
+ LAST_NODE;
+ F_NODE(nd_body, "in clauses");
+ return;
+
+ case NODE_WHEN:
+ ANN("when clause");
+ ANN("format: when [nd_head]; [nd_body]; (when or else) [nd_next]");
+ ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
+ F_NODE(nd_head, "when value");
+ F_NODE(nd_body, "when body");
+ LAST_NODE;
+ F_NODE(nd_next, "next when clause");
+ return;
+
+ case NODE_IN:
+ ANN("in clause");
+ ANN("format: in [nd_head]; [nd_body]; (in or else) [nd_next]");
+ ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
+ F_NODE(nd_head, "in pattern");
+ F_NODE(nd_body, "in body");
+ LAST_NODE;
+ F_NODE(nd_next, "next in clause");
+ return;
+
+ case NODE_WHILE:
+ ANN("while statement");
+ ANN("format: while [nd_cond]; [nd_body]; end");
+ ANN("example: while x == 1; foo; end");
+ goto loop;
+ case NODE_UNTIL:
+ ANN("until statement");
+ ANN("format: until [nd_cond]; [nd_body]; end");
+ ANN("example: until x == 1; foo; end");
+ loop:
+ F_CUSTOM1(nd_state, "begin-end-while?") {
+ A_INT((int)node->nd_state);
+ A((node->nd_state == 1) ? " (while-end)" : " (begin-end-while)");
+ }
+ F_NODE(nd_cond, "condition");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_ITER:
+ ANN("method call with block");
+ ANN("format: [nd_iter] { [nd_body] }");
+ ANN("example: 3.times { foo }");
+ goto iter;
+ case NODE_FOR:
+ ANN("for statement");
+ ANN("format: for * in [nd_iter] do [nd_body] end");
+ ANN("example: for i in 1..3 do foo end");
+ iter:
+ F_NODE(nd_iter, "iteration receiver");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_FOR_MASGN:
+ ANN("vars of for statement with masgn");
+ ANN("format: for [nd_var] in ... do ... end");
+ ANN("example: for x, y in 1..3 do foo end");
+ LAST_NODE;
+ F_NODE(nd_var, "var");
+ return;
+
+ case NODE_BREAK:
+ ANN("break statement");
+ ANN("format: break [nd_stts]");
+ ANN("example: break 1");
+ goto jump;
+ case NODE_NEXT:
+ ANN("next statement");
+ ANN("format: next [nd_stts]");
+ ANN("example: next 1");
+ goto jump;
+ case NODE_RETURN:
+ ANN("return statement");
+ ANN("format: return [nd_stts]");
+ ANN("example: return 1");
+ jump:
+ LAST_NODE;
+ F_NODE(nd_stts, "value");
+ return;
+
+ case NODE_REDO:
+ ANN("redo statement");
+ ANN("format: redo");
+ ANN("example: redo");
+ return;
+
+ case NODE_RETRY:
+ ANN("retry statement");
+ ANN("format: retry");
+ ANN("example: retry");
+ return;
+
+ case NODE_BEGIN:
+ ANN("begin statement");
+ ANN("format: begin; [nd_body]; end");
+ ANN("example: begin; 1; end");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_RESCUE:
+ ANN("rescue clause");
+ ANN("format: begin; [nd_body]; (rescue) [nd_resq]; else [nd_else]; end");
+ ANN("example: begin; foo; rescue; bar; else; baz; end");
+ F_NODE(nd_head, "body");
+ F_NODE(nd_resq, "rescue clause list");
+ LAST_NODE;
+ F_NODE(nd_else, "rescue else clause");
+ return;
+
+ case NODE_RESBODY:
+ ANN("rescue clause (cont'd)");
+ ANN("format: rescue [nd_args]; [nd_body]; (rescue) [nd_head]");
+ ANN("example: begin; foo; rescue; bar; else; baz; end");
+ F_NODE(nd_args, "rescue exceptions");
+ F_NODE(nd_body, "rescue clause");
+ LAST_NODE;
+ F_NODE(nd_head, "next rescue clause");
+ return;
+
+ case NODE_ENSURE:
+ ANN("ensure clause");
+ ANN("format: begin; [nd_head]; ensure; [nd_ensr]; end");
+ ANN("example: begin; foo; ensure; bar; end");
+ F_NODE(nd_head, "body");
+ LAST_NODE;
+ F_NODE(nd_ensr, "ensure clause");
+ return;
+
+ case NODE_AND:
+ ANN("&& operator");
+ ANN("format: [nd_1st] && [nd_2nd]");
+ ANN("example: foo && bar");
+ goto andor;
+ case NODE_OR:
+ ANN("|| operator");
+ ANN("format: [nd_1st] || [nd_2nd]");
+ ANN("example: foo || bar");
+ andor:
+ while (1) {
+ F_NODE(nd_1st, "left expr");
+ if (!node->nd_2nd || !nd_type_p(node->nd_2nd, type))
+ break;
+ node = node->nd_2nd;
+ }
+ LAST_NODE;
+ F_NODE(nd_2nd, "right expr");
+ return;
+
+ case NODE_MASGN:
+ ANN("multiple assignment");
+ ANN("format: [nd_head], [nd_args] = [nd_value]");
+ ANN("example: a, b = foo");
+ F_NODE(nd_value, "rhsn");
+ F_NODE(nd_head, "lhsn");
+ if (NODE_NAMED_REST_P(node->nd_args)) {
+ LAST_NODE;
+ F_NODE(nd_args, "splatn");
+ }
+ else {
+ F_MSG(nd_args, "splatn", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ return;
+
+ case NODE_LASGN:
+ ANN("local variable assignment");
+ ANN("format: [nd_vid](lvar) = [nd_value]");
+ ANN("example: x = foo");
+ F_ID(nd_vid, "local variable");
+ if (NODE_REQUIRED_KEYWORD_P(node)) {
+ F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
+ }
+ else {
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ }
+ return;
+ case NODE_DASGN:
+ ANN("dynamic variable assignment");
+ ANN("format: [nd_vid](dvar) = [nd_value]");
+ ANN("example: x = nil; 1.times { x = foo }");
+ ANN("example: 1.times { x = foo }");
+ F_ID(nd_vid, "local variable");
+ if (NODE_REQUIRED_KEYWORD_P(node)) {
+ F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
+ }
+ else {
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ }
+ return;
+ case NODE_IASGN:
+ ANN("instance variable assignment");
+ ANN("format: [nd_vid](ivar) = [nd_value]");
+ ANN("example: @x = foo");
+ F_ID(nd_vid, "instance variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+ case NODE_CVASGN:
+ ANN("class variable assignment");
+ ANN("format: [nd_vid](cvar) = [nd_value]");
+ ANN("example: @@x = foo");
+ F_ID(nd_vid, "class variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+ case NODE_GASGN:
+ ANN("global variable assignment");
+ ANN("format: [nd_entry](gvar) = [nd_value]");
+ ANN("example: $x = foo");
+ F_GENTRY(nd_entry, "global variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_CDECL:
+ ANN("constant declaration");
+ ANN("format: [nd_else]::[nd_vid](constant) = [nd_value]");
+ ANN("example: X = foo");
+ if (node->nd_vid) {
+ F_ID(nd_vid, "constant");
+ F_MSG(nd_else, "extension", "not used");
+ }
+ else {
+ F_MSG(nd_vid, "constant", "0 (see extension field)");
+ F_NODE(nd_else, "extension");
+ }
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_OP_ASGN1:
+ ANN("array assignment with operator");
+ ANN("format: [nd_recv] [ [nd_args->nd_head] ] [nd_mid]= [nd_args->nd_body]");
+ ANN("example: ary[1] += foo");
+ F_NODE(nd_recv, "receiver");
+ F_ID(nd_mid, "operator");
+ F_NODE(nd_args->nd_head, "index");
+ LAST_NODE;
+ F_NODE(nd_args->nd_body, "rvalue");
+ return;
+
+ case NODE_OP_ASGN2:
+ ANN("attr assignment with operator");
+ ANN("format: [nd_recv].[attr] [nd_next->nd_mid]= [nd_value]");
+ ANN(" where [attr]: [nd_next->nd_vid]");
+ ANN("example: struct.field += foo");
+ F_NODE(nd_recv, "receiver");
+ F_CUSTOM1(nd_next->nd_vid, "attr") {
+ if (node->nd_next->nd_aid) A("? ");
+ A_ID(node->nd_next->nd_vid);
+ }
+ F_ID(nd_next->nd_mid, "operator");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_OP_ASGN_AND:
+ ANN("assignment with && operator");
+ ANN("format: [nd_head] &&= [nd_value]");
+ ANN("example: foo &&= bar");
+ goto asgn_andor;
+ case NODE_OP_ASGN_OR:
+ ANN("assignment with || operator");
+ ANN("format: [nd_head] ||= [nd_value]");
+ ANN("example: foo ||= bar");
+ asgn_andor:
+ F_NODE(nd_head, "variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_OP_CDECL:
+ ANN("constant declaration with operator");
+ ANN("format: [nd_head](constant) [nd_aid]= [nd_value]");
+ ANN("example: A::B ||= 1");
+ F_NODE(nd_head, "constant");
+ F_ID(nd_aid, "operator");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_CALL:
+ ANN("method invocation");
+ ANN("format: [nd_recv].[nd_mid]([nd_args])");
+ ANN("example: obj.foo(1)");
+ F_ID(nd_mid, "method id");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_OPCALL:
+ ANN("method invocation");
+ ANN("format: [nd_recv] [nd_mid] [nd_args]");
+ ANN("example: foo + bar");
+ F_ID(nd_mid, "method id");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_FCALL:
+ ANN("function call");
+ ANN("format: [nd_mid]([nd_args])");
+ ANN("example: foo(1)");
+ F_ID(nd_mid, "method id");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_VCALL:
+ ANN("function call with no argument");
+ ANN("format: [nd_mid]");
+ ANN("example: foo");
+ F_ID(nd_mid, "method id");
+ return;
+
+ case NODE_QCALL:
+ ANN("safe method invocation");
+ ANN("format: [nd_recv]&.[nd_mid]([nd_args])");
+ ANN("example: obj&.foo(1)");
+ F_ID(nd_mid, "method id");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_SUPER:
+ ANN("super invocation");
+ ANN("format: super [nd_args]");
+ ANN("example: super 1");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_ZSUPER:
+ ANN("super invocation with no argument");
+ ANN("format: super");
+ ANN("example: super");
+ return;
+
+ case NODE_LIST:
+ ANN("list constructor");
+ ANN("format: [ [nd_head], [nd_next].. ] (length: [nd_alen])");
+ ANN("example: [1, 2, 3]");
+ goto ary;
+ case NODE_VALUES:
+ ANN("return arguments");
+ ANN("format: [ [nd_head], [nd_next].. ] (length: [nd_alen])");
+ ANN("example: return 1, 2, 3");
+ ary:
+ dump_array(buf, indent, comment, node);
+ return;
+
+ case NODE_ZLIST:
+ ANN("empty list constructor");
+ ANN("format: []");
+ ANN("example: []");
+ return;
+
+ case NODE_HASH:
+ if (!node->nd_brace) {
+ ANN("keyword arguments");
+ ANN("format: nd_head");
+ ANN("example: a: 1, b: 2");
+ }
+ else {
+ ANN("hash constructor");
+ ANN("format: { [nd_head] }");
+ ANN("example: { 1 => 2, 3 => 4 }");
+ }
+ F_CUSTOM1(nd_brace, "keyword arguments or hash literal") {
+ switch (node->nd_brace) {
+ case 0: A("0 (keyword argument)"); break;
+ case 1: A("1 (hash literal)"); break;
+ }
+ }
+ LAST_NODE;
+ F_NODE(nd_head, "contents");
+ return;
+
+ case NODE_YIELD:
+ ANN("yield invocation");
+ ANN("format: yield [nd_head]");
+ ANN("example: yield 1");
+ LAST_NODE;
+ F_NODE(nd_head, "arguments");
+ return;
+
+ case NODE_LVAR:
+ ANN("local variable reference");
+ ANN("format: [nd_vid](lvar)");
+ ANN("example: x");
+ F_ID(nd_vid, "local variable");
+ return;
+ case NODE_DVAR:
+ ANN("dynamic variable reference");
+ ANN("format: [nd_vid](dvar)");
+ ANN("example: 1.times { x = 1; x }");
+ F_ID(nd_vid, "local variable");
+ return;
+ case NODE_IVAR:
+ ANN("instance variable reference");
+ ANN("format: [nd_vid](ivar)");
+ ANN("example: @x");
+ F_ID(nd_vid, "instance variable");
+ return;
+ case NODE_CONST:
+ ANN("constant reference");
+ ANN("format: [nd_vid](constant)");
+ ANN("example: X");
+ F_ID(nd_vid, "constant");
+ return;
+ case NODE_CVAR:
+ ANN("class variable reference");
+ ANN("format: [nd_vid](cvar)");
+ ANN("example: @@x");
+ F_ID(nd_vid, "class variable");
+ return;
+
+ case NODE_GVAR:
+ ANN("global variable reference");
+ ANN("format: [nd_entry](gvar)");
+ ANN("example: $x");
+ F_GENTRY(nd_entry, "global variable");
+ return;
+
+ case NODE_NTH_REF:
+ ANN("nth special variable reference");
+ ANN("format: $[nd_nth]");
+ ANN("example: $1, $2, ..");
+ F_CUSTOM1(nd_nth, "variable") { A("$"); A_LONG(node->nd_nth); }
+ return;
+
+ case NODE_BACK_REF:
+ ANN("back special variable reference");
+ ANN("format: $[nd_nth]");
+ ANN("example: $&, $`, $', $+");
+ F_CUSTOM1(nd_nth, "variable") {
+ char name[3] = "$ ";
+ name[1] = (char)node->nd_nth;
+ A(name);
+ }
+ return;
+
+ case NODE_MATCH:
+ ANN("match expression (against $_ implicitly)");
+ ANN("format: [nd_lit] (in condition)");
+ ANN("example: if /foo/; foo; end");
+ F_LIT(nd_lit, "regexp");
+ return;
+
+ case NODE_MATCH2:
+ ANN("match expression (regexp first)");
+ ANN("format: [nd_recv] =~ [nd_value]");
+ ANN("example: /foo/ =~ 'foo'");
+ F_NODE(nd_recv, "regexp (receiver)");
+ if (!node->nd_args) LAST_NODE;
+ F_NODE(nd_value, "string (argument)");
+ if (node->nd_args) {
+ LAST_NODE;
+ F_NODE(nd_args, "named captures");
+ }
+ return;
+
+ case NODE_MATCH3:
+ ANN("match expression (regexp second)");
+ ANN("format: [nd_recv] =~ [nd_value]");
+ ANN("example: 'foo' =~ /foo/");
+ F_NODE(nd_recv, "string (receiver)");
+ LAST_NODE;
+ F_NODE(nd_value, "regexp (argument)");
+ return;
+
+ case NODE_LIT:
+ ANN("literal");
+ ANN("format: [nd_lit]");
+ ANN("example: 1, /foo/");
+ goto lit;
+ case NODE_STR:
+ ANN("string literal");
+ ANN("format: [nd_lit]");
+ ANN("example: 'foo'");
+ goto lit;
+ case NODE_XSTR:
+ ANN("xstring literal");
+ ANN("format: [nd_lit]");
+ ANN("example: `foo`");
+ lit:
+ F_LIT(nd_lit, "literal");
+ return;
+
+ case NODE_ONCE:
+ ANN("once evaluation");
+ ANN("format: [nd_body]");
+ ANN("example: /foo#{ bar }baz/o");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+ case NODE_DSTR:
+ ANN("string literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: \"foo#{ bar }baz\"");
+ goto dlit;
+ case NODE_DXSTR:
+ ANN("xstring literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: `foo#{ bar }baz`");
+ goto dlit;
+ case NODE_DREGX:
+ ANN("regexp literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: /foo#{ bar }baz/");
+ goto dlit;
+ case NODE_DSYM:
+ ANN("symbol literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: :\"foo#{ bar }baz\"");
+ dlit:
+ F_LIT(nd_lit, "preceding string");
+ if (!node->nd_next) return;
+ F_NODE(nd_next->nd_head, "interpolation");
+ LAST_NODE;
+ F_NODE(nd_next->nd_next, "tailing strings");
+ return;
+
+ case NODE_EVSTR:
+ ANN("interpolation expression");
+ ANN("format: \"..#{ [nd_lit] }..\"");
+ ANN("example: \"foo#{ bar }baz\"");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_ARGSCAT:
+ ANN("splat argument following arguments");
+ ANN("format: ..(*[nd_head], [nd_body..])");
+ ANN("example: foo(*ary, post_arg1, post_arg2)");
+ F_NODE(nd_head, "preceding array");
+ LAST_NODE;
+ F_NODE(nd_body, "following array");
+ return;
+
+ case NODE_ARGSPUSH:
+ ANN("splat argument following one argument");
+ ANN("format: ..(*[nd_head], [nd_body])");
+ ANN("example: foo(*ary, post_arg)");
+ F_NODE(nd_head, "preceding array");
+ LAST_NODE;
+ F_NODE(nd_body, "following element");
+ return;
+
+ case NODE_SPLAT:
+ ANN("splat argument");
+ ANN("format: *[nd_head]");
+ ANN("example: foo(*ary)");
+ LAST_NODE;
+ F_NODE(nd_head, "splat'ed array");
+ return;
+
+ case NODE_BLOCK_PASS:
+ ANN("arguments with block argument");
+ ANN("format: ..([nd_head], &[nd_body])");
+ ANN("example: foo(x, &blk)");
+ F_NODE(nd_head, "other arguments");
+ LAST_NODE;
+ F_NODE(nd_body, "block argument");
+ return;
+
+ case NODE_DEFN:
+ ANN("method definition");
+ ANN("format: def [nd_mid] [nd_defn]; end");
+ ANN("example: def foo; bar; end");
+ F_ID(nd_mid, "method name");
+ LAST_NODE;
+ F_NODE(nd_defn, "method definition");
+ return;
+
+ case NODE_DEFS:
+ ANN("singleton method definition");
+ ANN("format: def [nd_recv].[nd_mid] [nd_defn]; end");
+ ANN("example: def obj.foo; bar; end");
+ F_NODE(nd_recv, "receiver");
+ F_ID(nd_mid, "method name");
+ LAST_NODE;
+ F_NODE(nd_defn, "method definition");
+ return;
+
+ case NODE_ALIAS:
+ ANN("method alias statement");
+ ANN("format: alias [nd_1st] [nd_2nd]");
+ ANN("example: alias bar foo");
+ F_NODE(nd_1st, "new name");
+ LAST_NODE;
+ F_NODE(nd_2nd, "old name");
+ return;
+
+ case NODE_VALIAS:
+ ANN("global variable alias statement");
+ ANN("format: alias [nd_alias](gvar) [nd_orig](gvar)");
+ ANN("example: alias $y $x");
+ F_ID(nd_alias, "new name");
+ F_ID(nd_orig, "old name");
+ return;
+
+ case NODE_UNDEF:
+ ANN("method undef statement");
+ ANN("format: undef [nd_undef]");
+ ANN("example: undef foo");
+ LAST_NODE;
+ F_NODE(nd_undef, "old name");
+ return;
+
+ case NODE_CLASS:
+ ANN("class definition");
+ ANN("format: class [nd_cpath] < [nd_super]; [nd_body]; end");
+ ANN("example: class C2 < C; ..; end");
+ F_NODE(nd_cpath, "class path");
+ F_NODE(nd_super, "superclass");
+ LAST_NODE;
+ F_NODE(nd_body, "class definition");
+ return;
+
+ case NODE_MODULE:
+ ANN("module definition");
+ ANN("format: module [nd_cpath]; [nd_body]; end");
+ ANN("example: module M; ..; end");
+ F_NODE(nd_cpath, "module path");
+ LAST_NODE;
+ F_NODE(nd_body, "module definition");
+ return;
+
+ case NODE_SCLASS:
+ ANN("singleton class definition");
+ ANN("format: class << [nd_recv]; [nd_body]; end");
+ ANN("example: class << obj; ..; end");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_body, "singleton class definition");
+ return;
+
+ case NODE_COLON2:
+ ANN("scoped constant reference");
+ ANN("format: [nd_head]::[nd_mid]");
+ ANN("example: M::C");
+ F_ID(nd_mid, "constant name");
+ LAST_NODE;
+ F_NODE(nd_head, "receiver");
+ return;
+
+ case NODE_COLON3:
+ ANN("top-level constant reference");
+ ANN("format: ::[nd_mid]");
+ ANN("example: ::Object");
+ F_ID(nd_mid, "constant name");
+ return;
+
+ case NODE_DOT2:
+ ANN("range constructor (incl.)");
+ ANN("format: [nd_beg]..[nd_end]");
+ ANN("example: 1..5");
+ goto dot;
+ case NODE_DOT3:
+ ANN("range constructor (excl.)");
+ ANN("format: [nd_beg]...[nd_end]");
+ ANN("example: 1...5");
+ goto dot;
+ case NODE_FLIP2:
+ ANN("flip-flop condition (incl.)");
+ ANN("format: [nd_beg]..[nd_end]");
+ ANN("example: if (x==1)..(x==5); foo; end");
+ goto dot;
+ case NODE_FLIP3:
+ ANN("flip-flop condition (excl.)");
+ ANN("format: [nd_beg]...[nd_end]");
+ ANN("example: if (x==1)...(x==5); foo; end");
+ dot:
+ F_NODE(nd_beg, "begin");
+ LAST_NODE;
+ F_NODE(nd_end, "end");
+ return;
+
+ case NODE_SELF:
+ ANN("self");
+ ANN("format: self");
+ ANN("example: self");
+ return;
+
+ case NODE_NIL:
+ ANN("nil");
+ ANN("format: nil");
+ ANN("example: nil");
+ return;
+
+ case NODE_TRUE:
+ ANN("true");
+ ANN("format: true");
+ ANN("example: true");
+ return;
+
+ case NODE_FALSE:
+ ANN("false");
+ ANN("format: false");
+ ANN("example: false");
+ return;
+
+ case NODE_ERRINFO:
+ ANN("virtual reference to $!");
+ ANN("format: rescue => id");
+ ANN("example: rescue => id");
+ return;
+
+ case NODE_DEFINED:
+ ANN("defined? expression");
+ ANN("format: defined?([nd_head])");
+ ANN("example: defined?(foo)");
+ F_NODE(nd_head, "expr");
+ return;
+
+ case NODE_POSTEXE:
+ ANN("post-execution");
+ ANN("format: END { [nd_body] }");
+ ANN("example: END { foo }");
+ LAST_NODE;
+ F_NODE(nd_body, "END clause");
+ return;
+
+ case NODE_ATTRASGN:
+ ANN("attr assignment");
+ ANN("format: [nd_recv].[nd_mid] = [nd_args]");
+ ANN("example: struct.field = foo");
+ F_NODE(nd_recv, "receiver");
+ F_ID(nd_mid, "method name");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_LAMBDA:
+ ANN("lambda expression");
+ ANN("format: -> [nd_body]");
+ ANN("example: -> { foo }");
+ LAST_NODE;
+ F_NODE(nd_body, "lambda clause");
+ return;
+
+ case NODE_OPT_ARG:
+ ANN("optional arguments");
+ ANN("format: def method_name([nd_body=some], [nd_next..])");
+ ANN("example: def foo(a, b=1, c); end");
+ F_NODE(nd_body, "body");
+ LAST_NODE;
+ F_NODE(nd_next, "next");
+ return;
+
+ case NODE_KW_ARG:
+ ANN("keyword arguments");
+ ANN("format: def method_name([nd_body=some], [nd_next..])");
+ ANN("example: def foo(a:1, b:2); end");
+ F_NODE(nd_body, "body");
+ LAST_NODE;
+ F_NODE(nd_next, "next");
+ return;
+
+ case NODE_POSTARG:
+ ANN("post arguments");
+ ANN("format: *[nd_1st], [nd_2nd..] = ..");
+ ANN("example: a, *rest, z = foo");
+ if (NODE_NAMED_REST_P(node->nd_1st)) {
+ F_NODE(nd_1st, "rest argument");
+ }
+ else {
+ F_MSG(nd_1st, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ LAST_NODE;
+ F_NODE(nd_2nd, "post arguments");
+ return;
+
+ case NODE_ARGS:
+ ANN("method parameters");
+ ANN("format: def method_name(.., [nd_ainfo->nd_optargs], *[nd_ainfo->rest_arg], [nd_ainfo->first_post_arg], .., [nd_ainfo->kw_args], **[nd_ainfo->kw_rest_arg], &[nd_ainfo->block_arg])");
+ ANN("example: def foo(a, b, opt1=1, opt2=2, *rest, y, z, kw: 1, **kwrest, &blk); end");
+ F_INT(nd_ainfo->pre_args_num, "count of mandatory (pre-)arguments");
+ F_NODE(nd_ainfo->pre_init, "initialization of (pre-)arguments");
+ F_INT(nd_ainfo->post_args_num, "count of mandatory post-arguments");
+ F_NODE(nd_ainfo->post_init, "initialization of post-arguments");
+ F_ID(nd_ainfo->first_post_arg, "first post argument");
+ F_CUSTOM1(nd_ainfo->rest_arg, "rest argument") {
+ if (node->nd_ainfo->rest_arg == NODE_SPECIAL_EXCESSIVE_COMMA) {
+ A("1 (excessed comma)");
+ }
+ else {
+ A_ID(node->nd_ainfo->rest_arg);
+ }
+ }
+ F_ID(nd_ainfo->block_arg, "block argument");
+ F_NODE(nd_ainfo->opt_args, "optional arguments");
+ F_NODE(nd_ainfo->kw_args, "keyword arguments");
+ LAST_NODE;
+ F_NODE(nd_ainfo->kw_rest_arg, "keyword rest argument");
+ return;
+
+ case NODE_SCOPE:
+ ANN("new scope");
+ ANN("format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body");
+ F_CUSTOM1(nd_tbl, "local table") {
+ rb_ast_id_table_t *tbl = node->nd_tbl;
+ int i;
+ int size = tbl ? tbl->size : 0;
+ if (size == 0) A("(empty)");
+ for (i = 0; i < size; i++) {
+ A_ID(tbl->ids[i]); if (i < size - 1) A(",");
+ }
+ }
+ F_NODE(nd_args, "arguments");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_ARYPTN:
+ ANN("array pattern");
+ ANN("format: [nd_pconst]([pre_args], ..., *[rest_arg], [post_args], ...)");
+ F_NODE(nd_pconst, "constant");
+ F_NODE(nd_apinfo->pre_args, "pre arguments");
+ if (NODE_NAMED_REST_P(node->nd_apinfo->rest_arg)) {
+ F_NODE(nd_apinfo->rest_arg, "rest argument");
+ }
+ else {
+ F_MSG(nd_apinfo->rest_arg, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ LAST_NODE;
+ F_NODE(nd_apinfo->post_args, "post arguments");
+ return;
+
+ case NODE_FNDPTN:
+ ANN("find pattern");
+ ANN("format: [nd_pconst](*[pre_rest_arg], args, ..., *[post_rest_arg])");
+ F_NODE(nd_pconst, "constant");
+ if (NODE_NAMED_REST_P(node->nd_fpinfo->pre_rest_arg)) {
+ F_NODE(nd_fpinfo->pre_rest_arg, "pre rest argument");
+ }
+ else {
+ F_MSG(nd_fpinfo->pre_rest_arg, "pre rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ F_NODE(nd_fpinfo->args, "arguments");
+
+ LAST_NODE;
+ if (NODE_NAMED_REST_P(node->nd_fpinfo->post_rest_arg)) {
+ F_NODE(nd_fpinfo->post_rest_arg, "post rest argument");
+ }
+ else {
+ F_MSG(nd_fpinfo->post_rest_arg, "post rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ return;
+
+ case NODE_HSHPTN:
+ ANN("hash pattern");
+ ANN("format: [nd_pconst]([nd_pkwargs], ..., **[nd_pkwrestarg])");
+ F_NODE(nd_pconst, "constant");
+ F_NODE(nd_pkwargs, "keyword arguments");
+ LAST_NODE;
+ if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
+ F_MSG(nd_pkwrestarg, "keyword rest argument", "NODE_SPECIAL_NO_REST_KEYWORD (**nil)");
+ }
+ else {
+ F_NODE(nd_pkwrestarg, "keyword rest argument");
+ }
+ return;
+ case NODE_ERROR:
+ ANN("Broken input recovered by Error Tolerant mode");
+ return;
+
+ case NODE_ARGS_AUX:
+ case NODE_LAST:
+ break;
+ }
+
+ rb_bug("dump_node: unknown node: %s", ruby_node_name(nd_type(node)));
+}
+
+VALUE
+rb_parser_dump_tree(const NODE *node, int comment)
+{
+ VALUE buf = rb_str_new_cstr(
+ "###########################################################\n"
+ "## Do NOT use this node dump for any purpose other than ##\n"
+ "## debug and research. Compatibility is not guaranteed. ##\n"
+ "###########################################################\n\n"
+ );
+ dump_node(buf, rb_str_new_cstr("# "), comment, node);
+ return buf;
+}
/* Setup NODE structure.
* NODE is not an object managed by GC, but it imitates an object
@@ -107,58 +1130,83 @@ static void iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_
* objects.
*/
void
-rb_node_init(NODE *n, enum node_type type)
+rb_node_init(NODE *n, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
- RNODE(n)->flags = T_NODE;
- nd_init_type(RNODE(n), type);
- RNODE(n)->nd_loc.beg_pos.lineno = 0;
- RNODE(n)->nd_loc.beg_pos.column = 0;
- RNODE(n)->nd_loc.end_pos.lineno = 0;
- RNODE(n)->nd_loc.end_pos.column = 0;
- RNODE(n)->node_id = -1;
+ n->flags = T_NODE;
+ nd_init_type(n, type);
+ n->u1.value = a0;
+ n->u2.value = a1;
+ n->u3.value = a2;
+ n->nd_loc.beg_pos.lineno = 0;
+ n->nd_loc.beg_pos.column = 0;
+ n->nd_loc.end_pos.lineno = 0;
+ n->nd_loc.end_pos.column = 0;
+ n->node_id = -1;
}
-const char *
-rb_node_name(int node)
-{
- switch (node) {
-#include "node_name.inc"
- default:
- return 0;
- }
-}
+typedef struct node_buffer_elem_struct {
+ struct node_buffer_elem_struct *next;
+ long len;
+ NODE buf[FLEX_ARY_LEN];
+} node_buffer_elem_t;
+
+typedef struct {
+ long idx, len;
+ node_buffer_elem_t *head;
+ node_buffer_elem_t *last;
+} node_buffer_list_t;
+
+struct node_buffer_struct {
+ node_buffer_list_t unmarkable;
+ node_buffer_list_t markable;
+ struct rb_ast_local_table_link *local_tables;
+ VALUE mark_hash;
+ // - id (sequence number)
+ // - token_type
+ // - text of token
+ // - location info
+ // Array, whose entry is array
+ VALUE tokens;
+};
-#ifdef UNIVERSAL_PARSER
-const char *
-ruby_node_name(int node)
+static void
+init_node_buffer_list(node_buffer_list_t * nb, node_buffer_elem_t *head)
{
- return rb_node_name(node);
+ nb->idx = 0;
+ nb->len = NODE_BUF_DEFAULT_LEN;
+ nb->head = nb->last = head;
+ nb->head->len = nb->len;
+ nb->head->next = NULL;
}
-#else
-const char *
-ruby_node_name(int node)
-{
- const char *name = rb_node_name(node);
- if (!name) rb_bug("unknown node: %d", node);
- return name;
+static node_buffer_t *
+rb_node_buffer_new(void)
+{
+ const size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE);
+ const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size * 2);
+ STATIC_ASSERT(
+ integer_overflow,
+ offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE)
+ > sizeof(node_buffer_t) + 2 * sizeof(node_buffer_elem_t));
+ node_buffer_t *nb = ruby_xmalloc(alloc_size);
+ init_node_buffer_list(&nb->unmarkable, (node_buffer_elem_t*)&nb[1]);
+ init_node_buffer_list(&nb->markable, (node_buffer_elem_t*)((size_t)nb->unmarkable.head + bucket_size));
+ nb->local_tables = 0;
+ nb->mark_hash = Qnil;
+ nb->tokens = Qnil;
+ return nb;
}
-#endif
static void
-node_buffer_list_free(rb_ast_t *ast, node_buffer_list_t * nb)
+node_buffer_list_free(node_buffer_list_t * nb)
{
node_buffer_elem_t *nbe = nb->head;
+
while (nbe != nb->last) {
void *buf = nbe;
- xfree(nbe->nodes);
nbe = nbe->next;
xfree(buf);
}
-
- /* The last node_buffer_elem_t is allocated in the node_buffer_t, so we
- * only need to free the nodes. */
- xfree(nbe->nodes);
}
struct rb_ast_local_table_link {
@@ -170,20 +1218,10 @@ struct rb_ast_local_table_link {
};
static void
-free_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
-{
- switch (nd_type(node)) {
- default:
- break;
- }
-}
-
-static void
-rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb)
+rb_node_buffer_free(node_buffer_t *nb)
{
- iterate_node_values(ast, &nb->unmarkable, free_ast_value, NULL);
- node_buffer_list_free(ast, &nb->unmarkable);
- node_buffer_list_free(ast, &nb->markable);
+ node_buffer_list_free(&nb->unmarkable);
+ node_buffer_list_free(&nb->markable);
struct rb_ast_local_table_link *local_table = nb->local_tables;
while (local_table) {
struct rb_ast_local_table_link *next_table = local_table->next;
@@ -193,31 +1231,20 @@ rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb)
xfree(nb);
}
-#define buf_add_offset(nbe, offset) ((char *)(nbe->buf) + (offset))
-
static NODE *
-ast_newnode_in_bucket(rb_ast_t *ast, node_buffer_list_t *nb, size_t size, size_t alignment)
+ast_newnode_in_bucket(node_buffer_list_t *nb)
{
- size_t padding;
- NODE *ptr;
-
- padding = alignment - (size_t)buf_add_offset(nb->head, nb->head->used) % alignment;
- padding = padding == alignment ? 0 : padding;
-
- if (nb->head->used + size + padding > nb->head->allocated) {
- size_t n = nb->head->allocated * 2;
+ if (nb->idx >= nb->len) {
+ long n = nb->len * 2;
node_buffer_elem_t *nbe;
- nbe = rb_xmalloc_mul_add(n, sizeof(char *), offsetof(node_buffer_elem_t, buf));
- init_node_buffer_elem(nbe, n, ruby_xmalloc);
+ nbe = rb_xmalloc_mul_add(n, sizeof(NODE), offsetof(node_buffer_elem_t, buf));
+ nbe->len = n;
+ nb->idx = 0;
+ nb->len = n;
nbe->next = nb->head;
nb->head = nbe;
- padding = 0; /* malloc returns aligned address then no need to add padding */
}
-
- ptr = (NODE *)buf_add_offset(nb->head, nb->head->used + padding);
- nb->head->used += (size + padding);
- nb->head->nodes[nb->head->len++] = ptr;
- return ptr;
+ return &nb->head->buf[nb->idx++];
}
RBIMPL_ATTR_PURE()
@@ -233,6 +1260,9 @@ nodetype_markable_p(enum node_type type)
case NODE_DXSTR:
case NODE_DREGX:
case NODE_DSYM:
+ case NODE_ARGS:
+ case NODE_ARYPTN:
+ case NODE_FNDPTN:
return true;
default:
return false;
@@ -240,15 +1270,14 @@ nodetype_markable_p(enum node_type type)
}
NODE *
-rb_ast_newnode(rb_ast_t *ast, enum node_type type, size_t size, size_t alignment)
+rb_ast_newnode(rb_ast_t *ast, enum node_type type)
{
node_buffer_t *nb = ast->node_buffer;
node_buffer_list_t *bucket =
(nodetype_markable_p(type) ? &nb->markable : &nb->unmarkable);
- return ast_newnode_in_bucket(ast, bucket, size, alignment);
+ return ast_newnode_in_bucket(bucket);
}
-#if RUBY_DEBUG
void
rb_ast_node_type_change(NODE *n, enum node_type type)
{
@@ -258,7 +1287,6 @@ rb_ast_node_type_change(NODE *n, enum node_type type)
ruby_node_name(old_type), ruby_node_name(type));
}
}
-#endif
rb_ast_id_table_t *
rb_ast_new_local_table(rb_ast_t *ast, int size)
@@ -292,15 +1320,6 @@ rb_ast_delete_node(rb_ast_t *ast, NODE *n)
/* should we implement freelist? */
}
-#ifdef UNIVERSAL_PARSER
-rb_ast_t *
-rb_ast_new(rb_parser_config_t *config)
-{
- node_buffer_t *nb = rb_node_buffer_new(config);
- config->counter++;
- return config->ast_new((VALUE)nb);
-}
-#else
rb_ast_t *
rb_ast_new(void)
{
@@ -308,36 +1327,43 @@ rb_ast_new(void)
rb_ast_t *ast = (rb_ast_t *)rb_imemo_new(imemo_ast, 0, 0, 0, (VALUE)nb);
return ast;
}
-#endif
+
+typedef void node_itr_t(void *ctx, NODE * node);
static void
-iterate_buffer_elements(rb_ast_t *ast, node_buffer_elem_t *nbe, long len, node_itr_t *func, void *ctx)
+iterate_buffer_elements(node_buffer_elem_t *nbe, long len, node_itr_t *func, void *ctx)
{
long cursor;
for (cursor = 0; cursor < len; cursor++) {
- func(ast, ctx, nbe->nodes[cursor]);
+ func(ctx, &nbe->buf[cursor]);
}
}
static void
-iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx)
+iterate_node_values(node_buffer_list_t *nb, node_itr_t * func, void *ctx)
{
node_buffer_elem_t *nbe = nb->head;
+ /* iterate over the head first because it's not full */
+ iterate_buffer_elements(nbe, nb->idx, func, ctx);
+
+ nbe = nbe->next;
while (nbe) {
- iterate_buffer_elements(ast, nbe, nbe->len, func, ctx);
+ iterate_buffer_elements(nbe, nbe->len, func, ctx);
nbe = nbe->next;
}
}
static void
-mark_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
+mark_ast_value(void *ctx, NODE * node)
{
-#ifdef UNIVERSAL_PARSER
- bug_report_func rb_bug = ast->node_buffer->config->bug;
-#endif
-
switch (nd_type(node)) {
+ case NODE_ARGS:
+ {
+ struct rb_args_info *args = node->nd_ainfo;
+ rb_gc_mark_movable(args->imemo);
+ break;
+ }
case NODE_MATCH:
case NODE_LIT:
case NODE_STR:
@@ -346,7 +1372,11 @@ mark_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
case NODE_DXSTR:
case NODE_DREGX:
case NODE_DSYM:
- rb_gc_mark_movable(RNODE_LIT(node)->nd_lit);
+ rb_gc_mark_movable(node->nd_lit);
+ break;
+ case NODE_ARYPTN:
+ case NODE_FNDPTN:
+ rb_gc_mark_movable(node->nd_rval);
break;
default:
rb_bug("unreachable node %s", ruby_node_name(nd_type(node)));
@@ -354,13 +1384,15 @@ mark_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
}
static void
-update_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
+update_ast_value(void *ctx, NODE * node)
{
-#ifdef UNIVERSAL_PARSER
- bug_report_func rb_bug = ast->node_buffer->config->bug;
-#endif
-
switch (nd_type(node)) {
+ case NODE_ARGS:
+ {
+ struct rb_args_info *args = node->nd_ainfo;
+ args->imemo = rb_gc_location(args->imemo);
+ break;
+ }
case NODE_MATCH:
case NODE_LIT:
case NODE_STR:
@@ -369,7 +1401,11 @@ update_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
case NODE_DXSTR:
case NODE_DREGX:
case NODE_DSYM:
- RNODE_LIT(node)->nd_lit = rb_gc_location(RNODE_LIT(node)->nd_lit);
+ node->nd_lit = rb_gc_location(node->nd_lit);
+ break;
+ case NODE_ARYPTN:
+ case NODE_FNDPTN:
+ node->nd_rval = rb_gc_location(node->nd_rval);
break;
default:
rb_bug("unreachable");
@@ -382,7 +1418,7 @@ rb_ast_update_references(rb_ast_t *ast)
if (ast->node_buffer) {
node_buffer_t *nb = ast->node_buffer;
- iterate_node_values(ast, &nb->markable, update_ast_value, NULL);
+ iterate_node_values(&nb->markable, update_ast_value, NULL);
}
}
@@ -392,28 +1428,22 @@ rb_ast_mark(rb_ast_t *ast)
if (ast->node_buffer) {
rb_gc_mark(ast->node_buffer->mark_hash);
rb_gc_mark(ast->node_buffer->tokens);
+ }
+ if (ast->body.compile_option) rb_gc_mark(ast->body.compile_option);
+ if (ast->node_buffer) {
node_buffer_t *nb = ast->node_buffer;
- iterate_node_values(ast, &nb->markable, mark_ast_value, NULL);
- if (ast->body.script_lines) rb_gc_mark(ast->body.script_lines);
+
+ iterate_node_values(&nb->markable, mark_ast_value, NULL);
}
+ if (ast->body.script_lines) rb_gc_mark(ast->body.script_lines);
}
void
rb_ast_free(rb_ast_t *ast)
{
if (ast->node_buffer) {
-#ifdef UNIVERSAL_PARSER
- rb_parser_config_t *config = ast->node_buffer->config;
-#endif
-
- rb_node_buffer_free(ast, ast->node_buffer);
+ rb_node_buffer_free(ast->node_buffer);
ast->node_buffer = 0;
-#ifdef UNIVERSAL_PARSER
- config->counter--;
- if (config->counter <= 0) {
- rb_ruby_parser_config_free(config);
- }
-#endif
}
}
@@ -423,8 +1453,8 @@ buffer_list_size(node_buffer_list_t *nb)
size_t size = 0;
node_buffer_elem_t *nbe = nb->head;
while (nbe != nb->last) {
- size += offsetof(node_buffer_elem_t, buf) + nbe->used;
nbe = nbe->next;
+ size += offsetof(node_buffer_elem_t, buf) + nb->len * sizeof(NODE);
}
return size;
}
@@ -436,7 +1466,7 @@ rb_ast_memsize(const rb_ast_t *ast)
node_buffer_t *nb = ast->node_buffer;
if (nb) {
- size += sizeof(node_buffer_t);
+ size += sizeof(node_buffer_t) + offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE);
size += buffer_list_size(&nb->unmarkable);
size += buffer_list_size(&nb->markable);
}
@@ -458,13 +1488,6 @@ rb_ast_add_mark_object(rb_ast_t *ast, VALUE obj)
rb_hash_aset(ast->node_buffer->mark_hash, obj, Qtrue);
}
-void
-rb_ast_delete_mark_object(rb_ast_t *ast, VALUE obj)
-{
- if (NIL_P(ast->node_buffer->mark_hash)) return;
- rb_hash_delete(ast->node_buffer->mark_hash, obj);
-}
-
VALUE
rb_ast_tokens(rb_ast_t *ast)
{
@@ -476,12 +1499,3 @@ rb_ast_set_tokens(rb_ast_t *ast, VALUE tokens)
{
RB_OBJ_WRITE(ast, &ast->node_buffer->tokens, tokens);
}
-
-VALUE
-rb_node_set_type(NODE *n, enum node_type t)
-{
-#if RUBY_DEBUG
- rb_ast_node_type_change(n, t);
-#endif
- return nd_init_type(n, t);
-}
diff --git a/node.h b/node.h
index d8d104975a..befb1328fb 100644
--- a/node.h
+++ b/node.h
@@ -11,118 +11,504 @@
**********************************************************************/
-#include <stdbool.h>
-#include "rubyparser.h"
-#include "ruby/backward/2/attributes.h"
-
-typedef void (*bug_report_func)(const char *fmt, ...);
-
-typedef struct node_buffer_elem_struct {
- struct node_buffer_elem_struct *next;
- long len; /* Length of nodes */
- size_t allocated; /* Total memory size of allocated buf */
- size_t used; /* Current usage of buf */
- NODE **nodes; /* Array of node pointers */
- NODE *buf[FLEX_ARY_LEN];
-} node_buffer_elem_t;
-
-typedef struct {
- node_buffer_elem_t *head;
- node_buffer_elem_t *last;
-} node_buffer_list_t;
-
-struct node_buffer_struct {
- node_buffer_list_t unmarkable;
- node_buffer_list_t markable;
- struct rb_ast_local_table_link *local_tables;
- VALUE mark_hash;
- // - id (sequence number)
- // - token_type
- // - text of token
- // - location info
- // Array, whose entry is array
- VALUE tokens;
-#ifdef UNIVERSAL_PARSER
- rb_parser_config_t *config;
+#include "internal/compilers.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
#endif
+
+enum node_type {
+ NODE_SCOPE,
+ NODE_BLOCK,
+ NODE_IF,
+ NODE_UNLESS,
+ NODE_CASE,
+ NODE_CASE2,
+ NODE_CASE3,
+ NODE_WHEN,
+ NODE_IN,
+ NODE_WHILE,
+ NODE_UNTIL,
+ NODE_ITER,
+ NODE_FOR,
+ NODE_FOR_MASGN,
+ NODE_BREAK,
+ NODE_NEXT,
+ NODE_REDO,
+ NODE_RETRY,
+ NODE_BEGIN,
+ NODE_RESCUE,
+ NODE_RESBODY,
+ NODE_ENSURE,
+ NODE_AND,
+ NODE_OR,
+ NODE_MASGN,
+ NODE_LASGN,
+ NODE_DASGN,
+ NODE_GASGN,
+ NODE_IASGN,
+ NODE_CDECL,
+ NODE_CVASGN,
+ NODE_OP_ASGN1,
+ NODE_OP_ASGN2,
+ NODE_OP_ASGN_AND,
+ NODE_OP_ASGN_OR,
+ NODE_OP_CDECL,
+ NODE_CALL,
+ NODE_OPCALL,
+ NODE_FCALL,
+ NODE_VCALL,
+ NODE_QCALL,
+ NODE_SUPER,
+ NODE_ZSUPER,
+ NODE_LIST,
+ NODE_ZLIST,
+ NODE_VALUES,
+ NODE_HASH,
+ NODE_RETURN,
+ NODE_YIELD,
+ NODE_LVAR,
+ NODE_DVAR,
+ NODE_GVAR,
+ NODE_IVAR,
+ NODE_CONST,
+ NODE_CVAR,
+ NODE_NTH_REF,
+ NODE_BACK_REF,
+ NODE_MATCH,
+ NODE_MATCH2,
+ NODE_MATCH3,
+ NODE_LIT,
+ NODE_STR,
+ NODE_DSTR,
+ NODE_XSTR,
+ NODE_DXSTR,
+ NODE_EVSTR,
+ NODE_DREGX,
+ NODE_ONCE,
+ NODE_ARGS,
+ NODE_ARGS_AUX,
+ NODE_OPT_ARG,
+ NODE_KW_ARG,
+ NODE_POSTARG,
+ NODE_ARGSCAT,
+ NODE_ARGSPUSH,
+ NODE_SPLAT,
+ NODE_BLOCK_PASS,
+ NODE_DEFN,
+ NODE_DEFS,
+ NODE_ALIAS,
+ NODE_VALIAS,
+ NODE_UNDEF,
+ NODE_CLASS,
+ NODE_MODULE,
+ NODE_SCLASS,
+ NODE_COLON2,
+ NODE_COLON3,
+ NODE_DOT2,
+ NODE_DOT3,
+ NODE_FLIP2,
+ NODE_FLIP3,
+ NODE_SELF,
+ NODE_NIL,
+ NODE_TRUE,
+ NODE_FALSE,
+ NODE_ERRINFO,
+ NODE_DEFINED,
+ NODE_POSTEXE,
+ NODE_DSYM,
+ NODE_ATTRASGN,
+ NODE_LAMBDA,
+ NODE_ARYPTN,
+ NODE_HSHPTN,
+ NODE_FNDPTN,
+ NODE_ERROR,
+ NODE_LAST
};
+typedef struct rb_code_position_struct {
+ int lineno;
+ int column;
+} rb_code_position_t;
+
+typedef struct rb_code_location_struct {
+ rb_code_position_t beg_pos;
+ rb_code_position_t end_pos;
+} rb_code_location_t;
+
+static inline rb_code_location_t
+code_loc_gen(const rb_code_location_t *loc1, const rb_code_location_t *loc2)
+{
+ rb_code_location_t loc;
+ loc.beg_pos = loc1->beg_pos;
+ loc.end_pos = loc2->end_pos;
+ return loc;
+}
+
+typedef struct rb_ast_id_table {
+ int size;
+ ID ids[FLEX_ARY_LEN];
+} rb_ast_id_table_t;
+
+typedef struct RNode {
+ VALUE flags;
+ union {
+ struct RNode *node;
+ ID id;
+ VALUE value;
+ rb_ast_id_table_t *tbl;
+ } u1;
+ union {
+ struct RNode *node;
+ ID id;
+ long argc;
+ VALUE value;
+ } u2;
+ union {
+ struct RNode *node;
+ ID id;
+ long state;
+ struct rb_args_info *args;
+ struct rb_ary_pattern_info *apinfo;
+ struct rb_fnd_pattern_info *fpinfo;
+ VALUE value;
+ } u3;
+ rb_code_location_t nd_loc;
+ int node_id;
+} NODE;
+
+#define RNODE(obj) ((struct RNode *)(obj))
+
+/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8: UNUSED, 9: UNUSED, 10: EXIVAR, 11: FREEZE */
+/* NODE_FL: 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: NODE_FL_NEWLINE,
+ * 8..14: nd_type,
+ * 15..: nd_line
+ */
+#define NODE_FL_NEWLINE (((VALUE)1)<<7)
+
+#define NODE_TYPESHIFT 8
+#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT)
+
+#define nd_type(n) ((int) (((n)->flags & NODE_TYPEMASK)>>NODE_TYPESHIFT))
+#define nd_set_type(n,t) \
+ rb_node_set_type(n, t)
+#define nd_init_type(n,t) \
+ (n)->flags=(((n)->flags&~NODE_TYPEMASK)|((((unsigned long)(t))<<NODE_TYPESHIFT)&NODE_TYPEMASK))
+
+#define NODE_LSHIFT (NODE_TYPESHIFT+7)
+#define NODE_LMASK (((SIGNED_VALUE)1<<(sizeof(VALUE)*CHAR_BIT-NODE_LSHIFT))-1)
+#define nd_line(n) (int)(((SIGNED_VALUE)(n)->flags)>>NODE_LSHIFT)
+#define nd_set_line(n,l) \
+ (n)->flags=(((n)->flags&~((VALUE)(-1)<<NODE_LSHIFT))|((VALUE)((l)&NODE_LMASK)<<NODE_LSHIFT))
+
+#define nd_first_column(n) ((int)((n)->nd_loc.beg_pos.column))
+#define nd_set_first_column(n, v) ((n)->nd_loc.beg_pos.column = (v))
+#define nd_first_lineno(n) ((int)((n)->nd_loc.beg_pos.lineno))
+#define nd_set_first_lineno(n, v) ((n)->nd_loc.beg_pos.lineno = (v))
+#define nd_first_loc(n) ((n)->nd_loc.beg_pos)
+#define nd_set_first_loc(n, v) (nd_first_loc(n) = (v))
+
+#define nd_last_column(n) ((int)((n)->nd_loc.end_pos.column))
+#define nd_set_last_column(n, v) ((n)->nd_loc.end_pos.column = (v))
+#define nd_last_lineno(n) ((int)((n)->nd_loc.end_pos.lineno))
+#define nd_set_last_lineno(n, v) ((n)->nd_loc.end_pos.lineno = (v))
+#define nd_last_loc(n) ((n)->nd_loc.end_pos)
+#define nd_set_last_loc(n, v) (nd_last_loc(n) = (v))
+#define nd_node_id(n) ((n)->node_id)
+#define nd_set_node_id(n,id) ((n)->node_id = (id))
+
+#define nd_head u1.node
+#define nd_alen u2.argc
+#define nd_next u3.node
+
+#define nd_cond u1.node
+#define nd_body u2.node
+#define nd_else u3.node
+
+#define nd_resq u2.node
+#define nd_ensr u3.node
+
+#define nd_1st u1.node
+#define nd_2nd u2.node
+
+#define nd_stts u1.node
+
+#define nd_entry u3.id
+#define nd_vid u1.id
+
+#define nd_var u1.node
+#define nd_iter u3.node
+
+#define nd_value u2.node
+#define nd_aid u3.id
+
+#define nd_lit u1.value
+
+#define nd_recv u1.node
+#define nd_mid u2.id
+#define nd_args u3.node
+#define nd_ainfo u3.args
+
+#define nd_defn u3.node
+
+#define nd_cpath u1.node
+#define nd_super u3.node
+
+#define nd_beg u1.node
+#define nd_end u2.node
+#define nd_state u3.state
+
+#define nd_nth u2.argc
+
+#define nd_alias u1.id
+#define nd_orig u2.id
+#define nd_undef u2.node
+
+#define nd_brace u2.argc
+
+#define nd_pconst u1.node
+#define nd_pkwargs u2.node
+#define nd_pkwrestarg u3.node
+
+#define nd_apinfo u3.apinfo
+
+#define nd_fpinfo u3.fpinfo
+
+// for NODE_SCOPE
+#define nd_tbl u1.tbl
+
+// for NODE_ARGS_AUX
+#define nd_pid u1.id
+#define nd_plen u2.argc
+#define nd_cflag u2.id
+
+// for ripper
+#define nd_cval u3.value
+#define nd_rval u2.value
+#define nd_tag u1.id
+
+#define NEW_NODE(t,a0,a1,a2,loc) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2),loc)
+#define NEW_NODE_WITH_LOCALS(t,a1,a2,loc) node_newnode_with_locals(p, (t),(VALUE)(a1),(VALUE)(a2),loc)
+
+#define NEW_DEFN(i,a,d,loc) NEW_NODE(NODE_DEFN,0,i,NEW_SCOPE(a,d,loc),loc)
+#define NEW_DEFS(r,i,a,d,loc) NEW_NODE(NODE_DEFS,r,i,NEW_SCOPE(a,d,loc),loc)
+#define NEW_SCOPE(a,b,loc) NEW_NODE_WITH_LOCALS(NODE_SCOPE,b,a,loc)
+#define NEW_BLOCK(a,loc) NEW_NODE(NODE_BLOCK,a,0,0,loc)
+#define NEW_IF(c,t,e,loc) NEW_NODE(NODE_IF,c,t,e,loc)
+#define NEW_UNLESS(c,t,e,loc) NEW_NODE(NODE_UNLESS,c,t,e,loc)
+#define NEW_CASE(h,b,loc) NEW_NODE(NODE_CASE,h,b,0,loc)
+#define NEW_CASE2(b,loc) NEW_NODE(NODE_CASE2,0,b,0,loc)
+#define NEW_CASE3(h,b,loc) NEW_NODE(NODE_CASE3,h,b,0,loc)
+#define NEW_WHEN(c,t,e,loc) NEW_NODE(NODE_WHEN,c,t,e,loc)
+#define NEW_IN(c,t,e,loc) NEW_NODE(NODE_IN,c,t,e,loc)
+#define NEW_WHILE(c,b,n,loc) NEW_NODE(NODE_WHILE,c,b,n,loc)
+#define NEW_UNTIL(c,b,n,loc) NEW_NODE(NODE_UNTIL,c,b,n,loc)
+#define NEW_FOR(i,b,loc) NEW_NODE(NODE_FOR,0,b,i,loc)
+#define NEW_FOR_MASGN(v,loc) NEW_NODE(NODE_FOR_MASGN,v,0,0,loc)
+#define NEW_ITER(a,b,loc) NEW_NODE(NODE_ITER,0,NEW_SCOPE(a,b,loc),0,loc)
+#define NEW_LAMBDA(a,b,loc) NEW_NODE(NODE_LAMBDA,0,NEW_SCOPE(a,b,loc),0,loc)
+#define NEW_BREAK(s,loc) NEW_NODE(NODE_BREAK,s,0,0,loc)
+#define NEW_NEXT(s,loc) NEW_NODE(NODE_NEXT,s,0,0,loc)
+#define NEW_REDO(loc) NEW_NODE(NODE_REDO,0,0,0,loc)
+#define NEW_RETRY(loc) NEW_NODE(NODE_RETRY,0,0,0,loc)
+#define NEW_BEGIN(b,loc) NEW_NODE(NODE_BEGIN,0,b,0,loc)
+#define NEW_RESCUE(b,res,e,loc) NEW_NODE(NODE_RESCUE,b,res,e,loc)
+#define NEW_RESBODY(a,ex,n,loc) NEW_NODE(NODE_RESBODY,n,ex,a,loc)
+#define NEW_ENSURE(b,en,loc) NEW_NODE(NODE_ENSURE,b,0,en,loc)
+#define NEW_RETURN(s,loc) NEW_NODE(NODE_RETURN,s,0,0,loc)
+#define NEW_YIELD(a,loc) NEW_NODE(NODE_YIELD,a,0,0,loc)
+#define NEW_LIST(a,loc) NEW_NODE(NODE_LIST,a,1,0,loc)
+#define NEW_ZLIST(loc) NEW_NODE(NODE_ZLIST,0,0,0,loc)
+#define NEW_HASH(a,loc) NEW_NODE(NODE_HASH,a,0,0,loc)
+#define NEW_MASGN(l,r,loc) NEW_NODE(NODE_MASGN,l,0,r,loc)
+#define NEW_GASGN(v,val,loc) NEW_NODE(NODE_GASGN,v,val,v,loc)
+#define NEW_LASGN(v,val,loc) NEW_NODE(NODE_LASGN,v,val,0,loc)
+#define NEW_DASGN(v,val,loc) NEW_NODE(NODE_DASGN,v,val,0,loc)
+#define NEW_IASGN(v,val,loc) NEW_NODE(NODE_IASGN,v,val,0,loc)
+#define NEW_CDECL(v,val,path,loc) NEW_NODE(NODE_CDECL,v,val,path,loc)
+#define NEW_CVASGN(v,val,loc) NEW_NODE(NODE_CVASGN,v,val,0,loc)
+#define NEW_OP_ASGN1(p,id,a,loc) NEW_NODE(NODE_OP_ASGN1,p,id,a,loc)
+#define NEW_OP_ASGN2(r,t,i,o,val,loc) NEW_NODE(NODE_OP_ASGN2,r,val,NEW_OP_ASGN22(i,o,t,loc),loc)
+#define NEW_OP_ASGN22(i,o,t,loc) NEW_NODE(NODE_OP_ASGN2,i,o,t,loc)
+#define NEW_OP_ASGN_OR(i,val,loc) NEW_NODE(NODE_OP_ASGN_OR,i,val,0,loc)
+#define NEW_OP_ASGN_AND(i,val,loc) NEW_NODE(NODE_OP_ASGN_AND,i,val,0,loc)
+#define NEW_OP_CDECL(v,op,val,loc) NEW_NODE(NODE_OP_CDECL,v,val,op,loc)
+#define NEW_GVAR(v,loc) NEW_NODE(NODE_GVAR,v,0,v,loc)
+#define NEW_LVAR(v,loc) NEW_NODE(NODE_LVAR,v,0,0,loc)
+#define NEW_DVAR(v,loc) NEW_NODE(NODE_DVAR,v,0,0,loc)
+#define NEW_IVAR(v,loc) NEW_NODE(NODE_IVAR,v,0,0,loc)
+#define NEW_CONST(v,loc) NEW_NODE(NODE_CONST,v,0,0,loc)
+#define NEW_CVAR(v,loc) NEW_NODE(NODE_CVAR,v,0,0,loc)
+#define NEW_NTH_REF(n,loc) NEW_NODE(NODE_NTH_REF,0,n,0,loc)
+#define NEW_BACK_REF(n,loc) NEW_NODE(NODE_BACK_REF,0,n,0,loc)
+#define NEW_MATCH(c,loc) NEW_NODE(NODE_MATCH,c,0,0,loc)
+#define NEW_MATCH2(n1,n2,loc) NEW_NODE(NODE_MATCH2,n1,n2,0,loc)
+#define NEW_MATCH3(r,n2,loc) NEW_NODE(NODE_MATCH3,r,n2,0,loc)
+#define NEW_LIT(l,loc) NEW_NODE(NODE_LIT,l,0,0,loc)
+#define NEW_STR(s,loc) NEW_NODE(NODE_STR,s,0,0,loc)
+#define NEW_DSTR(s,loc) NEW_NODE(NODE_DSTR,s,1,0,loc)
+#define NEW_XSTR(s,loc) NEW_NODE(NODE_XSTR,s,0,0,loc)
+#define NEW_DXSTR(s,loc) NEW_NODE(NODE_DXSTR,s,0,0,loc)
+#define NEW_DSYM(s,loc) NEW_NODE(NODE_DSYM,s,0,0,loc)
+#define NEW_EVSTR(n,loc) NEW_NODE(NODE_EVSTR,0,(n),0,loc)
+#define NEW_CALL(r,m,a,loc) NEW_NODE(NODE_CALL,r,m,a,loc)
+#define NEW_OPCALL(r,m,a,loc) NEW_NODE(NODE_OPCALL,r,m,a,loc)
+#define NEW_FCALL(m,a,loc) NEW_NODE(NODE_FCALL,0,m,a,loc)
+#define NEW_VCALL(m,loc) NEW_NODE(NODE_VCALL,0,m,0,loc)
+#define NEW_SUPER(a,loc) NEW_NODE(NODE_SUPER,0,0,a,loc)
+#define NEW_ZSUPER(loc) NEW_NODE(NODE_ZSUPER,0,0,0,loc)
+#define NEW_ARGS_AUX(r,b,loc) NEW_NODE(NODE_ARGS_AUX,r,b,0,loc)
+#define NEW_OPT_ARG(i,v,loc) NEW_NODE(NODE_OPT_ARG,i,v,0,loc)
+#define NEW_KW_ARG(i,v,loc) NEW_NODE(NODE_KW_ARG,i,v,0,loc)
+#define NEW_POSTARG(i,v,loc) NEW_NODE(NODE_POSTARG,i,v,0,loc)
+#define NEW_ARGSCAT(a,b,loc) NEW_NODE(NODE_ARGSCAT,a,b,0,loc)
+#define NEW_ARGSPUSH(a,b,loc) NEW_NODE(NODE_ARGSPUSH,a,b,0,loc)
+#define NEW_SPLAT(a,loc) NEW_NODE(NODE_SPLAT,a,0,0,loc)
+#define NEW_BLOCK_PASS(b,loc) NEW_NODE(NODE_BLOCK_PASS,0,b,0,loc)
+#define NEW_ALIAS(n,o,loc) NEW_NODE(NODE_ALIAS,n,o,0,loc)
+#define NEW_VALIAS(n,o,loc) NEW_NODE(NODE_VALIAS,n,o,0,loc)
+#define NEW_UNDEF(i,loc) NEW_NODE(NODE_UNDEF,0,i,0,loc)
+#define NEW_CLASS(n,b,s,loc) NEW_NODE(NODE_CLASS,n,NEW_SCOPE(0,b,loc),(s),loc)
+#define NEW_SCLASS(r,b,loc) NEW_NODE(NODE_SCLASS,r,NEW_SCOPE(0,b,loc),0,loc)
+#define NEW_MODULE(n,b,loc) NEW_NODE(NODE_MODULE,n,NEW_SCOPE(0,b,loc),0,loc)
+#define NEW_COLON2(c,i,loc) NEW_NODE(NODE_COLON2,c,i,0,loc)
+#define NEW_COLON3(i,loc) NEW_NODE(NODE_COLON3,0,i,0,loc)
+#define NEW_DOT2(b,e,loc) NEW_NODE(NODE_DOT2,b,e,0,loc)
+#define NEW_DOT3(b,e,loc) NEW_NODE(NODE_DOT3,b,e,0,loc)
+#define NEW_SELF(loc) NEW_NODE(NODE_SELF,0,0,1,loc)
+#define NEW_NIL(loc) NEW_NODE(NODE_NIL,0,0,0,loc)
+#define NEW_TRUE(loc) NEW_NODE(NODE_TRUE,0,0,0,loc)
+#define NEW_FALSE(loc) NEW_NODE(NODE_FALSE,0,0,0,loc)
+#define NEW_ERRINFO(loc) NEW_NODE(NODE_ERRINFO,0,0,0,loc)
+#define NEW_DEFINED(e,loc) NEW_NODE(NODE_DEFINED,e,0,0,loc)
+#define NEW_POSTEXE(b,loc) NEW_NODE(NODE_POSTEXE,0,b,0,loc)
+#define NEW_ATTRASGN(r,m,a,loc) NEW_NODE(NODE_ATTRASGN,r,m,a,loc)
+#define NEW_ERROR(loc) NEW_NODE(NODE_ERROR,0,0,0,loc)
+
+#define NODE_SPECIAL_REQUIRED_KEYWORD ((NODE *)-1)
+#define NODE_REQUIRED_KEYWORD_P(node) ((node)->nd_value == NODE_SPECIAL_REQUIRED_KEYWORD)
+#define NODE_SPECIAL_NO_NAME_REST ((NODE *)-1)
+#define NODE_NAMED_REST_P(node) ((node) != NODE_SPECIAL_NO_NAME_REST)
+#define NODE_SPECIAL_EXCESSIVE_COMMA ((ID)1)
+#define NODE_SPECIAL_NO_REST_KEYWORD ((NODE *)-1)
+
+VALUE rb_node_case_when_optimizable_literal(const NODE *const node);
+
RUBY_SYMBOL_EXPORT_BEGIN
-#ifdef UNIVERSAL_PARSER
-rb_ast_t *rb_ast_new(rb_parser_config_t *config);
-#else
+typedef struct node_buffer_struct node_buffer_t;
+/* T_IMEMO/ast */
+typedef struct rb_ast_body_struct {
+ const NODE *root;
+ VALUE compile_option;
+ VALUE script_lines;
+ // script_lines is either:
+ // - a Fixnum that represents the line count of the original source, or
+ // - an Array that contains the lines of the original source
+} rb_ast_body_t;
+typedef struct rb_ast_struct {
+ VALUE flags;
+ node_buffer_t *node_buffer;
+ rb_ast_body_t body;
+} rb_ast_t;
rb_ast_t *rb_ast_new(void);
-#endif
-size_t rb_ast_memsize(const rb_ast_t*);
-void rb_ast_dispose(rb_ast_t*);
-VALUE rb_ast_tokens(rb_ast_t *ast);
-#if RUBY_DEBUG
-void rb_ast_node_type_change(NODE *n, enum node_type type);
-#endif
-const char *ruby_node_name(int node);
-void rb_node_init(NODE *n, enum node_type type);
-
void rb_ast_mark(rb_ast_t*);
void rb_ast_update_references(rb_ast_t*);
+void rb_ast_dispose(rb_ast_t*);
void rb_ast_free(rb_ast_t*);
+size_t rb_ast_memsize(const rb_ast_t*);
void rb_ast_add_mark_object(rb_ast_t*, VALUE);
-void rb_ast_delete_mark_object(rb_ast_t*, VALUE);
void rb_ast_set_tokens(rb_ast_t*, VALUE);
-NODE *rb_ast_newnode(rb_ast_t*, enum node_type type, size_t size, size_t alignment);
+VALUE rb_ast_tokens(rb_ast_t *ast);
+NODE *rb_ast_newnode(rb_ast_t*, enum node_type type);
void rb_ast_delete_node(rb_ast_t*, NODE *n);
rb_ast_id_table_t *rb_ast_new_local_table(rb_ast_t*, int);
rb_ast_id_table_t *rb_ast_resize_latest_local_table(rb_ast_t*, int);
+VALUE rb_parser_new(void);
+VALUE rb_parser_end_seen_p(VALUE);
+VALUE rb_parser_encoding(VALUE);
+VALUE rb_parser_set_yydebug(VALUE, VALUE);
VALUE rb_parser_dump_tree(const NODE *node, int comment);
+void rb_parser_set_options(VALUE, int, int, int, int);
+
+rb_ast_t *rb_parser_compile_string(VALUE, const char*, VALUE, int);
+rb_ast_t *rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line);
+rb_ast_t *rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE input, int line);
+rb_ast_t *rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int line);
+
+void rb_node_init(NODE *n, enum node_type type, VALUE a0, VALUE a1, VALUE a2);
+const char *ruby_node_name(int node);
const struct kwtable *rb_reserved_word(const char *, unsigned int);
+struct rb_args_info {
+ NODE *pre_init;
+ NODE *post_init;
+
+ int pre_args_num; /* count of mandatory pre-arguments */
+ int post_args_num; /* count of mandatory post-arguments */
+
+ ID first_post_arg;
+
+ ID rest_arg;
+ ID block_arg;
+
+ NODE *kw_args;
+ NODE *kw_rest_arg;
+
+ NODE *opt_args;
+ unsigned int no_kwarg: 1;
+ unsigned int ruby2_keywords: 1;
+ unsigned int forwarding: 1;
+
+ VALUE imemo;
+};
+
+struct rb_ary_pattern_info {
+ NODE *pre_args;
+ NODE *rest_arg;
+ NODE *post_args;
+};
+
+struct rb_fnd_pattern_info {
+ NODE *pre_rest_arg;
+ NODE *args;
+ NODE *post_rest_arg;
+};
+
struct parser_params;
void *rb_parser_malloc(struct parser_params *, size_t);
void *rb_parser_realloc(struct parser_params *, void *, size_t);
void *rb_parser_calloc(struct parser_params *, size_t, size_t);
void rb_parser_free(struct parser_params *, void *);
PRINTF_ARGS(void rb_parser_printf(struct parser_params *parser, const char *fmt, ...), 2, 3);
-VALUE rb_node_set_type(NODE *n, enum node_type t);
+void rb_ast_node_type_change(NODE *n, enum node_type type);
RUBY_SYMBOL_EXPORT_END
-#define NODE_LSHIFT (NODE_TYPESHIFT+7)
-#define NODE_LMASK (((SIGNED_VALUE)1<<(sizeof(VALUE)*CHAR_BIT-NODE_LSHIFT))-1)
-
-#define nd_line(n) (int)(((SIGNED_VALUE)(n)->flags)>>NODE_LSHIFT)
-#define nd_set_line(n,l) \
- (n)->flags=(((n)->flags&~((VALUE)(-1)<<NODE_LSHIFT))|((VALUE)((l)&NODE_LMASK)<<NODE_LSHIFT))
-
-
-#define NODE_SPECIAL_REQUIRED_KEYWORD ((NODE *)-1)
-#define NODE_REQUIRED_KEYWORD_P(node) ((node) == NODE_SPECIAL_REQUIRED_KEYWORD)
-#define NODE_SPECIAL_NO_NAME_REST ((NODE *)-1)
-#define NODE_NAMED_REST_P(node) ((node) != NODE_SPECIAL_NO_NAME_REST)
-#define NODE_SPECIAL_EXCESSIVE_COMMA ((ID)1)
-#define NODE_SPECIAL_NO_REST_KEYWORD ((NODE *)-1)
-
-#define nd_first_column(n) ((int)(RNODE(n)->nd_loc.beg_pos.column))
-#define nd_set_first_column(n, v) (RNODE(n)->nd_loc.beg_pos.column = (v))
-#define nd_first_lineno(n) ((int)(RNODE(n)->nd_loc.beg_pos.lineno))
-#define nd_set_first_lineno(n, v) (RNODE(n)->nd_loc.beg_pos.lineno = (v))
-#define nd_first_loc(n) (RNODE(n)->nd_loc.beg_pos)
-#define nd_set_first_loc(n, v) (nd_first_loc(n) = (v))
-
-#define nd_last_column(n) ((int)(RNODE(n)->nd_loc.end_pos.column))
-#define nd_set_last_column(n, v) (RNODE(n)->nd_loc.end_pos.column = (v))
-#define nd_last_lineno(n) ((int)(RNODE(n)->nd_loc.end_pos.lineno))
-#define nd_set_last_lineno(n, v) (RNODE(n)->nd_loc.end_pos.lineno = (v))
-#define nd_last_loc(n) (RNODE(n)->nd_loc.end_pos)
-#define nd_set_last_loc(n, v) (nd_last_loc(n) = (v))
-#define nd_node_id(n) (RNODE(n)->node_id)
-#define nd_set_node_id(n,id) (RNODE(n)->node_id = (id))
+static inline VALUE
+rb_node_set_type(NODE *n, enum node_type t)
+{
+#if RUBY_DEBUG
+ rb_ast_node_type_change(n, t);
+#endif
+ return nd_init_type(n, t);
+}
static inline bool
nd_type_p(const NODE *n, enum node_type t)
{
return (enum node_type)nd_type(n) == t;
}
+#if defined(__cplusplus)
+#if 0
+{ /* satisfy cc-mode */
+#endif
+} /* extern "C" { */
+#endif
#endif /* RUBY_NODE_H */
diff --git a/node_dump.c b/node_dump.c
deleted file mode 100644
index 391aea10b1..0000000000
--- a/node_dump.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/**********************************************************************
-
- node_dump.c - dump ruby node tree
-
- $Author: mame $
- created at: 09/12/06 21:23:44 JST
-
- Copyright (C) 2009 Yusuke Endoh
-
-**********************************************************************/
-
-#include "internal.h"
-#include "internal/hash.h"
-#include "internal/variable.h"
-#include "ruby/ruby.h"
-#include "vm_core.h"
-
-#define A(str) rb_str_cat2(buf, (str))
-#define AR(str) rb_str_concat(buf, (str))
-
-#define A_INDENT add_indent(buf, indent)
-#define D_INDENT rb_str_cat2(indent, next_indent)
-#define D_DEDENT rb_str_resize(indent, RSTRING_LEN(indent) - 4)
-#define A_ID(id) add_id(buf, (id))
-#define A_INT(val) rb_str_catf(buf, "%d", (val))
-#define A_LONG(val) rb_str_catf(buf, "%ld", (val))
-#define A_LIT(lit) AR(rb_dump_literal(lit))
-#define A_NODE_HEADER(node, term) \
- rb_str_catf(buf, "@ %s (id: %d, line: %d, location: (%d,%d)-(%d,%d))%s"term, \
- ruby_node_name(nd_type(node)), nd_node_id(node), nd_line(node), \
- nd_first_lineno(node), nd_first_column(node), \
- nd_last_lineno(node), nd_last_column(node), \
- (nd_fl_newline(node) ? "*" : ""))
-#define A_FIELD_HEADER(len, name, term) \
- rb_str_catf(buf, "+- %.*s:"term, (len), (name))
-#define D_FIELD_HEADER(len, name, term) (A_INDENT, A_FIELD_HEADER(len, name, term))
-
-#define D_NULL_NODE (A_INDENT, A("(null node)\n"))
-#define D_NODE_HEADER(node) (A_INDENT, A_NODE_HEADER(node, "\n"))
-
-#define COMPOUND_FIELD(len, name) \
- FIELD_BLOCK((D_FIELD_HEADER((len), (name), "\n"), D_INDENT), D_DEDENT)
-
-#define COMPOUND_FIELD1(name, ann) \
- COMPOUND_FIELD(FIELD_NAME_LEN(name, ann), \
- FIELD_NAME_DESC(name, ann))
-
-#define FIELD_NAME_DESC(name, ann) name " (" ann ")"
-#define FIELD_NAME_LEN(name, ann) (int)( \
- comment ? \
- rb_strlen_lit(FIELD_NAME_DESC(name, ann)) : \
- rb_strlen_lit(name))
-#define SIMPLE_FIELD(len, name) \
- FIELD_BLOCK(D_FIELD_HEADER((len), (name), " "), A("\n"))
-
-#define FIELD_BLOCK(init, reset) \
- for (init, field_flag = 1; \
- field_flag; /* should be optimized away */ \
- reset, field_flag = 0)
-
-#define SIMPLE_FIELD1(name, ann) SIMPLE_FIELD(FIELD_NAME_LEN(name, ann), FIELD_NAME_DESC(name, ann))
-#define F_CUSTOM1(name, ann) SIMPLE_FIELD1(#name, ann)
-#define F_ID(name, type, ann) SIMPLE_FIELD1(#name, ann) A_ID(type(node)->name)
-#define F_INT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_INT(type(node)->name)
-#define F_LONG(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LONG(type(node)->name)
-#define F_LIT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LIT(type(node)->name)
-#define F_MSG(name, ann, desc) SIMPLE_FIELD1(#name, ann) A(desc)
-
-#define F_NODE(name, type, ann) \
- COMPOUND_FIELD1(#name, ann) {dump_node(buf, indent, comment, RNODE(type(node)->name));}
-
-#define F_NODE2(name, n, ann) \
- COMPOUND_FIELD1(#name, ann) {dump_node(buf, indent, comment, n);}
-
-#define ANN(ann) \
- if (comment) { \
- A_INDENT; A("| # " ann "\n"); \
- }
-
-#define LAST_NODE (next_indent = " ")
-
-VALUE
-rb_dump_literal(VALUE lit)
-{
- if (!RB_SPECIAL_CONST_P(lit)) {
- VALUE str;
- switch (RB_BUILTIN_TYPE(lit)) {
- case T_CLASS: case T_MODULE: case T_ICLASS:
- str = rb_class_path(lit);
- if (FL_TEST(lit, FL_SINGLETON)) {
- str = rb_sprintf("<%"PRIsVALUE">", str);
- }
- return str;
- default:
- break;
- }
- }
- return rb_inspect(lit);
-}
-
-static void
-add_indent(VALUE buf, VALUE indent)
-{
- AR(indent);
-}
-
-static void
-add_id(VALUE buf, ID id)
-{
- if (id == 0) {
- A("(null)");
- }
- else {
- VALUE str = rb_id2str(id);
- if (str) {
- A(":"); AR(str);
- }
- else {
- rb_str_catf(buf, "(internal variable: 0x%"PRIsVALUE")", id);
- }
- }
-}
-
-struct add_option_arg {
- VALUE buf, indent;
- st_index_t count;
-};
-
-static void dump_node(VALUE, VALUE, int, const NODE *);
-static const char default_indent[] = "| ";
-
-static void
-dump_array(VALUE buf, VALUE indent, int comment, const NODE *node)
-{
- int field_flag;
- const char *next_indent = default_indent;
- F_LONG(as.nd_alen, RNODE_LIST, "length");
- F_NODE(nd_head, RNODE_LIST, "element");
- while (RNODE_LIST(node)->nd_next && nd_type_p(RNODE_LIST(node)->nd_next, NODE_LIST)) {
- node = RNODE_LIST(node)->nd_next;
- F_NODE(nd_head, RNODE_LIST, "element");
- }
- LAST_NODE;
- F_NODE(nd_next, RNODE_LIST, "next element");
-}
-
-static void
-dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
-{
- int field_flag;
- int i;
- const char *next_indent = default_indent;
- enum node_type type;
-
- if (!node) {
- D_NULL_NODE;
- return;
- }
-
- D_NODE_HEADER(node);
-
- type = nd_type(node);
- switch (type) {
- case NODE_BLOCK:
- ANN("statement sequence");
- ANN("format: [nd_head]; ...; [nd_next]");
- ANN("example: foo; bar");
- i = 0;
- do {
- A_INDENT;
- rb_str_catf(buf, "+- nd_head (%s%d):\n",
- comment ? "statement #" : "", ++i);
- if (!RNODE_BLOCK(node)->nd_next) LAST_NODE;
- D_INDENT;
- dump_node(buf, indent, comment, RNODE_BLOCK(node)->nd_head);
- D_DEDENT;
- } while (RNODE_BLOCK(node)->nd_next &&
- nd_type_p(RNODE_BLOCK(node)->nd_next, NODE_BLOCK) &&
- (node = RNODE_BLOCK(node)->nd_next, 1));
- if (RNODE_BLOCK(node)->nd_next) {
- LAST_NODE;
- F_NODE(nd_next, RNODE_BLOCK, "next block");
- }
- return;
-
- case NODE_IF:
- ANN("if statement");
- ANN("format: if [nd_cond] then [nd_body] else [nd_else] end");
- ANN("example: if x == 1 then foo else bar end");
- F_NODE(nd_cond, RNODE_IF, "condition expr");
- F_NODE(nd_body, RNODE_IF, "then clause");
- LAST_NODE;
- F_NODE(nd_else, RNODE_IF, "else clause");
- return;
-
- case NODE_UNLESS:
- ANN("unless statement");
- ANN("format: unless [nd_cond] then [nd_body] else [nd_else] end");
- ANN("example: unless x == 1 then foo else bar end");
- F_NODE(nd_cond, RNODE_UNLESS, "condition expr");
- F_NODE(nd_body, RNODE_UNLESS, "then clause");
- LAST_NODE;
- F_NODE(nd_else, RNODE_UNLESS, "else clause");
- return;
-
- case NODE_CASE:
- ANN("case statement");
- ANN("format: case [nd_head]; [nd_body]; end");
- ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_CASE, "case expr");
- LAST_NODE;
- F_NODE(nd_body, RNODE_CASE, "when clauses");
- return;
- case NODE_CASE2:
- ANN("case statement with no head");
- ANN("format: case; [nd_body]; end");
- ANN("example: case; when 1; foo; when 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_CASE2, "case expr");
- LAST_NODE;
- F_NODE(nd_body, RNODE_CASE2, "when clauses");
- return;
- case NODE_CASE3:
- ANN("case statement (pattern matching)");
- ANN("format: case [nd_head]; [nd_body]; end");
- ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_CASE3, "case expr");
- LAST_NODE;
- F_NODE(nd_body, RNODE_CASE3, "in clauses");
- return;
-
- case NODE_WHEN:
- ANN("when clause");
- ANN("format: when [nd_head]; [nd_body]; (when or else) [nd_next]");
- ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_WHEN, "when value");
- F_NODE(nd_body, RNODE_WHEN, "when body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_WHEN, "next when clause");
- return;
-
- case NODE_IN:
- ANN("in clause");
- ANN("format: in [nd_head]; [nd_body]; (in or else) [nd_next]");
- ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_IN, "in pattern");
- F_NODE(nd_body, RNODE_IN, "in body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_IN, "next in clause");
- return;
-
- case NODE_WHILE:
- ANN("while statement");
- ANN("format: while [nd_cond]; [nd_body]; end");
- ANN("example: while x == 1; foo; end");
- goto loop;
- case NODE_UNTIL:
- ANN("until statement");
- ANN("format: until [nd_cond]; [nd_body]; end");
- ANN("example: until x == 1; foo; end");
- loop:
- F_CUSTOM1(nd_state, "begin-end-while?") {
- A_INT((int)RNODE_WHILE(node)->nd_state);
- A((RNODE_WHILE(node)->nd_state == 1) ? " (while-end)" : " (begin-end-while)");
- }
- F_NODE(nd_cond, RNODE_WHILE, "condition");
- LAST_NODE;
- F_NODE(nd_body, RNODE_WHILE, "body");
- return;
-
- case NODE_ITER:
- ANN("method call with block");
- ANN("format: [nd_iter] { [nd_body] }");
- ANN("example: 3.times { foo }");
- goto iter;
- case NODE_FOR:
- ANN("for statement");
- ANN("format: for * in [nd_iter] do [nd_body] end");
- ANN("example: for i in 1..3 do foo end");
- iter:
- F_NODE(nd_iter, RNODE_ITER, "iteration receiver");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ITER, "body");
- return;
-
- case NODE_FOR_MASGN:
- ANN("vars of for statement with masgn");
- ANN("format: for [nd_var] in ... do ... end");
- ANN("example: for x, y in 1..3 do foo end");
- LAST_NODE;
- F_NODE(nd_var, RNODE_FOR_MASGN, "var");
- return;
-
- case NODE_BREAK:
- ANN("break statement");
- ANN("format: break [nd_stts]");
- ANN("example: break 1");
- LAST_NODE;
- F_NODE(nd_stts, RNODE_BREAK, "value");
- return;
- case NODE_NEXT:
- ANN("next statement");
- ANN("format: next [nd_stts]");
- ANN("example: next 1");
- LAST_NODE;
- F_NODE(nd_stts, RNODE_NEXT, "value");
- return;
- case NODE_RETURN:
- ANN("return statement");
- ANN("format: return [nd_stts]");
- ANN("example: return 1");
- LAST_NODE;
- F_NODE(nd_stts, RNODE_RETURN, "value");
- return;
-
- case NODE_REDO:
- ANN("redo statement");
- ANN("format: redo");
- ANN("example: redo");
- return;
-
- case NODE_RETRY:
- ANN("retry statement");
- ANN("format: retry");
- ANN("example: retry");
- return;
-
- case NODE_BEGIN:
- ANN("begin statement");
- ANN("format: begin; [nd_body]; end");
- ANN("example: begin; 1; end");
- LAST_NODE;
- F_NODE(nd_body, RNODE_BEGIN, "body");
- return;
-
- case NODE_RESCUE:
- ANN("rescue clause");
- ANN("format: begin; [nd_body]; (rescue) [nd_resq]; else [nd_else]; end");
- ANN("example: begin; foo; rescue; bar; else; baz; end");
- F_NODE(nd_head, RNODE_RESCUE, "body");
- F_NODE(nd_resq, RNODE_RESCUE, "rescue clause list");
- LAST_NODE;
- F_NODE(nd_else, RNODE_RESCUE, "rescue else clause");
- return;
-
- case NODE_RESBODY:
- ANN("rescue clause (cont'd)");
- ANN("format: rescue [nd_args]; [nd_body]; (rescue) [nd_head]");
- ANN("example: begin; foo; rescue; bar; else; baz; end");
- F_NODE(nd_args, RNODE_RESBODY, "rescue exceptions");
- F_NODE(nd_body, RNODE_RESBODY, "rescue clause");
- LAST_NODE;
- F_NODE(nd_head, RNODE_RESBODY, "next rescue clause");
- return;
-
- case NODE_ENSURE:
- ANN("ensure clause");
- ANN("format: begin; [nd_head]; ensure; [nd_ensr]; end");
- ANN("example: begin; foo; ensure; bar; end");
- F_NODE(nd_head, RNODE_ENSURE, "body");
- LAST_NODE;
- F_NODE(nd_ensr, RNODE_ENSURE, "ensure clause");
- return;
-
- case NODE_AND:
- ANN("&& operator");
- ANN("format: [nd_1st] && [nd_2nd]");
- ANN("example: foo && bar");
- goto andor;
- case NODE_OR:
- ANN("|| operator");
- ANN("format: [nd_1st] || [nd_2nd]");
- ANN("example: foo || bar");
- andor:
- while (1) {
- F_NODE(nd_1st, RNODE_AND, "left expr");
- if (!RNODE_AND(node)->nd_2nd || !nd_type_p(RNODE_AND(node)->nd_2nd, type))
- break;
- node = RNODE_AND(node)->nd_2nd;
- }
- LAST_NODE;
- F_NODE(nd_2nd, RNODE_AND, "right expr");
- return;
-
- case NODE_MASGN:
- ANN("multiple assignment");
- ANN("format: [nd_head], [nd_args] = [nd_value]");
- ANN("example: a, b = foo");
- F_NODE(nd_value, RNODE_MASGN, "rhsn");
- F_NODE(nd_head, RNODE_MASGN, "lhsn");
- if (NODE_NAMED_REST_P(RNODE_MASGN(node)->nd_args)) {
- LAST_NODE;
- F_NODE(nd_args, RNODE_MASGN, "splatn");
- }
- else {
- F_MSG(nd_args, "splatn", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- return;
-
- case NODE_LASGN:
- ANN("local variable assignment");
- ANN("format: [nd_vid](lvar) = [nd_value]");
- ANN("example: x = foo");
- F_ID(nd_vid, RNODE_LASGN, "local variable");
- if (NODE_REQUIRED_KEYWORD_P(RNODE_LASGN(node)->nd_value)) {
- F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
- }
- else {
- LAST_NODE;
- F_NODE(nd_value, RNODE_LASGN, "rvalue");
- }
- return;
- case NODE_DASGN:
- ANN("dynamic variable assignment");
- ANN("format: [nd_vid](dvar) = [nd_value]");
- ANN("example: x = nil; 1.times { x = foo }");
- ANN("example: 1.times { x = foo }");
- F_ID(nd_vid, RNODE_DASGN, "local variable");
- if (NODE_REQUIRED_KEYWORD_P(RNODE_DASGN(node)->nd_value)) {
- F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
- }
- else {
- LAST_NODE;
- F_NODE(nd_value, RNODE_DASGN, "rvalue");
- }
- return;
- case NODE_IASGN:
- ANN("instance variable assignment");
- ANN("format: [nd_vid](ivar) = [nd_value]");
- ANN("example: @x = foo");
- F_ID(nd_vid, RNODE_IASGN, "instance variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_IASGN, "rvalue");
- return;
- case NODE_CVASGN:
- ANN("class variable assignment");
- ANN("format: [nd_vid](cvar) = [nd_value]");
- ANN("example: @@x = foo");
- F_ID(nd_vid, RNODE_CVASGN, "class variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_CVASGN, "rvalue");
- return;
- case NODE_GASGN:
- ANN("global variable assignment");
- ANN("format: [nd_vid](gvar) = [nd_value]");
- ANN("example: $x = foo");
- F_ID(nd_vid, RNODE_GASGN, "global variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_GASGN, "rvalue");
- return;
-
- case NODE_CDECL:
- ANN("constant declaration");
- ANN("format: [nd_else]::[nd_vid](constant) = [nd_value]");
- ANN("example: X = foo");
- if (RNODE_CDECL(node)->nd_vid) {
- F_ID(nd_vid, RNODE_CDECL, "constant");
- F_MSG(nd_else, "extension", "not used");
- }
- else {
- F_MSG(nd_vid, "constant", "0 (see extension field)");
- F_NODE(nd_else, RNODE_CDECL, "extension");
- }
- LAST_NODE;
- F_NODE(nd_value, RNODE_CDECL, "rvalue");
- return;
-
- case NODE_OP_ASGN1:
- ANN("array assignment with operator");
- ANN("format: [nd_recv] [ [nd_index] ] [nd_mid]= [nd_rvalue]");
- ANN("example: ary[1] += foo");
- F_NODE(nd_recv, RNODE_OP_ASGN1, "receiver");
- F_ID(nd_mid, RNODE_OP_ASGN1, "operator");
- F_NODE(nd_index, RNODE_OP_ASGN1, "index");
- LAST_NODE;
- F_NODE(nd_rvalue, RNODE_OP_ASGN1, "rvalue");
- return;
-
- case NODE_OP_ASGN2:
- ANN("attr assignment with operator");
- ANN("format: [nd_recv].[nd_vid] [nd_mid]= [nd_value]");
- ANN("example: struct.field += foo");
- F_NODE(nd_recv, RNODE_OP_ASGN2, "receiver");
- F_CUSTOM1(nd_vid, "attr") {
- if (RNODE_OP_ASGN2(node)->nd_aid) A("? ");
- A_ID(RNODE_OP_ASGN2(node)->nd_vid);
- }
- F_ID(nd_mid, RNODE_OP_ASGN2, "operator");
- LAST_NODE;
- F_NODE(nd_value, RNODE_OP_ASGN2, "rvalue");
- return;
-
- case NODE_OP_ASGN_AND:
- ANN("assignment with && operator");
- ANN("format: [nd_head] &&= [nd_value]");
- ANN("example: foo &&= bar");
- goto asgn_andor;
- case NODE_OP_ASGN_OR:
- ANN("assignment with || operator");
- ANN("format: [nd_head] ||= [nd_value]");
- ANN("example: foo ||= bar");
- asgn_andor:
- F_NODE(nd_head, RNODE_OP_ASGN_AND, "variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_OP_ASGN_AND, "rvalue");
- return;
-
- case NODE_OP_CDECL:
- ANN("constant declaration with operator");
- ANN("format: [nd_head](constant) [nd_aid]= [nd_value]");
- ANN("example: A::B ||= 1");
- F_NODE(nd_head, RNODE_OP_CDECL, "constant");
- F_ID(nd_aid, RNODE_OP_CDECL, "operator");
- LAST_NODE;
- F_NODE(nd_value, RNODE_OP_CDECL, "rvalue");
- return;
-
- case NODE_CALL:
- ANN("method invocation");
- ANN("format: [nd_recv].[nd_mid]([nd_args])");
- ANN("example: obj.foo(1)");
- F_ID(nd_mid, RNODE_CALL, "method id");
- F_NODE(nd_recv, RNODE_CALL, "receiver");
- LAST_NODE;
- F_NODE(nd_args, RNODE_CALL, "arguments");
- return;
-
- case NODE_OPCALL:
- ANN("method invocation");
- ANN("format: [nd_recv] [nd_mid] [nd_args]");
- ANN("example: foo + bar");
- F_ID(nd_mid, RNODE_OPCALL, "method id");
- F_NODE(nd_recv, RNODE_OPCALL, "receiver");
- LAST_NODE;
- F_NODE(nd_args, RNODE_OPCALL, "arguments");
- return;
-
- case NODE_FCALL:
- ANN("function call");
- ANN("format: [nd_mid]([nd_args])");
- ANN("example: foo(1)");
- F_ID(nd_mid, RNODE_FCALL, "method id");
- LAST_NODE;
- F_NODE(nd_args, RNODE_FCALL, "arguments");
- return;
-
- case NODE_VCALL:
- ANN("function call with no argument");
- ANN("format: [nd_mid]");
- ANN("example: foo");
- F_ID(nd_mid, RNODE_VCALL, "method id");
- return;
-
- case NODE_QCALL:
- ANN("safe method invocation");
- ANN("format: [nd_recv]&.[nd_mid]([nd_args])");
- ANN("example: obj&.foo(1)");
- F_ID(nd_mid, RNODE_QCALL, "method id");
- F_NODE(nd_recv, RNODE_QCALL, "receiver");
- LAST_NODE;
- F_NODE(nd_args, RNODE_QCALL, "arguments");
- return;
-
- case NODE_SUPER:
- ANN("super invocation");
- ANN("format: super [nd_args]");
- ANN("example: super 1");
- LAST_NODE;
- F_NODE(nd_args, RNODE_SUPER, "arguments");
- return;
-
- case NODE_ZSUPER:
- ANN("super invocation with no argument");
- ANN("format: super");
- ANN("example: super");
- return;
-
- case NODE_LIST:
- ANN("list constructor");
- ANN("format: [ [nd_head], [nd_next].. ] (length: [nd_alen])");
- ANN("example: [1, 2, 3]");
- dump_array(buf, indent, comment, node);
- return;
-
- case NODE_ZLIST:
- ANN("empty list constructor");
- ANN("format: []");
- ANN("example: []");
- return;
-
- case NODE_HASH:
- if (!RNODE_HASH(node)->nd_brace) {
- ANN("keyword arguments");
- ANN("format: [nd_head]");
- ANN("example: a: 1, b: 2");
- }
- else {
- ANN("hash constructor");
- ANN("format: { [nd_head] }");
- ANN("example: { 1 => 2, 3 => 4 }");
- }
- F_CUSTOM1(nd_brace, "keyword arguments or hash literal") {
- switch (RNODE_HASH(node)->nd_brace) {
- case 0: A("0 (keyword argument)"); break;
- case 1: A("1 (hash literal)"); break;
- }
- }
- LAST_NODE;
- F_NODE(nd_head, RNODE_HASH, "contents");
- return;
-
- case NODE_YIELD:
- ANN("yield invocation");
- ANN("format: yield [nd_head]");
- ANN("example: yield 1");
- LAST_NODE;
- F_NODE(nd_head, RNODE_YIELD, "arguments");
- return;
-
- case NODE_LVAR:
- ANN("local variable reference");
- ANN("format: [nd_vid](lvar)");
- ANN("example: x");
- F_ID(nd_vid, RNODE_LVAR, "local variable");
- return;
- case NODE_DVAR:
- ANN("dynamic variable reference");
- ANN("format: [nd_vid](dvar)");
- ANN("example: 1.times { x = 1; x }");
- F_ID(nd_vid, RNODE_DVAR, "local variable");
- return;
- case NODE_IVAR:
- ANN("instance variable reference");
- ANN("format: [nd_vid](ivar)");
- ANN("example: @x");
- F_ID(nd_vid, RNODE_IVAR, "instance variable");
- return;
- case NODE_CONST:
- ANN("constant reference");
- ANN("format: [nd_vid](constant)");
- ANN("example: X");
- F_ID(nd_vid, RNODE_CONST, "constant");
- return;
- case NODE_CVAR:
- ANN("class variable reference");
- ANN("format: [nd_vid](cvar)");
- ANN("example: @@x");
- F_ID(nd_vid, RNODE_CVAR, "class variable");
- return;
-
- case NODE_GVAR:
- ANN("global variable reference");
- ANN("format: [nd_vid](gvar)");
- ANN("example: $x");
- F_ID(nd_vid, RNODE_GVAR, "global variable");
- return;
-
- case NODE_NTH_REF:
- ANN("nth special variable reference");
- ANN("format: $[nd_nth]");
- ANN("example: $1, $2, ..");
- F_CUSTOM1(nd_nth, "variable") { A("$"); A_LONG(RNODE_NTH_REF(node)->nd_nth); }
- return;
-
- case NODE_BACK_REF:
- ANN("back special variable reference");
- ANN("format: $[nd_nth]");
- ANN("example: $&, $`, $', $+");
- F_CUSTOM1(nd_nth, "variable") {
- char name[3] = "$ ";
- name[1] = (char)RNODE_BACK_REF(node)->nd_nth;
- A(name);
- }
- return;
-
- case NODE_MATCH:
- ANN("match expression (against $_ implicitly)");
- ANN("format: [nd_lit] (in condition)");
- ANN("example: if /foo/; foo; end");
- F_LIT(nd_lit, RNODE_MATCH, "regexp");
- return;
-
- case NODE_MATCH2:
- ANN("match expression (regexp first)");
- ANN("format: [nd_recv] =~ [nd_value]");
- ANN("example: /foo/ =~ 'foo'");
- F_NODE(nd_recv, RNODE_MATCH2, "regexp (receiver)");
- if (!RNODE_MATCH2(node)->nd_args) LAST_NODE;
- F_NODE(nd_value, RNODE_MATCH2, "string (argument)");
- if (RNODE_MATCH2(node)->nd_args) {
- LAST_NODE;
- F_NODE(nd_args, RNODE_MATCH2, "named captures");
- }
- return;
-
- case NODE_MATCH3:
- ANN("match expression (regexp second)");
- ANN("format: [nd_recv] =~ [nd_value]");
- ANN("example: 'foo' =~ /foo/");
- F_NODE(nd_recv, RNODE_MATCH3, "string (receiver)");
- LAST_NODE;
- F_NODE(nd_value, RNODE_MATCH3, "regexp (argument)");
- return;
-
- case NODE_LIT:
- ANN("literal");
- ANN("format: [nd_lit]");
- ANN("example: 1, /foo/");
- goto lit;
- case NODE_STR:
- ANN("string literal");
- ANN("format: [nd_lit]");
- ANN("example: 'foo'");
- goto lit;
- case NODE_XSTR:
- ANN("xstring literal");
- ANN("format: [nd_lit]");
- ANN("example: `foo`");
- lit:
- F_LIT(nd_lit, RNODE_LIT, "literal");
- return;
-
- case NODE_ONCE:
- ANN("once evaluation");
- ANN("format: [nd_body]");
- ANN("example: /foo#{ bar }baz/o");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ONCE, "body");
- return;
-
- case NODE_DSTR:
- ANN("string literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: \"foo#{ bar }baz\"");
- goto dlit;
- case NODE_DXSTR:
- ANN("xstring literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: `foo#{ bar }baz`");
- goto dlit;
- case NODE_DREGX:
- ANN("regexp literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: /foo#{ bar }baz/");
- goto dlit;
- case NODE_DSYM:
- ANN("symbol literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: :\"foo#{ bar }baz\"");
- dlit:
- F_LIT(nd_lit, RNODE_DSTR, "preceding string");
- if (!RNODE_DSTR(node)->nd_next) return;
- F_NODE(nd_next->nd_head, RNODE_DSTR, "interpolation");
- LAST_NODE;
- F_NODE(nd_next->nd_next, RNODE_DSTR, "tailing strings");
- return;
-
- case NODE_EVSTR:
- ANN("interpolation expression");
- ANN("format: \"..#{ [nd_body] }..\"");
- ANN("example: \"foo#{ bar }baz\"");
- LAST_NODE;
- F_NODE(nd_body, RNODE_EVSTR, "body");
- return;
-
- case NODE_ARGSCAT:
- ANN("splat argument following arguments");
- ANN("format: ..(*[nd_head], [nd_body..])");
- ANN("example: foo(*ary, post_arg1, post_arg2)");
- F_NODE(nd_head, RNODE_ARGSCAT, "preceding array");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ARGSCAT, "following array");
- return;
-
- case NODE_ARGSPUSH:
- ANN("splat argument following one argument");
- ANN("format: ..(*[nd_head], [nd_body])");
- ANN("example: foo(*ary, post_arg)");
- F_NODE(nd_head, RNODE_ARGSPUSH, "preceding array");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ARGSPUSH, "following element");
- return;
-
- case NODE_SPLAT:
- ANN("splat argument");
- ANN("format: *[nd_head]");
- ANN("example: foo(*ary)");
- LAST_NODE;
- F_NODE(nd_head, RNODE_SPLAT, "splat'ed array");
- return;
-
- case NODE_BLOCK_PASS:
- ANN("arguments with block argument");
- ANN("format: ..([nd_head], &[nd_body])");
- ANN("example: foo(x, &blk)");
- F_NODE(nd_head, RNODE_BLOCK_PASS, "other arguments");
- LAST_NODE;
- F_NODE(nd_body, RNODE_BLOCK_PASS, "block argument");
- return;
-
- case NODE_DEFN:
- ANN("method definition");
- ANN("format: def [nd_mid] [nd_defn]; end");
- ANN("example: def foo; bar; end");
- F_ID(nd_mid, RNODE_DEFN, "method name");
- LAST_NODE;
- F_NODE(nd_defn, RNODE_DEFN, "method definition");
- return;
-
- case NODE_DEFS:
- ANN("singleton method definition");
- ANN("format: def [nd_recv].[nd_mid] [nd_defn]; end");
- ANN("example: def obj.foo; bar; end");
- F_NODE(nd_recv, RNODE_DEFS, "receiver");
- F_ID(nd_mid, RNODE_DEFS, "method name");
- LAST_NODE;
- F_NODE(nd_defn, RNODE_DEFS, "method definition");
- return;
-
- case NODE_ALIAS:
- ANN("method alias statement");
- ANN("format: alias [nd_1st] [nd_2nd]");
- ANN("example: alias bar foo");
- F_NODE(nd_1st, RNODE_ALIAS, "new name");
- LAST_NODE;
- F_NODE(nd_2nd, RNODE_ALIAS, "old name");
- return;
-
- case NODE_VALIAS:
- ANN("global variable alias statement");
- ANN("format: alias [nd_alias](gvar) [nd_orig](gvar)");
- ANN("example: alias $y $x");
- F_ID(nd_alias, RNODE_VALIAS, "new name");
- F_ID(nd_orig, RNODE_VALIAS, "old name");
- return;
-
- case NODE_UNDEF:
- ANN("method undef statement");
- ANN("format: undef [nd_undef]");
- ANN("example: undef foo");
- LAST_NODE;
- F_NODE(nd_undef, RNODE_UNDEF, "old name");
- return;
-
- case NODE_CLASS:
- ANN("class definition");
- ANN("format: class [nd_cpath] < [nd_super]; [nd_body]; end");
- ANN("example: class C2 < C; ..; end");
- F_NODE(nd_cpath, RNODE_CLASS, "class path");
- F_NODE(nd_super, RNODE_CLASS, "superclass");
- LAST_NODE;
- F_NODE(nd_body, RNODE_CLASS, "class definition");
- return;
-
- case NODE_MODULE:
- ANN("module definition");
- ANN("format: module [nd_cpath]; [nd_body]; end");
- ANN("example: module M; ..; end");
- F_NODE(nd_cpath, RNODE_MODULE, "module path");
- LAST_NODE;
- F_NODE(nd_body, RNODE_MODULE, "module definition");
- return;
-
- case NODE_SCLASS:
- ANN("singleton class definition");
- ANN("format: class << [nd_recv]; [nd_body]; end");
- ANN("example: class << obj; ..; end");
- F_NODE(nd_recv, RNODE_SCLASS, "receiver");
- LAST_NODE;
- F_NODE(nd_body, RNODE_SCLASS, "singleton class definition");
- return;
-
- case NODE_COLON2:
- ANN("scoped constant reference");
- ANN("format: [nd_head]::[nd_mid]");
- ANN("example: M::C");
- F_ID(nd_mid, RNODE_COLON2, "constant name");
- LAST_NODE;
- F_NODE(nd_head, RNODE_COLON2, "receiver");
- return;
-
- case NODE_COLON3:
- ANN("top-level constant reference");
- ANN("format: ::[nd_mid]");
- ANN("example: ::Object");
- F_ID(nd_mid, RNODE_COLON3, "constant name");
- return;
-
- case NODE_DOT2:
- ANN("range constructor (incl.)");
- ANN("format: [nd_beg]..[nd_end]");
- ANN("example: 1..5");
- goto dot;
- case NODE_DOT3:
- ANN("range constructor (excl.)");
- ANN("format: [nd_beg]...[nd_end]");
- ANN("example: 1...5");
- goto dot;
- case NODE_FLIP2:
- ANN("flip-flop condition (incl.)");
- ANN("format: [nd_beg]..[nd_end]");
- ANN("example: if (x==1)..(x==5); foo; end");
- goto dot;
- case NODE_FLIP3:
- ANN("flip-flop condition (excl.)");
- ANN("format: [nd_beg]...[nd_end]");
- ANN("example: if (x==1)...(x==5); foo; end");
- dot:
- F_NODE(nd_beg, RNODE_DOT2, "begin");
- LAST_NODE;
- F_NODE(nd_end, RNODE_DOT2, "end");
- return;
-
- case NODE_SELF:
- ANN("self");
- ANN("format: self");
- ANN("example: self");
- return;
-
- case NODE_NIL:
- ANN("nil");
- ANN("format: nil");
- ANN("example: nil");
- return;
-
- case NODE_TRUE:
- ANN("true");
- ANN("format: true");
- ANN("example: true");
- return;
-
- case NODE_FALSE:
- ANN("false");
- ANN("format: false");
- ANN("example: false");
- return;
-
- case NODE_ERRINFO:
- ANN("virtual reference to $!");
- ANN("format: rescue => id");
- ANN("example: rescue => id");
- return;
-
- case NODE_DEFINED:
- ANN("defined? expression");
- ANN("format: defined?([nd_head])");
- ANN("example: defined?(foo)");
- F_NODE(nd_head, RNODE_DEFINED, "expr");
- return;
-
- case NODE_POSTEXE:
- ANN("post-execution");
- ANN("format: END { [nd_body] }");
- ANN("example: END { foo }");
- LAST_NODE;
- F_NODE(nd_body, RNODE_POSTEXE, "END clause");
- return;
-
- case NODE_ATTRASGN:
- ANN("attr assignment");
- ANN("format: [nd_recv].[nd_mid] = [nd_args]");
- ANN("example: struct.field = foo");
- F_NODE(nd_recv, RNODE_ATTRASGN, "receiver");
- F_ID(nd_mid, RNODE_ATTRASGN, "method name");
- LAST_NODE;
- F_NODE(nd_args, RNODE_ATTRASGN, "arguments");
- return;
-
- case NODE_LAMBDA:
- ANN("lambda expression");
- ANN("format: -> [nd_body]");
- ANN("example: -> { foo }");
- LAST_NODE;
- F_NODE(nd_body, RNODE_LAMBDA, "lambda clause");
- return;
-
- case NODE_OPT_ARG:
- ANN("optional arguments");
- ANN("format: def method_name([nd_body=some], [nd_next..])");
- ANN("example: def foo(a, b=1, c); end");
- F_NODE(nd_body, RNODE_OPT_ARG, "body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_OPT_ARG, "next");
- return;
-
- case NODE_KW_ARG:
- ANN("keyword arguments");
- ANN("format: def method_name([nd_body=some], [nd_next..])");
- ANN("example: def foo(a:1, b:2); end");
- F_NODE(nd_body, RNODE_KW_ARG, "body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_KW_ARG, "next");
- return;
-
- case NODE_POSTARG:
- ANN("post arguments");
- ANN("format: *[nd_1st], [nd_2nd..] = ..");
- ANN("example: a, *rest, z = foo");
- if (NODE_NAMED_REST_P(RNODE_POSTARG(node)->nd_1st)) {
- F_NODE(nd_1st, RNODE_POSTARG, "rest argument");
- }
- else {
- F_MSG(nd_1st, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- LAST_NODE;
- F_NODE(nd_2nd, RNODE_POSTARG, "post arguments");
- return;
-
- case NODE_ARGS:
- ANN("method parameters");
- ANN("format: def method_name(.., [nd_ainfo.nd_optargs], *[nd_ainfo.rest_arg], [nd_ainfo.first_post_arg], .., [nd_ainfo.kw_args], **[nd_ainfo.kw_rest_arg], &[nd_ainfo.block_arg])");
- ANN("example: def foo(a, b, opt1=1, opt2=2, *rest, y, z, kw: 1, **kwrest, &blk); end");
- F_INT(nd_ainfo.pre_args_num, RNODE_ARGS, "count of mandatory (pre-)arguments");
- F_NODE(nd_ainfo.pre_init, RNODE_ARGS, "initialization of (pre-)arguments");
- F_INT(nd_ainfo.post_args_num, RNODE_ARGS, "count of mandatory post-arguments");
- F_NODE(nd_ainfo.post_init, RNODE_ARGS, "initialization of post-arguments");
- F_ID(nd_ainfo.first_post_arg, RNODE_ARGS, "first post argument");
- F_CUSTOM1(nd_ainfo.rest_arg, "rest argument") {
- if (RNODE_ARGS(node)->nd_ainfo.rest_arg == NODE_SPECIAL_EXCESSIVE_COMMA) {
- A("1 (excessed comma)");
- }
- else {
- A_ID(RNODE_ARGS(node)->nd_ainfo.rest_arg);
- }
- }
- F_ID(nd_ainfo.block_arg, RNODE_ARGS, "block argument");
- F_NODE(nd_ainfo.opt_args, RNODE_ARGS, "optional arguments");
- F_NODE(nd_ainfo.kw_args, RNODE_ARGS, "keyword arguments");
- LAST_NODE;
- F_NODE(nd_ainfo.kw_rest_arg, RNODE_ARGS, "keyword rest argument");
- return;
-
- case NODE_SCOPE:
- ANN("new scope");
- ANN("format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body");
- F_CUSTOM1(nd_tbl, "local table") {
- rb_ast_id_table_t *tbl = RNODE_SCOPE(node)->nd_tbl;
- int i;
- int size = tbl ? tbl->size : 0;
- if (size == 0) A("(empty)");
- for (i = 0; i < size; i++) {
- A_ID(tbl->ids[i]); if (i < size - 1) A(",");
- }
- }
- F_NODE(nd_args, RNODE_SCOPE, "arguments");
- LAST_NODE;
- F_NODE(nd_body, RNODE_SCOPE, "body");
- return;
-
- case NODE_ARYPTN:
- ANN("array pattern");
- ANN("format: [nd_pconst]([pre_args], ..., *[rest_arg], [post_args], ...)");
- F_NODE(nd_pconst, RNODE_ARYPTN, "constant");
- F_NODE(pre_args, RNODE_ARYPTN, "pre arguments");
- if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
- F_NODE(rest_arg, RNODE_ARYPTN, "rest argument");
- }
- else {
- F_MSG(rest_arg, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- LAST_NODE;
- F_NODE(post_args, RNODE_ARYPTN, "post arguments");
- return;
-
- case NODE_FNDPTN:
- ANN("find pattern");
- ANN("format: [nd_pconst](*[pre_rest_arg], args, ..., *[post_rest_arg])");
- F_NODE(nd_pconst, RNODE_FNDPTN, "constant");
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
- F_NODE(pre_rest_arg, RNODE_FNDPTN, "pre rest argument");
- }
- else {
- F_MSG(pre_rest_arg, "pre rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- F_NODE(args, RNODE_FNDPTN, "arguments");
-
- LAST_NODE;
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
- F_NODE(post_rest_arg, RNODE_FNDPTN, "post rest argument");
- }
- else {
- F_MSG(post_rest_arg, "post rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- return;
-
- case NODE_HSHPTN:
- ANN("hash pattern");
- ANN("format: [nd_pconst]([nd_pkwargs], ..., **[nd_pkwrestarg])");
- F_NODE(nd_pconst, RNODE_HSHPTN, "constant");
- F_NODE(nd_pkwargs, RNODE_HSHPTN, "keyword arguments");
- LAST_NODE;
- if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
- F_MSG(nd_pkwrestarg, "keyword rest argument", "NODE_SPECIAL_NO_REST_KEYWORD (**nil)");
- }
- else {
- F_NODE(nd_pkwrestarg, RNODE_HSHPTN, "keyword rest argument");
- }
- return;
- case NODE_ERROR:
- ANN("Broken input recovered by Error Tolerant mode");
- return;
-
- case NODE_ARGS_AUX:
- case NODE_RIPPER:
- case NODE_RIPPER_VALUES:
- case NODE_LAST:
- break;
- }
-
- rb_bug("dump_node: unknown node: %s", ruby_node_name(nd_type(node)));
-}
-
-VALUE
-rb_parser_dump_tree(const NODE *node, int comment)
-{
- VALUE buf = rb_str_new_cstr(
- "###########################################################\n"
- "## Do NOT use this node dump for any purpose other than ##\n"
- "## debug and research. Compatibility is not guaranteed. ##\n"
- "###########################################################\n\n"
- );
- dump_node(buf, rb_str_new_cstr("# "), comment, node);
- return buf;
-}
diff --git a/numeric.c b/numeric.c
index 8cea384d8f..6dd1ff6d2f 100644
--- a/numeric.c
+++ b/numeric.c
@@ -144,37 +144,31 @@ round_half_down(double x, double s)
static double
round_half_even(double x, double s)
{
- double u, v, us, vs, f, d, uf;
-
- v = modf(x, &u);
- us = u * s;
- vs = v * s;
+ double f, d, xs = x * s;
if (x > 0.0) {
- f = floor(vs);
- uf = us + f;
- d = vs - f;
+ f = floor(xs);
+ d = xs - f;
if (d > 0.5)
d = 1.0;
- else if (d == 0.5 || ((double)((uf + 0.5) / s) <= x))
- d = fmod(uf, 2.0);
+ else if (d == 0.5 || ((double)((f + 0.5) / s) <= x))
+ d = fmod(f, 2.0);
else
d = 0.0;
x = f + d;
}
else if (x < 0.0) {
- f = ceil(vs);
- uf = us + f;
- d = f - vs;
+ f = ceil(xs);
+ d = f - xs;
if (d > 0.5)
d = 1.0;
- else if (d == 0.5 || ((double)((uf - 0.5) / s) >= x))
- d = fmod(-uf, 2.0);
+ else if (d == 0.5 || ((double)((f - 0.5) / s) >= x))
+ d = fmod(-f, 2.0);
else
d = 0.0;
x = f - d;
}
- return us + x;
+ return x;
}
static VALUE fix_lshift(long, unsigned long);
@@ -671,7 +665,7 @@ num_div(VALUE x, VALUE y)
* Of the Core and Standard Library classes,
* only Rational uses this implementation.
*
- * For Rational +r+ and real number +n+, these expressions are equivalent:
+ * For \Rational +r+ and real number +n+, these expressions are equivalent:
*
* r % n
* r-n*(r/n).floor
@@ -694,6 +688,8 @@ num_div(VALUE x, VALUE y)
* (-r) % r2 # => (119/100)
* (-r) %-r2 # => (-21/100)
*
+ * Numeric#modulo is an alias for Numeric#%.
+ *
*/
static VALUE
@@ -738,9 +734,6 @@ num_modulo(VALUE x, VALUE y)
static VALUE
num_remainder(VALUE x, VALUE y)
{
- if (!rb_obj_is_kind_of(y, rb_cNumeric)) {
- do_coerce(&x, &y, TRUE);
- }
VALUE z = num_funcall1(x, '%', y);
if ((!rb_equal(z, INT2FIX(0))) &&
@@ -802,6 +795,8 @@ num_divmod(VALUE x, VALUE y)
* (-34.56).abs #=> 34.56
* -34.56.abs #=> 34.56
*
+ * Numeric#magnitude is an alias for Numeric#abs.
+ *
*/
static VALUE
@@ -948,7 +943,7 @@ num_negative_p(VALUE num)
* So you should know its esoteric system. See following:
*
* - https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
- * - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#-why-are-rubys-floats-imprecise
+ * - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#floats_imprecise
* - https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
*
* You can create a \Float object explicitly with:
@@ -999,10 +994,10 @@ num_negative_p(VALUE num)
* - #/: Returns the quotient of +self+ and the given value.
* - #ceil: Returns the smallest number greater than or equal to +self+.
* - #coerce: Returns a 2-element array containing the given value converted to a \Float
- * and +self+
+ and +self+
* - #divmod: Returns a 2-element array containing the quotient and remainder
* results of dividing +self+ by the given value.
- * - #fdiv: Returns the \Float result of dividing +self+ by the given value.
+ * - #fdiv: Returns the Float result of dividing +self+ by the given value.
* - #floor: Returns the greatest number smaller than or equal to +self+.
* - #next_float: Returns the next-larger representable \Float.
* - #prev_float: Returns the next-smaller representable \Float.
@@ -1018,7 +1013,7 @@ num_negative_p(VALUE num)
VALUE
rb_float_new_in_heap(double d)
{
- NEWOBJ_OF(flt, struct RFloat, rb_cFloat, T_FLOAT | (RGENGC_WB_PROTECTED_FLOAT ? FL_WB_PROTECTED : 0), sizeof(struct RFloat), 0);
+ NEWOBJ_OF(flt, struct RFloat, rb_cFloat, T_FLOAT | (RGENGC_WB_PROTECTED_FLOAT ? FL_WB_PROTECTED : 0));
#if SIZEOF_DOUBLE <= SIZEOF_VALUE
flt->float_value = d;
@@ -1152,7 +1147,7 @@ flo_coerce(VALUE x, VALUE y)
return rb_assoc_new(rb_Float(y), x);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_uminus(VALUE flt)
{
return DBL2NUM(-RFLOAT_VALUE(flt));
@@ -1265,7 +1260,7 @@ double_div_double(double x, double y)
}
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_flo_div_flo(VALUE x, VALUE y)
{
double num = RFLOAT_VALUE(x);
@@ -1324,6 +1319,8 @@ rb_float_div(VALUE x, VALUE y)
* f.quo(Rational(2, 1)) # => 1.57
* f.quo(Complex(2, 0)) # => (1.57+0.0i)
*
+ * Float#fdiv is an alias for Float#quo.
+ *
*/
static VALUE
@@ -1375,7 +1372,7 @@ flodivmod(double x, double y, double *divp, double *modp)
* An error will be raised if y == 0.
*/
-double
+MJIT_FUNC_EXPORTED double
ruby_float_mod(double x, double y)
{
double mod;
@@ -1410,6 +1407,8 @@ ruby_float_mod(double x, double y)
* 10.0 % 4.0 # => 2.0
* 10.0 % Rational(4, 1) # => 2.0
*
+ * Float#modulo is an alias for Float#%.
+ *
*/
static VALUE
@@ -1610,7 +1609,7 @@ num_equal(VALUE x, VALUE y)
*
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_equal(VALUE x, VALUE y)
{
volatile double a, b;
@@ -1683,12 +1682,12 @@ rb_dbl_cmp(double a, double b)
* Examples:
*
* 2.0 <=> 2 # => 0
- * 2.0 <=> 2.0 # => 0
- * 2.0 <=> Rational(2, 1) # => 0
- * 2.0 <=> Complex(2, 0) # => 0
- * 2.0 <=> 1.9 # => 1
- * 2.0 <=> 2.1 # => -1
- * 2.0 <=> 'foo' # => nil
+ 2.0 <=> 2.0 # => 0
+ 2.0 <=> Rational(2, 1) # => 0
+ 2.0 <=> Complex(2, 0) # => 0
+ 2.0 <=> 1.9 # => 1
+ 2.0 <=> 2.1 # => -1
+ 2.0 <=> 'foo' # => nil
*
* This is the basis for the tests in the Comparable module.
*
@@ -1728,7 +1727,7 @@ flo_cmp(VALUE x, VALUE y)
return rb_dbl_cmp(a, b);
}
-int
+MJIT_FUNC_EXPORTED int
rb_float_cmp(VALUE x, VALUE y)
{
return NUM2INT(ensure_cmp(flo_cmp(x, y), x, y));
@@ -1922,7 +1921,7 @@ flo_le(VALUE x, VALUE y)
* Related: Float#== (performs type conversions).
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_eql(VALUE x, VALUE y)
{
if (RB_FLOAT_TYPE_P(y)) {
@@ -1938,7 +1937,7 @@ rb_float_eql(VALUE x, VALUE y)
#define flo_eql rb_float_eql
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_abs(VALUE flt)
{
double val = fabs(RFLOAT_VALUE(flt));
@@ -2335,7 +2334,7 @@ int_half_p_half_down(VALUE num, VALUE n, VALUE f)
}
/*
- * Assumes num is an \Integer, ndigits <= 0
+ * Assumes num is an Integer, ndigits <= 0
*/
static VALUE
rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
@@ -2373,11 +2372,7 @@ rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
static VALUE
rb_int_floor(VALUE num, int ndigits)
{
- VALUE f;
-
- if (int_round_zero_p(num, ndigits))
- return INT2FIX(0);
- f = int_pow(10, -ndigits);
+ VALUE f = int_pow(10, -ndigits);
if (FIXNUM_P(num) && FIXNUM_P(f)) {
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
int neg = x < 0;
@@ -2386,21 +2381,19 @@ rb_int_floor(VALUE num, int ndigits)
if (neg) x = -x;
return LONG2NUM(x);
}
- if (RB_FLOAT_TYPE_P(f)) {
- /* then int_pow overflow */
- return INT2FIX(0);
+ else {
+ bool neg = int_neg_p(num);
+ if (neg) num = rb_int_minus(rb_int_plus(rb_int_uminus(num), f), INT2FIX(1));
+ num = rb_int_mul(rb_int_div(num, f), f);
+ if (neg) num = rb_int_uminus(num);
+ return num;
}
- return rb_int_minus(num, rb_int_modulo(num, f));
}
static VALUE
rb_int_ceil(VALUE num, int ndigits)
{
- VALUE f;
-
- if (int_round_zero_p(num, ndigits))
- return INT2FIX(0);
- f = int_pow(10, -ndigits);
+ VALUE f = int_pow(10, -ndigits);
if (FIXNUM_P(num) && FIXNUM_P(f)) {
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
int neg = x < 0;
@@ -2410,11 +2403,16 @@ rb_int_ceil(VALUE num, int ndigits)
if (neg) x = -x;
return LONG2NUM(x);
}
- if (RB_FLOAT_TYPE_P(f)) {
- /* then int_pow overflow */
- return INT2FIX(0);
+ else {
+ bool neg = int_neg_p(num);
+ if (neg)
+ num = rb_int_uminus(num);
+ else
+ num = rb_int_plus(num, rb_int_minus(f, INT2FIX(1)));
+ num = rb_int_mul(rb_int_div(num, f), f);
+ if (neg) num = rb_int_uminus(num);
+ return num;
}
- return rb_int_plus(num, rb_int_minus(f, rb_int_modulo(num, f)));
}
VALUE
@@ -2592,6 +2590,7 @@ float_round_underflow(int ndigits, int binexp)
*
* (0.3 / 0.1).to_i # => 2 (!)
*
+ * Float#to_int is an alias for Float#to_i.
*/
static VALUE
@@ -2834,7 +2833,7 @@ ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl)
}
if (RTEST(rb_funcall(from, cmp, 1, to))) return INT2FIX(0);
result = rb_funcall(rb_funcall(to, '-', 1, from), id_div, 1, step);
- if (!excl || RTEST(rb_funcall(to, cmp, 1, rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step))))) {
+ if (!excl || RTEST(rb_funcall(rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step)), cmp, 1, to))) {
result = rb_funcall(result, '+', 1, INT2FIX(1));
}
return result;
@@ -2960,11 +2959,11 @@ num_step_size(VALUE from, VALUE args, VALUE eobj)
* The generated sequence:
*
* - Begins with +self+.
- * - Continues at intervals of +by+ (which may not be zero).
- * - Ends with the last number that is within or equal to +to+;
- * that is, less than or equal to +to+ if +by+ is positive,
- * greater than or equal to +to+ if +by+ is negative.
- * If +to+ is +nil+, the sequence is of infinite length.
+ * - Continues at intervals of +step+ (which may not be zero).
+ * - Ends with the last number that is within or equal to +limit+;
+ * that is, less than or equal to +limit+ if +step+ is positive,
+ * greater than or equal to +limit+ if +step+ is negative.
+ * If +limit+ is not given, the sequence is of infinite length.
*
* If a block is given, calls the block with each number in the sequence;
* returns +self+. If no block is given, returns an Enumerator::ArithmeticSequence.
@@ -3006,7 +3005,7 @@ num_step_size(VALUE from, VALUE args, VALUE eobj)
*
* <b>Positional Arguments</b>
*
- * With optional positional arguments +to+ and +by+,
+ * With optional positional arguments +limit+ and +step+,
* their values (or defaults) determine the step and limit:
*
* squares = []
@@ -3165,7 +3164,7 @@ rb_num2ulong_internal(VALUE val, int *wrap_p)
{
again:
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
}
if (FIXNUM_P(val)) {
@@ -3440,7 +3439,7 @@ unsigned LONG_LONG
rb_num2ull(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_raise(rb_eTypeError, "no implicit conversion from nil");
}
else if (FIXNUM_P(val)) {
return (LONG_LONG)FIX2LONG(val); /* this is FIX2LONG, intended */
@@ -3459,10 +3458,15 @@ rb_num2ull(VALUE val)
else if (RB_BIGNUM_TYPE_P(val)) {
return rb_big2ull(val);
}
- else {
- val = rb_to_int(val);
- return NUM2ULL(val);
+ else if (RB_TYPE_P(val, T_STRING)) {
+ rb_raise(rb_eTypeError, "no implicit conversion from string");
+ }
+ else if (RB_TYPE_P(val, T_TRUE) || RB_TYPE_P(val, T_FALSE)) {
+ rb_raise(rb_eTypeError, "no implicit conversion from boolean");
}
+
+ val = rb_to_int(val);
+ return NUM2ULL(val);
}
#endif /* HAVE_LONG_LONG */
@@ -3690,6 +3694,8 @@ int_nobits_p(VALUE num, VALUE mask)
* 1.succ #=> 2
* -1.succ #=> 0
*
+ * Integer#next is an alias for Integer#succ.
+ *
* Related: Integer#pred (predecessor value).
*/
@@ -3886,7 +3892,7 @@ rb_fix2str(VALUE x, int base)
static VALUE rb_fix_to_s_static[10];
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_fix_to_s(VALUE x)
{
long i = FIX2LONG(x);
@@ -3912,9 +3918,12 @@ rb_fix_to_s(VALUE x)
* 78546939656932.to_s(36) # => "rubyrules"
*
* Raises an exception if +base+ is out of range.
+ *
+ * Integer#inspect is an alias for Integer#to_s.
+ *
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_int_to_s(int argc, VALUE *argv, VALUE x)
{
int base;
@@ -4305,6 +4314,8 @@ fix_mod(VALUE x, VALUE y)
* 10 % 3.0 # => 1.0
* 10 % Rational(3, 1) # => (1/1)
*
+ * Integer#modulo is an alias for Integer#%.
+ *
*/
VALUE
rb_int_modulo(VALUE x, VALUE y)
@@ -4345,22 +4356,12 @@ static VALUE
int_remainder(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
- if (FIXNUM_P(y)) {
- VALUE z = fix_mod(x, y);
- assert(FIXNUM_P(z));
- if (z != INT2FIX(0) && (SIGNED_VALUE)(x ^ y) < 0)
- z = fix_minus(z, y);
- return z;
- }
- else if (!RB_BIGNUM_TYPE_P(y)) {
- return num_remainder(x, y);
- }
- x = rb_int2big(FIX2LONG(x));
+ return num_remainder(x, y);
}
- else if (!RB_BIGNUM_TYPE_P(x)) {
- return Qnil;
+ else if (RB_BIGNUM_TYPE_P(x)) {
+ return rb_big_remainder(x, y);
}
- return rb_big_remainder(x, y);
+ return Qnil;
}
static VALUE
@@ -4623,6 +4624,9 @@ fix_equal(VALUE x, VALUE y)
* 1 == 1.0 #=> true
*
* Related: Integer#eql? (requires +other+ to be an \Integer).
+ *
+ * Integer#=== is an alias for Integer#==.
+ *
*/
VALUE
@@ -5169,7 +5173,7 @@ rb_int_rshift(VALUE x, VALUE y)
return Qnil;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_fix_aref(VALUE fix, VALUE idx)
{
long val = FIX2LONG(fix);
@@ -5339,7 +5343,7 @@ int_aref(int const argc, VALUE * const argv, VALUE const num)
* 1.to_f # => 1.0
* -1.to_f # => -1.0
*
- * If the value of +self+ does not fit in a Float,
+ * If the value of +self+ does not fit in a \Float,
* the result is infinity:
*
* (10**400).to_f # => Infinity
@@ -5393,7 +5397,7 @@ fix_size(VALUE fix)
return INT2FIX(sizeof(long));
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_int_size(VALUE num)
{
if (FIXNUM_P(num)) {
@@ -5652,6 +5656,58 @@ int_downto(VALUE from, VALUE to)
return from;
}
+static VALUE
+int_dotimes_size(VALUE num, VALUE args, VALUE eobj)
+{
+ if (FIXNUM_P(num)) {
+ if (NUM2LONG(num) <= 0) return INT2FIX(0);
+ }
+ else {
+ if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) return INT2FIX(0);
+ }
+ return num;
+}
+
+/*
+ * call-seq:
+ * times {|i| ... } -> self
+ * times -> enumerator
+ *
+ * Calls the given block +self+ times with each integer in <tt>(0..self-1)</tt>:
+ *
+ * a = []
+ * 5.times {|i| a.push(i) } # => 5
+ * a # => [0, 1, 2, 3, 4]
+ *
+ * With no block given, returns an Enumerator.
+ *
+ */
+
+static VALUE
+int_dotimes(VALUE num)
+{
+ RETURN_SIZED_ENUMERATOR(num, 0, 0, int_dotimes_size);
+
+ if (FIXNUM_P(num)) {
+ long i, end;
+
+ end = FIX2LONG(num);
+ for (i=0; i<end; i++) {
+ rb_yield_1(LONG2FIX(i));
+ }
+ }
+ else {
+ VALUE i = INT2FIX(0);
+
+ for (;;) {
+ if (!RTEST(int_le(i, num))) break;
+ rb_yield(i);
+ i = rb_int_plus(i, INT2FIX(1));
+ }
+ }
+ return num;
+}
+
/*
* call-seq:
* round(ndigits= 0, half: :up) -> integer
@@ -5932,22 +5988,7 @@ rb_int_s_isqrt(VALUE self, VALUE num)
}
}
-/*
- * call-seq:
- * Integer.try_convert(object) -> object, integer, or nil
- *
- * If +object+ is an \Integer object, returns +object+.
- * Integer.try_convert(1) # => 1
- *
- * Otherwise if +object+ responds to <tt>:to_int</tt>,
- * calls <tt>object.to_int</tt> and returns the result.
- * Integer.try_convert(1.25) # => 1
- *
- * Returns +nil+ if +object+ does not respond to <tt>:to_int</tt>
- * Integer.try_convert([]) # => nil
- *
- * Raises an exception unless <tt>object.to_int</tt> returns an \Integer object.
- */
+/* :nodoc: */
static VALUE
int_s_try_convert(VALUE self, VALUE num)
{
@@ -5980,9 +6021,9 @@ int_s_try_convert(VALUE self, VALUE num)
/*
* Document-class: Numeric
*
- * \Numeric is the class from which all higher-level numeric classes should inherit.
+ * Numeric is the class from which all higher-level numeric classes should inherit.
*
- * \Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as
+ * Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as
* Integer are implemented as immediates, which means that each Integer is a single immutable
* object which is always passed by value.
*
@@ -5996,9 +6037,9 @@ int_s_try_convert(VALUE self, VALUE num)
* 1.dup #=> 1
* 1.object_id == 1.dup.object_id #=> true
*
- * For this reason, \Numeric should be used when defining other numeric classes.
+ * For this reason, Numeric should be used when defining other numeric classes.
*
- * Classes which inherit from \Numeric must implement +coerce+, which returns a two-member
+ * Classes which inherit from Numeric must implement +coerce+, which returns a two-member
* Array containing an object that has been coerced into an instance of the new class
* and +self+ (see #coerce).
*
@@ -6191,6 +6232,7 @@ Init_Numeric(void)
rb_define_method(rb_cInteger, "nobits?", int_nobits_p, 1);
rb_define_method(rb_cInteger, "upto", int_upto, 1);
rb_define_method(rb_cInteger, "downto", int_downto, 1);
+ rb_define_method(rb_cInteger, "times", int_dotimes, 0);
rb_define_method(rb_cInteger, "succ", int_succ, 0);
rb_define_method(rb_cInteger, "next", int_succ, 0);
rb_define_method(rb_cInteger, "pred", int_pred, 0);
diff --git a/numeric.rb b/numeric.rb
index 3c059a58a4..f026679210 100644
--- a/numeric.rb
+++ b/numeric.rb
@@ -1,56 +1,62 @@
class Numeric
-
+ #
# call-seq:
- # real? -> true or false
+ # num.real? -> true or false
#
- # Returns +true+ if +self+ is a real number (i.e. not Complex).
+ # Returns +true+ if +num+ is a real number (i.e. not Complex).
#
def real?
true
end
+ #
# call-seq:
- # real -> self
+ # num.real -> self
#
- # Returns +self+.
+ # Returns self.
#
def real
self
end
+ #
# call-seq:
- # integer? -> true or false
+ # num.integer? -> true or false
#
- # Returns +true+ if +self+ is an Integer.
+ # Returns +true+ if +num+ is an Integer.
#
- # 1.0.integer? # => false
- # 1.integer? # => true
+ # 1.0.integer? #=> false
+ # 1.integer? #=> true
#
def integer?
false
end
+ #
# call-seq:
- # finite? -> true or false
+ # num.finite? -> true or false
#
- # Returns +true+ if +self+ is a finite number, +false+ otherwise.
+ # Returns +true+ if +num+ is a finite number, otherwise returns +false+.
#
def finite?
true
end
+ #
# call-seq:
- # infinite? -> -1, 1, or nil
+ # num.infinite? -> -1, 1, or nil
#
- # Returns +nil+, -1, or 1 depending on whether +self+ is
- # finite, <tt>-Infinity</tt>, or <tt>+Infinity</tt>.
+ # Returns +nil+, -1, or 1 depending on whether the value is
+ # finite, <code>-Infinity</code>, or <code>+Infinity</code>.
#
def infinite?
nil
end
+ #
# call-seq:
- # imag -> 0
+ # num.imag -> 0
+ # num.imaginary -> 0
#
# Returns zero.
#
@@ -60,10 +66,12 @@ class Numeric
alias imag imaginary
+ #
# call-seq:
- # conj -> self
+ # num.conj -> self
+ # num.conjugate -> self
#
- # Returns +self+.
+ # Returns self.
#
def conjugate
self
@@ -74,298 +82,323 @@ end
class Integer
# call-seq:
- # -int -> integer
+ # -int -> integer
#
- # Returns +self+, negated.
+ # Returns +int+, negated.
def -@
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_uminus(self)'
end
# call-seq:
- # ~int -> integer
+ # ~int -> integer
#
- # One's complement:
- # returns the value of +self+ with each bit inverted.
+ # One's complement: returns a number where each bit is flipped.
#
- # Because an integer value is conceptually of infinite length,
- # the result acts as if it had an infinite number of
- # one bits to the left.
- # In hex representations, this is displayed
- # as two periods to the left of the digits:
- #
- # sprintf("%X", ~0x1122334455) # => "..FEEDDCCBBAA"
+ # Inverts the bits in an Integer. As integers are conceptually of
+ # infinite length, the result acts as if it had an infinite number of
+ # one bits to the left. In hex representations, this is displayed
+ # as two periods to the left of the digits.
#
+ # sprintf("%X", ~0x1122334455) #=> "..FEEDDCCBBAA"
def ~
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_comp(self)'
end
# call-seq:
- # abs -> integer
+ # int.abs -> integer
+ # int.magnitude -> integer
#
- # Returns the absolute value of +self+.
+ # Returns the absolute value of +int+.
#
- # (-12345).abs # => 12345
- # -12345.abs # => 12345
- # 12345.abs # => 12345
+ # (-12345).abs #=> 12345
+ # -12345.abs #=> 12345
+ # 12345.abs #=> 12345
#
+ # Integer#magnitude is an alias for Integer#abs.
def abs
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_abs(self)'
end
# call-seq:
- # bit_length -> integer
+ # int.bit_length -> integer
#
- # Returns the number of bits of the value of +self+,
- # which is the bit position of the highest-order bit
- # that is different from the sign bit
- # (where the least significant bit has bit position 1).
- # If there is no such bit (zero or minus one), returns zero.
- #
- # This method returns <tt>ceil(log2(self < 0 ? -self : self + 1))</tt>>.
- #
- # (-2**1000-1).bit_length # => 1001
- # (-2**1000).bit_length # => 1000
- # (-2**1000+1).bit_length # => 1000
- # (-2**12-1).bit_length # => 13
- # (-2**12).bit_length # => 12
- # (-2**12+1).bit_length # => 12
- # -0x101.bit_length # => 9
- # -0x100.bit_length # => 8
- # -0xff.bit_length # => 8
- # -2.bit_length # => 1
- # -1.bit_length # => 0
- # 0.bit_length # => 0
- # 1.bit_length # => 1
- # 0xff.bit_length # => 8
- # 0x100.bit_length # => 9
- # (2**12-1).bit_length # => 12
- # (2**12).bit_length # => 13
- # (2**12+1).bit_length # => 13
- # (2**1000-1).bit_length # => 1000
- # (2**1000).bit_length # => 1001
- # (2**1000+1).bit_length # => 1001
- #
- # For \Integer _n_,
- # this method can be used to detect overflow in Array#pack:
- #
- # if n.bit_length < 32
- # [n].pack('l') # No overflow.
- # else
- # raise 'Overflow'
- # end
+ # Returns the number of bits of the value of +int+.
#
+ # "Number of bits" means the bit position of the highest bit
+ # which is different from the sign bit
+ # (where the least significant bit has bit position 1).
+ # If there is no such bit (zero or minus one), zero is returned.
+ #
+ # I.e. this method returns <i>ceil(log2(int < 0 ? -int : int+1))</i>.
+ #
+ # (-2**1000-1).bit_length #=> 1001
+ # (-2**1000).bit_length #=> 1000
+ # (-2**1000+1).bit_length #=> 1000
+ # (-2**12-1).bit_length #=> 13
+ # (-2**12).bit_length #=> 12
+ # (-2**12+1).bit_length #=> 12
+ # -0x101.bit_length #=> 9
+ # -0x100.bit_length #=> 8
+ # -0xff.bit_length #=> 8
+ # -2.bit_length #=> 1
+ # -1.bit_length #=> 0
+ # 0.bit_length #=> 0
+ # 1.bit_length #=> 1
+ # 0xff.bit_length #=> 8
+ # 0x100.bit_length #=> 9
+ # (2**12-1).bit_length #=> 12
+ # (2**12).bit_length #=> 13
+ # (2**12+1).bit_length #=> 13
+ # (2**1000-1).bit_length #=> 1000
+ # (2**1000).bit_length #=> 1001
+ # (2**1000+1).bit_length #=> 1001
+ #
+ # This method can be used to detect overflow in Array#pack as follows:
+ #
+ # if n.bit_length < 32
+ # [n].pack("l") # no overflow
+ # else
+ # raise "overflow"
+ # end
def bit_length
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_bit_length(self)'
end
# call-seq:
- # even? -> true or false
+ # int.even? -> true or false
#
- # Returns +true+ if +self+ is an even number, +false+ otherwise.
+ # Returns +true+ if +int+ is an even number.
def even?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_even_p(self)'
end
# call-seq:
- # integer? -> true
+ # int.integer? -> true
#
- # Since +self+ is already an \Integer, always returns +true+.
+ # Since +int+ is already an Integer, this always returns +true+.
def integer?
true
end
alias magnitude abs
+=begin
+ def magnitude
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'rb_int_abs(self)'
+ end
+=end
# call-seq:
- # odd? -> true or false
+ # int.odd? -> true or false
#
- # Returns +true+ if +self+ is an odd number, +false+ otherwise.
+ # Returns +true+ if +int+ is an odd number.
def odd?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_odd_p(self)'
end
# call-seq:
- # ord -> self
+ # int.ord -> self
+ #
+ # Returns the +int+ itself.
#
- # Returns +self+;
- # intended for compatibility to character literals in Ruby 1.9.
+ # 97.ord #=> 97
+ #
+ # This method is intended for compatibility to character literals
+ # in Ruby 1.9.
+ #
+ # For example, <code>?a.ord</code> returns 97 both in 1.8 and 1.9.
def ord
self
end
+ #
+ # Document-method: Integer#size
# call-seq:
- # size -> integer
+ # int.size -> int
#
- # Returns the number of bytes in the machine representation of +self+;
- # the value is system-dependent:
+ # Returns the number of bytes in the machine representation of +int+
+ # (machine dependent).
#
- # 1.size # => 8
- # -1.size # => 8
- # 2147483647.size # => 8
- # (256**10 - 1).size # => 10
- # (256**20 - 1).size # => 20
- # (256**40 - 1).size # => 40
+ # 1.size #=> 8
+ # -1.size #=> 8
+ # 2147483647.size #=> 8
+ # (256**10 - 1).size #=> 10
+ # (256**20 - 1).size #=> 20
+ # (256**40 - 1).size #=> 40
#
def size
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_size(self)'
end
- # call-seq:
- # times {|i| ... } -> self
- # times -> enumerator
- #
- # Calls the given block +self+ times with each integer in <tt>(0..self-1)</tt>:
- #
- # a = []
- # 5.times {|i| a.push(i) } # => 5
- # a # => [0, 1, 2, 3, 4]
- #
- # With no block given, returns an Enumerator.
- def times
- unless block_given?
- return to_enum(:times) { self < 0 ? 0 : self }
- end
- i = 0
- while i < self
- yield i
- i = i.succ
- end
- self
- end
-
# call-seq:
- # to_i -> self
+ # int.to_i -> integer
+ #
+ # Since +int+ is already an Integer, returns +self+.
#
- # Returns +self+ (which is already an \Integer).
+ # #to_int is an alias for #to_i.
def to_i
self
end
# call-seq:
- # to_int -> self
+ # int.to_int -> integer
#
- # Returns +self+ (which is already an \Integer).
+ # Since +int+ is already an Integer, returns +self+.
def to_int
self
end
# call-seq:
- # zero? -> true or false
+ # int.zero? -> true or false
#
- # Returns +true+ if +self+ has a zero value, +false+ otherwise.
+ # Returns +true+ if +int+ has a zero value.
def zero?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_zero_p(self)'
end
# call-seq:
- # ceildiv(numeric) -> integer
+ # ceildiv(other) -> integer
#
- # Returns the result of division +self+ by +numeric+.
- # rounded up to the nearest integer.
+ # Returns the result of division +self+ by +other+. The result is rounded up to the nearest integer.
#
- # 3.ceildiv(3) # => 1
- # 4.ceildiv(3) # => 2
+ # 3.ceildiv(3) # => 1
+ # 4.ceildiv(3) # => 2
#
- # 4.ceildiv(-3) # => -1
- # -4.ceildiv(3) # => -1
+ # 4.ceildiv(-3) # => -1
+ # -4.ceildiv(3) # => -1
# -4.ceildiv(-3) # => 2
#
# 3.ceildiv(1.2) # => 3
- #
def ceildiv(other)
- -div(0 - other)
+ -div(-other)
end
#
# call-seq:
- # numerator -> self
+ # int.numerator -> self
#
- # Returns +self+.
+ # Returns self.
#
def numerator
self
end
+ #
# call-seq:
- # denominator -> 1
+ # int.denominator -> 1
+ #
+ # Returns 1.
#
- # Returns +1+.
def denominator
1
end
end
-class Float
+# call-seq:
+# Integer.try_convert(object) -> object, integer, or nil
+#
+# If +object+ is an \Integer object, returns +object+.
+# Integer.try_convert(1) # => 1
+#
+# Otherwise if +object+ responds to <tt>:to_int</tt>,
+# calls <tt>object.to_int</tt> and returns the result.
+# Integer.try_convert(1.25) # => 1
+#
+# Returns +nil+ if +object+ does not respond to <tt>:to_int</tt>
+# Integer.try_convert([]) # => nil
+#
+# Raises an exception unless <tt>object.to_int</tt> returns an \Integer object.
+#
+def Integer.try_convert(num)
+=begin
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'rb_check_integer_type(num)'
+=end
+end if false
+class Float
+ #
# call-seq:
- # to_f -> self
+ # float.to_f -> self
+ #
+ # Since +float+ is already a Float, returns +self+.
#
- # Returns +self+ (which is already a \Float).
def to_f
self
end
+ #
# call-seq:
- # float.abs -> float
+ # float.abs -> float
+ # float.magnitude -> float
+ #
+ # Returns the absolute value of +float+.
#
- # Returns the absolute value of +self+:
+ # (-34.56).abs #=> 34.56
+ # -34.56.abs #=> 34.56
+ # 34.56.abs #=> 34.56
#
- # (-34.56).abs # => 34.56
- # -34.56.abs # => 34.56
- # 34.56.abs # => 34.56
+ # Float#magnitude is an alias for Float#abs.
#
def abs
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_float_abs(self)'
end
def magnitude
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_float_abs(self)'
end
+ #
# call-seq:
- # -float -> float
+ # -float -> float
#
- # Returns +self+, negated.
+ # Returns +float+, negated.
#
def -@
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_float_uminus(self)'
end
+ #
# call-seq:
- # zero? -> true or false
+ # float.zero? -> true or false
+ #
+ # Returns +true+ if +float+ is 0.0.
#
- # Returns +true+ if +self+ is 0.0, +false+ otherwise.
def zero?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'RBOOL(FLOAT_ZERO_P(self))'
end
+ #
# call-seq:
- # positive? -> true or false
+ # float.positive? -> true or false
+ #
+ # Returns +true+ if +float+ is greater than 0.
#
- # Returns +true+ if +self+ is greater than 0, +false+ otherwise.
def positive?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'RBOOL(RFLOAT_VALUE(self) > 0.0)'
end
+ #
# call-seq:
- # negative? -> true or false
+ # float.negative? -> true or false
+ #
+ # Returns +true+ if +float+ is less than 0.
#
- # Returns +true+ if +self+ is less than 0, +false+ otherwise.
def negative?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'RBOOL(RFLOAT_VALUE(self) < 0.0)'
end
diff --git a/object.c b/object.c
index 73fbe78edc..e1fc72c89f 100644
--- a/object.c
+++ b/object.c
@@ -42,18 +42,6 @@
#include "builtin.h"
#include "shape.h"
-/* Flags of RObject
- *
- * 1: ROBJECT_EMBED
- * The object has its instance variables embedded (the array of
- * instance variables directly follow the object, rather than being
- * on a separately allocated buffer).
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID for the object.
- * endif
- */
-
/*!
* \addtogroup object
* \{
@@ -113,24 +101,19 @@ rb_obj_reveal(VALUE obj, VALUE klass)
VALUE
rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
{
- RBASIC(obj)->flags = type;
+ VALUE ignored_flags = RUBY_FL_PROMOTED | RUBY_FL_SEEN_OBJ_ID;
+ RBASIC(obj)->flags = (type & ~ignored_flags) | (RBASIC(obj)->flags & ignored_flags);
RBASIC_SET_CLASS(obj, klass);
return obj;
}
-/*
- * call-seq:
- * true === other -> true or false
- * false === other -> true or false
- * nil === other -> true or false
- *
- * Returns +true+ or +false+.
- *
- * Like Object#==, if +object+ is an instance of Object
- * (and not an instance of one of its many subclasses).
+/**
+ * call-seq:
+ * obj === other -> true or false
*
- * This method is commonly overridden by those subclasses,
- * to provide meaningful semantics in +case+ statements.
+ * Case Equality -- For class Object, effectively the same as calling
+ * <code>#==</code>, but typically overridden by descendants to provide
+ * meaningful semantics in +case+ statements.
*/
#define case_equal rb_equal
/* The default implementation of #=== is
@@ -203,7 +186,7 @@ rb_eql(VALUE obj1, VALUE obj2)
* \private
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
return RBOOL(obj1 == obj2);
@@ -221,7 +204,7 @@ VALUE rb_obj_hash(VALUE obj);
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_not(VALUE obj)
{
return RBOOL(!RTEST(obj));
@@ -237,7 +220,7 @@ rb_obj_not(VALUE obj)
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_not_equal(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
@@ -284,7 +267,7 @@ rb_obj_singleton_class(VALUE obj)
}
/*! \private */
-void
+MJIT_FUNC_EXPORTED void
rb_obj_copy_ivar(VALUE dest, VALUE obj)
{
RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE));
@@ -292,8 +275,8 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(BUILTIN_TYPE(dest) == BUILTIN_TYPE(obj));
rb_shape_t * src_shape = rb_shape_get_shape(obj);
- if (rb_shape_obj_too_complex(obj)) {
- st_table * table = rb_st_init_numtable_with_size(rb_st_table_size(ROBJECT_IV_HASH(obj)));
+ if (rb_shape_id(src_shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
+ st_table *table = st_copy(ROBJECT_IV_HASH(obj));
rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
rb_shape_set_too_complex(dest);
@@ -326,18 +309,9 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
- if (UNLIKELY(rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
- st_table * table = rb_st_init_numtable_with_size(src_num_ivs);
-
- rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
- rb_shape_set_too_complex(dest);
- ROBJECT(dest)->as.heap.ivptr = (VALUE *)table;
-
- return;
- }
}
- RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity || rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID);
+ RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity);
if (initial_shape->capacity < shape_to_set_on_dest->capacity) {
rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity);
dest_buf = ROBJECT_IVPTR(dest);
@@ -472,16 +446,11 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze)
rb_funcall(clone, id_init_clone, 1, obj);
RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
if (RB_OBJ_FROZEN(obj)) {
- rb_shape_t * next_shape = rb_shape_transition_shape_frozen(clone);
- if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- rb_evict_ivars_to_hash(clone, rb_shape_get_shape(clone));
- }
- else {
- rb_shape_set_shape(clone, next_shape);
- }
+ rb_shape_transition_shape_frozen(clone);
}
break;
- case Qtrue: {
+ case Qtrue:
+ {
static VALUE freeze_true_hash;
if (!freeze_true_hash) {
freeze_true_hash = rb_hash_new();
@@ -494,18 +463,11 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze)
argv[1] = freeze_true_hash;
rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS);
RBASIC(clone)->flags |= FL_FREEZE;
- rb_shape_t * next_shape = rb_shape_transition_shape_frozen(clone);
- // If we're out of shapes, but we want to freeze, then we need to
- // evacuate this clone to a hash
- if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- rb_evict_ivars_to_hash(clone, rb_shape_get_shape(clone));
- }
- else {
- rb_shape_set_shape(clone, next_shape);
- }
+ rb_shape_transition_shape_frozen(clone);
break;
- }
- case Qfalse: {
+ }
+ case Qfalse:
+ {
static VALUE freeze_false_hash;
if (!freeze_false_hash) {
freeze_false_hash = rb_hash_new();
@@ -518,7 +480,7 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze)
argv[1] = freeze_false_hash;
rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS);
break;
- }
+ }
default:
rb_bug("invalid kwfreeze passed to mutable_obj_clone");
}
@@ -610,6 +572,12 @@ rb_obj_size(VALUE self, VALUE args, VALUE obj)
return LONG2FIX(1);
}
+static VALUE
+block_given_p(rb_execution_context_t *ec, VALUE self)
+{
+ return RBOOL(rb_block_given_p());
+}
+
/**
* :nodoc:
*--
@@ -1292,47 +1260,17 @@ rb_obj_frozen_p(VALUE obj)
/*
* Document-class: NilClass
*
- * The class of the singleton object +nil+.
- *
- * Several of its methods act as operators:
- *
- * - #&
- * - #|
- * - #===
- * - #=~
- * - #^
- *
- * Others act as converters, carrying the concept of _nullity_
- * to other classes:
- *
- * - #rationalize
- * - #to_a
- * - #to_c
- * - #to_h
- * - #to_r
- * - #to_s
- *
- * Another method provides inspection:
- *
- * - #inspect
- *
- * Finally, there is this query method:
- *
- * - #nil?
- *
+ * The class of the singleton object <code>nil</code>.
*/
/*
- * call-seq:
- * to_s -> ''
- *
- * Returns an empty String:
- *
- * nil.to_s # => ""
+ * call-seq:
+ * nil.to_s -> ""
*
+ * Always returns the empty string.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_nil_to_s(VALUE obj)
{
return rb_cNilClass_to_s;
@@ -1341,13 +1279,12 @@ rb_nil_to_s(VALUE obj)
/*
* Document-method: to_a
*
- * call-seq:
- * to_a -> []
- *
- * Returns an empty Array.
+ * call-seq:
+ * nil.to_a -> []
*
- * nil.to_a # => []
+ * Always returns an empty array.
*
+ * nil.to_a #=> []
*/
static VALUE
@@ -1359,13 +1296,12 @@ nil_to_a(VALUE obj)
/*
* Document-method: to_h
*
- * call-seq:
- * to_h -> {}
- *
- * Returns an empty Hash.
+ * call-seq:
+ * nil.to_h -> {}
*
- * nil.to_h #=> {}
+ * Always returns an empty hash.
*
+ * nil.to_h #=> {}
*/
static VALUE
@@ -1375,13 +1311,10 @@ nil_to_h(VALUE obj)
}
/*
- * call-seq:
- * inspect -> 'nil'
- *
- * Returns string <tt>'nil'</tt>:
- *
- * nil.inspect # => "nil"
+ * call-seq:
+ * nil.inspect -> "nil"
*
+ * Always returns the string "nil".
*/
static VALUE
@@ -1391,17 +1324,12 @@ nil_inspect(VALUE obj)
}
/*
- * call-seq:
- * nil =~ object -> nil
- *
- * Returns +nil+.
- *
- * This method makes it useful to write:
+ * call-seq:
+ * nil =~ other -> nil
*
- * while gets =~ /re/
- * # ...
- * end
+ * Dummy pattern matching -- always returns nil.
*
+ * This method makes it possible to `while gets =~ /re/ do`.
*/
static VALUE
@@ -1410,38 +1338,24 @@ nil_match(VALUE obj1, VALUE obj2)
return Qnil;
}
-/*
+/***********************************************************************
* Document-class: TrueClass
*
- * The class of the singleton object +true+.
- *
- * Several of its methods act as operators:
- *
- * - #&
- * - #|
- * - #===
- * - #^
- *
- * One other method:
- *
- * - #to_s and its alias #inspect.
- *
+ * The global value <code>true</code> is the only instance of class
+ * TrueClass and represents a logically true value in
+ * boolean expressions. The class provides operators allowing
+ * <code>true</code> to be used in logical expressions.
*/
/*
* call-seq:
- * true.to_s -> 'true'
- *
- * Returns string <tt>'true'</tt>:
- *
- * true.to_s # => "true"
- *
- * TrueClass#inspect is an alias for TrueClass#to_s.
+ * true.to_s -> "true"
*
+ * The string representation of <code>true</code> is "true".
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_true_to_s(VALUE obj)
{
return rb_cTrueClass_to_s;
@@ -1450,14 +1364,10 @@ rb_true_to_s(VALUE obj)
/*
* call-seq:
- * true & object -> true or false
- *
- * Returns +false+ if +object+ is +false+ or +nil+, +true+ otherwise:
- *
- * true & Object.new # => true
- * true & false # => false
- * true & nil # => false
+ * true & obj -> true or false
*
+ * And---Returns <code>false</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>, <code>true</code> otherwise.
*/
static VALUE
@@ -1468,21 +1378,18 @@ true_and(VALUE obj, VALUE obj2)
/*
* call-seq:
- * true | object -> true
+ * true | obj -> true
*
- * Returns +true+:
+ * Or---Returns <code>true</code>. As <i>obj</i> is an argument to
+ * a method call, it is always evaluated; there is no short-circuit
+ * evaluation in this case.
*
- * true | Object.new # => true
- * true | false # => true
- * true | nil # => true
+ * true | puts("or")
+ * true || puts("logical or")
*
- * Argument +object+ is evaluated.
- * This is different from +true+ with the short-circuit operator,
- * whose operand is evaluated only if necessary:
- *
- * true | raise # => Raises RuntimeError.
- * true || raise # => true
+ * <em>produces:</em>
*
+ * or
*/
static VALUE
@@ -1494,14 +1401,11 @@ true_or(VALUE obj, VALUE obj2)
/*
* call-seq:
- * true ^ object -> !object
- *
- * Returns +true+ if +object+ is +false+ or +nil+, +false+ otherwise:
- *
- * true ^ Object.new # => false
- * true ^ false # => true
- * true ^ nil # => true
+ * true ^ obj -> !obj
*
+ * Exclusive Or---Returns <code>true</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>, <code>false</code>
+ * otherwise.
*/
static VALUE
@@ -1528,27 +1432,22 @@ true_xor(VALUE obj, VALUE obj2)
* The string representation of <code>false</code> is "false".
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_false_to_s(VALUE obj)
{
return rb_cFalseClass_to_s;
}
/*
- * call-seq:
- * false & object -> false
- * nil & object -> false
- *
- * Returns +false+:
- *
- * false & true # => false
- * false & Object.new # => false
- *
- * Argument +object+ is evaluated:
- *
- * false & raise # Raises RuntimeError.
+ * call-seq:
+ * false & obj -> false
+ * nil & obj -> false
*
+ * And---Returns <code>false</code>. <i>obj</i> is always
+ * evaluated as it is the argument to a method call---there is no
+ * short-circuit evaluation in this case.
*/
+
static VALUE
false_and(VALUE obj, VALUE obj2)
{
@@ -1557,30 +1456,24 @@ false_and(VALUE obj, VALUE obj2)
/*
- * call-seq:
- * false | object -> true or false
- * nil | object -> true or false
- *
- * Returns +false+ if +object+ is +nil+ or +false+, +true+ otherwise:
- *
- * nil | nil # => false
- * nil | false # => false
- * nil | Object.new # => true
+ * call-seq:
+ * false | obj -> true or false
+ * nil | obj -> true or false
*
+ * Or---Returns <code>false</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>; <code>true</code> otherwise.
*/
#define false_or true_and
/*
- * call-seq:
- * false ^ object -> true or false
- * nil ^ object -> true or false
- *
- * Returns +false+ if +object+ is +nil+ or +false+, +true+ otherwise:
+ * call-seq:
+ * false ^ obj -> true or false
+ * nil ^ obj -> true or false
*
- * nil ^ nil # => false
- * nil ^ false # => false
- * nil ^ Object.new # => true
+ * Exclusive Or---If <i>obj</i> is <code>nil</code> or
+ * <code>false</code>, returns <code>false</code>; otherwise, returns
+ * <code>true</code>.
*
*/
@@ -1588,10 +1481,9 @@ false_and(VALUE obj, VALUE obj2)
/*
* call-seq:
- * nil.nil? -> true
+ * nil.nil? -> true
*
- * Returns +true+.
- * For all other objects, method <tt>nil?</tt> returns +false+.
+ * Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>.
*/
static VALUE
@@ -1611,7 +1503,7 @@ rb_true(VALUE obj)
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_false(VALUE obj)
{
return Qfalse;
@@ -1696,7 +1588,7 @@ rb_obj_cmp(VALUE obj1, VALUE obj2)
* show information on the thing we're attached to as well.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_mod_to_s(VALUE klass)
{
ID id_defined_at;
@@ -1704,7 +1596,7 @@ rb_mod_to_s(VALUE klass)
if (FL_TEST(klass, FL_SINGLETON)) {
VALUE s = rb_usascii_str_new2("#<Class:");
- VALUE v = RCLASS_ATTACHED_OBJECT(klass);
+ VALUE v = rb_ivar_get(klass, id__attached__);
if (CLASS_OR_MODULE_P(v)) {
rb_str_append(s, rb_inspect(v));
@@ -3170,7 +3062,7 @@ rb_check_convert_type(VALUE val, int type, const char *tname, const char *method
}
/*! \private */
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_check_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
{
VALUE v;
@@ -3335,17 +3227,121 @@ rb_opts_exception_p(VALUE opts, int default_value)
return default_value;
}
-static VALUE
-rb_f_integer1(rb_execution_context_t *ec, VALUE obj, VALUE arg)
-{
- return rb_convert_to_integer(arg, 0, TRUE);
-}
+#define opts_exception_p(opts) rb_opts_exception_p((opts), TRUE)
+
+/*
+ * call-seq:
+ * Integer(object, base = 0, exception: true) -> integer or nil
+ *
+ * Returns an integer converted from +object+.
+ *
+ * Tries to convert +object+ to an integer
+ * using +to_int+ first and +to_i+ second;
+ * see below for exceptions.
+ *
+ * With a non-zero +base+, +object+ must be a string or convertible
+ * to a string.
+ *
+ * ==== numeric objects
+ *
+ * With integer argument +object+ given, returns +object+:
+ *
+ * Integer(1) # => 1
+ * Integer(-1) # => -1
+ *
+ * With floating-point argument +object+ given,
+ * returns +object+ truncated to an intger:
+ *
+ * Integer(1.9) # => 1 # Rounds toward zero.
+ * Integer(-1.9) # => -1 # Rounds toward zero.
+ *
+ * ==== string objects
+ *
+ * With string argument +object+ and zero +base+ given,
+ * returns +object+ converted to an integer in base 10:
+ *
+ * Integer('100') # => 100
+ * Integer('-100') # => -100
+ *
+ * With +base+ zero, string +object+ may contain leading characters
+ * to specify the actual base (radix indicator):
+ *
+ * Integer('0100') # => 64 # Leading '0' specifies base 8.
+ * Integer('0b100') # => 4 # Leading '0b', specifies base 2.
+ * Integer('0x100') # => 256 # Leading '0x' specifies base 16.
+ *
+ * With a positive +base+ (in range 2..36) given, returns +object+
+ * converted to an integer in the given base:
+ *
+ * Integer('100', 2) # => 4
+ * Integer('100', 8) # => 64
+ * Integer('-100', 16) # => -256
+ *
+ * With a negative +base+ (in range -36..-2) given, returns +object+
+ * converted to an integer in the radix indicator if exists or
+ * +-base+:
+ *
+ * Integer('0x100', -2) # => 256
+ * Integer('100', -2) # => 4
+ * Integer('0b100', -8) # => 4
+ * Integer('100', -8) # => 64
+ * Integer('0o100', -10) # => 64
+ * Integer('100', -10) # => 100
+ *
+ * +base+ -1 is equal the -10 case.
+ *
+ * When converting strings, surrounding whitespace and embedded underscores
+ * are allowed and ignored:
+ *
+ * Integer(' 100 ') # => 100
+ * Integer('-1_0_0', 16) # => -256
+ *
+ * ==== other classes
+ *
+ * Examples with +object+ of various other classes:
+ *
+ * Integer(Rational(9, 10)) # => 0 # Rounds toward zero.
+ * Integer(Complex(2, 0)) # => 2 # Imaginary part must be zero.
+ * Integer(Time.now) # => 1650974042
+ *
+ * ==== keywords
+ *
+ * With optional keyword argument +exception+ given as +true+ (the default):
+ *
+ * - Raises TypeError if +object+ does not respond to +to_int+ or +to_i+.
+ * - Raises TypeError if +object+ is +nil+.
+ * - Raise ArgumentError if +object+ is an invalid string.
+ *
+ * With +exception+ given as +false+, an exception of any kind is suppressed
+ * and +nil+ is returned.
+ *
+ */
static VALUE
-rb_f_integer(rb_execution_context_t *ec, VALUE obj, VALUE arg, VALUE base, VALUE exception)
+rb_f_integer(int argc, VALUE *argv, VALUE obj)
{
- int exc = rb_bool_expected(exception, "exception", TRUE);
- return rb_convert_to_integer(arg, NUM2INT(base), exc);
+ VALUE arg = Qnil, opts = Qnil;
+ int base = 0;
+
+ if (argc > 1) {
+ int narg = 1;
+ VALUE vbase = rb_check_to_int(argv[1]);
+ if (!NIL_P(vbase)) {
+ base = NUM2INT(vbase);
+ narg = 2;
+ }
+ if (argc > narg) {
+ VALUE hash = rb_check_hash_type(argv[argc-1]);
+ if (!NIL_P(hash)) {
+ opts = rb_extract_keywords(&hash);
+ if (!hash) --argc;
+ }
+ }
+ }
+ rb_check_arity(argc, 1, 2);
+ arg = argv[0];
+
+ return rb_convert_to_integer(arg, base, opts_exception_p(opts));
}
static double
@@ -3479,6 +3475,7 @@ rb_str_to_dbl_raise(VALUE str, int badcheck, int raise, int *error)
VALUE v = 0;
StringValue(str);
+ rb_must_asciicompat(str);
s = RSTRING_PTR(str);
len = RSTRING_LEN(str);
if (s) {
@@ -3938,6 +3935,9 @@ rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound)
*
* For details on +format_string+, see
* {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ *
+ * Kernel#format is an alias for Kernel#sprintf.
+ *
*/
static VALUE
@@ -4163,7 +4163,7 @@ f_sprintf(int c, const VALUE *v, VALUE _)
* and frozen state.
* - #define_singleton_method: Defines a singleton method in +self+
* for the given symbol method-name and block or proc.
- * - #display: Prints +self+ to the given IO stream or <tt>$stdout</tt>.
+ * - #display: Prints +self+ to the given \IO stream or <tt>$stdout</tt>.
* - #dup: Returns a shallow unfrozen copy of +self+.
* - #enum_for (aliased as #to_enum): Returns an Enumerator for +self+
* using the using the given method, arguments, and block.
@@ -4179,6 +4179,27 @@ f_sprintf(int c, const VALUE *v, VALUE _)
*
*/
+/*!
+ *--
+ * \private
+ * Initializes the world of objects and classes.
+ *
+ * At first, the function bootstraps the class hierarchy.
+ * It initializes the most fundamental classes and their metaclasses.
+ * - \c BasicObject
+ * - \c Object
+ * - \c Module
+ * - \c Class
+ * After the bootstrap step, the class hierarchy becomes as the following
+ * diagram.
+ *
+ * \image html boottime-classes.png
+ *
+ * Then, the function defines classes, modules and methods as usual.
+ * \ingroup class
+ *++
+ */
+
void
InitVM_Object(void)
{
@@ -4394,6 +4415,8 @@ InitVM_Object(void)
rb_define_global_function("sprintf", f_sprintf, -1);
rb_define_global_function("format", f_sprintf, -1);
+ rb_define_global_function("Integer", rb_f_integer, -1);
+
rb_define_global_function("String", rb_f_string, 1);
rb_define_global_function("Array", rb_f_array, 1);
rb_define_global_function("Hash", rb_f_hash, 1);
@@ -4429,7 +4452,6 @@ InitVM_Object(void)
rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */
rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */
rb_define_method(rb_cModule, "name", rb_mod_name, 0); /* in variable.c */
- rb_define_method(rb_cModule, "set_temporary_name", rb_mod_set_temporary_name, 1); /* in variable.c */
rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */
rb_define_method(rb_cModule, "attr", rb_mod_attr, -1);
diff --git a/pack.c b/pack.c
index 4fdaf7fd89..3bdae01362 100644
--- a/pack.c
+++ b/pack.c
@@ -36,11 +36,10 @@
*/
#ifdef HAVE_TRUE_LONG_LONG
static const char natstr[] = "sSiIlLqQjJ";
-# define endstr natstr
#else
static const char natstr[] = "sSiIlLjJ";
-static const char endstr[] = "sSiIlLqQjJ";
#endif
+static const char endstr[] = "sSiIlLqQjJ";
#ifdef HAVE_TRUE_LONG_LONG
/* It is intentional to use long long instead of LONG_LONG. */
@@ -155,7 +154,6 @@ associated_pointer(VALUE associates, const char *t)
UNREACHABLE_RETURN(Qnil);
}
-RBIMPL_ATTR_NORETURN()
static void
unknown_directive(const char *mode, char type, VALUE fmt)
{
@@ -169,7 +167,7 @@ unknown_directive(const char *mode, char type, VALUE fmt)
snprintf(unknown, sizeof(unknown), "\\x%.2x", type & 0xff);
}
fmt = rb_str_quote_unprintable(fmt);
- rb_raise(rb_eArgError, "unknown %s directive '%s' in '%"PRIsVALUE"'",
+ rb_warn("unknown %s directive '%s' in '%"PRIsVALUE"'",
mode, unknown, fmt);
}
@@ -538,7 +536,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
bigendian_p = explicit_endian == '>';
}
if (integer_size > MAX_INTEGER_PACK_SIZE)
- rb_bug("unexpected integer size for pack: %d", integer_size);
+ rb_bug("unexpected intger size for pack: %d", integer_size);
while (len-- > 0) {
char intbuf[MAX_INTEGER_PACK_SIZE];
diff --git a/parse.y b/parse.y
index caddbcc178..1c808bd60e 100644
--- a/parse.y
+++ b/parse.y
@@ -22,29 +22,13 @@
#define YYLTYPE rb_code_location_t
#define YYLTYPE_IS_DECLARED 1
-/* For Ripper */
-#ifdef RUBY_EXTCONF_H
-# include RUBY_EXTCONF_H
-#endif
-
#include "ruby/internal/config.h"
+#include <ctype.h>
#include <errno.h>
+#include <stdio.h>
-#ifdef UNIVERSAL_PARSER
-
-#include "internal/ruby_parser.h"
-#include "parser_node.h"
-#include "universal_parser.c"
-
-#ifdef RIPPER
-#undef T_NODE
-#define T_NODE 0x1b
-#define STATIC_ID2SYM p->config->static_id2sym
-#define rb_str_coderange_scan_restartable p->config->str_coderange_scan_restartable
-#endif
-
-#else
+struct lex_context;
#include "internal.h"
#include "internal/compile.h"
@@ -59,12 +43,10 @@
#include "internal/parse.h"
#include "internal/rational.h"
#include "internal/re.h"
-#include "internal/ruby_parser.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "node.h"
-#include "parser_node.h"
#include "probes.h"
#include "regenc.h"
#include "ruby/encoding.h"
@@ -75,177 +57,6 @@
#include "ruby/ractor.h"
#include "symbol.h"
-#ifndef RIPPER
-static void
-bignum_negate(VALUE b)
-{
- BIGNUM_NEGATE(b);
-}
-
-static void
-rational_set_num(VALUE r, VALUE n)
-{
- RATIONAL_SET_NUM(r, n);
-}
-
-static VALUE
-rational_get_num(VALUE obj)
-{
- return RRATIONAL(obj)->num;
-}
-
-static void
-rcomplex_set_real(VALUE cmp, VALUE r)
-{
- RCOMPLEX_SET_REAL(cmp, r);
-}
-
-static VALUE
-rcomplex_get_real(VALUE obj)
-{
- return RCOMPLEX(obj)->real;
-}
-
-static void
-rcomplex_set_imag(VALUE cmp, VALUE i)
-{
- RCOMPLEX_SET_IMAG(cmp, i);
-}
-
-static VALUE
-rcomplex_get_imag(VALUE obj)
-{
- return RCOMPLEX(obj)->imag;
-}
-
-static bool
-hash_literal_key_p(VALUE k)
-{
- switch (OBJ_BUILTIN_TYPE(k)) {
- case T_NODE:
- return false;
- default:
- return true;
- }
-}
-
-static int
-literal_cmp(VALUE val, VALUE lit)
-{
- if (val == lit) return 0;
- if (!hash_literal_key_p(val) || !hash_literal_key_p(lit)) return -1;
- return rb_iseq_cdhash_cmp(val, lit);
-}
-
-static st_index_t
-literal_hash(VALUE a)
-{
- if (!hash_literal_key_p(a)) return (st_index_t)a;
- return rb_iseq_cdhash_hash(a);
-}
-
-static VALUE
-syntax_error_new(void)
-{
- return rb_class_new_instance(0, 0, rb_eSyntaxError);
-}
-
-static NODE *reg_named_capture_assign(struct parser_params* p, VALUE regexp, const YYLTYPE *loc);
-#endif /* !RIPPER */
-
-#define compile_callback rb_suppress_tracing
-VALUE rb_io_gets_internal(VALUE io);
-
-VALUE rb_node_case_when_optimizable_literal(const NODE *const node);
-#endif /* !UNIVERSAL_PARSER */
-
-static inline int
-parse_isascii(int c)
-{
- return '\0' <= c && c <= '\x7f';
-}
-
-#undef ISASCII
-#define ISASCII parse_isascii
-
-static inline int
-parse_isspace(int c)
-{
- return c == ' ' || ('\t' <= c && c <= '\r');
-}
-
-#undef ISSPACE
-#define ISSPACE parse_isspace
-
-static inline int
-parse_iscntrl(int c)
-{
- return ('\0' <= c && c < ' ') || c == '\x7f';
-}
-
-#undef ISCNTRL
-#define ISCNTRL(c) parse_iscntrl(c)
-
-static inline int
-parse_isupper(int c)
-{
- return 'A' <= c && c <= 'Z';
-}
-
-static inline int
-parse_islower(int c)
-{
- return 'a' <= c && c <= 'z';
-}
-
-static inline int
-parse_isalpha(int c)
-{
- return parse_isupper(c) || parse_islower(c);
-}
-
-#undef ISALPHA
-#define ISALPHA(c) parse_isalpha(c)
-
-static inline int
-parse_isdigit(int c)
-{
- return '0' <= c && c <= '9';
-}
-
-#undef ISDIGIT
-#define ISDIGIT(c) parse_isdigit(c)
-
-static inline int
-parse_isalnum(int c)
-{
- return parse_isalpha(c) || parse_isdigit(c);
-}
-
-#undef ISALNUM
-#define ISALNUM(c) parse_isalnum(c)
-
-static inline int
-parse_isxdigit(int c)
-{
- return parse_isdigit(c) || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f');
-}
-
-#undef ISXDIGIT
-#define ISXDIGIT(c) parse_isxdigit(c)
-
-#include "parser_st.h"
-
-#undef STRCASECMP
-#define STRCASECMP rb_parser_st_locale_insensitive_strcasecmp
-
-#undef STRNCASECMP
-#define STRNCASECMP rb_parser_st_locale_insensitive_strncasecmp
-
-#ifdef RIPPER
-#include "ripper_init.h"
-#endif
-
enum shareability {
shareable_none,
shareable_literal,
@@ -253,13 +64,6 @@ enum shareability {
shareable_everything,
};
-enum rescue_context {
- before_rescue,
- after_rescue,
- after_else,
- after_ensure,
-};
-
struct lex_context {
unsigned int in_defined: 1;
unsigned int in_kwarg: 1;
@@ -267,12 +71,8 @@ struct lex_context {
unsigned int in_def: 1;
unsigned int in_class: 1;
BITFIELD(enum shareability, shareable_constant_value, 2);
- BITFIELD(enum rescue_context, in_rescue, 2);
};
-typedef struct RNode_DEF_TEMP rb_node_def_temp_t;
-typedef struct RNode_EXITS rb_node_exits_t;
-
#if defined(__GNUC__) && !defined(__clang__)
// Suppress "parameter passing for argument of type 'struct
// lex_context' changed" notes. `struct lex_context` is file scope,
@@ -301,18 +101,18 @@ RBIMPL_WARNING_POP()
#define YYREALLOC(ptr, size) rb_parser_realloc(p, (ptr), (size))
#define YYCALLOC(nelem, size) rb_parser_calloc(p, (nelem), (size))
#define YYFREE(ptr) rb_parser_free(p, (ptr))
-#define YYFPRINTF(out, ...) rb_parser_printf(p, __VA_ARGS__)
-#define YY_LOCATION_PRINT(File, loc, p) \
+#define YYFPRINTF rb_parser_printf
+#define YY_LOCATION_PRINT(File, loc) \
rb_parser_printf(p, "%d.%d-%d.%d", \
- (loc).beg_pos.lineno, (loc).beg_pos.column,\
- (loc).end_pos.lineno, (loc).end_pos.column)
+ (loc).beg_pos.lineno, (loc).beg_pos.column,\
+ (loc).end_pos.lineno, (loc).end_pos.column)
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
if (N) \
- { \
- (Current).beg_pos = YYRHSLOC(Rhs, 1).beg_pos; \
- (Current).end_pos = YYRHSLOC(Rhs, N).end_pos; \
- } \
+ { \
+ (Current).beg_pos = YYRHSLOC(Rhs, 1).beg_pos; \
+ (Current).end_pos = YYRHSLOC(Rhs, N).end_pos; \
+ } \
else \
{ \
(Current).beg_pos = YYRHSLOC(Rhs, 0).end_pos; \
@@ -337,10 +137,48 @@ RBIMPL_WARNING_POP()
rb_parser_set_location(p, &(Current))
#define RUBY_INIT_YYLLOC() \
{ \
- {p->ruby_sourceline, (int)(p->lex.ptok - p->lex.pbeg)}, \
- {p->ruby_sourceline, (int)(p->lex.pcur - p->lex.pbeg)}, \
- }
-
+ {p->ruby_sourceline, (int)(p->lex.ptok - p->lex.pbeg)}, \
+ {p->ruby_sourceline, (int)(p->lex.pcur - p->lex.pbeg)}, \
+ }
+
+enum lex_state_bits {
+ EXPR_BEG_bit, /* ignore newline, +/- is a sign. */
+ EXPR_END_bit, /* newline significant, +/- is an operator. */
+ EXPR_ENDARG_bit, /* ditto, and unbound braces. */
+ EXPR_ENDFN_bit, /* ditto, and unbound braces. */
+ EXPR_ARG_bit, /* newline significant, +/- is an operator. */
+ EXPR_CMDARG_bit, /* newline significant, +/- is an operator. */
+ EXPR_MID_bit, /* newline significant, +/- is an operator. */
+ EXPR_FNAME_bit, /* ignore newline, no reserved words. */
+ EXPR_DOT_bit, /* right after `.' or `::', no reserved words. */
+ EXPR_CLASS_bit, /* immediate after `class', no here document. */
+ EXPR_LABEL_bit, /* flag bit, label is allowed. */
+ EXPR_LABELED_bit, /* flag bit, just after a label. */
+ EXPR_FITEM_bit, /* symbol literal as FNAME. */
+ EXPR_MAX_STATE
+};
+/* examine combinations */
+enum lex_state_e {
+#define DEF_EXPR(n) EXPR_##n = (1 << EXPR_##n##_bit)
+ DEF_EXPR(BEG),
+ DEF_EXPR(END),
+ DEF_EXPR(ENDARG),
+ DEF_EXPR(ENDFN),
+ DEF_EXPR(ARG),
+ DEF_EXPR(CMDARG),
+ DEF_EXPR(MID),
+ DEF_EXPR(FNAME),
+ DEF_EXPR(DOT),
+ DEF_EXPR(CLASS),
+ DEF_EXPR(LABEL),
+ DEF_EXPR(LABELED),
+ DEF_EXPR(FITEM),
+ EXPR_VALUE = EXPR_BEG,
+ EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS),
+ EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG),
+ EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN),
+ EXPR_NONE = 0
+};
#define IS_lex_state_for(x, ls) ((x) & (ls))
#define IS_lex_state_all_for(x, ls) (((x) & (ls)) == (ls))
#define IS_lex_state(ls) IS_lex_state_for(p->lex.state, (ls))
@@ -391,7 +229,7 @@ struct local_vars {
struct local_vars *prev;
# ifndef RIPPER
struct {
- NODE *outer, *inner, *current;
+ NODE *outer, *inner, *current;
} numparam;
# endif
};
@@ -402,6 +240,18 @@ enum {
NUMPARAM_MAX = 9,
};
+#define NUMPARAM_ID_P(id) numparam_id_p(id)
+#define NUMPARAM_ID_TO_IDX(id) (unsigned int)(((id) >> ID_SCOPE_SHIFT) - (tNUMPARAM_1 - 1))
+#define NUMPARAM_IDX_TO_ID(idx) TOKEN2LOCALID((tNUMPARAM_1 - 1 + (idx)))
+static int
+numparam_id_p(ID id)
+{
+ if (!is_local_id(id) || id < (tNUMPARAM_1 << ID_SCOPE_SHIFT)) return 0;
+ unsigned int idx = NUMPARAM_ID_TO_IDX(id);
+ return idx > 0 && idx <= NUMPARAM_MAX;
+}
+static void numparam_name(struct parser_params *p, ID id);
+
#define DVARS_INHERIT ((void*)1)
#define DVARS_TOPSCOPE NULL
#define DVARS_TERMINAL_P(tbl) ((tbl) == DVARS_INHERIT || (tbl) == DVARS_TOPSCOPE)
@@ -414,6 +264,8 @@ typedef struct token_info {
struct token_info *next;
} token_info;
+typedef struct rb_strterm_struct rb_strterm_t;
+
/*
Structure of Lexer Buffer:
@@ -430,31 +282,32 @@ struct parser_params {
YYLTYPE *yylloc;
struct {
- rb_strterm_t *strterm;
- VALUE (*gets)(struct parser_params*,VALUE);
- VALUE input;
- VALUE lastline;
- VALUE nextline;
- const char *pbeg;
- const char *pcur;
- const char *pend;
- const char *ptok;
- union {
- long ptr;
- VALUE (*call)(VALUE, int);
- } gets_;
- enum lex_state_e state;
- /* track the nest level of any parens "()[]{}" */
- int paren_nest;
- /* keep p->lex.paren_nest at the beginning of lambda "->" to detect tLAMBEG and keyword_do_LAMBDA */
- int lpar_beg;
- /* track the nest level of only braces "{}" */
- int brace_nest;
+ rb_strterm_t *strterm;
+ VALUE (*gets)(struct parser_params*,VALUE);
+ VALUE input;
+ VALUE lastline;
+ VALUE nextline;
+ const char *pbeg;
+ const char *pcur;
+ const char *pend;
+ const char *ptok;
+ union {
+ long ptr;
+ VALUE (*call)(VALUE, int);
+ } gets_;
+ enum lex_state_e state;
+ /* track the nest level of any parens "()[]{}" */
+ int paren_nest;
+ /* keep p->lex.paren_nest at the beginning of lambda "->" to detect tLAMBEG and keyword_do_LAMBDA */
+ int lpar_beg;
+ /* track the nest level of only braces "{}" */
+ int brace_nest;
} lex;
stack_type cond_stack;
stack_type cmdarg_stack;
int tokidx;
int toksiz;
+ int tokline;
int heredoc_end;
int heredoc_indent;
int heredoc_line_indent;
@@ -469,17 +322,17 @@ struct parser_params {
rb_encoding *enc;
token_info *token_info;
VALUE case_labels;
- rb_node_exits_t *exits;
+ VALUE compile_option;
VALUE debug_buffer;
VALUE debug_output;
struct {
- VALUE token;
- int beg_line;
- int beg_col;
- int end_line;
- int end_col;
+ VALUE token;
+ int beg_line;
+ int beg_col;
+ int end_line;
+ int end_col;
} delayed;
ID cur_arg;
@@ -491,12 +344,6 @@ struct parser_params {
struct lex_context ctxt;
-#ifdef UNIVERSAL_PARSER
- rb_parser_config_t *config;
-#endif
- /* compile_option */
- signed int frozen_string_literal:2; /* -1: not specified, 0: false, 1: true */
-
unsigned int command_start:1;
unsigned int eofp: 1;
unsigned int ruby__end__seen: 1;
@@ -517,6 +364,7 @@ struct parser_params {
unsigned int do_loop: 1;
unsigned int do_chomp: 1;
unsigned int do_split: 1;
+ unsigned int keep_script_lines: 1;
unsigned int error_tolerant: 1;
unsigned int keep_tokens: 1;
@@ -540,27 +388,21 @@ struct parser_params {
#endif
};
-#define NUMPARAM_ID_P(id) numparam_id_p(p, id)
-#define NUMPARAM_ID_TO_IDX(id) (unsigned int)(((id) >> ID_SCOPE_SHIFT) - (tNUMPARAM_1 - 1))
-#define NUMPARAM_IDX_TO_ID(idx) TOKEN2LOCALID((tNUMPARAM_1 - 1 + (idx)))
-static int
-numparam_id_p(struct parser_params *p, ID id)
-{
- if (!is_local_id(id) || id < (tNUMPARAM_1 << ID_SCOPE_SHIFT)) return 0;
- unsigned int idx = NUMPARAM_ID_TO_IDX(id);
- return idx > 0 && idx <= NUMPARAM_MAX;
-}
-static void numparam_name(struct parser_params *p, ID id);
-
-
#define intern_cstr(n,l,en) rb_intern3(n,l,en)
#define STR_NEW(ptr,len) rb_enc_str_new((ptr),(len),p->enc)
#define STR_NEW0() rb_enc_str_new(0,0,p->enc)
#define STR_NEW2(ptr) rb_enc_str_new((ptr),strlen(ptr),p->enc)
-#define STR_NEW3(ptr,len,e,func) parser_str_new(p, (ptr),(len),(e),(func),p->enc)
+#define STR_NEW3(ptr,len,e,func) parser_str_new((ptr),(len),(e),(func),p->enc)
#define TOK_INTERN() intern_cstr(tok(p), toklen(p), p->enc)
-#define VALID_SYMNAME_P(s, l, enc, type) (rb_enc_symname_type(s, l, enc, (1U<<(type))) == (int)(type))
+
+static st_table *
+push_pvtbl(struct parser_params *p)
+{
+ st_table *tbl = p->pvtbl;
+ p->pvtbl = st_init_numtable();
+ return tbl;
+}
static void
pop_pvtbl(struct parser_params *p, st_table *tbl)
@@ -569,6 +411,14 @@ pop_pvtbl(struct parser_params *p, st_table *tbl)
p->pvtbl = tbl;
}
+static st_table *
+push_pktbl(struct parser_params *p)
+{
+ st_table *tbl = p->pktbl;
+ p->pktbl = 0;
+ return tbl;
+}
+
static void
pop_pktbl(struct parser_params *p, st_table *tbl)
{
@@ -613,7 +463,7 @@ peek_end_expect_token_locations(struct parser_params *p)
}
static ID
-parser_token2id(struct parser_params *p, enum yytokentype tok)
+parser_token2id(enum yytokentype tok)
{
switch ((int) tok) {
#define TOKEN2ID(tok) case tok: return rb_intern(#tok);
@@ -645,7 +495,6 @@ parser_token2id(struct parser_params *p, enum yytokentype tok)
TOKEN2ID2(']', "]");
TOKEN2ID2('(', "(");
TOKEN2ID2(')', ")");
- TOKEN2ID2('\\', "backslash");
TOKEN2ID(keyword_class);
TOKEN2ID(keyword_module);
TOKEN2ID(keyword_def);
@@ -794,10 +643,8 @@ static int parser_yyerror0(struct parser_params*, const char*);
#define yyerror(yylloc, p, msg) parser_yyerror(p, yylloc, msg)
#define token_flush(ptr) ((ptr)->lex.ptok = (ptr)->lex.pcur)
#define lex_goto_eol(p) ((p)->lex.pcur = (p)->lex.pend)
-#define lex_eol_p(p) lex_eol_n_p(p, 0)
-#define lex_eol_n_p(p,n) lex_eol_ptr_n_p(p, (p)->lex.pcur, n)
-#define lex_eol_ptr_p(p,ptr) lex_eol_ptr_n_p(p,ptr,0)
-#define lex_eol_ptr_n_p(p,ptr,n) ((ptr)+(n) >= (p)->lex.pend)
+#define lex_eol_p(p) ((p)->lex.pcur >= (p)->lex.pend)
+#define lex_eol_n_p(p,n) ((p)->lex.pcur+(n) >= (p)->lex.pend)
static void token_info_setup(token_info *ptinfo, const char *ptr, const rb_code_location_t *loc);
static void token_info_push(struct parser_params*, const char *token, const rb_code_location_t *loc);
@@ -814,7 +661,8 @@ static void token_info_drop(struct parser_params *p, const char *token, rb_code_
#define token_column ((int)(p->lex.ptok - p->lex.pbeg))
#define CALL_Q_P(q) ((q) == TOKEN2VAL(tANDDOT))
-#define NEW_QCALL(q,r,m,a,loc) (CALL_Q_P(q) ? NEW_QCALL0(r,m,a,loc) : NEW_CALL(r,m,a,loc))
+#define NODE_CALL_Q(q) (CALL_Q_P(q) ? NODE_QCALL : NODE_CALL)
+#define NEW_QCALL(q,r,m,a,loc) NEW_NODE(NODE_CALL_Q(q),r,m,a,loc)
#define lambda_beginning_p() (p->lex.lpar_beg == p->lex.paren_nest)
@@ -833,281 +681,23 @@ static inline VALUE
add_mark_object(struct parser_params *p, VALUE obj)
{
if (!SPECIAL_CONST_P(obj)
- && !RB_TYPE_P(obj, T_NODE) /* Ripper jumbles NODE objects and other objects... */
+ && !RB_TYPE_P(obj, T_NODE) /* Ripper jumbles NODE objects and other objects... */
) {
- rb_ast_add_mark_object(p->ast, obj);
+ rb_ast_add_mark_object(p->ast, obj);
}
return obj;
}
-
-static rb_node_ripper_t *rb_node_ripper_new(struct parser_params *p, ID a, VALUE b, VALUE c, const YYLTYPE *loc);
-static rb_node_ripper_values_t *rb_node_ripper_values_new(struct parser_params *p, VALUE a, VALUE b, VALUE c, const YYLTYPE *loc);
-#define NEW_RIPPER(a,b,c,loc) (VALUE)rb_node_ripper_new(p,a,b,c,loc)
-#define NEW_RIPPER_VALUES(a,b,c,loc) (VALUE)rb_node_ripper_values_new(p,a,b,c,loc)
-
-#else
-static rb_node_scope_t *rb_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_scope_t *rb_node_scope_new2(struct parser_params *p, rb_ast_id_table_t *nd_tbl, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_block_t *rb_node_block_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_if_t *rb_node_if_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc);
-static rb_node_unless_t *rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc);
-static rb_node_case_t *rb_node_case_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_case2_t *rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_case3_t *rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_when_t *rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_in_t *rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_while_t *rb_node_while_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc);
-static rb_node_until_t *rb_node_until_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc);
-static rb_node_iter_t *rb_node_iter_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_for_t *rb_node_for_new(struct parser_params *p, NODE *nd_iter, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_for_masgn_t *rb_node_for_masgn_new(struct parser_params *p, NODE *nd_var, const YYLTYPE *loc);
-static rb_node_retry_t *rb_node_retry_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_begin_t *rb_node_begin_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_rescue_t *rb_node_rescue_new(struct parser_params *p, NODE *nd_head, NODE *nd_resq, NODE *nd_else, const YYLTYPE *loc);
-static rb_node_resbody_t *rb_node_resbody_new(struct parser_params *p, NODE *nd_args, NODE *nd_body, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_ensure_t *rb_node_ensure_new(struct parser_params *p, NODE *nd_head, NODE *nd_ensr, const YYLTYPE *loc);
-static rb_node_and_t *rb_node_and_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc);
-static rb_node_or_t *rb_node_or_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc);
-static rb_node_masgn_t *rb_node_masgn_new(struct parser_params *p, NODE *nd_head, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_lasgn_t *rb_node_lasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_dasgn_t *rb_node_dasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_gasgn_t *rb_node_gasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_iasgn_t *rb_node_iasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_cdecl_t *rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, const YYLTYPE *loc);
-static rb_node_cvasgn_t *rb_node_cvasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_op_asgn1_t *rb_node_op_asgn1_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *index, NODE *rvalue, const YYLTYPE *loc);
-static rb_node_op_asgn2_t *rb_node_op_asgn2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, ID nd_vid, ID nd_mid, bool nd_aid, const YYLTYPE *loc);
-static rb_node_op_asgn_or_t *rb_node_op_asgn_or_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_op_asgn_and_t *rb_node_op_asgn_and_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_op_cdecl_t *rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, const YYLTYPE *loc);
-static rb_node_call_t *rb_node_call_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_opcall_t *rb_node_opcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_fcall_t *rb_node_fcall_new(struct parser_params *p, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_vcall_t *rb_node_vcall_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc);
-static rb_node_qcall_t *rb_node_qcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_super_t *rb_node_super_new(struct parser_params *p, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_zsuper_t * rb_node_zsuper_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_list_t *rb_node_list_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_list_t *rb_node_list_new2(struct parser_params *p, NODE *nd_head, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_zlist_t *rb_node_zlist_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_hash_t *rb_node_hash_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_return_t *rb_node_return_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc);
-static rb_node_yield_t *rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_lvar_t *rb_node_lvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_dvar_t *rb_node_dvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_gvar_t *rb_node_gvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_ivar_t *rb_node_ivar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_const_t *rb_node_const_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_cvar_t *rb_node_cvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_nth_ref_t *rb_node_nth_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc);
-static rb_node_back_ref_t *rb_node_back_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc);
-static rb_node_match2_t *rb_node_match2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_match3_t *rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_lit_t *rb_node_lit_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc);
-static rb_node_str_t *rb_node_str_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc);
-static rb_node_dstr_t *rb_node_dstr_new0(struct parser_params *p, VALUE nd_lit, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_dstr_t *rb_node_dstr_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc);
-static rb_node_xstr_t *rb_node_xstr_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc);
-static rb_node_dxstr_t *rb_node_dxstr_new(struct parser_params *p, VALUE nd_lit, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_evstr_t *rb_node_evstr_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_once_t *rb_node_once_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_args_t *rb_node_args_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_args_aux_t *rb_node_args_aux_new(struct parser_params *p, ID nd_pid, long nd_plen, const YYLTYPE *loc);
-static rb_node_opt_arg_t *rb_node_opt_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_kw_arg_t *rb_node_kw_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_postarg_t *rb_node_postarg_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc);
-static rb_node_argscat_t *rb_node_argscat_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_argspush_t *rb_node_argspush_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_splat_t *rb_node_splat_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_block_pass_t *rb_node_block_pass_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_defn_t *rb_node_defn_new(struct parser_params *p, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc);
-static rb_node_defs_t *rb_node_defs_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc);
-static rb_node_alias_t *rb_node_alias_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc);
-static rb_node_valias_t *rb_node_valias_new(struct parser_params *p, ID nd_alias, ID nd_orig, const YYLTYPE *loc);
-static rb_node_undef_t *rb_node_undef_new(struct parser_params *p, NODE *nd_undef, const YYLTYPE *loc);
-static rb_node_class_t *rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc);
-static rb_node_module_t *rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_sclass_t *rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_colon2_t *rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc);
-static rb_node_colon3_t *rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc);
-static rb_node_dot2_t *rb_node_dot2_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc);
-static rb_node_dot3_t *rb_node_dot3_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc);
-static rb_node_self_t *rb_node_self_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_nil_t *rb_node_nil_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_true_t *rb_node_true_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_false_t *rb_node_false_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_errinfo_t *rb_node_errinfo_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_defined_t *rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_postexe_t *rb_node_postexe_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_dsym_t *rb_node_dsym_new(struct parser_params *p, VALUE nd_lit, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_attrasgn_t *rb_node_attrasgn_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_lambda_t *rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_aryptn_t *rb_node_aryptn_new(struct parser_params *p, NODE *pre_args, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc);
-static rb_node_hshptn_t *rb_node_hshptn_new(struct parser_params *p, NODE *nd_pconst, NODE *nd_pkwargs, NODE *nd_pkwrestarg, const YYLTYPE *loc);
-static rb_node_fndptn_t *rb_node_fndptn_new(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
-static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE *loc);
-
-#define NEW_SCOPE(a,b,loc) (NODE *)rb_node_scope_new(p,a,b,loc)
-#define NEW_SCOPE2(t,a,b,loc) (NODE *)rb_node_scope_new2(p,t,a,b,loc)
-#define NEW_BLOCK(a,loc) (NODE *)rb_node_block_new(p,a,loc)
-#define NEW_IF(c,t,e,loc) (NODE *)rb_node_if_new(p,c,t,e,loc)
-#define NEW_UNLESS(c,t,e,loc) (NODE *)rb_node_unless_new(p,c,t,e,loc)
-#define NEW_CASE(h,b,loc) (NODE *)rb_node_case_new(p,h,b,loc)
-#define NEW_CASE2(b,loc) (NODE *)rb_node_case2_new(p,b,loc)
-#define NEW_CASE3(h,b,loc) (NODE *)rb_node_case3_new(p,h,b,loc)
-#define NEW_WHEN(c,t,e,loc) (NODE *)rb_node_when_new(p,c,t,e,loc)
-#define NEW_IN(c,t,e,loc) (NODE *)rb_node_in_new(p,c,t,e,loc)
-#define NEW_WHILE(c,b,n,loc) (NODE *)rb_node_while_new(p,c,b,n,loc)
-#define NEW_UNTIL(c,b,n,loc) (NODE *)rb_node_until_new(p,c,b,n,loc)
-#define NEW_ITER(a,b,loc) (NODE *)rb_node_iter_new(p,a,b,loc)
-#define NEW_FOR(i,b,loc) (NODE *)rb_node_for_new(p,i,b,loc)
-#define NEW_FOR_MASGN(v,loc) (NODE *)rb_node_for_masgn_new(p,v,loc)
-#define NEW_RETRY(loc) (NODE *)rb_node_retry_new(p,loc)
-#define NEW_BEGIN(b,loc) (NODE *)rb_node_begin_new(p,b,loc)
-#define NEW_RESCUE(b,res,e,loc) (NODE *)rb_node_rescue_new(p,b,res,e,loc)
-#define NEW_RESBODY(a,ex,n,loc) (NODE *)rb_node_resbody_new(p,a,ex,n,loc)
-#define NEW_ENSURE(b,en,loc) (NODE *)rb_node_ensure_new(p,b,en,loc)
-#define NEW_AND(f,s,loc) (NODE *)rb_node_and_new(p,f,s,loc)
-#define NEW_OR(f,s,loc) (NODE *)rb_node_or_new(p,f,s,loc)
-#define NEW_MASGN(l,r,loc) rb_node_masgn_new(p,l,r,loc)
-#define NEW_LASGN(v,val,loc) (NODE *)rb_node_lasgn_new(p,v,val,loc)
-#define NEW_DASGN(v,val,loc) (NODE *)rb_node_dasgn_new(p,v,val,loc)
-#define NEW_GASGN(v,val,loc) (NODE *)rb_node_gasgn_new(p,v,val,loc)
-#define NEW_IASGN(v,val,loc) (NODE *)rb_node_iasgn_new(p,v,val,loc)
-#define NEW_CDECL(v,val,path,loc) (NODE *)rb_node_cdecl_new(p,v,val,path,loc)
-#define NEW_CVASGN(v,val,loc) (NODE *)rb_node_cvasgn_new(p,v,val,loc)
-#define NEW_OP_ASGN1(r,id,idx,rval,loc) (NODE *)rb_node_op_asgn1_new(p,r,id,idx,rval,loc)
-#define NEW_OP_ASGN2(r,t,i,o,val,loc) (NODE *)rb_node_op_asgn2_new(p,r,val,i,o,t,loc)
-#define NEW_OP_ASGN_OR(i,val,loc) (NODE *)rb_node_op_asgn_or_new(p,i,val,loc)
-#define NEW_OP_ASGN_AND(i,val,loc) (NODE *)rb_node_op_asgn_and_new(p,i,val,loc)
-#define NEW_OP_CDECL(v,op,val,loc) (NODE *)rb_node_op_cdecl_new(p,v,val,op,loc)
-#define NEW_CALL(r,m,a,loc) (NODE *)rb_node_call_new(p,r,m,a,loc)
-#define NEW_OPCALL(r,m,a,loc) (NODE *)rb_node_opcall_new(p,r,m,a,loc)
-#define NEW_FCALL(m,a,loc) rb_node_fcall_new(p,m,a,loc)
-#define NEW_VCALL(m,loc) (NODE *)rb_node_vcall_new(p,m,loc)
-#define NEW_QCALL0(r,m,a,loc) (NODE *)rb_node_qcall_new(p,r,m,a,loc)
-#define NEW_SUPER(a,loc) (NODE *)rb_node_super_new(p,a,loc)
-#define NEW_ZSUPER(loc) (NODE *)rb_node_zsuper_new(p,loc)
-#define NEW_LIST(a,loc) (NODE *)rb_node_list_new(p,a,loc)
-#define NEW_LIST2(h,l,n,loc) (NODE *)rb_node_list_new2(p,h,l,n,loc)
-#define NEW_ZLIST(loc) (NODE *)rb_node_zlist_new(p,loc)
-#define NEW_HASH(a,loc) (NODE *)rb_node_hash_new(p,a,loc)
-#define NEW_RETURN(s,loc) (NODE *)rb_node_return_new(p,s,loc)
-#define NEW_YIELD(a,loc) (NODE *)rb_node_yield_new(p,a,loc)
-#define NEW_LVAR(v,loc) (NODE *)rb_node_lvar_new(p,v,loc)
-#define NEW_DVAR(v,loc) (NODE *)rb_node_dvar_new(p,v,loc)
-#define NEW_GVAR(v,loc) (NODE *)rb_node_gvar_new(p,v,loc)
-#define NEW_IVAR(v,loc) (NODE *)rb_node_ivar_new(p,v,loc)
-#define NEW_CONST(v,loc) (NODE *)rb_node_const_new(p,v,loc)
-#define NEW_CVAR(v,loc) (NODE *)rb_node_cvar_new(p,v,loc)
-#define NEW_NTH_REF(n,loc) (NODE *)rb_node_nth_ref_new(p,n,loc)
-#define NEW_BACK_REF(n,loc) (NODE *)rb_node_back_ref_new(p,n,loc)
-#define NEW_MATCH2(n1,n2,loc) (NODE *)rb_node_match2_new(p,n1,n2,loc)
-#define NEW_MATCH3(r,n2,loc) (NODE *)rb_node_match3_new(p,r,n2,loc)
-#define NEW_LIT(l,loc) (NODE *)rb_node_lit_new(p,l,loc)
-#define NEW_STR(s,loc) (NODE *)rb_node_str_new(p,s,loc)
-#define NEW_DSTR0(s,l,n,loc) (NODE *)rb_node_dstr_new0(p,s,l,n,loc)
-#define NEW_DSTR(s,loc) (NODE *)rb_node_dstr_new(p,s,loc)
-#define NEW_XSTR(s,loc) (NODE *)rb_node_xstr_new(p,s,loc)
-#define NEW_DXSTR(s,l,n,loc) (NODE *)rb_node_dxstr_new(p,s,l,n,loc)
-#define NEW_EVSTR(n,loc) (NODE *)rb_node_evstr_new(p,n,loc)
-#define NEW_ONCE(b,loc) (NODE *)rb_node_once_new(p,b,loc)
-#define NEW_ARGS(loc) rb_node_args_new(p,loc)
-#define NEW_ARGS_AUX(r,b,loc) rb_node_args_aux_new(p,r,b,loc)
-#define NEW_OPT_ARG(v,loc) rb_node_opt_arg_new(p,v,loc)
-#define NEW_KW_ARG(v,loc) rb_node_kw_arg_new(p,v,loc)
-#define NEW_POSTARG(i,v,loc) (NODE *)rb_node_postarg_new(p,i,v,loc)
-#define NEW_ARGSCAT(a,b,loc) (NODE *)rb_node_argscat_new(p,a,b,loc)
-#define NEW_ARGSPUSH(a,b,loc) (NODE *)rb_node_argspush_new(p,a,b,loc)
-#define NEW_SPLAT(a,loc) (NODE *)rb_node_splat_new(p,a,loc)
-#define NEW_BLOCK_PASS(b,loc) rb_node_block_pass_new(p,b,loc)
-#define NEW_DEFN(i,s,loc) (NODE *)rb_node_defn_new(p,i,s,loc)
-#define NEW_DEFS(r,i,s,loc) (NODE *)rb_node_defs_new(p,r,i,s,loc)
-#define NEW_ALIAS(n,o,loc) (NODE *)rb_node_alias_new(p,n,o,loc)
-#define NEW_VALIAS(n,o,loc) (NODE *)rb_node_valias_new(p,n,o,loc)
-#define NEW_UNDEF(i,loc) (NODE *)rb_node_undef_new(p,i,loc)
-#define NEW_CLASS(n,b,s,loc) (NODE *)rb_node_class_new(p,n,b,s,loc)
-#define NEW_MODULE(n,b,loc) (NODE *)rb_node_module_new(p,n,b,loc)
-#define NEW_SCLASS(r,b,loc) (NODE *)rb_node_sclass_new(p,r,b,loc)
-#define NEW_COLON2(c,i,loc) (NODE *)rb_node_colon2_new(p,c,i,loc)
-#define NEW_COLON3(i,loc) (NODE *)rb_node_colon3_new(p,i,loc)
-#define NEW_DOT2(b,e,loc) (NODE *)rb_node_dot2_new(p,b,e,loc)
-#define NEW_DOT3(b,e,loc) (NODE *)rb_node_dot3_new(p,b,e,loc)
-#define NEW_SELF(loc) (NODE *)rb_node_self_new(p,loc)
-#define NEW_NIL(loc) (NODE *)rb_node_nil_new(p,loc)
-#define NEW_TRUE(loc) (NODE *)rb_node_true_new(p,loc)
-#define NEW_FALSE(loc) (NODE *)rb_node_false_new(p,loc)
-#define NEW_ERRINFO(loc) (NODE *)rb_node_errinfo_new(p,loc)
-#define NEW_DEFINED(e,loc) (NODE *)rb_node_defined_new(p,e,loc)
-#define NEW_POSTEXE(b,loc) (NODE *)rb_node_postexe_new(p,b,loc)
-#define NEW_DSYM(s,l,n,loc) (NODE *)rb_node_dsym_new(p,s,l,n,loc)
-#define NEW_ATTRASGN(r,m,a,loc) (NODE *)rb_node_attrasgn_new(p,r,m,a,loc)
-#define NEW_LAMBDA(a,b,loc) (NODE *)rb_node_lambda_new(p,a,b,loc)
-#define NEW_ARYPTN(pre,r,post,loc) (NODE *)rb_node_aryptn_new(p,pre,r,post,loc)
-#define NEW_HSHPTN(c,kw,kwrest,loc) (NODE *)rb_node_hshptn_new(p,c,kw,kwrest,loc)
-#define NEW_FNDPTN(pre,a,post,loc) (NODE *)rb_node_fndptn_new(p,pre,a,post,loc)
-#define NEW_ERROR(loc) (NODE *)rb_node_error_new(p,loc)
-
-#endif
-
-enum internal_node_type {
- NODE_INTERNAL_ONLY = NODE_LAST,
- NODE_DEF_TEMP,
- NODE_EXITS,
- NODE_INTERNAL_LAST
-};
-
-static const char *
-parser_node_name(int node)
-{
- switch (node) {
- case NODE_DEF_TEMP:
- return "NODE_DEF_TEMP";
- case NODE_EXITS:
- return "NODE_EXITS";
- default:
- return ruby_node_name(node);
- }
-}
-
-/* This node is parse.y internal */
-struct RNode_DEF_TEMP {
- NODE node;
-
- /* for NODE_DEFN/NODE_DEFS */
-#ifndef RIPPER
- struct RNode *nd_def;
- ID nd_mid;
#else
- VALUE nd_recv;
- VALUE nd_mid;
- VALUE dot_or_colon;
+static NODE* node_newnode_with_locals(struct parser_params *, enum node_type, VALUE, VALUE, const rb_code_location_t*);
#endif
- struct {
- ID cur_arg;
- int max_numparam;
- NODE *numparam_save;
- struct lex_context ctxt;
- } save;
-};
-
-#define RNODE_DEF_TEMP(node) ((struct RNode_DEF_TEMP *)(node))
+static NODE* node_newnode(struct parser_params *, enum node_type, VALUE, VALUE, VALUE, const rb_code_location_t*);
+#define rb_node_newnode(type, a1, a2, a3, loc) node_newnode(p, (type), (a1), (a2), (a3), (loc))
-static rb_node_break_t *rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc);
-static rb_node_next_t *rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc);
-static rb_node_redo_t *rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_def_temp_t *rb_node_def_temp_new(struct parser_params *p, const YYLTYPE *loc);
-
-#define NEW_BREAK(s,loc) (NODE *)rb_node_break_new(p,s,loc)
-#define NEW_NEXT(s,loc) (NODE *)rb_node_next_new(p,s,loc)
-#define NEW_REDO(loc) (NODE *)rb_node_redo_new(p,loc)
-#define NEW_DEF_TEMP(loc) rb_node_def_temp_new(p,loc)
-
-/* Make a new internal node, which should not be appeared in the
+/* Make a new temporal node, which should not be appeared in the
* result AST and does not have node_id and location. */
-static NODE* node_new_internal(struct parser_params *p, enum node_type type, size_t size, size_t alignment);
-#define NODE_NEW_INTERNAL(ndtype, type) (type *)node_new_internal(p, (enum node_type)(ndtype), sizeof(type), RUBY_ALIGNOF(type))
+static NODE* node_new_temporal(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2);
+#define NODE_NEW_TEMPORAL(t,a0,a1,a2) node_new_temporal(p, (t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
static NODE *nd_set_loc(NODE *nd, const YYLTYPE *loc);
@@ -1119,14 +709,6 @@ parser_get_node_id(struct parser_params *p)
return node_id;
}
-static void
-anddot_multiple_assignment_check(struct parser_params* p, const YYLTYPE *loc, ID id)
-{
- if (id == tANDDOT) {
- yyerror1(loc, "&. inside multiple assignment destination");
- }
-}
-
#ifndef RIPPER
static inline void
set_line_body(NODE *body, int line)
@@ -1135,24 +717,8 @@ set_line_body(NODE *body, int line)
switch (nd_type(body)) {
case NODE_RESCUE:
case NODE_ENSURE:
- nd_set_line(body, line);
- }
-}
-
-static void
-set_embraced_location(NODE *node, const rb_code_location_t *beg, const rb_code_location_t *end)
-{
- RNODE_ITER(node)->nd_body->nd_loc = code_loc_gen(beg, end);
- nd_set_line(node, beg->end_pos.lineno);
-}
-
-static NODE *
-last_expr_node(NODE *expr)
-{
- if (nd_type_p(expr, NODE_BLOCK)) {
- expr = RNODE_BLOCK(RNODE_BLOCK(expr)->nd_end)->nd_head;
+ nd_set_line(body, line);
}
- return expr;
}
#define yyparse ruby_yyparse
@@ -1186,7 +752,6 @@ static NODE *rest_arg_append(struct parser_params *p, NODE *args, NODE *rest_arg
static NODE *literal_concat(struct parser_params*,NODE*,NODE*,const YYLTYPE*);
static NODE *new_evstr(struct parser_params*,NODE*,const YYLTYPE*);
static NODE *new_dstr(struct parser_params*,NODE*,const YYLTYPE*);
-static NODE *str2dstr(struct parser_params*,NODE*);
static NODE *evstr2dstr(struct parser_params*,NODE*);
static NODE *splat_array(NODE*);
static void mark_lvar_used(struct parser_params *p, NODE *rhs);
@@ -1195,24 +760,24 @@ static NODE *call_bin_op(struct parser_params*,NODE*,ID,NODE*,const YYLTYPE*,con
static NODE *call_uni_op(struct parser_params*,NODE*,ID,const YYLTYPE*,const YYLTYPE*);
static NODE *new_qcall(struct parser_params* p, ID atype, NODE *recv, ID mid, NODE *args, const YYLTYPE *op_loc, const YYLTYPE *loc);
static NODE *new_command_qcall(struct parser_params* p, ID atype, NODE *recv, ID mid, NODE *args, NODE *block, const YYLTYPE *op_loc, const YYLTYPE *loc);
-static NODE *method_add_block(struct parser_params*p, NODE *m, NODE *b, const YYLTYPE *loc) {RNODE_ITER(b)->nd_iter = m; b->nd_loc = *loc; return b;}
+static NODE *method_add_block(struct parser_params*p, NODE *m, NODE *b, const YYLTYPE *loc) {b->nd_iter = m; b->nd_loc = *loc; return b;}
static bool args_info_empty_p(struct rb_args_info *args);
-static rb_node_args_t *new_args(struct parser_params*,rb_node_args_aux_t*,rb_node_opt_arg_t*,ID,rb_node_args_aux_t*,rb_node_args_t*,const YYLTYPE*);
-static rb_node_args_t *new_args_tail(struct parser_params*,rb_node_kw_arg_t*,ID,ID,const YYLTYPE*);
+static NODE *new_args(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*,const YYLTYPE*);
+static NODE *new_args_tail(struct parser_params*,NODE*,ID,ID,const YYLTYPE*);
static NODE *new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *aryptn, const YYLTYPE *loc);
-static NODE *new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc);
+static NODE *new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID rest_arg, NODE *post_args, const YYLTYPE *loc);
static NODE *new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc);
-static NODE *new_find_pattern_tail(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
+static NODE *new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc);
static NODE *new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc);
static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, const YYLTYPE *loc);
-static rb_node_kw_arg_t *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
-static rb_node_args_t *args_with_numbered(struct parser_params*,rb_node_args_t*,int);
+static NODE *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
+static NODE *args_with_numbered(struct parser_params*,NODE*,int);
static VALUE negate_lit(struct parser_params*, VALUE);
static NODE *ret_args(struct parser_params*,NODE*);
-static NODE *arg_blk_pass(NODE*,rb_node_block_pass_t*);
+static NODE *arg_blk_pass(NODE*,NODE*);
static NODE *new_yield(struct parser_params*,NODE*,const YYLTYPE*);
static NODE *dsym_node(struct parser_params*,NODE*,const YYLTYPE*);
@@ -1233,8 +798,8 @@ static NODE *new_bodystmt(struct parser_params *p, NODE *head, NODE *rescue, NOD
static NODE *const_decl(struct parser_params *p, NODE* path, const YYLTYPE *loc);
-static rb_node_opt_arg_t *opt_arg_append(rb_node_opt_arg_t*, rb_node_opt_arg_t*);
-static rb_node_kw_arg_t *kwd_append(rb_node_kw_arg_t*, rb_node_kw_arg_t*);
+static NODE *opt_arg_append(NODE*, NODE*);
+static NODE *kwd_append(NODE*, NODE*);
static NODE *new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc);
static NODE *new_unique_key_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc);
@@ -1256,6 +821,7 @@ static rb_ast_id_table_t *local_tbl(struct parser_params*);
static VALUE reg_compile(struct parser_params*, VALUE, int);
static void reg_fragment_setenc(struct parser_params*, VALUE, int);
static int reg_fragment_check(struct parser_params*, VALUE, int);
+static NODE *reg_named_capture_assign(struct parser_params* p, VALUE regexp, const YYLTYPE *loc);
static int literal_concat0(struct parser_params *p, VALUE head, VALUE tail);
static NODE *heredoc_dedent(struct parser_params*,NODE*);
@@ -1266,29 +832,22 @@ static void check_literal_when(struct parser_params *p, NODE *args, const YYLTYP
#define get_value(val) (val)
#define get_num(num) (num)
#else /* RIPPER */
+#define NODE_RIPPER NODE_CDECL
+#define NEW_RIPPER(a,b,c,loc) (VALUE)NEW_CDECL(a,b,c,loc)
-static inline int ripper_is_node_yylval(struct parser_params *p, VALUE n);
+static inline int ripper_is_node_yylval(VALUE n);
static inline VALUE
ripper_new_yylval(struct parser_params *p, ID a, VALUE b, VALUE c)
{
- if (ripper_is_node_yylval(p, c)) c = RNODE_RIPPER(c)->nd_cval;
+ if (ripper_is_node_yylval(c)) c = RNODE(c)->nd_cval;
add_mark_object(p, b);
add_mark_object(p, c);
return NEW_RIPPER(a, b, c, &NULL_LOC);
}
-static inline VALUE
-ripper_new_yylval2(struct parser_params *p, VALUE a, VALUE b, VALUE c)
-{
- add_mark_object(p, a);
- add_mark_object(p, b);
- add_mark_object(p, c);
- return NEW_RIPPER_VALUES(a, b, c, &NULL_LOC);
-}
-
static inline int
-ripper_is_node_yylval(struct parser_params *p, VALUE n)
+ripper_is_node_yylval(VALUE n)
{
return RB_TYPE_P(n, T_NODE) && nd_type_p(RNODE(n), NODE_RIPPER);
}
@@ -1296,11 +855,11 @@ ripper_is_node_yylval(struct parser_params *p, VALUE n)
#define value_expr(node) ((void)(node))
#define remove_begin(node) (node)
#define void_stmts(p,x) (x)
-#undef rb_dvar_defined
#define rb_dvar_defined(id, base) 0
-#undef rb_local_defined
#define rb_local_defined(id, base) 0
+static ID ripper_get_id(VALUE);
#define get_id(id) ripper_get_id(id)
+static VALUE ripper_get_value(VALUE);
#define get_value(val) ripper_get_value(val)
#define get_num(num) (int)get_id(num)
static VALUE assignable(struct parser_params*,VALUE);
@@ -1326,11 +885,14 @@ static VALUE parser_reg_compile(struct parser_params*, VALUE, int, VALUE *);
static VALUE backref_error(struct parser_params*, NODE *, VALUE);
#endif /* !RIPPER */
+/* forward declaration */
+typedef struct rb_strterm_heredoc_struct rb_strterm_heredoc_t;
+
RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_parser_reg_compile(struct parser_params* p, VALUE str, int options);
int rb_reg_fragment_setenc(struct parser_params*, VALUE, int);
enum lex_state_e rb_parser_trace_lex_state(struct parser_params *, enum lex_state_e, enum lex_state_e, int);
-VALUE rb_parser_lex_state_name(struct parser_params *p, enum lex_state_e state);
+VALUE rb_parser_lex_state_name(enum lex_state_e state);
void rb_parser_show_bitstack(struct parser_params *, stack_type, const char *, int);
PRINTF_ARGS(void rb_parser_fatal(struct parser_params *p, const char *fmt, ...), 2, 3);
YYLTYPE *rb_parser_set_location_from_strterm_heredoc(struct parser_params *p, rb_strterm_heredoc_t *here, YYLTYPE *yylloc);
@@ -1387,11 +949,6 @@ static void numparam_pop(struct parser_params *p, NODE *prev_inner);
#define idFWD_KWREST idPow /* Use simple "**", as tDSTAR is "**arg" */
#define idFWD_BLOCK '&'
#define idFWD_ALL idDot3
-#ifdef RIPPER
-#define arg_FWD_BLOCK Qnone
-#else
-#define arg_FWD_BLOCK idFWD_BLOCK
-#endif
#define FORWARD_ARGS_WITH_RUBY2_KEYWORDS
#define RE_OPTION_ONCE (1<<16)
@@ -1402,6 +959,72 @@ static void numparam_pop(struct parser_params *p, NODE *prev_inner);
#define RE_OPTION_MASK 0xff
#define RE_OPTION_ARG_ENCODING_NONE 32
+/* structs for managing terminator of string literal and heredocment */
+typedef struct rb_strterm_literal_struct {
+ union {
+ VALUE dummy;
+ long nest;
+ } u0;
+ union {
+ VALUE dummy;
+ long func; /* STR_FUNC_* (e.g., STR_FUNC_ESCAPE and STR_FUNC_EXPAND) */
+ } u1;
+ union {
+ VALUE dummy;
+ long paren; /* '(' of `%q(...)` */
+ } u2;
+ union {
+ VALUE dummy;
+ long term; /* ')' of `%q(...)` */
+ } u3;
+} rb_strterm_literal_t;
+
+#define HERETERM_LENGTH_BITS ((SIZEOF_VALUE - 1) * CHAR_BIT - 1)
+
+struct rb_strterm_heredoc_struct {
+ VALUE lastline; /* the string of line that contains `<<"END"` */
+ long offset; /* the column of END in `<<"END"` */
+ int sourceline; /* lineno of the line that contains `<<"END"` */
+ unsigned length /* the length of END in `<<"END"` */
+#if HERETERM_LENGTH_BITS < SIZEOF_INT * CHAR_BIT
+ : HERETERM_LENGTH_BITS
+# define HERETERM_LENGTH_MAX ((1U << HERETERM_LENGTH_BITS) - 1)
+#else
+# define HERETERM_LENGTH_MAX UINT_MAX
+#endif
+ ;
+#if HERETERM_LENGTH_BITS < SIZEOF_INT * CHAR_BIT
+ unsigned quote: 1;
+ unsigned func: 8;
+#else
+ uint8_t quote;
+ uint8_t func;
+#endif
+};
+STATIC_ASSERT(rb_strterm_heredoc_t, sizeof(rb_strterm_heredoc_t) <= 4 * SIZEOF_VALUE);
+
+#define STRTERM_HEREDOC IMEMO_FL_USER0
+
+struct rb_strterm_struct {
+ VALUE flags;
+ union {
+ rb_strterm_literal_t literal;
+ rb_strterm_heredoc_t heredoc;
+ } u;
+};
+
+#ifndef RIPPER
+void
+rb_strterm_mark(VALUE obj)
+{
+ rb_strterm_t *strterm = (rb_strterm_t*)obj;
+ if (RBASIC(obj)->flags & STRTERM_HEREDOC) {
+ rb_strterm_heredoc_t *heredoc = &strterm->u.heredoc;
+ rb_gc_mark(heredoc->lastline);
+ }
+}
+#endif
+
#define yytnamerr(yyres, yystr) (YYSIZE_T)rb_yytnamerr(p, yyres, yystr)
size_t rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr);
@@ -1417,11 +1040,12 @@ size_t rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr);
/****** Ripper *******/
#ifdef RIPPER
+#define RIPPER_VERSION "0.1.0"
-#include "eventids1.h"
-#include "eventids2.h"
+static inline VALUE intern_sym(const char *name);
-extern const struct ripper_parser_ids ripper_parser_ids;
+#include "eventids1.c"
+#include "eventids2.c"
static VALUE ripper_dispatch0(struct parser_params*,ID);
static VALUE ripper_dispatch1(struct parser_params*,ID,VALUE);
@@ -1430,7 +1054,7 @@ static VALUE ripper_dispatch3(struct parser_params*,ID,VALUE,VALUE,VALUE);
static VALUE ripper_dispatch4(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE);
static VALUE ripper_dispatch5(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE,VALUE);
static VALUE ripper_dispatch7(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE);
-void ripper_error(struct parser_params *p);
+static void ripper_error(struct parser_params *p);
#define dispatch0(n) ripper_dispatch0(p, TOKEN_PASTE(ripper_id_, n))
#define dispatch1(n,a) ripper_dispatch1(p, TOKEN_PASTE(ripper_id_, n), (a))
@@ -1449,18 +1073,24 @@ void ripper_error(struct parser_params *p);
#define params_new(pars, opts, rest, pars2, kws, kwrest, blk) \
dispatch7(params, (pars), (opts), (rest), (pars2), (kws), (kwrest), (blk))
+#define escape_Qundef(x) ((x)==Qundef ? Qnil : (x))
+
static inline VALUE
new_args(struct parser_params *p, VALUE pre_args, VALUE opt_args, VALUE rest_arg, VALUE post_args, VALUE tail, YYLTYPE *loc)
{
- struct RNode_RIPPER_VALUES *t = RNODE_RIPPER_VALUES(tail);
- VALUE kw_args = t->nd_val1, kw_rest_arg = t->nd_val2, block = t->nd_val3;
- return params_new(pre_args, opt_args, rest_arg, post_args, kw_args, kw_rest_arg, block);
+ NODE *t = (NODE *)tail;
+ VALUE kw_args = t->u1.value, kw_rest_arg = t->u2.value, block = t->u3.value;
+ return params_new(pre_args, opt_args, rest_arg, post_args, kw_args, kw_rest_arg, escape_Qundef(block));
}
static inline VALUE
new_args_tail(struct parser_params *p, VALUE kw_args, VALUE kw_rest_arg, VALUE block, YYLTYPE *loc)
{
- return ripper_new_yylval2(p, kw_args, kw_rest_arg, block);
+ NODE *t = rb_node_newnode(NODE_ARGS_AUX, kw_args, kw_rest_arg, block, &NULL_LOC);
+ add_mark_object(p, kw_args);
+ add_mark_object(p, kw_rest_arg);
+ add_mark_object(p, block);
+ return (VALUE)t;
}
static inline VALUE
@@ -1472,16 +1102,16 @@ args_with_numbered(struct parser_params *p, VALUE args, int max_numparam)
static VALUE
new_array_pattern(struct parser_params *p, VALUE constant, VALUE pre_arg, VALUE aryptn, const YYLTYPE *loc)
{
- struct RNode_RIPPER_VALUES *t = RNODE_RIPPER_VALUES(aryptn);
- VALUE pre_args = t->nd_val1, rest_arg = t->nd_val2, post_args = t->nd_val3;
+ NODE *t = (NODE *)aryptn;
+ VALUE pre_args = t->u1.value, rest_arg = t->u2.value, post_args = t->u3.value;
if (!NIL_P(pre_arg)) {
- if (!NIL_P(pre_args)) {
- rb_ary_unshift(pre_args, pre_arg);
- }
- else {
- pre_args = rb_ary_new_from_args(1, pre_arg);
- }
+ if (!NIL_P(pre_args)) {
+ rb_ary_unshift(pre_args, pre_arg);
+ }
+ else {
+ pre_args = rb_ary_new_from_args(1, pre_arg);
+ }
}
return dispatch4(aryptn, constant, pre_args, rest_arg, post_args);
}
@@ -1489,14 +1119,27 @@ new_array_pattern(struct parser_params *p, VALUE constant, VALUE pre_arg, VALUE
static VALUE
new_array_pattern_tail(struct parser_params *p, VALUE pre_args, VALUE has_rest, VALUE rest_arg, VALUE post_args, const YYLTYPE *loc)
{
- return ripper_new_yylval2(p, pre_args, rest_arg, post_args);
+ NODE *t;
+
+ if (has_rest) {
+ rest_arg = dispatch1(var_field, rest_arg ? rest_arg : Qnil);
+ }
+ else {
+ rest_arg = Qnil;
+ }
+
+ t = rb_node_newnode(NODE_ARYPTN, pre_args, rest_arg, post_args, &NULL_LOC);
+ add_mark_object(p, pre_args);
+ add_mark_object(p, rest_arg);
+ add_mark_object(p, post_args);
+ return (VALUE)t;
}
static VALUE
new_find_pattern(struct parser_params *p, VALUE constant, VALUE fndptn, const YYLTYPE *loc)
{
- struct RNode_RIPPER_VALUES *t = RNODE_RIPPER_VALUES(fndptn);
- VALUE pre_rest_arg = t->nd_val1, args = t->nd_val2, post_rest_arg = t->nd_val3;
+ NODE *t = (NODE *)fndptn;
+ VALUE pre_rest_arg = t->u1.value, args = t->u2.value, post_rest_arg = t->u3.value;
return dispatch4(fndptn, constant, pre_rest_arg, args, post_rest_arg);
}
@@ -1504,7 +1147,16 @@ new_find_pattern(struct parser_params *p, VALUE constant, VALUE fndptn, const YY
static VALUE
new_find_pattern_tail(struct parser_params *p, VALUE pre_rest_arg, VALUE args, VALUE post_rest_arg, const YYLTYPE *loc)
{
- return ripper_new_yylval2(p, pre_rest_arg, args, post_rest_arg);
+ NODE *t;
+
+ pre_rest_arg = dispatch1(var_field, pre_rest_arg ? pre_rest_arg : Qnil);
+ post_rest_arg = dispatch1(var_field, post_rest_arg ? post_rest_arg : Qnil);
+
+ t = rb_node_newnode(NODE_FNDPTN, pre_rest_arg, args, post_rest_arg, &NULL_LOC);
+ add_mark_object(p, pre_rest_arg);
+ add_mark_object(p, args);
+ add_mark_object(p, post_rest_arg);
+ return (VALUE)t;
}
#define new_hash(p,h,l) rb_ary_new_from_args(0)
@@ -1518,21 +1170,26 @@ new_unique_key_hash(struct parser_params *p, VALUE ary, const YYLTYPE *loc)
static VALUE
new_hash_pattern(struct parser_params *p, VALUE constant, VALUE hshptn, const YYLTYPE *loc)
{
- struct RNode_RIPPER_VALUES *t = RNODE_RIPPER_VALUES(hshptn);
- VALUE kw_args = t->nd_val1, kw_rest_arg = t->nd_val2;
+ NODE *t = (NODE *)hshptn;
+ VALUE kw_args = t->u1.value, kw_rest_arg = t->u2.value;
return dispatch3(hshptn, constant, kw_args, kw_rest_arg);
}
static VALUE
new_hash_pattern_tail(struct parser_params *p, VALUE kw_args, VALUE kw_rest_arg, const YYLTYPE *loc)
{
+ NODE *t;
if (kw_rest_arg) {
- kw_rest_arg = dispatch1(var_field, kw_rest_arg);
+ kw_rest_arg = dispatch1(var_field, kw_rest_arg);
}
else {
- kw_rest_arg = Qnil;
+ kw_rest_arg = Qnil;
}
- return ripper_new_yylval2(p, kw_args, kw_rest_arg, Qnil);
+ t = rb_node_newnode(NODE_HSHPTN, kw_args, kw_rest_arg, 0, &NULL_LOC);
+
+ add_mark_object(p, kw_args);
+ add_mark_object(p, kw_rest_arg);
+ return (VALUE)t;
}
#define new_defined(p,expr,loc) dispatch1(defined, (expr))
@@ -1545,19 +1202,20 @@ static VALUE heredoc_dedent(struct parser_params*,VALUE);
#define KWD2EID(t, v) keyword_##t
static NODE *
-new_scope_body(struct parser_params *p, rb_node_args_t *args, NODE *body, const YYLTYPE *loc)
+set_defun_body(struct parser_params *p, NODE *n, NODE *args, NODE *body, const YYLTYPE *loc)
{
body = remove_begin(body);
reduce_nodes(p, &body);
- NODE *n = NEW_SCOPE(args, body, loc);
- nd_set_line(n, loc->end_pos.lineno);
+ n->nd_defn = NEW_SCOPE(args, body, loc);
+ n->nd_loc = *loc;
+ nd_set_line(n->nd_defn, loc->end_pos.lineno);
set_line_body(body, loc->beg_pos.lineno);
return n;
}
static NODE *
rescued_expr(struct parser_params *p, NODE *arg, NODE *rescue,
- const YYLTYPE *arg_loc, const YYLTYPE *mod_loc, const YYLTYPE *res_loc)
+ const YYLTYPE *arg_loc, const YYLTYPE *mod_loc, const YYLTYPE *res_loc)
{
YYLTYPE loc = code_loc_gen(mod_loc, res_loc);
rescue = NEW_RESBODY(0, remove_begin(rescue), 0, &loc);
@@ -1567,62 +1225,32 @@ rescued_expr(struct parser_params *p, NODE *arg, NODE *rescue,
#endif /* RIPPER */
-static NODE *add_block_exit(struct parser_params *p, NODE *node);
-static rb_node_exits_t *init_block_exit(struct parser_params *p);
-static rb_node_exits_t *allow_block_exit(struct parser_params *p);
-static void restore_block_exit(struct parser_params *p, rb_node_exits_t *exits);
-static void clear_block_exit(struct parser_params *p, bool error);
-
-static void
-next_rescue_context(struct lex_context *next, const struct lex_context *outer, enum rescue_context def)
-{
- next->in_rescue = outer->in_rescue == after_rescue ? after_rescue : def;
-}
-
static void
-restore_defun(struct parser_params *p, rb_node_def_temp_t *temp)
+restore_defun(struct parser_params *p, NODE *name)
{
- /* See: def_name action */
- struct lex_context ctxt = temp->save.ctxt;
- p->cur_arg = temp->save.cur_arg;
- p->ctxt.in_def = ctxt.in_def;
- p->ctxt.shareable_constant_value = ctxt.shareable_constant_value;
- p->ctxt.in_rescue = ctxt.in_rescue;
- p->max_numparam = temp->save.max_numparam;
- numparam_pop(p, temp->save.numparam_save);
- clear_block_exit(p, true);
+ NODE *save = name->nd_next;
+ YYSTYPE c = {.val = save->nd_cval};
+ p->cur_arg = name->nd_vid;
+ p->ctxt.in_def = c.ctxt.in_def;
+ p->ctxt.shareable_constant_value = c.ctxt.shareable_constant_value;
+ p->max_numparam = (int)save->nd_nth;
+ numparam_pop(p, save->nd_head);
}
static void
-endless_method_name(struct parser_params *p, ID mid, const YYLTYPE *loc)
+endless_method_name(struct parser_params *p, NODE *defn, const YYLTYPE *loc)
{
+#ifdef RIPPER
+ defn = defn->nd_defn;
+#endif
+ ID mid = defn->nd_mid;
if (is_attrset_id(mid)) {
- yyerror1(loc, "setter method cannot be defined in an endless method definition");
+ yyerror1(loc, "setter method cannot be defined in an endless method definition");
}
token_info_drop(p, "def", loc->beg_pos);
}
-#define debug_token_line(p, name, line) do { \
- if (p->debug) { \
- const char *const pcur = p->lex.pcur; \
- const char *const ptok = p->lex.ptok; \
- rb_parser_printf(p, name ":%d (%d: %"PRIdPTRDIFF"|%"PRIdPTRDIFF"|%"PRIdPTRDIFF")\n", \
- line, p->ruby_sourceline, \
- ptok - p->lex.pbeg, pcur - ptok, p->lex.pend - pcur); \
- } \
- } while (0)
-
-#define begin_definition(k, loc_beg, loc_end) \
- do { \
- if (!(p->ctxt.in_class = (k)[0] != 0)) { \
- p->ctxt.in_def = 0; \
- } \
- else if (p->ctxt.in_def) { \
- YYLTYPE loc = code_loc_gen(loc_beg, loc_end); \
- yyerror1(&loc, k " definition in method body"); \
- } \
- local_push(p, 0); \
- } while (0)
+#define debug_token_line(p, name, line) if (p->debug) rb_parser_printf(p, name ":%d (%d: %ld|%ld|%ld)\n", line, p->ruby_sourceline, p->lex.ptok - p->lex.pbeg, p->lex.pcur - p->lex.ptok, p->lex.pend - p->lex.pcur)
#ifndef RIPPER
# define Qnone 0
@@ -1655,7 +1283,7 @@ endless_method_name(struct parser_params *p, ID mid, const YYLTYPE *loc)
# define rb_warning3L(l,fmt,a,b,c) WARNING_CALL(WARNING_ARGS_L(l, fmt, 4), (a), (b), (c))
# define rb_warning4L(l,fmt,a,b,c,d) WARNING_CALL(WARNING_ARGS_L(l, fmt, 5), (a), (b), (c), (d))
#ifdef RIPPER
-extern const ID id_warn, id_warning, id_gets, id_assoc;
+static ID id_warn, id_warning, id_gets, id_assoc;
# define ERR_MESG() STR_NEW2(mesg) /* to bypass Ripper DSL */
# define WARN_S_L(s,l) STR_NEW(s,l)
# define WARN_S(s) STR_NEW2(s)
@@ -1678,6 +1306,7 @@ extern const ID id_warn, id_warning, id_gets, id_assoc;
# else
# define WARNING_CALL rb_funcall
# endif
+PRINTF_ARGS(static void ripper_compile_error(struct parser_params*, const char *fmt, ...), 2, 3);
# define compile_error ripper_compile_error
#else
# define WARN_S_L(s,l) s
@@ -1693,205 +1322,15 @@ extern const ID id_warn, id_warning, id_gets, id_assoc;
# define WARNING_ARGS(fmt,n) WARN_ARGS(fmt,n)
# define WARNING_ARGS_L(l,fmt,n) WARN_ARGS_L(l,fmt,n)
# define WARNING_CALL rb_compile_warning
-PRINTF_ARGS(static void parser_compile_error(struct parser_params*, const rb_code_location_t *loc, const char *fmt, ...), 3, 4);
-# define compile_error(p, ...) parser_compile_error(p, NULL, __VA_ARGS__)
+PRINTF_ARGS(static void parser_compile_error(struct parser_params*, const char *fmt, ...), 2, 3);
+# define compile_error parser_compile_error
#endif
-struct RNode_EXITS {
- NODE node;
-
- NODE *nd_chain; /* Assume NODE_BREAK, NODE_NEXT, NODE_REDO have nd_chain here */
- NODE *nd_end;
-};
-
-#define RNODE_EXITS(node) ((rb_node_exits_t*)(node))
-
-static NODE *
-add_block_exit(struct parser_params *p, NODE *node)
-{
- if (!node) {
- compile_error(p, "unexpected null node");
- return 0;
- }
- switch (nd_type(node)) {
- case NODE_BREAK: case NODE_NEXT: case NODE_REDO: break;
- default:
- compile_error(p, "unexpected node: %s", parser_node_name(nd_type(node)));
- return node;
- }
- if (!p->ctxt.in_defined) {
- rb_node_exits_t *exits = p->exits;
- if (exits) {
- RNODE_EXITS(exits->nd_end)->nd_chain = node;
- exits->nd_end = node;
- }
- }
- return node;
-}
-
-static rb_node_exits_t *
-init_block_exit(struct parser_params *p)
-{
- rb_node_exits_t *old = p->exits;
- rb_node_exits_t *exits = NODE_NEW_INTERNAL(NODE_EXITS, rb_node_exits_t);
- exits->nd_chain = 0;
- exits->nd_end = RNODE(exits);
- p->exits = exits;
- return old;
-}
-
-static rb_node_exits_t *
-allow_block_exit(struct parser_params *p)
-{
- rb_node_exits_t *exits = p->exits;
- p->exits = 0;
- return exits;
-}
-
-static void
-restore_block_exit(struct parser_params *p, rb_node_exits_t *exits)
-{
- p->exits = exits;
-}
-
-static void
-clear_block_exit(struct parser_params *p, bool error)
-{
- rb_node_exits_t *exits = p->exits;
- if (!exits) return;
- if (error && !compile_for_eval) {
- for (NODE *e = RNODE(exits); (e = RNODE_EXITS(e)->nd_chain) != 0; ) {
- switch (nd_type(e)) {
- case NODE_BREAK:
- yyerror1(&e->nd_loc, "Invalid break");
- break;
- case NODE_NEXT:
- yyerror1(&e->nd_loc, "Invalid next");
- break;
- case NODE_REDO:
- yyerror1(&e->nd_loc, "Invalid redo");
- break;
- default:
- yyerror1(&e->nd_loc, "unexpected node");
- goto end_checks; /* no nd_chain */
- }
- }
- end_checks:;
- }
- exits->nd_end = RNODE(exits);
- exits->nd_chain = 0;
-}
-
#define WARN_EOL(tok) \
(looking_at_eol_p(p) ? \
(void)rb_warning0("`" tok "' at the end of line without an expression") : \
(void)0)
static int looking_at_eol_p(struct parser_params *p);
-
-#ifndef RIPPER
-static NODE *
-get_nd_value(struct parser_params *p, NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_GASGN:
- return RNODE_GASGN(node)->nd_value;
- case NODE_IASGN:
- return RNODE_IASGN(node)->nd_value;
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_value;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_value;
- case NODE_MASGN:
- return RNODE_MASGN(node)->nd_value;
- case NODE_CVASGN:
- return RNODE_CVASGN(node)->nd_value;
- case NODE_CDECL:
- return RNODE_CDECL(node)->nd_value;
- default:
- compile_error(p, "unexpected node: %s", parser_node_name(nd_type(node)));
- return 0;
- }
-}
-
-static void
-set_nd_value(struct parser_params *p, NODE *node, NODE *rhs)
-{
- switch (nd_type(node)) {
- case NODE_CDECL:
- RNODE_CDECL(node)->nd_value = rhs;
- break;
- case NODE_GASGN:
- RNODE_GASGN(node)->nd_value = rhs;
- break;
- case NODE_IASGN:
- RNODE_IASGN(node)->nd_value = rhs;
- break;
- case NODE_LASGN:
- RNODE_LASGN(node)->nd_value = rhs;
- break;
- case NODE_DASGN:
- RNODE_DASGN(node)->nd_value = rhs;
- break;
- case NODE_MASGN:
- RNODE_MASGN(node)->nd_value = rhs;
- break;
- case NODE_CVASGN:
- RNODE_CVASGN(node)->nd_value = rhs;
- break;
- default:
- compile_error(p, "unexpected node: %s", parser_node_name(nd_type(node)));
- break;
- }
-}
-
-static ID
-get_nd_vid(struct parser_params *p, NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CDECL:
- return RNODE_CDECL(node)->nd_vid;
- case NODE_GASGN:
- return RNODE_GASGN(node)->nd_vid;
- case NODE_IASGN:
- return RNODE_IASGN(node)->nd_vid;
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_vid;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_vid;
- case NODE_CVASGN:
- return RNODE_CVASGN(node)->nd_vid;
- default:
- compile_error(p, "unexpected node: %s", parser_node_name(nd_type(node)));
- return 0;
- }
-}
-
-static NODE *
-get_nd_args(struct parser_params *p, NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_args;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_args;
- case NODE_FCALL:
- return RNODE_FCALL(node)->nd_args;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_args;
- case NODE_VCALL:
- case NODE_SUPER:
- case NODE_ZSUPER:
- case NODE_YIELD:
- case NODE_RETURN:
- case NODE_BREAK:
- case NODE_NEXT:
- return 0;
- default:
- compile_error(p, "unexpected node: %s", parser_node_name(nd_type(node)));
- return 0;
- }
-}
-#endif
%}
%expect 0
@@ -1899,39 +1338,36 @@ get_nd_args(struct parser_params *p, NODE *node)
%define parse.error verbose
%printer {
#ifndef RIPPER
- if ((NODE *)$$ == (NODE *)-1) {
- rb_parser_printf(p, "NODE_SPECIAL");
- }
- else if ($$) {
- rb_parser_printf(p, "%s", parser_node_name(nd_type(RNODE($$))));
+ if ($$) {
+ rb_parser_printf(p, "%s", ruby_node_name(nd_type($$)));
}
#else
#endif
-} <node> <node_fcall> <node_args> <node_args_aux> <node_opt_arg> <node_kw_arg> <node_block_pass>
+} <node>
%printer {
#ifndef RIPPER
rb_parser_printf(p, "%"PRIsVALUE, rb_id2str($$));
#else
- rb_parser_printf(p, "%"PRIsVALUE, RNODE_RIPPER($$)->nd_rval);
+ rb_parser_printf(p, "%"PRIsVALUE, RNODE($$)->nd_rval);
#endif
} tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL tOP_ASGN
%printer {
#ifndef RIPPER
- rb_parser_printf(p, "%+"PRIsVALUE, RNODE_LIT($$)->nd_lit);
+ rb_parser_printf(p, "%+"PRIsVALUE, $$->nd_lit);
#else
rb_parser_printf(p, "%+"PRIsVALUE, get_value($$));
#endif
} tINTEGER tFLOAT tRATIONAL tIMAGINARY tSTRING_CONTENT tCHAR
%printer {
#ifndef RIPPER
- rb_parser_printf(p, "$%ld", RNODE_NTH_REF($$)->nd_nth);
+ rb_parser_printf(p, "$%ld", $$->nd_nth);
#else
rb_parser_printf(p, "%"PRIsVALUE, $$);
#endif
} tNTH_REF
%printer {
#ifndef RIPPER
- rb_parser_printf(p, "$%c", (int)RNODE_BACK_REF($$)->nd_nth);
+ rb_parser_printf(p, "$%c", (int)$$->nd_nth);
#else
rb_parser_printf(p, "%"PRIsVALUE, $$);
#endif
@@ -1947,15 +1383,6 @@ get_nd_args(struct parser_params *p, NODE *node)
%union {
VALUE val;
NODE *node;
- rb_node_fcall_t *node_fcall;
- rb_node_args_t *node_args;
- rb_node_args_aux_t *node_args_aux;
- rb_node_opt_arg_t *node_opt_arg;
- rb_node_kw_arg_t *node_kw_arg;
- rb_node_block_pass_t *node_block_pass;
- rb_node_masgn_t *node_masgn;
- rb_node_def_temp_t *node_def_temp;
- rb_node_exits_t *node_exits;
ID id;
int num;
st_table *tbl;
@@ -2036,56 +1463,39 @@ get_nd_args(struct parser_params *p, NODE *node)
%type <node> singleton strings string string1 xstring regexp
%type <node> string_contents xstring_contents regexp_contents string_content
%type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word
-%type <node> literal numeric simple_numeric ssym dsym symbol cpath
-/*ripper*/ %type <node_def_temp> defn_head defs_head k_def
-/*ripper*/ %type <node_exits> block_open k_while k_until k_for allow_exits
-%type <node> top_compstmt top_stmts top_stmt begin_block endless_arg endless_command
+%type <node> literal numeric simple_numeric ssym dsym symbol cpath def_name defn_head defs_head
+%type <node> top_compstmt top_stmts top_stmt begin_block
%type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
-%type <node> expr_value expr_value_do arg_value primary_value rel_expr
-%type <node_fcall> fcall
+%type <node> expr_value expr_value_do arg_value primary_value fcall rel_expr
%type <node> if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure
%type <node> args call_args opt_call_args
-%type <node> paren_args opt_paren_args
-%type <node_args> args_tail opt_args_tail block_args_tail opt_block_args_tail
-%type <node> command_args aref_args
-%type <node_block_pass> opt_block_arg block_arg
-%type <node> var_ref var_lhs
+%type <node> paren_args opt_paren_args args_tail opt_args_tail block_args_tail opt_block_args_tail
+%type <node> command_args aref_args opt_block_arg block_arg var_ref var_lhs
%type <node> command_rhs arg_rhs
%type <node> command_asgn mrhs mrhs_arg superclass block_call block_command
-%type <node_opt_arg> f_block_optarg f_block_opt
-%type <node_args> f_arglist f_opt_paren_args f_paren_args f_args
-%type <node_args_aux> f_arg f_arg_item
-%type <node_opt_arg> f_optarg
-%type <node> f_marg f_marg_list f_rest_marg
-%type <node_masgn> f_margs
+%type <node> f_block_optarg f_block_opt
+%type <node> f_arglist f_opt_paren_args f_paren_args f_args f_arg f_arg_item
+%type <node> f_optarg f_marg f_marg_list f_margs f_rest_marg
%type <node> assoc_list assocs assoc undef_list backref string_dvar for_var
-%type <node_args> block_param opt_block_param block_param_def
-%type <node_opt_arg> f_opt
-%type <node_kw_arg> f_kwarg f_kw f_block_kwarg f_block_kw
+%type <node> block_param opt_block_param block_param_def f_opt
+%type <node> f_kwarg f_kw f_block_kwarg f_block_kw
%type <node> bv_decls opt_bv_decl bvar
-%type <node> lambda lambda_body brace_body do_body
-%type <node_args> f_larglist
+%type <node> lambda f_larglist lambda_body brace_body do_body
%type <node> brace_block cmd_brace_block do_block lhs none fitem
-%type <node> mlhs_head mlhs_item mlhs_node mlhs_post
-%type <node_masgn> mlhs mlhs_basic mlhs_inner
+%type <node> mlhs mlhs_head mlhs_basic mlhs_item mlhs_node mlhs_post mlhs_inner
%type <node> p_case_body p_cases p_top_expr p_top_expr_body
%type <node> p_expr p_as p_alt p_expr_basic p_find
-%type <node> p_args p_args_head p_args_tail p_args_post p_arg p_rest
+%type <node> p_args p_args_head p_args_tail p_args_post p_arg
%type <node> p_value p_primitive p_variable p_var_ref p_expr_ref p_const
%type <node> p_kwargs p_kwarg p_kw
%type <id> keyword_variable user_variable sym operation operation2 operation3
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
%type <id> f_kwrest f_label f_arg_asgn call_op call_op2 reswords relop dot_or_colon
-%type <id> p_kwrest p_kwnorest p_any_kwrest p_kw_label
-%type <id> f_no_kwarg f_any_kwrest args_forward excessed_comma nonlocal_var def_name
-%type <ctxt> lex_ctxt begin_defined k_class k_module k_END k_rescue k_ensure after_rescue
-%type <ctxt> p_in_kwarg
-%type <tbl> p_lparen p_lbracket p_pktbl p_pvtbl
-/* ripper */ %type <num> max_numparam
-/* ripper */ %type <node> numparam
+%type <id> p_rest p_kwrest p_kwnorest p_any_kwrest p_kw_label
+%type <id> f_no_kwarg f_any_kwrest args_forward excessed_comma nonlocal_var
+ %type <ctxt> lex_ctxt /* keep <ctxt> in ripper */
%token END_OF_INPUT 0 "end-of-input"
%token <id> '.'
-
/* escaped chars, should be ignored otherwise */
%token <id> '\\' "backslash"
%token tSP "escaped space"
@@ -2176,1569 +1586,1546 @@ get_nd_args(struct parser_params *p, NODE *node)
%%
program : {
- SET_LEX_STATE(EXPR_BEG);
- local_push(p, ifndef_ripper(1)+0);
- /* jumps are possible in the top-level loop. */
- if (!ifndef_ripper(p->do_loop) + 0) init_block_exit(p);
- }
- top_compstmt
- {
- /*%%%*/
- if ($2 && !compile_for_eval) {
- NODE *node = $2;
- /* last expression should not be void */
- if (nd_type_p(node, NODE_BLOCK)) {
- while (RNODE_BLOCK(node)->nd_next) {
- node = RNODE_BLOCK(node)->nd_next;
- }
- node = RNODE_BLOCK(node)->nd_head;
- }
- node = remove_begin(node);
- void_expr(p, node);
- }
- p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), &@$);
- /*% %*/
- /*% ripper[final]: program!($2) %*/
- local_pop(p);
- }
- ;
+ SET_LEX_STATE(EXPR_BEG);
+ local_push(p, ifndef_ripper(1)+0);
+ }
+ top_compstmt
+ {
+ /*%%%*/
+ if ($2 && !compile_for_eval) {
+ NODE *node = $2;
+ /* last expression should not be void */
+ if (nd_type_p(node, NODE_BLOCK)) {
+ while (node->nd_next) {
+ node = node->nd_next;
+ }
+ node = node->nd_head;
+ }
+ node = remove_begin(node);
+ void_expr(p, node);
+ }
+ p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), &@$);
+ /*% %*/
+ /*% ripper[final]: program!($2) %*/
+ local_pop(p);
+ }
+ ;
top_compstmt : top_stmts opt_terms
- {
- $$ = void_stmts(p, $1);
- }
- ;
+ {
+ $$ = void_stmts(p, $1);
+ }
+ ;
top_stmts : none
{
- /*%%%*/
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
- }
- | top_stmt
- {
- /*%%%*/
- $$ = newline_node($1);
- /*% %*/
- /*% ripper: stmts_add!(stmts_new!, $1) %*/
- }
- | top_stmts terms top_stmt
- {
- /*%%%*/
- $$ = block_append(p, $1, newline_node($3));
- /*% %*/
- /*% ripper: stmts_add!($1, $3) %*/
- }
- ;
+ /*%%%*/
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
+ }
+ | top_stmt
+ {
+ /*%%%*/
+ $$ = newline_node($1);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, $1) %*/
+ }
+ | top_stmts terms top_stmt
+ {
+ /*%%%*/
+ $$ = block_append(p, $1, newline_node($3));
+ /*% %*/
+ /*% ripper: stmts_add!($1, $3) %*/
+ }
+ ;
top_stmt : stmt
- {
- clear_block_exit(p, true);
- $$ = $1;
- }
- | keyword_BEGIN begin_block
- {
- $$ = $2;
- }
- ;
-
-block_open : '{' {$$ = init_block_exit(p);};
-
-begin_block : block_open top_compstmt '}'
- {
- restore_block_exit(p, $block_open);
- /*%%%*/
- p->eval_tree_begin = block_append(p, p->eval_tree_begin,
- NEW_BEGIN($2, &@$));
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper: BEGIN!($2) %*/
- }
- ;
-
-bodystmt : compstmt[body]
- lex_ctxt[ctxt]
- opt_rescue
- k_else
- {
- if (!$opt_rescue) yyerror1(&@k_else, "else without rescue is useless");
- next_rescue_context(&p->ctxt, &$ctxt, after_else);
- }
- compstmt[elsebody]
- {
- next_rescue_context(&p->ctxt, &$ctxt, after_ensure);
- }
- opt_ensure
- {
- /*%%%*/
- $$ = new_bodystmt(p, $body, $opt_rescue, $elsebody, $opt_ensure, &@$);
- /*% %*/
- /*% ripper: bodystmt!($body, $opt_rescue, $elsebody, $opt_ensure) %*/
- }
- | compstmt[body]
- lex_ctxt[ctxt]
- opt_rescue
- {
- next_rescue_context(&p->ctxt, &$ctxt, after_ensure);
- }
- opt_ensure
- {
- /*%%%*/
- $$ = new_bodystmt(p, $body, $opt_rescue, 0, $opt_ensure, &@$);
- /*% %*/
- /*% ripper: bodystmt!($body, $opt_rescue, Qnil, $opt_ensure) %*/
- }
- ;
+ | keyword_BEGIN begin_block
+ {
+ $$ = $2;
+ }
+ ;
+
+begin_block : '{' top_compstmt '}'
+ {
+ /*%%%*/
+ p->eval_tree_begin = block_append(p, p->eval_tree_begin,
+ NEW_BEGIN($2, &@$));
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: BEGIN!($2) %*/
+ }
+ ;
+
+bodystmt : compstmt
+ opt_rescue
+ k_else {if (!$2) {yyerror1(&@3, "else without rescue is useless");}}
+ compstmt
+ opt_ensure
+ {
+ /*%%%*/
+ $$ = new_bodystmt(p, $1, $2, $5, $6, &@$);
+ /*% %*/
+ /*% ripper: bodystmt!(escape_Qundef($1), escape_Qundef($2), escape_Qundef($5), escape_Qundef($6)) %*/
+ }
+ | compstmt
+ opt_rescue
+ opt_ensure
+ {
+ /*%%%*/
+ $$ = new_bodystmt(p, $1, $2, 0, $3, &@$);
+ /*% %*/
+ /*% ripper: bodystmt!(escape_Qundef($1), escape_Qundef($2), Qnil, escape_Qundef($3)) %*/
+ }
+ ;
compstmt : stmts opt_terms
- {
- $$ = void_stmts(p, $1);
- }
- ;
+ {
+ $$ = void_stmts(p, $1);
+ }
+ ;
stmts : none
{
- /*%%%*/
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
- }
- | stmt_or_begin
- {
- /*%%%*/
- $$ = newline_node($1);
- /*% %*/
- /*% ripper: stmts_add!(stmts_new!, $1) %*/
- }
- | stmts terms stmt_or_begin
- {
- /*%%%*/
- $$ = block_append(p, $1, newline_node($3));
- /*% %*/
- /*% ripper: stmts_add!($1, $3) %*/
- }
- ;
+ /*%%%*/
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
+ }
+ | stmt_or_begin
+ {
+ /*%%%*/
+ $$ = newline_node($1);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, $1) %*/
+ }
+ | stmts terms stmt_or_begin
+ {
+ /*%%%*/
+ $$ = block_append(p, $1, newline_node($3));
+ /*% %*/
+ /*% ripper: stmts_add!($1, $3) %*/
+ }
+ ;
stmt_or_begin : stmt
{
- $$ = $1;
- }
+ $$ = $1;
+ }
| keyword_BEGIN
- {
- yyerror1(&@1, "BEGIN is permitted only at toplevel");
- }
- begin_block
- {
- $$ = $3;
- }
- ;
-
-allow_exits : {$$ = allow_block_exit(p);};
-
-k_END : keyword_END lex_ctxt
- {
- $$ = $2;
- p->ctxt.in_rescue = before_rescue;
- };
+ {
+ yyerror1(&@1, "BEGIN is permitted only at toplevel");
+ }
+ begin_block
+ {
+ $$ = $3;
+ }
+ ;
stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
- {
- /*%%%*/
- $$ = NEW_ALIAS($2, $4, &@$);
- /*% %*/
- /*% ripper: alias!($2, $4) %*/
- }
- | keyword_alias tGVAR tGVAR
- {
- /*%%%*/
- $$ = NEW_VALIAS($2, $3, &@$);
- /*% %*/
- /*% ripper: var_alias!($2, $3) %*/
- }
- | keyword_alias tGVAR tBACK_REF
- {
- /*%%%*/
- char buf[2];
- buf[0] = '$';
- buf[1] = (char)RNODE_BACK_REF($3)->nd_nth;
- $$ = NEW_VALIAS($2, rb_intern2(buf, 2), &@$);
- /*% %*/
- /*% ripper: var_alias!($2, $3) %*/
- }
- | keyword_alias tGVAR tNTH_REF
- {
- static const char mesg[] = "can't make alias for the number variables";
- /*%%%*/
- yyerror1(&@3, mesg);
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper[error]: alias_error!(ERR_MESG(), $3) %*/
- }
- | keyword_undef undef_list
- {
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: undef!($2) %*/
- }
- | stmt modifier_if expr_value
- {
- /*%%%*/
- $$ = new_if(p, $3, remove_begin($1), 0, &@$);
- fixpos($$, $3);
- /*% %*/
- /*% ripper: if_mod!($3, $1) %*/
- }
- | stmt modifier_unless expr_value
- {
- /*%%%*/
- $$ = new_unless(p, $3, remove_begin($1), 0, &@$);
- fixpos($$, $3);
- /*% %*/
- /*% ripper: unless_mod!($3, $1) %*/
- }
- | stmt modifier_while expr_value
- {
- clear_block_exit(p, false);
- /*%%%*/
- if ($1 && nd_type_p($1, NODE_BEGIN)) {
- $$ = NEW_WHILE(cond(p, $3, &@3), RNODE_BEGIN($1)->nd_body, 0, &@$);
- }
- else {
- $$ = NEW_WHILE(cond(p, $3, &@3), $1, 1, &@$);
- }
- /*% %*/
- /*% ripper: while_mod!($3, $1) %*/
- }
- | stmt modifier_until expr_value
- {
- clear_block_exit(p, false);
- /*%%%*/
- if ($1 && nd_type_p($1, NODE_BEGIN)) {
- $$ = NEW_UNTIL(cond(p, $3, &@3), RNODE_BEGIN($1)->nd_body, 0, &@$);
- }
- else {
- $$ = NEW_UNTIL(cond(p, $3, &@3), $1, 1, &@$);
- }
- /*% %*/
- /*% ripper: until_mod!($3, $1) %*/
- }
- | stmt modifier_rescue after_rescue stmt
- {
- p->ctxt.in_rescue = $3.in_rescue;
- /*%%%*/
- NODE *resq;
- YYLTYPE loc = code_loc_gen(&@2, &@4);
- resq = NEW_RESBODY(0, remove_begin($4), 0, &loc);
- $$ = NEW_RESCUE(remove_begin($1), resq, 0, &@$);
- /*% %*/
- /*% ripper: rescue_mod!($1, $4) %*/
- }
- | k_END allow_exits '{' compstmt '}'
- {
- if (p->ctxt.in_def) {
- rb_warn0("END in method; use at_exit");
- }
- restore_block_exit(p, $allow_exits);
- p->ctxt = $k_END;
- /*%%%*/
- {
- NODE *scope = NEW_SCOPE2(0 /* tbl */, 0 /* args */, $compstmt /* body */, &@$);
- $$ = NEW_POSTEXE(scope, &@$);
- }
- /*% %*/
- /*% ripper: END!($compstmt) %*/
- }
- | command_asgn
- | mlhs '=' lex_ctxt command_call
- {
- /*%%%*/
- value_expr($4);
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% %*/
- /*% ripper: massign!($1, $4) %*/
- }
- | lhs '=' lex_ctxt mrhs
- {
- /*%%%*/
- $$ = node_assign(p, $1, $4, $3, &@$);
- /*% %*/
- /*% ripper: assign!($1, $4) %*/
- }
- | mlhs '=' lex_ctxt mrhs_arg modifier_rescue
- after_rescue stmt[resbody]
- {
- p->ctxt.in_rescue = $3.in_rescue;
- /*%%%*/
- YYLTYPE loc = code_loc_gen(&@modifier_rescue, &@resbody);
- $resbody = NEW_RESBODY(0, remove_begin($resbody), 0, &loc);
- loc.beg_pos = @mrhs_arg.beg_pos;
- $mrhs_arg = NEW_RESCUE($mrhs_arg, $resbody, 0, &loc);
- $$ = node_assign(p, (NODE *)$mlhs, $mrhs_arg, $lex_ctxt, &@$);
- /*% %*/
- /*% ripper: massign!($1, rescue_mod!($4, $7)) %*/
- }
- | mlhs '=' lex_ctxt mrhs_arg
- {
- /*%%%*/
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% %*/
- /*% ripper: massign!($1, $4) %*/
- }
- | expr
- | error
- {
- (void)yynerrs;
- /*%%%*/
- $$ = NEW_ERROR(&@$);
- /*% %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_ALIAS($2, $4, &@$);
+ /*% %*/
+ /*% ripper: alias!($2, $4) %*/
+ }
+ | keyword_alias tGVAR tGVAR
+ {
+ /*%%%*/
+ $$ = NEW_VALIAS($2, $3, &@$);
+ /*% %*/
+ /*% ripper: var_alias!($2, $3) %*/
+ }
+ | keyword_alias tGVAR tBACK_REF
+ {
+ /*%%%*/
+ char buf[2];
+ buf[0] = '$';
+ buf[1] = (char)$3->nd_nth;
+ $$ = NEW_VALIAS($2, rb_intern2(buf, 2), &@$);
+ /*% %*/
+ /*% ripper: var_alias!($2, $3) %*/
+ }
+ | keyword_alias tGVAR tNTH_REF
+ {
+ static const char mesg[] = "can't make alias for the number variables";
+ /*%%%*/
+ yyerror1(&@3, mesg);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: alias_error!(ERR_MESG(), $3) %*/
+ }
+ | keyword_undef undef_list
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: undef!($2) %*/
+ }
+ | stmt modifier_if expr_value
+ {
+ /*%%%*/
+ $$ = new_if(p, $3, remove_begin($1), 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: if_mod!($3, $1) %*/
+ }
+ | stmt modifier_unless expr_value
+ {
+ /*%%%*/
+ $$ = new_unless(p, $3, remove_begin($1), 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: unless_mod!($3, $1) %*/
+ }
+ | stmt modifier_while expr_value
+ {
+ /*%%%*/
+ if ($1 && nd_type_p($1, NODE_BEGIN)) {
+ $$ = NEW_WHILE(cond(p, $3, &@3), $1->nd_body, 0, &@$);
+ }
+ else {
+ $$ = NEW_WHILE(cond(p, $3, &@3), $1, 1, &@$);
+ }
+ /*% %*/
+ /*% ripper: while_mod!($3, $1) %*/
+ }
+ | stmt modifier_until expr_value
+ {
+ /*%%%*/
+ if ($1 && nd_type_p($1, NODE_BEGIN)) {
+ $$ = NEW_UNTIL(cond(p, $3, &@3), $1->nd_body, 0, &@$);
+ }
+ else {
+ $$ = NEW_UNTIL(cond(p, $3, &@3), $1, 1, &@$);
+ }
+ /*% %*/
+ /*% ripper: until_mod!($3, $1) %*/
+ }
+ | stmt modifier_rescue stmt
+ {
+ /*%%%*/
+ NODE *resq;
+ YYLTYPE loc = code_loc_gen(&@2, &@3);
+ resq = NEW_RESBODY(0, remove_begin($3), 0, &loc);
+ $$ = NEW_RESCUE(remove_begin($1), resq, 0, &@$);
+ /*% %*/
+ /*% ripper: rescue_mod!($1, $3) %*/
+ }
+ | keyword_END '{' compstmt '}'
+ {
+ if (p->ctxt.in_def) {
+ rb_warn0("END in method; use at_exit");
+ }
+ /*%%%*/
+ {
+ NODE *scope = NEW_NODE(
+ NODE_SCOPE, 0 /* tbl */, $3 /* body */, 0 /* args */, &@$);
+ $$ = NEW_POSTEXE(scope, &@$);
+ }
+ /*% %*/
+ /*% ripper: END!($3) %*/
+ }
+ | command_asgn
+ | mlhs '=' lex_ctxt command_call
+ {
+ /*%%%*/
+ value_expr($4);
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: massign!($1, $4) %*/
+ }
+ | lhs '=' lex_ctxt mrhs
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: assign!($1, $4) %*/
+ }
+ | mlhs '=' lex_ctxt mrhs_arg modifier_rescue stmt
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@5, &@6);
+ $$ = node_assign(p, $1, NEW_RESCUE($4, NEW_RESBODY(0, remove_begin($6), 0, &loc), 0, &@$), $3, &@$);
+ /*% %*/
+ /*% ripper: massign!($1, rescue_mod!($4, $6)) %*/
+ }
+ | mlhs '=' lex_ctxt mrhs_arg
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: massign!($1, $4) %*/
+ }
+ | expr
+ | error
+ {
+ /*%%%*/
+ $$ = NEW_ERROR(&@$);
+ /*% %*/
+ }
+ ;
command_asgn : lhs '=' lex_ctxt command_rhs
- {
- /*%%%*/
- $$ = node_assign(p, $1, $4, $3, &@$);
- /*% %*/
- /*% ripper: assign!($1, $4) %*/
- }
- | var_lhs tOP_ASGN lex_ctxt command_rhs
- {
- /*%%%*/
- $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
- /*% %*/
- /*% ripper: opassign!($1, $2, $4) %*/
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt command_rhs
- {
- /*%%%*/
- $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$);
- /*% %*/
- /*% ripper: opassign!(aref_field!($1, $3), $5, $7) %*/
-
- }
- | primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt command_rhs
- {
- /*%%%*/
- $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
- /*% %*/
- /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
- }
- | primary_value call_op tCONSTANT tOP_ASGN lex_ctxt command_rhs
- {
- /*%%%*/
- $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
- /*% %*/
- /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt command_rhs
- {
- /*%%%*/
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
- /*% %*/
- /*% ripper: opassign!(const_path_field!($1, $3), $4, $6) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt command_rhs
- {
- /*%%%*/
- $$ = new_attr_op_assign(p, $1, ID2VAL(idCOLON2), $3, $4, $6, &@$);
- /*% %*/
- /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
- }
- | defn_head[head] f_opt_paren_args[args] '=' endless_command[bodystmt]
- {
- endless_method_name(p, get_id($head->nd_mid), &@head);
- restore_defun(p, $head);
- /*%%%*/
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFN($$)->nd_defn = $bodystmt;
- /*% %*/
- /*% ripper[$bodystmt]: bodystmt!($bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: def!($head->nd_mid, $args, $bodystmt) %*/
- local_pop(p);
- }
- | defs_head[head] f_opt_paren_args[args] '=' endless_command[bodystmt]
- {
- endless_method_name(p, get_id($head->nd_mid), &@head);
- restore_defun(p, $head);
- /*%%%*/
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFS($$)->nd_defn = $bodystmt;
- /*% %*/
- /*% ripper[$bodystmt]: bodystmt!($bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: defs!($head->nd_recv, $head->dot_or_colon, $head->nd_mid, $args, $bodystmt) %*/
- local_pop(p);
- }
- | backref tOP_ASGN lex_ctxt command_rhs
- {
- /*%%%*/
- rb_backref_error(p, $1);
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper[error]: backref_error(p, RNODE($1), assign!(var_field(p, $1), $4)) %*/
- }
- ;
-
-endless_command : command
- | endless_command modifier_rescue after_rescue arg
- {
- p->ctxt.in_rescue = $3.in_rescue;
- /*%%%*/
- $$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
- /*% %*/
- /*% ripper: rescue_mod!($1, $4) %*/
- }
- | keyword_not opt_nl endless_command
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- }
- ;
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: assign!($1, $4) %*/
+ }
+ | var_lhs tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: opassign!($1, $2, $4) %*/
+ }
+ | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$);
+ /*% %*/
+ /*% ripper: opassign!(aref_field!($1, escape_Qundef($3)), $5, $7) %*/
+
+ }
+ | primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value call_op tCONSTANT tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
+ /*% %*/
+ /*% ripper: opassign!(const_path_field!($1, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, ID2VAL(idCOLON2), $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | defn_head f_opt_paren_args '=' command
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defn_head f_opt_paren_args '=' command modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' command
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' command modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | backref tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), assign!(var_field(p, $1), $4)) %*/
+ }
+ ;
command_rhs : command_call %prec tOP_ASGN
- {
- value_expr($1);
- $$ = $1;
- }
- | command_call modifier_rescue after_rescue stmt
- {
- p->ctxt.in_rescue = $3.in_rescue;
- /*%%%*/
- YYLTYPE loc = code_loc_gen(&@2, &@4);
- value_expr($1);
- $$ = NEW_RESCUE($1, NEW_RESBODY(0, remove_begin($4), 0, &loc), 0, &@$);
- /*% %*/
- /*% ripper: rescue_mod!($1, $4) %*/
- }
- | command_asgn
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | command_call modifier_rescue stmt
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@2, &@3);
+ value_expr($1);
+ $$ = NEW_RESCUE($1, NEW_RESBODY(0, remove_begin($3), 0, &loc), 0, &@$);
+ /*% %*/
+ /*% ripper: rescue_mod!($1, $3) %*/
+ }
+ | command_asgn
+ ;
expr : command_call
- | expr keyword_and expr
- {
- $$ = logop(p, idAND, $1, $3, &@2, &@$);
- }
- | expr keyword_or expr
- {
- $$ = logop(p, idOR, $1, $3, &@2, &@$);
- }
- | keyword_not opt_nl expr
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- }
- | '!' command_call
- {
- $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
- }
- | arg tASSOC
- {
- value_expr($arg);
- }
- p_in_kwarg[ctxt] p_pvtbl p_pktbl
- p_top_expr_body[body]
- {
- pop_pktbl(p, $p_pktbl);
- pop_pvtbl(p, $p_pvtbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- /*%%%*/
- $$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body), &@$);
- /*% %*/
- /*% ripper: case!($arg, in!($body, Qnil, Qnil)) %*/
- }
- | arg keyword_in
- {
- value_expr($arg);
- }
- p_in_kwarg[ctxt] p_pvtbl p_pktbl
- p_top_expr_body[body]
- {
- pop_pktbl(p, $p_pktbl);
- pop_pvtbl(p, $p_pvtbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- /*%%%*/
- $$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body), &@$);
- /*% %*/
- /*% ripper: case!($arg, in!($body, Qnil, Qnil)) %*/
- }
- | arg %prec tLBRACE_ARG
- ;
-
-def_name : fname
+ | expr keyword_and expr
+ {
+ $$ = logop(p, idAND, $1, $3, &@2, &@$);
+ }
+ | expr keyword_or expr
+ {
+ $$ = logop(p, idOR, $1, $3, &@2, &@$);
+ }
+ | keyword_not opt_nl expr
+ {
+ $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
+ }
+ | '!' command_call
+ {
+ $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
+ }
+ | arg tASSOC
+ {
+ value_expr($1);
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>2 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+ }
+ {
+ $<tbl>$ = push_pktbl(p);
+ }
+ p_top_expr_body
+ {
+ pop_pktbl(p, $<tbl>4);
+ pop_pvtbl(p, $<tbl>3);
+ p->ctxt.in_kwarg = $<ctxt>2.in_kwarg;
+ /*%%%*/
+ $$ = NEW_CASE3($1, NEW_IN($5, 0, 0, &@5), &@$);
+ /*% %*/
+ /*% ripper: case!($1, in!($5, Qnil, Qnil)) %*/
+ }
+ | arg keyword_in
+ {
+ value_expr($1);
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>2 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+ }
+ {
+ $<tbl>$ = push_pktbl(p);
+ }
+ p_top_expr_body
+ {
+ pop_pktbl(p, $<tbl>4);
+ pop_pvtbl(p, $<tbl>3);
+ p->ctxt.in_kwarg = $<ctxt>2.in_kwarg;
+ /*%%%*/
+ $$ = NEW_CASE3($1, NEW_IN($5, NEW_TRUE(&@5), NEW_FALSE(&@5), &@5), &@$);
+ /*% %*/
+ /*% ripper: case!($1, in!($5, Qnil, Qnil)) %*/
+ }
+ | arg %prec tLBRACE_ARG
+ ;
+
+def_name : fname
{
ID fname = get_id($1);
+ ID cur_arg = p->cur_arg;
+ YYSTYPE c = {.ctxt = p->ctxt};
numparam_name(p, fname);
+ NODE *save =
+ NODE_NEW_TEMPORAL(NODE_SELF,
+ /*head*/numparam_push(p),
+ /*nth*/p->max_numparam,
+ /*cval*/c.val);
local_push(p, 0);
p->cur_arg = 0;
p->ctxt.in_def = 1;
- p->ctxt.in_rescue = before_rescue;
- $$ = $1;
- }
- ;
-
-defn_head : k_def def_name
- {
- $$ = $k_def;
- $$->nd_mid = $def_name;
+ $<node>$ = NEW_NODE(NODE_SELF, /*vid*/cur_arg, /*mid*/fname, /*args*/save, &@$);
/*%%%*/
- $$->nd_def = NEW_DEFN($def_name, 0, &@$);
/*%
- add_mark_object(p, $def_name);
- %*/
+ $$ = NEW_RIPPER(fname, get_value($1), $$, &NULL_LOC);
+ %*/
}
;
+defn_head : k_def def_name
+ {
+ $$ = $2;
+ /*%%%*/
+ $$ = NEW_NODE(NODE_DEFN, 0, $$->nd_mid, $$, &@$);
+ /*% %*/
+ }
+ ;
+
defs_head : k_def singleton dot_or_colon
- {
- SET_LEX_STATE(EXPR_FNAME);
- p->ctxt.in_argdef = 1;
- }
- def_name
- {
- SET_LEX_STATE(EXPR_ENDFN|EXPR_LABEL); /* force for args */
- $$ = $k_def;
- $$->nd_mid = $def_name;
- /*%%%*/
- $$->nd_def = NEW_DEFS($singleton, $def_name, 0, &@$);
- /*%
- add_mark_object(p, $def_name);
- $$->nd_recv = add_mark_object(p, $singleton);
- $$->dot_or_colon = add_mark_object(p, $dot_or_colon);
- %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_FNAME);
+ p->ctxt.in_argdef = 1;
+ }
+ def_name
+ {
+ SET_LEX_STATE(EXPR_ENDFN|EXPR_LABEL); /* force for args */
+ $$ = $5;
+ /*%%%*/
+ $$ = NEW_NODE(NODE_DEFS, $2, $$->nd_mid, $$, &@$);
+ /*%
+ VALUE ary = rb_ary_new_from_args(3, $2, $3, get_value($$));
+ add_mark_object(p, ary);
+ $<node>$->nd_rval = ary;
+ %*/
+ }
+ ;
expr_value : expr
- {
- value_expr($1);
- $$ = $1;
- }
- | error
- {
- /*%%%*/
- $$ = NEW_ERROR(&@$);
- /*% %*/
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | error
+ {
+ /*%%%*/
+ $$ = NEW_ERROR(&@$);
+ /*% %*/
+ }
+ ;
expr_value_do : {COND_PUSH(1);} expr_value do {COND_POP();}
- {
- $$ = $2;
- }
- ;
+ {
+ $$ = $2;
+ }
+ ;
command_call : command
- | block_command
- ;
+ | block_command
+ ;
block_command : block_call
- | block_call call_op2 operation2 command_args
- {
- /*%%%*/
- $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
- /*% %*/
- /*% ripper: method_add_arg!(call!($1, $2, $3), $4) %*/
- }
- ;
+ | block_call call_op2 operation2 command_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, $3), $4) %*/
+ }
+ ;
cmd_brace_block : tLBRACE_ARG brace_body '}'
- {
- $$ = $2;
- /*%%%*/
- set_embraced_location($$, &@1, &@3);
- /*% %*/
- }
- ;
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ ;
fcall : operation
- {
- /*%%%*/
- $$ = NEW_FCALL($1, 0, &@$);
- /*% %*/
- /*% ripper: $1 %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_FCALL($1, 0, &@$);
+ nd_set_line($$, p->tokline);
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ ;
command : fcall command_args %prec tLOWEST
- {
- /*%%%*/
- $1->nd_args = $2;
- nd_set_last_loc($1, @2.end_pos);
- $$ = (NODE *)$1;
- /*% %*/
- /*% ripper: command!($1, $2) %*/
- }
- | fcall command_args cmd_brace_block
- {
- /*%%%*/
- block_dup_check(p, $2, $3);
- $1->nd_args = $2;
- $$ = method_add_block(p, (NODE *)$1, $3, &@$);
- fixpos($$, RNODE($1));
- nd_set_last_loc($1, @2.end_pos);
- /*% %*/
- /*% ripper: method_add_block!(command!($1, $2), $3) %*/
- }
- | primary_value call_op operation2 command_args %prec tLOWEST
- {
- /*%%%*/
- $$ = new_command_qcall(p, $2, $1, $3, $4, Qnull, &@3, &@$);
- /*% %*/
- /*% ripper: command_call!($1, $2, $3, $4) %*/
- }
- | primary_value call_op operation2 command_args cmd_brace_block
- {
- /*%%%*/
- $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
- /*% %*/
- /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
- }
- | primary_value tCOLON2 operation2 command_args %prec tLOWEST
- {
- /*%%%*/
- $$ = new_command_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, Qnull, &@3, &@$);
- /*% %*/
- /*% ripper: command_call!($1, $2, $3, $4) %*/
- }
- | primary_value tCOLON2 operation2 command_args cmd_brace_block
- {
- /*%%%*/
- $$ = new_command_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, $5, &@3, &@$);
- /*% %*/
- /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
- }
- | primary_value tCOLON2 tCONSTANT '{' brace_body '}'
- {
- /*%%%*/
- set_embraced_location($5, &@4, &@6);
- $$ = new_command_qcall(p, ID2VAL(idCOLON2), $1, $3, Qnull, $5, &@3, &@$);
- /*% %*/
- /*% ripper: method_add_block!(command_call!($1, $2, $3, Qnull), $5) %*/
- }
- | keyword_super command_args
- {
- /*%%%*/
- $$ = NEW_SUPER($2, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: super!($2) %*/
- }
- | k_yield command_args
- {
- /*%%%*/
- $$ = new_yield(p, $2, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: yield!($2) %*/
- }
- | k_return call_args
- {
- /*%%%*/
- $$ = NEW_RETURN(ret_args(p, $2), &@$);
- /*% %*/
- /*% ripper: return!($2) %*/
- }
- | keyword_break call_args
- {
- NODE *args = 0;
- /*%%%*/
- args = ret_args(p, $2);
- /*% %*/
- $<node>$ = add_block_exit(p, NEW_BREAK(args, &@$));
- /*% ripper: break!($2) %*/
- }
- | keyword_next call_args
- {
- NODE *args = 0;
- /*%%%*/
- args = ret_args(p, $2);
- /*% %*/
- $<node>$ = add_block_exit(p, NEW_NEXT(args, &@$));
- /*% ripper: next!($2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $1->nd_args = $2;
+ nd_set_last_loc($1, @2.end_pos);
+ $$ = $1;
+ /*% %*/
+ /*% ripper: command!($1, $2) %*/
+ }
+ | fcall command_args cmd_brace_block
+ {
+ /*%%%*/
+ block_dup_check(p, $2, $3);
+ $1->nd_args = $2;
+ $$ = method_add_block(p, $1, $3, &@$);
+ fixpos($$, $1);
+ nd_set_last_loc($1, @2.end_pos);
+ /*% %*/
+ /*% ripper: method_add_block!(command!($1, $2), $3) %*/
+ }
+ | primary_value call_op operation2 command_args %prec tLOWEST
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, Qnull, &@3, &@$);
+ /*% %*/
+ /*% ripper: command_call!($1, $2, $3, $4) %*/
+ }
+ | primary_value call_op operation2 command_args cmd_brace_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
+ }
+ | primary_value tCOLON2 operation2 command_args %prec tLOWEST
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, Qnull, &@3, &@$);
+ /*% %*/
+ /*% ripper: command_call!($1, $2, $3, $4) %*/
+ }
+ | primary_value tCOLON2 operation2 command_args cmd_brace_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
+ }
+ | keyword_super command_args
+ {
+ /*%%%*/
+ $$ = NEW_SUPER($2, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: super!($2) %*/
+ }
+ | keyword_yield command_args
+ {
+ /*%%%*/
+ $$ = new_yield(p, $2, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: yield!($2) %*/
+ }
+ | k_return call_args
+ {
+ /*%%%*/
+ $$ = NEW_RETURN(ret_args(p, $2), &@$);
+ /*% %*/
+ /*% ripper: return!($2) %*/
+ }
+ | keyword_break call_args
+ {
+ /*%%%*/
+ $$ = NEW_BREAK(ret_args(p, $2), &@$);
+ /*% %*/
+ /*% ripper: break!($2) %*/
+ }
+ | keyword_next call_args
+ {
+ /*%%%*/
+ $$ = NEW_NEXT(ret_args(p, $2), &@$);
+ /*% %*/
+ /*% ripper: next!($2) %*/
+ }
+ ;
mlhs : mlhs_basic
- | tLPAREN mlhs_inner rparen
- {
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: mlhs_paren!($2) %*/
- }
- ;
+ | tLPAREN mlhs_inner rparen
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
mlhs_inner : mlhs_basic
- | tLPAREN mlhs_inner rparen
- {
- /*%%%*/
- $$ = NEW_MASGN(NEW_LIST((NODE *)$2, &@$), 0, &@$);
- /*% %*/
- /*% ripper: mlhs_paren!($2) %*/
- }
- ;
+ | tLPAREN mlhs_inner rparen
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(NEW_LIST($2, &@$), 0, &@$);
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
mlhs_basic : mlhs_head
- {
- /*%%%*/
- $$ = NEW_MASGN($1, 0, &@$);
- /*% %*/
- /*% ripper: $1 %*/
- }
- | mlhs_head mlhs_item
- {
- /*%%%*/
- $$ = NEW_MASGN(list_append(p, $1, $2), 0, &@$);
- /*% %*/
- /*% ripper: mlhs_add!($1, $2) %*/
- }
- | mlhs_head tSTAR mlhs_node
- {
- /*%%%*/
- $$ = NEW_MASGN($1, $3, &@$);
- /*% %*/
- /*% ripper: mlhs_add_star!($1, $3) %*/
- }
- | mlhs_head tSTAR mlhs_node ',' mlhs_post
- {
- /*%%%*/
- $$ = NEW_MASGN($1, NEW_POSTARG($3,$5,&@$), &@$);
- /*% %*/
- /*% ripper: mlhs_add_post!(mlhs_add_star!($1, $3), $5) %*/
- }
- | mlhs_head tSTAR
- {
- /*%%%*/
- $$ = NEW_MASGN($1, NODE_SPECIAL_NO_NAME_REST, &@$);
- /*% %*/
- /*% ripper: mlhs_add_star!($1, Qnil) %*/
- }
- | mlhs_head tSTAR ',' mlhs_post
- {
- /*%%%*/
- $$ = NEW_MASGN($1, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $4, &@$), &@$);
- /*% %*/
- /*% ripper: mlhs_add_post!(mlhs_add_star!($1, Qnil), $4) %*/
- }
- | tSTAR mlhs_node
- {
- /*%%%*/
- $$ = NEW_MASGN(0, $2, &@$);
- /*% %*/
- /*% ripper: mlhs_add_star!(mlhs_new!, $2) %*/
- }
- | tSTAR mlhs_node ',' mlhs_post
- {
- /*%%%*/
- $$ = NEW_MASGN(0, NEW_POSTARG($2,$4,&@$), &@$);
- /*% %*/
- /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $2), $4) %*/
- }
- | tSTAR
- {
- /*%%%*/
- $$ = NEW_MASGN(0, NODE_SPECIAL_NO_NAME_REST, &@$);
- /*% %*/
- /*% ripper: mlhs_add_star!(mlhs_new!, Qnil) %*/
- }
- | tSTAR ',' mlhs_post
- {
- /*%%%*/
- $$ = NEW_MASGN(0, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $3, &@$), &@$);
- /*% %*/
- /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, Qnil), $3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, 0, &@$);
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ | mlhs_head mlhs_item
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(list_append(p, $1,$2), 0, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $2) %*/
+ }
+ | mlhs_head tSTAR mlhs_node
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, $3, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!($1, $3) %*/
+ }
+ | mlhs_head tSTAR mlhs_node ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NEW_POSTARG($3,$5,&@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!($1, $3), $5) %*/
+ }
+ | mlhs_head tSTAR
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NODE_SPECIAL_NO_NAME_REST, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!($1, Qnil) %*/
+ }
+ | mlhs_head tSTAR ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $4, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!($1, Qnil), $4) %*/
+ }
+ | tSTAR mlhs_node
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, $2, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!(mlhs_new!, $2) %*/
+ }
+ | tSTAR mlhs_node ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NEW_POSTARG($2,$4,&@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $2), $4) %*/
+ }
+ | tSTAR
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NODE_SPECIAL_NO_NAME_REST, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!(mlhs_new!, Qnil) %*/
+ }
+ | tSTAR ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, Qnil), $3) %*/
+ }
+ ;
mlhs_item : mlhs_node
- | tLPAREN mlhs_inner rparen
- {
- /*%%%*/
- $$ = (NODE *)$2;
- /*% %*/
- /*% ripper: mlhs_paren!($2) %*/
- }
- ;
+ | tLPAREN mlhs_inner rparen
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
mlhs_head : mlhs_item ','
- {
- /*%%%*/
- $$ = NEW_LIST($1, &@1);
- /*% %*/
- /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
- }
- | mlhs_head mlhs_item ','
- {
- /*%%%*/
- $$ = list_append(p, $1, $2);
- /*% %*/
- /*% ripper: mlhs_add!($1, $2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@1);
+ /*% %*/
+ /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
+ }
+ | mlhs_head mlhs_item ','
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $2);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $2) %*/
+ }
+ ;
mlhs_post : mlhs_item
- {
- /*%%%*/
- $$ = NEW_LIST($1, &@$);
- /*% %*/
- /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
- }
- | mlhs_post ',' mlhs_item
- {
- /*%%%*/
- $$ = list_append(p, $1, $3);
- /*% %*/
- /*% ripper: mlhs_add!($1, $3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
+ }
+ | mlhs_post ',' mlhs_item
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $3);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $3) %*/
+ }
+ ;
mlhs_node : user_variable
- {
- /*%%%*/
- $$ = assignable(p, $1, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $1)) %*/
- }
- | keyword_variable
- {
- /*%%%*/
- $$ = assignable(p, $1, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $1)) %*/
- }
- | primary_value '[' opt_call_args rbracket
- {
- /*%%%*/
- $$ = aryset(p, $1, $3, &@$);
- /*% %*/
- /*% ripper: aref_field!($1, $3) %*/
- }
- | primary_value call_op tIDENTIFIER
- {
- anddot_multiple_assignment_check(p, &@2, $2);
- /*%%%*/
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% %*/
- /*% ripper: field!($1, $2, $3) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- /*%%%*/
- $$ = attrset(p, $1, idCOLON2, $3, &@$);
- /*% %*/
- /*% ripper: const_path_field!($1, $3) %*/
- }
- | primary_value call_op tCONSTANT
- {
- anddot_multiple_assignment_check(p, &@2, $2);
- /*%%%*/
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% %*/
- /*% ripper: field!($1, $2, $3) %*/
- }
- | primary_value tCOLON2 tCONSTANT
- {
- /*%%%*/
- $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
- /*% %*/
- /*% ripper: const_decl(p, const_path_field!($1, $3)) %*/
- }
- | tCOLON3 tCONSTANT
- {
- /*%%%*/
- $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
- /*% %*/
- /*% ripper: const_decl(p, top_const_field!($2)) %*/
- }
- | backref
- {
- /*%%%*/
- rb_backref_error(p, $1);
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper[error]: backref_error(p, RNODE($1), var_field(p, $1)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ /*%%%*/
+ $$ = aryset(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: aref_field!($1, escape_Qundef($3)) %*/
+ }
+ | primary_value call_op tIDENTIFIER
+ {
+ if ($2 == tANDDOT) {
+ yyerror1(&@2, "&. inside multiple assignment destination");
+ }
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, idCOLON2, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_field!($1, $3) %*/
+ }
+ | primary_value call_op tCONSTANT
+ {
+ if ($2 == tANDDOT) {
+ yyerror1(&@2, "&. inside multiple assignment destination");
+ }
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, const_path_field!($1, $3)) %*/
+ }
+ | tCOLON3 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, top_const_field!($2)) %*/
+ }
+ | backref
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), var_field(p, $1)) %*/
+ }
+ ;
lhs : user_variable
- {
- /*%%%*/
- $$ = assignable(p, $1, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $1)) %*/
- }
- | keyword_variable
- {
- /*%%%*/
- $$ = assignable(p, $1, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $1)) %*/
- }
- | primary_value '[' opt_call_args rbracket
- {
- /*%%%*/
- $$ = aryset(p, $1, $3, &@$);
- /*% %*/
- /*% ripper: aref_field!($1, $3) %*/
- }
- | primary_value call_op tIDENTIFIER
- {
- /*%%%*/
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% %*/
- /*% ripper: field!($1, $2, $3) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- /*%%%*/
- $$ = attrset(p, $1, idCOLON2, $3, &@$);
- /*% %*/
- /*% ripper: field!($1, $2, $3) %*/
- }
- | primary_value call_op tCONSTANT
- {
- /*%%%*/
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% %*/
- /*% ripper: field!($1, $2, $3) %*/
- }
- | primary_value tCOLON2 tCONSTANT
- {
- /*%%%*/
- $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
- /*% %*/
- /*% ripper: const_decl(p, const_path_field!($1, $3)) %*/
- }
- | tCOLON3 tCONSTANT
- {
- /*%%%*/
- $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
- /*% %*/
- /*% ripper: const_decl(p, top_const_field!($2)) %*/
- }
- | backref
- {
- /*%%%*/
- rb_backref_error(p, $1);
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper[error]: backref_error(p, RNODE($1), var_field(p, $1)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ /*%%%*/
+ $$ = aryset(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: aref_field!($1, escape_Qundef($3)) %*/
+ }
+ | primary_value call_op tIDENTIFIER
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, idCOLON2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value call_op tCONSTANT
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, const_path_field!($1, $3)) %*/
+ }
+ | tCOLON3 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, top_const_field!($2)) %*/
+ }
+ | backref
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), var_field(p, $1)) %*/
+ }
+ ;
cname : tIDENTIFIER
- {
- static const char mesg[] = "class/module name must be CONSTANT";
- /*%%%*/
- yyerror1(&@1, mesg);
- /*% %*/
- /*% ripper[error]: class_name_error!(ERR_MESG(), $1) %*/
- }
- | tCONSTANT
- ;
+ {
+ static const char mesg[] = "class/module name must be CONSTANT";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ /*% %*/
+ /*% ripper[error]: class_name_error!(ERR_MESG(), $1) %*/
+ }
+ | tCONSTANT
+ ;
cpath : tCOLON3 cname
- {
- /*%%%*/
- $$ = NEW_COLON3($2, &@$);
- /*% %*/
- /*% ripper: top_const_ref!($2) %*/
- }
- | cname
- {
- /*%%%*/
- $$ = NEW_COLON2(0, $1, &@$);
- /*% %*/
- /*% ripper: const_ref!($1) %*/
- }
- | primary_value tCOLON2 cname
- {
- /*%%%*/
- $$ = NEW_COLON2($1, $3, &@$);
- /*% %*/
- /*% ripper: const_path_ref!($1, $3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_COLON3($2, &@$);
+ /*% %*/
+ /*% ripper: top_const_ref!($2) %*/
+ }
+ | cname
+ {
+ /*%%%*/
+ $$ = NEW_COLON2(0, $$, &@$);
+ /*% %*/
+ /*% ripper: const_ref!($1) %*/
+ }
+ | primary_value tCOLON2 cname
+ {
+ /*%%%*/
+ $$ = NEW_COLON2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_ref!($1, $3) %*/
+ }
+ ;
fname : tIDENTIFIER
- | tCONSTANT
- | tFID
- | op
- {
- SET_LEX_STATE(EXPR_ENDFN);
- $$ = $1;
- }
- | reswords
- ;
+ | tCONSTANT
+ | tFID
+ | op
+ {
+ SET_LEX_STATE(EXPR_ENDFN);
+ $$ = $1;
+ }
+ | reswords
+ ;
fitem : fname
- {
- /*%%%*/
- $$ = NEW_LIT(ID2SYM($1), &@$);
- /*% %*/
- /*% ripper: symbol_literal!($1) %*/
- }
- | symbol
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIT(ID2SYM($1), &@$);
+ /*% %*/
+ /*% ripper: symbol_literal!($1) %*/
+ }
+ | symbol
+ ;
undef_list : fitem
- {
- /*%%%*/
- $$ = NEW_UNDEF($1, &@$);
- /*% %*/
- /*% ripper: rb_ary_new3(1, get_value($1)) %*/
- }
- | undef_list ',' {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
- {
- /*%%%*/
- NODE *undef = NEW_UNDEF($4, &@4);
- $$ = block_append(p, $1, undef);
- /*% %*/
- /*% ripper: rb_ary_push($1, get_value($4)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_UNDEF($1, &@$);
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | undef_list ',' {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
+ {
+ /*%%%*/
+ NODE *undef = NEW_UNDEF($4, &@4);
+ $$ = block_append(p, $1, undef);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($4)) %*/
+ }
+ ;
op : '|' { ifndef_ripper($$ = '|'); }
- | '^' { ifndef_ripper($$ = '^'); }
- | '&' { ifndef_ripper($$ = '&'); }
- | tCMP { ifndef_ripper($$ = tCMP); }
- | tEQ { ifndef_ripper($$ = tEQ); }
- | tEQQ { ifndef_ripper($$ = tEQQ); }
- | tMATCH { ifndef_ripper($$ = tMATCH); }
- | tNMATCH { ifndef_ripper($$ = tNMATCH); }
- | '>' { ifndef_ripper($$ = '>'); }
- | tGEQ { ifndef_ripper($$ = tGEQ); }
- | '<' { ifndef_ripper($$ = '<'); }
- | tLEQ { ifndef_ripper($$ = tLEQ); }
- | tNEQ { ifndef_ripper($$ = tNEQ); }
- | tLSHFT { ifndef_ripper($$ = tLSHFT); }
- | tRSHFT { ifndef_ripper($$ = tRSHFT); }
- | '+' { ifndef_ripper($$ = '+'); }
- | '-' { ifndef_ripper($$ = '-'); }
- | '*' { ifndef_ripper($$ = '*'); }
- | tSTAR { ifndef_ripper($$ = '*'); }
- | '/' { ifndef_ripper($$ = '/'); }
- | '%' { ifndef_ripper($$ = '%'); }
- | tPOW { ifndef_ripper($$ = tPOW); }
- | tDSTAR { ifndef_ripper($$ = tDSTAR); }
- | '!' { ifndef_ripper($$ = '!'); }
- | '~' { ifndef_ripper($$ = '~'); }
- | tUPLUS { ifndef_ripper($$ = tUPLUS); }
- | tUMINUS { ifndef_ripper($$ = tUMINUS); }
- | tAREF { ifndef_ripper($$ = tAREF); }
- | tASET { ifndef_ripper($$ = tASET); }
- | '`' { ifndef_ripper($$ = '`'); }
- ;
+ | '^' { ifndef_ripper($$ = '^'); }
+ | '&' { ifndef_ripper($$ = '&'); }
+ | tCMP { ifndef_ripper($$ = tCMP); }
+ | tEQ { ifndef_ripper($$ = tEQ); }
+ | tEQQ { ifndef_ripper($$ = tEQQ); }
+ | tMATCH { ifndef_ripper($$ = tMATCH); }
+ | tNMATCH { ifndef_ripper($$ = tNMATCH); }
+ | '>' { ifndef_ripper($$ = '>'); }
+ | tGEQ { ifndef_ripper($$ = tGEQ); }
+ | '<' { ifndef_ripper($$ = '<'); }
+ | tLEQ { ifndef_ripper($$ = tLEQ); }
+ | tNEQ { ifndef_ripper($$ = tNEQ); }
+ | tLSHFT { ifndef_ripper($$ = tLSHFT); }
+ | tRSHFT { ifndef_ripper($$ = tRSHFT); }
+ | '+' { ifndef_ripper($$ = '+'); }
+ | '-' { ifndef_ripper($$ = '-'); }
+ | '*' { ifndef_ripper($$ = '*'); }
+ | tSTAR { ifndef_ripper($$ = '*'); }
+ | '/' { ifndef_ripper($$ = '/'); }
+ | '%' { ifndef_ripper($$ = '%'); }
+ | tPOW { ifndef_ripper($$ = tPOW); }
+ | tDSTAR { ifndef_ripper($$ = tDSTAR); }
+ | '!' { ifndef_ripper($$ = '!'); }
+ | '~' { ifndef_ripper($$ = '~'); }
+ | tUPLUS { ifndef_ripper($$ = tUPLUS); }
+ | tUMINUS { ifndef_ripper($$ = tUMINUS); }
+ | tAREF { ifndef_ripper($$ = tAREF); }
+ | tASET { ifndef_ripper($$ = tASET); }
+ | '`' { ifndef_ripper($$ = '`'); }
+ ;
reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
- | keyword_BEGIN | keyword_END
- | keyword_alias | keyword_and | keyword_begin
- | keyword_break | keyword_case | keyword_class | keyword_def
- | keyword_defined | keyword_do | keyword_else | keyword_elsif
- | keyword_end | keyword_ensure | keyword_false
- | keyword_for | keyword_in | keyword_module | keyword_next
- | keyword_nil | keyword_not | keyword_or | keyword_redo
- | keyword_rescue | keyword_retry | keyword_return | keyword_self
- | keyword_super | keyword_then | keyword_true | keyword_undef
- | keyword_when | keyword_yield | keyword_if | keyword_unless
- | keyword_while | keyword_until
- ;
+ | keyword_BEGIN | keyword_END
+ | keyword_alias | keyword_and | keyword_begin
+ | keyword_break | keyword_case | keyword_class | keyword_def
+ | keyword_defined | keyword_do | keyword_else | keyword_elsif
+ | keyword_end | keyword_ensure | keyword_false
+ | keyword_for | keyword_in | keyword_module | keyword_next
+ | keyword_nil | keyword_not | keyword_or | keyword_redo
+ | keyword_rescue | keyword_retry | keyword_return | keyword_self
+ | keyword_super | keyword_then | keyword_true | keyword_undef
+ | keyword_when | keyword_yield | keyword_if | keyword_unless
+ | keyword_while | keyword_until
+ ;
arg : lhs '=' lex_ctxt arg_rhs
- {
- /*%%%*/
- $$ = node_assign(p, $1, $4, $3, &@$);
- /*% %*/
- /*% ripper: assign!($1, $4) %*/
- }
- | var_lhs tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
- /*% %*/
- /*% ripper: opassign!($1, $2, $4) %*/
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$);
- /*% %*/
- /*% ripper: opassign!(aref_field!($1, $3), $5, $7) %*/
- }
- | primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
- /*% %*/
- /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
- }
- | primary_value call_op tCONSTANT tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
- /*% %*/
- /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- $$ = new_attr_op_assign(p, $1, ID2VAL(idCOLON2), $3, $4, $6, &@$);
- /*% %*/
- /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
- /*% %*/
- /*% ripper: opassign!(const_path_field!($1, $3), $4, $6) %*/
- }
- | tCOLON3 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- YYLTYPE loc = code_loc_gen(&@1, &@2);
- $$ = new_const_op_assign(p, NEW_COLON3($2, &loc), $3, $5, $4, &@$);
- /*% %*/
- /*% ripper: opassign!(top_const_field!($2), $3, $5) %*/
- }
- | backref tOP_ASGN lex_ctxt arg_rhs
- {
- /*%%%*/
- rb_backref_error(p, $1);
- $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper[error]: backref_error(p, RNODE($1), opassign!(var_field(p, $1), $2, $4)) %*/
- }
- | arg tDOT2 arg
- {
- /*%%%*/
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT2($1, $3, &@$);
- /*% %*/
- /*% ripper: dot2!($1, $3) %*/
- }
- | arg tDOT3 arg
- {
- /*%%%*/
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT3($1, $3, &@$);
- /*% %*/
- /*% ripper: dot3!($1, $3) %*/
- }
- | arg tDOT2
- {
- /*%%%*/
- value_expr($1);
- $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% %*/
- /*% ripper: dot2!($1, Qnil) %*/
- }
- | arg tDOT3
- {
- /*%%%*/
- value_expr($1);
- $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% %*/
- /*% ripper: dot3!($1, Qnil) %*/
- }
- | tBDOT2 arg
- {
- /*%%%*/
- value_expr($2);
- $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% %*/
- /*% ripper: dot2!(Qnil, $2) %*/
- }
- | tBDOT3 arg
- {
- /*%%%*/
- value_expr($2);
- $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% %*/
- /*% ripper: dot3!(Qnil, $2) %*/
- }
- | arg '+' arg
- {
- $$ = call_bin_op(p, $1, '+', $3, &@2, &@$);
- }
- | arg '-' arg
- {
- $$ = call_bin_op(p, $1, '-', $3, &@2, &@$);
- }
- | arg '*' arg
- {
- $$ = call_bin_op(p, $1, '*', $3, &@2, &@$);
- }
- | arg '/' arg
- {
- $$ = call_bin_op(p, $1, '/', $3, &@2, &@$);
- }
- | arg '%' arg
- {
- $$ = call_bin_op(p, $1, '%', $3, &@2, &@$);
- }
- | arg tPOW arg
- {
- $$ = call_bin_op(p, $1, idPow, $3, &@2, &@$);
- }
- | tUMINUS_NUM simple_numeric tPOW arg
- {
- $$ = call_uni_op(p, call_bin_op(p, $2, idPow, $4, &@2, &@$), idUMinus, &@1, &@$);
- }
- | tUPLUS arg
- {
- $$ = call_uni_op(p, $2, idUPlus, &@1, &@$);
- }
- | tUMINUS arg
- {
- $$ = call_uni_op(p, $2, idUMinus, &@1, &@$);
- }
- | arg '|' arg
- {
- $$ = call_bin_op(p, $1, '|', $3, &@2, &@$);
- }
- | arg '^' arg
- {
- $$ = call_bin_op(p, $1, '^', $3, &@2, &@$);
- }
- | arg '&' arg
- {
- $$ = call_bin_op(p, $1, '&', $3, &@2, &@$);
- }
- | arg tCMP arg
- {
- $$ = call_bin_op(p, $1, idCmp, $3, &@2, &@$);
- }
- | rel_expr %prec tCMP
- | arg tEQ arg
- {
- $$ = call_bin_op(p, $1, idEq, $3, &@2, &@$);
- }
- | arg tEQQ arg
- {
- $$ = call_bin_op(p, $1, idEqq, $3, &@2, &@$);
- }
- | arg tNEQ arg
- {
- $$ = call_bin_op(p, $1, idNeq, $3, &@2, &@$);
- }
- | arg tMATCH arg
- {
- $$ = match_op(p, $1, $3, &@2, &@$);
- }
- | arg tNMATCH arg
- {
- $$ = call_bin_op(p, $1, idNeqTilde, $3, &@2, &@$);
- }
- | '!' arg
- {
- $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
- }
- | '~' arg
- {
- $$ = call_uni_op(p, $2, '~', &@1, &@$);
- }
- | arg tLSHFT arg
- {
- $$ = call_bin_op(p, $1, idLTLT, $3, &@2, &@$);
- }
- | arg tRSHFT arg
- {
- $$ = call_bin_op(p, $1, idGTGT, $3, &@2, &@$);
- }
- | arg tANDOP arg
- {
- $$ = logop(p, idANDOP, $1, $3, &@2, &@$);
- }
- | arg tOROP arg
- {
- $$ = logop(p, idOROP, $1, $3, &@2, &@$);
- }
- | keyword_defined opt_nl begin_defined arg
- {
- p->ctxt.in_defined = $3.in_defined;
- $$ = new_defined(p, $4, &@$);
- }
- | arg '?' arg opt_nl ':' arg
- {
- /*%%%*/
- value_expr($1);
- $$ = new_if(p, $1, $3, $6, &@$);
- fixpos($$, $1);
- /*% %*/
- /*% ripper: ifop!($1, $3, $6) %*/
- }
- | defn_head[head] f_opt_paren_args[args] '=' endless_arg[bodystmt]
- {
- endless_method_name(p, get_id($head->nd_mid), &@head);
- restore_defun(p, $head);
- /*%%%*/
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFN($$)->nd_defn = $bodystmt;
- /*% %*/
- /*% ripper[$bodystmt]: bodystmt!($bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: def!($head->nd_mid, $args, $bodystmt) %*/
- local_pop(p);
- }
- | defs_head[head] f_opt_paren_args[args] '=' endless_arg[bodystmt]
- {
- endless_method_name(p, get_id($head->nd_mid), &@head);
- restore_defun(p, $head);
- /*%%%*/
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFS($$)->nd_defn = $bodystmt;
- /*% %*/
- /*% ripper[$bodystmt]: bodystmt!($bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: defs!($head->nd_recv, $head->dot_or_colon, $head->nd_mid, $args, $bodystmt) %*/
- local_pop(p);
- }
- | primary
- {
- $$ = $1;
- }
- ;
-
-endless_arg : arg %prec modifier_rescue
- | endless_arg modifier_rescue after_rescue arg
- {
- p->ctxt.in_rescue = $3.in_rescue;
- /*%%%*/
- $$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
- /*% %*/
- /*% ripper: rescue_mod!($1, $4) %*/
- }
- | keyword_not opt_nl endless_arg
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- }
- ;
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: assign!($1, $4) %*/
+ }
+ | var_lhs tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: opassign!($1, $2, $4) %*/
+ }
+ | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$);
+ /*% %*/
+ /*% ripper: opassign!(aref_field!($1, escape_Qundef($3)), $5, $7) %*/
+ }
+ | primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value call_op tCONSTANT tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, ID2VAL(idCOLON2), $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
+ /*% %*/
+ /*% ripper: opassign!(const_path_field!($1, $3), $4, $6) %*/
+ }
+ | tCOLON3 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@2);
+ $$ = new_const_op_assign(p, NEW_COLON3($2, &loc), $3, $5, $4, &@$);
+ /*% %*/
+ /*% ripper: opassign!(top_const_field!($2), $3, $5) %*/
+ }
+ | backref tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), opassign!(var_field(p, $1), $2, $4)) %*/
+ }
+ | arg tDOT2 arg
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, $3) %*/
+ }
+ | arg tDOT3 arg
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT3($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, $3) %*/
+ }
+ | arg tDOT2
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, Qnil) %*/
+ }
+ | arg tDOT3
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, Qnil) %*/
+ }
+ | tBDOT2 arg
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot2!(Qnil, $2) %*/
+ }
+ | tBDOT3 arg
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot3!(Qnil, $2) %*/
+ }
+ | arg '+' arg
+ {
+ $$ = call_bin_op(p, $1, '+', $3, &@2, &@$);
+ }
+ | arg '-' arg
+ {
+ $$ = call_bin_op(p, $1, '-', $3, &@2, &@$);
+ }
+ | arg '*' arg
+ {
+ $$ = call_bin_op(p, $1, '*', $3, &@2, &@$);
+ }
+ | arg '/' arg
+ {
+ $$ = call_bin_op(p, $1, '/', $3, &@2, &@$);
+ }
+ | arg '%' arg
+ {
+ $$ = call_bin_op(p, $1, '%', $3, &@2, &@$);
+ }
+ | arg tPOW arg
+ {
+ $$ = call_bin_op(p, $1, idPow, $3, &@2, &@$);
+ }
+ | tUMINUS_NUM simple_numeric tPOW arg
+ {
+ $$ = call_uni_op(p, call_bin_op(p, $2, idPow, $4, &@2, &@$), idUMinus, &@1, &@$);
+ }
+ | tUPLUS arg
+ {
+ $$ = call_uni_op(p, $2, idUPlus, &@1, &@$);
+ }
+ | tUMINUS arg
+ {
+ $$ = call_uni_op(p, $2, idUMinus, &@1, &@$);
+ }
+ | arg '|' arg
+ {
+ $$ = call_bin_op(p, $1, '|', $3, &@2, &@$);
+ }
+ | arg '^' arg
+ {
+ $$ = call_bin_op(p, $1, '^', $3, &@2, &@$);
+ }
+ | arg '&' arg
+ {
+ $$ = call_bin_op(p, $1, '&', $3, &@2, &@$);
+ }
+ | arg tCMP arg
+ {
+ $$ = call_bin_op(p, $1, idCmp, $3, &@2, &@$);
+ }
+ | rel_expr %prec tCMP
+ | arg tEQ arg
+ {
+ $$ = call_bin_op(p, $1, idEq, $3, &@2, &@$);
+ }
+ | arg tEQQ arg
+ {
+ $$ = call_bin_op(p, $1, idEqq, $3, &@2, &@$);
+ }
+ | arg tNEQ arg
+ {
+ $$ = call_bin_op(p, $1, idNeq, $3, &@2, &@$);
+ }
+ | arg tMATCH arg
+ {
+ $$ = match_op(p, $1, $3, &@2, &@$);
+ }
+ | arg tNMATCH arg
+ {
+ $$ = call_bin_op(p, $1, idNeqTilde, $3, &@2, &@$);
+ }
+ | '!' arg
+ {
+ $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
+ }
+ | '~' arg
+ {
+ $$ = call_uni_op(p, $2, '~', &@1, &@$);
+ }
+ | arg tLSHFT arg
+ {
+ $$ = call_bin_op(p, $1, idLTLT, $3, &@2, &@$);
+ }
+ | arg tRSHFT arg
+ {
+ $$ = call_bin_op(p, $1, idGTGT, $3, &@2, &@$);
+ }
+ | arg tANDOP arg
+ {
+ $$ = logop(p, idANDOP, $1, $3, &@2, &@$);
+ }
+ | arg tOROP arg
+ {
+ $$ = logop(p, idOROP, $1, $3, &@2, &@$);
+ }
+ | keyword_defined opt_nl {p->ctxt.in_defined = 1;} arg
+ {
+ p->ctxt.in_defined = 0;
+ $$ = new_defined(p, $4, &@$);
+ }
+ | arg '?' arg opt_nl ':' arg
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = new_if(p, $1, $3, $6, &@$);
+ fixpos($$, $1);
+ /*% %*/
+ /*% ripper: ifop!($1, $3, $6) %*/
+ }
+ | defn_head f_opt_paren_args '=' arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defn_head f_opt_paren_args '=' arg modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' arg modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | primary
+ {
+ $$ = $1;
+ }
+ ;
relop : '>' {$$ = '>';}
- | '<' {$$ = '<';}
- | tGEQ {$$ = idGE;}
- | tLEQ {$$ = idLE;}
- ;
+ | '<' {$$ = '<';}
+ | tGEQ {$$ = idGE;}
+ | tLEQ {$$ = idLE;}
+ ;
rel_expr : arg relop arg %prec '>'
- {
- $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
- }
- | rel_expr relop arg %prec '>'
- {
- rb_warning1("comparison '%s' after comparison", WARN_ID($2));
- $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
- }
- ;
+ {
+ $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
+ }
+ | rel_expr relop arg %prec '>'
+ {
+ rb_warning1("comparison '%s' after comparison", WARN_ID($2));
+ $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
+ }
+ ;
lex_ctxt : none
- {
- $$ = p->ctxt;
- }
- ;
-
-begin_defined : lex_ctxt
- {
- p->ctxt.in_defined = 1;
- $$ = $1;
- }
- ;
-
-after_rescue : lex_ctxt
- {
- p->ctxt.in_rescue = after_rescue;
- $$ = $1;
- }
- ;
+ {
+ $$ = p->ctxt;
+ }
+ ;
arg_value : arg
- {
- value_expr($1);
- $$ = $1;
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ ;
aref_args : none
- | args trailer
- {
- $$ = $1;
- }
- | args ',' assocs trailer
- {
- /*%%%*/
- $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
- /*% %*/
- /*% ripper: args_add!($1, bare_assoc_hash!($3)) %*/
- }
- | assocs trailer
- {
- /*%%%*/
- $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@$) : 0;
- /*% %*/
- /*% ripper: args_add!(args_new!, bare_assoc_hash!($1)) %*/
- }
- ;
+ | args trailer
+ {
+ $$ = $1;
+ }
+ | args ',' assocs trailer
+ {
+ /*%%%*/
+ $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
+ /*% %*/
+ /*% ripper: args_add!($1, bare_assoc_hash!($3)) %*/
+ }
+ | assocs trailer
+ {
+ /*%%%*/
+ $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@$) : 0;
+ /*% %*/
+ /*% ripper: args_add!(args_new!, bare_assoc_hash!($1)) %*/
+ }
+ ;
arg_rhs : arg %prec tOP_ASGN
- {
- value_expr($1);
- $$ = $1;
- }
- | arg modifier_rescue after_rescue arg
- {
- p->ctxt.in_rescue = $3.in_rescue;
- /*%%%*/
- value_expr($1);
- $$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
- /*% %*/
- /*% ripper: rescue_mod!($1, $4) %*/
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | arg modifier_rescue arg
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = rescued_expr(p, $1, $3, &@1, &@2, &@3);
+ /*% %*/
+ /*% ripper: rescue_mod!($1, $3) %*/
+ }
+ ;
paren_args : '(' opt_call_args rparen
- {
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: arg_paren!($2) %*/
- }
- | '(' args ',' args_forward rparen
- {
- if (!check_forwarding_args(p)) {
- $$ = Qnone;
- }
- else {
- /*%%%*/
- $$ = new_args_forward_call(p, $2, &@4, &@$);
- /*% %*/
- /*% ripper: arg_paren!(args_add!($2, $4)) %*/
- }
- }
- | '(' args_forward rparen
- {
- if (!check_forwarding_args(p)) {
- $$ = Qnone;
- }
- else {
- /*%%%*/
- $$ = new_args_forward_call(p, 0, &@2, &@$);
- /*% %*/
- /*% ripper: arg_paren!($2) %*/
- }
- }
- ;
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: arg_paren!(escape_Qundef($2)) %*/
+ }
+ | '(' args ',' args_forward rparen
+ {
+ if (!check_forwarding_args(p)) {
+ $$ = Qnone;
+ }
+ else {
+ /*%%%*/
+ $$ = new_args_forward_call(p, $2, &@4, &@$);
+ /*% %*/
+ /*% ripper: arg_paren!(args_add!($2, $4)) %*/
+ }
+ }
+ | '(' args_forward rparen
+ {
+ if (!check_forwarding_args(p)) {
+ $$ = Qnone;
+ }
+ else {
+ /*%%%*/
+ $$ = new_args_forward_call(p, 0, &@2, &@$);
+ /*% %*/
+ /*% ripper: arg_paren!($2) %*/
+ }
+ }
+ ;
opt_paren_args : none
- | paren_args
- ;
+ | paren_args
+ ;
opt_call_args : none
- | call_args
- | args ','
- {
- $$ = $1;
- }
- | args ',' assocs ','
- {
- /*%%%*/
- $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
- /*% %*/
- /*% ripper: args_add!($1, bare_assoc_hash!($3)) %*/
- }
- | assocs ','
- {
- /*%%%*/
- $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
- /*% %*/
- /*% ripper: args_add!(args_new!, bare_assoc_hash!($1)) %*/
- }
- ;
+ | call_args
+ | args ','
+ {
+ $$ = $1;
+ }
+ | args ',' assocs ','
+ {
+ /*%%%*/
+ $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
+ /*% %*/
+ /*% ripper: args_add!($1, bare_assoc_hash!($3)) %*/
+ }
+ | assocs ','
+ {
+ /*%%%*/
+ $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
+ /*% %*/
+ /*% ripper: args_add!(args_new!, bare_assoc_hash!($1)) %*/
+ }
+ ;
call_args : command
- {
- /*%%%*/
- value_expr($1);
- $$ = NEW_LIST($1, &@$);
- /*% %*/
- /*% ripper: args_add!(args_new!, $1) %*/
- }
- | args opt_block_arg
- {
- /*%%%*/
- $$ = arg_blk_pass($1, $2);
- /*% %*/
- /*% ripper: args_add_block!($1, $2) %*/
- }
- | assocs opt_block_arg
- {
- /*%%%*/
- $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
- $$ = arg_blk_pass($$, $2);
- /*% %*/
- /*% ripper: args_add_block!(args_add!(args_new!, bare_assoc_hash!($1)), $2) %*/
- }
- | args ',' assocs opt_block_arg
- {
- /*%%%*/
- $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
- $$ = arg_blk_pass($$, $4);
- /*% %*/
- /*% ripper: args_add_block!(args_add!($1, bare_assoc_hash!($3)), $4) %*/
- }
- | block_arg
- /*% ripper[brace]: args_add_block!(args_new!, $1) %*/
- ;
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: args_add!(args_new!, $1) %*/
+ }
+ | args opt_block_arg
+ {
+ /*%%%*/
+ $$ = arg_blk_pass($1, $2);
+ /*% %*/
+ /*% ripper: args_add_block!($1, $2) %*/
+ }
+ | assocs opt_block_arg
+ {
+ /*%%%*/
+ $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
+ $$ = arg_blk_pass($$, $2);
+ /*% %*/
+ /*% ripper: args_add_block!(args_add!(args_new!, bare_assoc_hash!($1)), $2) %*/
+ }
+ | args ',' assocs opt_block_arg
+ {
+ /*%%%*/
+ $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
+ $$ = arg_blk_pass($$, $4);
+ /*% %*/
+ /*% ripper: args_add_block!(args_add!($1, bare_assoc_hash!($3)), $4) %*/
+ }
+ | block_arg
+ /*% ripper[brace]: args_add_block!(args_new!, $1) %*/
+ ;
command_args : {
- /* If call_args starts with a open paren '(' or '[',
- * look-ahead reading of the letters calls CMDARG_PUSH(0),
- * but the push must be done after CMDARG_PUSH(1).
- * So this code makes them consistent by first cancelling
- * the premature CMDARG_PUSH(0), doing CMDARG_PUSH(1),
- * and finally redoing CMDARG_PUSH(0).
- */
- int lookahead = 0;
- switch (yychar) {
- case '(': case tLPAREN: case tLPAREN_ARG: case '[': case tLBRACK:
- lookahead = 1;
- }
- if (lookahead) CMDARG_POP();
- CMDARG_PUSH(1);
- if (lookahead) CMDARG_PUSH(0);
- }
- call_args
- {
- /* call_args can be followed by tLBRACE_ARG (that does CMDARG_PUSH(0) in the lexer)
- * but the push must be done after CMDARG_POP() in the parser.
- * So this code does CMDARG_POP() to pop 0 pushed by tLBRACE_ARG,
- * CMDARG_POP() to pop 1 pushed by command_args,
- * and CMDARG_PUSH(0) to restore back the flag set by tLBRACE_ARG.
- */
- int lookahead = 0;
- switch (yychar) {
- case tLBRACE_ARG:
- lookahead = 1;
- }
- if (lookahead) CMDARG_POP();
- CMDARG_POP();
- if (lookahead) CMDARG_PUSH(0);
- $$ = $2;
- }
- ;
+ /* If call_args starts with a open paren '(' or '[',
+ * look-ahead reading of the letters calls CMDARG_PUSH(0),
+ * but the push must be done after CMDARG_PUSH(1).
+ * So this code makes them consistent by first cancelling
+ * the premature CMDARG_PUSH(0), doing CMDARG_PUSH(1),
+ * and finally redoing CMDARG_PUSH(0).
+ */
+ int lookahead = 0;
+ switch (yychar) {
+ case '(': case tLPAREN: case tLPAREN_ARG: case '[': case tLBRACK:
+ lookahead = 1;
+ }
+ if (lookahead) CMDARG_POP();
+ CMDARG_PUSH(1);
+ if (lookahead) CMDARG_PUSH(0);
+ }
+ call_args
+ {
+ /* call_args can be followed by tLBRACE_ARG (that does CMDARG_PUSH(0) in the lexer)
+ * but the push must be done after CMDARG_POP() in the parser.
+ * So this code does CMDARG_POP() to pop 0 pushed by tLBRACE_ARG,
+ * CMDARG_POP() to pop 1 pushed by command_args,
+ * and CMDARG_PUSH(0) to restore back the flag set by tLBRACE_ARG.
+ */
+ int lookahead = 0;
+ switch (yychar) {
+ case tLBRACE_ARG:
+ lookahead = 1;
+ }
+ if (lookahead) CMDARG_POP();
+ CMDARG_POP();
+ if (lookahead) CMDARG_PUSH(0);
+ $$ = $2;
+ }
+ ;
block_arg : tAMPER arg_value
- {
- /*%%%*/
- $$ = NEW_BLOCK_PASS($2, &@$);
- /*% %*/
- /*% ripper: $2 %*/
- }
+ {
+ /*%%%*/
+ $$ = NEW_BLOCK_PASS($2, &@$);
+ /*% %*/
+ /*% ripper: $2 %*/
+ }
| tAMPER
{
if (!local_id(p, idFWD_BLOCK)) {
@@ -3749,1836 +3136,1829 @@ block_arg : tAMPER arg_value
/*% %*/
/*% ripper: Qnil %*/
}
- ;
+ ;
opt_block_arg : ',' block_arg
- {
- $$ = $2;
- }
- | none
- {
- $$ = 0;
- }
- ;
+ {
+ $$ = $2;
+ }
+ | none
+ {
+ $$ = 0;
+ }
+ ;
/* value */
args : arg_value
- {
- /*%%%*/
- $$ = NEW_LIST($1, &@$);
- /*% %*/
- /*% ripper: args_add!(args_new!, $1) %*/
- }
- | tSTAR arg_value
- {
- /*%%%*/
- $$ = NEW_SPLAT($2, &@$);
- /*% %*/
- /*% ripper: args_add_star!(args_new!, $2) %*/
- }
- | tSTAR
- {
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: args_add!(args_new!, $1) %*/
+ }
+ | tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = NEW_SPLAT($2, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!(args_new!, $2) %*/
+ }
+ | tSTAR
+ {
if (!local_id(p, idFWD_REST) ||
local_id(p, idFWD_ALL)) {
compile_error(p, "no anonymous rest parameter");
}
- /*%%%*/
- $$ = NEW_SPLAT(NEW_LVAR(idFWD_REST, &@1), &@$);
- /*% %*/
- /*% ripper: args_add_star!(args_new!, Qnil) %*/
- }
- | args ',' arg_value
- {
- /*%%%*/
- $$ = last_arg_append(p, $1, $3, &@$);
- /*% %*/
- /*% ripper: args_add!($1, $3) %*/
- }
- | args ',' tSTAR arg_value
- {
- /*%%%*/
- $$ = rest_arg_append(p, $1, $4, &@$);
- /*% %*/
- /*% ripper: args_add_star!($1, $4) %*/
- }
- | args ',' tSTAR
- {
+ /*%%%*/
+ $$ = NEW_SPLAT(NEW_LVAR(idFWD_REST, &@1), &@$);
+ /*% %*/
+ /*% ripper: args_add_star!(args_new!, Qnil) %*/
+ }
+ | args ',' arg_value
+ {
+ /*%%%*/
+ $$ = last_arg_append(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: args_add!($1, $3) %*/
+ }
+ | args ',' tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, $4, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!($1, $4) %*/
+ }
+ | args ',' tSTAR
+ {
if (!local_id(p, idFWD_REST) ||
local_id(p, idFWD_ALL)) {
compile_error(p, "no anonymous rest parameter");
}
- /*%%%*/
- $$ = rest_arg_append(p, $1, NEW_LVAR(idFWD_REST, &@3), &@$);
- /*% %*/
- /*% ripper: args_add_star!($1, Qnil) %*/
- }
- ;
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, NEW_LVAR(idFWD_REST, &@3), &@$);
+ /*% %*/
+ /*% ripper: args_add_star!($1, Qnil) %*/
+ }
+ ;
/* value */
mrhs_arg : mrhs
- | arg_value
- ;
+ | arg_value
+ ;
/* value */
mrhs : args ',' arg_value
- {
- /*%%%*/
- $$ = last_arg_append(p, $1, $3, &@$);
- /*% %*/
- /*% ripper: mrhs_add!(mrhs_new_from_args!($1), $3) %*/
- }
- | args ',' tSTAR arg_value
- {
- /*%%%*/
- $$ = rest_arg_append(p, $1, $4, &@$);
- /*% %*/
- /*% ripper: mrhs_add_star!(mrhs_new_from_args!($1), $4) %*/
- }
- | tSTAR arg_value
- {
- /*%%%*/
- $$ = NEW_SPLAT($2, &@$);
- /*% %*/
- /*% ripper: mrhs_add_star!(mrhs_new!, $2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = last_arg_append(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: mrhs_add!(mrhs_new_from_args!($1), $3) %*/
+ }
+ | args ',' tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, $4, &@$);
+ /*% %*/
+ /*% ripper: mrhs_add_star!(mrhs_new_from_args!($1), $4) %*/
+ }
+ | tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = NEW_SPLAT($2, &@$);
+ /*% %*/
+ /*% ripper: mrhs_add_star!(mrhs_new!, $2) %*/
+ }
+ ;
primary : literal
- | strings
- | xstring
- | regexp
- | words
- | qwords
- | symbols
- | qsymbols
- | var_ref
- | backref
- | tFID
- {
- /*%%%*/
- $$ = (NODE *)NEW_FCALL($1, 0, &@$);
- /*% %*/
- /*% ripper: method_add_arg!(fcall!($1), args_new!) %*/
- }
- | k_begin
- {
- CMDARG_PUSH(0);
- }
- bodystmt
- k_end
- {
- CMDARG_POP();
- /*%%%*/
- set_line_body($3, @1.end_pos.lineno);
- $$ = NEW_BEGIN($3, &@$);
- nd_set_line($$, @1.end_pos.lineno);
- /*% %*/
- /*% ripper: begin!($3) %*/
- }
- | tLPAREN_ARG compstmt {SET_LEX_STATE(EXPR_ENDARG);} ')'
- {
- /*%%%*/
- if (nd_type_p($2, NODE_SELF)) RNODE_SELF($2)->nd_state = 0;
- $$ = $2;
- /*% %*/
- /*% ripper: paren!($2) %*/
- }
- | tLPAREN compstmt ')'
- {
- /*%%%*/
- if (nd_type_p($2, NODE_SELF)) RNODE_SELF($2)->nd_state = 0;
- $$ = $2;
- /*% %*/
- /*% ripper: paren!($2) %*/
- }
- | primary_value tCOLON2 tCONSTANT
- {
- /*%%%*/
- $$ = NEW_COLON2($1, $3, &@$);
- /*% %*/
- /*% ripper: const_path_ref!($1, $3) %*/
- }
- | tCOLON3 tCONSTANT
- {
- /*%%%*/
- $$ = NEW_COLON3($2, &@$);
- /*% %*/
- /*% ripper: top_const_ref!($2) %*/
- }
- | tLBRACK aref_args ']'
- {
- /*%%%*/
- $$ = make_list($2, &@$);
- /*% %*/
- /*% ripper: array!($2) %*/
- }
- | tLBRACE assoc_list '}'
- {
- /*%%%*/
- $$ = new_hash(p, $2, &@$);
- RNODE_HASH($$)->nd_brace = TRUE;
- /*% %*/
- /*% ripper: hash!($2) %*/
- }
- | k_return
- {
- /*%%%*/
- $$ = NEW_RETURN(0, &@$);
- /*% %*/
- /*% ripper: return0! %*/
- }
- | k_yield '(' call_args rparen
- {
- /*%%%*/
- $$ = new_yield(p, $3, &@$);
- /*% %*/
- /*% ripper: yield!(paren!($3)) %*/
- }
- | k_yield '(' rparen
- {
- /*%%%*/
- $$ = NEW_YIELD(0, &@$);
- /*% %*/
- /*% ripper: yield!(paren!(args_new!)) %*/
- }
- | k_yield
- {
- /*%%%*/
- $$ = NEW_YIELD(0, &@$);
- /*% %*/
- /*% ripper: yield0! %*/
- }
- | keyword_defined opt_nl '(' begin_defined expr rparen
- {
- p->ctxt.in_defined = $4.in_defined;
- $$ = new_defined(p, $5, &@$);
- }
- | keyword_not '(' expr rparen
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- }
- | keyword_not '(' rparen
- {
- $$ = call_uni_op(p, method_cond(p, new_nil(&@2), &@2), METHOD_NOT, &@1, &@$);
- }
- | fcall brace_block
- {
- /*%%%*/
- $$ = method_add_block(p, (NODE *)$1, $2, &@$);
- /*% %*/
- /*% ripper: method_add_block!(method_add_arg!(fcall!($1), args_new!), $2) %*/
- }
- | method_call
- | method_call brace_block
- {
- /*%%%*/
- block_dup_check(p, get_nd_args(p, $1), $2);
- $$ = method_add_block(p, $1, $2, &@$);
- /*% %*/
- /*% ripper: method_add_block!($1, $2) %*/
- }
- | lambda
- | k_if expr_value then
- compstmt
- if_tail
- k_end
- {
- /*%%%*/
- $$ = new_if(p, $2, $4, $5, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: if!($2, $4, $5) %*/
- }
- | k_unless expr_value then
- compstmt
- opt_else
- k_end
- {
- /*%%%*/
- $$ = new_unless(p, $2, $4, $5, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: unless!($2, $4, $5) %*/
- }
- | k_while expr_value_do
- compstmt
- k_end
- {
- restore_block_exit(p, $1);
- /*%%%*/
- $$ = NEW_WHILE(cond(p, $2, &@2), $3, 1, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: while!($2, $3) %*/
- }
- | k_until expr_value_do
- compstmt
- k_end
- {
- restore_block_exit(p, $1);
- /*%%%*/
- $$ = NEW_UNTIL(cond(p, $2, &@2), $3, 1, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: until!($2, $3) %*/
- }
- | k_case expr_value opt_terms
- {
- $<val>$ = p->case_labels;
- p->case_labels = Qnil;
- }
- case_body
- k_end
- {
- if (RTEST(p->case_labels)) rb_hash_clear(p->case_labels);
- p->case_labels = $<val>4;
- /*%%%*/
- $$ = NEW_CASE($2, $5, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: case!($2, $5) %*/
- }
- | k_case opt_terms
- {
- $<val>$ = p->case_labels;
- p->case_labels = 0;
- }
- case_body
- k_end
- {
- if (RTEST(p->case_labels)) rb_hash_clear(p->case_labels);
- p->case_labels = $<val>3;
- /*%%%*/
- $$ = NEW_CASE2($4, &@$);
- /*% %*/
- /*% ripper: case!(Qnil, $4) %*/
- }
- | k_case expr_value opt_terms
- p_case_body
- k_end
- {
- /*%%%*/
- $$ = NEW_CASE3($2, $4, &@$);
- /*% %*/
- /*% ripper: case!($2, $4) %*/
- }
- | k_for for_var keyword_in expr_value_do
- compstmt
- k_end
- {
- restore_block_exit(p, $1);
- /*%%%*/
- /*
- * for a, b, c in e
- * #=>
- * e.each{|*x| a, b, c = x}
- *
- * for a in e
- * #=>
- * e.each{|x| a, = x}
- */
- ID id = internal_id(p);
- rb_node_args_aux_t *m = NEW_ARGS_AUX(0, 0, &NULL_LOC);
- rb_node_args_t *args;
- NODE *scope, *internal_var = NEW_DVAR(id, &@2);
+ | strings
+ | xstring
+ | regexp
+ | words
+ | qwords
+ | symbols
+ | qsymbols
+ | var_ref
+ | backref
+ | tFID
+ {
+ /*%%%*/
+ $$ = NEW_FCALL($1, 0, &@$);
+ /*% %*/
+ /*% ripper: method_add_arg!(fcall!($1), args_new!) %*/
+ }
+ | k_begin
+ {
+ CMDARG_PUSH(0);
+ }
+ bodystmt
+ k_end
+ {
+ CMDARG_POP();
+ /*%%%*/
+ set_line_body($3, @1.end_pos.lineno);
+ $$ = NEW_BEGIN($3, &@$);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ /*% ripper: begin!($3) %*/
+ }
+ | tLPAREN_ARG {SET_LEX_STATE(EXPR_ENDARG);} rparen
+ {
+ /*%%%*/
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: paren!(0) %*/
+ }
+ | tLPAREN_ARG stmt {SET_LEX_STATE(EXPR_ENDARG);} rparen
+ {
+ /*%%%*/
+ if (nd_type_p($2, NODE_SELF)) $2->nd_state = 0;
+ $$ = $2;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ }
+ | tLPAREN compstmt ')'
+ {
+ /*%%%*/
+ if (nd_type_p($2, NODE_SELF)) $2->nd_state = 0;
+ $$ = $2;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ /*%%%*/
+ $$ = NEW_COLON2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_ref!($1, $3) %*/
+ }
+ | tCOLON3 tCONSTANT
+ {
+ /*%%%*/
+ $$ = NEW_COLON3($2, &@$);
+ /*% %*/
+ /*% ripper: top_const_ref!($2) %*/
+ }
+ | tLBRACK aref_args ']'
+ {
+ /*%%%*/
+ $$ = make_list($2, &@$);
+ /*% %*/
+ /*% ripper: array!(escape_Qundef($2)) %*/
+ }
+ | tLBRACE assoc_list '}'
+ {
+ /*%%%*/
+ $$ = new_hash(p, $2, &@$);
+ $$->nd_brace = TRUE;
+ /*% %*/
+ /*% ripper: hash!(escape_Qundef($2)) %*/
+ }
+ | k_return
+ {
+ /*%%%*/
+ $$ = NEW_RETURN(0, &@$);
+ /*% %*/
+ /*% ripper: return0! %*/
+ }
+ | keyword_yield '(' call_args rparen
+ {
+ /*%%%*/
+ $$ = new_yield(p, $3, &@$);
+ /*% %*/
+ /*% ripper: yield!(paren!($3)) %*/
+ }
+ | keyword_yield '(' rparen
+ {
+ /*%%%*/
+ $$ = NEW_YIELD(0, &@$);
+ /*% %*/
+ /*% ripper: yield!(paren!(args_new!)) %*/
+ }
+ | keyword_yield
+ {
+ /*%%%*/
+ $$ = NEW_YIELD(0, &@$);
+ /*% %*/
+ /*% ripper: yield0! %*/
+ }
+ | keyword_defined opt_nl '(' {p->ctxt.in_defined = 1;} expr rparen
+ {
+ p->ctxt.in_defined = 0;
+ $$ = new_defined(p, $5, &@$);
+ }
+ | keyword_not '(' expr rparen
+ {
+ $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
+ }
+ | keyword_not '(' rparen
+ {
+ $$ = call_uni_op(p, method_cond(p, new_nil(&@2), &@2), METHOD_NOT, &@1, &@$);
+ }
+ | fcall brace_block
+ {
+ /*%%%*/
+ $$ = method_add_block(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(method_add_arg!(fcall!($1), args_new!), $2) %*/
+ }
+ | method_call
+ | method_call brace_block
+ {
+ /*%%%*/
+ block_dup_check(p, $1->nd_args, $2);
+ $$ = method_add_block(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!($1, $2) %*/
+ }
+ | lambda
+ | k_if expr_value then
+ compstmt
+ if_tail
+ k_end
+ {
+ /*%%%*/
+ $$ = new_if(p, $2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: if!($2, $4, escape_Qundef($5)) %*/
+ }
+ | k_unless expr_value then
+ compstmt
+ opt_else
+ k_end
+ {
+ /*%%%*/
+ $$ = new_unless(p, $2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: unless!($2, $4, escape_Qundef($5)) %*/
+ }
+ | k_while expr_value_do
+ compstmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_WHILE(cond(p, $2, &@2), $3, 1, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: while!($2, $3) %*/
+ }
+ | k_until expr_value_do
+ compstmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_UNTIL(cond(p, $2, &@2), $3, 1, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: until!($2, $3) %*/
+ }
+ | k_case expr_value opt_terms
+ {
+ $<val>$ = p->case_labels;
+ p->case_labels = Qnil;
+ }
+ case_body
+ k_end
+ {
+ if (RTEST(p->case_labels)) rb_hash_clear(p->case_labels);
+ p->case_labels = $<val>4;
+ /*%%%*/
+ $$ = NEW_CASE($2, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: case!($2, $5) %*/
+ }
+ | k_case opt_terms
+ {
+ $<val>$ = p->case_labels;
+ p->case_labels = 0;
+ }
+ case_body
+ k_end
+ {
+ if (RTEST(p->case_labels)) rb_hash_clear(p->case_labels);
+ p->case_labels = $<val>3;
+ /*%%%*/
+ $$ = NEW_CASE2($4, &@$);
+ /*% %*/
+ /*% ripper: case!(Qnil, $4) %*/
+ }
+ | k_case expr_value opt_terms
+ p_case_body
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_CASE3($2, $4, &@$);
+ /*% %*/
+ /*% ripper: case!($2, $4) %*/
+ }
+ | k_for for_var keyword_in expr_value_do
+ compstmt
+ k_end
+ {
+ /*%%%*/
+ /*
+ * for a, b, c in e
+ * #=>
+ * e.each{|*x| a, b, c = x}
+ *
+ * for a in e
+ * #=>
+ * e.each{|x| a, = x}
+ */
+ ID id = internal_id(p);
+ NODE *m = NEW_ARGS_AUX(0, 0, &NULL_LOC);
+ NODE *args, *scope, *internal_var = NEW_DVAR(id, &@2);
rb_ast_id_table_t *tbl = rb_ast_new_local_table(p->ast, 1);
- tbl->ids[0] = id; /* internal id */
-
- switch (nd_type($2)) {
- case NODE_LASGN:
- case NODE_DASGN: /* e.each {|internal_var| a = internal_var; ... } */
- set_nd_value(p, $2, internal_var);
- id = 0;
- m->nd_plen = 1;
- m->nd_next = $2;
- break;
- case NODE_MASGN: /* e.each {|*internal_var| a, b, c = (internal_var.length == 1 && Array === (tmp = internal_var[0]) ? tmp : internal_var); ... } */
- m->nd_next = node_assign(p, $2, NEW_FOR_MASGN(internal_var, &@2), NO_LEX_CTXT, &@2);
- break;
- default: /* e.each {|*internal_var| @a, B, c[1], d.attr = internal_val; ... } */
- m->nd_next = node_assign(p, (NODE *)NEW_MASGN(NEW_LIST($2, &@2), 0, &@2), internal_var, NO_LEX_CTXT, &@2);
- }
- /* {|*internal_id| <m> = internal_id; ... } */
- args = new_args(p, m, 0, id, 0, new_args_tail(p, 0, 0, 0, &@2), &@2);
- scope = NEW_SCOPE2(tbl, args, $5, &@$);
- $$ = NEW_FOR($4, scope, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: for!($2, $4, $5) %*/
- }
- | k_class cpath superclass
- {
- begin_definition("class", &@k_class, &@cpath);
- }
- bodystmt
- k_end
- {
- /*%%%*/
- $$ = NEW_CLASS($cpath, $bodystmt, $superclass, &@$);
- nd_set_line(RNODE_CLASS($$)->nd_body, @k_end.end_pos.lineno);
- set_line_body($bodystmt, @superclass.end_pos.lineno);
- nd_set_line($$, @superclass.end_pos.lineno);
- /*% %*/
- /*% ripper: class!($cpath, $superclass, $bodystmt) %*/
- local_pop(p);
- p->ctxt.in_class = $k_class.in_class;
- p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
- }
- | k_class tLSHFT expr
- {
- begin_definition("", &@k_class, &@tLSHFT);
- }
- term
- bodystmt
- k_end
- {
- /*%%%*/
- $$ = NEW_SCLASS($expr, $bodystmt, &@$);
- nd_set_line(RNODE_SCLASS($$)->nd_body, @k_end.end_pos.lineno);
- set_line_body($bodystmt, nd_line($expr));
- fixpos($$, $expr);
- /*% %*/
- /*% ripper: sclass!($expr, $bodystmt) %*/
- local_pop(p);
- p->ctxt.in_def = $k_class.in_def;
- p->ctxt.in_class = $k_class.in_class;
- p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
- }
- | k_module cpath
- {
- begin_definition("module", &@k_module, &@cpath);
- }
- bodystmt
- k_end
- {
- /*%%%*/
- $$ = NEW_MODULE($cpath, $bodystmt, &@$);
- nd_set_line(RNODE_MODULE($$)->nd_body, @k_end.end_pos.lineno);
- set_line_body($bodystmt, @cpath.end_pos.lineno);
- nd_set_line($$, @cpath.end_pos.lineno);
- /*% %*/
- /*% ripper: module!($cpath, $bodystmt) %*/
- local_pop(p);
- p->ctxt.in_class = $k_module.in_class;
- p->ctxt.shareable_constant_value = $k_module.shareable_constant_value;
- }
- | defn_head[head]
- f_arglist[args]
- {
- /*%%%*/
- push_end_expect_token_locations(p, &@head.beg_pos);
- /*% %*/
- }
- bodystmt
- k_end
- {
- restore_defun(p, $head);
- /*%%%*/
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFN($$)->nd_defn = $bodystmt;
- /*% %*/
- /*% ripper: def!($head->nd_mid, $args, $bodystmt) %*/
- local_pop(p);
- }
- | defs_head[head]
- f_arglist[args]
- {
- /*%%%*/
- push_end_expect_token_locations(p, &@head.beg_pos);
- /*% %*/
- }
- bodystmt
- k_end
- {
- restore_defun(p, $head);
- /*%%%*/
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFS($$)->nd_defn = $bodystmt;
- /*% %*/
- /*% ripper: defs!($head->nd_recv, $head->dot_or_colon, $head->nd_mid, $args, $bodystmt) %*/
- local_pop(p);
- }
- | keyword_break
- {
- $<node>$ = add_block_exit(p, NEW_BREAK(0, &@$));
- /*% ripper: break!(args_new!) %*/
- }
- | keyword_next
- {
- $<node>$ = add_block_exit(p, NEW_NEXT(0, &@$));
- /*% ripper: next!(args_new!) %*/
- }
- | keyword_redo
- {
- $<node>$ = add_block_exit(p, NEW_REDO(&@$));
- /*% ripper: redo! %*/
- }
- | keyword_retry
- {
- if (!p->ctxt.in_defined) {
- switch (p->ctxt.in_rescue) {
- case before_rescue: yyerror1(&@1, "Invalid retry without rescue"); break;
- case after_rescue: /* ok */ break;
- case after_else: yyerror1(&@1, "Invalid retry after else"); break;
- case after_ensure: yyerror1(&@1, "Invalid retry after ensure"); break;
- }
- }
- /*%%%*/
- $$ = NEW_RETRY(&@$);
- /*% %*/
- /*% ripper: retry! %*/
- }
- ;
+ tbl->ids[0] = id; /* internal id */
+
+ switch (nd_type($2)) {
+ case NODE_LASGN:
+ case NODE_DASGN: /* e.each {|internal_var| a = internal_var; ... } */
+ $2->nd_value = internal_var;
+ id = 0;
+ m->nd_plen = 1;
+ m->nd_next = $2;
+ break;
+ case NODE_MASGN: /* e.each {|*internal_var| a, b, c = (internal_var.length == 1 && Array === (tmp = internal_var[0]) ? tmp : internal_var); ... } */
+ m->nd_next = node_assign(p, $2, NEW_FOR_MASGN(internal_var, &@2), NO_LEX_CTXT, &@2);
+ break;
+ default: /* e.each {|*internal_var| @a, B, c[1], d.attr = internal_val; ... } */
+ m->nd_next = node_assign(p, NEW_MASGN(NEW_LIST($2, &@2), 0, &@2), internal_var, NO_LEX_CTXT, &@2);
+ }
+ /* {|*internal_id| <m> = internal_id; ... } */
+ args = new_args(p, m, 0, id, 0, new_args_tail(p, 0, 0, 0, &@2), &@2);
+ scope = NEW_NODE(NODE_SCOPE, tbl, $5, args, &@$);
+ $$ = NEW_FOR($4, scope, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: for!($2, $4, $5) %*/
+ }
+ | k_class cpath superclass
+ {
+ if (p->ctxt.in_def) {
+ YYLTYPE loc = code_loc_gen(&@1, &@2);
+ yyerror1(&loc, "class definition in method body");
+ }
+ p->ctxt.in_class = 1;
+ local_push(p, 0);
+ }
+ bodystmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_CLASS($2, $5, $3, &@$);
+ nd_set_line($$->nd_body, @6.end_pos.lineno);
+ set_line_body($5, @3.end_pos.lineno);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: class!($2, $3, $5) %*/
+ local_pop(p);
+ p->ctxt.in_class = $<ctxt>1.in_class;
+ p->ctxt.shareable_constant_value = $<ctxt>1.shareable_constant_value;
+ }
+ | k_class tLSHFT expr
+ {
+ p->ctxt.in_def = 0;
+ p->ctxt.in_class = 0;
+ local_push(p, 0);
+ }
+ term
+ bodystmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_SCLASS($3, $6, &@$);
+ nd_set_line($$->nd_body, @7.end_pos.lineno);
+ set_line_body($6, nd_line($3));
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: sclass!($3, $6) %*/
+ local_pop(p);
+ p->ctxt.in_def = $<ctxt>1.in_def;
+ p->ctxt.in_class = $<ctxt>1.in_class;
+ p->ctxt.shareable_constant_value = $<ctxt>1.shareable_constant_value;
+ }
+ | k_module cpath
+ {
+ if (p->ctxt.in_def) {
+ YYLTYPE loc = code_loc_gen(&@1, &@2);
+ yyerror1(&loc, "module definition in method body");
+ }
+ p->ctxt.in_class = 1;
+ local_push(p, 0);
+ }
+ bodystmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_MODULE($2, $4, &@$);
+ nd_set_line($$->nd_body, @5.end_pos.lineno);
+ set_line_body($4, @2.end_pos.lineno);
+ nd_set_line($$, @2.end_pos.lineno);
+ /*% %*/
+ /*% ripper: module!($2, $4) %*/
+ local_pop(p);
+ p->ctxt.in_class = $<ctxt>1.in_class;
+ p->ctxt.shareable_constant_value = $<ctxt>1.shareable_constant_value;
+ }
+ | defn_head
+ f_arglist
+ {
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ bodystmt
+ k_end
+ {
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head
+ f_arglist
+ {
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ bodystmt
+ k_end
+ {
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | keyword_break
+ {
+ /*%%%*/
+ $$ = NEW_BREAK(0, &@$);
+ /*% %*/
+ /*% ripper: break!(args_new!) %*/
+ }
+ | keyword_next
+ {
+ /*%%%*/
+ $$ = NEW_NEXT(0, &@$);
+ /*% %*/
+ /*% ripper: next!(args_new!) %*/
+ }
+ | keyword_redo
+ {
+ /*%%%*/
+ $$ = NEW_REDO(&@$);
+ /*% %*/
+ /*% ripper: redo! %*/
+ }
+ | keyword_retry
+ {
+ /*%%%*/
+ $$ = NEW_RETRY(&@$);
+ /*% %*/
+ /*% ripper: retry! %*/
+ }
+ ;
primary_value : primary
- {
- value_expr($1);
- $$ = $1;
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ ;
k_begin : keyword_begin
- {
- token_info_push(p, "begin", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ token_info_push(p, "begin", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_if : keyword_if
- {
- WARN_EOL("if");
- token_info_push(p, "if", &@$);
- if (p->token_info && p->token_info->nonspc &&
- p->token_info->next && !strcmp(p->token_info->next->token, "else")) {
- const char *tok = p->lex.ptok - rb_strlen_lit("if");
- const char *beg = p->lex.pbeg + p->token_info->next->beg.column;
- beg += rb_strlen_lit("else");
- while (beg < tok && ISSPACE(*beg)) beg++;
- if (beg == tok) {
- p->token_info->nonspc = 0;
- }
- }
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ WARN_EOL("if");
+ token_info_push(p, "if", &@$);
+ if (p->token_info && p->token_info->nonspc &&
+ p->token_info->next && !strcmp(p->token_info->next->token, "else")) {
+ const char *tok = p->lex.ptok - rb_strlen_lit("if");
+ const char *beg = p->lex.pbeg + p->token_info->next->beg.column;
+ beg += rb_strlen_lit("else");
+ while (beg < tok && ISSPACE(*beg)) beg++;
+ if (beg == tok) {
+ p->token_info->nonspc = 0;
+ }
+ }
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_unless : keyword_unless
- {
- token_info_push(p, "unless", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
-
-k_while : keyword_while allow_exits
- {
- $$ = $allow_exits;
- token_info_push(p, "while", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
-
-k_until : keyword_until allow_exits
- {
- $$ = $allow_exits;
- token_info_push(p, "until", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ token_info_push(p, "unless", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
+
+k_while : keyword_while
+ {
+ token_info_push(p, "while", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
+
+k_until : keyword_until
+ {
+ token_info_push(p, "until", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_case : keyword_case
- {
- token_info_push(p, "case", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
-
-k_for : keyword_for allow_exits
- {
- $$ = $allow_exits;
- token_info_push(p, "for", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ token_info_push(p, "case", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
+
+k_for : keyword_for
+ {
+ token_info_push(p, "for", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_class : keyword_class
- {
- token_info_push(p, "class", &@$);
- $$ = p->ctxt;
- p->ctxt.in_rescue = before_rescue;
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ token_info_push(p, "class", &@$);
+ $<ctxt>$ = p->ctxt;
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_module : keyword_module
- {
- token_info_push(p, "module", &@$);
- $$ = p->ctxt;
- p->ctxt.in_rescue = before_rescue;
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ token_info_push(p, "module", &@$);
+ $<ctxt>$ = p->ctxt;
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_def : keyword_def
- {
- token_info_push(p, "def", &@$);
- $$ = NEW_DEF_TEMP(&@$);
- p->ctxt.in_argdef = 1;
- }
- ;
+ {
+ token_info_push(p, "def", &@$);
+ p->ctxt.in_argdef = 1;
+ }
+ ;
k_do : keyword_do
- {
- token_info_push(p, "do", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ token_info_push(p, "do", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+
+ }
+ ;
k_do_block : keyword_do_block
- {
- token_info_push(p, "do", &@$);
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- ;
+ {
+ token_info_push(p, "do", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_rescue : keyword_rescue
- {
- token_info_warn(p, "rescue", p->token_info, 1, &@$);
- $$ = p->ctxt;
- p->ctxt.in_rescue = after_rescue;
- }
- ;
+ {
+ token_info_warn(p, "rescue", p->token_info, 1, &@$);
+ }
+ ;
k_ensure : keyword_ensure
- {
- token_info_warn(p, "ensure", p->token_info, 1, &@$);
- $$ = p->ctxt;
- }
- ;
+ {
+ token_info_warn(p, "ensure", p->token_info, 1, &@$);
+ }
+ ;
k_when : keyword_when
- {
- token_info_warn(p, "when", p->token_info, 0, &@$);
- }
- ;
+ {
+ token_info_warn(p, "when", p->token_info, 0, &@$);
+ }
+ ;
k_else : keyword_else
- {
- token_info *ptinfo_beg = p->token_info;
- int same = ptinfo_beg && strcmp(ptinfo_beg->token, "case") != 0;
- token_info_warn(p, "else", p->token_info, same, &@$);
- if (same) {
- token_info e;
- e.next = ptinfo_beg->next;
- e.token = "else";
- token_info_setup(&e, p->lex.pbeg, &@$);
- if (!e.nonspc) *ptinfo_beg = e;
- }
- }
- ;
+ {
+ token_info *ptinfo_beg = p->token_info;
+ int same = ptinfo_beg && strcmp(ptinfo_beg->token, "case") != 0;
+ token_info_warn(p, "else", p->token_info, same, &@$);
+ if (same) {
+ token_info e;
+ e.next = ptinfo_beg->next;
+ e.token = "else";
+ token_info_setup(&e, p->lex.pbeg, &@$);
+ if (!e.nonspc) *ptinfo_beg = e;
+ }
+ }
+ ;
k_elsif : keyword_elsif
- {
- WARN_EOL("elsif");
- token_info_warn(p, "elsif", p->token_info, 1, &@$);
- }
- ;
+ {
+ WARN_EOL("elsif");
+ token_info_warn(p, "elsif", p->token_info, 1, &@$);
+ }
+ ;
k_end : keyword_end
- {
- token_info_pop(p, "end", &@$);
- /*%%%*/
- pop_end_expect_token_locations(p);
- /*% %*/
- }
- | tDUMNY_END
- {
- compile_error(p, "syntax error, unexpected end-of-input");
- }
- ;
+ {
+ token_info_pop(p, "end", &@$);
+ /*%%%*/
+ pop_end_expect_token_locations(p);
+ /*% %*/
+ }
+ | tDUMNY_END
+ {
+ compile_error(p, "syntax error, unexpected end-of-input");
+ }
+ ;
k_return : keyword_return
- {
- if (p->ctxt.in_class && !p->ctxt.in_def && !dyna_in_block(p))
- yyerror1(&@1, "Invalid return in class/module body");
- }
- ;
-
-k_yield : keyword_yield
- {
- if (!p->ctxt.in_defined && !p->ctxt.in_def && !compile_for_eval)
- yyerror1(&@1, "Invalid yield");
- }
- ;
+ {
+ if (p->ctxt.in_class && !p->ctxt.in_def && !dyna_in_block(p))
+ yyerror1(&@1, "Invalid return in class/module body");
+ }
+ ;
then : term
- | keyword_then
- | term keyword_then
- ;
+ | keyword_then
+ | term keyword_then
+ ;
do : term
- | keyword_do_cond
- ;
+ | keyword_do_cond
+ ;
if_tail : opt_else
- | k_elsif expr_value then
- compstmt
- if_tail
- {
- /*%%%*/
- $$ = new_if(p, $2, $4, $5, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: elsif!($2, $4, $5) %*/
- }
- ;
+ | k_elsif expr_value then
+ compstmt
+ if_tail
+ {
+ /*%%%*/
+ $$ = new_if(p, $2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: elsif!($2, $4, escape_Qundef($5)) %*/
+ }
+ ;
opt_else : none
- | k_else compstmt
- {
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: else!($2) %*/
- }
- ;
+ | k_else compstmt
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: else!($2) %*/
+ }
+ ;
for_var : lhs
- | mlhs
- ;
+ | mlhs
+ ;
f_marg : f_norm_arg
- {
- /*%%%*/
- $$ = assignable(p, $1, 0, &@$);
- mark_lvar_used(p, $$);
- /*% %*/
- /*% ripper: assignable(p, $1) %*/
- }
- | tLPAREN f_margs rparen
- {
- /*%%%*/
- $$ = (NODE *)$2;
- /*% %*/
- /*% ripper: mlhs_paren!($2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ mark_lvar_used(p, $$);
+ /*% %*/
+ /*% ripper: assignable(p, $1) %*/
+ }
+ | tLPAREN f_margs rparen
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
f_marg_list : f_marg
- {
- /*%%%*/
- $$ = NEW_LIST($1, &@$);
- /*% %*/
- /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
- }
- | f_marg_list ',' f_marg
- {
- /*%%%*/
- $$ = list_append(p, $1, $3);
- /*% %*/
- /*% ripper: mlhs_add!($1, $3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
+ }
+ | f_marg_list ',' f_marg
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $3);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $3) %*/
+ }
+ ;
f_margs : f_marg_list
- {
- /*%%%*/
- $$ = NEW_MASGN($1, 0, &@$);
- /*% %*/
- /*% ripper: $1 %*/
- }
- | f_marg_list ',' f_rest_marg
- {
- /*%%%*/
- $$ = NEW_MASGN($1, $3, &@$);
- /*% %*/
- /*% ripper: mlhs_add_star!($1, $3) %*/
- }
- | f_marg_list ',' f_rest_marg ',' f_marg_list
- {
- /*%%%*/
- $$ = NEW_MASGN($1, NEW_POSTARG($3, $5, &@$), &@$);
- /*% %*/
- /*% ripper: mlhs_add_post!(mlhs_add_star!($1, $3), $5) %*/
- }
- | f_rest_marg
- {
- /*%%%*/
- $$ = NEW_MASGN(0, $1, &@$);
- /*% %*/
- /*% ripper: mlhs_add_star!(mlhs_new!, $1) %*/
- }
- | f_rest_marg ',' f_marg_list
- {
- /*%%%*/
- $$ = NEW_MASGN(0, NEW_POSTARG($1, $3, &@$), &@$);
- /*% %*/
- /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $1), $3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, 0, &@$);
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ | f_marg_list ',' f_rest_marg
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, $3, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!($1, $3) %*/
+ }
+ | f_marg_list ',' f_rest_marg ',' f_marg_list
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NEW_POSTARG($3, $5, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!($1, $3), $5) %*/
+ }
+ | f_rest_marg
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, $1, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!(mlhs_new!, $1) %*/
+ }
+ | f_rest_marg ',' f_marg_list
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NEW_POSTARG($1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $1), $3) %*/
+ }
+ ;
f_rest_marg : tSTAR f_norm_arg
- {
- /*%%%*/
- $$ = assignable(p, $2, 0, &@$);
- mark_lvar_used(p, $$);
- /*% %*/
- /*% ripper: assignable(p, $2) %*/
- }
- | tSTAR
- {
- /*%%%*/
- $$ = NODE_SPECIAL_NO_NAME_REST;
- /*% %*/
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = assignable(p, $2, 0, &@$);
+ mark_lvar_used(p, $$);
+ /*% %*/
+ /*% ripper: assignable(p, $2) %*/
+ }
+ | tSTAR
+ {
+ /*%%%*/
+ $$ = NODE_SPECIAL_NO_NAME_REST;
+ /*% %*/
+ /*% ripper: Qnil %*/
+ }
+ ;
f_any_kwrest : f_kwrest
- | f_no_kwarg {$$ = ID2VAL(idNil);}
- ;
+ | f_no_kwarg {$$ = ID2VAL(idNil);}
+ ;
f_eq : {p->ctxt.in_argdef = 0;} '=';
block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, $3, $4, &@3);
- }
- | f_block_kwarg opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, Qnone, $2, &@1);
- }
- | f_any_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, Qnone, $1, $2, &@1);
- }
- | f_block_arg
- {
- $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
- }
- ;
+ {
+ $$ = new_args_tail(p, $1, $3, $4, &@3);
+ }
+ | f_block_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, Qnone, $2, &@1);
+ }
+ | f_any_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, $1, $2, &@1);
+ }
+ | f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
+ }
+ ;
opt_block_args_tail : ',' block_args_tail
- {
- $$ = $2;
- }
- | /* none */
- {
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- }
- ;
+ {
+ $$ = $2;
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ }
+ ;
excessed_comma : ','
- {
- /* magic number for rest_id in iseq_set_arguments() */
- /*%%%*/
- $$ = NODE_SPECIAL_EXCESSIVE_COMMA;
- /*% %*/
- /*% ripper: excessed_comma! %*/
- }
- ;
+ {
+ /* magic number for rest_id in iseq_set_arguments() */
+ /*%%%*/
+ $$ = NODE_SPECIAL_EXCESSIVE_COMMA;
+ /*% %*/
+ /*% ripper: excessed_comma! %*/
+ }
+ ;
block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
- {
- $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
- }
- | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
- {
- $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
- }
- | f_arg ',' f_block_optarg opt_block_args_tail
- {
- $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
- }
- | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
- {
- $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
- }
+ {
+ $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
+ }
+ | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
+ }
+ | f_arg ',' f_block_optarg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
+ }
+ | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
+ }
| f_arg ',' f_rest_arg opt_block_args_tail
- {
- $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
- }
- | f_arg excessed_comma
- {
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@2);
- $$ = new_args(p, $1, Qnone, $2, Qnone, $$, &@$);
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
- {
- $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
- }
- | f_arg opt_block_args_tail
- {
- $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
- }
- | f_block_optarg ',' f_rest_arg opt_block_args_tail
- {
- $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
- }
- | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
- {
- $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
- }
- | f_block_optarg opt_block_args_tail
- {
- $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
- }
- | f_block_optarg ',' f_arg opt_block_args_tail
- {
- $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
- }
- | f_rest_arg opt_block_args_tail
- {
- $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
- }
- | f_rest_arg ',' f_arg opt_block_args_tail
- {
- $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
- }
- | block_args_tail
- {
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
- }
- ;
+ {
+ $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
+ }
+ | f_arg excessed_comma
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@2);
+ $$ = new_args(p, $1, Qnone, $2, Qnone, $$, &@$);
+ }
+ | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
+ }
+ | f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
+ }
+ | f_block_optarg ',' f_rest_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
+ }
+ | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
+ }
+ | f_block_optarg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
+ }
+ | f_block_optarg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
+ }
+ | f_rest_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
+ }
+ | f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
+ }
+ | block_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
+ }
+ ;
opt_block_param : none
- | block_param_def
- {
- p->command_start = TRUE;
- }
- ;
+ | block_param_def
+ {
+ p->command_start = TRUE;
+ }
+ ;
block_param_def : '|' opt_bv_decl '|'
- {
- p->cur_arg = 0;
- p->max_numparam = ORDINAL_PARAM;
- p->ctxt.in_argdef = 0;
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: params!(Qnil,Qnil,Qnil,Qnil,Qnil,Qnil,Qnil) %*/
- /*% ripper: block_var!($$, $2) %*/
- }
- | '|' block_param opt_bv_decl '|'
- {
- p->cur_arg = 0;
- p->max_numparam = ORDINAL_PARAM;
- p->ctxt.in_argdef = 0;
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: block_var!($2, $3) %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ p->max_numparam = ORDINAL_PARAM;
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: block_var!(params!(Qnil,Qnil,Qnil,Qnil,Qnil,Qnil,Qnil), escape_Qundef($2)) %*/
+ }
+ | '|' block_param opt_bv_decl '|'
+ {
+ p->cur_arg = 0;
+ p->max_numparam = ORDINAL_PARAM;
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: block_var!(escape_Qundef($2), escape_Qundef($3)) %*/
+ }
+ ;
opt_bv_decl : opt_nl
- {
- $$ = 0;
- }
- | opt_nl ';' bv_decls opt_nl
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: $3 %*/
- }
- ;
+ {
+ $$ = 0;
+ }
+ | opt_nl ';' bv_decls opt_nl
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: $3 %*/
+ }
+ ;
bv_decls : bvar
- /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
- | bv_decls ',' bvar
- /*% ripper[brace]: rb_ary_push($1, get_value($3)) %*/
- ;
+ /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
+ | bv_decls ',' bvar
+ /*% ripper[brace]: rb_ary_push($1, get_value($3)) %*/
+ ;
bvar : tIDENTIFIER
- {
- new_bv(p, get_id($1));
- /*% ripper: get_value($1) %*/
- }
- | f_bad_arg
- {
- $$ = 0;
- }
- ;
-
-max_numparam : {
- $$ = p->max_numparam;
- p->max_numparam = 0;
- }
- ;
-
-numparam : {
- $$ = numparam_push(p);
- }
- ;
-
-lambda : tLAMBDA[dyna]
- {
- token_info_push(p, "->", &@1);
- $<vars>dyna = dyna_push(p);
- $<num>$ = p->lex.lpar_beg;
- p->lex.lpar_beg = p->lex.paren_nest;
- }[lpar]
- max_numparam numparam allow_exits
- f_larglist[args]
- {
- CMDARG_PUSH(0);
- }
- lambda_body[body]
- {
- int max_numparam = p->max_numparam;
- p->lex.lpar_beg = $<num>lpar;
- p->max_numparam = $max_numparam;
- restore_block_exit(p, $allow_exits);
- CMDARG_POP();
- $args = args_with_numbered(p, $args, max_numparam);
- /*%%%*/
+ {
+ new_bv(p, get_id($1));
+ /*% ripper: get_value($1) %*/
+ }
+ | f_bad_arg
+ {
+ $$ = 0;
+ }
+ ;
+
+lambda : tLAMBDA
+ {
+ token_info_push(p, "->", &@1);
+ $<vars>1 = dyna_push(p);
+ $<num>$ = p->lex.lpar_beg;
+ p->lex.lpar_beg = p->lex.paren_nest;
+ }
+ {
+ $<num>$ = p->max_numparam;
+ p->max_numparam = 0;
+ }
+ {
+ $<node>$ = numparam_push(p);
+ }
+ f_larglist
+ {
+ CMDARG_PUSH(0);
+ }
+ lambda_body
+ {
+ int max_numparam = p->max_numparam;
+ p->lex.lpar_beg = $<num>2;
+ p->max_numparam = $<num>3;
+ CMDARG_POP();
+ $5 = args_with_numbered(p, $5, max_numparam);
+ /*%%%*/
{
- YYLTYPE loc = code_loc_gen(&@args, &@body);
- $$ = NEW_LAMBDA($args, $body, &loc);
- nd_set_line(RNODE_LAMBDA($$)->nd_body, @body.end_pos.lineno);
- nd_set_line($$, @args.end_pos.lineno);
- nd_set_first_loc($$, @1.beg_pos);
+ YYLTYPE loc = code_loc_gen(&@5, &@7);
+ $$ = NEW_LAMBDA($5, $7, &loc);
+ nd_set_line($$->nd_body, @7.end_pos.lineno);
+ nd_set_line($$, @5.end_pos.lineno);
+ nd_set_first_loc($$, @1.beg_pos);
}
- /*% %*/
- /*% ripper: lambda!($args, $body) %*/
- numparam_pop(p, $numparam);
- dyna_pop(p, $<vars>dyna);
- }
- ;
+ /*% %*/
+ /*% ripper: lambda!($5, $7) %*/
+ numparam_pop(p, $<node>4);
+ dyna_pop(p, $<vars>1);
+ }
+ ;
f_larglist : '(' f_args opt_bv_decl ')'
- {
- p->ctxt.in_argdef = 0;
- /*%%%*/
- $$ = $2;
- p->max_numparam = ORDINAL_PARAM;
- /*% %*/
- /*% ripper: paren!($2) %*/
- }
- | f_args
- {
- p->ctxt.in_argdef = 0;
- /*%%%*/
- if (!args_info_empty_p(&$1->nd_ainfo))
- p->max_numparam = ORDINAL_PARAM;
- /*% %*/
- $$ = $1;
- }
- ;
+ {
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ $$ = $2;
+ p->max_numparam = ORDINAL_PARAM;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ }
+ | f_args
+ {
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ if (!args_info_empty_p($1->nd_ainfo))
+ p->max_numparam = ORDINAL_PARAM;
+ /*% %*/
+ $$ = $1;
+ }
+ ;
lambda_body : tLAMBEG compstmt '}'
- {
- token_info_pop(p, "}", &@3);
- $$ = $2;
- }
- | keyword_do_LAMBDA
- {
- /*%%%*/
- push_end_expect_token_locations(p, &@1.beg_pos);
- /*% %*/
- }
- bodystmt k_end
- {
- $$ = $3;
- }
- ;
+ {
+ token_info_pop(p, "}", &@3);
+ $$ = $2;
+ }
+ | keyword_do_LAMBDA
+ {
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ bodystmt k_end
+ {
+ $$ = $3;
+ }
+ ;
do_block : k_do_block do_body k_end
- {
- $$ = $2;
- /*%%%*/
- set_embraced_location($$, &@1, &@3);
- /*% %*/
- }
- ;
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ ;
block_call : command do_block
- {
- /*%%%*/
- if (nd_type_p($1, NODE_YIELD)) {
- compile_error(p, "block given to yield");
- }
- else {
- block_dup_check(p, get_nd_args(p, $1), $2);
- }
- $$ = method_add_block(p, $1, $2, &@$);
- fixpos($$, $1);
- /*% %*/
- /*% ripper: method_add_block!($1, $2) %*/
- }
- | block_call call_op2 operation2 opt_paren_args
- {
- /*%%%*/
- $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
- /*% %*/
- /*% ripper: opt_event(:method_add_arg!, call!($1, $2, $3), $4) %*/
- }
- | block_call call_op2 operation2 opt_paren_args brace_block
- {
- /*%%%*/
- $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
- /*% %*/
- /*% ripper: opt_event(:method_add_block!, command_call!($1, $2, $3, $4), $5) %*/
- }
- | block_call call_op2 operation2 command_args do_block
- {
- /*%%%*/
- $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
- /*% %*/
- /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
- }
- ;
+ {
+ /*%%%*/
+ if (nd_type_p($1, NODE_YIELD)) {
+ compile_error(p, "block given to yield");
+ }
+ else {
+ block_dup_check(p, $1->nd_args, $2);
+ }
+ $$ = method_add_block(p, $1, $2, &@$);
+ fixpos($$, $1);
+ /*% %*/
+ /*% ripper: method_add_block!($1, $2) %*/
+ }
+ | block_call call_op2 operation2 opt_paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
+ /*% %*/
+ /*% ripper: opt_event(:method_add_arg!, call!($1, $2, $3), $4) %*/
+ }
+ | block_call call_op2 operation2 opt_paren_args brace_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: opt_event(:method_add_block!, command_call!($1, $2, $3, $4), $5) %*/
+ }
+ | block_call call_op2 operation2 command_args do_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
+ }
+ ;
method_call : fcall paren_args
- {
- /*%%%*/
- $1->nd_args = $2;
- $$ = (NODE *)$1;
- nd_set_last_loc($1, @2.end_pos);
- /*% %*/
- /*% ripper: method_add_arg!(fcall!($1), $2) %*/
- }
- | primary_value call_op operation2 opt_paren_args
- {
- /*%%%*/
- $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
- nd_set_line($$, @3.end_pos.lineno);
- /*% %*/
- /*% ripper: opt_event(:method_add_arg!, call!($1, $2, $3), $4) %*/
- }
- | primary_value tCOLON2 operation2 paren_args
- {
- /*%%%*/
- $$ = new_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, &@3, &@$);
- nd_set_line($$, @3.end_pos.lineno);
- /*% %*/
- /*% ripper: method_add_arg!(call!($1, $2, $3), $4) %*/
- }
- | primary_value tCOLON2 operation3
- {
- /*%%%*/
- $$ = new_qcall(p, ID2VAL(idCOLON2), $1, $3, Qnull, &@3, &@$);
- /*% %*/
- /*% ripper: call!($1, $2, $3) %*/
- }
- | primary_value call_op paren_args
- {
- /*%%%*/
- $$ = new_qcall(p, $2, $1, ID2VAL(idCall), $3, &@2, &@$);
- nd_set_line($$, @2.end_pos.lineno);
- /*% %*/
- /*% ripper: method_add_arg!(call!($1, $2, ID2VAL(idCall)), $3) %*/
- }
- | primary_value tCOLON2 paren_args
- {
- /*%%%*/
- $$ = new_qcall(p, ID2VAL(idCOLON2), $1, ID2VAL(idCall), $3, &@2, &@$);
- nd_set_line($$, @2.end_pos.lineno);
- /*% %*/
- /*% ripper: method_add_arg!(call!($1, $2, ID2VAL(idCall)), $3) %*/
- }
- | keyword_super paren_args
- {
- /*%%%*/
- $$ = NEW_SUPER($2, &@$);
- /*% %*/
- /*% ripper: super!($2) %*/
- }
- | keyword_super
- {
- /*%%%*/
- $$ = NEW_ZSUPER(&@$);
- /*% %*/
- /*% ripper: zsuper! %*/
- }
- | primary_value '[' opt_call_args rbracket
- {
- /*%%%*/
- $$ = NEW_CALL($1, tAREF, $3, &@$);
- fixpos($$, $1);
- /*% %*/
- /*% ripper: aref!($1, $3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = $1;
+ $$->nd_args = $2;
+ nd_set_last_loc($1, @2.end_pos);
+ /*% %*/
+ /*% ripper: method_add_arg!(fcall!($1), $2) %*/
+ }
+ | primary_value call_op operation2 opt_paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: opt_event(:method_add_arg!, call!($1, $2, $3), $4) %*/
+ }
+ | primary_value tCOLON2 operation2 paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, &@3, &@$);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, $3), $4) %*/
+ }
+ | primary_value tCOLON2 operation3
+ {
+ /*%%%*/
+ $$ = new_qcall(p, ID2VAL(idCOLON2), $1, $3, Qnull, &@3, &@$);
+ /*% %*/
+ /*% ripper: call!($1, $2, $3) %*/
+ }
+ | primary_value call_op paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, ID2VAL(idCall), $3, &@2, &@$);
+ nd_set_line($$, @2.end_pos.lineno);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, ID2VAL(idCall)), $3) %*/
+ }
+ | primary_value tCOLON2 paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, ID2VAL(idCOLON2), $1, ID2VAL(idCall), $3, &@2, &@$);
+ nd_set_line($$, @2.end_pos.lineno);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, ID2VAL(idCall)), $3) %*/
+ }
+ | keyword_super paren_args
+ {
+ /*%%%*/
+ $$ = NEW_SUPER($2, &@$);
+ /*% %*/
+ /*% ripper: super!($2) %*/
+ }
+ | keyword_super
+ {
+ /*%%%*/
+ $$ = NEW_ZSUPER(&@$);
+ /*% %*/
+ /*% ripper: zsuper! %*/
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ /*%%%*/
+ if ($1 && nd_type_p($1, NODE_SELF))
+ $$ = NEW_FCALL(tAREF, $3, &@$);
+ else
+ $$ = NEW_CALL($1, tAREF, $3, &@$);
+ fixpos($$, $1);
+ /*% %*/
+ /*% ripper: aref!($1, escape_Qundef($3)) %*/
+ }
+ ;
brace_block : '{' brace_body '}'
- {
- $$ = $2;
- /*%%%*/
- set_embraced_location($$, &@1, &@3);
- /*% %*/
- }
- | k_do do_body k_end
- {
- $$ = $2;
- /*%%%*/
- set_embraced_location($$, &@1, &@3);
- /*% %*/
- }
- ;
-
-brace_body : {$<vars>$ = dyna_push(p);}[dyna]
- max_numparam numparam allow_exits
- opt_block_param[args] compstmt
- {
- int max_numparam = p->max_numparam;
- p->max_numparam = $max_numparam;
- $args = args_with_numbered(p, $args, max_numparam);
- /*%%%*/
- $$ = NEW_ITER($args, $compstmt, &@$);
- /*% %*/
- /*% ripper: brace_block!($args, $compstmt) %*/
- restore_block_exit(p, $allow_exits);
- numparam_pop(p, $numparam);
- dyna_pop(p, $<vars>dyna);
- }
- ;
-
-do_body : {
- $<vars>$ = dyna_push(p);
- CMDARG_PUSH(0);
- }[dyna]
- max_numparam numparam allow_exits
- opt_block_param[args] bodystmt
- {
- int max_numparam = p->max_numparam;
- p->max_numparam = $max_numparam;
- $args = args_with_numbered(p, $args, max_numparam);
- /*%%%*/
- $$ = NEW_ITER($args, $bodystmt, &@$);
- /*% %*/
- /*% ripper: do_block!($args, $bodystmt) %*/
- CMDARG_POP();
- restore_block_exit(p, $allow_exits);
- numparam_pop(p, $numparam);
- dyna_pop(p, $<vars>dyna);
- }
- ;
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ | k_do do_body k_end
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ ;
+
+brace_body : {$<vars>$ = dyna_push(p);}
+ {
+ $<num>$ = p->max_numparam;
+ p->max_numparam = 0;
+ }
+ {
+ $<node>$ = numparam_push(p);
+ }
+ opt_block_param compstmt
+ {
+ int max_numparam = p->max_numparam;
+ p->max_numparam = $<num>2;
+ $4 = args_with_numbered(p, $4, max_numparam);
+ /*%%%*/
+ $$ = NEW_ITER($4, $5, &@$);
+ /*% %*/
+ /*% ripper: brace_block!(escape_Qundef($4), $5) %*/
+ numparam_pop(p, $<node>3);
+ dyna_pop(p, $<vars>1);
+ }
+ ;
+
+do_body : {$<vars>$ = dyna_push(p);}
+ {
+ $<num>$ = p->max_numparam;
+ p->max_numparam = 0;
+ }
+ {
+ $<node>$ = numparam_push(p);
+ CMDARG_PUSH(0);
+ }
+ opt_block_param bodystmt
+ {
+ int max_numparam = p->max_numparam;
+ p->max_numparam = $<num>2;
+ $4 = args_with_numbered(p, $4, max_numparam);
+ /*%%%*/
+ $$ = NEW_ITER($4, $5, &@$);
+ /*% %*/
+ /*% ripper: do_block!(escape_Qundef($4), $5) %*/
+ CMDARG_POP();
+ numparam_pop(p, $<node>3);
+ dyna_pop(p, $<vars>1);
+ }
+ ;
case_args : arg_value
- {
- /*%%%*/
- check_literal_when(p, $1, &@1);
- $$ = NEW_LIST($1, &@$);
- /*% %*/
- /*% ripper: args_add!(args_new!, $1) %*/
- }
- | tSTAR arg_value
- {
- /*%%%*/
- $$ = NEW_SPLAT($2, &@$);
- /*% %*/
- /*% ripper: args_add_star!(args_new!, $2) %*/
- }
- | case_args ',' arg_value
- {
- /*%%%*/
- check_literal_when(p, $3, &@3);
- $$ = last_arg_append(p, $1, $3, &@$);
- /*% %*/
- /*% ripper: args_add!($1, $3) %*/
- }
- | case_args ',' tSTAR arg_value
- {
- /*%%%*/
- $$ = rest_arg_append(p, $1, $4, &@$);
- /*% %*/
- /*% ripper: args_add_star!($1, $4) %*/
- }
- ;
+ {
+ /*%%%*/
+ check_literal_when(p, $1, &@1);
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: args_add!(args_new!, $1) %*/
+ }
+ | tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = NEW_SPLAT($2, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!(args_new!, $2) %*/
+ }
+ | case_args ',' arg_value
+ {
+ /*%%%*/
+ check_literal_when(p, $3, &@3);
+ $$ = last_arg_append(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: args_add!($1, $3) %*/
+ }
+ | case_args ',' tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, $4, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!($1, $4) %*/
+ }
+ ;
case_body : k_when case_args then
- compstmt
- cases
- {
- /*%%%*/
- $$ = NEW_WHEN($2, $4, $5, &@$);
- fixpos($$, $2);
- /*% %*/
- /*% ripper: when!($2, $4, $5) %*/
- }
- ;
+ compstmt
+ cases
+ {
+ /*%%%*/
+ $$ = NEW_WHEN($2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: when!($2, $4, escape_Qundef($5)) %*/
+ }
+ ;
cases : opt_else
- | case_body
- ;
-
-p_pvtbl : {$$ = p->pvtbl; p->pvtbl = st_init_numtable();};
-p_pktbl : {$$ = p->pktbl; p->pktbl = 0;};
-
-p_in_kwarg : {
- $$ = p->ctxt;
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p->command_start = FALSE;
- p->ctxt.in_kwarg = 1;
- }
- ;
+ | case_body
+ ;
p_case_body : keyword_in
- p_in_kwarg[ctxt] p_pvtbl p_pktbl
- p_top_expr[expr] then
- {
- pop_pktbl(p, $p_pktbl);
- pop_pvtbl(p, $p_pvtbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- }
- compstmt
- p_cases[cases]
- {
- /*%%%*/
- $$ = NEW_IN($expr, $compstmt, $cases, &@$);
- /*% %*/
- /*% ripper: in!($expr, $compstmt, $cases) %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>1 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+ }
+ {
+ $<tbl>$ = push_pktbl(p);
+ }
+ p_top_expr then
+ {
+ pop_pktbl(p, $<tbl>3);
+ pop_pvtbl(p, $<tbl>2);
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+ }
+ compstmt
+ p_cases
+ {
+ /*%%%*/
+ $$ = NEW_IN($4, $7, $8, &@$);
+ /*% %*/
+ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
+ }
+ ;
p_cases : opt_else
- | p_case_body
- ;
+ | p_case_body
+ ;
p_top_expr : p_top_expr_body
- | p_top_expr_body modifier_if expr_value
- {
- /*%%%*/
- $$ = new_if(p, $3, $1, 0, &@$);
- fixpos($$, $3);
- /*% %*/
- /*% ripper: if_mod!($3, $1) %*/
- }
- | p_top_expr_body modifier_unless expr_value
- {
- /*%%%*/
- $$ = new_unless(p, $3, $1, 0, &@$);
- fixpos($$, $3);
- /*% %*/
- /*% ripper: unless_mod!($3, $1) %*/
- }
- ;
+ | p_top_expr_body modifier_if expr_value
+ {
+ /*%%%*/
+ $$ = new_if(p, $3, $1, 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: if_mod!($3, $1) %*/
+ }
+ | p_top_expr_body modifier_unless expr_value
+ {
+ /*%%%*/
+ $$ = new_unless(p, $3, $1, 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: unless_mod!($3, $1) %*/
+ }
+ ;
p_top_expr_body : p_expr
- | p_expr ','
- {
- $$ = new_array_pattern_tail(p, Qnone, 1, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, Qnone, get_value($1), $$, &@$);
- }
- | p_expr ',' p_args
- {
- $$ = new_array_pattern(p, Qnone, get_value($1), $3, &@$);
- /*%%%*/
- nd_set_first_loc($$, @1.beg_pos);
- /*%
- %*/
- }
- | p_find
- {
- $$ = new_find_pattern(p, Qnone, $1, &@$);
- }
- | p_args_tail
- {
- $$ = new_array_pattern(p, Qnone, Qnone, $1, &@$);
- }
- | p_kwargs
- {
- $$ = new_hash_pattern(p, Qnone, $1, &@$);
- }
- ;
+ | p_expr ','
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 1, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, Qnone, get_value($1), $$, &@$);
+ }
+ | p_expr ',' p_args
+ {
+ $$ = new_array_pattern(p, Qnone, get_value($1), $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_find
+ {
+ $$ = new_find_pattern(p, Qnone, $1, &@$);
+ }
+ | p_args_tail
+ {
+ $$ = new_array_pattern(p, Qnone, Qnone, $1, &@$);
+ }
+ | p_kwargs
+ {
+ $$ = new_hash_pattern(p, Qnone, $1, &@$);
+ }
+ ;
p_expr : p_as
- ;
+ ;
p_as : p_expr tASSOC p_variable
- {
- /*%%%*/
- NODE *n = NEW_LIST($1, &@$);
- n = list_append(p, n, $3);
- $$ = new_hash(p, n, &@$);
- /*% %*/
- /*% ripper: binary!($1, STATIC_ID2SYM((id_assoc)), $3) %*/
- }
- | p_alt
- ;
+ {
+ /*%%%*/
+ NODE *n = NEW_LIST($1, &@$);
+ n = list_append(p, n, $3);
+ $$ = new_hash(p, n, &@$);
+ /*% %*/
+ /*% ripper: binary!($1, STATIC_ID2SYM((id_assoc)), $3) %*/
+ }
+ | p_alt
+ ;
p_alt : p_alt '|' p_expr_basic
- {
- /*%%%*/
- $$ = NEW_OR($1, $3, &@$);
- /*% %*/
- /*% ripper: binary!($1, STATIC_ID2SYM(idOr), $3) %*/
- }
- | p_expr_basic
- ;
-
-p_lparen : '(' p_pktbl { $$ = $2;};
-p_lbracket : '[' p_pktbl { $$ = $2;};
+ {
+ /*%%%*/
+ $$ = NEW_NODE(NODE_OR, $1, $3, 0, &@$);
+ /*% %*/
+ /*% ripper: binary!($1, STATIC_ID2SYM(idOr), $3) %*/
+ }
+ | p_expr_basic
+ ;
+
+p_lparen : '(' {$<tbl>$ = push_pktbl(p);};
+p_lbracket : '[' {$<tbl>$ = push_pktbl(p);};
p_expr_basic : p_value
- | p_variable
- | p_const p_lparen[p_pktbl] p_args rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_array_pattern(p, $p_const, Qnone, $p_args, &@$);
- /*%%%*/
- nd_set_first_loc($$, @p_const.beg_pos);
- /*%
- %*/
- }
- | p_const p_lparen[p_pktbl] p_find rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_find_pattern(p, $p_const, $p_find, &@$);
- /*%%%*/
- nd_set_first_loc($$, @p_const.beg_pos);
- /*%
- %*/
- }
- | p_const p_lparen[p_pktbl] p_kwargs rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_hash_pattern(p, $p_const, $p_kwargs, &@$);
- /*%%%*/
- nd_set_first_loc($$, @p_const.beg_pos);
- /*%
- %*/
- }
- | p_const '(' rparen
- {
- $$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, $p_const, Qnone, $$, &@$);
- }
- | p_const p_lbracket[p_pktbl] p_args rbracket
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_array_pattern(p, $p_const, Qnone, $p_args, &@$);
- /*%%%*/
- nd_set_first_loc($$, @p_const.beg_pos);
- /*%
- %*/
- }
- | p_const p_lbracket[p_pktbl] p_find rbracket
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_find_pattern(p, $p_const, $p_find, &@$);
- /*%%%*/
- nd_set_first_loc($$, @p_const.beg_pos);
- /*%
- %*/
- }
- | p_const p_lbracket[p_pktbl] p_kwargs rbracket
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_hash_pattern(p, $p_const, $p_kwargs, &@$);
- /*%%%*/
- nd_set_first_loc($$, @p_const.beg_pos);
- /*%
- %*/
- }
- | p_const '[' rbracket
- {
- $$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, $1, Qnone, $$, &@$);
- }
- | tLBRACK p_args rbracket
- {
- $$ = new_array_pattern(p, Qnone, Qnone, $p_args, &@$);
- }
- | tLBRACK p_find rbracket
- {
- $$ = new_find_pattern(p, Qnone, $p_find, &@$);
- }
- | tLBRACK rbracket
- {
- $$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
- $$ = new_array_pattern(p, Qnone, Qnone, $$, &@$);
- }
- | tLBRACE p_pktbl lex_ctxt[ctxt]
- {
- p->ctxt.in_kwarg = 0;
- }
- p_kwargs rbrace
- {
- pop_pktbl(p, $p_pktbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- $$ = new_hash_pattern(p, Qnone, $p_kwargs, &@$);
- }
- | tLBRACE rbrace
- {
- $$ = new_hash_pattern_tail(p, Qnone, 0, &@$);
- $$ = new_hash_pattern(p, Qnone, $$, &@$);
- }
- | tLPAREN p_pktbl p_expr rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = $p_expr;
- }
- ;
+ | p_variable
+ | p_const p_lparen p_args rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_array_pattern(p, $1, Qnone, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lparen p_find rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_find_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lparen p_kwargs rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_hash_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const '(' rparen
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, $1, Qnone, $$, &@$);
+ }
+ | p_const p_lbracket p_args rbracket
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_array_pattern(p, $1, Qnone, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lbracket p_find rbracket
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_find_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lbracket p_kwargs rbracket
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_hash_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const '[' rbracket
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, $1, Qnone, $$, &@$);
+ }
+ | tLBRACK p_args rbracket
+ {
+ $$ = new_array_pattern(p, Qnone, Qnone, $2, &@$);
+ }
+ | tLBRACK p_find rbracket
+ {
+ $$ = new_find_pattern(p, Qnone, $2, &@$);
+ }
+ | tLBRACK rbracket
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, Qnone, Qnone, $$, &@$);
+ }
+ | tLBRACE
+ {
+ $<tbl>$ = push_pktbl(p);
+ $<ctxt>1 = p->ctxt;
+ p->ctxt.in_kwarg = 0;
+ }
+ p_kwargs rbrace
+ {
+ pop_pktbl(p, $<tbl>2);
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+ $$ = new_hash_pattern(p, Qnone, $3, &@$);
+ }
+ | tLBRACE rbrace
+ {
+ $$ = new_hash_pattern_tail(p, Qnone, 0, &@$);
+ $$ = new_hash_pattern(p, Qnone, $$, &@$);
+ }
+ | tLPAREN {$<tbl>$ = push_pktbl(p);} p_expr rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = $3;
+ }
+ ;
p_args : p_expr
- {
- /*%%%*/
- NODE *pre_args = NEW_LIST($1, &@$);
- $$ = new_array_pattern_tail(p, pre_args, 0, Qnone, Qnone, &@$);
- /*%
- $$ = new_array_pattern_tail(p, rb_ary_new_from_args(1, get_value($1)), 0, Qnone, Qnone, &@$);
- %*/
- }
- | p_args_head
- {
- $$ = new_array_pattern_tail(p, $1, 1, Qnone, Qnone, &@$);
- }
- | p_args_head p_arg
- {
- /*%%%*/
- $$ = new_array_pattern_tail(p, list_concat($1, $2), 0, Qnone, Qnone, &@$);
- /*%
- VALUE pre_args = rb_ary_concat($1, get_value($2));
- $$ = new_array_pattern_tail(p, pre_args, 0, Qnone, Qnone, &@$);
- %*/
- }
- | p_args_head p_rest
- {
- $$ = new_array_pattern_tail(p, $1, 1, $2, Qnone, &@$);
- }
- | p_args_head p_rest ',' p_args_post
- {
- $$ = new_array_pattern_tail(p, $1, 1, $2, $4, &@$);
- }
- | p_args_tail
- ;
+ {
+ /*%%%*/
+ NODE *pre_args = NEW_LIST($1, &@$);
+ $$ = new_array_pattern_tail(p, pre_args, 0, 0, Qnone, &@$);
+ /*%
+ $$ = new_array_pattern_tail(p, rb_ary_new_from_args(1, get_value($1)), 0, 0, Qnone, &@$);
+ %*/
+ }
+ | p_args_head
+ {
+ $$ = new_array_pattern_tail(p, $1, 1, 0, Qnone, &@$);
+ }
+ | p_args_head p_arg
+ {
+ /*%%%*/
+ $$ = new_array_pattern_tail(p, list_concat($1, $2), 0, 0, Qnone, &@$);
+ /*%
+ VALUE pre_args = rb_ary_concat($1, get_value($2));
+ $$ = new_array_pattern_tail(p, pre_args, 0, 0, Qnone, &@$);
+ %*/
+ }
+ | p_args_head p_rest
+ {
+ $$ = new_array_pattern_tail(p, $1, 1, $2, Qnone, &@$);
+ }
+ | p_args_head p_rest ',' p_args_post
+ {
+ $$ = new_array_pattern_tail(p, $1, 1, $2, $4, &@$);
+ }
+ | p_args_tail
+ ;
p_args_head : p_arg ','
- {
- $$ = $1;
- }
- | p_args_head p_arg ','
- {
- /*%%%*/
- $$ = list_concat($1, $2);
- /*% %*/
- /*% ripper: rb_ary_concat($1, get_value($2)) %*/
- }
- ;
+ {
+ $$ = $1;
+ }
+ | p_args_head p_arg ','
+ {
+ /*%%%*/
+ $$ = list_concat($1, $2);
+ /*% %*/
+ /*% ripper: rb_ary_concat($1, get_value($2)) %*/
+ }
+ ;
p_args_tail : p_rest
- {
- $$ = new_array_pattern_tail(p, Qnone, 1, $1, Qnone, &@$);
- }
- | p_rest ',' p_args_post
- {
- $$ = new_array_pattern_tail(p, Qnone, 1, $1, $3, &@$);
- }
- ;
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 1, $1, Qnone, &@$);
+ }
+ | p_rest ',' p_args_post
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 1, $1, $3, &@$);
+ }
+ ;
p_find : p_rest ',' p_args_post ',' p_rest
- {
- $$ = new_find_pattern_tail(p, $1, $3, $5, &@$);
- }
- ;
+ {
+ $$ = new_find_pattern_tail(p, $1, $3, $5, &@$);
+ }
+ ;
p_rest : tSTAR tIDENTIFIER
- {
- /*%%%*/
- error_duplicate_pattern_variable(p, $2, &@2);
- $$ = assignable(p, $2, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $2)) %*/
- }
- | tSTAR
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: var_field(p, Qnil) %*/
- }
- ;
+ {
+ $$ = $2;
+ }
+ | tSTAR
+ {
+ $$ = 0;
+ }
+ ;
p_args_post : p_arg
- | p_args_post ',' p_arg
- {
- /*%%%*/
- $$ = list_concat($1, $3);
- /*% %*/
- /*% ripper: rb_ary_concat($1, get_value($3)) %*/
- }
- ;
+ | p_args_post ',' p_arg
+ {
+ /*%%%*/
+ $$ = list_concat($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_concat($1, get_value($3)) %*/
+ }
+ ;
p_arg : p_expr
- {
- /*%%%*/
- $$ = NEW_LIST($1, &@$);
- /*% %*/
- /*% ripper: rb_ary_new_from_args(1, get_value($1)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: rb_ary_new_from_args(1, get_value($1)) %*/
+ }
+ ;
p_kwargs : p_kwarg ',' p_any_kwrest
- {
- $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), $3, &@$);
- }
- | p_kwarg
- {
- $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
- }
- | p_kwarg ','
- {
- $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
- }
- | p_any_kwrest
- {
- $$ = new_hash_pattern_tail(p, new_hash(p, Qnone, &@$), $1, &@$);
- }
- ;
+ {
+ $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), $3, &@$);
+ }
+ | p_kwarg
+ {
+ $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
+ }
+ | p_kwarg ','
+ {
+ $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
+ }
+ | p_any_kwrest
+ {
+ $$ = new_hash_pattern_tail(p, new_hash(p, Qnone, &@$), $1, &@$);
+ }
+ ;
p_kwarg : p_kw
- /*% ripper[brace]: rb_ary_new_from_args(1, $1) %*/
- | p_kwarg ',' p_kw
- {
- /*%%%*/
- $$ = list_concat($1, $3);
- /*% %*/
- /*% ripper: rb_ary_push($1, $3) %*/
- }
- ;
+ /*% ripper[brace]: rb_ary_new_from_args(1, $1) %*/
+ | p_kwarg ',' p_kw
+ {
+ /*%%%*/
+ $$ = list_concat($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, $3) %*/
+ }
+ ;
p_kw : p_kw_label p_expr
- {
- error_duplicate_pattern_key(p, get_id($1), &@1);
- /*%%%*/
- $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), $2);
- /*% %*/
- /*% ripper: rb_ary_new_from_args(2, get_value($1), get_value($2)) %*/
- }
- | p_kw_label
- {
- error_duplicate_pattern_key(p, get_id($1), &@1);
- if ($1 && !is_local_id(get_id($1))) {
- yyerror1(&@1, "key must be valid as local variables");
- }
- error_duplicate_pattern_variable(p, get_id($1), &@1);
- /*%%%*/
- $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@$), &@$), assignable(p, $1, 0, &@$));
- /*% %*/
- /*% ripper: rb_ary_new_from_args(2, get_value(assignable(p, $1)), Qnil) %*/
- }
- ;
+ {
+ error_duplicate_pattern_key(p, get_id($1), &@1);
+ /*%%%*/
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), $2);
+ /*% %*/
+ /*% ripper: rb_ary_new_from_args(2, get_value($1), get_value($2)) %*/
+ }
+ | p_kw_label
+ {
+ error_duplicate_pattern_key(p, get_id($1), &@1);
+ if ($1 && !is_local_id(get_id($1))) {
+ yyerror1(&@1, "key must be valid as local variables");
+ }
+ error_duplicate_pattern_variable(p, get_id($1), &@1);
+ /*%%%*/
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@$), &@$), assignable(p, $1, 0, &@$));
+ /*% %*/
+ /*% ripper: rb_ary_new_from_args(2, get_value($1), Qnil) %*/
+ }
+ ;
p_kw_label : tLABEL
- | tSTRING_BEG string_contents tLABEL_END
- {
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- /*%%%*/
- if (!$2 || nd_type_p($2, NODE_STR)) {
- NODE *node = dsym_node(p, $2, &loc);
- $$ = SYM2ID(RNODE_LIT(node)->nd_lit);
- }
- /*%
- if (ripper_is_node_yylval(p, $2) && RNODE_RIPPER($2)->nd_cval) {
- VALUE label = RNODE_RIPPER($2)->nd_cval;
- VALUE rval = RNODE_RIPPER($2)->nd_rval;
- $$ = ripper_new_yylval(p, rb_intern_str(label), rval, label);
- RNODE($$)->nd_loc = loc;
- }
- %*/
- else {
- yyerror1(&loc, "symbol literal with interpolation is not allowed");
- $$ = 0;
- }
- }
- ;
+ | tSTRING_BEG string_contents tLABEL_END
+ {
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ /*%%%*/
+ if (!$2 || nd_type_p($2, NODE_STR)) {
+ NODE *node = dsym_node(p, $2, &loc);
+ $$ = SYM2ID(node->nd_lit);
+ }
+ /*%
+ if (ripper_is_node_yylval($2) && RNODE($2)->nd_cval) {
+ VALUE label = RNODE($2)->nd_cval;
+ VALUE rval = RNODE($2)->nd_rval;
+ $$ = ripper_new_yylval(p, rb_intern_str(label), rval, label);
+ RNODE($$)->nd_loc = loc;
+ }
+ %*/
+ else {
+ yyerror1(&loc, "symbol literal with interpolation is not allowed");
+ $$ = 0;
+ }
+ }
+ ;
p_kwrest : kwrest_mark tIDENTIFIER
- {
- $$ = $2;
- }
- | kwrest_mark
- {
- $$ = 0;
- }
- ;
+ {
+ $$ = $2;
+ }
+ | kwrest_mark
+ {
+ $$ = 0;
+ }
+ ;
p_kwnorest : kwrest_mark keyword_nil
- {
- $$ = 0;
- }
- ;
+ {
+ $$ = 0;
+ }
+ ;
p_any_kwrest : p_kwrest
- | p_kwnorest {$$ = ID2VAL(idNil);}
- ;
+ | p_kwnorest {$$ = ID2VAL(idNil);}
+ ;
p_value : p_primitive
- | p_primitive tDOT2 p_primitive
- {
- /*%%%*/
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT2($1, $3, &@$);
- /*% %*/
- /*% ripper: dot2!($1, $3) %*/
- }
- | p_primitive tDOT3 p_primitive
- {
- /*%%%*/
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT3($1, $3, &@$);
- /*% %*/
- /*% ripper: dot3!($1, $3) %*/
- }
- | p_primitive tDOT2
- {
- /*%%%*/
- value_expr($1);
- $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% %*/
- /*% ripper: dot2!($1, Qnil) %*/
- }
- | p_primitive tDOT3
- {
- /*%%%*/
- value_expr($1);
- $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% %*/
- /*% ripper: dot3!($1, Qnil) %*/
- }
- | p_var_ref
- | p_expr_ref
- | p_const
- | tBDOT2 p_primitive
- {
- /*%%%*/
- value_expr($2);
- $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% %*/
- /*% ripper: dot2!(Qnil, $2) %*/
- }
- | tBDOT3 p_primitive
- {
- /*%%%*/
- value_expr($2);
- $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% %*/
- /*% ripper: dot3!(Qnil, $2) %*/
- }
- ;
+ | p_primitive tDOT2 p_primitive
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, $3) %*/
+ }
+ | p_primitive tDOT3 p_primitive
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT3($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, $3) %*/
+ }
+ | p_primitive tDOT2
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, Qnil) %*/
+ }
+ | p_primitive tDOT3
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, Qnil) %*/
+ }
+ | p_var_ref
+ | p_expr_ref
+ | p_const
+ | tBDOT2 p_primitive
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot2!(Qnil, $2) %*/
+ }
+ | tBDOT3 p_primitive
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot3!(Qnil, $2) %*/
+ }
+ ;
p_primitive : literal
- | strings
- | xstring
- | regexp
- | words
- | qwords
- | symbols
- | qsymbols
- | keyword_variable
- {
- /*%%%*/
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper: var_ref!($1) %*/
- }
- | lambda
- ;
+ | strings
+ | xstring
+ | regexp
+ | words
+ | qwords
+ | symbols
+ | qsymbols
+ | keyword_variable
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | lambda
+ ;
p_variable : tIDENTIFIER
- {
- /*%%%*/
- error_duplicate_pattern_variable(p, $1, &@1);
- $$ = assignable(p, $1, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $1)) %*/
- }
- ;
+ {
+ /*%%%*/
+ error_duplicate_pattern_variable(p, $1, &@1);
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ ;
p_var_ref : '^' tIDENTIFIER
- {
- /*%%%*/
- NODE *n = gettable(p, $2, &@$);
- if (!(nd_type_p(n, NODE_LVAR) || nd_type_p(n, NODE_DVAR))) {
- compile_error(p, "%"PRIsVALUE": no such local variable", rb_id2str($2));
- }
- $$ = n;
- /*% %*/
- /*% ripper: var_ref!($2) %*/
- }
+ {
+ /*%%%*/
+ NODE *n = gettable(p, $2, &@$);
+ if (!(nd_type_p(n, NODE_LVAR) || nd_type_p(n, NODE_DVAR))) {
+ compile_error(p, "%"PRIsVALUE": no such local variable", rb_id2str($2));
+ }
+ $$ = n;
+ /*% %*/
+ /*% ripper: var_ref!($2) %*/
+ }
| '^' nonlocal_var
- {
- /*%%%*/
- if (!($$ = gettable(p, $2, &@$))) $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper: var_ref!($2) %*/
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $2, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($2) %*/
}
- ;
+ ;
p_expr_ref : '^' tLPAREN expr_value rparen
- {
- /*%%%*/
- $$ = NEW_BEGIN($3, &@$);
- /*% %*/
- /*% ripper: begin!($3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_BEGIN($3, &@$);
+ /*% %*/
+ /*% ripper: begin!($3) %*/
+ }
+ ;
p_const : tCOLON3 cname
- {
- /*%%%*/
- $$ = NEW_COLON3($2, &@$);
- /*% %*/
- /*% ripper: top_const_ref!($2) %*/
- }
- | p_const tCOLON2 cname
- {
- /*%%%*/
- $$ = NEW_COLON2($1, $3, &@$);
- /*% %*/
- /*% ripper: const_path_ref!($1, $3) %*/
- }
- | tCONSTANT
- {
- /*%%%*/
- $$ = gettable(p, $1, &@$);
- /*% %*/
- /*% ripper: var_ref!($1) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_COLON3($2, &@$);
+ /*% %*/
+ /*% ripper: top_const_ref!($2) %*/
+ }
+ | p_const tCOLON2 cname
+ {
+ /*%%%*/
+ $$ = NEW_COLON2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_ref!($1, $3) %*/
+ }
+ | tCONSTANT
+ {
+ /*%%%*/
+ $$ = gettable(p, $1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ ;
opt_rescue : k_rescue exc_list exc_var then
- compstmt
- opt_rescue
- {
- /*%%%*/
- NODE *body = $5;
- if ($3) {
- NODE *err = NEW_ERRINFO(&@3);
- err = node_assign(p, $3, err, NO_LEX_CTXT, &@3);
- body = block_append(p, err, body);
- }
- $$ = NEW_RESBODY($2, body, $6, &@$);
+ compstmt
+ opt_rescue
+ {
+ /*%%%*/
+ $$ = NEW_RESBODY($2,
+ $3 ? block_append(p, node_assign(p, $3, NEW_ERRINFO(&@3), NO_LEX_CTXT, &@3), $5) : $5,
+ $6, &@$);
+
if ($2) {
fixpos($$, $2);
}
@@ -5588,1082 +4968,1089 @@ opt_rescue : k_rescue exc_list exc_var then
else {
fixpos($$, $5);
}
- /*% %*/
- /*% ripper: rescue!($2, $3, $5, $6) %*/
- }
- | none
- ;
+ /*% %*/
+ /*% ripper: rescue!(escape_Qundef($2), escape_Qundef($3), escape_Qundef($5), escape_Qundef($6)) %*/
+ }
+ | none
+ ;
exc_list : arg_value
- {
- /*%%%*/
- $$ = NEW_LIST($1, &@$);
- /*% %*/
- /*% ripper: rb_ary_new3(1, get_value($1)) %*/
- }
- | mrhs
- {
- /*%%%*/
- if (!($$ = splat_array($1))) $$ = $1;
- /*% %*/
- /*% ripper: $1 %*/
- }
- | none
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | mrhs
+ {
+ /*%%%*/
+ if (!($$ = splat_array($1))) $$ = $1;
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ | none
+ ;
exc_var : tASSOC lhs
- {
- $$ = $2;
- }
- | none
- ;
+ {
+ $$ = $2;
+ }
+ | none
+ ;
opt_ensure : k_ensure compstmt
- {
- p->ctxt.in_rescue = $1.in_rescue;
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: ensure!($2) %*/
- }
- | none
- ;
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: ensure!($2) %*/
+ }
+ | none
+ ;
literal : numeric
- | symbol
- ;
+ | symbol
+ ;
strings : string
- {
- /*%%%*/
- NODE *node = $1;
- if (!node) {
- node = NEW_STR(STR_NEW0(), &@$);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_STR(node)->nd_lit);
- }
- else {
- node = evstr2dstr(p, node);
- }
- $$ = node;
- /*% %*/
- /*% ripper: $1 %*/
- }
- ;
+ {
+ /*%%%*/
+ NODE *node = $1;
+ if (!node) {
+ node = NEW_STR(STR_NEW0(), &@$);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit);
+ }
+ else {
+ node = evstr2dstr(p, node);
+ }
+ $$ = node;
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ ;
string : tCHAR
- | string1
- | string string1
- {
- /*%%%*/
- $$ = literal_concat(p, $1, $2, &@$);
- /*% %*/
- /*% ripper: string_concat!($1, $2) %*/
- }
- ;
+ | string1
+ | string string1
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: string_concat!($1, $2) %*/
+ }
+ ;
string1 : tSTRING_BEG string_contents tSTRING_END
- {
- /*%%%*/
- $$ = heredoc_dedent(p, $2);
- if ($$) nd_set_loc($$, &@$);
- /*% %*/
- /*% ripper: string_literal!(heredoc_dedent(p, $2)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = heredoc_dedent(p, $2);
+ if ($$) nd_set_loc($$, &@$);
+ /*% %*/
+ /*% ripper: string_literal!(heredoc_dedent(p, $2)) %*/
+ }
+ ;
xstring : tXSTRING_BEG xstring_contents tSTRING_END
- {
- /*%%%*/
- $$ = new_xstring(p, heredoc_dedent(p, $2), &@$);
- /*% %*/
- /*% ripper: xstring_literal!(heredoc_dedent(p, $2)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = new_xstring(p, heredoc_dedent(p, $2), &@$);
+ /*% %*/
+ /*% ripper: xstring_literal!(heredoc_dedent(p, $2)) %*/
+ }
+ ;
regexp : tREGEXP_BEG regexp_contents tREGEXP_END
- {
- $$ = new_regexp(p, $2, $3, &@$);
- }
- ;
-
-words_sep : ' ' {}
- | words_sep ' '
- ;
-
-words : tWORDS_BEG words_sep word_list tSTRING_END
- {
- /*%%%*/
- $$ = make_list($3, &@$);
- /*% %*/
- /*% ripper: array!($3) %*/
- }
- ;
+ {
+ $$ = new_regexp(p, $2, $3, &@$);
+ }
+ ;
+
+words : tWORDS_BEG ' ' word_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
word_list : /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: words_new! %*/
- }
- | word_list word words_sep
- {
- /*%%%*/
- $$ = list_append(p, $1, evstr2dstr(p, $2));
- /*% %*/
- /*% ripper: words_add!($1, $2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: words_new! %*/
+ }
+ | word_list word ' '
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, evstr2dstr(p, $2));
+ /*% %*/
+ /*% ripper: words_add!($1, $2) %*/
+ }
+ ;
word : string_content
- /*% ripper[brace]: word_add!(word_new!, $1) %*/
- | word string_content
- {
- /*%%%*/
- $$ = literal_concat(p, $1, $2, &@$);
- /*% %*/
- /*% ripper: word_add!($1, $2) %*/
- }
- ;
-
-symbols : tSYMBOLS_BEG words_sep symbol_list tSTRING_END
- {
- /*%%%*/
- $$ = make_list($3, &@$);
- /*% %*/
- /*% ripper: array!($3) %*/
- }
- ;
+ /*% ripper[brace]: word_add!(word_new!, $1) %*/
+ | word string_content
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: word_add!($1, $2) %*/
+ }
+ ;
+
+symbols : tSYMBOLS_BEG ' ' symbol_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
symbol_list : /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: symbols_new! %*/
- }
- | symbol_list word words_sep
- {
- /*%%%*/
- $$ = symbol_append(p, $1, evstr2dstr(p, $2));
- /*% %*/
- /*% ripper: symbols_add!($1, $2) %*/
- }
- ;
-
-qwords : tQWORDS_BEG words_sep qword_list tSTRING_END
- {
- /*%%%*/
- $$ = make_list($3, &@$);
- /*% %*/
- /*% ripper: array!($3) %*/
- }
- ;
-
-qsymbols : tQSYMBOLS_BEG words_sep qsym_list tSTRING_END
- {
- /*%%%*/
- $$ = make_list($3, &@$);
- /*% %*/
- /*% ripper: array!($3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: symbols_new! %*/
+ }
+ | symbol_list word ' '
+ {
+ /*%%%*/
+ $$ = symbol_append(p, $1, evstr2dstr(p, $2));
+ /*% %*/
+ /*% ripper: symbols_add!($1, $2) %*/
+ }
+ ;
+
+qwords : tQWORDS_BEG ' ' qword_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
+
+qsymbols : tQSYMBOLS_BEG ' ' qsym_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
qword_list : /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: qwords_new! %*/
- }
- | qword_list tSTRING_CONTENT words_sep
- {
- /*%%%*/
- $$ = list_append(p, $1, $2);
- /*% %*/
- /*% ripper: qwords_add!($1, $2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: qwords_new! %*/
+ }
+ | qword_list tSTRING_CONTENT ' '
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $2);
+ /*% %*/
+ /*% ripper: qwords_add!($1, $2) %*/
+ }
+ ;
qsym_list : /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: qsymbols_new! %*/
- }
- | qsym_list tSTRING_CONTENT words_sep
- {
- /*%%%*/
- $$ = symbol_append(p, $1, $2);
- /*% %*/
- /*% ripper: qsymbols_add!($1, $2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: qsymbols_new! %*/
+ }
+ | qsym_list tSTRING_CONTENT ' '
+ {
+ /*%%%*/
+ $$ = symbol_append(p, $1, $2);
+ /*% %*/
+ /*% ripper: qsymbols_add!($1, $2) %*/
+ }
+ ;
string_contents : /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: string_content! %*/
- /*%%%*/
- /*%
- $$ = ripper_new_yylval(p, 0, $$, 0);
- %*/
- }
- | string_contents string_content
- {
- /*%%%*/
- $$ = literal_concat(p, $1, $2, &@$);
- /*% %*/
- /*% ripper: string_add!($1, $2) %*/
- /*%%%*/
- /*%
- if (ripper_is_node_yylval(p, $1) && ripper_is_node_yylval(p, $2) &&
- !RNODE_RIPPER($1)->nd_cval) {
- RNODE_RIPPER($1)->nd_cval = RNODE_RIPPER($2)->nd_cval;
- RNODE_RIPPER($1)->nd_rval = add_mark_object(p, $$);
- $$ = $1;
- }
- %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: string_content! %*/
+ /*%%%*/
+ /*%
+ $$ = ripper_new_yylval(p, 0, $$, 0);
+ %*/
+ }
+ | string_contents string_content
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: string_add!($1, $2) %*/
+ /*%%%*/
+ /*%
+ if (ripper_is_node_yylval($1) && ripper_is_node_yylval($2) &&
+ !RNODE($1)->nd_cval) {
+ RNODE($1)->nd_cval = RNODE($2)->nd_cval;
+ RNODE($1)->nd_rval = add_mark_object(p, $$);
+ $$ = $1;
+ }
+ %*/
+ }
+ ;
xstring_contents: /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: xstring_new! %*/
- }
- | xstring_contents string_content
- {
- /*%%%*/
- $$ = literal_concat(p, $1, $2, &@$);
- /*% %*/
- /*% ripper: xstring_add!($1, $2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: xstring_new! %*/
+ }
+ | xstring_contents string_content
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: xstring_add!($1, $2) %*/
+ }
+ ;
regexp_contents: /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: regexp_new! %*/
- /*%%%*/
- /*%
- $$ = ripper_new_yylval(p, 0, $$, 0);
- %*/
- }
- | regexp_contents string_content
- {
- /*%%%*/
- NODE *head = $1, *tail = $2;
- if (!head) {
- $$ = tail;
- }
- else if (!tail) {
- $$ = head;
- }
- else {
- switch (nd_type(head)) {
- case NODE_STR:
- head = str2dstr(p, head);
- break;
- case NODE_DSTR:
- break;
- default:
- head = list_append(p, NEW_DSTR(Qnil, &@$), head);
- break;
- }
- $$ = list_append(p, head, tail);
- }
- /*%
- VALUE s1 = 1, s2 = 0, n1 = $1, n2 = $2;
- if (ripper_is_node_yylval(p, n1)) {
- s1 = RNODE_RIPPER(n1)->nd_cval;
- n1 = RNODE_RIPPER(n1)->nd_rval;
- }
- if (ripper_is_node_yylval(p, n2)) {
- s2 = RNODE_RIPPER(n2)->nd_cval;
- n2 = RNODE_RIPPER(n2)->nd_rval;
- }
- $$ = dispatch2(regexp_add, n1, n2);
- if (!s1 && s2) {
- $$ = ripper_new_yylval(p, 0, $$, s2);
- }
- %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: regexp_new! %*/
+ /*%%%*/
+ /*%
+ $$ = ripper_new_yylval(p, 0, $$, 0);
+ %*/
+ }
+ | regexp_contents string_content
+ {
+ /*%%%*/
+ NODE *head = $1, *tail = $2;
+ if (!head) {
+ $$ = tail;
+ }
+ else if (!tail) {
+ $$ = head;
+ }
+ else {
+ switch (nd_type(head)) {
+ case NODE_STR:
+ nd_set_type(head, NODE_DSTR);
+ break;
+ case NODE_DSTR:
+ break;
+ default:
+ head = list_append(p, NEW_DSTR(Qnil, &@$), head);
+ break;
+ }
+ $$ = list_append(p, head, tail);
+ }
+ /*%
+ VALUE s1 = 1, s2 = 0, n1 = $1, n2 = $2;
+ if (ripper_is_node_yylval(n1)) {
+ s1 = RNODE(n1)->nd_cval;
+ n1 = RNODE(n1)->nd_rval;
+ }
+ if (ripper_is_node_yylval(n2)) {
+ s2 = RNODE(n2)->nd_cval;
+ n2 = RNODE(n2)->nd_rval;
+ }
+ $$ = dispatch2(regexp_add, n1, n2);
+ if (!s1 && s2) {
+ $$ = ripper_new_yylval(p, 0, $$, s2);
+ }
+ %*/
+ }
+ ;
string_content : tSTRING_CONTENT
- /*% ripper[brace]: ripper_new_yylval(p, 0, get_value($1), $1) %*/
- | tSTRING_DVAR
- {
- /* need to backup p->lex.strterm so that a string literal `%&foo,#$&,bar&` can be parsed */
- $<strterm>$ = p->lex.strterm;
- p->lex.strterm = 0;
- SET_LEX_STATE(EXPR_BEG);
- }
- string_dvar
- {
- p->lex.strterm = $<strterm>2;
- /*%%%*/
- $$ = NEW_EVSTR($3, &@$);
- nd_set_line($$, @3.end_pos.lineno);
- /*% %*/
- /*% ripper: string_dvar!($3) %*/
- }
- | tSTRING_DBEG[term]
- {
- CMDARG_PUSH(0);
- COND_PUSH(0);
- /* need to backup p->lex.strterm so that a string literal `%!foo,#{ !0 },bar!` can be parsed */
- $<strterm>term = p->lex.strterm;
- p->lex.strterm = 0;
- $<num>$ = p->lex.state;
- SET_LEX_STATE(EXPR_BEG);
- }[state]
- {
- $<num>$ = p->lex.brace_nest;
- p->lex.brace_nest = 0;
- }[brace]
- {
- $<num>$ = p->heredoc_indent;
- p->heredoc_indent = 0;
- }[indent]
- compstmt string_dend
- {
- COND_POP();
- CMDARG_POP();
- p->lex.strterm = $<strterm>term;
- SET_LEX_STATE($<num>state);
- p->lex.brace_nest = $<num>brace;
- p->heredoc_indent = $<num>indent;
- p->heredoc_line_indent = -1;
- /*%%%*/
- if ($compstmt) nd_unset_fl_newline($compstmt);
- $$ = new_evstr(p, $compstmt, &@$);
- /*% %*/
- /*% ripper: string_embexpr!($compstmt) %*/
- }
- ;
-
-string_dend : tSTRING_DEND
- | END_OF_INPUT
- ;
-
-string_dvar : nonlocal_var
- {
- /*%%%*/
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper: var_ref!($1) %*/
- }
- | backref
- ;
+ /*% ripper[brace]: ripper_new_yylval(p, 0, get_value($1), $1) %*/
+ | tSTRING_DVAR
+ {
+ /* need to backup p->lex.strterm so that a string literal `%&foo,#$&,bar&` can be parsed */
+ $<strterm>$ = p->lex.strterm;
+ p->lex.strterm = 0;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ string_dvar
+ {
+ p->lex.strterm = $<strterm>2;
+ /*%%%*/
+ $$ = NEW_EVSTR($3, &@$);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: string_dvar!($3) %*/
+ }
+ | tSTRING_DBEG
+ {
+ CMDARG_PUSH(0);
+ COND_PUSH(0);
+ }
+ {
+ /* need to backup p->lex.strterm so that a string literal `%!foo,#{ !0 },bar!` can be parsed */
+ $<strterm>$ = p->lex.strterm;
+ p->lex.strterm = 0;
+ }
+ {
+ $<num>$ = p->lex.state;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ {
+ $<num>$ = p->lex.brace_nest;
+ p->lex.brace_nest = 0;
+ }
+ {
+ $<num>$ = p->heredoc_indent;
+ p->heredoc_indent = 0;
+ }
+ compstmt tSTRING_DEND
+ {
+ COND_POP();
+ CMDARG_POP();
+ p->lex.strterm = $<strterm>3;
+ SET_LEX_STATE($<num>4);
+ p->lex.brace_nest = $<num>5;
+ p->heredoc_indent = $<num>6;
+ p->heredoc_line_indent = -1;
+ /*%%%*/
+ if ($7) $7->flags &= ~NODE_FL_NEWLINE;
+ $$ = new_evstr(p, $7, &@$);
+ /*% %*/
+ /*% ripper: string_embexpr!($7) %*/
+ }
+ ;
+
+string_dvar : tGVAR
+ {
+ /*%%%*/
+ $$ = NEW_GVAR($1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | tIVAR
+ {
+ /*%%%*/
+ $$ = NEW_IVAR($1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | tCVAR
+ {
+ /*%%%*/
+ $$ = NEW_CVAR($1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | backref
+ ;
symbol : ssym
- | dsym
- ;
+ | dsym
+ ;
ssym : tSYMBEG sym
- {
- SET_LEX_STATE(EXPR_END);
- /*%%%*/
- $$ = NEW_LIT(ID2SYM($2), &@$);
- /*% %*/
- /*% ripper: symbol_literal!(symbol!($2)) %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_END);
+ /*%%%*/
+ $$ = NEW_LIT(ID2SYM($2), &@$);
+ /*% %*/
+ /*% ripper: symbol_literal!(symbol!($2)) %*/
+ }
+ ;
sym : fname
- | nonlocal_var
- ;
+ | nonlocal_var
+ ;
dsym : tSYMBEG string_contents tSTRING_END
- {
- SET_LEX_STATE(EXPR_END);
- /*%%%*/
- $$ = dsym_node(p, $2, &@$);
- /*% %*/
- /*% ripper: dyna_symbol!($2) %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_END);
+ /*%%%*/
+ $$ = dsym_node(p, $2, &@$);
+ /*% %*/
+ /*% ripper: dyna_symbol!($2) %*/
+ }
+ ;
numeric : simple_numeric
- | tUMINUS_NUM simple_numeric %prec tLOWEST
- {
- /*%%%*/
- $$ = $2;
- RB_OBJ_WRITE(p->ast, &RNODE_LIT($$)->nd_lit, negate_lit(p, RNODE_LIT($$)->nd_lit));
- /*% %*/
- /*% ripper: unary!(ID2VAL(idUMinus), $2) %*/
- }
- ;
+ | tUMINUS_NUM simple_numeric %prec tLOWEST
+ {
+ /*%%%*/
+ $$ = $2;
+ RB_OBJ_WRITE(p->ast, &$$->nd_lit, negate_lit(p, $$->nd_lit));
+ /*% %*/
+ /*% ripper: unary!(ID2VAL(idUMinus), $2) %*/
+ }
+ ;
simple_numeric : tINTEGER
- | tFLOAT
- | tRATIONAL
- | tIMAGINARY
- ;
+ | tFLOAT
+ | tRATIONAL
+ | tIMAGINARY
+ ;
nonlocal_var : tIVAR
- | tGVAR
- | tCVAR
- ;
+ | tGVAR
+ | tCVAR
+ ;
user_variable : tIDENTIFIER
- | tCONSTANT
- | nonlocal_var
- ;
+ | tCONSTANT
+ | nonlocal_var
+ ;
keyword_variable: keyword_nil {$$ = KWD2EID(nil, $1);}
- | keyword_self {$$ = KWD2EID(self, $1);}
- | keyword_true {$$ = KWD2EID(true, $1);}
- | keyword_false {$$ = KWD2EID(false, $1);}
- | keyword__FILE__ {$$ = KWD2EID(_FILE__, $1);}
- | keyword__LINE__ {$$ = KWD2EID(_LINE__, $1);}
- | keyword__ENCODING__ {$$ = KWD2EID(_ENCODING__, $1);}
- ;
+ | keyword_self {$$ = KWD2EID(self, $1);}
+ | keyword_true {$$ = KWD2EID(true, $1);}
+ | keyword_false {$$ = KWD2EID(false, $1);}
+ | keyword__FILE__ {$$ = KWD2EID(_FILE__, $1);}
+ | keyword__LINE__ {$$ = KWD2EID(_LINE__, $1);}
+ | keyword__ENCODING__ {$$ = KWD2EID(_ENCODING__, $1);}
+ ;
var_ref : user_variable
- {
- /*%%%*/
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
- /*%
- if (id_is_var(p, get_id($1))) {
- $$ = dispatch1(var_ref, $1);
- }
- else {
- $$ = dispatch1(vcall, $1);
- }
- %*/
- }
- | keyword_variable
- {
- /*%%%*/
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
- /*% %*/
- /*% ripper: var_ref!($1) %*/
- }
- ;
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*%
+ if (id_is_var(p, get_id($1))) {
+ $$ = dispatch1(var_ref, $1);
+ }
+ else {
+ $$ = dispatch1(vcall, $1);
+ }
+ %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ ;
var_lhs : user_variable
- {
- /*%%%*/
- $$ = assignable(p, $1, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $1)) %*/
- }
- | keyword_variable
- {
- /*%%%*/
- $$ = assignable(p, $1, 0, &@$);
- /*% %*/
- /*% ripper: assignable(p, var_field(p, $1)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ ;
backref : tNTH_REF
- | tBACK_REF
- ;
+ | tBACK_REF
+ ;
superclass : '<'
- {
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- }
- expr_value term
- {
- $$ = $3;
- }
- | /* none */
- {
- /*%%%*/
- $$ = 0;
- /*% %*/
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ }
+ expr_value term
+ {
+ $$ = $3;
+ }
+ | /* none */
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: Qnil %*/
+ }
+ ;
f_opt_paren_args: f_paren_args
- | none
- {
- p->ctxt.in_argdef = 0;
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
- }
- ;
+ | none
+ {
+ p->ctxt.in_argdef = 0;
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
+ }
+ ;
f_paren_args : '(' f_args rparen
- {
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: paren!($2) %*/
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- p->ctxt.in_argdef = 0;
- }
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ p->ctxt.in_argdef = 0;
+ }
;
f_arglist : f_paren_args
- | {
- $<ctxt>$ = p->ctxt;
- p->ctxt.in_kwarg = 1;
- p->ctxt.in_argdef = 1;
- SET_LEX_STATE(p->lex.state|EXPR_LABEL); /* force for args */
- }
- f_args term
- {
- p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
- p->ctxt.in_argdef = 0;
- $$ = $2;
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- }
- ;
+ | {
+ $<ctxt>$ = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ p->ctxt.in_argdef = 1;
+ SET_LEX_STATE(p->lex.state|EXPR_LABEL); /* force for args */
+ }
+ f_args term
+ {
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+ p->ctxt.in_argdef = 0;
+ $$ = $2;
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ }
+ ;
args_tail : f_kwarg ',' f_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, $3, $4, &@3);
- }
- | f_kwarg opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, Qnone, $2, &@1);
- }
- | f_any_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, Qnone, $1, $2, &@1);
- }
- | f_block_arg
- {
- $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
- }
- | args_forward
- {
- add_forwarding_args(p);
- $$ = new_args_tail(p, Qnone, $1, arg_FWD_BLOCK, &@1);
- /*%%%*/
- $$->nd_ainfo.forwarding = 1;
- /*% %*/
- }
- ;
+ {
+ $$ = new_args_tail(p, $1, $3, $4, &@3);
+ }
+ | f_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, Qnone, $2, &@1);
+ }
+ | f_any_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, $1, $2, &@1);
+ }
+ | f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
+ }
+ | args_forward
+ {
+ add_forwarding_args(p);
+ $$ = new_args_tail(p, Qnone, $1, ID2VAL(idFWD_BLOCK), &@1);
+ /*%%%*/
+ ($$->nd_ainfo)->forwarding = 1;
+ /*% %*/
+ }
+ ;
opt_args_tail : ',' args_tail
- {
- $$ = $2;
- }
- | /* none */
- {
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- }
- ;
+ {
+ $$ = $2;
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ }
+ ;
f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
- {
- $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
- }
- | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
- {
- $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
- }
- | f_arg ',' f_optarg opt_args_tail
- {
- $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
- }
- | f_arg ',' f_optarg ',' f_arg opt_args_tail
- {
- $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
- }
- | f_arg ',' f_rest_arg opt_args_tail
- {
- $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
- {
- $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
- }
- | f_arg opt_args_tail
- {
- $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
- }
- | f_optarg ',' f_rest_arg opt_args_tail
- {
- $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
- }
- | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
- {
- $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
- }
- | f_optarg opt_args_tail
- {
- $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
- }
- | f_optarg ',' f_arg opt_args_tail
- {
- $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
- }
- | f_rest_arg opt_args_tail
- {
- $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
- }
- | f_rest_arg ',' f_arg opt_args_tail
- {
- $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
- }
- | args_tail
- {
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
- }
- | /* none */
- {
- $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
- $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
- }
- ;
+ {
+ $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
+ }
+ | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
+ }
+ | f_arg ',' f_optarg opt_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
+ }
+ | f_arg ',' f_optarg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
+ }
+ | f_arg ',' f_rest_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
+ }
+ | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
+ }
+ | f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
+ }
+ | f_optarg ',' f_rest_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
+ }
+ | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
+ }
+ | f_optarg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
+ }
+ | f_optarg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
+ }
+ | f_rest_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
+ }
+ | f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
+ }
+ | args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
+ }
+ ;
args_forward : tBDOT3
- {
- /*%%%*/
+ {
+ /*%%%*/
#ifdef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
- $$ = 0;
+ $$ = 0;
#else
- $$ = idFWD_KWREST;
+ $$ = idFWD_KWREST;
#endif
- /*% %*/
- /*% ripper: args_forward! %*/
- }
- ;
+ /*% %*/
+ /*% ripper: args_forward! %*/
+ }
+ ;
f_bad_arg : tCONSTANT
- {
- static const char mesg[] = "formal argument cannot be a constant";
- /*%%%*/
- yyerror1(&@1, mesg);
- $$ = 0;
- /*% %*/
- /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
- }
- | tIVAR
- {
- static const char mesg[] = "formal argument cannot be an instance variable";
- /*%%%*/
- yyerror1(&@1, mesg);
- $$ = 0;
- /*% %*/
- /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
- }
- | tGVAR
- {
- static const char mesg[] = "formal argument cannot be a global variable";
- /*%%%*/
- yyerror1(&@1, mesg);
- $$ = 0;
- /*% %*/
- /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
- }
- | tCVAR
- {
- static const char mesg[] = "formal argument cannot be a class variable";
- /*%%%*/
- yyerror1(&@1, mesg);
- $$ = 0;
- /*% %*/
- /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
- }
- ;
+ {
+ static const char mesg[] = "formal argument cannot be a constant";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ | tIVAR
+ {
+ static const char mesg[] = "formal argument cannot be an instance variable";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ | tGVAR
+ {
+ static const char mesg[] = "formal argument cannot be a global variable";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ | tCVAR
+ {
+ static const char mesg[] = "formal argument cannot be a class variable";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ ;
f_norm_arg : f_bad_arg
- | tIDENTIFIER
- {
- formal_argument(p, $1);
- p->max_numparam = ORDINAL_PARAM;
- $$ = $1;
- }
- ;
+ | tIDENTIFIER
+ {
+ formal_argument(p, $1);
+ p->max_numparam = ORDINAL_PARAM;
+ $$ = $1;
+ }
+ ;
f_arg_asgn : f_norm_arg
- {
- ID id = get_id($1);
- arg_var(p, id);
- p->cur_arg = id;
- $$ = $1;
- }
- ;
+ {
+ ID id = get_id($1);
+ arg_var(p, id);
+ p->cur_arg = id;
+ $$ = $1;
+ }
+ ;
f_arg_item : f_arg_asgn
- {
- p->cur_arg = 0;
- /*%%%*/
- $$ = NEW_ARGS_AUX($1, 1, &NULL_LOC);
- /*% %*/
- /*% ripper: get_value($1) %*/
- }
- | tLPAREN f_margs rparen
- {
- /*%%%*/
- ID tid = internal_id(p);
- YYLTYPE loc;
- loc.beg_pos = @2.beg_pos;
- loc.end_pos = @2.beg_pos;
- arg_var(p, tid);
- if (dyna_in_block(p)) {
- $2->nd_value = NEW_DVAR(tid, &loc);
- }
- else {
- $2->nd_value = NEW_LVAR(tid, &loc);
- }
- $$ = NEW_ARGS_AUX(tid, 1, &NULL_LOC);
- $$->nd_next = (NODE *)$2;
- /*% %*/
- /*% ripper: mlhs_paren!($2) %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ /*%%%*/
+ $$ = NEW_ARGS_AUX($1, 1, &NULL_LOC);
+ /*% %*/
+ /*% ripper: get_value($1) %*/
+ }
+ | tLPAREN f_margs rparen
+ {
+ /*%%%*/
+ ID tid = internal_id(p);
+ YYLTYPE loc;
+ loc.beg_pos = @2.beg_pos;
+ loc.end_pos = @2.beg_pos;
+ arg_var(p, tid);
+ if (dyna_in_block(p)) {
+ $2->nd_value = NEW_DVAR(tid, &loc);
+ }
+ else {
+ $2->nd_value = NEW_LVAR(tid, &loc);
+ }
+ $$ = NEW_ARGS_AUX(tid, 1, &NULL_LOC);
+ $$->nd_next = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
f_arg : f_arg_item
- /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
- | f_arg ',' f_arg_item
- {
- /*%%%*/
- $$ = $1;
- $$->nd_plen++;
- $$->nd_next = block_append(p, $$->nd_next, $3->nd_next);
- rb_discard_node(p, (NODE *)$3);
- /*% %*/
- /*% ripper: rb_ary_push($1, get_value($3)) %*/
- }
- ;
+ /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
+ | f_arg ',' f_arg_item
+ {
+ /*%%%*/
+ $$ = $1;
+ $$->nd_plen++;
+ $$->nd_next = block_append(p, $$->nd_next, $3->nd_next);
+ rb_discard_node(p, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
f_label : tLABEL
- {
- arg_var(p, formal_argument(p, $1));
- p->cur_arg = get_id($1);
- p->max_numparam = ORDINAL_PARAM;
- p->ctxt.in_argdef = 0;
- $$ = $1;
- }
- ;
+ {
+ arg_var(p, formal_argument(p, $1));
+ p->cur_arg = get_id($1);
+ p->max_numparam = ORDINAL_PARAM;
+ p->ctxt.in_argdef = 0;
+ $$ = $1;
+ }
+ ;
f_kw : f_label arg_value
- {
- p->cur_arg = 0;
- p->ctxt.in_argdef = 1;
- /*%%%*/
- $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
- /*% %*/
- /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($2)) %*/
- }
- | f_label
- {
- p->cur_arg = 0;
- p->ctxt.in_argdef = 1;
- /*%%%*/
- $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
- /*% %*/
- /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), 0) %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($2)) %*/
+ }
+ | f_label
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), 0) %*/
+ }
+ ;
f_block_kw : f_label primary_value
- {
- p->ctxt.in_argdef = 1;
- /*%%%*/
- $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
- /*% %*/
- /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($2)) %*/
- }
- | f_label
- {
- p->ctxt.in_argdef = 1;
- /*%%%*/
- $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
- /*% %*/
- /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), 0) %*/
- }
- ;
+ {
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($2)) %*/
+ }
+ | f_label
+ {
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), 0) %*/
+ }
+ ;
f_block_kwarg : f_block_kw
- {
- /*%%%*/
- $$ = $1;
- /*% %*/
- /*% ripper: rb_ary_new3(1, get_value($1)) %*/
- }
- | f_block_kwarg ',' f_block_kw
- {
- /*%%%*/
- $$ = kwd_append($1, $3);
- /*% %*/
- /*% ripper: rb_ary_push($1, get_value($3)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_block_kwarg ',' f_block_kw
+ {
+ /*%%%*/
+ $$ = kwd_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
f_kwarg : f_kw
- {
- /*%%%*/
- $$ = $1;
- /*% %*/
- /*% ripper: rb_ary_new3(1, get_value($1)) %*/
- }
- | f_kwarg ',' f_kw
- {
- /*%%%*/
- $$ = kwd_append($1, $3);
- /*% %*/
- /*% ripper: rb_ary_push($1, get_value($3)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_kwarg ',' f_kw
+ {
+ /*%%%*/
+ $$ = kwd_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
kwrest_mark : tPOW
- | tDSTAR
- ;
+ | tDSTAR
+ ;
f_no_kwarg : p_kwnorest
- {
- /*%%%*/
- /*% %*/
- /*% ripper: nokw_param!(Qnil) %*/
- }
- ;
+ {
+ /*%%%*/
+ /*% %*/
+ /*% ripper: nokw_param!(Qnil) %*/
+ }
+ ;
f_kwrest : kwrest_mark tIDENTIFIER
- {
- arg_var(p, shadowing_lvar(p, get_id($2)));
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: kwrest_param!($2) %*/
- }
- | kwrest_mark
- {
- arg_var(p, idFWD_KWREST);
- /*%%%*/
- $$ = idFWD_KWREST;
- /*% %*/
- /*% ripper: kwrest_param!(Qnil) %*/
- }
- ;
+ {
+ arg_var(p, shadowing_lvar(p, get_id($2)));
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: kwrest_param!($2) %*/
+ }
+ | kwrest_mark
+ {
+ arg_var(p, idFWD_KWREST);
+ /*%%%*/
+ $$ = idFWD_KWREST;
+ /*% %*/
+ /*% ripper: kwrest_param!(Qnil) %*/
+ }
+ ;
f_opt : f_arg_asgn f_eq arg_value
- {
- p->cur_arg = 0;
- p->ctxt.in_argdef = 1;
- /*%%%*/
- $$ = NEW_OPT_ARG(assignable(p, $1, $3, &@$), &@$);
- /*% %*/
- /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($3)) %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = NEW_OPT_ARG(0, assignable(p, $1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($3)) %*/
+ }
+ ;
f_block_opt : f_arg_asgn f_eq primary_value
- {
- p->cur_arg = 0;
- p->ctxt.in_argdef = 1;
- /*%%%*/
- $$ = NEW_OPT_ARG(assignable(p, $1, $3, &@$), &@$);
- /*% %*/
- /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($3)) %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = NEW_OPT_ARG(0, assignable(p, $1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($3)) %*/
+ }
+ ;
f_block_optarg : f_block_opt
- {
- /*%%%*/
- $$ = $1;
- /*% %*/
- /*% ripper: rb_ary_new3(1, get_value($1)) %*/
- }
- | f_block_optarg ',' f_block_opt
- {
- /*%%%*/
- $$ = opt_arg_append($1, $3);
- /*% %*/
- /*% ripper: rb_ary_push($1, get_value($3)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_block_optarg ',' f_block_opt
+ {
+ /*%%%*/
+ $$ = opt_arg_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
f_optarg : f_opt
- {
- /*%%%*/
- $$ = $1;
- /*% %*/
- /*% ripper: rb_ary_new3(1, get_value($1)) %*/
- }
- | f_optarg ',' f_opt
- {
- /*%%%*/
- $$ = opt_arg_append($1, $3);
- /*% %*/
- /*% ripper: rb_ary_push($1, get_value($3)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_optarg ',' f_opt
+ {
+ /*%%%*/
+ $$ = opt_arg_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
restarg_mark : '*'
- | tSTAR
- ;
+ | tSTAR
+ ;
f_rest_arg : restarg_mark tIDENTIFIER
- {
- arg_var(p, shadowing_lvar(p, get_id($2)));
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: rest_param!($2) %*/
- }
- | restarg_mark
- {
- arg_var(p, idFWD_REST);
- /*%%%*/
- $$ = idFWD_REST;
- /*% %*/
- /*% ripper: rest_param!(Qnil) %*/
- }
- ;
+ {
+ arg_var(p, shadowing_lvar(p, get_id($2)));
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: rest_param!($2) %*/
+ }
+ | restarg_mark
+ {
+ arg_var(p, idFWD_REST);
+ /*%%%*/
+ $$ = idFWD_REST;
+ /*% %*/
+ /*% ripper: rest_param!(Qnil) %*/
+ }
+ ;
blkarg_mark : '&'
- | tAMPER
- ;
+ | tAMPER
+ ;
f_block_arg : blkarg_mark tIDENTIFIER
- {
- arg_var(p, shadowing_lvar(p, get_id($2)));
- /*%%%*/
- $$ = $2;
- /*% %*/
- /*% ripper: blockarg!($2) %*/
- }
+ {
+ arg_var(p, shadowing_lvar(p, get_id($2)));
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: blockarg!($2) %*/
+ }
| blkarg_mark
{
- arg_var(p, idFWD_BLOCK);
+ arg_var(p, idFWD_BLOCK);
/*%%%*/
- $$ = idFWD_BLOCK;
+ $$ = idFWD_BLOCK;
/*% %*/
- /*% ripper: blockarg!(Qnil) %*/
+ /*% ripper: blockarg!(Qnil) %*/
}
- ;
+ ;
opt_f_block_arg : ',' f_block_arg
- {
- $$ = $2;
- }
- | none
- {
- $$ = Qnull;
- }
- ;
+ {
+ $$ = $2;
+ }
+ | none
+ {
+ $$ = Qnull;
+ }
+ ;
singleton : var_ref
- {
- value_expr($1);
- $$ = $1;
- }
- | '(' {SET_LEX_STATE(EXPR_BEG);} expr rparen
- {
- /*%%%*/
- NODE *expr = last_expr_node($3);
- switch (nd_type(expr)) {
- case NODE_STR:
- case NODE_DSTR:
- case NODE_XSTR:
- case NODE_DXSTR:
- case NODE_DREGX:
- case NODE_LIT:
- case NODE_DSYM:
- case NODE_LIST:
- case NODE_ZLIST:
- yyerror1(&expr->nd_loc, "can't define singleton method for literals");
- break;
- default:
- value_expr($3);
- break;
- }
- $$ = $3;
- /*% %*/
- /*% ripper: paren!($3) %*/
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | '(' {SET_LEX_STATE(EXPR_BEG);} expr rparen
+ {
+ /*%%%*/
+ switch (nd_type($3)) {
+ case NODE_STR:
+ case NODE_DSTR:
+ case NODE_XSTR:
+ case NODE_DXSTR:
+ case NODE_DREGX:
+ case NODE_LIT:
+ case NODE_LIST:
+ case NODE_ZLIST:
+ yyerror1(&@3, "can't define singleton method for literals");
+ break;
+ default:
+ value_expr($3);
+ break;
+ }
+ $$ = $3;
+ /*% %*/
+ /*% ripper: paren!($3) %*/
+ }
+ ;
assoc_list : none
- | assocs trailer
- {
- /*%%%*/
- $$ = $1;
- /*% %*/
- /*% ripper: assoclist_from_args!($1) %*/
- }
- ;
+ | assocs trailer
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: assoclist_from_args!($1) %*/
+ }
+ ;
assocs : assoc
- /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
- | assocs ',' assoc
- {
- /*%%%*/
- NODE *assocs = $1;
- NODE *tail = $3;
- if (!assocs) {
- assocs = tail;
- }
- else if (tail) {
- if (RNODE_LIST(assocs)->nd_head &&
- !RNODE_LIST(tail)->nd_head && nd_type_p(RNODE_LIST(tail)->nd_next, NODE_LIST) &&
- nd_type_p(RNODE_LIST(RNODE_LIST(tail)->nd_next)->nd_head, NODE_HASH)) {
+ /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
+ | assocs ',' assoc
+ {
+ /*%%%*/
+ NODE *assocs = $1;
+ NODE *tail = $3;
+ if (!assocs) {
+ assocs = tail;
+ }
+ else if (tail) {
+ if (assocs->nd_head &&
+ !tail->nd_head && nd_type_p(tail->nd_next, NODE_LIST) &&
+ nd_type_p(tail->nd_next->nd_head, NODE_HASH)) {
/* DSTAR */
- tail = RNODE_HASH(RNODE_LIST(RNODE_LIST(tail)->nd_next)->nd_head)->nd_head;
+ tail = tail->nd_next->nd_head->nd_head;
}
- assocs = list_concat(assocs, tail);
- }
- $$ = assocs;
- /*% %*/
- /*% ripper: rb_ary_push($1, get_value($3)) %*/
- }
- ;
+ assocs = list_concat(assocs, tail);
+ }
+ $$ = assocs;
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
assoc : arg_value tASSOC arg_value
- {
- /*%%%*/
- if (nd_type_p($1, NODE_STR)) {
- nd_set_type($1, NODE_LIT);
- RB_OBJ_WRITE(p->ast, &RNODE_LIT($1)->nd_lit, rb_fstring(RNODE_LIT($1)->nd_lit));
- }
- $$ = list_append(p, NEW_LIST($1, &@$), $3);
- /*% %*/
- /*% ripper: assoc_new!($1, $3) %*/
- }
- | tLABEL arg_value
- {
- /*%%%*/
- $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), $2);
- /*% %*/
- /*% ripper: assoc_new!($1, $2) %*/
- }
- | tLABEL
- {
- /*%%%*/
- NODE *val = gettable(p, $1, &@$);
- if (!val) val = NEW_BEGIN(0, &@$);
- $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), val);
- /*% %*/
- /*% ripper: assoc_new!($1, Qnil) %*/
- }
- | tSTRING_BEG string_contents tLABEL_END arg_value
- {
- /*%%%*/
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- $$ = list_append(p, NEW_LIST(dsym_node(p, $2, &loc), &loc), $4);
- /*% %*/
- /*% ripper: assoc_new!(dyna_symbol!($2), $4) %*/
- }
- | tDSTAR arg_value
- {
- /*%%%*/
+ {
+ /*%%%*/
+ if (nd_type_p($1, NODE_STR)) {
+ nd_set_type($1, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &$1->nd_lit, rb_fstring($1->nd_lit));
+ }
+ $$ = list_append(p, NEW_LIST($1, &@$), $3);
+ /*% %*/
+ /*% ripper: assoc_new!($1, $3) %*/
+ }
+ | tLABEL arg_value
+ {
+ /*%%%*/
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), $2);
+ /*% %*/
+ /*% ripper: assoc_new!($1, $2) %*/
+ }
+ | tLABEL
+ {
+ /*%%%*/
+ NODE *val = gettable(p, $1, &@$);
+ if (!val) val = NEW_BEGIN(0, &@$);
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), val);
+ /*% %*/
+ /*% ripper: assoc_new!($1, Qnil) %*/
+ }
+ | tSTRING_BEG string_contents tLABEL_END arg_value
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ $$ = list_append(p, NEW_LIST(dsym_node(p, $2, &loc), &loc), $4);
+ /*% %*/
+ /*% ripper: assoc_new!(dyna_symbol!($2), $4) %*/
+ }
+ | tDSTAR arg_value
+ {
+ /*%%%*/
if (nd_type_p($2, NODE_HASH) &&
- !(RNODE_HASH($2)->nd_head && RNODE_LIST(RNODE_HASH($2)->nd_head)->as.nd_alen)) {
+ !($2->nd_head && $2->nd_head->nd_alen)) {
static VALUE empty_hash;
if (!empty_hash) {
empty_hash = rb_obj_freeze(rb_hash_new());
@@ -6673,87 +6060,87 @@ assoc : arg_value tASSOC arg_value
}
else
$$ = list_append(p, NEW_LIST(0, &@$), $2);
- /*% %*/
- /*% ripper: assoc_splat!($2) %*/
- }
- | tDSTAR
- {
+ /*% %*/
+ /*% ripper: assoc_splat!($2) %*/
+ }
+ | tDSTAR
+ {
if (!local_id(p, idFWD_KWREST) ||
local_id(p, idFWD_ALL)) {
compile_error(p, "no anonymous keyword rest parameter");
}
- /*%%%*/
+ /*%%%*/
$$ = list_append(p, NEW_LIST(0, &@$),
NEW_LVAR(idFWD_KWREST, &@$));
- /*% %*/
- /*% ripper: assoc_splat!(Qnil) %*/
- }
- ;
+ /*% %*/
+ /*% ripper: assoc_splat!(Qnil) %*/
+ }
+ ;
operation : tIDENTIFIER
- | tCONSTANT
- | tFID
- ;
+ | tCONSTANT
+ | tFID
+ ;
operation2 : operation
- | op
- ;
+ | op
+ ;
operation3 : tIDENTIFIER
- | tFID
- | op
- ;
+ | tFID
+ | op
+ ;
dot_or_colon : '.'
- | tCOLON2
- ;
+ | tCOLON2
+ ;
call_op : '.'
- | tANDDOT
- ;
+ | tANDDOT
+ ;
call_op2 : call_op
- | tCOLON2
- ;
+ | tCOLON2
+ ;
opt_terms : /* none */
- | terms
- ;
+ | terms
+ ;
opt_nl : /* none */
- | '\n'
- ;
+ | '\n'
+ ;
rparen : opt_nl ')'
- ;
+ ;
rbracket : opt_nl ']'
- ;
+ ;
rbrace : opt_nl '}'
- ;
+ ;
trailer : opt_nl
- | ','
- ;
+ | ','
+ ;
term : ';' {yyerrok;token_flush(p);}
- | '\n'
- {
- @$.end_pos = @$.beg_pos;
- token_flush(p);
- }
- ;
+ | '\n'
+ {
+ @$.end_pos = @$.beg_pos;
+ token_flush(p);
+ }
+ ;
terms : term
- | terms ';' {yyerrok;}
- ;
+ | terms ';' {yyerrok;}
+ ;
none : /* none */
- {
- $$ = Qnull;
- }
- ;
+ {
+ $$ = Qnull;
+ }
+ ;
%%
# undef p
# undef yylex
@@ -6812,21 +6199,16 @@ ripper_yylval_id(struct parser_params *p, ID x)
static bool
parser_has_token(struct parser_params *p)
{
- const char *const pcur = p->lex.pcur;
- const char *const ptok = p->lex.ptok;
- if (p->keep_tokens && (pcur < ptok)) {
- rb_bug("lex.pcur < lex.ptok. (line: %d) %"PRIdPTRDIFF"|%"PRIdPTRDIFF"|%"PRIdPTRDIFF"",
- p->ruby_sourceline, ptok - p->lex.pbeg, pcur - ptok, p->lex.pend - pcur);
- }
- return pcur > ptok;
+ if (p->keep_tokens && (p->lex.pcur < p->lex.ptok)) rb_bug("lex.pcur < lex.ptok. (line: %d) %ld|%ld|%ld", p->ruby_sourceline, p->lex.ptok - p->lex.pbeg, p->lex.pcur - p->lex.ptok, p->lex.pend - p->lex.pcur);
+ return p->lex.pcur > p->lex.ptok;
}
static VALUE
-code_loc_to_ary(struct parser_params *p, const rb_code_location_t *loc)
+code_loc_to_ary(const rb_code_location_t *loc)
{
VALUE ary = rb_ary_new_from_args(4,
- INT2NUM(loc->beg_pos.lineno), INT2NUM(loc->beg_pos.column),
- INT2NUM(loc->end_pos.lineno), INT2NUM(loc->end_pos.column));
+ INT2NUM(loc->beg_pos.lineno), INT2NUM(loc->beg_pos.column),
+ INT2NUM(loc->end_pos.lineno), INT2NUM(loc->end_pos.column));
rb_obj_freeze(ary);
return ary;
@@ -6841,15 +6223,15 @@ parser_append_tokens(struct parser_params *p, VALUE str, enum yytokentype t, int
ary = rb_ary_new2(4);
token_id = p->token_id;
rb_ary_push(ary, INT2FIX(token_id));
- rb_ary_push(ary, ID2SYM(parser_token2id(p, t)));
+ rb_ary_push(ary, ID2SYM(parser_token2id(t)));
rb_ary_push(ary, str);
- rb_ary_push(ary, code_loc_to_ary(p, p->yylloc));
+ rb_ary_push(ary, code_loc_to_ary(p->yylloc));
rb_obj_freeze(ary);
rb_ary_push(p->tokens, ary);
p->token_id++;
if (p->debug) {
- rb_parser_printf(p, "Append tokens (line: %d) %"PRIsVALUE"\n", line, ary);
+ rb_parser_printf(p, "Append tokens (line: %d) %"PRIsVALUE"\n", line, ary);
}
}
@@ -6863,8 +6245,8 @@ parser_dispatch_scan_event(struct parser_params *p, enum yytokentype t, int line
RUBY_SET_YYLLOC(*p->yylloc);
if (p->keep_tokens) {
- VALUE str = STR_NEW(p->lex.ptok, p->lex.pcur - p->lex.ptok);
- parser_append_tokens(p, str, t, line);
+ VALUE str = STR_NEW(p->lex.ptok, p->lex.pcur - p->lex.ptok);
+ parser_append_tokens(p, str, t, line);
}
token_flush(p);
@@ -6874,6 +6256,9 @@ parser_dispatch_scan_event(struct parser_params *p, enum yytokentype t, int line
static void
parser_dispatch_delayed_token(struct parser_params *p, enum yytokentype t, int line)
{
+ int saved_line = p->ruby_sourceline;
+ const char *saved_tokp = p->lex.ptok;
+
debug_token_line(p, "parser_dispatch_delayed_token", line);
if (!has_delayed_token(p)) return;
@@ -6881,7 +6266,11 @@ parser_dispatch_delayed_token(struct parser_params *p, enum yytokentype t, int l
RUBY_SET_YYLLOC_OF_DELAYED_TOKEN(*p->yylloc);
if (p->keep_tokens) {
- parser_append_tokens(p, p->delayed.token, t, line);
+ p->ruby_sourceline = p->delayed.beg_line;
+ p->lex.ptok = p->lex.pbeg + p->delayed.beg_col;
+ parser_append_tokens(p, p->delayed.token, t, line);
+ p->ruby_sourceline = saved_line;
+ p->lex.ptok = saved_tokp;
}
p->delayed.token = Qnil;
@@ -6889,7 +6278,14 @@ parser_dispatch_delayed_token(struct parser_params *p, enum yytokentype t, int l
#else
#define literal_flush(p, ptr) ((void)(ptr))
-#define yylval_rval (*(RB_TYPE_P(yylval.val, T_NODE) ? &RNODE_RIPPER(yylval.node)->nd_rval : &yylval.val))
+#define yylval_rval (*(RB_TYPE_P(yylval.val, T_NODE) ? &yylval.node->nd_rval : &yylval.val))
+
+static inline VALUE
+intern_sym(const char *name)
+{
+ ID id = rb_intern_const(name);
+ return ID2SYM(id);
+}
static int
ripper_has_scan_event(struct parser_params *p)
@@ -6919,7 +6315,6 @@ ripper_dispatch_scan_event(struct parser_params *p, enum yytokentype t)
static void
ripper_dispatch_delayed_token(struct parser_params *p, enum yytokentype t)
{
- /* save and adjust the location to delayed token for callbacks */
int saved_line = p->ruby_sourceline;
const char *saved_tokp = p->lex.ptok;
@@ -6935,7 +6330,7 @@ ripper_dispatch_delayed_token(struct parser_params *p, enum yytokentype t)
#endif /* RIPPER */
static inline int
-is_identchar(struct parser_params *p, const char *ptr, const char *MAYBE_UNUSED(ptr_end), rb_encoding *enc)
+is_identchar(const char *ptr, const char *MAYBE_UNUSED(ptr_end), rb_encoding *enc)
{
return rb_enc_isalnum((unsigned char)*ptr, enc) || *ptr == '_' || !ISASCII(*ptr);
}
@@ -6943,7 +6338,7 @@ is_identchar(struct parser_params *p, const char *ptr, const char *MAYBE_UNUSED(
static inline int
parser_is_identchar(struct parser_params *p)
{
- return !(p)->eofp && is_identchar(p, p->lex.pcur-1, p->lex.pend, p->enc);
+ return !(p)->eofp && is_identchar(p->lex.pcur-1, p->lex.pend, p->enc);
}
static inline int
@@ -6957,13 +6352,13 @@ token_info_setup(token_info *ptinfo, const char *ptr, const rb_code_location_t *
{
int column = 1, nonspc = 0, i;
for (i = 0; i < loc->beg_pos.column; i++, ptr++) {
- if (*ptr == '\t') {
- column = (((column - 1) / TAB_WIDTH) + 1) * TAB_WIDTH;
- }
- column++;
- if (*ptr != ' ' && *ptr != '\t') {
- nonspc = 1;
- }
+ if (*ptr == '\t') {
+ column = (((column - 1) / TAB_WIDTH) + 1) * TAB_WIDTH;
+ }
+ column++;
+ if (*ptr != ' ' && *ptr != '\t') {
+ nonspc = 1;
+ }
}
ptinfo->beg = loc->beg_pos;
@@ -7007,12 +6402,12 @@ token_info_drop(struct parser_params *p, const char *token, rb_code_position_t b
p->token_info = ptinfo_beg->next;
if (ptinfo_beg->beg.lineno != beg_pos.lineno ||
- ptinfo_beg->beg.column != beg_pos.column ||
- strcmp(ptinfo_beg->token, token)) {
- compile_error(p, "token position mismatch: %d:%d:%s expected but %d:%d:%s",
- beg_pos.lineno, beg_pos.column, token,
- ptinfo_beg->beg.lineno, ptinfo_beg->beg.column,
- ptinfo_beg->token);
+ ptinfo_beg->beg.column != beg_pos.column ||
+ strcmp(ptinfo_beg->token, token)) {
+ compile_error(p, "token position mismatch: %d:%d:%s expected but %d:%d:%s",
+ beg_pos.lineno, beg_pos.column, token,
+ ptinfo_beg->beg.lineno, ptinfo_beg->beg.column,
+ ptinfo_beg->token);
}
ruby_sized_xfree(ptinfo_beg, sizeof(*ptinfo_beg));
@@ -7030,8 +6425,8 @@ token_info_warn(struct parser_params *p, const char *token, token_info *ptinfo_b
if (ptinfo_beg->indent == ptinfo_end->indent) return; /* the indents are matched */
if (!same && ptinfo_beg->indent < ptinfo_end->indent) return;
rb_warn3L(ptinfo_end->beg.lineno,
- "mismatched indentations at '%s' with '%s' at %d",
- WARN_S(token), WARN_S(ptinfo_beg->token), WARN_I(ptinfo_beg->beg.lineno));
+ "mismatched indentations at '%s' with '%s' at %d",
+ WARN_S(token), WARN_S(ptinfo_beg->token), WARN_I(ptinfo_beg->beg.lineno));
}
static int
@@ -7039,14 +6434,14 @@ parser_precise_mbclen(struct parser_params *p, const char *ptr)
{
int len = rb_enc_precise_mbclen(ptr, p->lex.pend, p->enc);
if (!MBCLEN_CHARFOUND_P(len)) {
- compile_error(p, "invalid multibyte char (%s)", rb_enc_name(p->enc));
- return -1;
+ compile_error(p, "invalid multibyte char (%s)", rb_enc_name(p->enc));
+ return -1;
}
return len;
}
#ifndef RIPPER
-static void ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yylloc, int lineno, VALUE str);
+static void ruby_show_error_line(VALUE errbuf, const YYLTYPE *yylloc, int lineno, VALUE str);
static inline void
parser_show_error_line(struct parser_params *p, const YYLTYPE *yylloc)
@@ -7054,32 +6449,32 @@ parser_show_error_line(struct parser_params *p, const YYLTYPE *yylloc)
VALUE str;
int lineno = p->ruby_sourceline;
if (!yylloc) {
- return;
+ return;
}
else if (yylloc->beg_pos.lineno == lineno) {
- str = p->lex.lastline;
+ str = p->lex.lastline;
}
else {
- return;
+ return;
}
- ruby_show_error_line(p, p->error_buffer, yylloc, lineno, str);
+ ruby_show_error_line(p->error_buffer, yylloc, lineno, str);
}
static int
-parser_yyerror(struct parser_params *p, const rb_code_location_t *yylloc, const char *msg)
+parser_yyerror(struct parser_params *p, const YYLTYPE *yylloc, const char *msg)
{
#if 0
YYLTYPE current;
if (!yylloc) {
- yylloc = RUBY_SET_YYLLOC(current);
+ yylloc = RUBY_SET_YYLLOC(current);
}
else if ((p->ruby_sourceline != yylloc->beg_pos.lineno &&
- p->ruby_sourceline != yylloc->end_pos.lineno)) {
- yylloc = 0;
+ p->ruby_sourceline != yylloc->end_pos.lineno)) {
+ yylloc = 0;
}
#endif
- parser_compile_error(p, yylloc, "%s", msg);
+ compile_error(p, "%s", msg);
parser_show_error_line(p, yylloc);
return 0;
}
@@ -7092,7 +6487,7 @@ parser_yyerror0(struct parser_params *p, const char *msg)
}
static void
-ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yylloc, int lineno, VALUE str)
+ruby_show_error_line(VALUE errbuf, const YYLTYPE *yylloc, int lineno, VALUE str)
{
VALUE mesg;
const int max_line_margin = 30;
@@ -7108,13 +6503,13 @@ ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yyllo
if (!yylloc) return;
pend = RSTRING_END(str);
if (pend > pbeg && pend[-1] == '\n') {
- if (--pend > pbeg && pend[-1] == '\r') --pend;
+ if (--pend > pbeg && pend[-1] == '\r') --pend;
}
pt = pend;
if (lineno == yylloc->end_pos.lineno &&
- (pend - pbeg) > yylloc->end_pos.column) {
- pt = pbeg + yylloc->end_pos.column;
+ (pend - pbeg) > yylloc->end_pos.column) {
+ pt = pbeg + yylloc->end_pos.column;
}
ptr = ptr_end = pt;
@@ -7126,72 +6521,72 @@ ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yyllo
len = ptr_end - ptr;
if (len > 4) {
- if (ptr > pbeg) {
- ptr = rb_enc_prev_char(pbeg, ptr, pt, rb_enc_get(str));
- if (ptr > pbeg) pre = "...";
- }
- if (ptr_end < pend) {
- ptr_end = rb_enc_prev_char(pt, ptr_end, pend, rb_enc_get(str));
- if (ptr_end < pend) post = "...";
- }
+ if (ptr > pbeg) {
+ ptr = rb_enc_prev_char(pbeg, ptr, pt, rb_enc_get(str));
+ if (ptr > pbeg) pre = "...";
+ }
+ if (ptr_end < pend) {
+ ptr_end = rb_enc_prev_char(pt, ptr_end, pend, rb_enc_get(str));
+ if (ptr_end < pend) post = "...";
+ }
}
pb = pbeg;
if (lineno == yylloc->beg_pos.lineno) {
- pb += yylloc->beg_pos.column;
- if (pb > pt) pb = pt;
+ pb += yylloc->beg_pos.column;
+ if (pb > pt) pb = pt;
}
if (pb < ptr) pb = ptr;
if (len <= 4 && yylloc->beg_pos.lineno == yylloc->end_pos.lineno) {
- return;
+ return;
}
if (RTEST(errbuf)) {
- mesg = rb_attr_get(errbuf, idMesg);
- if (RSTRING_LEN(mesg) > 0 && *(RSTRING_END(mesg)-1) != '\n')
- rb_str_cat_cstr(mesg, "\n");
+ mesg = rb_attr_get(errbuf, idMesg);
+ if (RSTRING_LEN(mesg) > 0 && *(RSTRING_END(mesg)-1) != '\n')
+ rb_str_cat_cstr(mesg, "\n");
}
else {
- mesg = rb_enc_str_new(0, 0, rb_enc_get(str));
+ mesg = rb_enc_str_new(0, 0, rb_enc_get(str));
}
if (!errbuf && rb_stderr_tty_p()) {
#define CSI_BEGIN "\033["
#define CSI_SGR "m"
- rb_str_catf(mesg,
- CSI_BEGIN""CSI_SGR"%s" /* pre */
- CSI_BEGIN"1"CSI_SGR"%.*s"
- CSI_BEGIN"1;4"CSI_SGR"%.*s"
- CSI_BEGIN";1"CSI_SGR"%.*s"
- CSI_BEGIN""CSI_SGR"%s" /* post */
- "\n",
- pre,
- (int)(pb - ptr), ptr,
- (int)(pt - pb), pb,
- (int)(ptr_end - pt), pt,
- post);
+ rb_str_catf(mesg,
+ CSI_BEGIN""CSI_SGR"%s" /* pre */
+ CSI_BEGIN"1"CSI_SGR"%.*s"
+ CSI_BEGIN"1;4"CSI_SGR"%.*s"
+ CSI_BEGIN";1"CSI_SGR"%.*s"
+ CSI_BEGIN""CSI_SGR"%s" /* post */
+ "\n",
+ pre,
+ (int)(pb - ptr), ptr,
+ (int)(pt - pb), pb,
+ (int)(ptr_end - pt), pt,
+ post);
}
else {
- char *p2;
-
- len = ptr_end - ptr;
- lim = pt < pend ? pt : pend;
- i = (int)(lim - ptr);
- buf = ALLOCA_N(char, i+2);
- code = ptr;
- caret = p2 = buf;
- if (ptr <= pb) {
- while (ptr < pb) {
- *p2++ = *ptr++ == '\t' ? '\t' : ' ';
- }
- *p2++ = '^';
- ptr++;
- }
- if (lim > ptr) {
- memset(p2, '~', (lim - ptr));
- p2 += (lim - ptr);
- }
- *p2 = '\0';
- rb_str_catf(mesg, "%s%.*s%s\n""%s%s\n",
- pre, (int)len, code, post,
- pre, caret);
+ char *p2;
+
+ len = ptr_end - ptr;
+ lim = pt < pend ? pt : pend;
+ i = (int)(lim - ptr);
+ buf = ALLOCA_N(char, i+2);
+ code = ptr;
+ caret = p2 = buf;
+ if (ptr <= pb) {
+ while (ptr < pb) {
+ *p2++ = *ptr++ == '\t' ? '\t' : ' ';
+ }
+ *p2++ = '^';
+ ptr++;
+ }
+ if (lim > ptr) {
+ memset(p2, '~', (lim - ptr));
+ p2 += (lim - ptr);
+ }
+ *p2 = '\0';
+ rb_str_catf(mesg, "%s%.*s%s\n""%s%s\n",
+ pre, (int)len, code, post,
+ pre, caret);
}
if (!errbuf) rb_write_error_str(mesg);
}
@@ -7201,16 +6596,16 @@ parser_yyerror(struct parser_params *p, const YYLTYPE *yylloc, const char *msg)
{
const char *pcur = 0, *ptok = 0;
if (p->ruby_sourceline == yylloc->beg_pos.lineno &&
- p->ruby_sourceline == yylloc->end_pos.lineno) {
- pcur = p->lex.pcur;
- ptok = p->lex.ptok;
- p->lex.ptok = p->lex.pbeg + yylloc->beg_pos.column;
- p->lex.pcur = p->lex.pbeg + yylloc->end_pos.column;
+ p->ruby_sourceline == yylloc->end_pos.lineno) {
+ pcur = p->lex.pcur;
+ ptok = p->lex.ptok;
+ p->lex.ptok = p->lex.pbeg + yylloc->beg_pos.column;
+ p->lex.pcur = p->lex.pbeg + yylloc->end_pos.column;
}
parser_yyerror0(p, msg);
if (pcur) {
- p->lex.ptok = ptok;
- p->lex.pcur = pcur;
+ p->lex.ptok = ptok;
+ p->lex.pcur = pcur;
}
return 0;
}
@@ -7234,10 +6629,10 @@ static int
vtable_size(const struct vtable *tbl)
{
if (!DVARS_TERMINAL_P(tbl)) {
- return tbl->pos;
+ return tbl->pos;
}
else {
- return 0;
+ return 0;
}
}
#endif
@@ -7252,7 +6647,7 @@ vtable_alloc_gen(struct parser_params *p, int line, struct vtable *prev)
tbl->prev = prev;
#ifndef RIPPER
if (p->debug) {
- rb_parser_printf(p, "vtable_alloc:%d: %p\n", line, (void *)tbl);
+ rb_parser_printf(p, "vtable_alloc:%d: %p\n", line, (void *)tbl);
}
#endif
return tbl;
@@ -7261,39 +6656,39 @@ vtable_alloc_gen(struct parser_params *p, int line, struct vtable *prev)
static void
vtable_free_gen(struct parser_params *p, int line, const char *name,
- struct vtable *tbl)
+ struct vtable *tbl)
{
#ifndef RIPPER
if (p->debug) {
- rb_parser_printf(p, "vtable_free:%d: %s(%p)\n", line, name, (void *)tbl);
+ rb_parser_printf(p, "vtable_free:%d: %s(%p)\n", line, name, (void *)tbl);
}
#endif
if (!DVARS_TERMINAL_P(tbl)) {
- if (tbl->tbl) {
- ruby_sized_xfree(tbl->tbl, tbl->capa * sizeof(ID));
- }
- ruby_sized_xfree(tbl, sizeof(*tbl));
+ if (tbl->tbl) {
+ ruby_sized_xfree(tbl->tbl, tbl->capa * sizeof(ID));
+ }
+ ruby_sized_xfree(tbl, sizeof(*tbl));
}
}
#define vtable_free(tbl) vtable_free_gen(p, __LINE__, #tbl, tbl)
static void
vtable_add_gen(struct parser_params *p, int line, const char *name,
- struct vtable *tbl, ID id)
+ struct vtable *tbl, ID id)
{
#ifndef RIPPER
if (p->debug) {
- rb_parser_printf(p, "vtable_add:%d: %s(%p), %s\n",
- line, name, (void *)tbl, rb_id2name(id));
+ rb_parser_printf(p, "vtable_add:%d: %s(%p), %s\n",
+ line, name, (void *)tbl, rb_id2name(id));
}
#endif
if (DVARS_TERMINAL_P(tbl)) {
- rb_parser_fatal(p, "vtable_add: vtable is not allocated (%p)", (void *)tbl);
- return;
+ rb_parser_fatal(p, "vtable_add: vtable is not allocated (%p)", (void *)tbl);
+ return;
}
if (tbl->pos == tbl->capa) {
- tbl->capa = tbl->capa * 2;
- SIZED_REALLOC_N(tbl->tbl, ID, tbl->capa, tbl->pos);
+ tbl->capa = tbl->capa * 2;
+ SIZED_REALLOC_N(tbl->tbl, ID, tbl->capa, tbl->pos);
}
tbl->tbl[tbl->pos++] = id;
}
@@ -7302,15 +6697,15 @@ vtable_add_gen(struct parser_params *p, int line, const char *name,
#ifndef RIPPER
static void
vtable_pop_gen(struct parser_params *p, int line, const char *name,
- struct vtable *tbl, int n)
+ struct vtable *tbl, int n)
{
if (p->debug) {
- rb_parser_printf(p, "vtable_pop:%d: %s(%p), %d\n",
- line, name, (void *)tbl, n);
+ rb_parser_printf(p, "vtable_pop:%d: %s(%p), %d\n",
+ line, name, (void *)tbl, n);
}
if (tbl->pos < n) {
- rb_parser_fatal(p, "vtable_pop: unreachable (%d < %d)", tbl->pos, n);
- return;
+ rb_parser_fatal(p, "vtable_pop: unreachable (%d < %d)", tbl->pos, n);
+ return;
}
tbl->pos -= n;
}
@@ -7323,11 +6718,11 @@ vtable_included(const struct vtable * tbl, ID id)
int i;
if (!DVARS_TERMINAL_P(tbl)) {
- for (i = 0; i < tbl->pos; i++) {
- if (tbl->tbl[i] == id) {
- return i+1;
- }
- }
+ for (i = 0; i < tbl->pos; i++) {
+ if (tbl->tbl[i] == id) {
+ return i+1;
+ }
+ }
}
return 0;
}
@@ -7337,6 +6732,22 @@ static void parser_prepare(struct parser_params *p);
#ifndef RIPPER
static NODE *parser_append_options(struct parser_params *p, NODE *node);
+static VALUE
+debug_lines(VALUE fname)
+{
+ ID script_lines;
+ CONST_ID(script_lines, "SCRIPT_LINES__");
+ if (rb_const_defined_at(rb_cObject, script_lines)) {
+ VALUE hash = rb_const_get_at(rb_cObject, script_lines);
+ if (RB_TYPE_P(hash, T_HASH)) {
+ VALUE lines = rb_ary_new();
+ rb_hash_aset(hash, fname, lines);
+ return lines;
+ }
+ }
+ return 0;
+}
+
static int
e_option_supplied(struct parser_params *p)
{
@@ -7349,30 +6760,35 @@ yycompile0(VALUE arg)
int n;
NODE *tree;
struct parser_params *p = (struct parser_params *)arg;
- int cov = FALSE;
+ VALUE cov = Qfalse;
if (!compile_for_eval && !NIL_P(p->ruby_sourcefile_string)) {
- if (p->debug_lines && p->ruby_sourceline > 0) {
- VALUE str = rb_default_rs;
- n = p->ruby_sourceline;
- do {
- rb_ary_push(p->debug_lines, str);
- } while (--n);
- }
+ p->debug_lines = debug_lines(p->ruby_sourcefile_string);
+ if (p->debug_lines && p->ruby_sourceline > 0) {
+ VALUE str = rb_default_rs;
+ n = p->ruby_sourceline;
+ do {
+ rb_ary_push(p->debug_lines, str);
+ } while (--n);
+ }
- if (!e_option_supplied(p)) {
- cov = TRUE;
- }
+ if (!e_option_supplied(p)) {
+ cov = Qtrue;
+ }
}
- if (p->debug_lines) {
+ if (p->keep_script_lines || ruby_vm_keep_script_lines) {
+ if (!p->debug_lines) {
+ p->debug_lines = rb_ary_new();
+ }
+
RB_OBJ_WRITE(p->ast, &p->ast->body.script_lines, p->debug_lines);
}
parser_prepare(p);
#define RUBY_DTRACE_PARSE_HOOK(name) \
if (RUBY_DTRACE_PARSE_##name##_ENABLED()) { \
- RUBY_DTRACE_PARSE_##name(p->ruby_sourcefile, p->ruby_sourceline); \
+ RUBY_DTRACE_PARSE_##name(p->ruby_sourcefile, p->ruby_sourceline); \
}
RUBY_DTRACE_PARSE_HOOK(BEGIN);
n = yyparse(p);
@@ -7382,31 +6798,33 @@ yycompile0(VALUE arg)
p->lex.strterm = 0;
p->lex.pcur = p->lex.pbeg = p->lex.pend = 0;
if (n || p->error_p) {
- VALUE mesg = p->error_buffer;
- if (!mesg) {
- mesg = syntax_error_new();
- }
- if (!p->error_tolerant) {
- rb_set_errinfo(mesg);
- return FALSE;
- }
+ VALUE mesg = p->error_buffer;
+ if (!mesg) {
+ mesg = rb_class_new_instance(0, 0, rb_eSyntaxError);
+ }
+ if (!p->error_tolerant) {
+ rb_set_errinfo(mesg);
+ return FALSE;
+ }
}
tree = p->eval_tree;
if (!tree) {
- tree = NEW_NIL(&NULL_LOC);
+ tree = NEW_NIL(&NULL_LOC);
}
else {
- VALUE tokens = p->tokens;
- NODE *prelude;
- NODE *body = parser_append_options(p, RNODE_SCOPE(tree)->nd_body);
- prelude = block_append(p, p->eval_tree_begin, body);
- RNODE_SCOPE(tree)->nd_body = prelude;
- p->ast->body.frozen_string_literal = p->frozen_string_literal;
- p->ast->body.coverage_enabled = cov;
- if (p->keep_tokens) {
- rb_obj_freeze(tokens);
- rb_ast_set_tokens(p->ast, tokens);
- }
+ VALUE opt = p->compile_option;
+ VALUE tokens = p->tokens;
+ NODE *prelude;
+ NODE *body = parser_append_options(p, tree->nd_body);
+ if (!opt) opt = rb_obj_hide(rb_ident_hash_new());
+ rb_hash_aset(opt, rb_sym_intern_ascii_cstr("coverage_enabled"), cov);
+ prelude = block_append(p, p->eval_tree_begin, body);
+ tree->nd_body = prelude;
+ RB_OBJ_WRITE(p->ast, &p->ast->body.compile_option, opt);
+ if (p->keep_tokens) {
+ rb_obj_freeze(tokens);
+ rb_ast_set_tokens(p->ast, tokens);
+ }
}
p->ast->body.root = tree;
if (!p->ast->body.script_lines) p->ast->body.script_lines = INT2FIX(p->line_count);
@@ -7414,24 +6832,25 @@ yycompile0(VALUE arg)
}
static rb_ast_t *
-yycompile(struct parser_params *p, VALUE fname, int line)
+yycompile(VALUE vparser, struct parser_params *p, VALUE fname, int line)
{
rb_ast_t *ast;
if (NIL_P(fname)) {
- p->ruby_sourcefile_string = Qnil;
- p->ruby_sourcefile = "(none)";
+ p->ruby_sourcefile_string = Qnil;
+ p->ruby_sourcefile = "(none)";
}
else {
- p->ruby_sourcefile_string = rb_fstring(fname);
- p->ruby_sourcefile = StringValueCStr(fname);
+ p->ruby_sourcefile_string = rb_fstring(fname);
+ p->ruby_sourcefile = StringValueCStr(fname);
}
p->ruby_sourceline = line - 1;
p->lvtbl = NULL;
p->ast = ast = rb_ast_new();
- compile_callback(yycompile0, (VALUE)p);
+ rb_suppress_tracing(yycompile0, (VALUE)p);
p->ast = 0;
+ RB_GC_GUARD(vparser); /* prohibit tail call optimization */
while (p->lvtbl) {
local_pop(p);
@@ -7442,11 +6861,11 @@ yycompile(struct parser_params *p, VALUE fname, int line)
#endif /* !RIPPER */
static rb_encoding *
-must_be_ascii_compatible(struct parser_params *p, VALUE s)
+must_be_ascii_compatible(VALUE s)
{
rb_encoding *enc = rb_enc_get(s);
if (!rb_enc_asciicompat(enc)) {
- rb_raise(rb_eArgError, "invalid source encoding");
+ rb_raise(rb_eArgError, "invalid source encoding");
}
return enc;
}
@@ -7461,9 +6880,9 @@ lex_get_str(struct parser_params *p, VALUE s)
len = RSTRING_LEN(s);
start = beg;
if (p->lex.gets_.ptr) {
- if (len == p->lex.gets_.ptr) return Qnil;
- beg += p->lex.gets_.ptr;
- len -= p->lex.gets_.ptr;
+ if (len == p->lex.gets_.ptr) return Qnil;
+ beg += p->lex.gets_.ptr;
+ len -= p->lex.gets_.ptr;
}
end = memchr(beg, '\n', len);
if (end) len = ++end - beg;
@@ -7476,37 +6895,45 @@ lex_getline(struct parser_params *p)
{
VALUE line = (*p->lex.gets)(p, p->lex.input);
if (NIL_P(line)) return line;
- must_be_ascii_compatible(p, line);
+ must_be_ascii_compatible(line);
if (RB_OBJ_FROZEN(line)) line = rb_str_dup(line); // needed for RubyVM::AST.of because script_lines in iseq is deep-frozen
p->line_count++;
return line;
}
+static const rb_data_type_t parser_data_type;
+
#ifndef RIPPER
static rb_ast_t*
-parser_compile_string(rb_parser_t *p, VALUE fname, VALUE s, int line)
+parser_compile_string(VALUE vparser, VALUE fname, VALUE s, int line)
{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+
p->lex.gets = lex_get_str;
p->lex.gets_.ptr = 0;
p->lex.input = rb_str_new_frozen(s);
p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
- return yycompile(p, fname, line);
+ return yycompile(vparser, p, fname, line);
}
rb_ast_t*
-rb_ruby_parser_compile_string_path(rb_parser_t *p, VALUE f, VALUE s, int line)
+rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
{
- must_be_ascii_compatible(p, s);
- return parser_compile_string(p, f, s, line);
+ return rb_parser_compile_string_path(vparser, rb_filesystem_str_new_cstr(f), s, line);
}
rb_ast_t*
-rb_ruby_parser_compile_string(rb_parser_t *p, const char *f, VALUE s, int line)
+rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
{
- return rb_ruby_parser_compile_string_path(p, rb_filesystem_str_new_cstr(f), s, line);
+ must_be_ascii_compatible(s);
+ return parser_compile_string(vparser, f, s, line);
}
+VALUE rb_io_gets_internal(VALUE io);
+
static VALUE
lex_io_gets(struct parser_params *p, VALUE io)
{
@@ -7514,13 +6941,17 @@ lex_io_gets(struct parser_params *p, VALUE io)
}
rb_ast_t*
-rb_ruby_parser_compile_file_path(rb_parser_t *p, VALUE fname, VALUE file, int start)
+rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+
p->lex.gets = lex_io_gets;
p->lex.input = file;
p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
- return yycompile(p, fname, start);
+ return yycompile(vparser, p, fname, start);
}
static VALUE
@@ -7530,14 +6961,18 @@ lex_generic_gets(struct parser_params *p, VALUE input)
}
rb_ast_t*
-rb_ruby_parser_compile_generic(rb_parser_t *p, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
+rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+
p->lex.gets = lex_generic_gets;
p->lex.gets_.call = lex_gets;
p->lex.input = input;
p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
- return yycompile(p, fname, start);
+ return yycompile(vparser, p, fname, start);
}
#endif /* !RIPPER */
@@ -7564,46 +6999,22 @@ enum string_type {
};
static VALUE
-parser_str_new(struct parser_params *p, const char *ptr, long len, rb_encoding *enc, int func, rb_encoding *enc0)
+parser_str_new(const char *ptr, long len, rb_encoding *enc, int func, rb_encoding *enc0)
{
VALUE str;
str = rb_enc_str_new(ptr, len, enc);
if (!(func & STR_FUNC_REGEXP) && rb_enc_asciicompat(enc)) {
- if (is_ascii_string(str)) {
- }
- else if (rb_is_usascii_enc((void *)enc0) && enc != rb_utf8_encoding()) {
- rb_enc_associate(str, rb_ascii8bit_encoding());
- }
+ if (is_ascii_string(str)) {
+ }
+ else if (rb_is_usascii_enc(enc0) && enc != rb_utf8_encoding()) {
+ rb_enc_associate(str, rb_ascii8bit_encoding());
+ }
}
return str;
}
-static int
-strterm_is_heredoc(rb_strterm_t *strterm)
-{
- return strterm->flags & STRTERM_HEREDOC;
-}
-
-static rb_strterm_t *
-new_strterm(struct parser_params *p, int func, int term, int paren)
-{
- rb_strterm_t *strterm = ZALLOC(rb_strterm_t);
- strterm->u.literal.func = func;
- strterm->u.literal.term = term;
- strterm->u.literal.paren = paren;
- return strterm;
-}
-
-static rb_strterm_t *
-new_heredoc(struct parser_params *p)
-{
- rb_strterm_t *strterm = ZALLOC(rb_strterm_t);
- strterm->flags |= STRTERM_HEREDOC;
- return strterm;
-}
-
#define peek(p,c) peek_n(p, (c), 0)
#define peek_n(p,c,n) (!lex_eol_n_p(p, n) && (c) == (unsigned char)(p)->lex.pcur[n])
#define peekc(p) peekc_n(p, 0)
@@ -7617,66 +7028,60 @@ add_delayed_token(struct parser_params *p, const char *tok, const char *end, int
#endif
if (tok < end) {
- if (!has_delayed_token(p)) {
- p->delayed.token = rb_str_buf_new(end - tok);
- rb_enc_associate(p->delayed.token, p->enc);
- p->delayed.beg_line = p->ruby_sourceline;
- p->delayed.beg_col = rb_long2int(tok - p->lex.pbeg);
- }
- rb_str_buf_cat(p->delayed.token, tok, end - tok);
- p->delayed.end_line = p->ruby_sourceline;
- p->delayed.end_col = rb_long2int(end - p->lex.pbeg);
- p->lex.ptok = end;
+ if (!has_delayed_token(p)) {
+ p->delayed.token = rb_str_buf_new(end - tok);
+ rb_enc_associate(p->delayed.token, p->enc);
+ p->delayed.beg_line = p->ruby_sourceline;
+ p->delayed.beg_col = rb_long2int(tok - p->lex.pbeg);
+ }
+ rb_str_buf_cat(p->delayed.token, tok, end - tok);
+ p->delayed.end_line = p->ruby_sourceline;
+ p->delayed.end_col = rb_long2int(end - p->lex.pbeg);
+ p->lex.ptok = end;
}
}
-static void
-set_lastline(struct parser_params *p, VALUE v)
-{
- p->lex.pbeg = p->lex.pcur = RSTRING_PTR(v);
- p->lex.pend = p->lex.pcur + RSTRING_LEN(v);
- p->lex.lastline = v;
-}
-
static int
nextline(struct parser_params *p, int set_encoding)
{
VALUE v = p->lex.nextline;
p->lex.nextline = 0;
if (!v) {
- if (p->eofp)
- return -1;
-
- if (!lex_eol_ptr_p(p, p->lex.pbeg) && *(p->lex.pend-1) != '\n') {
- goto end_of_input;
- }
-
- if (!p->lex.input || NIL_P(v = lex_getline(p))) {
- end_of_input:
- p->eofp = 1;
- lex_goto_eol(p);
- return -1;
- }
+ if (p->eofp)
+ return -1;
+
+ if (p->lex.pend > p->lex.pbeg && *(p->lex.pend-1) != '\n') {
+ goto end_of_input;
+ }
+
+ if (!p->lex.input || NIL_P(v = lex_getline(p))) {
+ end_of_input:
+ p->eofp = 1;
+ lex_goto_eol(p);
+ return -1;
+ }
#ifndef RIPPER
- if (p->debug_lines) {
- if (set_encoding) rb_enc_associate(v, p->enc);
- rb_ary_push(p->debug_lines, v);
- }
+ if (p->debug_lines) {
+ if (set_encoding) rb_enc_associate(v, p->enc);
+ rb_ary_push(p->debug_lines, v);
+ }
#endif
- p->cr_seen = FALSE;
+ p->cr_seen = FALSE;
}
else if (NIL_P(v)) {
- /* after here-document without terminator */
- goto end_of_input;
+ /* after here-document without terminator */
+ goto end_of_input;
}
add_delayed_token(p, p->lex.ptok, p->lex.pend, __LINE__);
if (p->heredoc_end > 0) {
- p->ruby_sourceline = p->heredoc_end;
- p->heredoc_end = 0;
+ p->ruby_sourceline = p->heredoc_end;
+ p->heredoc_end = 0;
}
p->ruby_sourceline++;
- set_lastline(p, v);
+ p->lex.pbeg = p->lex.pcur = RSTRING_PTR(v);
+ p->lex.pend = p->lex.pcur + RSTRING_LEN(v);
token_flush(p);
+ p->lex.lastline = v;
return 0;
}
@@ -7684,8 +7089,8 @@ static int
parser_cr(struct parser_params *p, int c)
{
if (peek(p, '\n')) {
- p->lex.pcur++;
- c = '\n';
+ p->lex.pcur++;
+ c = '\n';
}
return c;
}
@@ -7695,12 +7100,12 @@ nextc0(struct parser_params *p, int set_encoding)
{
int c;
- if (UNLIKELY(lex_eol_p(p) || p->eofp || RTEST(p->lex.nextline))) {
- if (nextline(p, set_encoding)) return -1;
+ if (UNLIKELY((p->lex.pcur == p->lex.pend) || p->eofp || RTEST(p->lex.nextline))) {
+ if (nextline(p, set_encoding)) return -1;
}
c = (unsigned char)*p->lex.pcur++;
if (UNLIKELY(c == '\r')) {
- c = parser_cr(p, c);
+ c = parser_cr(p, c);
}
return c;
@@ -7711,10 +7116,9 @@ static void
pushback(struct parser_params *p, int c)
{
if (c == -1) return;
- p->eofp = 0;
p->lex.pcur--;
if (p->lex.pcur > p->lex.pbeg && p->lex.pcur[0] == '\n' && p->lex.pcur[-1] == '\r') {
- p->lex.pcur--;
+ p->lex.pcur--;
}
}
@@ -7728,12 +7132,12 @@ static int
looking_at_eol_p(struct parser_params *p)
{
const char *ptr = p->lex.pcur;
- while (!lex_eol_ptr_p(p, ptr)) {
- int c = (unsigned char)*ptr++;
- int eol = (c == '\n' || c == '#');
- if (eol || !ISSPACE(c)) {
- return eol;
- }
+ while (ptr < p->lex.pend) {
+ int c = (unsigned char)*ptr++;
+ int eol = (c == '\n' || c == '#');
+ if (eol || !ISSPACE(c)) {
+ return eol;
+ }
}
return TRUE;
}
@@ -7742,13 +7146,14 @@ static char*
newtok(struct parser_params *p)
{
p->tokidx = 0;
+ p->tokline = p->ruby_sourceline;
if (!p->tokenbuf) {
- p->toksiz = 60;
- p->tokenbuf = ALLOC_N(char, 60);
+ p->toksiz = 60;
+ p->tokenbuf = ALLOC_N(char, 60);
}
if (p->toksiz > 4096) {
- p->toksiz = 60;
- REALLOC_N(p->tokenbuf, char, 60);
+ p->toksiz = 60;
+ REALLOC_N(p->tokenbuf, char, 60);
}
return p->tokenbuf;
}
@@ -7759,8 +7164,8 @@ tokspace(struct parser_params *p, int n)
p->tokidx += n;
if (p->tokidx >= p->toksiz) {
- do {p->toksiz *= 2;} while (p->toksiz < p->tokidx);
- REALLOC_N(p->tokenbuf, char, p->toksiz);
+ do {p->toksiz *= 2;} while (p->toksiz < p->tokidx);
+ REALLOC_N(p->tokenbuf, char, p->toksiz);
}
return &p->tokenbuf[p->tokidx-n];
}
@@ -7770,8 +7175,8 @@ tokadd(struct parser_params *p, int c)
{
p->tokenbuf[p->tokidx++] = (char)c;
if (p->tokidx >= p->toksiz) {
- p->toksiz *= 2;
- REALLOC_N(p->tokenbuf, char, p->toksiz);
+ p->toksiz *= 2;
+ REALLOC_N(p->tokenbuf, char, p->toksiz);
}
}
@@ -7780,11 +7185,11 @@ tok_hex(struct parser_params *p, size_t *numlen)
{
int c;
- c = (int)ruby_scan_hex(p->lex.pcur, 2, numlen);
+ c = scan_hex(p->lex.pcur, 2, numlen);
if (!*numlen) {
- yyerror0("invalid hex escape");
- token_flush(p);
- return 0;
+ yyerror0("invalid hex escape");
+ token_flush(p);
+ return 0;
}
p->lex.pcur += *numlen;
return c;
@@ -7798,23 +7203,23 @@ escaped_control_code(int c)
int c2 = 0;
switch (c) {
case ' ':
- c2 = 's';
- break;
+ c2 = 's';
+ break;
case '\n':
- c2 = 'n';
- break;
+ c2 = 'n';
+ break;
case '\t':
- c2 = 't';
- break;
+ c2 = 't';
+ break;
case '\v':
- c2 = 'v';
- break;
+ c2 = 'v';
+ break;
case '\r':
- c2 = 'r';
- break;
+ c2 = 'r';
+ break;
case '\f':
- c2 = 'f';
- break;
+ c2 = 'f';
+ break;
}
return c2;
}
@@ -7824,14 +7229,14 @@ escaped_control_code(int c)
static int
tokadd_codepoint(struct parser_params *p, rb_encoding **encp,
- int regexp_literal, int wide)
+ int regexp_literal, int wide)
{
size_t numlen;
- int codepoint = (int)ruby_scan_hex(p->lex.pcur, wide ? p->lex.pend - p->lex.pcur : 4, &numlen);
+ int codepoint = scan_hex(p->lex.pcur, wide ? p->lex.pend - p->lex.pcur : 4, &numlen);
p->lex.pcur += numlen;
if (p->lex.strterm == NULL ||
- strterm_is_heredoc(p->lex.strterm) ||
- (p->lex.strterm->u.literal.func != str_regexp)) {
+ (p->lex.strterm->flags & STRTERM_HEREDOC) ||
+ (p->lex.strterm->u.literal.u1.func != str_regexp)) {
if (wide ? (numlen == 0 || numlen > 6) : (numlen < 4)) {
literal_flush(p, p->lex.pcur);
yyerror0("invalid Unicode escape");
@@ -7849,31 +7254,41 @@ tokadd_codepoint(struct parser_params *p, rb_encoding **encp,
}
}
if (regexp_literal) {
- tokcopy(p, (int)numlen);
+ tokcopy(p, (int)numlen);
}
else if (codepoint >= 0x80) {
- rb_encoding *utf8 = rb_utf8_encoding();
- if (*encp && utf8 != *encp) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- compile_error(p, "UTF-8 mixed within %s source", rb_enc_name(*encp));
- parser_show_error_line(p, &loc);
- return wide;
- }
- *encp = utf8;
- tokaddmbc(p, codepoint, *encp);
+ rb_encoding *utf8 = rb_utf8_encoding();
+ if (*encp && utf8 != *encp) {
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ compile_error(p, "UTF-8 mixed within %s source", rb_enc_name(*encp));
+ parser_show_error_line(p, &loc);
+ return wide;
+ }
+ *encp = utf8;
+ tokaddmbc(p, codepoint, *encp);
}
else {
- tokadd(p, codepoint);
+ tokadd(p, codepoint);
}
return TRUE;
}
static int tokadd_mbchar(struct parser_params *p, int c);
+static int
+tokskip_mbchar(struct parser_params *p)
+{
+ int len = parser_precise_mbclen(p, p->lex.pcur-1);
+ if (len > 0) {
+ p->lex.pcur += len - 1;
+ }
+ return len;
+}
+
/* return value is for ?\u3042 */
static void
tokadd_utf8(struct parser_params *p, rb_encoding **encp,
- int term, int symbol_literal, int regexp_literal)
+ int term, int symbol_literal, int regexp_literal)
{
/*
* If `term` is not -1, then we allow multiple codepoints in \u{}
@@ -7887,7 +7302,7 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
if (regexp_literal) { tokadd(p, '\\'); tokadd(p, 'u'); }
if (peek(p, open_brace)) { /* handle \u{...} form */
- if (regexp_literal && p->lex.strterm->u.literal.func == str_regexp) {
+ if (regexp_literal && p->lex.strterm->u.literal.u1.func == str_regexp) {
/*
* Skip parsing validation code and copy bytes as-is until term or
* closing brace, in order to correctly handle extended regexps where
@@ -7895,7 +7310,7 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
* does its own validation and will catch any issues.
*/
tokadd(p, open_brace);
- while (!lex_eol_ptr_p(p, ++p->lex.pcur)) {
+ while (++p->lex.pcur < p->lex.pend) {
int c = peekc(p);
if (c == close_brace) {
tokadd(p, c);
@@ -7905,7 +7320,7 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
else if (c == term) {
break;
}
- if (c == '\\' && !lex_eol_n_p(p, 1)) {
+ if (c == '\\' && p->lex.pcur + 1 < p->lex.pend) {
tokadd(p, c);
c = *++p->lex.pcur;
}
@@ -7915,8 +7330,8 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
else {
const char *second = NULL;
int c, last = nextc(p);
- if (lex_eol_p(p)) goto unterminated;
- while (ISSPACE(c = peekc(p)) && !lex_eol_ptr_p(p, ++p->lex.pcur));
+ if (p->lex.pcur >= p->lex.pend) goto unterminated;
+ while (ISSPACE(c = *p->lex.pcur) && ++p->lex.pcur < p->lex.pend);
while (c != close_brace) {
if (c == term) goto unterminated;
if (second == multiple_codepoints)
@@ -7925,8 +7340,8 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
if (!tokadd_codepoint(p, encp, regexp_literal, TRUE)) {
break;
}
- while (ISSPACE(c = peekc(p))) {
- if (lex_eol_ptr_p(p, ++p->lex.pcur)) goto unterminated;
+ while (ISSPACE(c = *p->lex.pcur)) {
+ if (++p->lex.pcur >= p->lex.pend) goto unterminated;
last = c;
}
if (term == -1 && !second)
@@ -7954,10 +7369,10 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
}
}
else { /* handle \uxxxx form */
- if (!tokadd_codepoint(p, encp, regexp_literal, FALSE)) {
- token_flush(p);
- return;
- }
+ if (!tokadd_codepoint(p, encp, regexp_literal, FALSE)) {
+ token_flush(p);
+ return;
+ }
}
}
@@ -7965,131 +7380,139 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
#define ESCAPE_META 2
static int
-read_escape(struct parser_params *p, int flags)
+read_escape(struct parser_params *p, int flags, rb_encoding **encp)
{
int c;
size_t numlen;
switch (c = nextc(p)) {
case '\\': /* Backslash */
- return c;
+ return c;
case 'n': /* newline */
- return '\n';
+ return '\n';
case 't': /* horizontal tab */
- return '\t';
+ return '\t';
case 'r': /* carriage-return */
- return '\r';
+ return '\r';
case 'f': /* form-feed */
- return '\f';
+ return '\f';
case 'v': /* vertical tab */
- return '\13';
+ return '\13';
case 'a': /* alarm(bell) */
- return '\007';
+ return '\007';
case 'e': /* escape */
- return 033;
+ return 033;
case '0': case '1': case '2': case '3': /* octal constant */
case '4': case '5': case '6': case '7':
- pushback(p, c);
- c = (int)ruby_scan_oct(p->lex.pcur, 3, &numlen);
- p->lex.pcur += numlen;
- return c;
+ pushback(p, c);
+ c = scan_oct(p->lex.pcur, 3, &numlen);
+ p->lex.pcur += numlen;
+ return c;
case 'x': /* hex constant */
- c = tok_hex(p, &numlen);
- if (numlen == 0) return 0;
- return c;
+ c = tok_hex(p, &numlen);
+ if (numlen == 0) return 0;
+ return c;
case 'b': /* backspace */
- return '\010';
+ return '\010';
case 's': /* space */
- return ' ';
+ return ' ';
case 'M':
- if (flags & ESCAPE_META) goto eof;
- if ((c = nextc(p)) != '-') {
+ if (flags & ESCAPE_META) goto eof;
+ if ((c = nextc(p)) != '-') {
+ goto eof;
+ }
+ if ((c = nextc(p)) == '\\') {
+ switch (peekc(p)) {
+ case 'u': case 'U':
+ nextc(p);
+ goto eof;
+ }
+ return read_escape(p, flags|ESCAPE_META, encp) | 0x80;
+ }
+ else if (c == -1) goto eof;
+ else if (!ISASCII(c)) {
+ tokskip_mbchar(p);
goto eof;
}
- if ((c = nextc(p)) == '\\') {
- switch (peekc(p)) {
- case 'u': case 'U':
- nextc(p);
- goto eof;
- }
- return read_escape(p, flags|ESCAPE_META) | 0x80;
- }
- else if (c == -1 || !ISASCII(c)) goto eof;
- else {
- int c2 = escaped_control_code(c);
- if (c2) {
- if (ISCNTRL(c) || !(flags & ESCAPE_CONTROL)) {
- WARN_SPACE_CHAR(c2, "\\M-");
- }
- else {
- WARN_SPACE_CHAR(c2, "\\C-\\M-");
- }
- }
- else if (ISCNTRL(c)) goto eof;
- return ((c & 0xff) | 0x80);
- }
+ else {
+ int c2 = escaped_control_code(c);
+ if (c2) {
+ if (ISCNTRL(c) || !(flags & ESCAPE_CONTROL)) {
+ WARN_SPACE_CHAR(c2, "\\M-");
+ }
+ else {
+ WARN_SPACE_CHAR(c2, "\\C-\\M-");
+ }
+ }
+ else if (ISCNTRL(c)) goto eof;
+ return ((c & 0xff) | 0x80);
+ }
case 'C':
- if ((c = nextc(p)) != '-') {
- goto eof;
- }
+ if ((c = nextc(p)) != '-') {
+ goto eof;
+ }
case 'c':
- if (flags & ESCAPE_CONTROL) goto eof;
- if ((c = nextc(p))== '\\') {
- switch (peekc(p)) {
- case 'u': case 'U':
- nextc(p);
- goto eof;
- }
- c = read_escape(p, flags|ESCAPE_CONTROL);
- }
- else if (c == '?')
- return 0177;
- else if (c == -1 || !ISASCII(c)) goto eof;
- else {
- int c2 = escaped_control_code(c);
- if (c2) {
- if (ISCNTRL(c)) {
- if (flags & ESCAPE_META) {
- WARN_SPACE_CHAR(c2, "\\M-");
- }
- else {
- WARN_SPACE_CHAR(c2, "");
- }
- }
- else {
- if (flags & ESCAPE_META) {
- WARN_SPACE_CHAR(c2, "\\M-\\C-");
- }
- else {
- WARN_SPACE_CHAR(c2, "\\C-");
- }
- }
- }
- else if (ISCNTRL(c)) goto eof;
+ if (flags & ESCAPE_CONTROL) goto eof;
+ if ((c = nextc(p))== '\\') {
+ switch (peekc(p)) {
+ case 'u': case 'U':
+ nextc(p);
+ goto eof;
+ }
+ c = read_escape(p, flags|ESCAPE_CONTROL, encp);
+ }
+ else if (c == '?')
+ return 0177;
+ else if (c == -1) goto eof;
+ else if (!ISASCII(c)) {
+ tokskip_mbchar(p);
+ goto eof;
}
- return c & 0x9f;
+ else {
+ int c2 = escaped_control_code(c);
+ if (c2) {
+ if (ISCNTRL(c)) {
+ if (flags & ESCAPE_META) {
+ WARN_SPACE_CHAR(c2, "\\M-");
+ }
+ else {
+ WARN_SPACE_CHAR(c2, "");
+ }
+ }
+ else {
+ if (flags & ESCAPE_META) {
+ WARN_SPACE_CHAR(c2, "\\M-\\C-");
+ }
+ else {
+ WARN_SPACE_CHAR(c2, "\\C-");
+ }
+ }
+ }
+ else if (ISCNTRL(c)) goto eof;
+ }
+ return c & 0x9f;
eof:
case -1:
yyerror0("Invalid escape character syntax");
- token_flush(p);
- return '\0';
+ dispatch_scan_event(p, tSTRING_CONTENT);
+ return '\0';
default:
- return c;
+ return c;
}
}
@@ -8101,42 +7524,42 @@ tokaddmbc(struct parser_params *p, int c, rb_encoding *enc)
}
static int
-tokadd_escape(struct parser_params *p)
+tokadd_escape(struct parser_params *p, rb_encoding **encp)
{
int c;
size_t numlen;
switch (c = nextc(p)) {
case '\n':
- return 0; /* just ignore */
+ return 0; /* just ignore */
case '0': case '1': case '2': case '3': /* octal constant */
case '4': case '5': case '6': case '7':
- {
- ruby_scan_oct(--p->lex.pcur, 3, &numlen);
- if (numlen == 0) goto eof;
- p->lex.pcur += numlen;
- tokcopy(p, (int)numlen + 1);
- }
- return 0;
+ {
+ ruby_scan_oct(--p->lex.pcur, 3, &numlen);
+ if (numlen == 0) goto eof;
+ p->lex.pcur += numlen;
+ tokcopy(p, (int)numlen + 1);
+ }
+ return 0;
case 'x': /* hex constant */
- {
- tok_hex(p, &numlen);
- if (numlen == 0) return -1;
- tokcopy(p, (int)numlen + 2);
- }
- return 0;
+ {
+ tok_hex(p, &numlen);
+ if (numlen == 0) return -1;
+ tokcopy(p, (int)numlen + 2);
+ }
+ return 0;
eof:
case -1:
yyerror0("Invalid escape character syntax");
- token_flush(p);
- return -1;
+ token_flush(p);
+ return -1;
default:
- tokadd(p, '\\');
- tokadd(p, c);
+ tokadd(p, '\\');
+ tokadd(p, c);
}
return 0;
}
@@ -8155,26 +7578,26 @@ regx_options(struct parser_params *p)
options |= RE_OPTION_ONCE;
}
else if (rb_char_to_option_kcode(c, &opt, &kc)) {
- if (kc >= 0) {
- if (kc != rb_ascii8bit_encindex()) kcode = c;
- kopt = opt;
- }
- else {
- options |= opt;
- }
+ if (kc >= 0) {
+ if (kc != rb_ascii8bit_encindex()) kcode = c;
+ kopt = opt;
+ }
+ else {
+ options |= opt;
+ }
}
else {
- tokadd(p, c);
+ tokadd(p, c);
}
}
options |= kopt;
pushback(p, c);
if (toklen(p)) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- tokfix(p);
- compile_error(p, "unknown regexp option%s - %*s",
- toklen(p) > 1 ? "s" : "", toklen(p), tok(p));
- parser_show_error_line(p, &loc);
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ tokfix(p);
+ compile_error(p, "unknown regexp option%s - %*s",
+ toklen(p) > 1 ? "s" : "", toklen(p), tok(p));
+ parser_show_error_line(p, &loc);
}
return options | RE_OPTION_ENCODING(kcode);
}
@@ -8197,9 +7620,9 @@ simple_re_meta(int c)
case '$': case '*': case '+': case '.':
case '?': case '^': case '|':
case ')': case ']': case '}': case '>':
- return TRUE;
+ return TRUE;
default:
- return FALSE;
+ return FALSE;
}
}
@@ -8207,24 +7630,24 @@ static int
parser_update_heredoc_indent(struct parser_params *p, int c)
{
if (p->heredoc_line_indent == -1) {
- if (c == '\n') p->heredoc_line_indent = 0;
+ if (c == '\n') p->heredoc_line_indent = 0;
}
else {
- if (c == ' ') {
- p->heredoc_line_indent++;
- return TRUE;
- }
- else if (c == '\t') {
- int w = (p->heredoc_line_indent / TAB_WIDTH) + 1;
- p->heredoc_line_indent = w * TAB_WIDTH;
- return TRUE;
- }
- else if (c != '\n') {
- if (p->heredoc_indent > p->heredoc_line_indent) {
- p->heredoc_indent = p->heredoc_line_indent;
- }
- p->heredoc_line_indent = -1;
- }
+ if (c == ' ') {
+ p->heredoc_line_indent++;
+ return TRUE;
+ }
+ else if (c == '\t') {
+ int w = (p->heredoc_line_indent / TAB_WIDTH) + 1;
+ p->heredoc_line_indent = w * TAB_WIDTH;
+ return TRUE;
+ }
+ else if (c != '\n') {
+ if (p->heredoc_indent > p->heredoc_line_indent) {
+ p->heredoc_indent = p->heredoc_line_indent;
+ }
+ p->heredoc_line_indent = -1;
+ }
}
return FALSE;
}
@@ -8247,17 +7670,10 @@ parser_mixed_escape(struct parser_params *p, const char *beg, rb_encoding *enc1,
p->lex.pcur = pos;
}
-static inline char
-nibble_char_upper(unsigned int c)
-{
- c &= 0xf;
- return c + (c < 10 ? '0' : 'A' - 10);
-}
-
static int
tokadd_string(struct parser_params *p,
- int func, int term, int paren, long *nest,
- rb_encoding **encp, rb_encoding **enc)
+ int func, int term, int paren, long *nest,
+ rb_encoding **encp, rb_encoding **enc)
{
int c;
bool erred = false;
@@ -8272,9 +7688,9 @@ tokadd_string(struct parser_params *p,
(void)(erred || (parser_mixed_escape(p, beg, enc1, enc2), erred = true))
while ((c = nextc(p)) != -1) {
- if (p->heredoc_indent > 0) {
- parser_update_heredoc_indent(p, c);
- }
+ if (p->heredoc_indent > 0) {
+ parser_update_heredoc_indent(p, c);
+ }
#ifdef RIPPER
if (top_of_line && heredoc_end == p->ruby_sourceline) {
pushback(p, c);
@@ -8282,131 +7698,132 @@ tokadd_string(struct parser_params *p,
}
#endif
- if (paren && c == paren) {
- ++*nest;
- }
- else if (c == term) {
- if (!nest || !*nest) {
- pushback(p, c);
- break;
- }
- --*nest;
- }
- else if ((func & STR_FUNC_EXPAND) && c == '#' && !lex_eol_p(p)) {
- unsigned char c2 = *p->lex.pcur;
- if (c2 == '$' || c2 == '@' || c2 == '{') {
- pushback(p, c);
- break;
- }
- }
- else if (c == '\\') {
- c = nextc(p);
- switch (c) {
- case '\n':
- if (func & STR_FUNC_QWORDS) break;
- if (func & STR_FUNC_EXPAND) {
- if (!(func & STR_FUNC_INDENT) || (p->heredoc_indent < 0))
- continue;
- if (c == term) {
- c = '\\';
- goto terminate;
- }
- }
- tokadd(p, '\\');
- break;
-
- case '\\':
- if (func & STR_FUNC_ESCAPE) tokadd(p, c);
- break;
-
- case 'u':
- if ((func & STR_FUNC_EXPAND) == 0) {
- tokadd(p, '\\');
- break;
- }
- tokadd_utf8(p, enc, term,
- func & STR_FUNC_SYMBOL,
- func & STR_FUNC_REGEXP);
- continue;
-
- default:
- if (c == -1) return -1;
- if (!ISASCII(c)) {
- if ((func & STR_FUNC_EXPAND) == 0) tokadd(p, '\\');
- goto non_ascii;
- }
- if (func & STR_FUNC_REGEXP) {
+ if (paren && c == paren) {
+ ++*nest;
+ }
+ else if (c == term) {
+ if (!nest || !*nest) {
+ pushback(p, c);
+ break;
+ }
+ --*nest;
+ }
+ else if ((func & STR_FUNC_EXPAND) && c == '#' && p->lex.pcur < p->lex.pend) {
+ unsigned char c2 = *p->lex.pcur;
+ if (c2 == '$' || c2 == '@' || c2 == '{') {
+ pushback(p, c);
+ break;
+ }
+ }
+ else if (c == '\\') {
+ c = nextc(p);
+ switch (c) {
+ case '\n':
+ if (func & STR_FUNC_QWORDS) break;
+ if (func & STR_FUNC_EXPAND) {
+ if (!(func & STR_FUNC_INDENT) || (p->heredoc_indent < 0))
+ continue;
+ if (c == term) {
+ c = '\\';
+ goto terminate;
+ }
+ }
+ tokadd(p, '\\');
+ break;
+
+ case '\\':
+ if (func & STR_FUNC_ESCAPE) tokadd(p, c);
+ break;
+
+ case 'u':
+ if ((func & STR_FUNC_EXPAND) == 0) {
+ tokadd(p, '\\');
+ break;
+ }
+ tokadd_utf8(p, enc, term,
+ func & STR_FUNC_SYMBOL,
+ func & STR_FUNC_REGEXP);
+ continue;
+
+ default:
+ if (c == -1) return -1;
+ if (!ISASCII(c)) {
+ if ((func & STR_FUNC_EXPAND) == 0) tokadd(p, '\\');
+ goto non_ascii;
+ }
+ if (func & STR_FUNC_REGEXP) {
switch (c) {
case 'c':
case 'C':
case 'M': {
pushback(p, c);
- c = read_escape(p, 0);
+ c = read_escape(p, 0, enc);
- char *t = tokspace(p, rb_strlen_lit("\\x00"));
- *t++ = '\\';
- *t++ = 'x';
- *t++ = nibble_char_upper(c >> 4);
- *t++ = nibble_char_upper(c);
+ int i;
+ char escbuf[5];
+ snprintf(escbuf, sizeof(escbuf), "\\x%02X", c);
+ for (i = 0; i < 4; i++) {
+ tokadd(p, escbuf[i]);
+ }
continue;
}
}
- if (c == term && !simple_re_meta(c)) {
- tokadd(p, c);
- continue;
- }
- pushback(p, c);
- if ((c = tokadd_escape(p)) < 0)
- return -1;
- if (*enc && *enc != *encp) {
- mixed_escape(p->lex.ptok+2, *enc, *encp);
- }
- continue;
- }
- else if (func & STR_FUNC_EXPAND) {
- pushback(p, c);
- if (func & STR_FUNC_ESCAPE) tokadd(p, '\\');
- c = read_escape(p, 0);
- }
- else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
- /* ignore backslashed spaces in %w */
- }
- else if (c != term && !(paren && c == paren)) {
- tokadd(p, '\\');
- pushback(p, c);
- continue;
- }
- }
- }
- else if (!parser_isascii(p)) {
- non_ascii:
- if (!*enc) {
- *enc = *encp;
- }
- else if (*enc != *encp) {
- mixed_error(*enc, *encp);
- continue;
- }
- if (tokadd_mbchar(p, c) == -1) return -1;
- continue;
- }
- else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
- pushback(p, c);
- break;
- }
+ if (c == term && !simple_re_meta(c)) {
+ tokadd(p, c);
+ continue;
+ }
+ pushback(p, c);
+ if ((c = tokadd_escape(p, enc)) < 0)
+ return -1;
+ if (*enc && *enc != *encp) {
+ mixed_escape(p->lex.ptok+2, *enc, *encp);
+ }
+ continue;
+ }
+ else if (func & STR_FUNC_EXPAND) {
+ pushback(p, c);
+ if (func & STR_FUNC_ESCAPE) tokadd(p, '\\');
+ c = read_escape(p, 0, enc);
+ }
+ else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
+ /* ignore backslashed spaces in %w */
+ }
+ else if (c != term && !(paren && c == paren)) {
+ tokadd(p, '\\');
+ pushback(p, c);
+ continue;
+ }
+ }
+ }
+ else if (!parser_isascii(p)) {
+ non_ascii:
+ if (!*enc) {
+ *enc = *encp;
+ }
+ else if (*enc != *encp) {
+ mixed_error(*enc, *encp);
+ continue;
+ }
+ if (tokadd_mbchar(p, c) == -1) return -1;
+ continue;
+ }
+ else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
+ pushback(p, c);
+ break;
+ }
if (c & 0x80) {
- if (!*enc) {
- *enc = *encp;
- }
- else if (*enc != *encp) {
- mixed_error(*enc, *encp);
- continue;
- }
- }
- tokadd(p, c);
+ if (!*enc) {
+ *enc = *encp;
+ }
+ else if (*enc != *encp) {
+ mixed_error(*enc, *encp);
+ continue;
+ }
+ }
+ tokadd(p, c);
#ifdef RIPPER
- top_of_line = (c == '\n');
+ top_of_line = (c == '\n');
#endif
}
terminate:
@@ -8414,27 +7831,35 @@ tokadd_string(struct parser_params *p,
return c;
}
-#define NEW_STRTERM(func, term, paren) new_strterm(p, func, term, paren)
+static inline rb_strterm_t *
+new_strterm(VALUE v1, VALUE v2, VALUE v3, VALUE v0)
+{
+ return (rb_strterm_t*)rb_imemo_new(imemo_parser_strterm, v1, v2, v3, v0);
+}
+
+/* imemo_parser_strterm for literal */
+#define NEW_STRTERM(func, term, paren) \
+ new_strterm((VALUE)(func), (VALUE)(paren), (VALUE)(term), 0)
#ifdef RIPPER
static void
flush_string_content(struct parser_params *p, rb_encoding *enc)
{
VALUE content = yylval.val;
- if (!ripper_is_node_yylval(p, content))
- content = ripper_new_yylval(p, 0, 0, content);
+ if (!ripper_is_node_yylval(content))
+ content = ripper_new_yylval(p, 0, 0, content);
if (has_delayed_token(p)) {
- ptrdiff_t len = p->lex.pcur - p->lex.ptok;
- if (len > 0) {
- rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
- }
- dispatch_delayed_token(p, tSTRING_CONTENT);
- p->lex.ptok = p->lex.pcur;
- RNODE_RIPPER(content)->nd_rval = yylval.val;
+ ptrdiff_t len = p->lex.pcur - p->lex.ptok;
+ if (len > 0) {
+ rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
+ }
+ dispatch_delayed_token(p, tSTRING_CONTENT);
+ p->lex.ptok = p->lex.pcur;
+ RNODE(content)->nd_rval = yylval.val;
}
dispatch_scan_event(p, tSTRING_CONTENT);
if (yylval.val != content)
- RNODE_RIPPER(content)->nd_rval = yylval.val;
+ RNODE(content)->nd_rval = yylval.val;
yylval.val = content;
}
#else
@@ -8442,32 +7867,32 @@ static void
flush_string_content(struct parser_params *p, rb_encoding *enc)
{
if (has_delayed_token(p)) {
- ptrdiff_t len = p->lex.pcur - p->lex.ptok;
- if (len > 0) {
- rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
- p->delayed.end_line = p->ruby_sourceline;
- p->delayed.end_col = rb_long2int(p->lex.pcur - p->lex.pbeg);
- }
- dispatch_delayed_token(p, tSTRING_CONTENT);
- p->lex.ptok = p->lex.pcur;
+ ptrdiff_t len = p->lex.pcur - p->lex.ptok;
+ if (len > 0) {
+ rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
+ p->delayed.end_line = p->ruby_sourceline;
+ p->delayed.end_col = rb_long2int(p->lex.pcur - p->lex.pbeg);
+ }
+ dispatch_delayed_token(p, tSTRING_CONTENT);
+ p->lex.ptok = p->lex.pcur;
}
dispatch_scan_event(p, tSTRING_CONTENT);
}
#endif
-RUBY_FUNC_EXPORTED const uint_least32_t ruby_global_name_punct_bits[(0x7e - 0x20 + 31) / 32];
+RUBY_FUNC_EXPORTED const unsigned int ruby_global_name_punct_bits[(0x7e - 0x20 + 31) / 32];
/* this can be shared with ripper, since it's independent from struct
* parser_params. */
#ifndef RIPPER
#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
#define SPECIAL_PUNCT(idx) ( \
- BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
- BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
- BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
- BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
- BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
- BIT('0', idx))
-const uint_least32_t ruby_global_name_punct_bits[] = {
+ BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
+ BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
+ BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
+ BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
+ BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
+ BIT('0', idx))
+const unsigned int ruby_global_name_punct_bits[] = {
SPECIAL_PUNCT(0),
SPECIAL_PUNCT(1),
SPECIAL_PUNCT(2),
@@ -8482,33 +7907,33 @@ parser_peek_variable_name(struct parser_params *p)
int c;
const char *ptr = p->lex.pcur;
- if (lex_eol_ptr_n_p(p, ptr, 1)) return 0;
+ if (ptr + 1 >= p->lex.pend) return 0;
c = *ptr++;
switch (c) {
case '$':
- if ((c = *ptr) == '-') {
- if (lex_eol_ptr_p(p, ++ptr)) return 0;
- c = *ptr;
- }
- else if (is_global_name_punct(c) || ISDIGIT(c)) {
- return tSTRING_DVAR;
- }
- break;
+ if ((c = *ptr) == '-') {
+ if (++ptr >= p->lex.pend) return 0;
+ c = *ptr;
+ }
+ else if (is_global_name_punct(c) || ISDIGIT(c)) {
+ return tSTRING_DVAR;
+ }
+ break;
case '@':
- if ((c = *ptr) == '@') {
- if (lex_eol_ptr_p(p, ++ptr)) return 0;
- c = *ptr;
- }
- break;
+ if ((c = *ptr) == '@') {
+ if (++ptr >= p->lex.pend) return 0;
+ c = *ptr;
+ }
+ break;
case '{':
- p->lex.pcur = ptr;
- p->command_start = TRUE;
- return tSTRING_DBEG;
+ p->lex.pcur = ptr;
+ p->command_start = TRUE;
+ return tSTRING_DBEG;
default:
- return 0;
+ return 0;
}
if (!ISASCII(c) || c == '_' || ISALPHA(c))
- return tSTRING_DVAR;
+ return tSTRING_DVAR;
return 0;
}
@@ -8517,26 +7942,25 @@ parser_peek_variable_name(struct parser_params *p)
#define IS_BEG() (IS_lex_state(EXPR_BEG_ANY) || IS_lex_state_all(EXPR_ARG|EXPR_LABELED))
#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c))
#define IS_LABEL_POSSIBLE() (\
- (IS_lex_state(EXPR_LABEL|EXPR_ENDFN) && !cmd_state) || \
- IS_ARG())
+ (IS_lex_state(EXPR_LABEL|EXPR_ENDFN) && !cmd_state) || \
+ IS_ARG())
#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
#define IS_AFTER_OPERATOR() IS_lex_state(EXPR_FNAME | EXPR_DOT)
static inline enum yytokentype
parser_string_term(struct parser_params *p, int func)
{
- xfree(p->lex.strterm);
p->lex.strterm = 0;
if (func & STR_FUNC_REGEXP) {
- set_yylval_num(regx_options(p));
- dispatch_scan_event(p, tREGEXP_END);
- SET_LEX_STATE(EXPR_END);
- return tREGEXP_END;
+ set_yylval_num(regx_options(p));
+ dispatch_scan_event(p, tREGEXP_END);
+ SET_LEX_STATE(EXPR_END);
+ return tREGEXP_END;
}
if ((func & STR_FUNC_LABEL) && IS_LABEL_SUFFIX(0)) {
- nextc(p);
- SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
- return tLABEL_END;
+ nextc(p);
+ SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
+ return tLABEL_END;
}
SET_LEX_STATE(EXPR_END);
return tSTRING_END;
@@ -8545,76 +7969,74 @@ parser_string_term(struct parser_params *p, int func)
static enum yytokentype
parse_string(struct parser_params *p, rb_strterm_literal_t *quote)
{
- int func = quote->func;
- int term = quote->term;
- int paren = quote->paren;
+ int func = (int)quote->u1.func;
+ int term = (int)quote->u3.term;
+ int paren = (int)quote->u2.paren;
int c, space = 0;
rb_encoding *enc = p->enc;
rb_encoding *base_enc = 0;
VALUE lit;
if (func & STR_FUNC_TERM) {
- if (func & STR_FUNC_QWORDS) nextc(p); /* delayed term */
- SET_LEX_STATE(EXPR_END);
- xfree(p->lex.strterm);
- p->lex.strterm = 0;
- return func & STR_FUNC_REGEXP ? tREGEXP_END : tSTRING_END;
+ if (func & STR_FUNC_QWORDS) nextc(p); /* delayed term */
+ SET_LEX_STATE(EXPR_END);
+ p->lex.strterm = 0;
+ return func & STR_FUNC_REGEXP ? tREGEXP_END : tSTRING_END;
}
c = nextc(p);
if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
- while (c != '\n' && ISSPACE(c = nextc(p)));
- space = 1;
+ do {c = nextc(p);} while (ISSPACE(c));
+ space = 1;
}
if (func & STR_FUNC_LIST) {
- quote->func &= ~STR_FUNC_LIST;
- space = 1;
- }
- if (c == term && !quote->nest) {
- if (func & STR_FUNC_QWORDS) {
- quote->func |= STR_FUNC_TERM;
- pushback(p, c); /* dispatch the term at tSTRING_END */
- add_delayed_token(p, p->lex.ptok, p->lex.pcur, __LINE__);
- return ' ';
- }
- return parser_string_term(p, func);
+ quote->u1.func &= ~STR_FUNC_LIST;
+ space = 1;
+ }
+ if (c == term && !quote->u0.nest) {
+ if (func & STR_FUNC_QWORDS) {
+ quote->u1.func |= STR_FUNC_TERM;
+ pushback(p, c); /* dispatch the term at tSTRING_END */
+ add_delayed_token(p, p->lex.ptok, p->lex.pcur, __LINE__);
+ return ' ';
+ }
+ return parser_string_term(p, func);
}
if (space) {
- if (!ISSPACE(c)) pushback(p, c);
- add_delayed_token(p, p->lex.ptok, p->lex.pcur, __LINE__);
- return ' ';
+ pushback(p, c);
+ add_delayed_token(p, p->lex.ptok, p->lex.pcur, __LINE__);
+ return ' ';
}
newtok(p);
if ((func & STR_FUNC_EXPAND) && c == '#') {
- int t = parser_peek_variable_name(p);
- if (t) return t;
- tokadd(p, '#');
- c = nextc(p);
+ int t = parser_peek_variable_name(p);
+ if (t) return t;
+ tokadd(p, '#');
+ c = nextc(p);
}
pushback(p, c);
- if (tokadd_string(p, func, term, paren, &quote->nest,
- &enc, &base_enc) == -1) {
- if (p->eofp) {
+ if (tokadd_string(p, func, term, paren, &quote->u0.nest,
+ &enc, &base_enc) == -1) {
+ if (p->eofp) {
#ifndef RIPPER
# define unterminated_literal(mesg) yyerror0(mesg)
#else
# define unterminated_literal(mesg) compile_error(p, mesg)
#endif
- literal_flush(p, p->lex.pcur);
- if (func & STR_FUNC_QWORDS) {
- /* no content to add, bailing out here */
- unterminated_literal("unterminated list meets end of file");
- xfree(p->lex.strterm);
- p->lex.strterm = 0;
- return tSTRING_END;
- }
- if (func & STR_FUNC_REGEXP) {
- unterminated_literal("unterminated regexp meets end of file");
- }
- else {
- unterminated_literal("unterminated string meets end of file");
- }
- quote->func |= STR_FUNC_TERM;
- }
+ literal_flush(p, p->lex.pcur);
+ if (func & STR_FUNC_QWORDS) {
+ /* no content to add, bailing out here */
+ unterminated_literal("unterminated list meets end of file");
+ p->lex.strterm = 0;
+ return tSTRING_END;
+ }
+ if (func & STR_FUNC_REGEXP) {
+ unterminated_literal("unterminated regexp meets end of file");
+ }
+ else {
+ unterminated_literal("unterminated string meets end of file");
+ }
+ quote->u1.func |= STR_FUNC_TERM;
+ }
}
tokfix(p);
@@ -8638,71 +8060,70 @@ heredoc_identifier(struct parser_params *p)
int indent = 0;
if (c == '-') {
- c = nextc(p);
- func = STR_FUNC_INDENT;
- offset++;
+ c = nextc(p);
+ func = STR_FUNC_INDENT;
+ offset++;
}
else if (c == '~') {
- c = nextc(p);
- func = STR_FUNC_INDENT;
- offset++;
- indent = INT_MAX;
+ c = nextc(p);
+ func = STR_FUNC_INDENT;
+ offset++;
+ indent = INT_MAX;
}
switch (c) {
case '\'':
- func |= str_squote; goto quoted;
+ func |= str_squote; goto quoted;
case '"':
- func |= str_dquote; goto quoted;
+ func |= str_dquote; goto quoted;
case '`':
- token = tXSTRING_BEG;
- func |= str_xquote; goto quoted;
+ token = tXSTRING_BEG;
+ func |= str_xquote; goto quoted;
quoted:
- quote++;
- offset++;
- term = c;
- len = 0;
- while ((c = nextc(p)) != term) {
- if (c == -1 || c == '\r' || c == '\n') {
- yyerror0("unterminated here document identifier");
- return -1;
- }
- }
- break;
+ quote++;
+ offset++;
+ term = c;
+ len = 0;
+ while ((c = nextc(p)) != term) {
+ if (c == -1 || c == '\r' || c == '\n') {
+ yyerror0("unterminated here document identifier");
+ return -1;
+ }
+ }
+ break;
default:
- if (!parser_is_identchar(p)) {
- pushback(p, c);
- if (func & STR_FUNC_INDENT) {
- pushback(p, indent > 0 ? '~' : '-');
- }
- return 0;
- }
- func |= str_dquote;
- do {
- int n = parser_precise_mbclen(p, p->lex.pcur-1);
- if (n < 0) return 0;
- p->lex.pcur += --n;
- } while ((c = nextc(p)) != -1 && parser_is_identchar(p));
- pushback(p, c);
- break;
+ if (!parser_is_identchar(p)) {
+ pushback(p, c);
+ if (func & STR_FUNC_INDENT) {
+ pushback(p, indent > 0 ? '~' : '-');
+ }
+ return 0;
+ }
+ func |= str_dquote;
+ do {
+ int n = parser_precise_mbclen(p, p->lex.pcur-1);
+ if (n < 0) return 0;
+ p->lex.pcur += --n;
+ } while ((c = nextc(p)) != -1 && parser_is_identchar(p));
+ pushback(p, c);
+ break;
}
len = p->lex.pcur - (p->lex.pbeg + offset) - quote;
if ((unsigned long)len >= HERETERM_LENGTH_MAX)
- yyerror0("too long here document identifier");
+ yyerror0("too long here document identifier");
dispatch_scan_event(p, tHEREDOC_BEG);
lex_goto_eol(p);
- p->lex.strterm = new_heredoc(p);
+ p->lex.strterm = new_strterm(0, 0, 0, p->lex.lastline);
+ p->lex.strterm->flags |= STRTERM_HEREDOC;
rb_strterm_heredoc_t *here = &p->lex.strterm->u.heredoc;
here->offset = offset;
here->sourceline = p->ruby_sourceline;
- here->length = (unsigned)len;
+ here->length = (int)len;
here->quote = quote;
here->func = func;
- here->lastline = p->lex.lastline;
- rb_ast_add_mark_object(p->ast, p->lex.lastline);
token_flush(p);
p->heredoc_indent = indent;
@@ -8714,7 +8135,6 @@ static void
heredoc_restore(struct parser_params *p, rb_strterm_heredoc_t *here)
{
VALUE line;
- rb_strterm_t *term = p->lex.strterm;
p->lex.strterm = 0;
line = here->lastline;
@@ -8727,12 +8147,10 @@ heredoc_restore(struct parser_params *p, rb_strterm_heredoc_t *here)
p->ruby_sourceline = (int)here->sourceline;
if (p->eofp) p->lex.nextline = Qnil;
p->eofp = 0;
- xfree(term);
- rb_ast_delete_mark_object(p->ast, line);
}
static int
-dedent_string(struct parser_params *p, VALUE string, int width)
+dedent_string(VALUE string, int width)
{
char *str;
long len;
@@ -8740,23 +8158,23 @@ dedent_string(struct parser_params *p, VALUE string, int width)
RSTRING_GETMEM(string, str, len);
for (i = 0; i < len && col < width; i++) {
- if (str[i] == ' ') {
- col++;
- }
- else if (str[i] == '\t') {
- int n = TAB_WIDTH * (col / TAB_WIDTH + 1);
- if (n > width) break;
- col = n;
- }
- else {
- break;
- }
+ if (str[i] == ' ') {
+ col++;
+ }
+ else if (str[i] == '\t') {
+ int n = TAB_WIDTH * (col / TAB_WIDTH + 1);
+ if (n > width) break;
+ col = n;
+ }
+ else {
+ break;
+ }
}
if (!i) return 0;
rb_str_modify(string);
str = RSTRING_PTR(string);
if (RSTRING_LEN(string) != len)
- rb_fatal("literal string changed: %+"PRIsVALUE, string);
+ rb_fatal("literal string changed: %+"PRIsVALUE, string);
MEMMOVE(str, str + i, char, len - i);
rb_str_set_len(string, len - i);
return i;
@@ -8775,42 +8193,42 @@ heredoc_dedent(struct parser_params *p, NODE *root)
if (!root) return root;
prev_node = node = str_node = root;
- if (nd_type_p(root, NODE_LIST)) str_node = RNODE_LIST(root)->nd_head;
+ if (nd_type_p(root, NODE_LIST)) str_node = root->nd_head;
while (str_node) {
- VALUE lit = RNODE_LIT(str_node)->nd_lit;
- if (nd_fl_newline(str_node)) {
- dedent_string(p, lit, indent);
- }
- if (!prev_lit) {
- prev_lit = lit;
- }
- else if (!literal_concat0(p, prev_lit, lit)) {
- return 0;
- }
- else {
- NODE *end = RNODE_LIST(node)->as.nd_end;
- node = RNODE_LIST(prev_node)->nd_next = RNODE_LIST(node)->nd_next;
- if (!node) {
- if (nd_type_p(prev_node, NODE_DSTR))
- nd_set_type(prev_node, NODE_STR);
- break;
- }
- RNODE_LIST(node)->as.nd_end = end;
- goto next_str;
- }
-
- str_node = 0;
- while ((nd_type_p(node, NODE_LIST) || nd_type_p(node, NODE_DSTR)) && (node = RNODE_LIST(prev_node = node)->nd_next) != 0) {
- next_str:
- if (!nd_type_p(node, NODE_LIST)) break;
- if ((str_node = RNODE_LIST(node)->nd_head) != 0) {
- enum node_type type = nd_type(str_node);
- if (type == NODE_STR || type == NODE_DSTR) break;
- prev_lit = 0;
- str_node = 0;
- }
- }
+ VALUE lit = str_node->nd_lit;
+ if (str_node->flags & NODE_FL_NEWLINE) {
+ dedent_string(lit, indent);
+ }
+ if (!prev_lit) {
+ prev_lit = lit;
+ }
+ else if (!literal_concat0(p, prev_lit, lit)) {
+ return 0;
+ }
+ else {
+ NODE *end = node->nd_end;
+ node = prev_node->nd_next = node->nd_next;
+ if (!node) {
+ if (nd_type_p(prev_node, NODE_DSTR))
+ nd_set_type(prev_node, NODE_STR);
+ break;
+ }
+ node->nd_end = end;
+ goto next_str;
+ }
+
+ str_node = 0;
+ while ((node = (prev_node = node)->nd_next) != 0) {
+ next_str:
+ if (!nd_type_p(node, NODE_LIST)) break;
+ if ((str_node = node->nd_head) != 0) {
+ enum node_type type = nd_type(str_node);
+ if (type == NODE_STR || type == NODE_DSTR) break;
+ prev_lit = 0;
+ str_node = 0;
+ }
+ }
}
return root;
}
@@ -8825,31 +8243,51 @@ heredoc_dedent(struct parser_params *p, VALUE array)
dispatch2(heredoc_dedent, array, INT2NUM(indent));
return array;
}
+
+/*
+ * call-seq:
+ * Ripper.dedent_string(input, width) -> Integer
+ *
+ * USE OF RIPPER LIBRARY ONLY.
+ *
+ * Strips up to +width+ leading whitespaces from +input+,
+ * and returns the stripped column width.
+ */
+static VALUE
+parser_dedent_string(VALUE self, VALUE input, VALUE width)
+{
+ int wid, col;
+
+ StringValue(input);
+ wid = NUM2UINT(width);
+ col = dedent_string(input, wid);
+ return INT2NUM(col);
+}
#endif
static int
whole_match_p(struct parser_params *p, const char *eos, long len, int indent)
{
- const char *beg = p->lex.pbeg;
- const char *ptr = p->lex.pend;
+ const char *ptr = p->lex.pbeg;
+ long n;
- if (ptr - beg < len) return FALSE;
- if (ptr > beg && ptr[-1] == '\n') {
- if (--ptr > beg && ptr[-1] == '\r') --ptr;
- if (ptr - beg < len) return FALSE;
- }
- if (strncmp(eos, ptr -= len, len)) return FALSE;
if (indent) {
- while (beg < ptr && ISSPACE(*beg)) beg++;
+ while (*ptr && ISSPACE(*ptr)) ptr++;
}
- return beg == ptr;
+ n = p->lex.pend - (ptr + len);
+ if (n < 0) return FALSE;
+ if (n > 0 && ptr[len] != '\n') {
+ if (ptr[len] != '\r') return FALSE;
+ if (n <= 1 || ptr[len+1] != '\n') return FALSE;
+ }
+ return strncmp(eos, ptr, len) == 0;
}
static int
word_match_p(struct parser_params *p, const char *word, long len)
{
if (strncmp(p->lex.pcur, word, len)) return 0;
- if (lex_eol_n_p(p, len)) return 1;
+ if (p->lex.pcur + len == p->lex.pend) return 1;
int c = (unsigned char)p->lex.pcur[len];
if (ISSPACE(c)) return 1;
switch (c) {
@@ -8869,36 +8307,36 @@ number_literal_suffix(struct parser_params *p, int mask)
const char *lastp = p->lex.pcur;
while ((c = nextc(p)) != -1) {
- if ((mask & NUM_SUFFIX_I) && c == 'i') {
- result |= (mask & NUM_SUFFIX_I);
- mask &= ~NUM_SUFFIX_I;
- /* r after i, rational of complex is disallowed */
- mask &= ~NUM_SUFFIX_R;
- continue;
- }
- if ((mask & NUM_SUFFIX_R) && c == 'r') {
- result |= (mask & NUM_SUFFIX_R);
- mask &= ~NUM_SUFFIX_R;
- continue;
- }
- if (!ISASCII(c) || ISALPHA(c) || c == '_') {
- p->lex.pcur = lastp;
- literal_flush(p, p->lex.pcur);
- return 0;
- }
- pushback(p, c);
- break;
+ if ((mask & NUM_SUFFIX_I) && c == 'i') {
+ result |= (mask & NUM_SUFFIX_I);
+ mask &= ~NUM_SUFFIX_I;
+ /* r after i, rational of complex is disallowed */
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if ((mask & NUM_SUFFIX_R) && c == 'r') {
+ result |= (mask & NUM_SUFFIX_R);
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if (!ISASCII(c) || ISALPHA(c) || c == '_') {
+ p->lex.pcur = lastp;
+ literal_flush(p, p->lex.pcur);
+ return 0;
+ }
+ pushback(p, c);
+ break;
}
return result;
}
static enum yytokentype
set_number_literal(struct parser_params *p, VALUE v,
- enum yytokentype type, int suffix)
+ enum yytokentype type, int suffix)
{
if (suffix & NUM_SUFFIX_I) {
- v = rb_complex_raw(INT2FIX(0), v);
- type = tIMAGINARY;
+ v = rb_complex_raw(INT2FIX(0), v);
+ type = tIMAGINARY;
}
set_yylval_literal(v);
SET_LEX_STATE(EXPR_END);
@@ -8910,8 +8348,8 @@ set_integer_literal(struct parser_params *p, VALUE v, int suffix)
{
enum yytokentype type = tINTEGER;
if (suffix & NUM_SUFFIX_R) {
- v = rb_rational_raw1(v);
- type = tRATIONAL;
+ v = rb_rational_raw1(v);
+ type = tRATIONAL;
}
return set_number_literal(p, v, type, suffix);
}
@@ -8922,7 +8360,7 @@ dispatch_heredoc_end(struct parser_params *p)
{
VALUE str;
if (has_delayed_token(p))
- dispatch_delayed_token(p, tSTRING_CONTENT);
+ dispatch_delayed_token(p, tSTRING_CONTENT);
str = STR_NEW(p->lex.ptok, p->lex.pend - p->lex.ptok);
ripper_dispatch1(p, ripper_token2eventid(tHEREDOC_END), str);
RUBY_SET_YYLLOC_FROM_STRTERM_HEREDOC(*p->yylloc);
@@ -8936,12 +8374,12 @@ static void
parser_dispatch_heredoc_end(struct parser_params *p, int line)
{
if (has_delayed_token(p))
- dispatch_delayed_token(p, tSTRING_CONTENT);
+ dispatch_delayed_token(p, tSTRING_CONTENT);
if (p->keep_tokens) {
- VALUE str = STR_NEW(p->lex.ptok, p->lex.pend - p->lex.ptok);
- RUBY_SET_YYLLOC_OF_HEREDOC_END(*p->yylloc);
- parser_append_tokens(p, str, tHEREDOC_END, line);
+ VALUE str = STR_NEW(p->lex.ptok, p->lex.pend - p->lex.ptok);
+ RUBY_SET_YYLLOC_OF_HEREDOC_END(*p->yylloc);
+ parser_append_tokens(p, str, tHEREDOC_END, line);
}
RUBY_SET_YYLLOC_FROM_STRTERM_HEREDOC(*p->yylloc);
@@ -8968,148 +8406,150 @@ here_document(struct parser_params *p, rb_strterm_heredoc_t *here)
if ((c = nextc(p)) == -1) {
error:
#ifdef RIPPER
- if (!has_delayed_token(p)) {
- dispatch_scan_event(p, tSTRING_CONTENT);
- }
- else {
- if ((len = p->lex.pcur - p->lex.ptok) > 0) {
- if (!(func & STR_FUNC_REGEXP) && rb_enc_asciicompat(enc)) {
- int cr = ENC_CODERANGE_UNKNOWN;
- rb_str_coderange_scan_restartable(p->lex.ptok, p->lex.pcur, enc, &cr);
- if (cr != ENC_CODERANGE_7BIT &&
- rb_is_usascii_enc(p->enc) &&
- enc != rb_utf8_encoding()) {
- enc = rb_ascii8bit_encoding();
- }
- }
- rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
- }
- dispatch_delayed_token(p, tSTRING_CONTENT);
- }
- lex_goto_eol(p);
+ if (!has_delayed_token(p)) {
+ dispatch_scan_event(p, tSTRING_CONTENT);
+ }
+ else {
+ if ((len = p->lex.pcur - p->lex.ptok) > 0) {
+ if (!(func & STR_FUNC_REGEXP) && rb_enc_asciicompat(enc)) {
+ int cr = ENC_CODERANGE_UNKNOWN;
+ rb_str_coderange_scan_restartable(p->lex.ptok, p->lex.pcur, enc, &cr);
+ if (cr != ENC_CODERANGE_7BIT &&
+ rb_is_usascii_enc(p->enc) &&
+ enc != rb_utf8_encoding()) {
+ enc = rb_ascii8bit_encoding();
+ }
+ }
+ rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
+ }
+ dispatch_delayed_token(p, tSTRING_CONTENT);
+ }
+ lex_goto_eol(p);
#endif
- heredoc_restore(p, &p->lex.strterm->u.heredoc);
- compile_error(p, "can't find string \"%.*s\" anywhere before EOF",
- (int)len, eos);
- token_flush(p);
- SET_LEX_STATE(EXPR_END);
- return tSTRING_END;
+ heredoc_restore(p, &p->lex.strterm->u.heredoc);
+ compile_error(p, "can't find string \"%.*s\" anywhere before EOF",
+ (int)len, eos);
+ token_flush(p);
+ p->lex.strterm = 0;
+ SET_LEX_STATE(EXPR_END);
+ return tSTRING_END;
}
bol = was_bol(p);
if (!bol) {
- /* not beginning of line, cannot be the terminator */
+ /* not beginning of line, cannot be the terminator */
}
else if (p->heredoc_line_indent == -1) {
- /* `heredoc_line_indent == -1` means
- * - "after an interpolation in the same line", or
- * - "in a continuing line"
- */
- p->heredoc_line_indent = 0;
+ /* `heredoc_line_indent == -1` means
+ * - "after an interpolation in the same line", or
+ * - "in a continuing line"
+ */
+ p->heredoc_line_indent = 0;
}
else if (whole_match_p(p, eos, len, indent)) {
- dispatch_heredoc_end(p);
+ dispatch_heredoc_end(p);
restore:
- heredoc_restore(p, &p->lex.strterm->u.heredoc);
- token_flush(p);
- SET_LEX_STATE(EXPR_END);
- return tSTRING_END;
+ heredoc_restore(p, &p->lex.strterm->u.heredoc);
+ token_flush(p);
+ p->lex.strterm = 0;
+ SET_LEX_STATE(EXPR_END);
+ return tSTRING_END;
}
if (!(func & STR_FUNC_EXPAND)) {
- do {
- ptr = RSTRING_PTR(p->lex.lastline);
- ptr_end = p->lex.pend;
- if (ptr_end > ptr) {
- switch (ptr_end[-1]) {
- case '\n':
- if (--ptr_end == ptr || ptr_end[-1] != '\r') {
- ptr_end++;
- break;
- }
- case '\r':
- --ptr_end;
- }
- }
-
- if (p->heredoc_indent > 0) {
- long i = 0;
- while (ptr + i < ptr_end && parser_update_heredoc_indent(p, ptr[i]))
- i++;
- p->heredoc_line_indent = 0;
- }
-
- if (str)
- rb_str_cat(str, ptr, ptr_end - ptr);
- else
- str = STR_NEW(ptr, ptr_end - ptr);
- if (!lex_eol_ptr_p(p, ptr_end)) rb_str_cat(str, "\n", 1);
- lex_goto_eol(p);
- if (p->heredoc_indent > 0) {
- goto flush_str;
- }
- if (nextc(p) == -1) {
- if (str) {
- str = 0;
- }
- goto error;
- }
- } while (!whole_match_p(p, eos, len, indent));
+ do {
+ ptr = RSTRING_PTR(p->lex.lastline);
+ ptr_end = p->lex.pend;
+ if (ptr_end > ptr) {
+ switch (ptr_end[-1]) {
+ case '\n':
+ if (--ptr_end == ptr || ptr_end[-1] != '\r') {
+ ptr_end++;
+ break;
+ }
+ case '\r':
+ --ptr_end;
+ }
+ }
+
+ if (p->heredoc_indent > 0) {
+ long i = 0;
+ while (ptr + i < ptr_end && parser_update_heredoc_indent(p, ptr[i]))
+ i++;
+ p->heredoc_line_indent = 0;
+ }
+
+ if (str)
+ rb_str_cat(str, ptr, ptr_end - ptr);
+ else
+ str = STR_NEW(ptr, ptr_end - ptr);
+ if (ptr_end < p->lex.pend) rb_str_cat(str, "\n", 1);
+ lex_goto_eol(p);
+ if (p->heredoc_indent > 0) {
+ goto flush_str;
+ }
+ if (nextc(p) == -1) {
+ if (str) {
+ str = 0;
+ }
+ goto error;
+ }
+ } while (!whole_match_p(p, eos, len, indent));
}
else {
- /* int mb = ENC_CODERANGE_7BIT, *mbp = &mb;*/
- newtok(p);
- if (c == '#') {
- int t = parser_peek_variable_name(p);
- if (p->heredoc_line_indent != -1) {
- if (p->heredoc_indent > p->heredoc_line_indent) {
- p->heredoc_indent = p->heredoc_line_indent;
- }
- p->heredoc_line_indent = -1;
- }
- if (t) return t;
- tokadd(p, '#');
- c = nextc(p);
- }
- do {
- pushback(p, c);
- enc = p->enc;
- if ((c = tokadd_string(p, func, '\n', 0, NULL, &enc, &base_enc)) == -1) {
- if (p->eofp) goto error;
- goto restore;
- }
- if (c != '\n') {
- if (c == '\\') p->heredoc_line_indent = -1;
- flush:
- str = STR_NEW3(tok(p), toklen(p), enc, func);
- flush_str:
- set_yylval_str(str);
+ /* int mb = ENC_CODERANGE_7BIT, *mbp = &mb;*/
+ newtok(p);
+ if (c == '#') {
+ int t = parser_peek_variable_name(p);
+ if (p->heredoc_line_indent != -1) {
+ if (p->heredoc_indent > p->heredoc_line_indent) {
+ p->heredoc_indent = p->heredoc_line_indent;
+ }
+ p->heredoc_line_indent = -1;
+ }
+ if (t) return t;
+ tokadd(p, '#');
+ c = nextc(p);
+ }
+ do {
+ pushback(p, c);
+ enc = p->enc;
+ if ((c = tokadd_string(p, func, '\n', 0, NULL, &enc, &base_enc)) == -1) {
+ if (p->eofp) goto error;
+ goto restore;
+ }
+ if (c != '\n') {
+ if (c == '\\') p->heredoc_line_indent = -1;
+ flush:
+ str = STR_NEW3(tok(p), toklen(p), enc, func);
+ flush_str:
+ set_yylval_str(str);
#ifndef RIPPER
- if (bol) nd_set_fl_newline(yylval.node);
+ if (bol) yylval.node->flags |= NODE_FL_NEWLINE;
#endif
- flush_string_content(p, enc);
- return tSTRING_CONTENT;
- }
- tokadd(p, nextc(p));
- if (p->heredoc_indent > 0) {
- lex_goto_eol(p);
- goto flush;
- }
- /* if (mbp && mb == ENC_CODERANGE_UNKNOWN) mbp = 0;*/
- if ((c = nextc(p)) == -1) goto error;
- } while (!whole_match_p(p, eos, len, indent));
- str = STR_NEW3(tok(p), toklen(p), enc, func);
+ flush_string_content(p, enc);
+ return tSTRING_CONTENT;
+ }
+ tokadd(p, nextc(p));
+ if (p->heredoc_indent > 0) {
+ lex_goto_eol(p);
+ goto flush;
+ }
+ /* if (mbp && mb == ENC_CODERANGE_UNKNOWN) mbp = 0;*/
+ if ((c = nextc(p)) == -1) goto error;
+ } while (!whole_match_p(p, eos, len, indent));
+ str = STR_NEW3(tok(p), toklen(p), enc, func);
}
dispatch_heredoc_end(p);
#ifdef RIPPER
str = ripper_new_yylval(p, ripper_token2eventid(tSTRING_CONTENT),
- yylval.val, str);
+ yylval.val, str);
#endif
heredoc_restore(p, &p->lex.strterm->u.heredoc);
token_flush(p);
p->lex.strterm = NEW_STRTERM(func | STR_FUNC_TERM, 0, 0);
set_yylval_str(str);
#ifndef RIPPER
- if (bol) nd_set_fl_newline(yylval.node);
+ if (bol) yylval.node->flags |= NODE_FL_NEWLINE;
#endif
return tSTRING_CONTENT;
}
@@ -9143,27 +8583,27 @@ formal_argument(struct parser_params *p, VALUE lhs)
switch (id_type(id)) {
case ID_LOCAL:
- break;
+ break;
#ifndef RIPPER
# define ERR(mesg) yyerror0(mesg)
#else
# define ERR(mesg) (dispatch2(param_error, WARN_S(mesg), lhs), ripper_error(p))
#endif
case ID_CONST:
- ERR("formal argument cannot be a constant");
- return 0;
+ ERR("formal argument cannot be a constant");
+ return 0;
case ID_INSTANCE:
- ERR("formal argument cannot be an instance variable");
- return 0;
+ ERR("formal argument cannot be an instance variable");
+ return 0;
case ID_GLOBAL:
- ERR("formal argument cannot be a global variable");
- return 0;
+ ERR("formal argument cannot be a global variable");
+ return 0;
case ID_CLASS:
- ERR("formal argument cannot be a class variable");
- return 0;
+ ERR("formal argument cannot be a class variable");
+ return 0;
default:
- ERR("formal argument must be local variable");
- return 0;
+ ERR("formal argument must be local variable");
+ return 0;
#undef ERR
}
shadowing_lvar(p, id);
@@ -9183,16 +8623,16 @@ parser_encode_length(struct parser_params *p, const char *name, long len)
long nlen;
if (len > 5 && name[nlen = len - 5] == '-') {
- if (rb_memcicmp(name + nlen + 1, "unix", 4) == 0)
- return nlen;
+ if (rb_memcicmp(name + nlen + 1, "unix", 4) == 0)
+ return nlen;
}
if (len > 4 && name[nlen = len - 4] == '-') {
- if (rb_memcicmp(name + nlen + 1, "dos", 3) == 0)
- return nlen;
- if (rb_memcicmp(name + nlen + 1, "mac", 3) == 0 &&
- !(len == 8 && rb_memcicmp(name, "utf8-mac", len) == 0))
- /* exclude UTF8-MAC because the encoding named "UTF8" doesn't exist in Ruby */
- return nlen;
+ if (rb_memcicmp(name + nlen + 1, "dos", 3) == 0)
+ return nlen;
+ if (rb_memcicmp(name + nlen + 1, "mac", 3) == 0 &&
+ !(len == 8 && rb_memcicmp(name, "utf8-mac", len) == 0))
+ /* exclude UTF8-MAC because the encoding named "UTF8" doesn't exist in Ruby */
+ return nlen;
}
return len;
}
@@ -9205,26 +8645,26 @@ parser_set_encode(struct parser_params *p, const char *name)
VALUE excargs[3];
if (idx < 0) {
- excargs[1] = rb_sprintf("unknown encoding name: %s", name);
+ excargs[1] = rb_sprintf("unknown encoding name: %s", name);
error:
- excargs[0] = rb_eArgError;
- excargs[2] = rb_make_backtrace();
- rb_ary_unshift(excargs[2], rb_sprintf("%"PRIsVALUE":%d", p->ruby_sourcefile_string, p->ruby_sourceline));
- rb_exc_raise(rb_make_exception(3, excargs));
+ excargs[0] = rb_eArgError;
+ excargs[2] = rb_make_backtrace();
+ rb_ary_unshift(excargs[2], rb_sprintf("%"PRIsVALUE":%d", p->ruby_sourcefile_string, p->ruby_sourceline));
+ rb_exc_raise(rb_make_exception(3, excargs));
}
enc = rb_enc_from_index(idx);
if (!rb_enc_asciicompat(enc)) {
- excargs[1] = rb_sprintf("%s is not ASCII compatible", rb_enc_name(enc));
- goto error;
+ excargs[1] = rb_sprintf("%s is not ASCII compatible", rb_enc_name(enc));
+ goto error;
}
p->enc = enc;
#ifndef RIPPER
if (p->debug_lines) {
- VALUE lines = p->debug_lines;
- long i, n = RARRAY_LEN(lines);
- for (i = 0; i < n; ++i) {
- rb_enc_associate_index(RARRAY_AREF(lines, i), idx);
- }
+ VALUE lines = p->debug_lines;
+ long i, n = RARRAY_LEN(lines);
+ for (i = 0; i < n; ++i) {
+ rb_enc_associate_index(RARRAY_AREF(lines, i), idx);
+ }
}
#endif
}
@@ -9235,8 +8675,8 @@ comment_at_top(struct parser_params *p)
const char *ptr = p->lex.pbeg, *ptr_end = p->lex.pcur - 1;
if (p->line_count != (p->has_shebang ? 2 : 1)) return 0;
while (ptr < ptr_end) {
- if (!ISSPACE(*ptr)) return 0;
- ptr++;
+ if (!ISSPACE(*ptr)) return 0;
+ ptr++;
}
return 1;
}
@@ -9250,7 +8690,7 @@ static void
magic_comment_encoding(struct parser_params *p, const char *name, const char *val)
{
if (!comment_at_top(p)) {
- return;
+ return;
}
parser_set_encode(p, val);
}
@@ -9260,15 +8700,15 @@ parser_get_bool(struct parser_params *p, const char *name, const char *val)
{
switch (*val) {
case 't': case 'T':
- if (STRCASECMP(val, "true") == 0) {
- return TRUE;
- }
- break;
+ if (STRCASECMP(val, "true") == 0) {
+ return TRUE;
+ }
+ break;
case 'f': case 'F':
- if (STRCASECMP(val, "false") == 0) {
- return FALSE;
- }
- break;
+ if (STRCASECMP(val, "false") == 0) {
+ return FALSE;
+ }
+ break;
}
return parser_invalid_pragma_value(p, name, val);
}
@@ -9288,54 +8728,57 @@ parser_set_token_info(struct parser_params *p, const char *name, const char *val
}
static void
-parser_set_frozen_string_literal(struct parser_params *p, const char *name, const char *val)
+parser_set_compile_option_flag(struct parser_params *p, const char *name, const char *val)
{
int b;
if (p->token_seen) {
- rb_warning1("`%s' is ignored after any tokens", WARN_S(name));
- return;
+ rb_warning1("`%s' is ignored after any tokens", WARN_S(name));
+ return;
}
b = parser_get_bool(p, name, val);
if (b < 0) return;
- p->frozen_string_literal = b;
+ if (!p->compile_option)
+ p->compile_option = rb_obj_hide(rb_ident_hash_new());
+ rb_hash_aset(p->compile_option, ID2SYM(rb_intern(name)),
+ RBOOL(b));
}
static void
parser_set_shareable_constant_value(struct parser_params *p, const char *name, const char *val)
{
for (const char *s = p->lex.pbeg, *e = p->lex.pcur; s < e; ++s) {
- if (*s == ' ' || *s == '\t') continue;
- if (*s == '#') break;
- rb_warning1("`%s' is ignored unless in comment-only line", WARN_S(name));
- return;
+ if (*s == ' ' || *s == '\t') continue;
+ if (*s == '#') break;
+ rb_warning1("`%s' is ignored unless in comment-only line", WARN_S(name));
+ return;
}
switch (*val) {
case 'n': case 'N':
- if (STRCASECMP(val, "none") == 0) {
- p->ctxt.shareable_constant_value = shareable_none;
- return;
- }
- break;
+ if (STRCASECMP(val, "none") == 0) {
+ p->ctxt.shareable_constant_value = shareable_none;
+ return;
+ }
+ break;
case 'l': case 'L':
- if (STRCASECMP(val, "literal") == 0) {
- p->ctxt.shareable_constant_value = shareable_literal;
- return;
- }
- break;
+ if (STRCASECMP(val, "literal") == 0) {
+ p->ctxt.shareable_constant_value = shareable_literal;
+ return;
+ }
+ break;
case 'e': case 'E':
- if (STRCASECMP(val, "experimental_copy") == 0) {
- p->ctxt.shareable_constant_value = shareable_copy;
- return;
- }
- if (STRCASECMP(val, "experimental_everything") == 0) {
- p->ctxt.shareable_constant_value = shareable_everything;
- return;
- }
- break;
+ if (STRCASECMP(val, "experimental_copy") == 0) {
+ p->ctxt.shareable_constant_value = shareable_copy;
+ return;
+ }
+ if (STRCASECMP(val, "experimental_everything") == 0) {
+ p->ctxt.shareable_constant_value = shareable_everything;
+ return;
+ }
+ break;
}
parser_invalid_pragma_value(p, name, val);
}
@@ -9358,7 +8801,7 @@ struct magic_comment {
static const struct magic_comment magic_comments[] = {
{"coding", magic_comment_encoding, parser_encode_length},
{"encoding", magic_comment_encoding, parser_encode_length},
- {"frozen_string_literal", parser_set_frozen_string_literal},
+ {"frozen_string_literal", parser_set_compile_option_flag},
{"shareable_constant_value", parser_set_shareable_constant_value},
{"warn_indent", parser_set_token_info},
# if WARN_PAST_SCOPE
@@ -9372,29 +8815,29 @@ magic_comment_marker(const char *str, long len)
long i = 2;
while (i < len) {
- switch (str[i]) {
- case '-':
- if (str[i-1] == '*' && str[i-2] == '-') {
- return str + i + 1;
- }
- i += 2;
- break;
- case '*':
- if (i + 1 >= len) return 0;
- if (str[i+1] != '-') {
- i += 4;
- }
- else if (str[i-1] != '-') {
- i += 2;
- }
- else {
- return str + i + 2;
- }
- break;
- default:
- i += 3;
- break;
- }
+ switch (str[i]) {
+ case '-':
+ if (str[i-1] == '*' && str[i-2] == '-') {
+ return str + i + 1;
+ }
+ i += 2;
+ break;
+ case '*':
+ if (i + 1 >= len) return 0;
+ if (str[i+1] != '-') {
+ i += 4;
+ }
+ else if (str[i-1] != '-') {
+ i += 2;
+ }
+ else {
+ return str + i + 2;
+ }
+ break;
+ default:
+ i += 3;
+ break;
+ }
}
return 0;
}
@@ -9406,97 +8849,97 @@ parser_magic_comment(struct parser_params *p, const char *str, long len)
VALUE name = 0, val = 0;
const char *beg, *end, *vbeg, *vend;
#define str_copy(_s, _p, _n) ((_s) \
- ? (void)(rb_str_resize((_s), (_n)), \
- MEMCPY(RSTRING_PTR(_s), (_p), char, (_n)), (_s)) \
- : (void)((_s) = STR_NEW((_p), (_n))))
+ ? (void)(rb_str_resize((_s), (_n)), \
+ MEMCPY(RSTRING_PTR(_s), (_p), char, (_n)), (_s)) \
+ : (void)((_s) = STR_NEW((_p), (_n))))
if (len <= 7) return FALSE;
if (!!(beg = magic_comment_marker(str, len))) {
- if (!(end = magic_comment_marker(beg, str + len - beg)))
- return FALSE;
- indicator = TRUE;
- str = beg;
- len = end - beg - 3;
+ if (!(end = magic_comment_marker(beg, str + len - beg)))
+ return FALSE;
+ indicator = TRUE;
+ str = beg;
+ len = end - beg - 3;
}
/* %r"([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*" */
while (len > 0) {
- const struct magic_comment *mc = magic_comments;
- char *s;
- int i;
- long n = 0;
-
- for (; len > 0 && *str; str++, --len) {
- switch (*str) {
- case '\'': case '"': case ':': case ';':
- continue;
- }
- if (!ISSPACE(*str)) break;
- }
- for (beg = str; len > 0; str++, --len) {
- switch (*str) {
- case '\'': case '"': case ':': case ';':
- break;
- default:
- if (ISSPACE(*str)) break;
- continue;
- }
- break;
- }
- for (end = str; len > 0 && ISSPACE(*str); str++, --len);
- if (!len) break;
- if (*str != ':') {
- if (!indicator) return FALSE;
- continue;
- }
-
- do str++; while (--len > 0 && ISSPACE(*str));
- if (!len) break;
- if (*str == '"') {
- for (vbeg = ++str; --len > 0 && *str != '"'; str++) {
- if (*str == '\\') {
- --len;
- ++str;
- }
- }
- vend = str;
- if (len) {
- --len;
- ++str;
- }
- }
- else {
- for (vbeg = str; len > 0 && *str != '"' && *str != ';' && !ISSPACE(*str); --len, str++);
- vend = str;
- }
- if (indicator) {
- while (len > 0 && (*str == ';' || ISSPACE(*str))) --len, str++;
- }
- else {
- while (len > 0 && (ISSPACE(*str))) --len, str++;
- if (len) return FALSE;
- }
-
- n = end - beg;
- str_copy(name, beg, n);
- s = RSTRING_PTR(name);
- for (i = 0; i < n; ++i) {
- if (s[i] == '-') s[i] = '_';
- }
- do {
- if (STRNCASECMP(mc->name, s, n) == 0 && !mc->name[n]) {
- n = vend - vbeg;
- if (mc->length) {
- n = (*mc->length)(p, vbeg, n);
- }
- str_copy(val, vbeg, n);
- (*mc->func)(p, mc->name, RSTRING_PTR(val));
- break;
- }
- } while (++mc < magic_comments + numberof(magic_comments));
+ const struct magic_comment *mc = magic_comments;
+ char *s;
+ int i;
+ long n = 0;
+
+ for (; len > 0 && *str; str++, --len) {
+ switch (*str) {
+ case '\'': case '"': case ':': case ';':
+ continue;
+ }
+ if (!ISSPACE(*str)) break;
+ }
+ for (beg = str; len > 0; str++, --len) {
+ switch (*str) {
+ case '\'': case '"': case ':': case ';':
+ break;
+ default:
+ if (ISSPACE(*str)) break;
+ continue;
+ }
+ break;
+ }
+ for (end = str; len > 0 && ISSPACE(*str); str++, --len);
+ if (!len) break;
+ if (*str != ':') {
+ if (!indicator) return FALSE;
+ continue;
+ }
+
+ do str++; while (--len > 0 && ISSPACE(*str));
+ if (!len) break;
+ if (*str == '"') {
+ for (vbeg = ++str; --len > 0 && *str != '"'; str++) {
+ if (*str == '\\') {
+ --len;
+ ++str;
+ }
+ }
+ vend = str;
+ if (len) {
+ --len;
+ ++str;
+ }
+ }
+ else {
+ for (vbeg = str; len > 0 && *str != '"' && *str != ';' && !ISSPACE(*str); --len, str++);
+ vend = str;
+ }
+ if (indicator) {
+ while (len > 0 && (*str == ';' || ISSPACE(*str))) --len, str++;
+ }
+ else {
+ while (len > 0 && (ISSPACE(*str))) --len, str++;
+ if (len) return FALSE;
+ }
+
+ n = end - beg;
+ str_copy(name, beg, n);
+ s = RSTRING_PTR(name);
+ for (i = 0; i < n; ++i) {
+ if (s[i] == '-') s[i] = '_';
+ }
+ do {
+ if (STRNCASECMP(mc->name, s, n) == 0 && !mc->name[n]) {
+ n = vend - vbeg;
+ if (mc->length) {
+ n = (*mc->length)(p, vbeg, n);
+ }
+ str_copy(val, vbeg, n);
+ (*mc->func)(p, mc->name, RSTRING_PTR(val));
+ break;
+ }
+ } while (++mc < magic_comments + numberof(magic_comments));
#ifdef RIPPER
- str_copy(val, vbeg, vend - vbeg);
- dispatch2(magic_comment, name, val);
+ str_copy(val, vbeg, vend - vbeg);
+ dispatch2(magic_comment, name, val);
#endif
}
@@ -9511,34 +8954,34 @@ set_file_encoding(struct parser_params *p, const char *str, const char *send)
VALUE s;
for (;;) {
- if (send - str <= 6) return;
- switch (str[6]) {
- case 'C': case 'c': str += 6; continue;
- case 'O': case 'o': str += 5; continue;
- case 'D': case 'd': str += 4; continue;
- case 'I': case 'i': str += 3; continue;
- case 'N': case 'n': str += 2; continue;
- case 'G': case 'g': str += 1; continue;
- case '=': case ':':
- sep = 1;
- str += 6;
- break;
- default:
- str += 6;
- if (ISSPACE(*str)) break;
- continue;
- }
- if (STRNCASECMP(str-6, "coding", 6) == 0) break;
- sep = 0;
+ if (send - str <= 6) return;
+ switch (str[6]) {
+ case 'C': case 'c': str += 6; continue;
+ case 'O': case 'o': str += 5; continue;
+ case 'D': case 'd': str += 4; continue;
+ case 'I': case 'i': str += 3; continue;
+ case 'N': case 'n': str += 2; continue;
+ case 'G': case 'g': str += 1; continue;
+ case '=': case ':':
+ sep = 1;
+ str += 6;
+ break;
+ default:
+ str += 6;
+ if (ISSPACE(*str)) break;
+ continue;
+ }
+ if (STRNCASECMP(str-6, "coding", 6) == 0) break;
+ sep = 0;
}
for (;;) {
- do {
- if (++str >= send) return;
- } while (ISSPACE(*str));
- if (sep) break;
- if (*str != '=' && *str != ':') return;
- sep = 1;
- str++;
+ do {
+ if (++str >= send) return;
+ } while (ISSPACE(*str));
+ if (sep) break;
+ if (*str != '=' && *str != ':') return;
+ sep = 1;
+ str++;
}
beg = str;
while ((*str == '-' || *str == '_' || ISALNUM(*str)) && ++str < send);
@@ -9554,26 +8997,25 @@ parser_prepare(struct parser_params *p)
p->token_info_enabled = !compile_for_eval && RTEST(ruby_verbose);
switch (c) {
case '#':
- if (peek(p, '!')) p->has_shebang = 1;
- break;
+ if (peek(p, '!')) p->has_shebang = 1;
+ break;
case 0xef: /* UTF-8 BOM marker */
- if (!lex_eol_n_p(p, 2) &&
- (unsigned char)p->lex.pcur[0] == 0xbb &&
- (unsigned char)p->lex.pcur[1] == 0xbf) {
- p->enc = rb_utf8_encoding();
- p->lex.pcur += 2;
+ if (p->lex.pend - p->lex.pcur >= 2 &&
+ (unsigned char)p->lex.pcur[0] == 0xbb &&
+ (unsigned char)p->lex.pcur[1] == 0xbf) {
+ p->enc = rb_utf8_encoding();
+ p->lex.pcur += 2;
#ifndef RIPPER
- if (p->debug_lines) {
- rb_enc_associate(p->lex.lastline, p->enc);
- }
+ if (p->debug_lines) {
+ rb_enc_associate(p->lex.lastline, p->enc);
+ }
#endif
- p->lex.pbeg = p->lex.pcur;
- token_flush(p);
- return;
- }
- break;
+ p->lex.pbeg = p->lex.pcur;
+ return;
+ }
+ break;
case EOF:
- return;
+ return;
}
pushback(p, c);
p->enc = rb_enc_get(p->lex.lastline);
@@ -9623,227 +9065,226 @@ parse_numeric(struct parser_params *p, int c)
SET_LEX_STATE(EXPR_END);
newtok(p);
if (c == '-' || c == '+') {
- tokadd(p, c);
- c = nextc(p);
+ tokadd(p, c);
+ c = nextc(p);
}
if (c == '0') {
- int start = toklen(p);
- c = nextc(p);
- if (c == 'x' || c == 'X') {
- /* hexadecimal */
- c = nextc(p);
- if (c != -1 && ISXDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISXDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- return no_digits(p);
- }
- else if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_integer_literal(p, rb_cstr_to_inum(tok(p), 16, FALSE), suffix);
- }
- if (c == 'b' || c == 'B') {
- /* binary */
- c = nextc(p);
- if (c == '0' || c == '1') {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c != '0' && c != '1') break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- return no_digits(p);
- }
- else if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_integer_literal(p, rb_cstr_to_inum(tok(p), 2, FALSE), suffix);
- }
- if (c == 'd' || c == 'D') {
- /* decimal */
- c = nextc(p);
- if (c != -1 && ISDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- return no_digits(p);
- }
- else if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_integer_literal(p, rb_cstr_to_inum(tok(p), 10, FALSE), suffix);
- }
- if (c == '_') {
- /* 0_0 */
- goto octal_number;
- }
- if (c == 'o' || c == 'O') {
- /* prefixed octal */
- c = nextc(p);
- if (c == -1 || c == '_' || !ISDIGIT(c)) {
- return no_digits(p);
- }
- }
- if (c >= '0' && c <= '7') {
- /* octal */
- octal_number:
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c < '0' || c > '9') break;
- if (c > '7') goto invalid_octal;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- if (toklen(p) > start) {
- pushback(p, c);
- tokfix(p);
- if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_integer_literal(p, rb_cstr_to_inum(tok(p), 8, FALSE), suffix);
- }
- if (nondigit) {
- pushback(p, c);
- goto trailing_uc;
- }
- }
- if (c > '7' && c <= '9') {
- invalid_octal:
- yyerror0("Invalid octal digit");
- }
- else if (c == '.' || c == 'e' || c == 'E') {
- tokadd(p, '0');
- }
- else {
- pushback(p, c);
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_integer_literal(p, INT2FIX(0), suffix);
- }
+ int start = toklen(p);
+ c = nextc(p);
+ if (c == 'x' || c == 'X') {
+ /* hexadecimal */
+ c = nextc(p);
+ if (c != -1 && ISXDIGIT(c)) {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (!ISXDIGIT(c)) break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ return no_digits(p);
+ }
+ else if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 16, FALSE), suffix);
+ }
+ if (c == 'b' || c == 'B') {
+ /* binary */
+ c = nextc(p);
+ if (c == '0' || c == '1') {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (c != '0' && c != '1') break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ return no_digits(p);
+ }
+ else if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 2, FALSE), suffix);
+ }
+ if (c == 'd' || c == 'D') {
+ /* decimal */
+ c = nextc(p);
+ if (c != -1 && ISDIGIT(c)) {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (!ISDIGIT(c)) break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ return no_digits(p);
+ }
+ else if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 10, FALSE), suffix);
+ }
+ if (c == '_') {
+ /* 0_0 */
+ goto octal_number;
+ }
+ if (c == 'o' || c == 'O') {
+ /* prefixed octal */
+ c = nextc(p);
+ if (c == -1 || c == '_' || !ISDIGIT(c)) {
+ return no_digits(p);
+ }
+ }
+ if (c >= '0' && c <= '7') {
+ /* octal */
+ octal_number:
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (c < '0' || c > '9') break;
+ if (c > '7') goto invalid_octal;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ if (toklen(p) > start) {
+ pushback(p, c);
+ tokfix(p);
+ if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 8, FALSE), suffix);
+ }
+ if (nondigit) {
+ pushback(p, c);
+ goto trailing_uc;
+ }
+ }
+ if (c > '7' && c <= '9') {
+ invalid_octal:
+ yyerror0("Invalid octal digit");
+ }
+ else if (c == '.' || c == 'e' || c == 'E') {
+ tokadd(p, '0');
+ }
+ else {
+ pushback(p, c);
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, INT2FIX(0), suffix);
+ }
}
for (;;) {
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- nondigit = 0;
- tokadd(p, c);
- break;
-
- case '.':
- if (nondigit) goto trailing_uc;
- if (seen_point || seen_e) {
- goto decode_num;
- }
- else {
- int c0 = nextc(p);
- if (c0 == -1 || !ISDIGIT(c0)) {
- pushback(p, c0);
- goto decode_num;
- }
- c = c0;
- }
- seen_point = toklen(p);
- tokadd(p, '.');
- tokadd(p, c);
- is_float++;
- nondigit = 0;
- break;
-
- case 'e':
- case 'E':
- if (nondigit) {
- pushback(p, c);
- c = nondigit;
- goto decode_num;
- }
- if (seen_e) {
- goto decode_num;
- }
- nondigit = c;
- c = nextc(p);
- if (c != '-' && c != '+' && !ISDIGIT(c)) {
- pushback(p, c);
- c = nondigit;
- nondigit = 0;
- goto decode_num;
- }
- tokadd(p, nondigit);
- seen_e++;
- is_float++;
- tokadd(p, c);
- nondigit = (c == '-' || c == '+') ? c : 0;
- break;
-
- case '_': /* `_' in number just ignored */
- if (nondigit) goto decode_num;
- nondigit = c;
- break;
-
- default:
- goto decode_num;
- }
- c = nextc(p);
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ nondigit = 0;
+ tokadd(p, c);
+ break;
+
+ case '.':
+ if (nondigit) goto trailing_uc;
+ if (seen_point || seen_e) {
+ goto decode_num;
+ }
+ else {
+ int c0 = nextc(p);
+ if (c0 == -1 || !ISDIGIT(c0)) {
+ pushback(p, c0);
+ goto decode_num;
+ }
+ c = c0;
+ }
+ seen_point = toklen(p);
+ tokadd(p, '.');
+ tokadd(p, c);
+ is_float++;
+ nondigit = 0;
+ break;
+
+ case 'e':
+ case 'E':
+ if (nondigit) {
+ pushback(p, c);
+ c = nondigit;
+ goto decode_num;
+ }
+ if (seen_e) {
+ goto decode_num;
+ }
+ nondigit = c;
+ c = nextc(p);
+ if (c != '-' && c != '+' && !ISDIGIT(c)) {
+ pushback(p, c);
+ nondigit = 0;
+ goto decode_num;
+ }
+ tokadd(p, nondigit);
+ seen_e++;
+ is_float++;
+ tokadd(p, c);
+ nondigit = (c == '-' || c == '+') ? c : 0;
+ break;
+
+ case '_': /* `_' in number just ignored */
+ if (nondigit) goto decode_num;
+ nondigit = c;
+ break;
+
+ default:
+ goto decode_num;
+ }
+ c = nextc(p);
}
decode_num:
pushback(p, c);
if (nondigit) {
trailing_uc:
- literal_flush(p, p->lex.pcur - 1);
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- compile_error(p, "trailing `%c' in number", nondigit);
- parser_show_error_line(p, &loc);
+ literal_flush(p, p->lex.pcur - 1);
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ compile_error(p, "trailing `%c' in number", nondigit);
+ parser_show_error_line(p, &loc);
}
tokfix(p);
if (is_float) {
- enum yytokentype type = tFLOAT;
- VALUE v;
-
- suffix = number_literal_suffix(p, seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
- if (suffix & NUM_SUFFIX_R) {
- type = tRATIONAL;
- v = parse_rational(p, tok(p), toklen(p), seen_point);
- }
- else {
- double d = strtod(tok(p), 0);
- if (errno == ERANGE) {
- rb_warning1("Float %s out of range", WARN_S(tok(p)));
- errno = 0;
- }
- v = DBL2NUM(d);
- }
- return set_number_literal(p, v, type, suffix);
+ enum yytokentype type = tFLOAT;
+ VALUE v;
+
+ suffix = number_literal_suffix(p, seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
+ if (suffix & NUM_SUFFIX_R) {
+ type = tRATIONAL;
+ v = parse_rational(p, tok(p), toklen(p), seen_point);
+ }
+ else {
+ double d = strtod(tok(p), 0);
+ if (errno == ERANGE) {
+ rb_warning1("Float %s out of range", WARN_S(tok(p)));
+ errno = 0;
+ }
+ v = DBL2NUM(d);
+ }
+ return set_number_literal(p, v, type, suffix);
}
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
return set_integer_literal(p, rb_cstr_to_inum(tok(p), 10, FALSE), suffix);
@@ -9857,63 +9298,63 @@ parse_qmark(struct parser_params *p, int space_seen)
VALUE lit;
if (IS_END()) {
- SET_LEX_STATE(EXPR_VALUE);
- return '?';
+ SET_LEX_STATE(EXPR_VALUE);
+ return '?';
}
c = nextc(p);
if (c == -1) {
- compile_error(p, "incomplete character syntax");
- return 0;
+ compile_error(p, "incomplete character syntax");
+ return 0;
}
if (rb_enc_isspace(c, p->enc)) {
- if (!IS_ARG()) {
- int c2 = escaped_control_code(c);
- if (c2) {
- WARN_SPACE_CHAR(c2, "?");
- }
- }
+ if (!IS_ARG()) {
+ int c2 = escaped_control_code(c);
+ if (c2) {
+ WARN_SPACE_CHAR(c2, "?");
+ }
+ }
ternary:
- pushback(p, c);
- SET_LEX_STATE(EXPR_VALUE);
- return '?';
+ pushback(p, c);
+ SET_LEX_STATE(EXPR_VALUE);
+ return '?';
}
newtok(p);
enc = p->enc;
if (!parser_isascii(p)) {
- if (tokadd_mbchar(p, c) == -1) return 0;
+ if (tokadd_mbchar(p, c) == -1) return 0;
}
else if ((rb_enc_isalnum(c, p->enc) || c == '_') &&
- !lex_eol_p(p) && is_identchar(p, p->lex.pcur, p->lex.pend, p->enc)) {
- if (space_seen) {
- const char *start = p->lex.pcur - 1, *ptr = start;
- do {
- int n = parser_precise_mbclen(p, ptr);
- if (n < 0) return -1;
- ptr += n;
- } while (!lex_eol_ptr_p(p, ptr) && is_identchar(p, ptr, p->lex.pend, p->enc));
- rb_warn2("`?' just followed by `%.*s' is interpreted as" \
- " a conditional operator, put a space after `?'",
- WARN_I((int)(ptr - start)), WARN_S_L(start, (ptr - start)));
- }
- goto ternary;
+ p->lex.pcur < p->lex.pend && is_identchar(p->lex.pcur, p->lex.pend, p->enc)) {
+ if (space_seen) {
+ const char *start = p->lex.pcur - 1, *ptr = start;
+ do {
+ int n = parser_precise_mbclen(p, ptr);
+ if (n < 0) return -1;
+ ptr += n;
+ } while (ptr < p->lex.pend && is_identchar(ptr, p->lex.pend, p->enc));
+ rb_warn2("`?' just followed by `%.*s' is interpreted as" \
+ " a conditional operator, put a space after `?'",
+ WARN_I((int)(ptr - start)), WARN_S_L(start, (ptr - start)));
+ }
+ goto ternary;
}
else if (c == '\\') {
- if (peek(p, 'u')) {
- nextc(p);
- enc = rb_utf8_encoding();
- tokadd_utf8(p, &enc, -1, 0, 0);
- }
+ if (peek(p, 'u')) {
+ nextc(p);
+ enc = rb_utf8_encoding();
+ tokadd_utf8(p, &enc, -1, 0, 0);
+ }
else if (!ISASCII(c = peekc(p))) {
- nextc(p);
- if (tokadd_mbchar(p, c) == -1) return 0;
- }
- else {
- c = read_escape(p, 0);
- tokadd(p, c);
- }
+ nextc(p);
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ }
+ else {
+ c = read_escape(p, 0, &enc);
+ tokadd(p, c);
+ }
}
else {
- tokadd(p, c);
+ tokadd(p, c);
}
tokfix(p);
lit = STR_NEW3(tok(p), toklen(p), enc, 0);
@@ -9929,92 +9370,92 @@ parse_percent(struct parser_params *p, const int space_seen, const enum lex_stat
const char *ptok = p->lex.pcur;
if (IS_BEG()) {
- int term;
- int paren;
+ int term;
+ int paren;
- c = nextc(p);
+ c = nextc(p);
quotation:
- if (c == -1) goto unterminated;
- if (!ISALNUM(c)) {
- term = c;
- if (!ISASCII(c)) goto unknown;
- c = 'Q';
- }
- else {
- term = nextc(p);
- if (rb_enc_isalnum(term, p->enc) || !parser_isascii(p)) {
- unknown:
- pushback(p, term);
- c = parser_precise_mbclen(p, p->lex.pcur);
- if (c < 0) return 0;
- p->lex.pcur += c;
- yyerror0("unknown type of %string");
- return 0;
- }
- }
- if (term == -1) {
- unterminated:
- compile_error(p, "unterminated quoted string meets end of file");
- return 0;
- }
- paren = term;
- if (term == '(') term = ')';
- else if (term == '[') term = ']';
- else if (term == '{') term = '}';
- else if (term == '<') term = '>';
- else paren = 0;
-
- p->lex.ptok = ptok-1;
- switch (c) {
- case 'Q':
- p->lex.strterm = NEW_STRTERM(str_dquote, term, paren);
- return tSTRING_BEG;
-
- case 'q':
- p->lex.strterm = NEW_STRTERM(str_squote, term, paren);
- return tSTRING_BEG;
-
- case 'W':
- p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
- return tWORDS_BEG;
-
- case 'w':
- p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
- return tQWORDS_BEG;
-
- case 'I':
- p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
- return tSYMBOLS_BEG;
-
- case 'i':
- p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
- return tQSYMBOLS_BEG;
-
- case 'x':
- p->lex.strterm = NEW_STRTERM(str_xquote, term, paren);
- return tXSTRING_BEG;
-
- case 'r':
- p->lex.strterm = NEW_STRTERM(str_regexp, term, paren);
- return tREGEXP_BEG;
-
- case 's':
- p->lex.strterm = NEW_STRTERM(str_ssym, term, paren);
- SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);
- return tSYMBEG;
-
- default:
- yyerror0("unknown type of %string");
- return 0;
- }
+ if (c == -1) goto unterminated;
+ if (!ISALNUM(c)) {
+ term = c;
+ if (!ISASCII(c)) goto unknown;
+ c = 'Q';
+ }
+ else {
+ term = nextc(p);
+ if (rb_enc_isalnum(term, p->enc) || !parser_isascii(p)) {
+ unknown:
+ pushback(p, term);
+ c = parser_precise_mbclen(p, p->lex.pcur);
+ if (c < 0) return 0;
+ p->lex.pcur += c;
+ yyerror0("unknown type of %string");
+ return 0;
+ }
+ }
+ if (term == -1) {
+ unterminated:
+ compile_error(p, "unterminated quoted string meets end of file");
+ return 0;
+ }
+ paren = term;
+ if (term == '(') term = ')';
+ else if (term == '[') term = ']';
+ else if (term == '{') term = '}';
+ else if (term == '<') term = '>';
+ else paren = 0;
+
+ p->lex.ptok = ptok-1;
+ switch (c) {
+ case 'Q':
+ p->lex.strterm = NEW_STRTERM(str_dquote, term, paren);
+ return tSTRING_BEG;
+
+ case 'q':
+ p->lex.strterm = NEW_STRTERM(str_squote, term, paren);
+ return tSTRING_BEG;
+
+ case 'W':
+ p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
+ return tWORDS_BEG;
+
+ case 'w':
+ p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
+ return tQWORDS_BEG;
+
+ case 'I':
+ p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
+ return tSYMBOLS_BEG;
+
+ case 'i':
+ p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
+ return tQSYMBOLS_BEG;
+
+ case 'x':
+ p->lex.strterm = NEW_STRTERM(str_xquote, term, paren);
+ return tXSTRING_BEG;
+
+ case 'r':
+ p->lex.strterm = NEW_STRTERM(str_regexp, term, paren);
+ return tREGEXP_BEG;
+
+ case 's':
+ p->lex.strterm = NEW_STRTERM(str_ssym, term, paren);
+ SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);
+ return tSYMBEG;
+
+ default:
+ yyerror0("unknown type of %string");
+ return 0;
+ }
}
if ((c = nextc(p)) == '=') {
- set_yylval_id('%');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
+ set_yylval_id('%');
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
}
if (IS_SPCARG(c) || (IS_lex_state(EXPR_FITEM) && c == 's')) {
- goto quotation;
+ goto quotation;
}
SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
pushback(p, c);
@@ -10025,15 +9466,15 @@ static int
tokadd_ident(struct parser_params *p, int c)
{
do {
- if (tokadd_mbchar(p, c) == -1) return -1;
- c = nextc(p);
+ if (tokadd_mbchar(p, c) == -1) return -1;
+ c = nextc(p);
} while (parser_is_identchar(p));
pushback(p, c);
return 0;
}
static ID
-tokenize_ident(struct parser_params *p)
+tokenize_ident(struct parser_params *p, const enum lex_state_e last_state)
{
ID ident = TOK_INTERN();
@@ -10049,17 +9490,17 @@ parse_numvar(struct parser_params *p)
int overflow;
unsigned long n = ruby_scan_digits(tok(p)+1, toklen(p)-1, 10, &len, &overflow);
const unsigned long nth_ref_max =
- ((FIXNUM_MAX < INT_MAX) ? FIXNUM_MAX : INT_MAX) >> 1;
+ ((FIXNUM_MAX < INT_MAX) ? FIXNUM_MAX : INT_MAX) >> 1;
/* NTH_REF is left-shifted to be ORed with back-ref flag and
* turned into a Fixnum, in compile.c */
if (overflow || n > nth_ref_max) {
- /* compile_error()? */
- rb_warn1("`%s' is too big for a number variable, always nil", WARN_S(tok(p)));
- return 0; /* $0 is $PROGRAM_NAME, not NTH_REF */
+ /* compile_error()? */
+ rb_warn1("`%s' is too big for a number variable, always nil", WARN_S(tok(p)));
+ return 0; /* $0 is $PROGRAM_NAME, not NTH_REF */
}
else {
- return (int)n;
+ return (int)n;
}
}
@@ -10075,106 +9516,100 @@ parse_gvar(struct parser_params *p, const enum lex_state_e last_state)
c = nextc(p);
switch (c) {
case '_': /* $_: last read line string */
- c = nextc(p);
- if (parser_is_identchar(p)) {
- tokadd(p, '$');
- tokadd(p, '_');
- break;
- }
- pushback(p, c);
- c = '_';
- /* fall through */
- case '~': /* $~: match-data */
- case '*': /* $*: argv */
- case '$': /* $$: pid */
- case '?': /* $?: last status */
- case '!': /* $!: error string */
- case '@': /* $@: error position */
- case '/': /* $/: input record separator */
- case '\\': /* $\: output record separator */
- case ';': /* $;: field separator */
- case ',': /* $,: output field separator */
- case '.': /* $.: last read line number */
- case '=': /* $=: ignorecase */
- case ':': /* $:: load path */
- case '<': /* $<: reading filename */
- case '>': /* $>: default output handle */
- case '\"': /* $": already loaded files */
- tokadd(p, '$');
- tokadd(p, c);
- goto gvar;
+ c = nextc(p);
+ if (parser_is_identchar(p)) {
+ tokadd(p, '$');
+ tokadd(p, '_');
+ break;
+ }
+ pushback(p, c);
+ c = '_';
+ /* fall through */
+ case '~': /* $~: match-data */
+ case '*': /* $*: argv */
+ case '$': /* $$: pid */
+ case '?': /* $?: last status */
+ case '!': /* $!: error string */
+ case '@': /* $@: error position */
+ case '/': /* $/: input record separator */
+ case '\\': /* $\: output record separator */
+ case ';': /* $;: field separator */
+ case ',': /* $,: output field separator */
+ case '.': /* $.: last read line number */
+ case '=': /* $=: ignorecase */
+ case ':': /* $:: load path */
+ case '<': /* $<: reading filename */
+ case '>': /* $>: default output handle */
+ case '\"': /* $": already loaded files */
+ tokadd(p, '$');
+ tokadd(p, c);
+ goto gvar;
case '-':
- tokadd(p, '$');
- tokadd(p, c);
- c = nextc(p);
- if (parser_is_identchar(p)) {
- if (tokadd_mbchar(p, c) == -1) return 0;
- }
- else {
- pushback(p, c);
- pushback(p, '-');
- return '$';
- }
+ tokadd(p, '$');
+ tokadd(p, c);
+ c = nextc(p);
+ if (parser_is_identchar(p)) {
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ }
+ else {
+ pushback(p, c);
+ pushback(p, '-');
+ return '$';
+ }
gvar:
- set_yylval_name(TOK_INTERN());
- return tGVAR;
-
- case '&': /* $&: last match */
- case '`': /* $`: string before last match */
- case '\'': /* $': string after last match */
- case '+': /* $+: string matches last paren. */
- if (IS_lex_state_for(last_state, EXPR_FNAME)) {
- tokadd(p, '$');
- tokadd(p, c);
- goto gvar;
- }
- set_yylval_node(NEW_BACK_REF(c, &_cur_loc));
- return tBACK_REF;
+ set_yylval_name(TOK_INTERN());
+ return tGVAR;
+
+ case '&': /* $&: last match */
+ case '`': /* $`: string before last match */
+ case '\'': /* $': string after last match */
+ case '+': /* $+: string matches last paren. */
+ if (IS_lex_state_for(last_state, EXPR_FNAME)) {
+ tokadd(p, '$');
+ tokadd(p, c);
+ goto gvar;
+ }
+ set_yylval_node(NEW_BACK_REF(c, &_cur_loc));
+ return tBACK_REF;
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
- tokadd(p, '$');
- do {
- tokadd(p, c);
- c = nextc(p);
- } while (c != -1 && ISDIGIT(c));
- pushback(p, c);
- if (IS_lex_state_for(last_state, EXPR_FNAME)) goto gvar;
- tokfix(p);
- c = parse_numvar(p);
- set_yylval_node(NEW_NTH_REF(c, &_cur_loc));
- return tNTH_REF;
+ tokadd(p, '$');
+ do {
+ tokadd(p, c);
+ c = nextc(p);
+ } while (c != -1 && ISDIGIT(c));
+ pushback(p, c);
+ if (IS_lex_state_for(last_state, EXPR_FNAME)) goto gvar;
+ tokfix(p);
+ c = parse_numvar(p);
+ set_yylval_node(NEW_NTH_REF(c, &_cur_loc));
+ return tNTH_REF;
default:
- if (!parser_is_identchar(p)) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- if (c == -1 || ISSPACE(c)) {
- compile_error(p, "`$' without identifiers is not allowed as a global variable name");
- }
- else {
- pushback(p, c);
- compile_error(p, "`$%c' is not allowed as a global variable name", c);
- }
- parser_show_error_line(p, &loc);
- set_yylval_noname();
- return tGVAR;
- }
- /* fall through */
+ if (!parser_is_identchar(p)) {
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ if (c == -1 || ISSPACE(c)) {
+ compile_error(p, "`$' without identifiers is not allowed as a global variable name");
+ }
+ else {
+ pushback(p, c);
+ compile_error(p, "`$%c' is not allowed as a global variable name", c);
+ }
+ parser_show_error_line(p, &loc);
+ set_yylval_noname();
+ return tGVAR;
+ }
+ /* fall through */
case '0':
- tokadd(p, '$');
+ tokadd(p, '$');
}
if (tokadd_ident(p, c)) return 0;
SET_LEX_STATE(EXPR_END);
- if (VALID_SYMNAME_P(tok(p), toklen(p), p->enc, ID_GLOBAL)) {
- tokenize_ident(p);
- }
- else {
- compile_error(p, "`%.*s' is not allowed as a global variable name", toklen(p), tok(p));
- set_yylval_noname();
- }
+ tokenize_ident(p, last_state);
return tGVAR;
}
@@ -10185,18 +9620,18 @@ parser_numbered_param(struct parser_params *p, int n)
if (n < 0) return false;
if (DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev)) {
- return false;
+ return false;
}
if (p->max_numparam == ORDINAL_PARAM) {
- compile_error(p, "ordinary parameter is defined");
- return false;
+ compile_error(p, "ordinary parameter is defined");
+ return false;
}
struct vtable *args = p->lvtbl->args;
if (p->max_numparam < n) {
- p->max_numparam = n;
+ p->max_numparam = n;
}
while (n > args->pos) {
- vtable_add(args, NUMPARAM_IDX_TO_ID(args->pos+1));
+ vtable_add(args, NUMPARAM_IDX_TO_ID(args->pos+1));
}
return true;
}
@@ -10214,42 +9649,42 @@ parse_atmark(struct parser_params *p, const enum lex_state_e last_state)
newtok(p);
tokadd(p, '@');
if (c == '@') {
- result = tCVAR;
- tokadd(p, '@');
- c = nextc(p);
+ result = tCVAR;
+ tokadd(p, '@');
+ c = nextc(p);
}
SET_LEX_STATE(IS_lex_state_for(last_state, EXPR_FNAME) ? EXPR_ENDFN : EXPR_END);
if (c == -1 || !parser_is_identchar(p)) {
- pushback(p, c);
- RUBY_SET_YYLLOC(loc);
- if (result == tIVAR) {
- compile_error(p, "`@' without identifiers is not allowed as an instance variable name");
- }
- else {
- compile_error(p, "`@@' without identifiers is not allowed as a class variable name");
- }
- parser_show_error_line(p, &loc);
- set_yylval_noname();
- SET_LEX_STATE(EXPR_END);
- return result;
+ pushback(p, c);
+ RUBY_SET_YYLLOC(loc);
+ if (result == tIVAR) {
+ compile_error(p, "`@' without identifiers is not allowed as an instance variable name");
+ }
+ else {
+ compile_error(p, "`@@' without identifiers is not allowed as a class variable name");
+ }
+ parser_show_error_line(p, &loc);
+ set_yylval_noname();
+ SET_LEX_STATE(EXPR_END);
+ return result;
}
else if (ISDIGIT(c)) {
- pushback(p, c);
- RUBY_SET_YYLLOC(loc);
- if (result == tIVAR) {
- compile_error(p, "`@%c' is not allowed as an instance variable name", c);
- }
- else {
- compile_error(p, "`@@%c' is not allowed as a class variable name", c);
- }
- parser_show_error_line(p, &loc);
- set_yylval_noname();
- SET_LEX_STATE(EXPR_END);
- return result;
+ pushback(p, c);
+ RUBY_SET_YYLLOC(loc);
+ if (result == tIVAR) {
+ compile_error(p, "`@%c' is not allowed as an instance variable name", c);
+ }
+ else {
+ compile_error(p, "`@@%c' is not allowed as a class variable name", c);
+ }
+ parser_show_error_line(p, &loc);
+ set_yylval_noname();
+ SET_LEX_STATE(EXPR_END);
+ return result;
}
if (tokadd_ident(p, c)) return 0;
- tokenize_ident(p);
+ tokenize_ident(p, last_state);
return result;
}
@@ -10263,112 +9698,112 @@ parse_ident(struct parser_params *p, int c, int cmd_state)
int enforce_keyword_end = 0;
do {
- if (!ISASCII(c)) mb = ENC_CODERANGE_UNKNOWN;
- if (tokadd_mbchar(p, c) == -1) return 0;
- c = nextc(p);
+ if (!ISASCII(c)) mb = ENC_CODERANGE_UNKNOWN;
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ c = nextc(p);
} while (parser_is_identchar(p));
if ((c == '!' || c == '?') && !peek(p, '=')) {
- result = tFID;
- tokadd(p, c);
+ result = tFID;
+ tokadd(p, c);
}
else if (c == '=' && IS_lex_state(EXPR_FNAME) &&
- (!peek(p, '~') && !peek(p, '>') && (!peek(p, '=') || (peek_n(p, '>', 1))))) {
- result = tIDENTIFIER;
- tokadd(p, c);
+ (!peek(p, '~') && !peek(p, '>') && (!peek(p, '=') || (peek_n(p, '>', 1))))) {
+ result = tIDENTIFIER;
+ tokadd(p, c);
}
else {
- result = tCONSTANT; /* assume provisionally */
- pushback(p, c);
+ result = tCONSTANT; /* assume provisionally */
+ pushback(p, c);
}
tokfix(p);
if (IS_LABEL_POSSIBLE()) {
- if (IS_LABEL_SUFFIX(0)) {
- SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
- nextc(p);
- set_yylval_name(TOK_INTERN());
- return tLABEL;
- }
+ if (IS_LABEL_SUFFIX(0)) {
+ SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
+ nextc(p);
+ set_yylval_name(TOK_INTERN());
+ return tLABEL;
+ }
}
#ifndef RIPPER
if (!NIL_P(peek_end_expect_token_locations(p))) {
- VALUE end_loc;
- int lineno, column;
- int beg_pos = (int)(p->lex.ptok - p->lex.pbeg);
+ VALUE end_loc;
+ int lineno, column;
+ int beg_pos = (int)(p->lex.ptok - p->lex.pbeg);
- end_loc = peek_end_expect_token_locations(p);
- lineno = NUM2INT(rb_ary_entry(end_loc, 0));
- column = NUM2INT(rb_ary_entry(end_loc, 1));
+ end_loc = peek_end_expect_token_locations(p);
+ lineno = NUM2INT(rb_ary_entry(end_loc, 0));
+ column = NUM2INT(rb_ary_entry(end_loc, 1));
- if (p->debug) {
- rb_parser_printf(p, "enforce_keyword_end check. current: (%d, %d), peek: (%d, %d)\n",
- p->ruby_sourceline, beg_pos, lineno, column);
- }
+ if (p->debug) {
+ rb_parser_printf(p, "enforce_keyword_end check. current: (%d, %d), peek: (%d, %d)\n",
+ p->ruby_sourceline, beg_pos, lineno, column);
+ }
- if ((p->ruby_sourceline > lineno) && (beg_pos <= column)) {
- const struct kwtable *kw;
+ if ((p->ruby_sourceline > lineno) && (beg_pos <= column)) {
+ const struct kwtable *kw;
- if ((IS_lex_state(EXPR_DOT)) && (kw = rb_reserved_word(tok(p), toklen(p))) && (kw && kw->id[0] == keyword_end)) {
- if (p->debug) rb_parser_printf(p, "enforce_keyword_end is enabled\n");
- enforce_keyword_end = 1;
- }
- }
+ if ((IS_lex_state(EXPR_DOT)) && (kw = rb_reserved_word(tok(p), toklen(p))) && (kw && kw->id[0] == keyword_end)) {
+ if (p->debug) rb_parser_printf(p, "enforce_keyword_end is enabled\n");
+ enforce_keyword_end = 1;
+ }
+ }
}
#endif
if (mb == ENC_CODERANGE_7BIT && (!IS_lex_state(EXPR_DOT) || enforce_keyword_end)) {
- const struct kwtable *kw;
-
- /* See if it is a reserved word. */
- kw = rb_reserved_word(tok(p), toklen(p));
- if (kw) {
- enum lex_state_e state = p->lex.state;
- if (IS_lex_state_for(state, EXPR_FNAME)) {
- SET_LEX_STATE(EXPR_ENDFN);
- set_yylval_name(rb_intern2(tok(p), toklen(p)));
- return kw->id[0];
- }
- SET_LEX_STATE(kw->state);
- if (IS_lex_state(EXPR_BEG)) {
- p->command_start = TRUE;
- }
- if (kw->id[0] == keyword_do) {
- if (lambda_beginning_p()) {
- p->lex.lpar_beg = -1; /* make lambda_beginning_p() == FALSE in the body of "-> do ... end" */
- return keyword_do_LAMBDA;
- }
- if (COND_P()) return keyword_do_cond;
- if (CMDARG_P() && !IS_lex_state_for(state, EXPR_CMDARG))
- return keyword_do_block;
- return keyword_do;
- }
- if (IS_lex_state_for(state, (EXPR_BEG | EXPR_LABELED | EXPR_CLASS)))
- return kw->id[0];
- else {
- if (kw->id[0] != kw->id[1])
- SET_LEX_STATE(EXPR_BEG | EXPR_LABEL);
- return kw->id[1];
- }
- }
+ const struct kwtable *kw;
+
+ /* See if it is a reserved word. */
+ kw = rb_reserved_word(tok(p), toklen(p));
+ if (kw) {
+ enum lex_state_e state = p->lex.state;
+ if (IS_lex_state_for(state, EXPR_FNAME)) {
+ SET_LEX_STATE(EXPR_ENDFN);
+ set_yylval_name(rb_intern2(tok(p), toklen(p)));
+ return kw->id[0];
+ }
+ SET_LEX_STATE(kw->state);
+ if (IS_lex_state(EXPR_BEG)) {
+ p->command_start = TRUE;
+ }
+ if (kw->id[0] == keyword_do) {
+ if (lambda_beginning_p()) {
+ p->lex.lpar_beg = -1; /* make lambda_beginning_p() == FALSE in the body of "-> do ... end" */
+ return keyword_do_LAMBDA;
+ }
+ if (COND_P()) return keyword_do_cond;
+ if (CMDARG_P() && !IS_lex_state_for(state, EXPR_CMDARG))
+ return keyword_do_block;
+ return keyword_do;
+ }
+ if (IS_lex_state_for(state, (EXPR_BEG | EXPR_LABELED | EXPR_CLASS)))
+ return kw->id[0];
+ else {
+ if (kw->id[0] != kw->id[1])
+ SET_LEX_STATE(EXPR_BEG | EXPR_LABEL);
+ return kw->id[1];
+ }
+ }
}
if (IS_lex_state(EXPR_BEG_ANY | EXPR_ARG_ANY | EXPR_DOT)) {
- if (cmd_state) {
- SET_LEX_STATE(EXPR_CMDARG);
- }
- else {
- SET_LEX_STATE(EXPR_ARG);
- }
+ if (cmd_state) {
+ SET_LEX_STATE(EXPR_CMDARG);
+ }
+ else {
+ SET_LEX_STATE(EXPR_ARG);
+ }
}
else if (p->lex.state == EXPR_FNAME) {
- SET_LEX_STATE(EXPR_ENDFN);
+ SET_LEX_STATE(EXPR_ENDFN);
}
else {
- SET_LEX_STATE(EXPR_END);
+ SET_LEX_STATE(EXPR_END);
}
- ident = tokenize_ident(p);
+ ident = tokenize_ident(p, last_state);
if (result == tCONSTANT && is_local_id(ident)) result = tIDENTIFIER;
if (!IS_lex_state_for(last_state, EXPR_DOT|EXPR_FNAME) &&
(result == tIDENTIFIER) && /* not EXPR_FNAME, not attrasgn */
@@ -10382,9 +9817,9 @@ static void
warn_cr(struct parser_params *p)
{
if (!p->cr_seen) {
- p->cr_seen = TRUE;
- /* carried over with p->lex.nextline for nextc() */
- rb_warn0("encountered \\r in middle of line, treated as a mere space");
+ p->cr_seen = TRUE;
+ /* carried over with p->lex.nextline for nextc() */
+ rb_warn0("encountered \\r in middle of line, treated as a mere space");
}
}
@@ -10400,14 +9835,14 @@ parser_yylex(struct parser_params *p)
int token_seen = p->token_seen;
if (p->lex.strterm) {
- if (strterm_is_heredoc(p->lex.strterm)) {
- token_flush(p);
- return here_document(p, &p->lex.strterm->u.heredoc);
- }
- else {
- token_flush(p);
- return parse_string(p, &p->lex.strterm->u.literal);
- }
+ if (p->lex.strterm->flags & STRTERM_HEREDOC) {
+ token_flush(p);
+ return here_document(p, &p->lex.strterm->u.heredoc);
+ }
+ else {
+ token_flush(p);
+ return parse_string(p, &p->lex.strterm->u.literal);
+ }
}
cmd_state = p->command_start;
p->command_start = FALSE;
@@ -10422,687 +9857,686 @@ parser_yylex(struct parser_params *p)
case '\004': /* ^D */
case '\032': /* ^Z */
case -1: /* end of script. */
- p->eofp = 1;
+ p->eofp = 1;
#ifndef RIPPER
- if (!NIL_P(p->end_expect_token_locations) && RARRAY_LEN(p->end_expect_token_locations) > 0) {
- pop_end_expect_token_locations(p);
- RUBY_SET_YYLLOC_OF_DUMMY_END(*p->yylloc);
- return tDUMNY_END;
- }
+ if (!NIL_P(p->end_expect_token_locations) && RARRAY_LEN(p->end_expect_token_locations) > 0) {
+ pop_end_expect_token_locations(p);
+ RUBY_SET_YYLLOC_OF_DUMMY_END(*p->yylloc);
+ return tDUMNY_END;
+ }
#endif
- /* Set location for end-of-input because dispatch_scan_event is not called. */
- RUBY_SET_YYLLOC(*p->yylloc);
- return END_OF_INPUT;
+ /* Set location for end-of-input because dispatch_scan_event is not called. */
+ RUBY_SET_YYLLOC(*p->yylloc);
+ return 0;
- /* white spaces */
+ /* white spaces */
case '\r':
- warn_cr(p);
- /* fall through */
+ warn_cr(p);
+ /* fall through */
case ' ': case '\t': case '\f':
case '\13': /* '\v' */
- space_seen = 1;
- while ((c = nextc(p))) {
- switch (c) {
- case '\r':
- warn_cr(p);
- /* fall through */
- case ' ': case '\t': case '\f':
- case '\13': /* '\v' */
- break;
- default:
- goto outofloop;
- }
- }
+ space_seen = 1;
+ while ((c = nextc(p))) {
+ switch (c) {
+ case '\r':
+ warn_cr(p);
+ /* fall through */
+ case ' ': case '\t': case '\f':
+ case '\13': /* '\v' */
+ break;
+ default:
+ goto outofloop;
+ }
+ }
outofloop:
- pushback(p, c);
- dispatch_scan_event(p, tSP);
+ pushback(p, c);
+ dispatch_scan_event(p, tSP);
#ifndef RIPPER
- token_flush(p);
+ token_flush(p);
#endif
- goto retry;
+ goto retry;
case '#': /* it's a comment */
- p->token_seen = token_seen;
- /* no magic_comment in shebang line */
- if (!parser_magic_comment(p, p->lex.pcur, p->lex.pend - p->lex.pcur)) {
- if (comment_at_top(p)) {
- set_file_encoding(p, p->lex.pcur, p->lex.pend);
- }
- }
- lex_goto_eol(p);
+ p->token_seen = token_seen;
+ /* no magic_comment in shebang line */
+ if (!parser_magic_comment(p, p->lex.pcur, p->lex.pend - p->lex.pcur)) {
+ if (comment_at_top(p)) {
+ set_file_encoding(p, p->lex.pcur, p->lex.pend);
+ }
+ }
+ lex_goto_eol(p);
dispatch_scan_event(p, tCOMMENT);
fallthru = TRUE;
- /* fall through */
+ /* fall through */
case '\n':
- p->token_seen = token_seen;
- VALUE prevline = p->lex.lastline;
- c = (IS_lex_state(EXPR_BEG|EXPR_CLASS|EXPR_FNAME|EXPR_DOT) &&
- !IS_lex_state(EXPR_LABELED));
- if (c || IS_lex_state_all(EXPR_ARG|EXPR_LABELED)) {
+ p->token_seen = token_seen;
+ c = (IS_lex_state(EXPR_BEG|EXPR_CLASS|EXPR_FNAME|EXPR_DOT) &&
+ !IS_lex_state(EXPR_LABELED));
+ if (c || IS_lex_state_all(EXPR_ARG|EXPR_LABELED)) {
if (!fallthru) {
dispatch_scan_event(p, tIGNORED_NL);
}
fallthru = FALSE;
- if (!c && p->ctxt.in_kwarg) {
- goto normal_newline;
- }
- goto retry;
- }
- while (1) {
- switch (c = nextc(p)) {
- case ' ': case '\t': case '\f': case '\r':
- case '\13': /* '\v' */
- space_seen = 1;
- break;
- case '#':
- pushback(p, c);
- if (space_seen) {
- dispatch_scan_event(p, tSP);
- token_flush(p);
- }
- goto retry;
- case '&':
- case '.': {
- dispatch_delayed_token(p, tIGNORED_NL);
- if (peek(p, '.') == (c == '&')) {
- pushback(p, c);
- dispatch_scan_event(p, tSP);
- goto retry;
- }
- }
- default:
- p->ruby_sourceline--;
- p->lex.nextline = p->lex.lastline;
- set_lastline(p, prevline);
- case -1: /* EOF no decrement*/
- lex_goto_eol(p);
- if (c != -1) {
- token_flush(p);
- RUBY_SET_YYLLOC(*p->yylloc);
- }
- goto normal_newline;
- }
- }
+ if (!c && p->ctxt.in_kwarg) {
+ goto normal_newline;
+ }
+ goto retry;
+ }
+ while (1) {
+ switch (c = nextc(p)) {
+ case ' ': case '\t': case '\f': case '\r':
+ case '\13': /* '\v' */
+ space_seen = 1;
+ break;
+ case '#':
+ pushback(p, c);
+ if (space_seen) {
+ dispatch_scan_event(p, tSP);
+ token_flush(p);
+ }
+ goto retry;
+ case '&':
+ case '.': {
+ dispatch_delayed_token(p, tIGNORED_NL);
+ if (peek(p, '.') == (c == '&')) {
+ pushback(p, c);
+ dispatch_scan_event(p, tSP);
+ goto retry;
+ }
+ }
+ default:
+ p->ruby_sourceline--;
+ p->lex.nextline = p->lex.lastline;
+ case -1: /* EOF no decrement*/
+ lex_goto_eol(p);
+ if (c != -1) {
+ p->lex.ptok = p->lex.pcur;
+ }
+ goto normal_newline;
+ }
+ }
normal_newline:
- p->command_start = TRUE;
- SET_LEX_STATE(EXPR_BEG);
- return '\n';
+ p->command_start = TRUE;
+ SET_LEX_STATE(EXPR_BEG);
+ return '\n';
case '*':
- if ((c = nextc(p)) == '*') {
- if ((c = nextc(p)) == '=') {
- set_yylval_id(idPow);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- rb_warning0("`**' interpreted as argument prefix");
- c = tDSTAR;
- }
- else if (IS_BEG()) {
- c = tDSTAR;
- }
- else {
- c = warn_balanced((enum ruby_method_ids)tPOW, "**", "argument prefix");
- }
- }
- else {
- if (c == '=') {
+ if ((c = nextc(p)) == '*') {
+ if ((c = nextc(p)) == '=') {
+ set_yylval_id(idPow);
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ rb_warning0("`**' interpreted as argument prefix");
+ c = tDSTAR;
+ }
+ else if (IS_BEG()) {
+ c = tDSTAR;
+ }
+ else {
+ c = warn_balanced((enum ruby_method_ids)tPOW, "**", "argument prefix");
+ }
+ }
+ else {
+ if (c == '=') {
set_yylval_id('*');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- rb_warning0("`*' interpreted as argument prefix");
- c = tSTAR;
- }
- else if (IS_BEG()) {
- c = tSTAR;
- }
- else {
- c = warn_balanced('*', "*", "argument prefix");
- }
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- return c;
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ rb_warning0("`*' interpreted as argument prefix");
+ c = tSTAR;
+ }
+ else if (IS_BEG()) {
+ c = tSTAR;
+ }
+ else {
+ c = warn_balanced('*', "*", "argument prefix");
+ }
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ return c;
case '!':
- c = nextc(p);
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- if (c == '@') {
- return '!';
- }
- }
- else {
- SET_LEX_STATE(EXPR_BEG);
- }
- if (c == '=') {
- return tNEQ;
- }
- if (c == '~') {
- return tNMATCH;
- }
- pushback(p, c);
- return '!';
+ c = nextc(p);
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ if (c == '@') {
+ return '!';
+ }
+ }
+ else {
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ if (c == '=') {
+ return tNEQ;
+ }
+ if (c == '~') {
+ return tNMATCH;
+ }
+ pushback(p, c);
+ return '!';
case '=':
- if (was_bol(p)) {
- /* skip embedded rd document */
- if (word_match_p(p, "begin", 5)) {
- int first_p = TRUE;
-
- lex_goto_eol(p);
- dispatch_scan_event(p, tEMBDOC_BEG);
- for (;;) {
- lex_goto_eol(p);
- if (!first_p) {
- dispatch_scan_event(p, tEMBDOC);
- }
- first_p = FALSE;
- c = nextc(p);
- if (c == -1) {
- compile_error(p, "embedded document meets end of file");
- return END_OF_INPUT;
- }
- if (c == '=' && word_match_p(p, "end", 3)) {
- break;
- }
- pushback(p, c);
- }
- lex_goto_eol(p);
- dispatch_scan_event(p, tEMBDOC_END);
- goto retry;
- }
- }
-
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- if ((c = nextc(p)) == '=') {
- if ((c = nextc(p)) == '=') {
- return tEQQ;
- }
- pushback(p, c);
- return tEQ;
- }
- if (c == '~') {
- return tMATCH;
- }
- else if (c == '>') {
- return tASSOC;
- }
- pushback(p, c);
- return '=';
+ if (was_bol(p)) {
+ /* skip embedded rd document */
+ if (word_match_p(p, "begin", 5)) {
+ int first_p = TRUE;
+
+ lex_goto_eol(p);
+ dispatch_scan_event(p, tEMBDOC_BEG);
+ for (;;) {
+ lex_goto_eol(p);
+ if (!first_p) {
+ dispatch_scan_event(p, tEMBDOC);
+ }
+ first_p = FALSE;
+ c = nextc(p);
+ if (c == -1) {
+ compile_error(p, "embedded document meets end of file");
+ return 0;
+ }
+ if (c == '=' && word_match_p(p, "end", 3)) {
+ break;
+ }
+ pushback(p, c);
+ }
+ lex_goto_eol(p);
+ dispatch_scan_event(p, tEMBDOC_END);
+ goto retry;
+ }
+ }
+
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '=') {
+ return tEQQ;
+ }
+ pushback(p, c);
+ return tEQ;
+ }
+ if (c == '~') {
+ return tMATCH;
+ }
+ else if (c == '>') {
+ return tASSOC;
+ }
+ pushback(p, c);
+ return '=';
case '<':
- c = nextc(p);
- if (c == '<' &&
- !IS_lex_state(EXPR_DOT | EXPR_CLASS) &&
- !IS_END() &&
- (!IS_ARG() || IS_lex_state(EXPR_LABELED) || space_seen)) {
- int token = heredoc_identifier(p);
- if (token) return token < 0 ? 0 : token;
- }
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- }
- else {
- if (IS_lex_state(EXPR_CLASS))
- p->command_start = TRUE;
- SET_LEX_STATE(EXPR_BEG);
- }
- if (c == '=') {
- if ((c = nextc(p)) == '>') {
- return tCMP;
- }
- pushback(p, c);
- return tLEQ;
- }
- if (c == '<') {
- if ((c = nextc(p)) == '=') {
- set_yylval_id(idLTLT);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- return warn_balanced((enum ruby_method_ids)tLSHFT, "<<", "here document");
- }
- pushback(p, c);
- return '<';
+ c = nextc(p);
+ if (c == '<' &&
+ !IS_lex_state(EXPR_DOT | EXPR_CLASS) &&
+ !IS_END() &&
+ (!IS_ARG() || IS_lex_state(EXPR_LABELED) || space_seen)) {
+ int token = heredoc_identifier(p);
+ if (token) return token < 0 ? 0 : token;
+ }
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ }
+ else {
+ if (IS_lex_state(EXPR_CLASS))
+ p->command_start = TRUE;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ if (c == '=') {
+ if ((c = nextc(p)) == '>') {
+ return tCMP;
+ }
+ pushback(p, c);
+ return tLEQ;
+ }
+ if (c == '<') {
+ if ((c = nextc(p)) == '=') {
+ set_yylval_id(idLTLT);
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return warn_balanced((enum ruby_method_ids)tLSHFT, "<<", "here document");
+ }
+ pushback(p, c);
+ return '<';
case '>':
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- if ((c = nextc(p)) == '=') {
- return tGEQ;
- }
- if (c == '>') {
- if ((c = nextc(p)) == '=') {
- set_yylval_id(idGTGT);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- return tRSHFT;
- }
- pushback(p, c);
- return '>';
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
+ return tGEQ;
+ }
+ if (c == '>') {
+ if ((c = nextc(p)) == '=') {
+ set_yylval_id(idGTGT);
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tRSHFT;
+ }
+ pushback(p, c);
+ return '>';
case '"':
- label = (IS_LABEL_POSSIBLE() ? str_label : 0);
- p->lex.strterm = NEW_STRTERM(str_dquote | label, '"', 0);
- p->lex.ptok = p->lex.pcur-1;
- return tSTRING_BEG;
+ label = (IS_LABEL_POSSIBLE() ? str_label : 0);
+ p->lex.strterm = NEW_STRTERM(str_dquote | label, '"', 0);
+ p->lex.ptok = p->lex.pcur-1;
+ return tSTRING_BEG;
case '`':
- if (IS_lex_state(EXPR_FNAME)) {
- SET_LEX_STATE(EXPR_ENDFN);
- return c;
- }
- if (IS_lex_state(EXPR_DOT)) {
- if (cmd_state)
- SET_LEX_STATE(EXPR_CMDARG);
- else
- SET_LEX_STATE(EXPR_ARG);
- return c;
- }
- p->lex.strterm = NEW_STRTERM(str_xquote, '`', 0);
- return tXSTRING_BEG;
+ if (IS_lex_state(EXPR_FNAME)) {
+ SET_LEX_STATE(EXPR_ENDFN);
+ return c;
+ }
+ if (IS_lex_state(EXPR_DOT)) {
+ if (cmd_state)
+ SET_LEX_STATE(EXPR_CMDARG);
+ else
+ SET_LEX_STATE(EXPR_ARG);
+ return c;
+ }
+ p->lex.strterm = NEW_STRTERM(str_xquote, '`', 0);
+ return tXSTRING_BEG;
case '\'':
- label = (IS_LABEL_POSSIBLE() ? str_label : 0);
- p->lex.strterm = NEW_STRTERM(str_squote | label, '\'', 0);
- p->lex.ptok = p->lex.pcur-1;
- return tSTRING_BEG;
+ label = (IS_LABEL_POSSIBLE() ? str_label : 0);
+ p->lex.strterm = NEW_STRTERM(str_squote | label, '\'', 0);
+ p->lex.ptok = p->lex.pcur-1;
+ return tSTRING_BEG;
case '?':
- return parse_qmark(p, space_seen);
+ return parse_qmark(p, space_seen);
case '&':
- if ((c = nextc(p)) == '&') {
- SET_LEX_STATE(EXPR_BEG);
- if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '&') {
+ SET_LEX_STATE(EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
set_yylval_id(idANDOP);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- return tANDOP;
- }
- else if (c == '=') {
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tANDOP;
+ }
+ else if (c == '=') {
set_yylval_id('&');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- else if (c == '.') {
- set_yylval_id(idANDDOT);
- SET_LEX_STATE(EXPR_DOT);
- return tANDDOT;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- if ((c != ':') ||
- (c = peekc_n(p, 1)) == -1 ||
- !(c == '\'' || c == '"' ||
- is_identchar(p, (p->lex.pcur+1), p->lex.pend, p->enc))) {
- rb_warning0("`&' interpreted as argument prefix");
- }
- c = tAMPER;
- }
- else if (IS_BEG()) {
- c = tAMPER;
- }
- else {
- c = warn_balanced('&', "&", "argument prefix");
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- return c;
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ else if (c == '.') {
+ set_yylval_id(idANDDOT);
+ SET_LEX_STATE(EXPR_DOT);
+ return tANDDOT;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ if ((c != ':') ||
+ (c = peekc_n(p, 1)) == -1 ||
+ !(c == '\'' || c == '"' ||
+ is_identchar((p->lex.pcur+1), p->lex.pend, p->enc))) {
+ rb_warning0("`&' interpreted as argument prefix");
+ }
+ c = tAMPER;
+ }
+ else if (IS_BEG()) {
+ c = tAMPER;
+ }
+ else {
+ c = warn_balanced('&', "&", "argument prefix");
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ return c;
case '|':
- if ((c = nextc(p)) == '|') {
- SET_LEX_STATE(EXPR_BEG);
- if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '|') {
+ SET_LEX_STATE(EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
set_yylval_id(idOROP);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_lex_state_for(last_state, EXPR_BEG)) {
- c = '|';
- pushback(p, '|');
- return c;
- }
- return tOROP;
- }
- if (c == '=') {
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_lex_state_for(last_state, EXPR_BEG)) {
+ c = '|';
+ pushback(p, '|');
+ return c;
+ }
+ return tOROP;
+ }
+ if (c == '=') {
set_yylval_id('|');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL);
- pushback(p, c);
- return '|';
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL);
+ pushback(p, c);
+ return '|';
case '+':
- c = nextc(p);
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- if (c == '@') {
- return tUPLUS;
- }
- pushback(p, c);
- return '+';
- }
- if (c == '=') {
+ c = nextc(p);
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ if (c == '@') {
+ return tUPLUS;
+ }
+ pushback(p, c);
+ return '+';
+ }
+ if (c == '=') {
set_yylval_id('+');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '+'))) {
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- return parse_numeric(p, '+');
- }
- return tUPLUS;
- }
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- return warn_balanced('+', "+", "unary operator");
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '+'))) {
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ if (c != -1 && ISDIGIT(c)) {
+ return parse_numeric(p, '+');
+ }
+ return tUPLUS;
+ }
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ return warn_balanced('+', "+", "unary operator");
case '-':
- c = nextc(p);
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- if (c == '@') {
- return tUMINUS;
- }
- pushback(p, c);
- return '-';
- }
- if (c == '=') {
+ c = nextc(p);
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ if (c == '@') {
+ return tUMINUS;
+ }
+ pushback(p, c);
+ return '-';
+ }
+ if (c == '=') {
set_yylval_id('-');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- if (c == '>') {
- SET_LEX_STATE(EXPR_ENDFN);
- return tLAMBDA;
- }
- if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '-'))) {
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- return tUMINUS_NUM;
- }
- return tUMINUS;
- }
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- return warn_balanced('-', "-", "unary operator");
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ if (c == '>') {
+ SET_LEX_STATE(EXPR_ENDFN);
+ return tLAMBDA;
+ }
+ if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '-'))) {
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ if (c != -1 && ISDIGIT(c)) {
+ return tUMINUS_NUM;
+ }
+ return tUMINUS;
+ }
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ return warn_balanced('-', "-", "unary operator");
case '.': {
int is_beg = IS_BEG();
- SET_LEX_STATE(EXPR_BEG);
- if ((c = nextc(p)) == '.') {
- if ((c = nextc(p)) == '.') {
- if (p->ctxt.in_argdef) {
- SET_LEX_STATE(EXPR_ENDARG);
- return tBDOT3;
- }
- if (p->lex.paren_nest == 0 && looking_at_eol_p(p)) {
- rb_warn0("... at EOL, should be parenthesized?");
- }
- else if (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest) {
- if (IS_lex_state_for(last_state, EXPR_LABEL))
- return tDOT3;
- }
- return is_beg ? tBDOT3 : tDOT3;
- }
- pushback(p, c);
- return is_beg ? tBDOT2 : tDOT2;
- }
- pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- char prev = p->lex.pcur-1 > p->lex.pbeg ? *(p->lex.pcur-2) : 0;
- parse_numeric(p, '.');
- if (ISDIGIT(prev)) {
- yyerror0("unexpected fraction part after numeric literal");
- }
- else {
- yyerror0("no .<digit> floating literal anymore; put 0 before dot");
- }
- SET_LEX_STATE(EXPR_END);
- p->lex.ptok = p->lex.pcur;
- goto retry;
- }
- set_yylval_id('.');
- SET_LEX_STATE(EXPR_DOT);
- return '.';
+ SET_LEX_STATE(EXPR_BEG);
+ if ((c = nextc(p)) == '.') {
+ if ((c = nextc(p)) == '.') {
+ if (p->ctxt.in_argdef) {
+ SET_LEX_STATE(EXPR_ENDARG);
+ return tBDOT3;
+ }
+ if (p->lex.paren_nest == 0 && looking_at_eol_p(p)) {
+ rb_warn0("... at EOL, should be parenthesized?");
+ }
+ else if (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest) {
+ if (IS_lex_state_for(last_state, EXPR_LABEL))
+ return tDOT3;
+ }
+ return is_beg ? tBDOT3 : tDOT3;
+ }
+ pushback(p, c);
+ return is_beg ? tBDOT2 : tDOT2;
+ }
+ pushback(p, c);
+ if (c != -1 && ISDIGIT(c)) {
+ char prev = p->lex.pcur-1 > p->lex.pbeg ? *(p->lex.pcur-2) : 0;
+ parse_numeric(p, '.');
+ if (ISDIGIT(prev)) {
+ yyerror0("unexpected fraction part after numeric literal");
+ }
+ else {
+ yyerror0("no .<digit> floating literal anymore; put 0 before dot");
+ }
+ SET_LEX_STATE(EXPR_END);
+ p->lex.ptok = p->lex.pcur;
+ goto retry;
+ }
+ set_yylval_id('.');
+ SET_LEX_STATE(EXPR_DOT);
+ return '.';
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- return parse_numeric(p, c);
+ return parse_numeric(p, c);
case ')':
- COND_POP();
- CMDARG_POP();
- SET_LEX_STATE(EXPR_ENDFN);
- p->lex.paren_nest--;
- return c;
+ COND_POP();
+ CMDARG_POP();
+ SET_LEX_STATE(EXPR_ENDFN);
+ p->lex.paren_nest--;
+ return c;
case ']':
- COND_POP();
- CMDARG_POP();
- SET_LEX_STATE(EXPR_END);
- p->lex.paren_nest--;
- return c;
+ COND_POP();
+ CMDARG_POP();
+ SET_LEX_STATE(EXPR_END);
+ p->lex.paren_nest--;
+ return c;
case '}':
- /* tSTRING_DEND does COND_POP and CMDARG_POP in the yacc's rule */
- if (!p->lex.brace_nest--) return tSTRING_DEND;
- COND_POP();
- CMDARG_POP();
- SET_LEX_STATE(EXPR_END);
- p->lex.paren_nest--;
- return c;
+ /* tSTRING_DEND does COND_POP and CMDARG_POP in the yacc's rule */
+ if (!p->lex.brace_nest--) return tSTRING_DEND;
+ COND_POP();
+ CMDARG_POP();
+ SET_LEX_STATE(EXPR_END);
+ p->lex.paren_nest--;
+ return c;
case ':':
- c = nextc(p);
- if (c == ':') {
- if (IS_BEG() || IS_lex_state(EXPR_CLASS) || IS_SPCARG(-1)) {
- SET_LEX_STATE(EXPR_BEG);
- return tCOLON3;
- }
- set_yylval_id(idCOLON2);
- SET_LEX_STATE(EXPR_DOT);
- return tCOLON2;
- }
- if (IS_END() || ISSPACE(c) || c == '#') {
- pushback(p, c);
- c = warn_balanced(':', ":", "symbol literal");
- SET_LEX_STATE(EXPR_BEG);
- return c;
- }
- switch (c) {
- case '\'':
- p->lex.strterm = NEW_STRTERM(str_ssym, c, 0);
- break;
- case '"':
- p->lex.strterm = NEW_STRTERM(str_dsym, c, 0);
- break;
- default:
- pushback(p, c);
- break;
- }
- SET_LEX_STATE(EXPR_FNAME);
- return tSYMBEG;
+ c = nextc(p);
+ if (c == ':') {
+ if (IS_BEG() || IS_lex_state(EXPR_CLASS) || IS_SPCARG(-1)) {
+ SET_LEX_STATE(EXPR_BEG);
+ return tCOLON3;
+ }
+ set_yylval_id(idCOLON2);
+ SET_LEX_STATE(EXPR_DOT);
+ return tCOLON2;
+ }
+ if (IS_END() || ISSPACE(c) || c == '#') {
+ pushback(p, c);
+ c = warn_balanced(':', ":", "symbol literal");
+ SET_LEX_STATE(EXPR_BEG);
+ return c;
+ }
+ switch (c) {
+ case '\'':
+ p->lex.strterm = NEW_STRTERM(str_ssym, c, 0);
+ break;
+ case '"':
+ p->lex.strterm = NEW_STRTERM(str_dsym, c, 0);
+ break;
+ default:
+ pushback(p, c);
+ break;
+ }
+ SET_LEX_STATE(EXPR_FNAME);
+ return tSYMBEG;
case '/':
- if (IS_BEG()) {
- p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
- return tREGEXP_BEG;
- }
- if ((c = nextc(p)) == '=') {
+ if (IS_BEG()) {
+ p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
+ return tREGEXP_BEG;
+ }
+ if ((c = nextc(p)) == '=') {
set_yylval_id('/');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- arg_ambiguous(p, '/');
- p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
- return tREGEXP_BEG;
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- return warn_balanced('/', "/", "regexp literal");
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ arg_ambiguous(p, '/');
+ p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
+ return tREGEXP_BEG;
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ return warn_balanced('/', "/", "regexp literal");
case '^':
- if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '=') {
set_yylval_id('^');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- pushback(p, c);
- return '^';
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ pushback(p, c);
+ return '^';
case ';':
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- return ';';
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ return ';';
case ',':
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- return ',';
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ return ',';
case '~':
- if (IS_AFTER_OPERATOR()) {
- if ((c = nextc(p)) != '@') {
- pushback(p, c);
- }
- SET_LEX_STATE(EXPR_ARG);
- }
- else {
- SET_LEX_STATE(EXPR_BEG);
- }
- return '~';
+ if (IS_AFTER_OPERATOR()) {
+ if ((c = nextc(p)) != '@') {
+ pushback(p, c);
+ }
+ SET_LEX_STATE(EXPR_ARG);
+ }
+ else {
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ return '~';
case '(':
- if (IS_BEG()) {
- c = tLPAREN;
- }
- else if (!space_seen) {
- /* foo( ... ) => method call, no ambiguity */
- }
- else if (IS_ARG() || IS_lex_state_all(EXPR_END|EXPR_LABEL)) {
- c = tLPAREN_ARG;
- }
- else if (IS_lex_state(EXPR_ENDFN) && !lambda_beginning_p()) {
- rb_warning0("parentheses after method name is interpreted as "
- "an argument list, not a decomposed argument");
- }
- p->lex.paren_nest++;
- COND_PUSH(0);
- CMDARG_PUSH(0);
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- return c;
+ if (IS_BEG()) {
+ c = tLPAREN;
+ }
+ else if (!space_seen) {
+ /* foo( ... ) => method call, no ambiguity */
+ }
+ else if (IS_ARG() || IS_lex_state_all(EXPR_END|EXPR_LABEL)) {
+ c = tLPAREN_ARG;
+ }
+ else if (IS_lex_state(EXPR_ENDFN) && !lambda_beginning_p()) {
+ rb_warning0("parentheses after method name is interpreted as "
+ "an argument list, not a decomposed argument");
+ }
+ p->lex.paren_nest++;
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ return c;
case '[':
- p->lex.paren_nest++;
- if (IS_AFTER_OPERATOR()) {
- if ((c = nextc(p)) == ']') {
- p->lex.paren_nest--;
- SET_LEX_STATE(EXPR_ARG);
- if ((c = nextc(p)) == '=') {
- return tASET;
- }
- pushback(p, c);
- return tAREF;
- }
- pushback(p, c);
- SET_LEX_STATE(EXPR_ARG|EXPR_LABEL);
- return '[';
- }
- else if (IS_BEG()) {
- c = tLBRACK;
- }
- else if (IS_ARG() && (space_seen || IS_lex_state(EXPR_LABELED))) {
- c = tLBRACK;
- }
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- COND_PUSH(0);
- CMDARG_PUSH(0);
- return c;
+ p->lex.paren_nest++;
+ if (IS_AFTER_OPERATOR()) {
+ if ((c = nextc(p)) == ']') {
+ p->lex.paren_nest--;
+ SET_LEX_STATE(EXPR_ARG);
+ if ((c = nextc(p)) == '=') {
+ return tASET;
+ }
+ pushback(p, c);
+ return tAREF;
+ }
+ pushback(p, c);
+ SET_LEX_STATE(EXPR_ARG|EXPR_LABEL);
+ return '[';
+ }
+ else if (IS_BEG()) {
+ c = tLBRACK;
+ }
+ else if (IS_ARG() && (space_seen || IS_lex_state(EXPR_LABELED))) {
+ c = tLBRACK;
+ }
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ return c;
case '{':
- ++p->lex.brace_nest;
- if (lambda_beginning_p())
- c = tLAMBEG;
- else if (IS_lex_state(EXPR_LABELED))
- c = tLBRACE; /* hash */
- else if (IS_lex_state(EXPR_ARG_ANY | EXPR_END | EXPR_ENDFN))
- c = '{'; /* block (primary) */
- else if (IS_lex_state(EXPR_ENDARG))
- c = tLBRACE_ARG; /* block (expr) */
- else
- c = tLBRACE; /* hash */
- if (c != tLBRACE) {
- p->command_start = TRUE;
- SET_LEX_STATE(EXPR_BEG);
- }
- else {
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- }
- ++p->lex.paren_nest; /* after lambda_beginning_p() */
- COND_PUSH(0);
- CMDARG_PUSH(0);
- return c;
+ ++p->lex.brace_nest;
+ if (lambda_beginning_p())
+ c = tLAMBEG;
+ else if (IS_lex_state(EXPR_LABELED))
+ c = tLBRACE; /* hash */
+ else if (IS_lex_state(EXPR_ARG_ANY | EXPR_END | EXPR_ENDFN))
+ c = '{'; /* block (primary) */
+ else if (IS_lex_state(EXPR_ENDARG))
+ c = tLBRACE_ARG; /* block (expr) */
+ else
+ c = tLBRACE; /* hash */
+ if (c != tLBRACE) {
+ p->command_start = TRUE;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ else {
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ }
+ ++p->lex.paren_nest; /* after lambda_beginning_p() */
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ return c;
case '\\':
- c = nextc(p);
- if (c == '\n') {
- space_seen = 1;
- dispatch_scan_event(p, tSP);
- goto retry; /* skip \\n */
- }
- if (c == ' ') return tSP;
- if (ISSPACE(c)) return c;
- pushback(p, c);
- return '\\';
+ c = nextc(p);
+ if (c == '\n') {
+ space_seen = 1;
+ dispatch_scan_event(p, tSP);
+ goto retry; /* skip \\n */
+ }
+ if (c == ' ') return tSP;
+ if (ISSPACE(c)) return c;
+ pushback(p, c);
+ return '\\';
case '%':
- return parse_percent(p, space_seen, last_state);
+ return parse_percent(p, space_seen, last_state);
case '$':
- return parse_gvar(p, last_state);
+ return parse_gvar(p, last_state);
case '@':
- return parse_atmark(p, last_state);
+ return parse_atmark(p, last_state);
case '_':
- if (was_bol(p) && whole_match_p(p, "__END__", 7, 0)) {
- p->ruby__end__seen = 1;
- p->eofp = 1;
-#ifdef RIPPER
+ if (was_bol(p) && whole_match_p(p, "__END__", 7, 0)) {
+ p->ruby__end__seen = 1;
+ p->eofp = 1;
+#ifndef RIPPER
+ return -1;
+#else
lex_goto_eol(p);
dispatch_scan_event(p, k__END__);
+ return 0;
#endif
- return END_OF_INPUT;
- }
- newtok(p);
- break;
+ }
+ newtok(p);
+ break;
default:
- if (!parser_is_identchar(p)) {
- compile_error(p, "Invalid char `\\x%02X' in expression", c);
+ if (!parser_is_identchar(p)) {
+ compile_error(p, "Invalid char `\\x%02X' in expression", c);
token_flush(p);
- goto retry;
- }
+ goto retry;
+ }
- newtok(p);
- break;
+ newtok(p);
+ break;
}
return parse_ident(p, c, cmd_state);
@@ -11120,9 +10554,9 @@ yylex(YYSTYPE *lval, YYLTYPE *yylloc, struct parser_params *p)
t = parser_yylex(p);
if (has_delayed_token(p))
- dispatch_delayed_token(p, t);
- else if (t != END_OF_INPUT)
- dispatch_scan_event(p, t);
+ dispatch_delayed_token(p, t);
+ else if (t != 0)
+ dispatch_scan_event(p, t);
return t;
}
@@ -11130,1113 +10564,30 @@ yylex(YYSTYPE *lval, YYLTYPE *yylloc, struct parser_params *p)
#define LVAR_USED ((ID)1 << (sizeof(ID) * CHAR_BIT - 1))
static NODE*
-node_new_internal(struct parser_params *p, enum node_type type, size_t size, size_t alignment)
+node_new_temporal(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
- NODE *n = rb_ast_newnode(p->ast, type, size, alignment);
+ NODE *n = rb_ast_newnode(p->ast, type);
- rb_node_init(n, type);
+ rb_node_init(n, type, a0, a1, a2);
return n;
}
-static NODE *
-nd_set_loc(NODE *nd, const YYLTYPE *loc)
-{
- nd->nd_loc = *loc;
- nd_set_line(nd, loc->beg_pos.lineno);
- return nd;
-}
-
static NODE*
-node_newnode(struct parser_params *p, enum node_type type, size_t size, size_t alignment, const rb_code_location_t *loc)
+node_newnode(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2, const rb_code_location_t *loc)
{
- NODE *n = node_new_internal(p, type, size, alignment);
+ NODE *n = node_new_temporal(p, type, a0, a1, a2);
nd_set_loc(n, loc);
nd_set_node_id(n, parser_get_node_id(p));
return n;
}
-#define NODE_NEWNODE(node_type, type, loc) (type *)(node_newnode(p, node_type, sizeof(type), RUBY_ALIGNOF(type), loc))
-
-#ifndef RIPPER
-
-static rb_node_scope_t *
-rb_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_ast_id_table_t *nd_tbl;
- nd_tbl = local_tbl(p);
- rb_node_scope_t *n = NODE_NEWNODE(NODE_SCOPE, rb_node_scope_t, loc);
- n->nd_tbl = nd_tbl;
- n->nd_body = nd_body;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_scope_t *
-rb_node_scope_new2(struct parser_params *p, rb_ast_id_table_t *nd_tbl, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_scope_t *n = NODE_NEWNODE(NODE_SCOPE, rb_node_scope_t, loc);
- n->nd_tbl = nd_tbl;
- n->nd_body = nd_body;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_defn_t *
-rb_node_defn_new(struct parser_params *p, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc)
-{
- rb_node_defn_t *n = NODE_NEWNODE(NODE_DEFN, rb_node_defn_t, loc);
- n->nd_mid = nd_mid;
- n->nd_defn = nd_defn;
-
- return n;
-}
-
-static rb_node_defs_t *
-rb_node_defs_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc)
-{
- rb_node_defs_t *n = NODE_NEWNODE(NODE_DEFS, rb_node_defs_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_defn = nd_defn;
-
- return n;
-}
-
-static rb_node_block_t *
-rb_node_block_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_block_t *n = NODE_NEWNODE(NODE_BLOCK, rb_node_block_t, loc);
- n->nd_head = nd_head;
- n->nd_end = 0;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_for_t *
-rb_node_for_new(struct parser_params *p, NODE *nd_iter, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_for_t *n = NODE_NEWNODE(NODE_FOR, rb_node_for_t, loc);
- n->nd_body = nd_body;
- n->nd_iter = nd_iter;
-
- return n;
-}
-
-static rb_node_for_masgn_t *
-rb_node_for_masgn_new(struct parser_params *p, NODE *nd_var, const YYLTYPE *loc)
-{
- rb_node_for_masgn_t *n = NODE_NEWNODE(NODE_FOR_MASGN, rb_node_for_masgn_t, loc);
- n->nd_var = nd_var;
-
- return n;
-}
-
-static rb_node_retry_t *
-rb_node_retry_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_retry_t *n = NODE_NEWNODE(NODE_RETRY, rb_node_retry_t, loc);
-
- return n;
-}
-
-static rb_node_begin_t *
-rb_node_begin_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_begin_t *n = NODE_NEWNODE(NODE_BEGIN, rb_node_begin_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_rescue_t *
-rb_node_rescue_new(struct parser_params *p, NODE *nd_head, NODE *nd_resq, NODE *nd_else, const YYLTYPE *loc)
-{
- rb_node_rescue_t *n = NODE_NEWNODE(NODE_RESCUE, rb_node_rescue_t, loc);
- n->nd_head = nd_head;
- n->nd_resq = nd_resq;
- n->nd_else = nd_else;
-
- return n;
-}
-
-static rb_node_resbody_t *
-rb_node_resbody_new(struct parser_params *p, NODE *nd_args, NODE *nd_body, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_resbody_t *n = NODE_NEWNODE(NODE_RESBODY, rb_node_resbody_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_ensure_t *
-rb_node_ensure_new(struct parser_params *p, NODE *nd_head, NODE *nd_ensr, const YYLTYPE *loc)
-{
- rb_node_ensure_t *n = NODE_NEWNODE(NODE_ENSURE, rb_node_ensure_t, loc);
- n->nd_head = nd_head;
- n->nd_resq = 0;
- n->nd_ensr = nd_ensr;
-
- return n;
-}
-
-static rb_node_and_t *
-rb_node_and_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc)
-{
- rb_node_and_t *n = NODE_NEWNODE(NODE_AND, rb_node_and_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
-
- return n;
-}
-
-static rb_node_or_t *
-rb_node_or_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc)
-{
- rb_node_or_t *n = NODE_NEWNODE(NODE_OR, rb_node_or_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
-
- return n;
-}
-
-static rb_node_return_t *
-rb_node_return_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc)
-{
- rb_node_return_t *n = NODE_NEWNODE(NODE_RETURN, rb_node_return_t, loc);
- n->nd_stts = nd_stts;
- return n;
-}
-
-static rb_node_yield_t *
-rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_yield_t *n = NODE_NEWNODE(NODE_YIELD, rb_node_yield_t, loc);
- n->nd_head = nd_head;
-
- return n;
-}
-
-static rb_node_if_t *
-rb_node_if_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc)
-{
- rb_node_if_t *n = NODE_NEWNODE(NODE_IF, rb_node_if_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_else = nd_else;
-
- return n;
-}
-
-static rb_node_unless_t *
-rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc)
-{
- rb_node_unless_t *n = NODE_NEWNODE(NODE_UNLESS, rb_node_unless_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_else = nd_else;
-
- return n;
-}
-
-static rb_node_class_t *
-rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
- rb_node_class_t *n = NODE_NEWNODE(NODE_CLASS, rb_node_class_t, loc);
- n->nd_cpath = nd_cpath;
- n->nd_body = scope;
- n->nd_super = nd_super;
-
- return n;
-}
-
-static rb_node_sclass_t *
-rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
- rb_node_sclass_t *n = NODE_NEWNODE(NODE_SCLASS, rb_node_sclass_t, loc);
- n->nd_recv = nd_recv;
- n->nd_body = scope;
-
- return n;
-}
-
-static rb_node_module_t *
-rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
- rb_node_module_t *n = NODE_NEWNODE(NODE_MODULE, rb_node_module_t, loc);
- n->nd_cpath = nd_cpath;
- n->nd_body = scope;
-
- return n;
-}
-
-static rb_node_iter_t *
-rb_node_iter_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(nd_args, nd_body, loc);
- rb_node_iter_t *n = NODE_NEWNODE(NODE_ITER, rb_node_iter_t, loc);
- n->nd_body = scope;
- n->nd_iter = 0;
-
- return n;
-}
-
-static rb_node_lambda_t *
-rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(nd_args, nd_body, loc);
- rb_node_lambda_t *n = NODE_NEWNODE(NODE_LAMBDA, rb_node_lambda_t, loc);
- n->nd_body = scope;
-
- return n;
-}
-
-static rb_node_case_t *
-rb_node_case_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_case_t *n = NODE_NEWNODE(NODE_CASE, rb_node_case_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_case2_t *
-rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_case2_t *n = NODE_NEWNODE(NODE_CASE2, rb_node_case2_t, loc);
- n->nd_head = 0;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_case3_t *
-rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_case3_t *n = NODE_NEWNODE(NODE_CASE3, rb_node_case3_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_when_t *
-rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_when_t *n = NODE_NEWNODE(NODE_WHEN, rb_node_when_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
- n->nd_next = nd_next;
-
- return n;
-}
-
-static rb_node_in_t *
-rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_in_t *n = NODE_NEWNODE(NODE_IN, rb_node_in_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
- n->nd_next = nd_next;
-
- return n;
-}
-
-static rb_node_while_t *
-rb_node_while_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc)
-{
- rb_node_while_t *n = NODE_NEWNODE(NODE_WHILE, rb_node_while_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_state = nd_state;
-
- return n;
-}
-
-static rb_node_until_t *
-rb_node_until_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc)
-{
- rb_node_until_t *n = NODE_NEWNODE(NODE_UNTIL, rb_node_until_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_state = nd_state;
-
- return n;
-}
-
-static rb_node_colon2_t *
-rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc)
-{
- rb_node_colon2_t *n = NODE_NEWNODE(NODE_COLON2, rb_node_colon2_t, loc);
- n->nd_head = nd_head;
- n->nd_mid = nd_mid;
-
- return n;
-}
-
-static rb_node_colon3_t *
-rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc)
-{
- rb_node_colon3_t *n = NODE_NEWNODE(NODE_COLON3, rb_node_colon3_t, loc);
- n->nd_mid = nd_mid;
-
- return n;
-}
-
-static rb_node_dot2_t *
-rb_node_dot2_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc)
-{
- rb_node_dot2_t *n = NODE_NEWNODE(NODE_DOT2, rb_node_dot2_t, loc);
- n->nd_beg = nd_beg;
- n->nd_end = nd_end;
-
- return n;
-}
-
-static rb_node_dot3_t *
-rb_node_dot3_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc)
-{
- rb_node_dot3_t *n = NODE_NEWNODE(NODE_DOT3, rb_node_dot3_t, loc);
- n->nd_beg = nd_beg;
- n->nd_end = nd_end;
-
- return n;
-}
-
-static rb_node_self_t *
-rb_node_self_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_self_t *n = NODE_NEWNODE(NODE_SELF, rb_node_self_t, loc);
- n->nd_state = 1;
-
- return n;
-}
-
-static rb_node_nil_t *
-rb_node_nil_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_nil_t *n = NODE_NEWNODE(NODE_NIL, rb_node_nil_t, loc);
-
- return n;
-}
-
-static rb_node_true_t *
-rb_node_true_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_true_t *n = NODE_NEWNODE(NODE_TRUE, rb_node_true_t, loc);
-
- return n;
-}
-
-static rb_node_false_t *
-rb_node_false_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_false_t *n = NODE_NEWNODE(NODE_FALSE, rb_node_false_t, loc);
-
- return n;
-}
-
-static rb_node_super_t *
-rb_node_super_new(struct parser_params *p, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_super_t *n = NODE_NEWNODE(NODE_SUPER, rb_node_super_t, loc);
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_zsuper_t *
-rb_node_zsuper_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_zsuper_t *n = NODE_NEWNODE(NODE_ZSUPER, rb_node_zsuper_t, loc);
-
- return n;
-}
-
-static rb_node_match2_t *
-rb_node_match2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_match2_t *n = NODE_NEWNODE(NODE_MATCH2, rb_node_match2_t, loc);
- n->nd_recv = nd_recv;
- n->nd_value = nd_value;
- n->nd_args = 0;
-
- return n;
-}
-
-static rb_node_match3_t *
-rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_match3_t *n = NODE_NEWNODE(NODE_MATCH3, rb_node_match3_t, loc);
- n->nd_recv = nd_recv;
- n->nd_value = nd_value;
-
- return n;
-}
-
-/* TODO: Use union for NODE_LIST2 */
-static rb_node_list_t *
-rb_node_list_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_list_t *n = NODE_NEWNODE(NODE_LIST, rb_node_list_t, loc);
- n->nd_head = nd_head;
- n->as.nd_alen = 1;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_list_t *
-rb_node_list_new2(struct parser_params *p, NODE *nd_head, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_list_t *n = NODE_NEWNODE(NODE_LIST, rb_node_list_t, loc);
- n->nd_head = nd_head;
- n->as.nd_alen = nd_alen;
- n->nd_next = nd_next;
-
- return n;
-}
-
-static rb_node_zlist_t *
-rb_node_zlist_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_zlist_t *n = NODE_NEWNODE(NODE_ZLIST, rb_node_zlist_t, loc);
-
- return n;
-}
-
-static rb_node_hash_t *
-rb_node_hash_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_hash_t *n = NODE_NEWNODE(NODE_HASH, rb_node_hash_t, loc);
- n->nd_head = nd_head;
- n->nd_brace = 0;
-
- return n;
-}
-
-static rb_node_masgn_t *
-rb_node_masgn_new(struct parser_params *p, NODE *nd_head, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_masgn_t *n = NODE_NEWNODE(NODE_MASGN, rb_node_masgn_t, loc);
- n->nd_head = nd_head;
- n->nd_value = 0;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_gasgn_t *
-rb_node_gasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_gasgn_t *n = NODE_NEWNODE(NODE_GASGN, rb_node_gasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_lasgn_t *
-rb_node_lasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_lasgn_t *n = NODE_NEWNODE(NODE_LASGN, rb_node_lasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_dasgn_t *
-rb_node_dasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_dasgn_t *n = NODE_NEWNODE(NODE_DASGN, rb_node_dasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_iasgn_t *
-rb_node_iasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_iasgn_t *n = NODE_NEWNODE(NODE_IASGN, rb_node_iasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_cvasgn_t *
-rb_node_cvasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_cvasgn_t *n = NODE_NEWNODE(NODE_CVASGN, rb_node_cvasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_op_asgn1_t *
-rb_node_op_asgn1_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *index, NODE *rvalue, const YYLTYPE *loc)
-{
- rb_node_op_asgn1_t *n = NODE_NEWNODE(NODE_OP_ASGN1, rb_node_op_asgn1_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_index = index;
- n->nd_rvalue = rvalue;
-
- return n;
-}
-
-static rb_node_op_asgn2_t *
-rb_node_op_asgn2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, ID nd_vid, ID nd_mid, bool nd_aid, const YYLTYPE *loc)
-{
- rb_node_op_asgn2_t *n = NODE_NEWNODE(NODE_OP_ASGN2, rb_node_op_asgn2_t, loc);
- n->nd_recv = nd_recv;
- n->nd_value = nd_value;
- n->nd_vid = nd_vid;
- n->nd_mid = nd_mid;
- n->nd_aid = nd_aid;
-
- return n;
-}
-
-static rb_node_op_asgn_or_t *
-rb_node_op_asgn_or_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_op_asgn_or_t *n = NODE_NEWNODE(NODE_OP_ASGN_OR, rb_node_op_asgn_or_t, loc);
- n->nd_head = nd_head;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_op_asgn_and_t *
-rb_node_op_asgn_and_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_op_asgn_and_t *n = NODE_NEWNODE(NODE_OP_ASGN_AND, rb_node_op_asgn_and_t, loc);
- n->nd_head = nd_head;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_gvar_t *
-rb_node_gvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_gvar_t *n = NODE_NEWNODE(NODE_GVAR, rb_node_gvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_lvar_t *
-rb_node_lvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_lvar_t *n = NODE_NEWNODE(NODE_LVAR, rb_node_lvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_dvar_t *
-rb_node_dvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_dvar_t *n = NODE_NEWNODE(NODE_DVAR, rb_node_dvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_ivar_t *
-rb_node_ivar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_ivar_t *n = NODE_NEWNODE(NODE_IVAR, rb_node_ivar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_const_t *
-rb_node_const_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_const_t *n = NODE_NEWNODE(NODE_CONST, rb_node_const_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_cvar_t *
-rb_node_cvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_cvar_t *n = NODE_NEWNODE(NODE_CVAR, rb_node_cvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_nth_ref_t *
-rb_node_nth_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc)
-{
- rb_node_nth_ref_t *n = NODE_NEWNODE(NODE_NTH_REF, rb_node_nth_ref_t, loc);
- n->nd_nth = nd_nth;
-
- return n;
-}
-
-static rb_node_back_ref_t *
-rb_node_back_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc)
-{
- rb_node_back_ref_t *n = NODE_NEWNODE(NODE_BACK_REF, rb_node_back_ref_t, loc);
- n->nd_nth = nd_nth;
-
- return n;
-}
-
-static rb_node_lit_t *
-rb_node_lit_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc)
-{
- rb_node_lit_t *n = NODE_NEWNODE(NODE_LIT, rb_node_lit_t, loc);
- n->nd_lit = nd_lit;
-
- return n;
-}
-
-static rb_node_str_t *
-rb_node_str_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc)
-{
- rb_node_str_t *n = NODE_NEWNODE(NODE_STR, rb_node_str_t, loc);
- n->nd_lit = nd_lit;
-
- return n;
-}
-
-/* TODO; Use union for NODE_DSTR2 */
-static rb_node_dstr_t *
-rb_node_dstr_new0(struct parser_params *p, VALUE nd_lit, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_dstr_t *n = NODE_NEWNODE(NODE_DSTR, rb_node_dstr_t, loc);
- n->nd_lit = nd_lit;
- n->as.nd_alen = nd_alen;
- n->nd_next = (rb_node_list_t *)nd_next;
-
- return n;
-}
-
-static rb_node_dstr_t *
-rb_node_dstr_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc)
-{
- return rb_node_dstr_new0(p, nd_lit, 1, 0, loc);
-}
-
-static rb_node_xstr_t *
-rb_node_xstr_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc)
-{
- rb_node_xstr_t *n = NODE_NEWNODE(NODE_XSTR, rb_node_xstr_t, loc);
- n->nd_lit = nd_lit;
-
- return n;
-}
-
-static rb_node_dxstr_t *
-rb_node_dxstr_new(struct parser_params *p, VALUE nd_lit, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_dxstr_t *n = NODE_NEWNODE(NODE_DXSTR, rb_node_dxstr_t, loc);
- n->nd_lit = nd_lit;
- n->nd_alen = nd_alen;
- n->nd_next = (rb_node_list_t *)nd_next;
-
- return n;
-}
-
-static rb_node_dsym_t *
-rb_node_dsym_new(struct parser_params *p, VALUE nd_lit, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_dsym_t *n = NODE_NEWNODE(NODE_DSYM, rb_node_dsym_t, loc);
- n->nd_lit = nd_lit;
- n->nd_alen = nd_alen;
- n->nd_next = (rb_node_list_t *)nd_next;
-
- return n;
-}
-
-static rb_node_evstr_t *
-rb_node_evstr_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_evstr_t *n = NODE_NEWNODE(NODE_EVSTR, rb_node_evstr_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_call_t *
-rb_node_call_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_call_t *n = NODE_NEWNODE(NODE_CALL, rb_node_call_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_opcall_t *
-rb_node_opcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_opcall_t *n = NODE_NEWNODE(NODE_OPCALL, rb_node_opcall_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_fcall_t *
-rb_node_fcall_new(struct parser_params *p, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_fcall_t *n = NODE_NEWNODE(NODE_FCALL, rb_node_fcall_t, loc);
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_qcall_t *
-rb_node_qcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_qcall_t *n = NODE_NEWNODE(NODE_QCALL, rb_node_qcall_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_vcall_t *
-rb_node_vcall_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc)
-{
- rb_node_vcall_t *n = NODE_NEWNODE(NODE_VCALL, rb_node_vcall_t, loc);
- n->nd_mid = nd_mid;
-
- return n;
-}
-
-static rb_node_once_t *
-rb_node_once_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_once_t *n = NODE_NEWNODE(NODE_ONCE, rb_node_once_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_args_t *
-rb_node_args_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_args_t *n = NODE_NEWNODE(NODE_ARGS, rb_node_args_t, loc);
- MEMZERO(&n->nd_ainfo, struct rb_args_info, 1);
-
- return n;
-}
-
-static rb_node_args_aux_t *
-rb_node_args_aux_new(struct parser_params *p, ID nd_pid, long nd_plen, const YYLTYPE *loc)
-{
- rb_node_args_aux_t *n = NODE_NEWNODE(NODE_ARGS_AUX, rb_node_args_aux_t, loc);
- n->nd_pid = nd_pid;
- n->nd_plen = nd_plen;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_opt_arg_t *
-rb_node_opt_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_opt_arg_t *n = NODE_NEWNODE(NODE_OPT_ARG, rb_node_opt_arg_t, loc);
- n->nd_body = nd_body;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_kw_arg_t *
-rb_node_kw_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_kw_arg_t *n = NODE_NEWNODE(NODE_KW_ARG, rb_node_kw_arg_t, loc);
- n->nd_body = nd_body;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_postarg_t *
-rb_node_postarg_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc)
-{
- rb_node_postarg_t *n = NODE_NEWNODE(NODE_POSTARG, rb_node_postarg_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
-
- return n;
-}
-
-static rb_node_argscat_t *
-rb_node_argscat_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_argscat_t *n = NODE_NEWNODE(NODE_ARGSCAT, rb_node_argscat_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_argspush_t *
-rb_node_argspush_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_argspush_t *n = NODE_NEWNODE(NODE_ARGSPUSH, rb_node_argspush_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_splat_t *
-rb_node_splat_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_splat_t *n = NODE_NEWNODE(NODE_SPLAT, rb_node_splat_t, loc);
- n->nd_head = nd_head;
-
- return n;
-}
-
-static rb_node_block_pass_t *
-rb_node_block_pass_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_block_pass_t *n = NODE_NEWNODE(NODE_BLOCK_PASS, rb_node_block_pass_t, loc);
- n->nd_head = 0;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_alias_t *
-rb_node_alias_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc)
-{
- rb_node_alias_t *n = NODE_NEWNODE(NODE_ALIAS, rb_node_alias_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
-
- return n;
-}
-
-static rb_node_valias_t *
-rb_node_valias_new(struct parser_params *p, ID nd_alias, ID nd_orig, const YYLTYPE *loc)
-{
- rb_node_valias_t *n = NODE_NEWNODE(NODE_VALIAS, rb_node_valias_t, loc);
- n->nd_alias = nd_alias;
- n->nd_orig = nd_orig;
-
- return n;
-}
-
-static rb_node_undef_t *
-rb_node_undef_new(struct parser_params *p, NODE *nd_undef, const YYLTYPE *loc)
-{
- rb_node_undef_t *n = NODE_NEWNODE(NODE_UNDEF, rb_node_undef_t, loc);
- n->nd_undef = nd_undef;
-
- return n;
-}
-
-static rb_node_errinfo_t *
-rb_node_errinfo_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_errinfo_t *n = NODE_NEWNODE(NODE_ERRINFO, rb_node_errinfo_t, loc);
-
- return n;
-}
-
-static rb_node_defined_t *
-rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_defined_t *n = NODE_NEWNODE(NODE_DEFINED, rb_node_defined_t, loc);
- n->nd_head = nd_head;
-
- return n;
-}
-
-static rb_node_postexe_t *
-rb_node_postexe_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_postexe_t *n = NODE_NEWNODE(NODE_POSTEXE, rb_node_postexe_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_attrasgn_t *
-rb_node_attrasgn_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_attrasgn_t *n = NODE_NEWNODE(NODE_ATTRASGN, rb_node_attrasgn_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_aryptn_t *
-rb_node_aryptn_new(struct parser_params *p, NODE *pre_args, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc)
-{
- rb_node_aryptn_t *n = NODE_NEWNODE(NODE_ARYPTN, rb_node_aryptn_t, loc);
- n->nd_pconst = 0;
- n->pre_args = pre_args;
- n->rest_arg = rest_arg;
- n->post_args = post_args;
-
- return n;
-}
-
-static rb_node_hshptn_t *
-rb_node_hshptn_new(struct parser_params *p, NODE *nd_pconst, NODE *nd_pkwargs, NODE *nd_pkwrestarg, const YYLTYPE *loc)
-{
- rb_node_hshptn_t *n = NODE_NEWNODE(NODE_HSHPTN, rb_node_hshptn_t, loc);
- n->nd_pconst = nd_pconst;
- n->nd_pkwargs = nd_pkwargs;
- n->nd_pkwrestarg = nd_pkwrestarg;
-
- return n;
-}
-
-static rb_node_fndptn_t *
-rb_node_fndptn_new(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc)
-{
- rb_node_fndptn_t *n = NODE_NEWNODE(NODE_FNDPTN, rb_node_fndptn_t, loc);
- n->nd_pconst = 0;
- n->pre_rest_arg = pre_rest_arg;
- n->args = args;
- n->post_rest_arg = post_rest_arg;
-
- return n;
-}
-
-static rb_node_cdecl_t *
-rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, const YYLTYPE *loc)
-{
- rb_node_cdecl_t *n = NODE_NEWNODE(NODE_CDECL, rb_node_cdecl_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
- n->nd_else = nd_else;
-
- return n;
-}
-
-static rb_node_op_cdecl_t *
-rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, const YYLTYPE *loc)
-{
- rb_node_op_cdecl_t *n = NODE_NEWNODE(NODE_OP_CDECL, rb_node_op_cdecl_t, loc);
- n->nd_head = nd_head;
- n->nd_value = nd_value;
- n->nd_aid = nd_aid;
-
- return n;
-}
-
-static rb_node_error_t *
-rb_node_error_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_error_t *n = NODE_NEWNODE(NODE_ERROR, rb_node_error_t, loc);
-
- return n;
-}
-
-#else
-
-static rb_node_ripper_t *
-rb_node_ripper_new(struct parser_params *p, ID nd_vid, VALUE nd_rval, VALUE nd_cval, const YYLTYPE *loc)
-{
- rb_node_ripper_t *n = NODE_NEWNODE(NODE_RIPPER, rb_node_ripper_t, loc);
- n->nd_vid = nd_vid;
- n->nd_rval = nd_rval;
- n->nd_cval = nd_cval;
-
- return n;
-}
-
-static rb_node_ripper_values_t *
-rb_node_ripper_values_new(struct parser_params *p, VALUE nd_val1, VALUE nd_val2, VALUE nd_val3, const YYLTYPE *loc)
-{
- rb_node_ripper_values_t *n = NODE_NEWNODE(NODE_RIPPER_VALUES, rb_node_ripper_values_t, loc);
- n->nd_val1 = nd_val1;
- n->nd_val2 = nd_val2;
- n->nd_val3 = nd_val3;
-
- return n;
-}
-
-#endif
-
-static rb_node_break_t *
-rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc)
-{
- rb_node_break_t *n = NODE_NEWNODE(NODE_BREAK, rb_node_break_t, loc);
- n->nd_stts = nd_stts;
- n->nd_chain = 0;
-
- return n;
-}
-
-static rb_node_next_t *
-rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc)
-{
- rb_node_next_t *n = NODE_NEWNODE(NODE_NEXT, rb_node_next_t, loc);
- n->nd_stts = nd_stts;
- n->nd_chain = 0;
-
- return n;
-}
-
-static rb_node_redo_t *
-rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_redo_t *n = NODE_NEWNODE(NODE_REDO, rb_node_redo_t, loc);
- n->nd_chain = 0;
-
- return n;
-}
-
-static rb_node_def_temp_t *
-rb_node_def_temp_new(struct parser_params *p, const YYLTYPE *loc)
+static NODE *
+nd_set_loc(NODE *nd, const YYLTYPE *loc)
{
- rb_node_def_temp_t *n = NODE_NEWNODE((enum node_type)NODE_DEF_TEMP, rb_node_def_temp_t, loc);
- n->save.cur_arg = p->cur_arg;
- n->save.numparam_save = numparam_push(p);
- n->save.max_numparam = p->max_numparam;
- n->save.ctxt = p->ctxt;
-#ifdef RIPPER
- n->nd_recv = Qnil;
- n->nd_mid = Qnil;
- n->dot_or_colon = Qnil;
-#else
- n->nd_def = 0;
- n->nd_mid = 0;
-#endif
-
- return n;
+ nd->nd_loc = *loc;
+ nd_set_line(nd, loc->beg_pos.lineno);
+ return nd;
}
#ifndef RIPPER
@@ -12256,8 +10607,8 @@ static NODE*
newline_node(NODE *node)
{
if (node) {
- node = remove_begin(node);
- nd_set_fl_newline(node);
+ node = remove_begin(node);
+ node->flags |= NODE_FL_NEWLINE;
}
return node;
}
@@ -12291,38 +10642,46 @@ block_append(struct parser_params *p, NODE *head, NODE *tail)
if (h == 0) return tail;
switch (nd_type(h)) {
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_SELF:
+ case NODE_TRUE:
+ case NODE_FALSE:
+ case NODE_NIL:
+ parser_warning(p, h, "unused literal ignored");
+ return tail;
default:
- h = end = NEW_BLOCK(head, &head->nd_loc);
- RNODE_BLOCK(end)->nd_end = end;
- head = end;
- break;
+ h = end = NEW_BLOCK(head, &head->nd_loc);
+ end->nd_end = end;
+ head = end;
+ break;
case NODE_BLOCK:
- end = RNODE_BLOCK(h)->nd_end;
- break;
+ end = h->nd_end;
+ break;
}
- nd = RNODE_BLOCK(end)->nd_head;
+ nd = end->nd_head;
switch (nd_type(nd)) {
case NODE_RETURN:
case NODE_BREAK:
case NODE_NEXT:
case NODE_REDO:
case NODE_RETRY:
- if (RTEST(ruby_verbose)) {
- parser_warning(p, tail, "statement not reached");
- }
- break;
+ if (RTEST(ruby_verbose)) {
+ parser_warning(p, tail, "statement not reached");
+ }
+ break;
default:
- break;
+ break;
}
if (!nd_type_p(tail, NODE_BLOCK)) {
- tail = NEW_BLOCK(tail, &tail->nd_loc);
- RNODE_BLOCK(tail)->nd_end = tail;
+ tail = NEW_BLOCK(tail, &tail->nd_loc);
+ tail->nd_end = tail;
}
- RNODE_BLOCK(end)->nd_next = tail;
- RNODE_BLOCK(h)->nd_end = RNODE_BLOCK(tail)->nd_end;
+ end->nd_next = tail;
+ h->nd_end = tail->nd_end;
nd_set_last_loc(head, nd_last_loc(tail));
return head;
}
@@ -12334,16 +10693,16 @@ list_append(struct parser_params *p, NODE *list, NODE *item)
NODE *last;
if (list == 0) return NEW_LIST(item, &item->nd_loc);
- if (RNODE_LIST(list)->nd_next) {
- last = RNODE_LIST(RNODE_LIST(list)->nd_next)->as.nd_end;
+ if (list->nd_next) {
+ last = list->nd_next->nd_end;
}
else {
- last = list;
+ last = list;
}
- RNODE_LIST(list)->as.nd_alen += 1;
- RNODE_LIST(last)->nd_next = NEW_LIST(item, &item->nd_loc);
- RNODE_LIST(RNODE_LIST(list)->nd_next)->as.nd_end = RNODE_LIST(last)->nd_next;
+ list->nd_alen += 1;
+ last->nd_next = NEW_LIST(item, &item->nd_loc);
+ list->nd_next->nd_end = last->nd_next;
nd_set_last_loc(list, nd_last_loc(item));
@@ -12356,20 +10715,20 @@ list_concat(NODE *head, NODE *tail)
{
NODE *last;
- if (RNODE_LIST(head)->nd_next) {
- last = RNODE_LIST(RNODE_LIST(head)->nd_next)->as.nd_end;
+ if (head->nd_next) {
+ last = head->nd_next->nd_end;
}
else {
- last = head;
+ last = head;
}
- RNODE_LIST(head)->as.nd_alen += RNODE_LIST(tail)->as.nd_alen;
- RNODE_LIST(last)->nd_next = tail;
- if (RNODE_LIST(tail)->nd_next) {
- RNODE_LIST(RNODE_LIST(head)->nd_next)->as.nd_end = RNODE_LIST(RNODE_LIST(tail)->nd_next)->as.nd_end;
+ head->nd_alen += tail->nd_alen;
+ last->nd_next = tail;
+ if (tail->nd_next) {
+ head->nd_next->nd_end = tail->nd_next->nd_end;
}
else {
- RNODE_LIST(RNODE_LIST(head)->nd_next)->as.nd_end = tail;
+ head->nd_next->nd_end = tail;
}
nd_set_last_loc(head, nd_last_loc(tail));
@@ -12382,26 +10741,26 @@ literal_concat0(struct parser_params *p, VALUE head, VALUE tail)
{
if (NIL_P(tail)) return 1;
if (!rb_enc_compatible(head, tail)) {
- compile_error(p, "string literal encodings differ (%s / %s)",
- rb_enc_name(rb_enc_get(head)),
- rb_enc_name(rb_enc_get(tail)));
- rb_str_resize(head, 0);
- rb_str_resize(tail, 0);
- return 0;
+ compile_error(p, "string literal encodings differ (%s / %s)",
+ rb_enc_name(rb_enc_get(head)),
+ rb_enc_name(rb_enc_get(tail)));
+ rb_str_resize(head, 0);
+ rb_str_resize(tail, 0);
+ return 0;
}
rb_str_buf_append(head, tail);
return 1;
}
static VALUE
-string_literal_head(struct parser_params *p, enum node_type htype, NODE *head)
+string_literal_head(enum node_type htype, NODE *head)
{
if (htype != NODE_DSTR) return Qfalse;
- if (RNODE_DSTR(head)->nd_next) {
- head = RNODE_LIST(RNODE_LIST(RNODE_DSTR(head)->nd_next)->as.nd_end)->nd_head;
- if (!head || !nd_type_p(head, NODE_STR)) return Qfalse;
+ if (head->nd_next) {
+ head = head->nd_next->nd_end->nd_head;
+ if (!head || !nd_type_p(head, NODE_STR)) return Qfalse;
}
- const VALUE lit = RNODE_DSTR(head)->nd_lit;
+ const VALUE lit = head->nd_lit;
ASSUME(lit != Qfalse);
return lit;
}
@@ -12418,110 +10777,88 @@ literal_concat(struct parser_params *p, NODE *head, NODE *tail, const YYLTYPE *l
htype = nd_type(head);
if (htype == NODE_EVSTR) {
- head = new_dstr(p, head, loc);
- htype = NODE_DSTR;
+ head = new_dstr(p, head, loc);
+ htype = NODE_DSTR;
}
if (p->heredoc_indent > 0) {
- switch (htype) {
- case NODE_STR:
- head = str2dstr(p, head);
- case NODE_DSTR:
- return list_append(p, head, tail);
- default:
- break;
- }
+ switch (htype) {
+ case NODE_STR:
+ nd_set_type(head, NODE_DSTR);
+ case NODE_DSTR:
+ return list_append(p, head, tail);
+ default:
+ break;
+ }
}
switch (nd_type(tail)) {
case NODE_STR:
- if ((lit = string_literal_head(p, htype, head)) != Qfalse) {
- htype = NODE_STR;
- }
- else {
- lit = RNODE_DSTR(head)->nd_lit;
- }
- if (htype == NODE_STR) {
- if (!literal_concat0(p, lit, RNODE_STR(tail)->nd_lit)) {
- error:
- rb_discard_node(p, head);
- rb_discard_node(p, tail);
- return 0;
- }
- rb_discard_node(p, tail);
- }
- else {
- list_append(p, head, tail);
- }
- break;
+ if ((lit = string_literal_head(htype, head)) != Qfalse) {
+ htype = NODE_STR;
+ }
+ else {
+ lit = head->nd_lit;
+ }
+ if (htype == NODE_STR) {
+ if (!literal_concat0(p, lit, tail->nd_lit)) {
+ error:
+ rb_discard_node(p, head);
+ rb_discard_node(p, tail);
+ return 0;
+ }
+ rb_discard_node(p, tail);
+ }
+ else {
+ list_append(p, head, tail);
+ }
+ break;
case NODE_DSTR:
- if (htype == NODE_STR) {
- if (!literal_concat0(p, RNODE_STR(head)->nd_lit, RNODE_DSTR(tail)->nd_lit))
- goto error;
- RNODE_DSTR(tail)->nd_lit = RNODE_STR(head)->nd_lit;
- rb_discard_node(p, head);
- head = tail;
- }
- else if (NIL_P(RNODE_DSTR(tail)->nd_lit)) {
- append:
- RNODE_DSTR(head)->as.nd_alen += RNODE_DSTR(tail)->as.nd_alen - 1;
- if (!RNODE_DSTR(head)->nd_next) {
- RNODE_DSTR(head)->nd_next = RNODE_DSTR(tail)->nd_next;
- }
- else if (RNODE_DSTR(tail)->nd_next) {
- RNODE_DSTR(RNODE_DSTR(RNODE_DSTR(head)->nd_next)->as.nd_end)->nd_next = RNODE_DSTR(tail)->nd_next;
- RNODE_DSTR(RNODE_DSTR(head)->nd_next)->as.nd_end = RNODE_DSTR(RNODE_DSTR(tail)->nd_next)->as.nd_end;
- }
- rb_discard_node(p, tail);
- }
- else if ((lit = string_literal_head(p, htype, head)) != Qfalse) {
- if (!literal_concat0(p, lit, RNODE_DSTR(tail)->nd_lit))
- goto error;
- RNODE_DSTR(tail)->nd_lit = Qnil;
- goto append;
- }
- else {
- list_concat(head, NEW_LIST2(NEW_STR(RNODE_DSTR(tail)->nd_lit, loc), RNODE_DSTR(tail)->as.nd_alen, (NODE *)RNODE_DSTR(tail)->nd_next, loc));
- }
- break;
+ if (htype == NODE_STR) {
+ if (!literal_concat0(p, head->nd_lit, tail->nd_lit))
+ goto error;
+ tail->nd_lit = head->nd_lit;
+ rb_discard_node(p, head);
+ head = tail;
+ }
+ else if (NIL_P(tail->nd_lit)) {
+ append:
+ head->nd_alen += tail->nd_alen - 1;
+ if (!head->nd_next) {
+ head->nd_next = tail->nd_next;
+ }
+ else if (tail->nd_next) {
+ head->nd_next->nd_end->nd_next = tail->nd_next;
+ head->nd_next->nd_end = tail->nd_next->nd_end;
+ }
+ rb_discard_node(p, tail);
+ }
+ else if ((lit = string_literal_head(htype, head)) != Qfalse) {
+ if (!literal_concat0(p, lit, tail->nd_lit))
+ goto error;
+ tail->nd_lit = Qnil;
+ goto append;
+ }
+ else {
+ list_concat(head, NEW_NODE(NODE_LIST, NEW_STR(tail->nd_lit, loc), tail->nd_alen, tail->nd_next, loc));
+ }
+ break;
case NODE_EVSTR:
- if (htype == NODE_STR) {
- head = str2dstr(p, head);
- RNODE_DSTR(head)->as.nd_alen = 1;
- }
- list_append(p, head, tail);
- break;
+ if (htype == NODE_STR) {
+ nd_set_type(head, NODE_DSTR);
+ head->nd_alen = 1;
+ }
+ list_append(p, head, tail);
+ break;
}
return head;
}
-static void
-nd_copy_flag(NODE *new_node, NODE *old_node)
-{
- if (nd_fl_newline(old_node)) nd_set_fl_newline(new_node);
- nd_set_line(new_node, nd_line(old_node));
- new_node->nd_loc = old_node->nd_loc;
- new_node->node_id = old_node->node_id;
-}
-
-static NODE *
-str2dstr(struct parser_params *p, NODE *node)
-{
- NODE *new_node = (NODE *)NODE_NEW_INTERNAL(NODE_DSTR, rb_node_dstr_t);
- nd_copy_flag(new_node, node);
- RNODE_DSTR(new_node)->nd_lit = RNODE_STR(node)->nd_lit;
- RNODE_DSTR(new_node)->as.nd_alen = 0;
- RNODE_DSTR(new_node)->nd_next = 0;
- RNODE_STR(node)->nd_lit = 0;
-
- return new_node;
-}
-
static NODE *
evstr2dstr(struct parser_params *p, NODE *node)
{
if (nd_type_p(node, NODE_EVSTR)) {
- node = new_dstr(p, node, &node->nd_loc);
+ node = new_dstr(p, node, &node->nd_loc);
}
return node;
}
@@ -12532,14 +10869,15 @@ new_evstr(struct parser_params *p, NODE *node, const YYLTYPE *loc)
NODE *head = node;
if (node) {
- switch (nd_type(node)) {
- case NODE_STR:
- return str2dstr(p, node);
+ switch (nd_type(node)) {
+ case NODE_STR:
+ nd_set_type(node, NODE_DSTR);
+ return node;
case NODE_DSTR:
break;
case NODE_EVSTR:
- return node;
- }
+ return node;
+ }
}
return NEW_EVSTR(head, loc);
}
@@ -12555,7 +10893,7 @@ new_dstr(struct parser_params *p, NODE *node, const YYLTYPE *loc)
static NODE *
call_bin_op(struct parser_params *p, NODE *recv, ID id, NODE *arg1,
- const YYLTYPE *op_loc, const YYLTYPE *loc)
+ const YYLTYPE *op_loc, const YYLTYPE *loc)
{
NODE *expr;
value_expr(recv);
@@ -12594,17 +10932,7 @@ new_command_qcall(struct parser_params* p, ID atype, NODE *recv, ID mid, NODE *a
return ret;
}
-#define nd_once_body(node) (nd_type_p((node), NODE_ONCE) ? RNODE_ONCE(node)->nd_body : node)
-
-static NODE*
-last_expr_once_body(NODE *node)
-{
- if (!node) return 0;
- node = last_expr_node(node);
- if (!node) return 0;
- return nd_once_body(node);
-}
-
+#define nd_once_body(node) (nd_type_p((node), NODE_ONCE) ? (node)->nd_body : node)
static NODE*
match_op(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *op_loc, const YYLTYPE *loc)
{
@@ -12613,38 +10941,37 @@ match_op(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *op_lo
value_expr(node1);
value_expr(node2);
-
- if ((n = last_expr_once_body(node1)) != 0) {
- switch (nd_type(n)) {
- case NODE_DREGX:
- {
- NODE *match = NEW_MATCH2(node1, node2, loc);
- nd_set_line(match, line);
- return match;
- }
-
- case NODE_LIT:
- if (RB_TYPE_P(RNODE_LIT(n)->nd_lit, T_REGEXP)) {
- const VALUE lit = RNODE_LIT(n)->nd_lit;
- NODE *match = NEW_MATCH2(node1, node2, loc);
- RNODE_MATCH2(match)->nd_args = reg_named_capture_assign(p, lit, loc);
- nd_set_line(match, line);
- return match;
- }
- }
- }
-
- if ((n = last_expr_once_body(node2)) != 0) {
+ if (node1 && (n = nd_once_body(node1)) != 0) {
+ switch (nd_type(n)) {
+ case NODE_DREGX:
+ {
+ NODE *match = NEW_MATCH2(node1, node2, loc);
+ nd_set_line(match, line);
+ return match;
+ }
+
+ case NODE_LIT:
+ if (RB_TYPE_P(n->nd_lit, T_REGEXP)) {
+ const VALUE lit = n->nd_lit;
+ NODE *match = NEW_MATCH2(node1, node2, loc);
+ match->nd_args = reg_named_capture_assign(p, lit, loc);
+ nd_set_line(match, line);
+ return match;
+ }
+ }
+ }
+
+ if (node2 && (n = nd_once_body(node2)) != 0) {
NODE *match3;
- switch (nd_type(n)) {
- case NODE_LIT:
- if (!RB_TYPE_P(RNODE_LIT(n)->nd_lit, T_REGEXP)) break;
- /* fallthru */
- case NODE_DREGX:
- match3 = NEW_MATCH3(node2, node1, loc);
- return match3;
- }
+ switch (nd_type(n)) {
+ case NODE_LIT:
+ if (!RB_TYPE_P(n->nd_lit, T_REGEXP)) break;
+ /* fallthru */
+ case NODE_DREGX:
+ match3 = NEW_MATCH3(node2, node1, loc);
+ return match3;
+ }
}
n = NEW_CALL(node1, tMATCH, NEW_LIST(node2, &node2->nd_loc), loc);
@@ -12658,8 +10985,8 @@ past_dvar_p(struct parser_params *p, ID id)
{
struct vtable *past = p->lvtbl->past;
while (past) {
- if (vtable_included(past, id)) return 1;
- past = past->prev;
+ if (vtable_included(past, id)) return 1;
+ past = past->prev;
}
return 0;
}
@@ -12672,13 +10999,13 @@ numparam_nested_p(struct parser_params *p)
NODE *outer = local->numparam.outer;
NODE *inner = local->numparam.inner;
if (outer || inner) {
- NODE *used = outer ? outer : inner;
- compile_error(p, "numbered parameter is already used in\n"
- "%s:%d: %s block here",
- p->ruby_sourcefile, nd_line(used),
- outer ? "outer" : "inner");
- parser_show_error_line(p, &used->nd_loc);
- return 1;
+ NODE *used = outer ? outer : inner;
+ compile_error(p, "numbered parameter is already used in\n"
+ "%s:%d: %s block here",
+ p->ruby_sourcefile, nd_line(used),
+ outer ? "outer" : "inner");
+ parser_show_error_line(p, &used->nd_loc);
+ return 1;
}
return 0;
}
@@ -12690,102 +11017,101 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
NODE *node;
switch (id) {
case keyword_self:
- return NEW_SELF(loc);
+ return NEW_SELF(loc);
case keyword_nil:
- return NEW_NIL(loc);
+ return NEW_NIL(loc);
case keyword_true:
- return NEW_TRUE(loc);
+ return NEW_TRUE(loc);
case keyword_false:
- return NEW_FALSE(loc);
+ return NEW_FALSE(loc);
case keyword__FILE__:
- {
- VALUE file = p->ruby_sourcefile_string;
- if (NIL_P(file))
- file = rb_str_new(0, 0);
- else
- file = rb_str_dup(file);
- node = NEW_STR(file, loc);
+ {
+ VALUE file = p->ruby_sourcefile_string;
+ if (NIL_P(file))
+ file = rb_str_new(0, 0);
+ else
+ file = rb_str_dup(file);
+ node = NEW_STR(file, loc);
RB_OBJ_WRITTEN(p->ast, Qnil, file);
- }
- return node;
+ }
+ return node;
case keyword__LINE__:
- return NEW_LIT(INT2FIX(loc->beg_pos.lineno), loc);
+ return NEW_LIT(INT2FIX(p->tokline), loc);
case keyword__ENCODING__:
node = NEW_LIT(rb_enc_from_encoding(p->enc), loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(node)->nd_lit);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit);
return node;
}
switch (id_type(id)) {
case ID_LOCAL:
- if (dyna_in_block(p) && dvar_defined_ref(p, id, &vidp)) {
- if (NUMPARAM_ID_P(id) && numparam_nested_p(p)) return 0;
- if (id == p->cur_arg) {
+ if (dyna_in_block(p) && dvar_defined_ref(p, id, &vidp)) {
+ if (NUMPARAM_ID_P(id) && numparam_nested_p(p)) return 0;
+ if (id == p->cur_arg) {
compile_error(p, "circular argument reference - %"PRIsWARN, rb_id2str(id));
return 0;
- }
- if (vidp) *vidp |= LVAR_USED;
- node = NEW_DVAR(id, loc);
- return node;
- }
- if (local_id_ref(p, id, &vidp)) {
- if (id == p->cur_arg) {
+ }
+ if (vidp) *vidp |= LVAR_USED;
+ node = NEW_DVAR(id, loc);
+ return node;
+ }
+ if (local_id_ref(p, id, &vidp)) {
+ if (id == p->cur_arg) {
compile_error(p, "circular argument reference - %"PRIsWARN, rb_id2str(id));
return 0;
- }
- if (vidp) *vidp |= LVAR_USED;
- node = NEW_LVAR(id, loc);
- return node;
- }
- if (dyna_in_block(p) && NUMPARAM_ID_P(id) &&
- parser_numbered_param(p, NUMPARAM_ID_TO_IDX(id))) {
- if (numparam_nested_p(p)) return 0;
- node = NEW_DVAR(id, loc);
- struct local_vars *local = p->lvtbl;
- if (!local->numparam.current) local->numparam.current = node;
- return node;
- }
+ }
+ if (vidp) *vidp |= LVAR_USED;
+ node = NEW_LVAR(id, loc);
+ return node;
+ }
+ if (dyna_in_block(p) && NUMPARAM_ID_P(id) &&
+ parser_numbered_param(p, NUMPARAM_ID_TO_IDX(id))) {
+ if (numparam_nested_p(p)) return 0;
+ node = NEW_DVAR(id, loc);
+ struct local_vars *local = p->lvtbl;
+ if (!local->numparam.current) local->numparam.current = node;
+ return node;
+ }
# if WARN_PAST_SCOPE
- if (!p->ctxt.in_defined && RTEST(ruby_verbose) && past_dvar_p(p, id)) {
- rb_warning1("possible reference to past scope - %"PRIsWARN, rb_id2str(id));
- }
+ if (!p->ctxt.in_defined && RTEST(ruby_verbose) && past_dvar_p(p, id)) {
+ rb_warning1("possible reference to past scope - %"PRIsWARN, rb_id2str(id));
+ }
# endif
- /* method call without arguments */
- return NEW_VCALL(id, loc);
+ /* method call without arguments */
+ return NEW_VCALL(id, loc);
case ID_GLOBAL:
- return NEW_GVAR(id, loc);
+ return NEW_GVAR(id, loc);
case ID_INSTANCE:
- return NEW_IVAR(id, loc);
+ return NEW_IVAR(id, loc);
case ID_CONST:
- return NEW_CONST(id, loc);
+ return NEW_CONST(id, loc);
case ID_CLASS:
- return NEW_CVAR(id, loc);
+ return NEW_CVAR(id, loc);
}
compile_error(p, "identifier %"PRIsVALUE" is not valid to get", rb_id2str(id));
return 0;
}
-static rb_node_opt_arg_t *
-opt_arg_append(rb_node_opt_arg_t *opt_list, rb_node_opt_arg_t *opt)
+static NODE *
+opt_arg_append(NODE *opt_list, NODE *opt)
{
- rb_node_opt_arg_t *opts = opt_list;
- RNODE(opts)->nd_loc.end_pos = RNODE(opt)->nd_loc.end_pos;
+ NODE *opts = opt_list;
+ opts->nd_loc.end_pos = opt->nd_loc.end_pos;
while (opts->nd_next) {
- opts = opts->nd_next;
- RNODE(opts)->nd_loc.end_pos = RNODE(opt)->nd_loc.end_pos;
+ opts = opts->nd_next;
+ opts->nd_loc.end_pos = opt->nd_loc.end_pos;
}
opts->nd_next = opt;
return opt_list;
}
-static rb_node_kw_arg_t *
-kwd_append(rb_node_kw_arg_t *kwlist, rb_node_kw_arg_t *kw)
+static NODE *
+kwd_append(NODE *kwlist, NODE *kw)
{
if (kwlist) {
- /* Assume rb_node_kw_arg_t and rb_node_opt_arg_t has same structure */
- opt_arg_append(RNODE_OPT_ARG(kwlist), RNODE_OPT_ARG(kw));
+ opt_arg_append(kwlist, kw);
}
return kwlist;
}
@@ -12802,14 +11128,14 @@ symbol_append(struct parser_params *p, NODE *symbols, NODE *symbol)
enum node_type type = nd_type(symbol);
switch (type) {
case NODE_DSTR:
- nd_set_type(symbol, NODE_DSYM);
- break;
+ nd_set_type(symbol, NODE_DSYM);
+ break;
case NODE_STR:
- nd_set_type(symbol, NODE_LIT);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(symbol)->nd_lit = rb_str_intern(RNODE_LIT(symbol)->nd_lit));
- break;
+ nd_set_type(symbol, NODE_LIT);
+ RB_OBJ_WRITTEN(p->ast, Qnil, symbol->nd_lit = rb_str_intern(symbol->nd_lit));
+ break;
default:
- compile_error(p, "unexpected node as symbol: %s", parser_node_name(type));
+ compile_error(p, "unexpected node as symbol: %s", ruby_node_name(type));
}
return list_append(p, symbols, symbol);
}
@@ -12817,99 +11143,98 @@ symbol_append(struct parser_params *p, NODE *symbols, NODE *symbol)
static NODE *
new_regexp(struct parser_params *p, NODE *node, int options, const YYLTYPE *loc)
{
- struct RNode_LIST *list;
- NODE *prev;
+ NODE *list, *prev;
VALUE lit;
if (!node) {
- node = NEW_LIT(reg_compile(p, STR_NEW0(), options), loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(node)->nd_lit);
+ node = NEW_LIT(reg_compile(p, STR_NEW0(), options), loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit);
return node;
}
switch (nd_type(node)) {
case NODE_STR:
- {
- VALUE src = RNODE_STR(node)->nd_lit;
- nd_set_type(node, NODE_LIT);
- nd_set_loc(node, loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(node)->nd_lit = reg_compile(p, src, options));
- }
- break;
+ {
+ VALUE src = node->nd_lit;
+ nd_set_type(node, NODE_LIT);
+ nd_set_loc(node, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit = reg_compile(p, src, options));
+ }
+ break;
default:
- lit = STR_NEW0();
- node = NEW_DSTR0(lit, 1, NEW_LIST(node, loc), loc);
+ lit = STR_NEW0();
+ node = NEW_NODE(NODE_DSTR, lit, 1, NEW_LIST(node, loc), loc);
RB_OBJ_WRITTEN(p->ast, Qnil, lit);
- /* fall through */
+ /* fall through */
case NODE_DSTR:
- nd_set_type(node, NODE_DREGX);
- nd_set_loc(node, loc);
- RNODE_DREGX(node)->nd_cflag = options & RE_OPTION_MASK;
- if (!NIL_P(RNODE_DREGX(node)->nd_lit)) reg_fragment_check(p, RNODE_DREGX(node)->nd_lit, options);
- for (list = RNODE_DREGX(prev = node)->nd_next; list; list = RNODE_LIST(list->nd_next)) {
- NODE *frag = list->nd_head;
- enum node_type type = nd_type(frag);
- if (type == NODE_STR || (type == NODE_DSTR && !RNODE_DSTR(frag)->nd_next)) {
- VALUE tail = RNODE_STR(frag)->nd_lit;
- if (reg_fragment_check(p, tail, options) && prev && !NIL_P(RNODE_DREGX(prev)->nd_lit)) {
- VALUE lit = prev == node ? RNODE_DREGX(prev)->nd_lit : RNODE_LIT(RNODE_LIST(prev)->nd_head)->nd_lit;
- if (!literal_concat0(p, lit, tail)) {
- return NEW_NIL(loc); /* dummy node on error */
- }
- rb_str_resize(tail, 0);
- RNODE_LIST(prev)->nd_next = list->nd_next;
- rb_discard_node(p, list->nd_head);
- rb_discard_node(p, (NODE *)list);
- list = RNODE_LIST(prev);
- }
- else {
- prev = (NODE *)list;
- }
- }
- else {
- prev = 0;
- }
- }
- if (!RNODE_DREGX(node)->nd_next) {
- VALUE src = RNODE_DREGX(node)->nd_lit;
- nd_set_type(node, NODE_LIT);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(node)->nd_lit = reg_compile(p, src, options));
- }
- if (options & RE_OPTION_ONCE) {
- node = NEW_ONCE(node, loc);
- }
- break;
+ nd_set_type(node, NODE_DREGX);
+ nd_set_loc(node, loc);
+ node->nd_cflag = options & RE_OPTION_MASK;
+ if (!NIL_P(node->nd_lit)) reg_fragment_check(p, node->nd_lit, options);
+ for (list = (prev = node)->nd_next; list; list = list->nd_next) {
+ NODE *frag = list->nd_head;
+ enum node_type type = nd_type(frag);
+ if (type == NODE_STR || (type == NODE_DSTR && !frag->nd_next)) {
+ VALUE tail = frag->nd_lit;
+ if (reg_fragment_check(p, tail, options) && prev && !NIL_P(prev->nd_lit)) {
+ VALUE lit = prev == node ? prev->nd_lit : prev->nd_head->nd_lit;
+ if (!literal_concat0(p, lit, tail)) {
+ return NEW_NIL(loc); /* dummy node on error */
+ }
+ rb_str_resize(tail, 0);
+ prev->nd_next = list->nd_next;
+ rb_discard_node(p, list->nd_head);
+ rb_discard_node(p, list);
+ list = prev;
+ }
+ else {
+ prev = list;
+ }
+ }
+ else {
+ prev = 0;
+ }
+ }
+ if (!node->nd_next) {
+ VALUE src = node->nd_lit;
+ nd_set_type(node, NODE_LIT);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit = reg_compile(p, src, options));
+ }
+ if (options & RE_OPTION_ONCE) {
+ node = NEW_NODE(NODE_ONCE, 0, node, 0, loc);
+ }
+ break;
}
return node;
}
-static rb_node_kw_arg_t *
+static NODE *
new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc)
{
if (!k) return 0;
- return NEW_KW_ARG((k), loc);
+ return NEW_KW_ARG(0, (k), loc);
}
static NODE *
new_xstring(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
if (!node) {
- VALUE lit = STR_NEW0();
- NODE *xstr = NEW_XSTR(lit, loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, lit);
- return xstr;
+ VALUE lit = STR_NEW0();
+ NODE *xstr = NEW_XSTR(lit, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, lit);
+ return xstr;
}
switch (nd_type(node)) {
case NODE_STR:
- nd_set_type(node, NODE_XSTR);
- nd_set_loc(node, loc);
- break;
+ nd_set_type(node, NODE_XSTR);
+ nd_set_loc(node, loc);
+ break;
case NODE_DSTR:
- nd_set_type(node, NODE_DXSTR);
- nd_set_loc(node, loc);
- break;
+ nd_set_type(node, NODE_DXSTR);
+ nd_set_loc(node, loc);
+ break;
default:
- node = NEW_DXSTR(Qnil, 1, NEW_LIST(node, loc), loc);
- break;
+ node = NEW_NODE(NODE_DXSTR, Qnil, 1, NEW_LIST(node, loc), loc);
+ break;
}
return node;
}
@@ -12924,19 +11249,19 @@ check_literal_when(struct parser_params *p, NODE *arg, const YYLTYPE *loc)
lit = rb_node_case_when_optimizable_literal(arg);
if (UNDEF_P(lit)) return;
if (nd_type_p(arg, NODE_STR)) {
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_STR(arg)->nd_lit = lit);
+ RB_OBJ_WRITTEN(p->ast, Qnil, arg->nd_lit = lit);
}
if (NIL_P(p->case_labels)) {
- p->case_labels = rb_obj_hide(rb_hash_new());
+ p->case_labels = rb_obj_hide(rb_hash_new());
}
else {
- VALUE line = rb_hash_lookup(p->case_labels, lit);
- if (!NIL_P(line)) {
- rb_warning1("duplicated `when' clause with line %d is ignored",
- WARN_IVAL(line));
- return;
- }
+ VALUE line = rb_hash_lookup(p->case_labels, lit);
+ if (!NIL_P(line)) {
+ rb_warning1("duplicated `when' clause with line %d is ignored",
+ WARN_IVAL(line));
+ return;
+ }
}
rb_hash_aset(p->case_labels, lit, INT2NUM(p->ruby_sourceline));
}
@@ -12946,17 +11271,17 @@ static int
id_is_var(struct parser_params *p, ID id)
{
if (is_notop_id(id)) {
- switch (id & ID_SCOPE_MASK) {
- case ID_GLOBAL: case ID_INSTANCE: case ID_CONST: case ID_CLASS:
- return 1;
- case ID_LOCAL:
- if (dyna_in_block(p)) {
- if (NUMPARAM_ID_P(id) || dvar_defined(p, id)) return 1;
- }
- if (local_id(p, id)) return 1;
- /* method call without arguments */
- return 0;
- }
+ switch (id & ID_SCOPE_MASK) {
+ case ID_GLOBAL: case ID_INSTANCE: case ID_CONST: case ID_CLASS:
+ return 1;
+ case ID_LOCAL:
+ if (dyna_in_block(p)) {
+ if (NUMPARAM_ID_P(id) || dvar_defined(p, id)) return 1;
+ }
+ if (local_id(p, id)) return 1;
+ /* method call without arguments */
+ return 0;
+ }
}
compile_error(p, "identifier %"PRIsVALUE" is not valid to get", rb_id2str(id));
return 0;
@@ -12965,18 +11290,18 @@ id_is_var(struct parser_params *p, ID id)
static VALUE
new_regexp(struct parser_params *p, VALUE re, VALUE opt, const YYLTYPE *loc)
{
- VALUE src = 0, err = 0;
+ VALUE src = 0, err;
int options = 0;
- if (ripper_is_node_yylval(p, re)) {
- src = RNODE_RIPPER(re)->nd_cval;
- re = RNODE_RIPPER(re)->nd_rval;
+ if (ripper_is_node_yylval(re)) {
+ src = RNODE(re)->nd_cval;
+ re = RNODE(re)->nd_rval;
}
- if (ripper_is_node_yylval(p, opt)) {
- options = (int)RNODE_RIPPER(opt)->nd_vid;
- opt = RNODE_RIPPER(opt)->nd_rval;
+ if (ripper_is_node_yylval(opt)) {
+ options = (int)RNODE(opt)->nd_tag;
+ opt = RNODE(opt)->nd_rval;
}
if (src && NIL_P(parser_reg_compile(p, src, options, &err))) {
- compile_error(p, "%"PRIsVALUE, err);
+ compile_error(p, "%"PRIsVALUE, err);
}
return dispatch2(regexp_literal, re, opt);
}
@@ -12986,7 +11311,7 @@ static inline enum lex_state_e
parser_set_lex_state(struct parser_params *p, enum lex_state_e ls, int line)
{
if (p->debug) {
- ls = rb_parser_trace_lex_state(p, p->lex.state, ls, line);
+ ls = rb_parser_trace_lex_state(p, p->lex.state, ls, line);
}
return p->lex.state = ls;
}
@@ -12999,23 +11324,23 @@ static const char rb_parser_lex_state_names[][8] = {
};
static VALUE
-append_lex_state_name(struct parser_params *p, enum lex_state_e state, VALUE buf)
+append_lex_state_name(enum lex_state_e state, VALUE buf)
{
int i, sep = 0;
unsigned int mask = 1;
static const char none[] = "NONE";
for (i = 0; i < EXPR_MAX_STATE; ++i, mask <<= 1) {
- if ((unsigned)state & mask) {
- if (sep) {
- rb_str_cat(buf, "|", 1);
- }
- sep = 1;
- rb_str_cat_cstr(buf, rb_parser_lex_state_names[i]);
- }
+ if ((unsigned)state & mask) {
+ if (sep) {
+ rb_str_cat(buf, "|", 1);
+ }
+ sep = 1;
+ rb_str_cat_cstr(buf, rb_parser_lex_state_names[i]);
+ }
}
if (!sep) {
- rb_str_cat(buf, none, sizeof(none)-1);
+ rb_str_cat(buf, none, sizeof(none)-1);
}
return buf;
}
@@ -13026,53 +11351,53 @@ flush_debug_buffer(struct parser_params *p, VALUE out, VALUE str)
VALUE mesg = p->debug_buffer;
if (!NIL_P(mesg) && RSTRING_LEN(mesg)) {
- p->debug_buffer = Qnil;
- rb_io_puts(1, &mesg, out);
+ p->debug_buffer = Qnil;
+ rb_io_puts(1, &mesg, out);
}
if (!NIL_P(str) && RSTRING_LEN(str)) {
- rb_io_write(p->debug_output, str);
+ rb_io_write(p->debug_output, str);
}
}
enum lex_state_e
rb_parser_trace_lex_state(struct parser_params *p, enum lex_state_e from,
- enum lex_state_e to, int line)
+ enum lex_state_e to, int line)
{
VALUE mesg;
mesg = rb_str_new_cstr("lex_state: ");
- append_lex_state_name(p, from, mesg);
+ append_lex_state_name(from, mesg);
rb_str_cat_cstr(mesg, " -> ");
- append_lex_state_name(p, to, mesg);
+ append_lex_state_name(to, mesg);
rb_str_catf(mesg, " at line %d\n", line);
flush_debug_buffer(p, p->debug_output, mesg);
return to;
}
VALUE
-rb_parser_lex_state_name(struct parser_params *p, enum lex_state_e state)
+rb_parser_lex_state_name(enum lex_state_e state)
{
- return rb_fstring(append_lex_state_name(p, state, rb_str_new(0, 0)));
+ return rb_fstring(append_lex_state_name(state, rb_str_new(0, 0)));
}
static void
-append_bitstack_value(struct parser_params *p, stack_type stack, VALUE mesg)
+append_bitstack_value(stack_type stack, VALUE mesg)
{
if (stack == 0) {
- rb_str_cat_cstr(mesg, "0");
+ rb_str_cat_cstr(mesg, "0");
}
else {
- stack_type mask = (stack_type)1U << (CHAR_BIT * sizeof(stack_type) - 1);
- for (; mask && !(stack & mask); mask >>= 1) continue;
- for (; mask; mask >>= 1) rb_str_cat(mesg, stack & mask ? "1" : "0", 1);
+ stack_type mask = (stack_type)1U << (CHAR_BIT * sizeof(stack_type) - 1);
+ for (; mask && !(stack & mask); mask >>= 1) continue;
+ for (; mask; mask >>= 1) rb_str_cat(mesg, stack & mask ? "1" : "0", 1);
}
}
void
rb_parser_show_bitstack(struct parser_params *p, stack_type stack,
- const char *name, int line)
+ const char *name, int line)
{
VALUE mesg = rb_sprintf("%s: ", name);
- append_bitstack_value(p, stack, mesg);
+ append_bitstack_value(stack, mesg);
rb_str_catf(mesg, " at line %d\n", line);
flush_debug_buffer(p, p->debug_output, mesg);
}
@@ -13090,16 +11415,16 @@ rb_parser_fatal(struct parser_params *p, const char *fmt, ...)
RB_GC_GUARD(mesg);
mesg = rb_str_new(0, 0);
- append_lex_state_name(p, p->lex.state, mesg);
+ append_lex_state_name(p->lex.state, mesg);
compile_error(p, "lex.state: %"PRIsVALUE, mesg);
rb_str_resize(mesg, 0);
- append_bitstack_value(p, p->cond_stack, mesg);
+ append_bitstack_value(p->cond_stack, mesg);
compile_error(p, "cond_stack: %"PRIsVALUE, mesg);
rb_str_resize(mesg, 0);
- append_bitstack_value(p, p->cmdarg_stack, mesg);
+ append_bitstack_value(p->cmdarg_stack, mesg);
compile_error(p, "cmdarg_stack: %"PRIsVALUE, mesg);
if (p->debug_output == rb_ractor_stdout())
- p->debug_output = rb_ractor_stderr();
+ p->debug_output = rb_ractor_stderr();
p->debug = TRUE;
}
@@ -13118,7 +11443,7 @@ rb_parser_set_location_from_strterm_heredoc(struct parser_params *p, rb_strterm_
{
int sourceline = here->sourceline;
int beg_pos = (int)here->offset - here->quote
- - (rb_strlen_lit("<<-") - !(here->func & STR_FUNC_INDENT));
+ - (rb_strlen_lit("<<-") - !(here->func & STR_FUNC_INDENT));
int end_pos = (int)here->offset + here->length + here->quote;
return rb_parser_set_pos(yylloc, sourceline, beg_pos, end_pos);
@@ -13177,55 +11502,55 @@ assignable0(struct parser_params *p, ID id, const char **err)
if (!id) return -1;
switch (id) {
case keyword_self:
- *err = "Can't change the value of self";
- return -1;
+ *err = "Can't change the value of self";
+ return -1;
case keyword_nil:
- *err = "Can't assign to nil";
- return -1;
+ *err = "Can't assign to nil";
+ return -1;
case keyword_true:
- *err = "Can't assign to true";
- return -1;
+ *err = "Can't assign to true";
+ return -1;
case keyword_false:
- *err = "Can't assign to false";
- return -1;
+ *err = "Can't assign to false";
+ return -1;
case keyword__FILE__:
- *err = "Can't assign to __FILE__";
- return -1;
+ *err = "Can't assign to __FILE__";
+ return -1;
case keyword__LINE__:
- *err = "Can't assign to __LINE__";
- return -1;
+ *err = "Can't assign to __LINE__";
+ return -1;
case keyword__ENCODING__:
- *err = "Can't assign to __ENCODING__";
- return -1;
+ *err = "Can't assign to __ENCODING__";
+ return -1;
}
switch (id_type(id)) {
case ID_LOCAL:
- if (dyna_in_block(p)) {
- if (p->max_numparam > NO_PARAM && NUMPARAM_ID_P(id)) {
- compile_error(p, "Can't assign to numbered parameter _%d",
- NUMPARAM_ID_TO_IDX(id));
- return -1;
- }
- if (dvar_curr(p, id)) return NODE_DASGN;
- if (dvar_defined(p, id)) return NODE_DASGN;
- if (local_id(p, id)) return NODE_LASGN;
- dyna_var(p, id);
- return NODE_DASGN;
- }
- else {
- if (!local_id(p, id)) local_var(p, id);
- return NODE_LASGN;
- }
- break;
+ if (dyna_in_block(p)) {
+ if (p->max_numparam > NO_PARAM && NUMPARAM_ID_P(id)) {
+ compile_error(p, "Can't assign to numbered parameter _%d",
+ NUMPARAM_ID_TO_IDX(id));
+ return -1;
+ }
+ if (dvar_curr(p, id)) return NODE_DASGN;
+ if (dvar_defined(p, id)) return NODE_DASGN;
+ if (local_id(p, id)) return NODE_LASGN;
+ dyna_var(p, id);
+ return NODE_DASGN;
+ }
+ else {
+ if (!local_id(p, id)) local_var(p, id);
+ return NODE_LASGN;
+ }
+ break;
case ID_GLOBAL: return NODE_GASGN;
case ID_INSTANCE: return NODE_IASGN;
case ID_CONST:
- if (!p->ctxt.in_def) return NODE_CDECL;
- *err = "dynamic constant assignment";
- return -1;
+ if (!p->ctxt.in_def) return NODE_CDECL;
+ *err = "dynamic constant assignment";
+ return -1;
case ID_CLASS: return NODE_CVASGN;
default:
- compile_error(p, "identifier %"PRIsVALUE" is not valid to set", rb_id2str(id));
+ compile_error(p, "identifier %"PRIsVALUE" is not valid to set", rb_id2str(id));
}
return -1;
}
@@ -13259,7 +11584,7 @@ assignable(struct parser_params *p, VALUE lhs)
#endif
static int
-is_private_local_id(struct parser_params *p, ID name)
+is_private_local_id(ID name)
{
VALUE s;
if (name == idUScore) return 1;
@@ -13273,23 +11598,23 @@ static int
shadowing_lvar_0(struct parser_params *p, ID name)
{
if (dyna_in_block(p)) {
- if (dvar_curr(p, name)) {
- if (is_private_local_id(p, name)) return 1;
- yyerror0("duplicated argument name");
- }
- else if (dvar_defined(p, name) || local_id(p, name)) {
- vtable_add(p->lvtbl->vars, name);
- if (p->lvtbl->used) {
- vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline | LVAR_USED);
- }
- return 0;
- }
+ if (dvar_curr(p, name)) {
+ if (is_private_local_id(name)) return 1;
+ yyerror0("duplicated argument name");
+ }
+ else if (dvar_defined(p, name) || local_id(p, name)) {
+ vtable_add(p->lvtbl->vars, name);
+ if (p->lvtbl->used) {
+ vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline | LVAR_USED);
+ }
+ return 0;
+ }
}
else {
- if (local_id(p, name)) {
- if (is_private_local_id(p, name)) return 1;
- yyerror0("duplicated argument name");
- }
+ if (local_id(p, name)) {
+ if (is_private_local_id(name)) return 1;
+ yyerror0("duplicated argument name");
+ }
}
return 1;
}
@@ -13306,9 +11631,9 @@ new_bv(struct parser_params *p, ID name)
{
if (!name) return;
if (!is_local_id(name)) {
- compile_error(p, "invalid local variable - %"PRIsVALUE,
- rb_id2str(name));
- return;
+ compile_error(p, "invalid local variable - %"PRIsVALUE,
+ rb_id2str(name));
+ return;
}
if (!shadowing_lvar_0(p, name)) return;
dyna_var(p, name);
@@ -13325,7 +11650,7 @@ static void
block_dup_check(struct parser_params *p, NODE *node1, NODE *node2)
{
if (node2 && node1 && nd_type_p(node1, NODE_BLOCK_PASS)) {
- compile_error(p, "both block arg and actual block given");
+ compile_error(p, "both block arg and actual block given");
}
}
@@ -13341,11 +11666,11 @@ rb_backref_error(struct parser_params *p, NODE *node)
{
switch (nd_type(node)) {
case NODE_NTH_REF:
- compile_error(p, "Can't set variable $%ld", RNODE_NTH_REF(node)->nd_nth);
- break;
+ compile_error(p, "Can't set variable $%ld", node->nd_nth);
+ break;
case NODE_BACK_REF:
- compile_error(p, "Can't set variable $%c", (int)RNODE_BACK_REF(node)->nd_nth);
- break;
+ compile_error(p, "Can't set variable $%c", (int)node->nd_nth);
+ break;
}
}
#else
@@ -13353,7 +11678,7 @@ static VALUE
backref_error(struct parser_params *p, NODE *ref, VALUE expr)
{
VALUE mesg = rb_str_new_cstr("Can't set variable ");
- rb_str_append(mesg, RNODE_RIPPER(ref)->nd_cval);
+ rb_str_append(mesg, ref->nd_cval);
return dispatch2(assign_error, mesg, expr);
}
#endif
@@ -13365,20 +11690,20 @@ arg_append(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *loc
if (!node1) return NEW_LIST(node2, &node2->nd_loc);
switch (nd_type(node1)) {
case NODE_LIST:
- return list_append(p, node1, node2);
+ return list_append(p, node1, node2);
case NODE_BLOCK_PASS:
- RNODE_BLOCK_PASS(node1)->nd_head = arg_append(p, RNODE_BLOCK_PASS(node1)->nd_head, node2, loc);
- node1->nd_loc.end_pos = RNODE_BLOCK_PASS(node1)->nd_head->nd_loc.end_pos;
- return node1;
+ node1->nd_head = arg_append(p, node1->nd_head, node2, loc);
+ node1->nd_loc.end_pos = node1->nd_head->nd_loc.end_pos;
+ return node1;
case NODE_ARGSPUSH:
- RNODE_ARGSPUSH(node1)->nd_body = list_append(p, NEW_LIST(RNODE_ARGSPUSH(node1)->nd_body, &RNODE_ARGSPUSH(node1)->nd_body->nd_loc), node2);
- node1->nd_loc.end_pos = RNODE_ARGSPUSH(node1)->nd_body->nd_loc.end_pos;
- nd_set_type(node1, NODE_ARGSCAT);
- return node1;
+ node1->nd_body = list_append(p, NEW_LIST(node1->nd_body, &node1->nd_body->nd_loc), node2);
+ node1->nd_loc.end_pos = node1->nd_body->nd_loc.end_pos;
+ nd_set_type(node1, NODE_ARGSCAT);
+ return node1;
case NODE_ARGSCAT:
- if (!nd_type_p(RNODE_ARGSCAT(node1)->nd_body, NODE_LIST)) break;
- RNODE_ARGSCAT(node1)->nd_body = list_append(p, RNODE_ARGSCAT(node1)->nd_body, node2);
- node1->nd_loc.end_pos = RNODE_ARGSCAT(node1)->nd_body->nd_loc.end_pos;
+ if (!nd_type_p(node1->nd_body, NODE_LIST)) break;
+ node1->nd_body = list_append(p, node1->nd_body, node2);
+ node1->nd_loc.end_pos = node1->nd_body->nd_loc.end_pos;
return node1;
}
return NEW_ARGSPUSH(node1, node2, loc);
@@ -13390,21 +11715,21 @@ arg_concat(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *loc
if (!node2) return node1;
switch (nd_type(node1)) {
case NODE_BLOCK_PASS:
- if (RNODE_BLOCK_PASS(node1)->nd_head)
- RNODE_BLOCK_PASS(node1)->nd_head = arg_concat(p, RNODE_BLOCK_PASS(node1)->nd_head, node2, loc);
- else
- RNODE_LIST(node1)->nd_head = NEW_LIST(node2, loc);
- return node1;
+ if (node1->nd_head)
+ node1->nd_head = arg_concat(p, node1->nd_head, node2, loc);
+ else
+ node1->nd_head = NEW_LIST(node2, loc);
+ return node1;
case NODE_ARGSPUSH:
- if (!nd_type_p(node2, NODE_LIST)) break;
- RNODE_ARGSPUSH(node1)->nd_body = list_concat(NEW_LIST(RNODE_ARGSPUSH(node1)->nd_body, loc), node2);
- nd_set_type(node1, NODE_ARGSCAT);
- return node1;
+ if (!nd_type_p(node2, NODE_LIST)) break;
+ node1->nd_body = list_concat(NEW_LIST(node1->nd_body, loc), node2);
+ nd_set_type(node1, NODE_ARGSCAT);
+ return node1;
case NODE_ARGSCAT:
- if (!nd_type_p(node2, NODE_LIST) ||
- !nd_type_p(RNODE_ARGSCAT(node1)->nd_body, NODE_LIST)) break;
- RNODE_ARGSCAT(node1)->nd_body = list_concat(RNODE_ARGSCAT(node1)->nd_body, node2);
- return node1;
+ if (!nd_type_p(node2, NODE_LIST) ||
+ !nd_type_p(node1->nd_body, NODE_LIST)) break;
+ node1->nd_body = list_concat(node1->nd_body, node2);
+ return node1;
}
return NEW_ARGSCAT(node1, node2, loc);
}
@@ -13414,7 +11739,7 @@ last_arg_append(struct parser_params *p, NODE *args, NODE *last_arg, const YYLTY
{
NODE *n1;
if ((n1 = splat_array(args)) != 0) {
- return list_append(p, n1, last_arg);
+ return list_append(p, n1, last_arg);
}
return arg_append(p, args, last_arg, loc);
}
@@ -13424,7 +11749,7 @@ rest_arg_append(struct parser_params *p, NODE *args, NODE *rest_arg, const YYLTY
{
NODE *n1;
if ((nd_type_p(rest_arg, NODE_LIST)) && (n1 = splat_array(args)) != 0) {
- return list_concat(n1, rest_arg);
+ return list_concat(n1, rest_arg);
}
return arg_concat(p, args, rest_arg, loc);
}
@@ -13432,7 +11757,7 @@ rest_arg_append(struct parser_params *p, NODE *args, NODE *rest_arg, const YYLTY
static NODE *
splat_array(NODE* node)
{
- if (nd_type_p(node, NODE_SPLAT)) node = RNODE_SPLAT(node)->nd_head;
+ if (nd_type_p(node, NODE_SPLAT)) node = node->nd_head;
if (nd_type_p(node, NODE_LIST)) return node;
return 0;
}
@@ -13444,21 +11769,21 @@ mark_lvar_used(struct parser_params *p, NODE *rhs)
if (!rhs) return;
switch (nd_type(rhs)) {
case NODE_LASGN:
- if (local_id_ref(p, RNODE_LASGN(rhs)->nd_vid, &vidp)) {
- if (vidp) *vidp |= LVAR_USED;
- }
- break;
+ if (local_id_ref(p, rhs->nd_vid, &vidp)) {
+ if (vidp) *vidp |= LVAR_USED;
+ }
+ break;
case NODE_DASGN:
- if (dvar_defined_ref(p, RNODE_DASGN(rhs)->nd_vid, &vidp)) {
- if (vidp) *vidp |= LVAR_USED;
- }
- break;
+ if (dvar_defined_ref(p, rhs->nd_vid, &vidp)) {
+ if (vidp) *vidp |= LVAR_USED;
+ }
+ break;
#if 0
case NODE_MASGN:
- for (rhs = rhs->nd_head; rhs; rhs = rhs->nd_next) {
- mark_lvar_used(p, rhs->nd_head);
- }
- break;
+ for (rhs = rhs->nd_head; rhs; rhs = rhs->nd_next) {
+ mark_lvar_used(p, rhs->nd_head);
+ }
+ break;
#endif
}
}
@@ -13468,38 +11793,40 @@ const_decl_path(struct parser_params *p, NODE **dest)
{
NODE *n = *dest;
if (!nd_type_p(n, NODE_CALL)) {
- const YYLTYPE *loc = &n->nd_loc;
- VALUE path;
- if (RNODE_CDECL(n)->nd_vid) {
- path = rb_id2str(RNODE_CDECL(n)->nd_vid);
- }
- else {
- n = RNODE_CDECL(n)->nd_else;
- path = rb_ary_new();
- for (; n && nd_type_p(n, NODE_COLON2); n = RNODE_COLON2(n)->nd_head) {
- rb_ary_push(path, rb_id2str(RNODE_COLON2(n)->nd_mid));
- }
- if (n && nd_type_p(n, NODE_CONST)) {
- // Const::Name
- rb_ary_push(path, rb_id2str(RNODE_CONST(n)->nd_vid));
- }
- else if (n && nd_type_p(n, NODE_COLON3)) {
- // ::Const::Name
- rb_ary_push(path, rb_str_new(0, 0));
- }
- else {
- // expression::Name
- rb_ary_push(path, rb_str_new_cstr("..."));
- }
- path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
- path = rb_fstring(path);
- }
- *dest = n = NEW_LIT(path, loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(n)->nd_lit);
+ const YYLTYPE *loc = &n->nd_loc;
+ VALUE path;
+ if (n->nd_vid) {
+ path = rb_id2str(n->nd_vid);
+ }
+ else {
+ n = n->nd_else;
+ path = rb_ary_new();
+ for (; n && nd_type_p(n, NODE_COLON2); n = n->nd_head) {
+ rb_ary_push(path, rb_id2str(n->nd_mid));
+ }
+ if (n && nd_type_p(n, NODE_CONST)) {
+ // Const::Name
+ rb_ary_push(path, rb_id2str(n->nd_vid));
+ }
+ else if (n && nd_type_p(n, NODE_COLON3)) {
+ // ::Const::Name
+ rb_ary_push(path, rb_str_new(0, 0));
+ }
+ else {
+ // expression::Name
+ rb_ary_push(path, rb_str_new_cstr("..."));
+ }
+ path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
+ path = rb_fstring(path);
+ }
+ *dest = n = NEW_LIT(path, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, n->nd_lit);
}
return n;
}
+extern VALUE rb_mRubyVMFrozenCore;
+
static NODE *
make_shareable_node(struct parser_params *p, NODE *value, bool copy, const YYLTYPE *loc)
{
@@ -13527,21 +11854,21 @@ ensure_shareable_node(struct parser_params *p, NODE **dest, NODE *value, const Y
static int is_static_content(NODE *node);
static VALUE
-shareable_literal_value(struct parser_params *p, NODE *node)
+shareable_literal_value(NODE *node)
{
if (!node) return Qnil;
enum node_type type = nd_type(node);
switch (type) {
case NODE_TRUE:
- return Qtrue;
+ return Qtrue;
case NODE_FALSE:
- return Qfalse;
+ return Qfalse;
case NODE_NIL:
- return Qnil;
+ return Qnil;
case NODE_LIT:
- return RNODE_LIT(node)->nd_lit;
+ return node->nd_lit;
default:
- return Qundef;
+ return Qundef;
}
}
@@ -13551,7 +11878,7 @@ shareable_literal_value(struct parser_params *p, NODE *node)
static NODE *
shareable_literal_constant(struct parser_params *p, enum shareability shareable,
- NODE **dest, NODE *value, const YYLTYPE *loc, size_t level)
+ NODE **dest, NODE *value, const YYLTYPE *loc, size_t level)
{
# define shareable_literal_constant_next(n) \
shareable_literal_constant(p, shareable, dest, (n), &(n)->nd_loc, level+1)
@@ -13564,112 +11891,112 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable,
case NODE_FALSE:
case NODE_NIL:
case NODE_LIT:
- return value;
+ return value;
case NODE_DSTR:
- if (shareable == shareable_literal) {
- value = NEW_CALL(value, idUMinus, 0, loc);
- }
- return value;
+ if (shareable == shareable_literal) {
+ value = NEW_CALL(value, idUMinus, 0, loc);
+ }
+ return value;
case NODE_STR:
- lit = rb_fstring(RNODE_STR(value)->nd_lit);
- nd_set_type(value, NODE_LIT);
- RB_OBJ_WRITE(p->ast, &RNODE_LIT(value)->nd_lit, lit);
- return value;
+ lit = rb_fstring(value->nd_lit);
+ nd_set_type(value, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &value->nd_lit, lit);
+ return value;
case NODE_ZLIST:
- lit = rb_ary_new();
- OBJ_FREEZE_RAW(lit);
+ lit = rb_ary_new();
+ OBJ_FREEZE_RAW(lit);
NODE *n = NEW_LIT(lit, loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(n)->nd_lit);
+ RB_OBJ_WRITTEN(p->ast, Qnil, n->nd_lit);
return n;
case NODE_LIST:
- lit = rb_ary_new();
- for (NODE *n = value; n; n = RNODE_LIST(n)->nd_next) {
- NODE *elt = RNODE_LIST(n)->nd_head;
- if (elt) {
- elt = shareable_literal_constant_next(elt);
- if (elt) {
- RNODE_LIST(n)->nd_head = elt;
- }
- else if (RTEST(lit)) {
- rb_ary_clear(lit);
- lit = Qfalse;
- }
- }
- if (RTEST(lit)) {
- VALUE e = shareable_literal_value(p, elt);
- if (!UNDEF_P(e)) {
- rb_ary_push(lit, e);
- }
- else {
- rb_ary_clear(lit);
- lit = Qnil; /* make shareable at runtime */
- }
- }
- }
- break;
+ lit = rb_ary_new();
+ for (NODE *n = value; n; n = n->nd_next) {
+ NODE *elt = n->nd_head;
+ if (elt) {
+ elt = shareable_literal_constant_next(elt);
+ if (elt) {
+ n->nd_head = elt;
+ }
+ else if (RTEST(lit)) {
+ rb_ary_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ if (RTEST(lit)) {
+ VALUE e = shareable_literal_value(elt);
+ if (!UNDEF_P(e)) {
+ rb_ary_push(lit, e);
+ }
+ else {
+ rb_ary_clear(lit);
+ lit = Qnil; /* make shareable at runtime */
+ }
+ }
+ }
+ break;
case NODE_HASH:
- if (!RNODE_HASH(value)->nd_brace) return 0;
- lit = rb_hash_new();
- for (NODE *n = RNODE_HASH(value)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
- NODE *key = RNODE_LIST(n)->nd_head;
- NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
- if (key) {
- key = shareable_literal_constant_next(key);
- if (key) {
- RNODE_LIST(n)->nd_head = key;
- }
- else if (RTEST(lit)) {
- rb_hash_clear(lit);
- lit = Qfalse;
- }
- }
- if (val) {
- val = shareable_literal_constant_next(val);
- if (val) {
- RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head = val;
- }
- else if (RTEST(lit)) {
- rb_hash_clear(lit);
- lit = Qfalse;
- }
- }
- if (RTEST(lit)) {
- VALUE k = shareable_literal_value(p, key);
- VALUE v = shareable_literal_value(p, val);
- if (!UNDEF_P(k) && !UNDEF_P(v)) {
- rb_hash_aset(lit, k, v);
- }
- else {
- rb_hash_clear(lit);
- lit = Qnil; /* make shareable at runtime */
- }
- }
- }
- break;
+ if (!value->nd_brace) return 0;
+ lit = rb_hash_new();
+ for (NODE *n = value->nd_head; n; n = n->nd_next->nd_next) {
+ NODE *key = n->nd_head;
+ NODE *val = n->nd_next->nd_head;
+ if (key) {
+ key = shareable_literal_constant_next(key);
+ if (key) {
+ n->nd_head = key;
+ }
+ else if (RTEST(lit)) {
+ rb_hash_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ if (val) {
+ val = shareable_literal_constant_next(val);
+ if (val) {
+ n->nd_next->nd_head = val;
+ }
+ else if (RTEST(lit)) {
+ rb_hash_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ if (RTEST(lit)) {
+ VALUE k = shareable_literal_value(key);
+ VALUE v = shareable_literal_value(val);
+ if (!UNDEF_P(k) && !UNDEF_P(v)) {
+ rb_hash_aset(lit, k, v);
+ }
+ else {
+ rb_hash_clear(lit);
+ lit = Qnil; /* make shareable at runtime */
+ }
+ }
+ }
+ break;
default:
- if (shareable == shareable_literal &&
- (SHAREABLE_BARE_EXPRESSION || level > 0)) {
- return ensure_shareable_node(p, dest, value, loc);
- }
- return 0;
+ if (shareable == shareable_literal &&
+ (SHAREABLE_BARE_EXPRESSION || level > 0)) {
+ return ensure_shareable_node(p, dest, value, loc);
+ }
+ return 0;
}
/* Array or Hash */
if (!lit) return 0;
if (NIL_P(lit)) {
- // if shareable_literal, all elements should have been ensured
- // as shareable
- value = make_shareable_node(p, value, false, loc);
+ // if shareable_literal, all elements should have been ensured
+ // as shareable
+ value = make_shareable_node(p, value, false, loc);
}
else {
- value = NEW_LIT(rb_ractor_make_shareable(lit), loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(value)->nd_lit);
+ value = NEW_LIT(rb_ractor_make_shareable(lit), loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, value->nd_lit);
}
return value;
@@ -13678,32 +12005,32 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable,
static NODE *
shareable_constant_value(struct parser_params *p, enum shareability shareable,
- NODE *lhs, NODE *value, const YYLTYPE *loc)
+ NODE *lhs, NODE *value, const YYLTYPE *loc)
{
if (!value) return 0;
switch (shareable) {
case shareable_none:
- return value;
+ return value;
case shareable_literal:
- {
- NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
- if (lit) return lit;
- return value;
- }
- break;
+ {
+ NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
+ if (lit) return lit;
+ return value;
+ }
+ break;
case shareable_copy:
case shareable_everything:
- {
- NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
- if (lit) return lit;
- return make_shareable_node(p, value, shareable == shareable_copy, loc);
- }
- break;
+ {
+ NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
+ if (lit) return lit;
+ return make_shareable_node(p, value, shareable == shareable_copy, loc);
+ }
+ break;
default:
- UNREACHABLE_RETURN(0);
+ UNREACHABLE_RETURN(0);
}
}
@@ -13714,8 +12041,8 @@ node_assign(struct parser_params *p, NODE *lhs, NODE *rhs, struct lex_context ct
switch (nd_type(lhs)) {
case NODE_CDECL:
- rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
- /* fallthru */
+ rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
+ /* fallthru */
case NODE_GASGN:
case NODE_IASGN:
@@ -13723,18 +12050,18 @@ node_assign(struct parser_params *p, NODE *lhs, NODE *rhs, struct lex_context ct
case NODE_DASGN:
case NODE_MASGN:
case NODE_CVASGN:
- set_nd_value(p, lhs, rhs);
- nd_set_loc(lhs, loc);
- break;
+ lhs->nd_value = rhs;
+ nd_set_loc(lhs, loc);
+ break;
case NODE_ATTRASGN:
- RNODE_ATTRASGN(lhs)->nd_args = arg_append(p, RNODE_ATTRASGN(lhs)->nd_args, rhs, loc);
- nd_set_loc(lhs, loc);
- break;
+ lhs->nd_args = arg_append(p, lhs->nd_args, rhs, loc);
+ nd_set_loc(lhs, loc);
+ break;
default:
- /* should not happen */
- break;
+ /* should not happen */
+ break;
}
return lhs;
@@ -13746,67 +12073,67 @@ value_expr_check(struct parser_params *p, NODE *node)
NODE *void_node = 0, *vn;
if (!node) {
- rb_warning0("empty expression");
+ rb_warning0("empty expression");
}
while (node) {
- switch (nd_type(node)) {
- case NODE_RETURN:
- case NODE_BREAK:
- case NODE_NEXT:
- case NODE_REDO:
- case NODE_RETRY:
- return void_node ? void_node : node;
-
- case NODE_CASE3:
- if (!RNODE_CASE3(node)->nd_body || !nd_type_p(RNODE_CASE3(node)->nd_body, NODE_IN)) {
- compile_error(p, "unexpected node");
- return NULL;
- }
- if (RNODE_IN(RNODE_CASE3(node)->nd_body)->nd_body) {
- return NULL;
- }
- /* single line pattern matching with "=>" operator */
- return void_node ? void_node : node;
-
- case NODE_BLOCK:
- while (RNODE_BLOCK(node)->nd_next) {
- node = RNODE_BLOCK(node)->nd_next;
- }
- node = RNODE_BLOCK(node)->nd_head;
- break;
-
- case NODE_BEGIN:
- node = RNODE_BEGIN(node)->nd_body;
- break;
-
- case NODE_IF:
- case NODE_UNLESS:
- if (!RNODE_IF(node)->nd_body) {
- return NULL;
- }
- else if (!RNODE_IF(node)->nd_else) {
- return NULL;
- }
- vn = value_expr_check(p, RNODE_IF(node)->nd_body);
- if (!vn) return NULL;
- if (!void_node) void_node = vn;
- node = RNODE_IF(node)->nd_else;
- break;
-
- case NODE_AND:
- case NODE_OR:
- node = RNODE_AND(node)->nd_1st;
- break;
-
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_MASGN:
- mark_lvar_used(p, node);
- return NULL;
-
- default:
- return NULL;
- }
+ switch (nd_type(node)) {
+ case NODE_RETURN:
+ case NODE_BREAK:
+ case NODE_NEXT:
+ case NODE_REDO:
+ case NODE_RETRY:
+ return void_node ? void_node : node;
+
+ case NODE_CASE3:
+ if (!node->nd_body || !nd_type_p(node->nd_body, NODE_IN)) {
+ compile_error(p, "unexpected node");
+ return NULL;
+ }
+ if (node->nd_body->nd_body) {
+ return NULL;
+ }
+ /* single line pattern matching */
+ return void_node ? void_node : node;
+
+ case NODE_BLOCK:
+ while (node->nd_next) {
+ node = node->nd_next;
+ }
+ node = node->nd_head;
+ break;
+
+ case NODE_BEGIN:
+ node = node->nd_body;
+ break;
+
+ case NODE_IF:
+ case NODE_UNLESS:
+ if (!node->nd_body) {
+ return NULL;
+ }
+ else if (!node->nd_else) {
+ return NULL;
+ }
+ vn = value_expr_check(p, node->nd_body);
+ if (!vn) return NULL;
+ if (!void_node) void_node = vn;
+ node = node->nd_else;
+ break;
+
+ case NODE_AND:
+ case NODE_OR:
+ node = node->nd_1st;
+ break;
+
+ case NODE_LASGN:
+ case NODE_DASGN:
+ case NODE_MASGN:
+ mark_lvar_used(p, node);
+ return NULL;
+
+ default:
+ return NULL;
+ }
}
return NULL;
@@ -13817,13 +12144,12 @@ value_expr_gen(struct parser_params *p, NODE *node)
{
NODE *void_node = value_expr_check(p, node);
if (void_node) {
- yyerror1(&void_node->nd_loc, "void value expression");
- /* or "control never reach"? */
- return FALSE;
+ yyerror1(&void_node->nd_loc, "void value expression");
+ /* or "control never reach"? */
+ return FALSE;
}
return TRUE;
}
-
static void
void_expr(struct parser_params *p, NODE *node)
{
@@ -13834,29 +12160,29 @@ void_expr(struct parser_params *p, NODE *node)
if (!node || !(node = nd_once_body(node))) return;
switch (nd_type(node)) {
case NODE_OPCALL:
- switch (RNODE_OPCALL(node)->nd_mid) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case tPOW:
- case tUPLUS:
- case tUMINUS:
- case '|':
- case '^':
- case '&':
- case tCMP:
- case '>':
- case tGEQ:
- case '<':
- case tLEQ:
- case tEQ:
- case tNEQ:
- useless = rb_id2name(RNODE_OPCALL(node)->nd_mid);
- break;
- }
- break;
+ switch (node->nd_mid) {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case tPOW:
+ case tUPLUS:
+ case tUMINUS:
+ case '|':
+ case '^':
+ case '&':
+ case tCMP:
+ case '>':
+ case tGEQ:
+ case '<':
+ case tLEQ:
+ case tEQ:
+ case tNEQ:
+ useless = rb_id2name(node->nd_mid);
+ break;
+ }
+ break;
case NODE_LVAR:
case NODE_DVAR:
@@ -13865,46 +12191,46 @@ void_expr(struct parser_params *p, NODE *node)
case NODE_CVAR:
case NODE_NTH_REF:
case NODE_BACK_REF:
- useless = "a variable";
- break;
+ useless = "a variable";
+ break;
case NODE_CONST:
- useless = "a constant";
- break;
+ useless = "a constant";
+ break;
case NODE_LIT:
case NODE_STR:
case NODE_DSTR:
case NODE_DREGX:
- useless = "a literal";
- break;
+ useless = "a literal";
+ break;
case NODE_COLON2:
case NODE_COLON3:
- useless = "::";
- break;
+ useless = "::";
+ break;
case NODE_DOT2:
- useless = "..";
- break;
+ useless = "..";
+ break;
case NODE_DOT3:
- useless = "...";
- break;
+ useless = "...";
+ break;
case NODE_SELF:
- useless = "self";
- break;
+ useless = "self";
+ break;
case NODE_NIL:
- useless = "nil";
- break;
+ useless = "nil";
+ break;
case NODE_TRUE:
- useless = "true";
- break;
+ useless = "true";
+ break;
case NODE_FALSE:
- useless = "false";
- break;
+ useless = "false";
+ break;
case NODE_DEFINED:
- useless = "defined?";
- break;
+ useless = "defined?";
+ break;
}
if (useless) {
- rb_warn1L(nd_line(node), "possibly useless use of %s in void context", WARN_S(useless));
+ rb_warn1L(nd_line(node), "possibly useless use of %s in void context", WARN_S(useless));
}
}
@@ -13916,9 +12242,9 @@ void_stmts(struct parser_params *p, NODE *node)
if (!node) return n;
if (!nd_type_p(node, NODE_BLOCK)) return n;
- while (RNODE_BLOCK(node)->nd_next) {
- void_expr(p, RNODE_BLOCK(node)->nd_head);
- node = RNODE_BLOCK(node)->nd_next;
+ while (node->nd_next) {
+ void_expr(p, node->nd_head);
+ node = node->nd_next;
}
return n;
}
@@ -13927,8 +12253,8 @@ static NODE *
remove_begin(NODE *node)
{
NODE **n = &node, *n1 = node;
- while (n1 && nd_type_p(n1, NODE_BEGIN) && RNODE_BEGIN(n1)->nd_body) {
- *n = n1 = RNODE_BEGIN(n1)->nd_body;
+ while (n1 && nd_type_p(n1, NODE_BEGIN) && n1->nd_body) {
+ *n = n1 = n1->nd_body;
}
return node;
}
@@ -13938,7 +12264,7 @@ remove_begin_all(NODE *node)
{
NODE **n = &node, *n1 = node;
while (n1 && nd_type_p(n1, NODE_BEGIN)) {
- *n = n1 = RNODE_BEGIN(n1)->nd_body;
+ *n = n1 = n1->nd_body;
}
return node;
}
@@ -13949,58 +12275,57 @@ reduce_nodes(struct parser_params *p, NODE **body)
NODE *node = *body;
if (!node) {
- *body = NEW_NIL(&NULL_LOC);
- return;
+ *body = NEW_NIL(&NULL_LOC);
+ return;
}
-#define subnodes(type, n1, n2) \
- ((!type(node)->n1) ? (type(node)->n2 ? (body = &type(node)->n2, 1) : 0) : \
- (!type(node)->n2) ? (body = &type(node)->n1, 1) : \
- (reduce_nodes(p, &type(node)->n1), body = &type(node)->n2, 1))
+#define subnodes(n1, n2) \
+ ((!node->n1) ? (node->n2 ? (body = &node->n2, 1) : 0) : \
+ (!node->n2) ? (body = &node->n1, 1) : \
+ (reduce_nodes(p, &node->n1), body = &node->n2, 1))
while (node) {
- int newline = (int)(nd_fl_newline(node));
- switch (nd_type(node)) {
- end:
- case NODE_NIL:
- *body = 0;
- return;
- case NODE_RETURN:
- *body = node = RNODE_RETURN(node)->nd_stts;
- if (newline && node) nd_set_fl_newline(node);
- continue;
- case NODE_BEGIN:
- *body = node = RNODE_BEGIN(node)->nd_body;
- if (newline && node) nd_set_fl_newline(node);
- continue;
- case NODE_BLOCK:
- body = &RNODE_BLOCK(RNODE_BLOCK(node)->nd_end)->nd_head;
- break;
- case NODE_IF:
- case NODE_UNLESS:
- if (subnodes(RNODE_IF, nd_body, nd_else)) break;
- return;
- case NODE_CASE:
- body = &RNODE_CASE(node)->nd_body;
- break;
- case NODE_WHEN:
- if (!subnodes(RNODE_WHEN, nd_body, nd_next)) goto end;
- break;
- case NODE_ENSURE:
- if (!subnodes(RNODE_ENSURE, nd_head, nd_resq)) goto end;
- break;
- case NODE_RESCUE:
- newline = 0; // RESBODY should not be a NEWLINE
- if (RNODE_RESCUE(node)->nd_else) {
- body = &RNODE_RESCUE(node)->nd_resq;
- break;
- }
- if (!subnodes(RNODE_RESCUE, nd_head, nd_resq)) goto end;
- break;
- default:
- return;
- }
- node = *body;
- if (newline && node) nd_set_fl_newline(node);
+ int newline = (int)(node->flags & NODE_FL_NEWLINE);
+ switch (nd_type(node)) {
+ end:
+ case NODE_NIL:
+ *body = 0;
+ return;
+ case NODE_RETURN:
+ *body = node = node->nd_stts;
+ if (newline && node) node->flags |= NODE_FL_NEWLINE;
+ continue;
+ case NODE_BEGIN:
+ *body = node = node->nd_body;
+ if (newline && node) node->flags |= NODE_FL_NEWLINE;
+ continue;
+ case NODE_BLOCK:
+ body = &node->nd_end->nd_head;
+ break;
+ case NODE_IF:
+ case NODE_UNLESS:
+ if (subnodes(nd_body, nd_else)) break;
+ return;
+ case NODE_CASE:
+ body = &node->nd_body;
+ break;
+ case NODE_WHEN:
+ if (!subnodes(nd_body, nd_next)) goto end;
+ break;
+ case NODE_ENSURE:
+ if (!subnodes(nd_head, nd_resq)) goto end;
+ break;
+ case NODE_RESCUE:
+ if (node->nd_else) {
+ body = &node->nd_resq;
+ break;
+ }
+ if (!subnodes(nd_head, nd_resq)) goto end;
+ break;
+ default:
+ return;
+ }
+ node = *body;
+ if (newline && node) node->flags |= NODE_FL_NEWLINE;
}
#undef subnodes
@@ -14012,20 +12337,20 @@ is_static_content(NODE *node)
if (!node) return 1;
switch (nd_type(node)) {
case NODE_HASH:
- if (!(node = RNODE_HASH(node)->nd_head)) break;
+ if (!(node = node->nd_head)) break;
case NODE_LIST:
- do {
- if (!is_static_content(RNODE_LIST(node)->nd_head)) return 0;
- } while ((node = RNODE_LIST(node)->nd_next) != 0);
+ do {
+ if (!is_static_content(node->nd_head)) return 0;
+ } while ((node = node->nd_next) != 0);
case NODE_LIT:
case NODE_STR:
case NODE_NIL:
case NODE_TRUE:
case NODE_FALSE:
case NODE_ZLIST:
- break;
+ break;
default:
- return 0;
+ return 0;
}
return 1;
}
@@ -14039,18 +12364,16 @@ assign_in_cond(struct parser_params *p, NODE *node)
case NODE_DASGN:
case NODE_GASGN:
case NODE_IASGN:
- case NODE_CVASGN:
- case NODE_CDECL:
- break;
+ break;
default:
- return 0;
+ return 0;
}
- if (!get_nd_value(p, node)) return 1;
- if (is_static_content(get_nd_value(p, node))) {
- /* reports always */
- parser_warn(p, get_nd_value(p, node), "found `= literal' in conditional, should be ==");
+ if (!node->nd_value) return 1;
+ if (is_static_content(node->nd_value)) {
+ /* reports always */
+ parser_warn(p, node->nd_value, "found `= literal' in conditional, should be ==");
}
return 1;
}
@@ -14061,13 +12384,12 @@ enum cond_type {
COND_IN_FF
};
-#define SWITCH_BY_COND_TYPE(t, w, arg) do { \
+#define SWITCH_BY_COND_TYPE(t, w, arg) \
switch (t) { \
case COND_IN_OP: break; \
case COND_IN_COND: rb_##w##0(arg "literal in condition"); break; \
case COND_IN_FF: rb_##w##0(arg "literal in flip-flop"); break; \
- } \
-} while (0)
+ }
static NODE *cond0(struct parser_params*,NODE*,enum cond_type,const YYLTYPE*);
@@ -14080,10 +12402,10 @@ range_op(struct parser_params *p, NODE *node, const YYLTYPE *loc)
type = nd_type(node);
value_expr(node);
- if (type == NODE_LIT && FIXNUM_P(RNODE_LIT(node)->nd_lit)) {
- if (!e_option_supplied(p)) parser_warn(p, node, "integer literal in flip-flop");
- ID lineno = rb_intern("$.");
- return NEW_CALL(node, tEQ, NEW_LIST(NEW_GVAR(lineno, loc), loc), loc);
+ if (type == NODE_LIT && FIXNUM_P(node->nd_lit)) {
+ if (!e_option_supplied(p)) parser_warn(p, node, "integer literal in flip-flop");
+ ID lineno = rb_intern("$.");
+ return NEW_CALL(node, tEQ, NEW_LIST(NEW_GVAR(lineno, loc), loc), loc);
}
return cond0(p, node, COND_IN_FF, loc);
}
@@ -14099,54 +12421,50 @@ cond0(struct parser_params *p, NODE *node, enum cond_type type, const YYLTYPE *l
case NODE_DSTR:
case NODE_EVSTR:
case NODE_STR:
- SWITCH_BY_COND_TYPE(type, warn, "string ");
- break;
+ SWITCH_BY_COND_TYPE(type, warn, "string ")
+ break;
case NODE_DREGX:
- if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warning, "regex ");
+ if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warning, "regex ")
- return NEW_MATCH2(node, NEW_GVAR(idLASTLINE, loc), loc);
-
- case NODE_BLOCK:
- RNODE_BLOCK(RNODE_BLOCK(node)->nd_end)->nd_head = cond0(p, RNODE_BLOCK(RNODE_BLOCK(node)->nd_end)->nd_head, type, loc);
- break;
+ return NEW_MATCH2(node, NEW_GVAR(idLASTLINE, loc), loc);
case NODE_AND:
case NODE_OR:
- RNODE_AND(node)->nd_1st = cond0(p, RNODE_AND(node)->nd_1st, COND_IN_COND, loc);
- RNODE_AND(node)->nd_2nd = cond0(p, RNODE_AND(node)->nd_2nd, COND_IN_COND, loc);
- break;
+ node->nd_1st = cond0(p, node->nd_1st, COND_IN_COND, loc);
+ node->nd_2nd = cond0(p, node->nd_2nd, COND_IN_COND, loc);
+ break;
case NODE_DOT2:
case NODE_DOT3:
- RNODE_DOT2(node)->nd_beg = range_op(p, RNODE_DOT2(node)->nd_beg, loc);
- RNODE_DOT2(node)->nd_end = range_op(p, RNODE_DOT2(node)->nd_end, loc);
- if (nd_type_p(node, NODE_DOT2)) nd_set_type(node,NODE_FLIP2);
- else if (nd_type_p(node, NODE_DOT3)) nd_set_type(node, NODE_FLIP3);
- break;
+ node->nd_beg = range_op(p, node->nd_beg, loc);
+ node->nd_end = range_op(p, node->nd_end, loc);
+ if (nd_type_p(node, NODE_DOT2)) nd_set_type(node,NODE_FLIP2);
+ else if (nd_type_p(node, NODE_DOT3)) nd_set_type(node, NODE_FLIP3);
+ break;
case NODE_DSYM:
warn_symbol:
- SWITCH_BY_COND_TYPE(type, warning, "symbol ");
- break;
+ SWITCH_BY_COND_TYPE(type, warning, "symbol ")
+ break;
case NODE_LIT:
- if (RB_TYPE_P(RNODE_LIT(node)->nd_lit, T_REGEXP)) {
- if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warn, "regex ");
- nd_set_type(node, NODE_MATCH);
- }
- else if (RNODE_LIT(node)->nd_lit == Qtrue ||
- RNODE_LIT(node)->nd_lit == Qfalse) {
- /* booleans are OK, e.g., while true */
- }
- else if (SYMBOL_P(RNODE_LIT(node)->nd_lit)) {
- goto warn_symbol;
- }
- else {
- SWITCH_BY_COND_TYPE(type, warning, "");
- }
+ if (RB_TYPE_P(node->nd_lit, T_REGEXP)) {
+ if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warn, "regex ")
+ nd_set_type(node, NODE_MATCH);
+ }
+ else if (node->nd_lit == Qtrue ||
+ node->nd_lit == Qfalse) {
+ /* booleans are OK, e.g., while true */
+ }
+ else if (SYMBOL_P(node->nd_lit)) {
+ goto warn_symbol;
+ }
+ else {
+ SWITCH_BY_COND_TYPE(type, warning, "")
+ }
default:
- break;
+ break;
}
return node;
}
@@ -14188,37 +12506,33 @@ new_unless(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYL
return newline_node(NEW_UNLESS(cc, left, right, loc));
}
-#define NEW_AND_OR(type, f, s, loc) (type == NODE_AND ? NEW_AND(f,s,loc) : NEW_OR(f,s,loc))
-
static NODE*
logop(struct parser_params *p, ID id, NODE *left, NODE *right,
- const YYLTYPE *op_loc, const YYLTYPE *loc)
+ const YYLTYPE *op_loc, const YYLTYPE *loc)
{
enum node_type type = id == idAND || id == idANDOP ? NODE_AND : NODE_OR;
NODE *op;
value_expr(left);
if (left && nd_type_p(left, type)) {
- NODE *node = left, *second;
- while ((second = RNODE_AND(node)->nd_2nd) != 0 && nd_type_p(second, type)) {
- node = second;
- }
- RNODE_AND(node)->nd_2nd = NEW_AND_OR(type, second, right, loc);
- nd_set_line(RNODE_AND(node)->nd_2nd, op_loc->beg_pos.lineno);
- left->nd_loc.end_pos = loc->end_pos;
- return left;
- }
- op = NEW_AND_OR(type, left, right, loc);
+ NODE *node = left, *second;
+ while ((second = node->nd_2nd) != 0 && nd_type_p(second, type)) {
+ node = second;
+ }
+ node->nd_2nd = NEW_NODE(type, second, right, 0, loc);
+ nd_set_line(node->nd_2nd, op_loc->beg_pos.lineno);
+ left->nd_loc.end_pos = loc->end_pos;
+ return left;
+ }
+ op = NEW_NODE(type, left, right, 0, loc);
nd_set_line(op, op_loc->beg_pos.lineno);
return op;
}
-#undef NEW_AND_OR
-
static void
no_blockarg(struct parser_params *p, NODE *node)
{
if (nd_type_p(node, NODE_BLOCK_PASS)) {
- compile_error(p, "block argument should not be given");
+ compile_error(p, "block argument should not be given");
}
}
@@ -14226,10 +12540,15 @@ static NODE *
ret_args(struct parser_params *p, NODE *node)
{
if (node) {
- no_blockarg(p, node);
- if (nd_type_p(node, NODE_LIST) && !RNODE_LIST(node)->nd_next) {
- node = RNODE_LIST(node)->nd_head;
- }
+ no_blockarg(p, node);
+ if (nd_type_p(node, NODE_LIST)) {
+ if (node->nd_next == 0) {
+ node = node->nd_head;
+ }
+ else {
+ nd_set_type(node, NODE_VALUES);
+ }
+ }
}
return node;
}
@@ -14246,49 +12565,49 @@ static VALUE
negate_lit(struct parser_params *p, VALUE lit)
{
if (FIXNUM_P(lit)) {
- return LONG2FIX(-FIX2LONG(lit));
+ return LONG2FIX(-FIX2LONG(lit));
}
if (SPECIAL_CONST_P(lit)) {
#if USE_FLONUM
- if (FLONUM_P(lit)) {
- return DBL2NUM(-RFLOAT_VALUE(lit));
- }
+ if (FLONUM_P(lit)) {
+ return DBL2NUM(-RFLOAT_VALUE(lit));
+ }
#endif
- goto unknown;
+ goto unknown;
}
switch (BUILTIN_TYPE(lit)) {
case T_BIGNUM:
- bignum_negate(lit);
- lit = rb_big_norm(lit);
- break;
+ BIGNUM_NEGATE(lit);
+ lit = rb_big_norm(lit);
+ break;
case T_RATIONAL:
- rational_set_num(lit, negate_lit(p, rational_get_num(lit)));
- break;
+ RATIONAL_SET_NUM(lit, negate_lit(p, RRATIONAL(lit)->num));
+ break;
case T_COMPLEX:
- rcomplex_set_real(lit, negate_lit(p, rcomplex_get_real(lit)));
- rcomplex_set_imag(lit, negate_lit(p, rcomplex_get_imag(lit)));
- break;
+ RCOMPLEX_SET_REAL(lit, negate_lit(p, RCOMPLEX(lit)->real));
+ RCOMPLEX_SET_IMAG(lit, negate_lit(p, RCOMPLEX(lit)->imag));
+ break;
case T_FLOAT:
- lit = DBL2NUM(-RFLOAT_VALUE(lit));
- break;
+ lit = DBL2NUM(-RFLOAT_VALUE(lit));
+ break;
unknown:
default:
- rb_parser_fatal(p, "unknown literal type (%s) passed to negate_lit",
- rb_builtin_class_name(lit));
- break;
+ rb_parser_fatal(p, "unknown literal type (%s) passed to negate_lit",
+ rb_builtin_class_name(lit));
+ break;
}
return lit;
}
static NODE *
-arg_blk_pass(NODE *node1, rb_node_block_pass_t *node2)
+arg_blk_pass(NODE *node1, NODE *node2)
{
if (node2) {
- if (!node1) return (NODE *)node2;
- node2->nd_head = node1;
- nd_set_first_lineno(node2, nd_first_lineno(node1));
- nd_set_first_column(node2, nd_first_column(node1));
- return (NODE *)node2;
+ if (!node1) return node2;
+ node2->nd_head = node1;
+ nd_set_first_lineno(node2, nd_first_lineno(node1));
+ nd_set_first_column(node2, nd_first_column(node1));
+ return node2;
}
return node1;
}
@@ -14306,17 +12625,18 @@ args_info_empty_p(struct rb_args_info *args)
return true;
}
-static rb_node_args_t *
-new_args(struct parser_params *p, rb_node_args_aux_t *pre_args, rb_node_opt_arg_t *opt_args, ID rest_arg, rb_node_args_aux_t *post_args, rb_node_args_t *tail, const YYLTYPE *loc)
+static NODE*
+new_args(struct parser_params *p, NODE *pre_args, NODE *opt_args, ID rest_arg, NODE *post_args, NODE *tail, const YYLTYPE *loc)
{
- struct rb_args_info *args = &tail->nd_ainfo;
+ int saved_line = p->ruby_sourceline;
+ struct rb_args_info *args = tail->nd_ainfo;
if (args->forwarding) {
- if (rest_arg) {
- yyerror1(&RNODE(tail)->nd_loc, "... after rest argument");
- return tail;
- }
- rest_arg = idFWD_REST;
+ if (rest_arg) {
+ yyerror1(&tail->nd_loc, "... after rest argument");
+ return tail;
+ }
+ rest_arg = idFWD_REST;
}
args->pre_args_num = pre_args ? rb_long2int(pre_args->nd_plen) : 0;
@@ -14336,78 +12656,87 @@ new_args(struct parser_params *p, rb_node_args_aux_t *pre_args, rb_node_opt_arg_
args->ruby2_keywords = 0;
#endif
- nd_set_loc(RNODE(tail), loc);
+ p->ruby_sourceline = saved_line;
+ nd_set_loc(tail, loc);
return tail;
}
-static rb_node_args_t *
-new_args_tail(struct parser_params *p, rb_node_kw_arg_t *kw_args, ID kw_rest_arg, ID block, const YYLTYPE *kw_rest_loc)
+static NODE*
+new_args_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, ID block, const YYLTYPE *kw_rest_loc)
{
- rb_node_args_t *node = NEW_ARGS(&NULL_LOC);
- struct rb_args_info *args = &node->nd_ainfo;
+ int saved_line = p->ruby_sourceline;
+ NODE *node;
+ VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
+ struct rb_args_info *args = ZALLOC(struct rb_args_info);
+ rb_imemo_tmpbuf_set_ptr(tmpbuf, args);
+ args->imemo = tmpbuf;
+ node = NEW_NODE(NODE_ARGS, 0, 0, args, &NULL_LOC);
+ RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
if (p->error_p) return node;
args->block_arg = block;
args->kw_args = kw_args;
if (kw_args) {
- /*
- * def foo(k1: 1, kr1:, k2: 2, **krest, &b)
- * variable order: k1, kr1, k2, &b, internal_id, krest
- * #=> <reorder>
- * variable order: kr1, k1, k2, internal_id, krest, &b
- */
- ID kw_bits = internal_id(p), *required_kw_vars, *kw_vars;
- struct vtable *vtargs = p->lvtbl->args;
- rb_node_kw_arg_t *kwn = kw_args;
+ /*
+ * def foo(k1: 1, kr1:, k2: 2, **krest, &b)
+ * variable order: k1, kr1, k2, &b, internal_id, krest
+ * #=> <reorder>
+ * variable order: kr1, k1, k2, internal_id, krest, &b
+ */
+ ID kw_bits = internal_id(p), *required_kw_vars, *kw_vars;
+ struct vtable *vtargs = p->lvtbl->args;
+ NODE *kwn = kw_args;
if (block) block = vtargs->tbl[vtargs->pos-1];
- vtable_pop(vtargs, !!block + !!kw_rest_arg);
- required_kw_vars = kw_vars = &vtargs->tbl[vtargs->pos];
- while (kwn) {
- if (!NODE_REQUIRED_KEYWORD_P(get_nd_value(p, kwn->nd_body)))
- --kw_vars;
- --required_kw_vars;
- kwn = kwn->nd_next;
- }
-
- for (kwn = kw_args; kwn; kwn = kwn->nd_next) {
- ID vid = get_nd_vid(p, kwn->nd_body);
- if (NODE_REQUIRED_KEYWORD_P(get_nd_value(p, kwn->nd_body))) {
- *required_kw_vars++ = vid;
- }
- else {
- *kw_vars++ = vid;
- }
- }
-
- arg_var(p, kw_bits);
- if (kw_rest_arg) arg_var(p, kw_rest_arg);
- if (block) arg_var(p, block);
-
- args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
+ vtable_pop(vtargs, !!block + !!kw_rest_arg);
+ required_kw_vars = kw_vars = &vtargs->tbl[vtargs->pos];
+ while (kwn) {
+ if (!NODE_REQUIRED_KEYWORD_P(kwn->nd_body))
+ --kw_vars;
+ --required_kw_vars;
+ kwn = kwn->nd_next;
+ }
+
+ for (kwn = kw_args; kwn; kwn = kwn->nd_next) {
+ ID vid = kwn->nd_body->nd_vid;
+ if (NODE_REQUIRED_KEYWORD_P(kwn->nd_body)) {
+ *required_kw_vars++ = vid;
+ }
+ else {
+ *kw_vars++ = vid;
+ }
+ }
+
+ arg_var(p, kw_bits);
+ if (kw_rest_arg) arg_var(p, kw_rest_arg);
+ if (block) arg_var(p, block);
+
+ args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
+ args->kw_rest_arg->nd_cflag = kw_bits;
}
else if (kw_rest_arg == idNil) {
- args->no_kwarg = 1;
+ args->no_kwarg = 1;
}
else if (kw_rest_arg) {
- args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
+ args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
}
+ p->ruby_sourceline = saved_line;
return node;
}
-static rb_node_args_t *
-args_with_numbered(struct parser_params *p, rb_node_args_t *args, int max_numparam)
+static NODE *
+args_with_numbered(struct parser_params *p, NODE *args, int max_numparam)
{
if (max_numparam > NO_PARAM) {
- if (!args) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- args = new_args_tail(p, 0, 0, 0, 0);
- nd_set_loc(RNODE(args), &loc);
- }
- args->nd_ainfo.pre_args_num = max_numparam;
+ if (!args) {
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ args = new_args_tail(p, 0, 0, 0, 0);
+ nd_set_loc(args, &loc);
+ }
+ args->nd_ainfo->pre_args_num = max_numparam;
}
return args;
}
@@ -14415,76 +12744,106 @@ args_with_numbered(struct parser_params *p, rb_node_args_t *args, int max_numpar
static NODE*
new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *aryptn, const YYLTYPE *loc)
{
- RNODE_ARYPTN(aryptn)->nd_pconst = constant;
+ struct rb_ary_pattern_info *apinfo = aryptn->nd_apinfo;
+
+ aryptn->nd_pconst = constant;
if (pre_arg) {
- NODE *pre_args = NEW_LIST(pre_arg, loc);
- if (RNODE_ARYPTN(aryptn)->pre_args) {
- RNODE_ARYPTN(aryptn)->pre_args = list_concat(pre_args, RNODE_ARYPTN(aryptn)->pre_args);
- }
- else {
- RNODE_ARYPTN(aryptn)->pre_args = pre_args;
- }
+ NODE *pre_args = NEW_LIST(pre_arg, loc);
+ if (apinfo->pre_args) {
+ apinfo->pre_args = list_concat(pre_args, apinfo->pre_args);
+ }
+ else {
+ apinfo->pre_args = pre_args;
+ }
}
return aryptn;
}
static NODE*
-new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc)
+new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID rest_arg, NODE *post_args, const YYLTYPE *loc)
{
+ int saved_line = p->ruby_sourceline;
+ NODE *node;
+ VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
+ struct rb_ary_pattern_info *apinfo = ZALLOC(struct rb_ary_pattern_info);
+ rb_imemo_tmpbuf_set_ptr(tmpbuf, apinfo);
+ node = NEW_NODE(NODE_ARYPTN, 0, tmpbuf, apinfo, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
+
+ apinfo->pre_args = pre_args;
+
if (has_rest) {
- rest_arg = rest_arg ? rest_arg : NODE_SPECIAL_NO_NAME_REST;
+ if (rest_arg) {
+ apinfo->rest_arg = assignable(p, rest_arg, 0, loc);
+ }
+ else {
+ apinfo->rest_arg = NODE_SPECIAL_NO_NAME_REST;
+ }
}
else {
- rest_arg = NULL;
+ apinfo->rest_arg = NULL;
}
- NODE *node = NEW_ARYPTN(pre_args, rest_arg, post_args, loc);
+ apinfo->post_args = post_args;
+
+ p->ruby_sourceline = saved_line;
return node;
}
static NODE*
new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc)
{
- RNODE_FNDPTN(fndptn)->nd_pconst = constant;
+ fndptn->nd_pconst = constant;
return fndptn;
}
static NODE*
-new_find_pattern_tail(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc)
+new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc)
{
- pre_rest_arg = pre_rest_arg ? pre_rest_arg : NODE_SPECIAL_NO_NAME_REST;
- post_rest_arg = post_rest_arg ? post_rest_arg : NODE_SPECIAL_NO_NAME_REST;
- NODE *node = NEW_FNDPTN(pre_rest_arg, args, post_rest_arg, loc);
+ int saved_line = p->ruby_sourceline;
+ NODE *node;
+ VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
+ struct rb_fnd_pattern_info *fpinfo = ZALLOC(struct rb_fnd_pattern_info);
+ rb_imemo_tmpbuf_set_ptr(tmpbuf, fpinfo);
+ node = NEW_NODE(NODE_FNDPTN, 0, tmpbuf, fpinfo, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
+
+ fpinfo->pre_rest_arg = pre_rest_arg ? assignable(p, pre_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
+ fpinfo->args = args;
+ fpinfo->post_rest_arg = post_rest_arg ? assignable(p, post_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
+ p->ruby_sourceline = saved_line;
return node;
}
static NODE*
new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc)
{
- RNODE_HSHPTN(hshptn)->nd_pconst = constant;
+ hshptn->nd_pconst = constant;
return hshptn;
}
static NODE*
new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, const YYLTYPE *loc)
{
+ int saved_line = p->ruby_sourceline;
NODE *node, *kw_rest_arg_node;
if (kw_rest_arg == idNil) {
- kw_rest_arg_node = NODE_SPECIAL_NO_REST_KEYWORD;
+ kw_rest_arg_node = NODE_SPECIAL_NO_REST_KEYWORD;
}
else if (kw_rest_arg) {
- kw_rest_arg_node = assignable(p, kw_rest_arg, 0, loc);
+ kw_rest_arg_node = assignable(p, kw_rest_arg, 0, loc);
}
else {
- kw_rest_arg_node = NULL;
+ kw_rest_arg_node = NULL;
}
- node = NEW_HSHPTN(0, kw_args, kw_rest_arg_node, loc);
+ node = NEW_NODE(NODE_HSHPTN, 0, kw_args, kw_rest_arg_node, loc);
+ p->ruby_sourceline = saved_line;
return node;
}
@@ -14494,23 +12853,23 @@ dsym_node(struct parser_params *p, NODE *node, const YYLTYPE *loc)
VALUE lit;
if (!node) {
- return NEW_LIT(ID2SYM(idNULL), loc);
+ return NEW_LIT(ID2SYM(idNULL), loc);
}
switch (nd_type(node)) {
case NODE_DSTR:
- nd_set_type(node, NODE_DSYM);
- nd_set_loc(node, loc);
- break;
+ nd_set_type(node, NODE_DSYM);
+ nd_set_loc(node, loc);
+ break;
case NODE_STR:
- lit = RNODE_STR(node)->nd_lit;
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_STR(node)->nd_lit = ID2SYM(rb_intern_str(lit)));
- nd_set_type(node, NODE_LIT);
- nd_set_loc(node, loc);
- break;
+ lit = node->nd_lit;
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit = ID2SYM(rb_intern_str(lit)));
+ nd_set_type(node, NODE_LIT);
+ nd_set_loc(node, loc);
+ break;
default:
- node = NEW_DSYM(Qnil, 1, NEW_LIST(node, loc), loc);
- break;
+ node = NEW_NODE(NODE_DSYM, Qnil, 1, NEW_LIST(node, loc), loc);
+ break;
}
return node;
}
@@ -14520,60 +12879,83 @@ append_literal_keys(st_data_t k, st_data_t v, st_data_t h)
{
NODE *node = (NODE *)v;
NODE **result = (NODE **)h;
- RNODE_LIST(node)->as.nd_alen = 2;
- RNODE_LIST(RNODE_LIST(node)->nd_next)->as.nd_end = RNODE_LIST(node)->nd_next;
- RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next = 0;
+ node->nd_alen = 2;
+ node->nd_next->nd_end = node->nd_next;
+ node->nd_next->nd_next = 0;
if (*result)
- list_concat(*result, node);
+ list_concat(*result, node);
else
- *result = node;
+ *result = node;
return ST_CONTINUE;
}
+static bool
+hash_literal_key_p(VALUE k)
+{
+ switch (OBJ_BUILTIN_TYPE(k)) {
+ case T_NODE:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static int
+literal_cmp(VALUE val, VALUE lit)
+{
+ if (val == lit) return 0;
+ if (!hash_literal_key_p(val) || !hash_literal_key_p(lit)) return -1;
+ return rb_iseq_cdhash_cmp(val, lit);
+}
+
+static st_index_t
+literal_hash(VALUE a)
+{
+ if (!hash_literal_key_p(a)) return (st_index_t)a;
+ return rb_iseq_cdhash_hash(a);
+}
+
+static const struct st_hash_type literal_type = {
+ literal_cmp,
+ literal_hash,
+};
+
static NODE *
remove_duplicate_keys(struct parser_params *p, NODE *hash)
{
- struct st_hash_type literal_type = {
- literal_cmp,
- literal_hash,
- };
-
- st_table *literal_keys = st_init_table_with_size(&literal_type, RNODE_LIST(hash)->as.nd_alen / 2);
+ st_table *literal_keys = st_init_table_with_size(&literal_type, hash->nd_alen / 2);
NODE *result = 0;
NODE *last_expr = 0;
rb_code_location_t loc = hash->nd_loc;
- while (hash && RNODE_LIST(hash)->nd_next) {
- NODE *head = RNODE_LIST(hash)->nd_head;
- NODE *value = RNODE_LIST(hash)->nd_next;
- NODE *next = RNODE_LIST(value)->nd_next;
- st_data_t key = (st_data_t)head;
- st_data_t data;
- RNODE_LIST(value)->nd_next = 0;
- if (!head) {
- key = (st_data_t)value;
- }
- else if (nd_type_p(head, NODE_LIT) &&
- st_delete(literal_keys, (key = (st_data_t)RNODE_LIT(head)->nd_lit, &key), &data)) {
- NODE *dup_value = (RNODE_LIST((NODE *)data))->nd_next;
- rb_compile_warn(p->ruby_sourcefile, nd_line((NODE *)data),
- "key %+"PRIsVALUE" is duplicated and overwritten on line %d",
- RNODE_LIT(head)->nd_lit, nd_line(head));
- if (dup_value == last_expr) {
- RNODE_LIST(value)->nd_head = block_append(p, RNODE_LIST(dup_value)->nd_head, RNODE_LIST(value)->nd_head);
- }
- else {
- RNODE_LIST(last_expr)->nd_head = block_append(p, RNODE_LIST(dup_value)->nd_head, RNODE_LIST(last_expr)->nd_head);
- }
- }
- st_insert(literal_keys, (st_data_t)key, (st_data_t)hash);
- last_expr = !head || nd_type_p(head, NODE_LIT) ? value : head;
- hash = next;
+ while (hash && hash->nd_head && hash->nd_next) {
+ NODE *head = hash->nd_head;
+ NODE *value = hash->nd_next;
+ NODE *next = value->nd_next;
+ st_data_t key = (st_data_t)head;
+ st_data_t data;
+ value->nd_next = 0;
+ if (nd_type_p(head, NODE_LIT) &&
+ st_delete(literal_keys, (key = (st_data_t)head->nd_lit, &key), &data)) {
+ NODE *dup_value = ((NODE *)data)->nd_next;
+ rb_compile_warn(p->ruby_sourcefile, nd_line((NODE *)data),
+ "key %+"PRIsVALUE" is duplicated and overwritten on line %d",
+ head->nd_lit, nd_line(head));
+ if (dup_value == last_expr) {
+ value->nd_head = block_append(p, dup_value->nd_head, value->nd_head);
+ }
+ else {
+ last_expr->nd_head = block_append(p, dup_value->nd_head, last_expr->nd_head);
+ }
+ }
+ st_insert(literal_keys, (st_data_t)key, (st_data_t)hash);
+ last_expr = nd_type_p(head, NODE_LIT) ? value : head;
+ hash = next;
}
st_foreach(literal_keys, append_literal_keys, (st_data_t)&result);
st_free_table(literal_keys);
if (hash) {
- if (!result) result = hash;
- else list_concat(result, hash);
+ if (!result) result = hash;
+ else list_concat(result, hash);
}
result->nd_loc = loc;
return result;
@@ -14590,14 +12972,14 @@ new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc)
static void
error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc)
{
- if (is_private_local_id(p, id)) {
- return;
+ if (is_private_local_id(id)) {
+ return;
}
if (st_is_member(p->pvtbl, id)) {
- yyerror1(loc, "duplicated variable name");
+ yyerror1(loc, "duplicated variable name");
}
else {
- st_insert(p->pvtbl, (st_data_t)id, 0);
+ st_insert(p->pvtbl, (st_data_t)id, 0);
}
}
@@ -14605,11 +12987,11 @@ static void
error_duplicate_pattern_key(struct parser_params *p, VALUE key, const YYLTYPE *loc)
{
if (!p->pktbl) {
- p->pktbl = st_init_numtable();
+ p->pktbl = st_init_numtable();
}
else if (st_is_member(p->pktbl, key)) {
- yyerror1(loc, "duplicated key name");
- return;
+ yyerror1(loc, "duplicated key name");
+ return;
}
st_insert(p->pktbl, (st_data_t)key, 0);
}
@@ -14629,65 +13011,79 @@ new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_c
NODE *asgn;
if (lhs) {
- ID vid = get_nd_vid(p, lhs);
- YYLTYPE lhs_loc = lhs->nd_loc;
- int shareable = ctxt.shareable_constant_value;
- if (shareable) {
- switch (nd_type(lhs)) {
- case NODE_CDECL:
- case NODE_COLON2:
- case NODE_COLON3:
- break;
- default:
- shareable = 0;
- break;
- }
- }
- if (op == tOROP) {
- rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
- set_nd_value(p, lhs, rhs);
- nd_set_loc(lhs, loc);
- asgn = NEW_OP_ASGN_OR(gettable(p, vid, &lhs_loc), lhs, loc);
- }
- else if (op == tANDOP) {
- if (shareable) {
- rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
- }
- set_nd_value(p, lhs, rhs);
- nd_set_loc(lhs, loc);
- asgn = NEW_OP_ASGN_AND(gettable(p, vid, &lhs_loc), lhs, loc);
- }
- else {
- asgn = lhs;
- rhs = NEW_CALL(gettable(p, vid, &lhs_loc), op, NEW_LIST(rhs, &rhs->nd_loc), loc);
- if (shareable) {
- rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
- }
- set_nd_value(p, asgn, rhs);
- nd_set_loc(asgn, loc);
- }
+ ID vid = lhs->nd_vid;
+ YYLTYPE lhs_loc = lhs->nd_loc;
+ int shareable = ctxt.shareable_constant_value;
+ if (shareable) {
+ switch (nd_type(lhs)) {
+ case NODE_CDECL:
+ case NODE_COLON2:
+ case NODE_COLON3:
+ break;
+ default:
+ shareable = 0;
+ break;
+ }
+ }
+ if (op == tOROP) {
+ rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
+ lhs->nd_value = rhs;
+ nd_set_loc(lhs, loc);
+ asgn = NEW_OP_ASGN_OR(gettable(p, vid, &lhs_loc), lhs, loc);
+ if (is_notop_id(vid)) {
+ switch (id_type(vid)) {
+ case ID_GLOBAL:
+ case ID_INSTANCE:
+ case ID_CLASS:
+ asgn->nd_aid = vid;
+ }
+ }
+ }
+ else if (op == tANDOP) {
+ if (shareable) {
+ rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
+ }
+ lhs->nd_value = rhs;
+ nd_set_loc(lhs, loc);
+ asgn = NEW_OP_ASGN_AND(gettable(p, vid, &lhs_loc), lhs, loc);
+ }
+ else {
+ asgn = lhs;
+ rhs = NEW_CALL(gettable(p, vid, &lhs_loc), op, NEW_LIST(rhs, &rhs->nd_loc), loc);
+ if (shareable) {
+ rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
+ }
+ asgn->nd_value = rhs;
+ nd_set_loc(asgn, loc);
+ }
}
else {
- asgn = NEW_BEGIN(0, loc);
+ asgn = NEW_BEGIN(0, loc);
}
return asgn;
}
static NODE *
new_ary_op_assign(struct parser_params *p, NODE *ary,
- NODE *args, ID op, NODE *rhs, const YYLTYPE *args_loc, const YYLTYPE *loc)
+ NODE *args, ID op, NODE *rhs, const YYLTYPE *args_loc, const YYLTYPE *loc)
{
NODE *asgn;
args = make_list(args, args_loc);
- asgn = NEW_OP_ASGN1(ary, op, args, rhs, loc);
+ if (nd_type_p(args, NODE_BLOCK_PASS)) {
+ args = NEW_ARGSCAT(args, rhs, loc);
+ }
+ else {
+ args = arg_concat(p, args, rhs, loc);
+ }
+ asgn = NEW_OP_ASGN1(ary, op, args, loc);
fixpos(asgn, ary);
return asgn;
}
static NODE *
new_attr_op_assign(struct parser_params *p, NODE *lhs,
- ID atype, ID attr, ID op, NODE *rhs, const YYLTYPE *loc)
+ ID atype, ID attr, ID op, NODE *rhs, const YYLTYPE *loc)
{
NODE *asgn;
@@ -14702,11 +13098,11 @@ new_const_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct
NODE *asgn;
if (lhs) {
- rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
- asgn = NEW_OP_CDECL(lhs, op, rhs, loc);
+ rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
+ asgn = NEW_OP_CDECL(lhs, op, rhs, loc);
}
else {
- asgn = NEW_BEGIN(0, loc);
+ asgn = NEW_BEGIN(0, loc);
}
fixpos(asgn, lhs);
return asgn;
@@ -14716,7 +13112,7 @@ static NODE *
const_decl(struct parser_params *p, NODE *path, const YYLTYPE *loc)
{
if (p->ctxt.in_def) {
- yyerror1(loc, "dynamic constant assignment");
+ yyerror1(loc, "dynamic constant assignment");
}
return NEW_CDECL(0, 0, (path), loc);
}
@@ -14725,7 +13121,7 @@ static VALUE
const_decl(struct parser_params *p, VALUE path)
{
if (p->ctxt.in_def) {
- path = assign_error(p, "dynamic constant assignment", path);
+ path = assign_error(p, "dynamic constant assignment", path);
}
return path;
}
@@ -14776,15 +13172,15 @@ warn_unused_var(struct parser_params *p, struct local_vars *local)
if (!local->used) return;
cnt = local->used->pos;
if (cnt != local->vars->pos) {
- rb_parser_fatal(p, "local->used->pos != local->vars->pos");
+ rb_parser_fatal(p, "local->used->pos != local->vars->pos");
}
#ifndef RIPPER
ID *v = local->vars->tbl;
ID *u = local->used->tbl;
for (int i = 0; i < cnt; ++i) {
- if (!v[i] || (u[i] & LVAR_USED)) continue;
- if (is_private_local_id(p, v[i])) continue;
- rb_warn1L((int)u[i], "assigned but unused variable - %"PRIsWARN, rb_id2str(v[i]));
+ if (!v[i] || (u[i] & LVAR_USED)) continue;
+ if (is_private_local_id(v[i])) continue;
+ rb_warn1L((int)u[i], "assigned but unused variable - %"PRIsWARN, rb_id2str(v[i]));
}
#endif
}
@@ -14872,10 +13268,10 @@ local_tbl(struct parser_params *p)
MEMCPY(tbl->ids, p->lvtbl->args->tbl, ID, cnt_args);
/* remove IDs duplicated to warn shadowing */
for (i = 0, j = cnt_args; i < cnt_vars; ++i) {
- ID id = p->lvtbl->vars->tbl[i];
- if (!vtable_included(p->lvtbl->args, id)) {
- tbl->ids[j++] = id;
- }
+ ID id = p->lvtbl->vars->tbl[i];
+ if (!vtable_included(p->lvtbl->args, id)) {
+ tbl->ids[j++] = id;
+ }
}
if (j < cnt) {
tbl = rb_ast_resize_latest_local_table(p->ast, j);
@@ -14884,6 +13280,17 @@ local_tbl(struct parser_params *p)
return tbl;
}
+static NODE*
+node_newnode_with_locals(struct parser_params *p, enum node_type type, VALUE a1, VALUE a2, const rb_code_location_t *loc)
+{
+ rb_ast_id_table_t *a0;
+ NODE *n;
+
+ a0 = local_tbl(p);
+ n = NEW_NODE(type, a0, a1, a2, loc);
+ return n;
+}
+
#endif
static void
@@ -14907,7 +13314,7 @@ local_var(struct parser_params *p, ID id)
numparam_name(p, id);
vtable_add(p->lvtbl->vars, id);
if (p->lvtbl->used) {
- vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline);
+ vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline);
}
}
@@ -14921,21 +13328,21 @@ local_id_ref(struct parser_params *p, ID id, ID **vidrefp)
used = p->lvtbl->used;
while (vars && !DVARS_TERMINAL_P(vars->prev)) {
- vars = vars->prev;
- args = args->prev;
- if (used) used = used->prev;
+ vars = vars->prev;
+ args = args->prev;
+ if (used) used = used->prev;
}
if (vars && vars->prev == DVARS_INHERIT) {
- return rb_local_defined(id, p->parent_iseq);
+ return rb_local_defined(id, p->parent_iseq);
}
else if (vtable_included(args, id)) {
- return 1;
+ return 1;
}
else {
- int i = vtable_included(vars, id);
- if (i && used && vidrefp) *vidrefp = &used->tbl[i-1];
- return i != 0;
+ int i = vtable_included(vars, id);
+ if (i && used && vidrefp) *vidrefp = &used->tbl[i-1];
+ return i != 0;
}
}
@@ -14972,7 +13379,7 @@ new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc
#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
NODE *kwrest = list_append(p, NEW_LIST(0, loc), NEW_LVAR(idFWD_KWREST, loc));
#endif
- rb_node_block_pass_t *block = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, loc), loc);
+ NODE *block = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, loc), loc);
NODE *args = leading ? rest_arg_append(p, leading, rest, argsloc) : NEW_SPLAT(rest, loc);
#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
args = arg_append(p, args, new_hash(p, kwrest, loc), loc);
@@ -14988,7 +13395,7 @@ numparam_push(struct parser_params *p)
struct local_vars *local = p->lvtbl;
NODE *inner = local->numparam.inner;
if (!local->numparam.outer) {
- local->numparam.outer = local->numparam.current;
+ local->numparam.outer = local->numparam.current;
}
local->numparam.inner = 0;
local->numparam.current = 0;
@@ -15004,21 +13411,21 @@ numparam_pop(struct parser_params *p, NODE *prev_inner)
#ifndef RIPPER
struct local_vars *local = p->lvtbl;
if (prev_inner) {
- /* prefer first one */
- local->numparam.inner = prev_inner;
+ /* prefer first one */
+ local->numparam.inner = prev_inner;
}
else if (local->numparam.current) {
- /* current and inner are exclusive */
- local->numparam.inner = local->numparam.current;
+ /* current and inner are exclusive */
+ local->numparam.inner = local->numparam.current;
}
if (p->max_numparam > NO_PARAM) {
- /* current and outer are exclusive */
- local->numparam.current = local->numparam.outer;
- local->numparam.outer = 0;
+ /* current and outer are exclusive */
+ local->numparam.current = local->numparam.outer;
+ local->numparam.outer = 0;
}
else {
- /* no numbered parameter */
- local->numparam.current = 0;
+ /* no numbered parameter */
+ local->numparam.current = 0;
}
#endif
}
@@ -15029,7 +13436,7 @@ dyna_push(struct parser_params *p)
p->lvtbl->args = vtable_alloc(p->lvtbl->args);
p->lvtbl->vars = vtable_alloc(p->lvtbl->vars);
if (p->lvtbl->used) {
- p->lvtbl->used = vtable_alloc(p->lvtbl->used);
+ p->lvtbl->used = vtable_alloc(p->lvtbl->used);
}
return p->lvtbl->args;
}
@@ -15041,9 +13448,9 @@ dyna_pop_vtable(struct parser_params *p, struct vtable **vtblp)
*vtblp = tmp->prev;
# if WARN_PAST_SCOPE
if (p->past_scope_enabled) {
- tmp->prev = p->lvtbl->past;
- p->lvtbl->past = tmp;
- return;
+ tmp->prev = p->lvtbl->past;
+ p->lvtbl->past = tmp;
+ return;
}
# endif
vtable_free(tmp);
@@ -15055,9 +13462,9 @@ dyna_pop_1(struct parser_params *p)
struct vtable *tmp;
if ((tmp = p->lvtbl->used) != 0) {
- warn_unused_var(p, p->lvtbl);
- p->lvtbl->used = p->lvtbl->used->prev;
- vtable_free(tmp);
+ warn_unused_var(p, p->lvtbl);
+ p->lvtbl->used = p->lvtbl->used->prev;
+ vtable_free(tmp);
}
dyna_pop_vtable(p, &p->lvtbl->args);
dyna_pop_vtable(p, &p->lvtbl->vars);
@@ -15067,12 +13474,12 @@ static void
dyna_pop(struct parser_params *p, const struct vtable *lvargs)
{
while (p->lvtbl->args != lvargs) {
- dyna_pop_1(p);
- if (!p->lvtbl->args) {
- struct local_vars *local = p->lvtbl->prev;
- ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
- p->lvtbl = local;
- }
+ dyna_pop_1(p);
+ if (!p->lvtbl->args) {
+ struct local_vars *local = p->lvtbl->prev;
+ ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
+ p->lvtbl = local;
+ }
}
dyna_pop_1(p);
}
@@ -15094,17 +13501,17 @@ dvar_defined_ref(struct parser_params *p, ID id, ID **vidrefp)
used = p->lvtbl->used;
while (!DVARS_TERMINAL_P(vars)) {
- if (vtable_included(args, id)) {
- return 1;
- }
- if ((i = vtable_included(vars, id)) != 0) {
- if (used && vidrefp) *vidrefp = &used->tbl[i-1];
- return 1;
- }
- args = args->prev;
- vars = vars->prev;
- if (!vidrefp) used = 0;
- if (used) used = used->prev;
+ if (vtable_included(args, id)) {
+ return 1;
+ }
+ if ((i = vtable_included(vars, id)) != 0) {
+ if (used && vidrefp) *vidrefp = &used->tbl[i-1];
+ return 1;
+ }
+ args = args->prev;
+ vars = vars->prev;
+ if (!vidrefp) used = 0;
+ if (used) used = used->prev;
}
if (vars == DVARS_INHERIT && !NUMPARAM_ID_P(id)) {
@@ -15124,7 +13531,7 @@ static int
dvar_curr(struct parser_params *p, ID id)
{
return (vtable_included(p->lvtbl->args, id) ||
- vtable_included(p->lvtbl->vars, id));
+ vtable_included(p->lvtbl->vars, id));
}
static void
@@ -15142,13 +13549,13 @@ rb_reg_fragment_setenc(struct parser_params* p, VALUE str, int options)
int c = RE_OPTION_ENCODING_IDX(options);
if (c) {
- int opt, idx;
- rb_char_to_option_kcode(c, &opt, &idx);
- if (idx != ENCODING_GET(str) &&
- !is_ascii_string(str)) {
+ int opt, idx;
+ rb_char_to_option_kcode(c, &opt, &idx);
+ if (idx != ENCODING_GET(str) &&
+ !is_ascii_string(str)) {
goto error;
- }
- ENCODING_SET(str, idx);
+ }
+ ENCODING_SET(str, idx);
}
else if (RE_OPTION_ENCODING_NONE(options)) {
if (!ENCODING_IS_ASCII8BIT(str) &&
@@ -15156,16 +13563,16 @@ rb_reg_fragment_setenc(struct parser_params* p, VALUE str, int options)
c = 'n';
goto error;
}
- rb_enc_associate(str, rb_ascii8bit_encoding());
+ rb_enc_associate(str, rb_ascii8bit_encoding());
}
else if (rb_is_usascii_enc(p->enc)) {
- if (!is_ascii_string(str)) {
- /* raise in re.c */
- rb_enc_associate(str, rb_usascii_encoding());
- }
- else {
- rb_enc_associate(str, rb_ascii8bit_encoding());
- }
+ if (!is_ascii_string(str)) {
+ /* raise in re.c */
+ rb_enc_associate(str, rb_usascii_encoding());
+ }
+ else {
+ rb_enc_associate(str, rb_ascii8bit_encoding());
+ }
}
return 0;
@@ -15189,12 +13596,11 @@ reg_fragment_check(struct parser_params* p, VALUE str, int options)
if (err != Qnil) {
err = rb_obj_as_string(err);
compile_error(p, "%"PRIsVALUE, err);
- return 0;
+ return 0;
}
return 1;
}
-#ifndef UNIVERSAL_PARSER
typedef struct {
struct parser_params* parser;
rb_encoding *enc;
@@ -15211,8 +13617,23 @@ reg_named_capture_assign_iter(const OnigUChar *name, const OnigUChar *name_end,
rb_encoding *enc = arg->enc;
long len = name_end - name;
const char *s = (const char *)name;
+ ID var;
+ NODE *node, *succ;
- return rb_reg_named_capture_assign_iter_impl(p, s, len, enc, &arg->succ_block, arg->loc);
+ if (!len) return ST_CONTINUE;
+ if (rb_enc_symname_type(s, len, enc, (1U<<ID_LOCAL)) != ID_LOCAL)
+ return ST_CONTINUE;
+
+ var = intern_cstr(s, len, enc);
+ if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len)) {
+ if (!lvar_defined(p, var)) return ST_CONTINUE;
+ }
+ node = node_assign(p, assignable(p, var, 0, arg->loc), NEW_LIT(ID2SYM(var), arg->loc), NO_LEX_CTXT, arg->loc);
+ succ = arg->succ_block;
+ if (!succ) succ = NEW_BEGIN(0, arg->loc);
+ succ = block_append(p, succ, node);
+ arg->succ_block = succ;
+ return ST_CONTINUE;
}
static NODE *
@@ -15227,31 +13648,7 @@ reg_named_capture_assign(struct parser_params* p, VALUE regexp, const YYLTYPE *l
onig_foreach_name(RREGEXP_PTR(regexp), reg_named_capture_assign_iter, &arg);
if (!arg.succ_block) return 0;
- return RNODE_BLOCK(arg.succ_block)->nd_next;
-}
-#endif
-
-int
-rb_reg_named_capture_assign_iter_impl(struct parser_params *p, const char *s, long len,
- rb_encoding *enc, NODE **succ_block, const rb_code_location_t *loc)
-{
- ID var;
- NODE *node, *succ;
-
- if (!len) return ST_CONTINUE;
- if (!VALID_SYMNAME_P(s, len, enc, ID_LOCAL))
- return ST_CONTINUE;
-
- var = intern_cstr(s, len, enc);
- if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len)) {
- if (!lvar_defined(p, var)) return ST_CONTINUE;
- }
- node = node_assign(p, assignable(p, var, 0, loc), NEW_LIT(ID2SYM(var), loc), NO_LEX_CTXT, loc);
- succ = *succ_block;
- if (!succ) succ = NEW_BEGIN(0, loc);
- succ = block_append(p, succ, node);
- *succ_block = succ;
- return ST_CONTINUE;
+ return arg.succ_block->nd_next;
}
static VALUE
@@ -15276,10 +13673,10 @@ reg_compile(struct parser_params* p, VALUE str, int options)
err = rb_errinfo();
re = parser_reg_compile(p, str, options);
if (NIL_P(re)) {
- VALUE m = rb_attr_get(rb_errinfo(), idMesg);
- rb_set_errinfo(err);
- compile_error(p, "%"PRIsVALUE, m);
- return Qnil;
+ VALUE m = rb_attr_get(rb_errinfo(), idMesg);
+ rb_set_errinfo(err);
+ compile_error(p, "%"PRIsVALUE, m);
+ return Qnil;
}
return re;
}
@@ -15289,13 +13686,13 @@ parser_reg_compile(struct parser_params* p, VALUE str, int options, VALUE *errms
{
VALUE err = rb_errinfo();
VALUE re;
- str = ripper_is_node_yylval(p, str) ? RNODE_RIPPER(str)->nd_cval : str;
+ str = ripper_is_node_yylval(str) ? RNODE(str)->nd_cval : str;
int c = rb_reg_fragment_setenc(p, str, options);
if (c) reg_fragment_enc_error(p, str, c);
re = rb_parser_reg_compile(p, str, options);
if (NIL_P(re)) {
- *errmsg = rb_attr_get(rb_errinfo(), idMesg);
- rb_set_errinfo(err);
+ *errmsg = rb_attr_get(rb_errinfo(), idMesg);
+ rb_set_errinfo(err);
}
return re;
}
@@ -15303,8 +13700,10 @@ parser_reg_compile(struct parser_params* p, VALUE str, int options, VALUE *errms
#ifndef RIPPER
void
-rb_ruby_parser_set_options(struct parser_params *p, int print, int loop, int chomp, int split)
+rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
{
+ struct parser_params *p;
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
p->do_print = print;
p->do_loop = loop;
p->do_chomp = chomp;
@@ -15318,32 +13717,32 @@ parser_append_options(struct parser_params *p, NODE *node)
const YYLTYPE *const LOC = &default_location;
if (p->do_print) {
- NODE *print = (NODE *)NEW_FCALL(rb_intern("print"),
- NEW_LIST(NEW_GVAR(idLASTLINE, LOC), LOC),
- LOC);
- node = block_append(p, node, print);
+ NODE *print = NEW_FCALL(rb_intern("print"),
+ NEW_LIST(NEW_GVAR(idLASTLINE, LOC), LOC),
+ LOC);
+ node = block_append(p, node, print);
}
if (p->do_loop) {
- NODE *irs = NEW_LIST(NEW_GVAR(rb_intern("$/"), LOC), LOC);
-
- if (p->do_split) {
- ID ifs = rb_intern("$;");
- ID fields = rb_intern("$F");
- NODE *args = NEW_LIST(NEW_GVAR(ifs, LOC), LOC);
- NODE *split = NEW_GASGN(fields,
- NEW_CALL(NEW_GVAR(idLASTLINE, LOC),
- rb_intern("split"), args, LOC),
- LOC);
- node = block_append(p, split, node);
- }
- if (p->do_chomp) {
- NODE *chomp = NEW_LIT(ID2SYM(rb_intern("chomp")), LOC);
- chomp = list_append(p, NEW_LIST(chomp, LOC), NEW_TRUE(LOC));
- irs = list_append(p, irs, NEW_HASH(chomp, LOC));
- }
-
- node = NEW_WHILE((NODE *)NEW_FCALL(idGets, irs, LOC), node, 1, LOC);
+ NODE *irs = NEW_LIST(NEW_GVAR(rb_intern("$/"), LOC), LOC);
+
+ if (p->do_split) {
+ ID ifs = rb_intern("$;");
+ ID fields = rb_intern("$F");
+ NODE *args = NEW_LIST(NEW_GVAR(ifs, LOC), LOC);
+ NODE *split = NEW_GASGN(fields,
+ NEW_CALL(NEW_GVAR(idLASTLINE, LOC),
+ rb_intern("split"), args, LOC),
+ LOC);
+ node = block_append(p, split, node);
+ }
+ if (p->do_chomp) {
+ NODE *chomp = NEW_LIT(ID2SYM(rb_intern("chomp")), LOC);
+ chomp = list_append(p, NEW_LIST(chomp, LOC), NEW_TRUE(LOC));
+ irs = list_append(p, irs, NEW_HASH(chomp, LOC));
+ }
+
+ node = NEW_WHILE(NEW_FCALL(idGets, irs, LOC), node, 1, LOC);
}
return node;
@@ -15373,7 +13772,6 @@ parser_initialize(struct parser_params *p)
p->lex.lpar_beg = -1; /* make lambda_beginning_p() == FALSE at first */
p->node_id = 0;
p->delayed.token = Qnil;
- p->frozen_string_literal = -1; /* not specified */
#ifdef RIPPER
p->result = Qnil;
p->parsing_thread = Qnil;
@@ -15386,17 +13784,15 @@ parser_initialize(struct parser_params *p)
p->debug_buffer = Qnil;
p->debug_output = rb_ractor_stdout();
p->enc = rb_utf8_encoding();
- p->exits = 0;
}
#ifdef RIPPER
-#define rb_ruby_parser_mark ripper_parser_mark
-#define rb_ruby_parser_free ripper_parser_free
-#define rb_ruby_parser_memsize ripper_parser_memsize
+#define parser_mark ripper_parser_mark
+#define parser_free ripper_parser_free
#endif
-void
-rb_ruby_parser_mark(void *ptr)
+static void
+parser_mark(void *ptr)
{
struct parser_params *p = (struct parser_params*)ptr;
@@ -15404,11 +13800,13 @@ rb_ruby_parser_mark(void *ptr)
rb_gc_mark(p->lex.lastline);
rb_gc_mark(p->lex.nextline);
rb_gc_mark(p->ruby_sourcefile_string);
+ rb_gc_mark((VALUE)p->lex.strterm);
rb_gc_mark((VALUE)p->ast);
rb_gc_mark(p->case_labels);
rb_gc_mark(p->delayed.token);
#ifndef RIPPER
rb_gc_mark(p->debug_lines);
+ rb_gc_mark(p->compile_option);
rb_gc_mark(p->error_buffer);
rb_gc_mark(p->end_expect_token_locations);
rb_gc_mark(p->tokens);
@@ -15424,14 +13822,11 @@ rb_ruby_parser_mark(void *ptr)
#endif
}
-void
-rb_ruby_parser_free(void *ptr)
+static void
+parser_free(void *ptr)
{
struct parser_params *p = (struct parser_params*)ptr;
struct local_vars *local, *prev;
-#ifdef UNIVERSAL_PARSER
- rb_parser_config_t *config = p->config;
-#endif
if (p->tokenbuf) {
ruby_sized_xfree(p->tokenbuf, p->toksiz);
@@ -15447,20 +13842,13 @@ rb_ruby_parser_free(void *ptr)
while ((ptinfo = p->token_info) != 0) {
p->token_info = ptinfo->next;
xfree(ptinfo);
- }
+ }
}
xfree(ptr);
-
-#ifdef UNIVERSAL_PARSER
- config->counter--;
- if (config->counter <= 0) {
- rb_ruby_parser_config_free(config);
- }
-#endif
}
-size_t
-rb_ruby_parser_memsize(const void *ptr)
+static size_t
+parser_memsize(const void *ptr)
{
struct parser_params *p = (struct parser_params*)ptr;
struct local_vars *local;
@@ -15468,39 +13856,25 @@ rb_ruby_parser_memsize(const void *ptr)
size += p->toksiz;
for (local = p->lvtbl; local; local = local->prev) {
- size += sizeof(*local);
- if (local->vars) size += local->vars->capa * sizeof(ID);
+ size += sizeof(*local);
+ if (local->vars) size += local->vars->capa * sizeof(ID);
}
return size;
}
-#ifdef UNIVERSAL_PARSER
-rb_parser_config_t *
-rb_ruby_parser_config_new(void *(*malloc)(size_t size))
-{
- return (rb_parser_config_t *)malloc(sizeof(rb_parser_config_t));
-}
-
-void
-rb_ruby_parser_config_free(rb_parser_config_t *config)
-{
- config->free(config);
-}
-#endif
-
-#ifndef UNIVERSAL_PARSER
-#ifndef RIPPER
static const rb_data_type_t parser_data_type = {
+#ifndef RIPPER
"parser",
+#else
+ "ripper",
+#endif
{
- rb_ruby_parser_mark,
- rb_ruby_parser_free,
- rb_ruby_parser_memsize,
+ parser_mark,
+ parser_free,
+ parser_memsize,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
-#endif
-#endif
#ifndef RIPPER
#undef rb_reserved_word
@@ -15511,361 +13885,180 @@ rb_reserved_word(const char *str, unsigned int len)
return reserved_word(str, len);
}
-#ifdef UNIVERSAL_PARSER
-rb_parser_t *
-rb_ruby_parser_allocate(rb_parser_config_t *config)
-{
- /* parser_initialize expects fields to be set to 0 */
- rb_parser_t *p = (rb_parser_t *)config->calloc(1, sizeof(rb_parser_t));
- p->config = config;
- p->config->counter++;
- return p;
-}
-
-rb_parser_t *
-rb_ruby_parser_new(rb_parser_config_t *config)
+VALUE
+rb_parser_new(void)
{
- /* parser_initialize expects fields to be set to 0 */
- rb_parser_t *p = rb_ruby_parser_allocate(config);
+ struct parser_params *p;
+ VALUE parser = TypedData_Make_Struct(0, struct parser_params,
+ &parser_data_type, p);
parser_initialize(p);
- return p;
+ return parser;
}
-#endif
-rb_parser_t *
-rb_ruby_parser_set_context(rb_parser_t *p, const struct rb_iseq_struct *base, int main)
+VALUE
+rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
p->error_buffer = main ? Qfalse : Qnil;
p->parent_iseq = base;
- return p;
-}
-
-void
-rb_ruby_parser_set_script_lines(rb_parser_t *p, VALUE lines)
-{
- if (!RTEST(lines)) {
- lines = Qfalse;
- }
- else if (lines == Qtrue) {
- lines = rb_ary_new();
- }
- else {
- Check_Type(lines, T_ARRAY);
- rb_ary_modify(lines);
- }
- p->debug_lines = lines;
-}
-
-void
-rb_ruby_parser_error_tolerant(rb_parser_t *p)
-{
- p->error_tolerant = 1;
- // TODO
- p->end_expect_token_locations = rb_ary_new();
+ return vparser;
}
void
-rb_ruby_parser_keep_tokens(rb_parser_t *p)
-{
- p->keep_tokens = 1;
- // TODO
- p->tokens = rb_ary_new();
-}
-
-#ifndef UNIVERSAL_PARSER
-rb_ast_t*
-rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
+rb_parser_keep_script_lines(VALUE vparser)
{
struct parser_params *p;
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_file_path(p, fname, file, start);
+ p->keep_script_lines = 1;
}
-rb_ast_t*
-rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
+void
+rb_parser_error_tolerant(VALUE vparser)
{
struct parser_params *p;
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_generic(p, lex_gets, fname, input, start);
+ p->error_tolerant = 1;
+ p->end_expect_token_locations = rb_ary_new();
}
-rb_ast_t*
-rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
+void
+rb_parser_keep_tokens(VALUE vparser)
{
struct parser_params *p;
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_string(p, f, s, line);
+ p->keep_tokens = 1;
+ p->tokens = rb_ary_new();
}
-rb_ast_t*
-rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
-{
- struct parser_params *p;
+#endif
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- RB_GC_GUARD(vparser); /* prohibit tail call optimization */
- return rb_ruby_parser_compile_string_path(p, f, s, line);
-}
+#ifdef RIPPER
+#define rb_parser_end_seen_p ripper_parser_end_seen_p
+#define rb_parser_encoding ripper_parser_encoding
+#define rb_parser_get_yydebug ripper_parser_get_yydebug
+#define rb_parser_set_yydebug ripper_parser_set_yydebug
+#define rb_parser_get_debug_output ripper_parser_get_debug_output
+#define rb_parser_set_debug_output ripper_parser_set_debug_output
+static VALUE ripper_parser_end_seen_p(VALUE vparser);
+static VALUE ripper_parser_encoding(VALUE vparser);
+static VALUE ripper_parser_get_yydebug(VALUE self);
+static VALUE ripper_parser_set_yydebug(VALUE self, VALUE flag);
+static VALUE ripper_parser_get_debug_output(VALUE self);
+static VALUE ripper_parser_set_debug_output(VALUE self, VALUE output);
-VALUE
-rb_parser_encoding(VALUE vparser)
+/*
+ * call-seq:
+ * ripper.error? -> Boolean
+ *
+ * Return true if parsed source has errors.
+ */
+static VALUE
+ripper_error_p(VALUE vparser)
{
struct parser_params *p;
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- return rb_ruby_parser_encoding(p);
+ return RBOOL(p->error_p);
}
+#endif
+/*
+ * call-seq:
+ * ripper.end_seen? -> Boolean
+ *
+ * Return true if parsed source ended by +\_\_END\_\_+.
+ */
VALUE
rb_parser_end_seen_p(VALUE vparser)
{
struct parser_params *p;
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- return RBOOL(rb_ruby_parser_end_seen_p(p));
-}
-
-void
-rb_parser_error_tolerant(VALUE vparser)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_error_tolerant(p);
-}
-
-void
-rb_parser_set_script_lines(VALUE vparser, VALUE lines)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_script_lines(p, lines);
-}
-
-void
-rb_parser_keep_tokens(VALUE vparser)
-{
- struct parser_params *p;
-
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_keep_tokens(p);
-}
-
-VALUE
-rb_parser_new(void)
-{
- struct parser_params *p;
- VALUE parser = TypedData_Make_Struct(0, struct parser_params,
- &parser_data_type, p);
- parser_initialize(p);
- return parser;
+ return RBOOL(p->ruby__end__seen);
}
+/*
+ * call-seq:
+ * ripper.encoding -> encoding
+ *
+ * Return encoding of the source.
+ */
VALUE
-rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
+rb_parser_encoding(VALUE vparser)
{
struct parser_params *p;
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_context(p, base, main);
- return vparser;
+ return rb_enc_from_encoding(p->enc);
}
-void
-rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
+#ifdef RIPPER
+/*
+ * call-seq:
+ * ripper.yydebug -> true or false
+ *
+ * Get yydebug.
+ */
+VALUE
+rb_parser_get_yydebug(VALUE self)
{
struct parser_params *p;
- TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_options(p, print, loop, chomp, split);
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ return RBOOL(p->debug);
}
+#endif
+/*
+ * call-seq:
+ * ripper.yydebug = flag
+ *
+ * Set yydebug.
+ */
VALUE
rb_parser_set_yydebug(VALUE self, VALUE flag)
{
struct parser_params *p;
TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
- rb_ruby_parser_set_yydebug(p, RTEST(flag));
+ p->debug = RTEST(flag);
return flag;
}
-#endif /* !UNIVERSAL_PARSER */
+/*
+ * call-seq:
+ * ripper.debug_output -> obj
+ *
+ * Get debug output.
+ */
VALUE
-rb_ruby_parser_encoding(rb_parser_t *p)
+rb_parser_get_debug_output(VALUE self)
{
- return rb_enc_from_encoding(p->enc);
-}
-
-int
-rb_ruby_parser_end_seen_p(rb_parser_t *p)
-{
- return p->ruby__end__seen;
-}
-
-int
-rb_ruby_parser_set_yydebug(rb_parser_t *p, int flag)
-{
- p->debug = flag;
- return flag;
-}
-#endif /* !RIPPER */
-
-#ifdef RIPPER
-int
-rb_ruby_parser_get_yydebug(rb_parser_t *p)
-{
- return p->debug;
-}
-
-void
-rb_ruby_parser_set_value(rb_parser_t *p, VALUE value)
-{
- p->value = value;
-}
-
-int
-rb_ruby_parser_error_p(rb_parser_t *p)
-{
- return p->error_p;
-}
+ struct parser_params *p;
-VALUE
-rb_ruby_parser_debug_output(rb_parser_t *p)
-{
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
return p->debug_output;
}
-void
-rb_ruby_parser_set_debug_output(rb_parser_t *p, VALUE output)
-{
- p->debug_output = output;
-}
-
-VALUE
-rb_ruby_parser_parsing_thread(rb_parser_t *p)
-{
- return p->parsing_thread;
-}
-
-void
-rb_ruby_parser_set_parsing_thread(rb_parser_t *p, VALUE parsing_thread)
-{
- p->parsing_thread = parsing_thread;
-}
-
-void
-rb_ruby_parser_ripper_initialize(rb_parser_t *p, VALUE (*gets)(struct parser_params*,VALUE), VALUE input, VALUE sourcefile_string, const char *sourcefile, int sourceline)
-{
- p->lex.gets = gets;
- p->lex.input = input;
- p->eofp = 0;
- p->ruby_sourcefile_string = sourcefile_string;
- p->ruby_sourcefile = sourcefile;
- p->ruby_sourceline = sourceline;
-}
-
-VALUE
-rb_ruby_parser_result(rb_parser_t *p)
-{
- return p->result;
-}
-
-rb_encoding *
-rb_ruby_parser_enc(rb_parser_t *p)
-{
- return p->enc;
-}
-
-VALUE
-rb_ruby_parser_ruby_sourcefile_string(rb_parser_t *p)
-{
- return p->ruby_sourcefile_string;
-}
-
-int
-rb_ruby_parser_ruby_sourceline(rb_parser_t *p)
-{
- return p->ruby_sourceline;
-}
-
-int
-rb_ruby_parser_lex_state(rb_parser_t *p)
-{
- return p->lex.state;
-}
-
-void
-rb_ruby_ripper_parse0(rb_parser_t *p)
-{
- parser_prepare(p);
- p->ast = rb_ast_new();
- ripper_yyparse((void*)p);
- rb_ast_dispose(p->ast);
- p->ast = 0;
-}
-
-int
-rb_ruby_ripper_dedent_string(rb_parser_t *p, VALUE string, int width)
-{
- return dedent_string(p, string, width);
-}
-
-VALUE
-rb_ruby_ripper_lex_get_str(rb_parser_t *p, VALUE s)
-{
- return lex_get_str(p, s);
-}
-
-int
-rb_ruby_ripper_initialized_p(rb_parser_t *p)
-{
- return p->lex.input != 0;
-}
-
-void
-rb_ruby_ripper_parser_initialize(rb_parser_t *p)
-{
- parser_initialize(p);
-}
-
-long
-rb_ruby_ripper_column(rb_parser_t *p)
-{
- return p->lex.ptok - p->lex.pbeg;
-}
-
-long
-rb_ruby_ripper_token_len(rb_parser_t *p)
-{
- return p->lex.pcur - p->lex.ptok;
-}
-
-VALUE
-rb_ruby_ripper_lex_lastline(rb_parser_t *p)
-{
- return p->lex.lastline;
-}
-
+/*
+ * call-seq:
+ * ripper.debug_output = obj
+ *
+ * Set debug output.
+ */
VALUE
-rb_ruby_ripper_lex_state_name(struct parser_params *p, int state)
+rb_parser_set_debug_output(VALUE self, VALUE output)
{
- return rb_parser_lex_state_name(p, (enum lex_state_e)state);
-}
+ struct parser_params *p;
-struct parser_params*
-rb_ruby_ripper_parser_allocate(void)
-{
- return (struct parser_params *)ruby_xcalloc(1, sizeof(struct parser_params));
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ return p->debug_output = output;
}
-#endif /* RIPPER */
#ifndef RIPPER
#ifdef YYMALLOC
@@ -15874,7 +14067,7 @@ rb_ruby_ripper_parser_allocate(void)
* potential memory leak */
#define NEWHEAP() rb_imemo_tmpbuf_parser_heap(0, p->heap, 0)
#define ADD2HEAP(new, cnt, ptr) ((p->heap = (new))->ptr = (ptr), \
- (new)->cnt = (cnt), (ptr))
+ (new)->cnt = (cnt), (ptr))
void *
rb_parser_malloc(struct parser_params *p, size_t size)
@@ -15903,13 +14096,13 @@ rb_parser_realloc(struct parser_params *p, void *ptr, size_t size)
size_t cnt = HEAPCNT(1, size);
if (ptr && (n = p->heap) != NULL) {
- do {
- if (n->ptr == ptr) {
- n->ptr = ptr = xrealloc(ptr, size);
- if (n->cnt) n->cnt = cnt;
- return ptr;
- }
- } while ((n = n->next) != NULL);
+ do {
+ if (n->ptr == ptr) {
+ n->ptr = ptr = xrealloc(ptr, size);
+ if (n->cnt) n->cnt = cnt;
+ return ptr;
+ }
+ } while ((n = n->next) != NULL);
}
n = NEWHEAP();
ptr = xrealloc(ptr, size);
@@ -15922,11 +14115,11 @@ rb_parser_free(struct parser_params *p, void *ptr)
rb_imemo_tmpbuf_t **prev = &p->heap, *n;
while ((n = *prev) != NULL) {
- if (n->ptr == ptr) {
- *prev = n->next;
- break;
- }
- prev = &n->next;
+ if (n->ptr == ptr) {
+ *prev = n->next;
+ break;
+ }
+ prev = &n->next;
}
}
#endif
@@ -15942,34 +14135,25 @@ rb_parser_printf(struct parser_params *p, const char *fmt, ...)
rb_str_vcatf(mesg, fmt, ap);
va_end(ap);
if (RSTRING_END(mesg)[-1] == '\n') {
- rb_io_write(p->debug_output, mesg);
- p->debug_buffer = Qnil;
+ rb_io_write(p->debug_output, mesg);
+ p->debug_buffer = Qnil;
}
}
static void
-parser_compile_error(struct parser_params *p, const rb_code_location_t *loc, const char *fmt, ...)
+parser_compile_error(struct parser_params *p, const char *fmt, ...)
{
va_list ap;
- int lineno, column;
-
- if (loc) {
- lineno = loc->end_pos.lineno;
- column = loc->end_pos.column;
- }
- else {
- lineno = p->ruby_sourceline;
- column = rb_long2int(p->lex.pcur - p->lex.pbeg);
- }
rb_io_flush(p->debug_output);
p->error_p = 1;
va_start(ap, fmt);
p->error_buffer =
- rb_syntax_error_append(p->error_buffer,
- p->ruby_sourcefile_string,
- lineno, column,
- p->enc, fmt, ap);
+ rb_syntax_error_append(p->error_buffer,
+ p->ruby_sourcefile_string,
+ p->ruby_sourceline,
+ rb_long2int(p->lex.pcur - p->lex.pbeg),
+ p->enc, fmt, ap);
va_end(ap);
}
@@ -15991,58 +14175,58 @@ RUBY_FUNC_EXPORTED size_t
rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr)
{
if (*yystr == '"') {
- size_t yyn = 0, bquote = 0;
- const char *yyp = yystr;
-
- while (*++yyp) {
- switch (*yyp) {
- case '`':
- if (!bquote) {
- bquote = count_char(yyp+1, '`') + 1;
- if (yyres) memcpy(&yyres[yyn], yyp, bquote);
- yyn += bquote;
- yyp += bquote - 1;
- break;
- }
- goto default_char;
-
- case '\'':
- if (bquote && count_char(yyp+1, '\'') + 1 == bquote) {
- if (yyres) memcpy(yyres + yyn, yyp, bquote);
- yyn += bquote;
- yyp += bquote - 1;
- bquote = 0;
- break;
- }
- if (yyp[1] && yyp[1] != '\'' && yyp[2] == '\'') {
- if (yyres) memcpy(yyres + yyn, yyp, 3);
- yyn += 3;
- yyp += 2;
- break;
- }
- goto do_not_strip_quotes;
-
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default_char:
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- case '\0':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- }
+ size_t yyn = 0, bquote = 0;
+ const char *yyp = yystr;
+
+ while (*++yyp) {
+ switch (*yyp) {
+ case '`':
+ if (!bquote) {
+ bquote = count_char(yyp+1, '`') + 1;
+ if (yyres) memcpy(&yyres[yyn], yyp, bquote);
+ yyn += bquote;
+ yyp += bquote - 1;
+ break;
+ }
+ goto default_char;
+
+ case '\'':
+ if (bquote && count_char(yyp+1, '\'') + 1 == bquote) {
+ if (yyres) memcpy(yyres + yyn, yyp, bquote);
+ yyn += bquote;
+ yyp += bquote - 1;
+ bquote = 0;
+ break;
+ }
+ if (yyp[1] && yyp[1] != '\'' && yyp[2] == '\'') {
+ if (yyres) memcpy(yyres + yyn, yyp, 3);
+ yyn += 3;
+ yyp += 2;
+ break;
+ }
+ goto do_not_strip_quotes;
+
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default_char:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ case '\0':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ }
do_not_strip_quotes: ;
}
@@ -16062,7 +14246,7 @@ ripper_validate_object(VALUE self, VALUE x)
if (x == Qtrue) return x;
if (NIL_P(x)) return x;
if (UNDEF_P(x))
- rb_raise(rb_eArgError, "Qundef given");
+ rb_raise(rb_eArgError, "Qundef given");
if (FIXNUM_P(x)) return x;
if (SYMBOL_P(x)) return x;
switch (BUILTIN_TYPE(x)) {
@@ -16073,20 +14257,20 @@ ripper_validate_object(VALUE self, VALUE x)
case T_FLOAT:
case T_COMPLEX:
case T_RATIONAL:
- break;
+ break;
case T_NODE:
- if (!nd_type_p((NODE *)x, NODE_RIPPER)) {
- rb_raise(rb_eArgError, "NODE given: %p", (void *)x);
- }
- x = ((NODE *)x)->nd_rval;
- break;
+ if (!nd_type_p((NODE *)x, NODE_RIPPER)) {
+ rb_raise(rb_eArgError, "NODE given: %p", (void *)x);
+ }
+ x = ((NODE *)x)->nd_rval;
+ break;
default:
- rb_raise(rb_eArgError, "wrong type of ruby object: %p (%s)",
- (void *)x, rb_obj_classname(x));
+ rb_raise(rb_eArgError, "wrong type of ruby object: %p (%s)",
+ (void *)x, rb_obj_classname(x));
}
if (!RBASIC_CLASS(x)) {
- rb_raise(rb_eArgError, "hidden ruby object: %p (%s)",
- (void *)x, rb_builtin_type_name(TYPE(x)));
+ rb_raise(rb_eArgError, "hidden ruby object: %p (%s)",
+ (void *)x, rb_builtin_type_name(TYPE(x)));
}
return x;
}
@@ -16158,21 +14342,377 @@ ripper_dispatch7(struct parser_params *p, ID mid, VALUE a, VALUE b, VALUE c, VAL
return rb_funcall(p->value, mid, 7, a, b, c, d, e, f, g);
}
-void
+static ID
+ripper_get_id(VALUE v)
+{
+ NODE *nd;
+ if (!RB_TYPE_P(v, T_NODE)) return 0;
+ nd = (NODE *)v;
+ if (!nd_type_p(nd, NODE_RIPPER)) return 0;
+ return nd->nd_vid;
+}
+
+static VALUE
+ripper_get_value(VALUE v)
+{
+ NODE *nd;
+ if (UNDEF_P(v)) return Qnil;
+ if (!RB_TYPE_P(v, T_NODE)) return v;
+ nd = (NODE *)v;
+ if (!nd_type_p(nd, NODE_RIPPER)) return Qnil;
+ return nd->nd_rval;
+}
+
+static void
ripper_error(struct parser_params *p)
{
p->error_p = TRUE;
}
-VALUE
-ripper_value(struct parser_params *p)
+static void
+ripper_compile_error(struct parser_params *p, const char *fmt, ...)
+{
+ VALUE str;
+ va_list args;
+
+ va_start(args, fmt);
+ str = rb_vsprintf(fmt, args);
+ va_end(args);
+ rb_funcall(p->value, rb_intern("compile_error"), 1, str);
+ ripper_error(p);
+}
+
+static VALUE
+ripper_lex_get_generic(struct parser_params *p, VALUE src)
+{
+ VALUE line = rb_funcallv_public(src, id_gets, 0, 0);
+ if (!NIL_P(line) && !RB_TYPE_P(line, T_STRING)) {
+ rb_raise(rb_eTypeError,
+ "gets returned %"PRIsVALUE" (expected String or nil)",
+ rb_obj_class(line));
+ }
+ return line;
+}
+
+static VALUE
+ripper_lex_io_get(struct parser_params *p, VALUE src)
+{
+ return rb_io_gets(src);
+}
+
+static VALUE
+ripper_s_allocate(VALUE klass)
+{
+ struct parser_params *p;
+ VALUE self = TypedData_Make_Struct(klass, struct parser_params,
+ &parser_data_type, p);
+ p->value = self;
+ return self;
+}
+
+#define ripper_initialized_p(r) ((r)->lex.input != 0)
+
+/*
+ * call-seq:
+ * Ripper.new(src, filename="(ripper)", lineno=1) -> ripper
+ *
+ * Create a new Ripper object.
+ * _src_ must be a String, an IO, or an Object which has #gets method.
+ *
+ * This method does not starts parsing.
+ * See also Ripper#parse and Ripper.parse.
+ */
+static VALUE
+ripper_initialize(int argc, VALUE *argv, VALUE self)
+{
+ struct parser_params *p;
+ VALUE src, fname, lineno;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ rb_scan_args(argc, argv, "12", &src, &fname, &lineno);
+ if (RB_TYPE_P(src, T_FILE)) {
+ p->lex.gets = ripper_lex_io_get;
+ }
+ else if (rb_respond_to(src, id_gets)) {
+ p->lex.gets = ripper_lex_get_generic;
+ }
+ else {
+ StringValue(src);
+ p->lex.gets = lex_get_str;
+ }
+ p->lex.input = src;
+ p->eofp = 0;
+ if (NIL_P(fname)) {
+ fname = STR_NEW2("(ripper)");
+ OBJ_FREEZE(fname);
+ }
+ else {
+ StringValueCStr(fname);
+ fname = rb_str_new_frozen(fname);
+ }
+ parser_initialize(p);
+
+ p->ruby_sourcefile_string = fname;
+ p->ruby_sourcefile = RSTRING_PTR(fname);
+ p->ruby_sourceline = NIL_P(lineno) ? 0 : NUM2INT(lineno) - 1;
+
+ return Qnil;
+}
+
+static VALUE
+ripper_parse0(VALUE parser_v)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(parser_v, struct parser_params, &parser_data_type, p);
+ parser_prepare(p);
+ p->ast = rb_ast_new();
+ ripper_yyparse((void*)p);
+ rb_ast_dispose(p->ast);
+ p->ast = 0;
+ return p->result;
+}
+
+static VALUE
+ripper_ensure(VALUE parser_v)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(parser_v, struct parser_params, &parser_data_type, p);
+ p->parsing_thread = Qnil;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * ripper.parse
+ *
+ * Start parsing and returns the value of the root action.
+ */
+static VALUE
+ripper_parse(VALUE self)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (!NIL_P(p->parsing_thread)) {
+ if (p->parsing_thread == rb_thread_current())
+ rb_raise(rb_eArgError, "Ripper#parse is not reentrant");
+ else
+ rb_raise(rb_eArgError, "Ripper#parse is not multithread-safe");
+ }
+ p->parsing_thread = rb_thread_current();
+ rb_ensure(ripper_parse0, self, ripper_ensure, self);
+
+ return p->result;
+}
+
+/*
+ * call-seq:
+ * ripper.column -> Integer
+ *
+ * Return column number of current parsing line.
+ * This number starts from 0.
+ */
+static VALUE
+ripper_column(VALUE self)
+{
+ struct parser_params *p;
+ long col;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ col = p->lex.ptok - p->lex.pbeg;
+ return LONG2NUM(col);
+}
+
+/*
+ * call-seq:
+ * ripper.filename -> String
+ *
+ * Return current parsing filename.
+ */
+static VALUE
+ripper_filename(VALUE self)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ return p->ruby_sourcefile_string;
+}
+
+/*
+ * call-seq:
+ * ripper.lineno -> Integer
+ *
+ * Return line number of current parsing line.
+ * This number starts from 1.
+ */
+static VALUE
+ripper_lineno(VALUE self)
{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ return INT2NUM(p->ruby_sourceline);
+}
+
+/*
+ * call-seq:
+ * ripper.state -> Integer
+ *
+ * Return scanner state of current token.
+ */
+static VALUE
+ripper_state(VALUE self)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ return INT2NUM(p->lex.state);
+}
+
+/*
+ * call-seq:
+ * ripper.token -> String
+ *
+ * Return the current token string.
+ */
+static VALUE
+ripper_token(VALUE self)
+{
+ struct parser_params *p;
+ long pos, len;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ pos = p->lex.ptok - p->lex.pbeg;
+ len = p->lex.pcur - p->lex.ptok;
+ return rb_str_subseq(p->lex.lastline, pos, len);
+}
+
+#ifdef RIPPER_DEBUG
+/* :nodoc: */
+static VALUE
+ripper_assert_Qundef(VALUE self, VALUE obj, VALUE msg)
+{
+ StringValue(msg);
+ if (UNDEF_P(obj)) {
+ rb_raise(rb_eArgError, "%"PRIsVALUE, msg);
+ }
+ return Qnil;
+}
+
+/* :nodoc: */
+static VALUE
+ripper_value(VALUE self, VALUE obj)
+{
+ return ULONG2NUM(obj);
+}
+#endif
+
+/*
+ * call-seq:
+ * Ripper.lex_state_name(integer) -> string
+ *
+ * Returns a string representation of lex_state.
+ */
+static VALUE
+ripper_lex_state_name(VALUE self, VALUE state)
+{
+ return rb_parser_lex_state_name(NUM2INT(state));
+}
+
+void
+Init_ripper(void)
+{
+ ripper_init_eventids1();
+ ripper_init_eventids2();
+ id_warn = rb_intern_const("warn");
+ id_warning = rb_intern_const("warning");
+ id_gets = rb_intern_const("gets");
+ id_assoc = rb_intern_const("=>");
+
(void)yystpcpy; /* may not used in newer bison */
- return p->value;
+ InitVM(ripper);
}
+void
+InitVM_ripper(void)
+{
+ VALUE Ripper;
+
+ Ripper = rb_define_class("Ripper", rb_cObject);
+ /* version of Ripper */
+ rb_define_const(Ripper, "Version", rb_usascii_str_new2(RIPPER_VERSION));
+ rb_define_alloc_func(Ripper, ripper_s_allocate);
+ rb_define_method(Ripper, "initialize", ripper_initialize, -1);
+ rb_define_method(Ripper, "parse", ripper_parse, 0);
+ rb_define_method(Ripper, "column", ripper_column, 0);
+ rb_define_method(Ripper, "filename", ripper_filename, 0);
+ rb_define_method(Ripper, "lineno", ripper_lineno, 0);
+ rb_define_method(Ripper, "state", ripper_state, 0);
+ rb_define_method(Ripper, "token", ripper_token, 0);
+ rb_define_method(Ripper, "end_seen?", rb_parser_end_seen_p, 0);
+ rb_define_method(Ripper, "encoding", rb_parser_encoding, 0);
+ rb_define_method(Ripper, "yydebug", rb_parser_get_yydebug, 0);
+ rb_define_method(Ripper, "yydebug=", rb_parser_set_yydebug, 1);
+ rb_define_method(Ripper, "debug_output", rb_parser_get_debug_output, 0);
+ rb_define_method(Ripper, "debug_output=", rb_parser_set_debug_output, 1);
+ rb_define_method(Ripper, "error?", ripper_error_p, 0);
+#ifdef RIPPER_DEBUG
+ rb_define_method(Ripper, "assert_Qundef", ripper_assert_Qundef, 2);
+ rb_define_method(Ripper, "rawVALUE", ripper_value, 1);
+ rb_define_method(Ripper, "validate_object", ripper_validate_object, 1);
+#endif
+
+ rb_define_singleton_method(Ripper, "dedent_string", parser_dedent_string, 2);
+ rb_define_private_method(Ripper, "dedent_string", parser_dedent_string, 2);
+
+ rb_define_singleton_method(Ripper, "lex_state_name", ripper_lex_state_name, 1);
+
+<% @exprs.each do |expr, desc| -%>
+ /* <%=desc%> */
+ rb_define_const(Ripper, "<%=expr%>", INT2NUM(<%=expr%>));
+<% end %>
+ ripper_init_eventids1_table(Ripper);
+ ripper_init_eventids2_table(Ripper);
+
+# if 0
+ /* Hack to let RDoc document SCRIPT_LINES__ */
+
+ /*
+ * When a Hash is assigned to +SCRIPT_LINES__+ the contents of files loaded
+ * after the assignment will be added as an Array of lines with the file
+ * name as the key.
+ */
+ rb_define_global_const("SCRIPT_LINES__", Qnil);
+#endif
+
+}
#endif /* RIPPER */
+
/*
* Local variables:
* mode: c
diff --git a/parser_bits.h b/parser_bits.h
deleted file mode 100644
index ca7535280e..0000000000
--- a/parser_bits.h
+++ /dev/null
@@ -1,564 +0,0 @@
-#ifndef INTERNAL_BITS2_H /*-*-C-*-vi:se ft=c:*/
-#define INTERNAL_BITS2_H
-/**
- * @author Ruby developers <ruby-core@ruby-lang.org>
- * @copyright This file is a part of the programming language Ruby.
- * Permission is hereby granted, to either redistribute and/or
- * modify this file, provided that the conditions mentioned in the
- * file COPYING are met. Consult the file for details.
- * @brief Internal header for bitwise integer algorithms.
- * @see Henry S. Warren Jr., "Hacker's Delight" (2nd ed.), 2013.
- * @see SEI CERT C Coding Standard INT32-C. "Ensure that operations on
- * signed integers do not result in overflow"
- * @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
- * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateleft
- * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateright
- * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort
- * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rotl-rotl64-rotr-rotr64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanreverse-bitscanreverse64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/lzcnt16-lzcnt-lzcnt64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/popcnt16-popcnt-popcnt64
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_lzcnt_u32
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_tzcnt_u32
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotl64
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotr64
- * @see https://stackoverflow.com/a/776523
- */
-#include "ruby/internal/config.h"
-#include <limits.h> /* for CHAR_BITS */
-#include <stdint.h> /* for uintptr_t */
-#include "internal/compilers.h" /* for MSC_VERSION_SINCE */
-
-#if MSC_VERSION_SINCE(1310)
-# include <stdlib.h> /* for _byteswap_uint64 */
-#endif
-
-#if defined(HAVE_X86INTRIN_H)
-# include <x86intrin.h> /* for _lzcnt_u64 */
-#elif MSC_VERSION_SINCE(1310)
-# include <intrin.h> /* for the following intrinsics */
-#endif
-
-#if defined(_MSC_VER) && defined(__AVX__)
-# pragma intrinsic(__popcnt)
-# pragma intrinsic(__popcnt64)
-#endif
-
-#if defined(_MSC_VER) && defined(__AVX2__)
-# pragma intrinsic(__lzcnt)
-# pragma intrinsic(__lzcnt64)
-#endif
-
-#if MSC_VERSION_SINCE(1310)
-# pragma intrinsic(_rotl)
-# pragma intrinsic(_rotr)
-# ifdef _WIN64
-# pragma intrinsic(_rotl64)
-# pragma intrinsic(_rotr64)
-# endif
-#endif
-
-#if MSC_VERSION_SINCE(1400)
-# pragma intrinsic(_BitScanForward)
-# pragma intrinsic(_BitScanReverse)
-# ifdef _WIN64
-# pragma intrinsic(_BitScanForward64)
-# pragma intrinsic(_BitScanReverse64)
-# endif
-#endif
-
-#include "parser_value.h" /* for VALUE */
-#include "internal/static_assert.h" /* for STATIC_ASSERT */
-
-/* The most significant bit of the lower part of half-long integer.
- * If sizeof(long) == 4, this is 0x8000.
- * If sizeof(long) == 8, this is 0x80000000.
- */
-#define HALF_LONG_MSB ((SIGNED_VALUE)1<<((SIZEOF_LONG*CHAR_BIT-1)/2))
-
-#define SIGNED_INTEGER_TYPE_P(T) (0 > ((T)0)-1)
-
-#define SIGNED_INTEGER_MIN(T) \
- ((sizeof(T) == sizeof(int8_t)) ? ((T)INT8_MIN) : \
- ((sizeof(T) == sizeof(int16_t)) ? ((T)INT16_MIN) : \
- ((sizeof(T) == sizeof(int32_t)) ? ((T)INT32_MIN) : \
- ((sizeof(T) == sizeof(int64_t)) ? ((T)INT64_MIN) : \
- 0))))
-
-#define SIGNED_INTEGER_MAX(T) ((T)(SIGNED_INTEGER_MIN(T) ^ ((T)~(T)0)))
-
-#define UNSIGNED_INTEGER_MAX(T) ((T)~(T)0)
-
-#if __has_builtin(__builtin_mul_overflow_p)
-# define MUL_OVERFLOW_P(a, b) \
- __builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0)
-#elif __has_builtin(__builtin_mul_overflow)
-# define MUL_OVERFLOW_P(a, b) \
- __extension__ ({ __typeof__(a) c; __builtin_mul_overflow((a), (b), &c); })
-#endif
-
-#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
- (a) == 0 ? 0 : \
- (a) == -1 ? (b) < -(max) : \
- (a) > 0 ? \
- ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
- ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
-
-#if __has_builtin(__builtin_mul_overflow_p)
-/* __builtin_mul_overflow_p can take bitfield */
-/* and GCC permits bitfields for integers other than int */
-# define MUL_OVERFLOW_FIXNUM_P(a, b) \
- __extension__ ({ \
- struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
- __builtin_mul_overflow_p((a), (b), c.fixnum); \
- })
-#else
-# define MUL_OVERFLOW_FIXNUM_P(a, b) \
- MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
-#endif
-
-#ifdef MUL_OVERFLOW_P
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
-# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
-# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_P(a, b)
-#else
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
-# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
-# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
-#endif
-
-#ifdef HAVE_UINT128_T
-# define bit_length(x) \
- (unsigned int) \
- (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
- sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \
- 128 - nlz_int128((uint128_t)(x)))
-#else
-# define bit_length(x) \
- (unsigned int) \
- (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
- 64 - nlz_int64((uint64_t)(x)))
-#endif
-
-#ifndef swap16
-# define swap16 ruby_swap16
-#endif
-
-#ifndef swap32
-# define swap32 ruby_swap32
-#endif
-
-#ifndef swap64
-# define swap64 ruby_swap64
-#endif
-
-static inline uint16_t ruby_swap16(uint16_t);
-static inline uint32_t ruby_swap32(uint32_t);
-static inline uint64_t ruby_swap64(uint64_t);
-static inline unsigned nlz_int(unsigned x);
-static inline unsigned nlz_long(unsigned long x);
-static inline unsigned nlz_long_long(unsigned long long x);
-static inline unsigned nlz_intptr(uintptr_t x);
-static inline unsigned nlz_int32(uint32_t x);
-static inline unsigned nlz_int64(uint64_t x);
-#ifdef HAVE_UINT128_T
-static inline unsigned nlz_int128(uint128_t x);
-#endif
-static inline unsigned rb_popcount32(uint32_t x);
-static inline unsigned rb_popcount64(uint64_t x);
-static inline unsigned rb_popcount_intptr(uintptr_t x);
-static inline int ntz_int32(uint32_t x);
-static inline int ntz_int64(uint64_t x);
-static inline int ntz_intptr(uintptr_t x);
-static inline VALUE RUBY_BIT_ROTL(VALUE, int);
-static inline VALUE RUBY_BIT_ROTR(VALUE, int);
-
-static inline uint16_t
-ruby_swap16(uint16_t x)
-{
-#if __has_builtin(__builtin_bswap16)
- return __builtin_bswap16(x);
-
-#elif MSC_VERSION_SINCE(1310)
- return _byteswap_ushort(x);
-
-#else
- return (x << 8) | (x >> 8);
-
-#endif
-}
-
-static inline uint32_t
-ruby_swap32(uint32_t x)
-{
-#if __has_builtin(__builtin_bswap32)
- return __builtin_bswap32(x);
-
-#elif MSC_VERSION_SINCE(1310)
- return _byteswap_ulong(x);
-
-#else
- x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16);
- x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8);
- return x;
-
-#endif
-}
-
-static inline uint64_t
-ruby_swap64(uint64_t x)
-{
-#if __has_builtin(__builtin_bswap64)
- return __builtin_bswap64(x);
-
-#elif MSC_VERSION_SINCE(1310)
- return _byteswap_uint64(x);
-
-#else
- x = ((x & 0x00000000FFFFFFFFULL) << 32) | ((x & 0xFFFFFFFF00000000ULL) >> 32);
- x = ((x & 0x0000FFFF0000FFFFULL) << 16) | ((x & 0xFFFF0000FFFF0000ULL) >> 16);
- x = ((x & 0x00FF00FF00FF00FFULL) << 8) | ((x & 0xFF00FF00FF00FF00ULL) >> 8);
- return x;
-
-#endif
-}
-
-static inline unsigned int
-nlz_int32(uint32_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX2__)
- /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC.
- * AMD CPUs have had this instruction for decades (since K10) but for
- * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum
- * safety. */
- return (unsigned int)__lzcnt(x);
-
-#elif defined(__x86_64__) && defined(__LZCNT__)
- return (unsigned int)_lzcnt_u32(x);
-
-#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
- unsigned long r;
- return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
-
-#elif __has_builtin(__builtin_clz)
- STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
- return x ? (unsigned int)__builtin_clz(x) : 32;
-
-#else
- uint32_t y;
- unsigned n = 32;
- y = x >> 16; if (y) {n -= 16; x = y;}
- y = x >> 8; if (y) {n -= 8; x = y;}
- y = x >> 4; if (y) {n -= 4; x = y;}
- y = x >> 2; if (y) {n -= 2; x = y;}
- y = x >> 1; if (y) {return n - 2;}
- return (unsigned int)(n - x);
-#endif
-}
-
-static inline unsigned int
-nlz_int64(uint64_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX2__)
- return (unsigned int)__lzcnt64(x);
-
-#elif defined(__x86_64__) && defined(__LZCNT__)
- return (unsigned int)_lzcnt_u64(x);
-
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
- unsigned long r;
- return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
-
-#elif __has_builtin(__builtin_clzl)
- if (x == 0) {
- return 64;
- }
- else if (sizeof(long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_clzl((unsigned long)x);
- }
- else if (sizeof(long long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_clzll((unsigned long long)x);
- }
- else {
- /* :FIXME: Is there a way to make this branch a compile-time error? */
- UNREACHABLE_RETURN(~0);
- }
-
-#else
- uint64_t y;
- unsigned int n = 64;
- y = x >> 32; if (y) {n -= 32; x = y;}
- y = x >> 16; if (y) {n -= 16; x = y;}
- y = x >> 8; if (y) {n -= 8; x = y;}
- y = x >> 4; if (y) {n -= 4; x = y;}
- y = x >> 2; if (y) {n -= 2; x = y;}
- y = x >> 1; if (y) {return n - 2;}
- return (unsigned int)(n - x);
-
-#endif
-}
-
-#ifdef HAVE_UINT128_T
-static inline unsigned int
-nlz_int128(uint128_t x)
-{
- uint64_t y = (uint64_t)(x >> 64);
-
- if (x == 0) {
- return 128;
- }
- else if (y == 0) {
- return (unsigned int)nlz_int64(x) + 64;
- }
- else {
- return (unsigned int)nlz_int64(y);
- }
-}
-#endif
-
-static inline unsigned int
-nlz_int(unsigned int x)
-{
- if (sizeof(unsigned int) * CHAR_BIT == 32) {
- return nlz_int32((uint32_t)x);
- }
- else if (sizeof(unsigned int) * CHAR_BIT == 64) {
- return nlz_int64((uint64_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-nlz_long(unsigned long x)
-{
- if (sizeof(unsigned long) * CHAR_BIT == 32) {
- return nlz_int32((uint32_t)x);
- }
- else if (sizeof(unsigned long) * CHAR_BIT == 64) {
- return nlz_int64((uint64_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-nlz_long_long(unsigned long long x)
-{
- if (sizeof(unsigned long long) * CHAR_BIT == 64) {
- return nlz_int64((uint64_t)x);
- }
-#ifdef HAVE_UINT128_T
- else if (sizeof(unsigned long long) * CHAR_BIT == 128) {
- return nlz_int128((uint128_t)x);
- }
-#endif
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-nlz_intptr(uintptr_t x)
-{
- if (sizeof(uintptr_t) == sizeof(unsigned int)) {
- return nlz_int((unsigned int)x);
- }
- if (sizeof(uintptr_t) == sizeof(unsigned long)) {
- return nlz_long((unsigned long)x);
- }
- if (sizeof(uintptr_t) == sizeof(unsigned long long)) {
- return nlz_long_long((unsigned long long)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-rb_popcount32(uint32_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX__)
- /* Note: CPUs since Nehalem and Barcelona have had this instruction so SSE
- * 4.2 should suffice, but it seems there is no such thing like __SSE_4_2__
- * predefined macro in MSVC. They do have __AVX__ so use it instead. */
- return (unsigned int)__popcnt(x);
-
-#elif __has_builtin(__builtin_popcount)
- STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT >= 32);
- return (unsigned int)__builtin_popcount(x);
-
-#else
- x = (x & 0x55555555) + (x >> 1 & 0x55555555);
- x = (x & 0x33333333) + (x >> 2 & 0x33333333);
- x = (x & 0x0f0f0f0f) + (x >> 4 & 0x0f0f0f0f);
- x = (x & 0x001f001f) + (x >> 8 & 0x001f001f);
- x = (x & 0x0000003f) + (x >>16 & 0x0000003f);
- return (unsigned int)x;
-
-#endif
-}
-
-static inline unsigned int
-rb_popcount64(uint64_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX__)
- return (unsigned int)__popcnt64(x);
-
-#elif __has_builtin(__builtin_popcount)
- if (sizeof(long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_popcountl((unsigned long)x);
- }
- else if (sizeof(long long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_popcountll((unsigned long long)x);
- }
- else {
- /* :FIXME: Is there a way to make this branch a compile-time error? */
- UNREACHABLE_RETURN(~0);
- }
-
-#else
- x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555);
- x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
- x = (x & 0x0707070707070707) + (x >> 4 & 0x0707070707070707);
- x = (x & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f);
- x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f);
- x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f);
- return (unsigned int)x;
-
-#endif
-}
-
-static inline unsigned int
-rb_popcount_intptr(uintptr_t x)
-{
- if (sizeof(uintptr_t) * CHAR_BIT == 64) {
- return rb_popcount64((uint64_t)x);
- }
- else if (sizeof(uintptr_t) * CHAR_BIT == 32) {
- return rb_popcount32((uint32_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline int
-ntz_int32(uint32_t x)
-{
-#if defined(__x86_64__) && defined(__BMI__)
- return (unsigned)_tzcnt_u32(x);
-
-#elif MSC_VERSION_SINCE(1400)
- /* :FIXME: Is there any way to issue TZCNT instead of BSF, apart from using
- * assembly? Because issuing LZCNT seems possible (see nlz.h). */
- unsigned long r;
- return _BitScanForward(&r, x) ? (int)r : 32;
-
-#elif __has_builtin(__builtin_ctz)
- STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
- return x ? (unsigned)__builtin_ctz(x) : 32;
-
-#else
- return rb_popcount32((~x) & (x-1));
-
-#endif
-}
-
-static inline int
-ntz_int64(uint64_t x)
-{
-#if defined(__x86_64__) && defined(__BMI__)
- return (unsigned)_tzcnt_u64(x);
-
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
- unsigned long r;
- return _BitScanForward64(&r, x) ? (int)r : 64;
-
-#elif __has_builtin(__builtin_ctzl)
- if (x == 0) {
- return 64;
- }
- else if (sizeof(long) * CHAR_BIT == 64) {
- return (unsigned)__builtin_ctzl((unsigned long)x);
- }
- else if (sizeof(long long) * CHAR_BIT == 64) {
- return (unsigned)__builtin_ctzll((unsigned long long)x);
- }
- else {
- /* :FIXME: Is there a way to make this branch a compile-time error? */
- UNREACHABLE_RETURN(~0);
- }
-
-#else
- return rb_popcount64((~x) & (x-1));
-
-#endif
-}
-
-static inline int
-ntz_intptr(uintptr_t x)
-{
- if (sizeof(uintptr_t) * CHAR_BIT == 64) {
- return ntz_int64((uint64_t)x);
- }
- else if (sizeof(uintptr_t) * CHAR_BIT == 32) {
- return ntz_int32((uint32_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline VALUE
-RUBY_BIT_ROTL(VALUE v, int n)
-{
-#if __has_builtin(__builtin_rotateleft32) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return __builtin_rotateleft32(v, n);
-
-#elif __has_builtin(__builtin_rotateleft64) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return __builtin_rotateleft64(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return _rotl(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return _rotl64(v, n);
-
-#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG)
- return _lrotl(v, n);
-
-#else
- const int m = (sizeof(VALUE) * CHAR_BIT) - 1;
- return (v << (n & m)) | (v >> (-n & m));
-#endif
-}
-
-static inline VALUE
-RUBY_BIT_ROTR(VALUE v, int n)
-{
-#if __has_builtin(__builtin_rotateright32) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return __builtin_rotateright32(v, n);
-
-#elif __has_builtin(__builtin_rotateright64) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return __builtin_rotateright64(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return _rotr(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return _rotr64(v, n);
-
-#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG)
- return _lrotr(v, n);
-
-#else
- const int m = (sizeof(VALUE) * CHAR_BIT) - 1;
- return (v << (-n & m)) | (v >> (n & m));
-#endif
-}
-
-#endif /* INTERNAL_BITS2_H */
diff --git a/parser_node.h b/parser_node.h
deleted file mode 100644
index 2955720676..0000000000
--- a/parser_node.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef RUBY_PARSER_NODE_H
-#define RUBY_PARSER_NODE_H 1
-/*
- * This is a header file used by only "parse.y"
- */
-#include "rubyparser.h"
-#include "internal/compilers.h"
-
-#if defined(__cplusplus)
-extern "C" {
-#if 0
-} /* satisfy cc-mode */
-#endif
-#endif
-
-static inline rb_code_location_t
-code_loc_gen(const rb_code_location_t *loc1, const rb_code_location_t *loc2)
-{
- rb_code_location_t loc;
- loc.beg_pos = loc1->beg_pos;
- loc.end_pos = loc2->end_pos;
- return loc;
-}
-
-#if defined(__cplusplus)
-#if 0
-{ /* satisfy cc-mode */
-#endif
-} /* extern "C" { */
-#endif
-
-#endif /* RUBY_PARSER_NODE_H */
diff --git a/parser_st.c b/parser_st.c
deleted file mode 100644
index c7a45d25e6..0000000000
--- a/parser_st.c
+++ /dev/null
@@ -1,163 +0,0 @@
-#include "parser_st.h"
-#include "parser_bits.h"
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-
-#ifndef FALSE
-# define FALSE 0
-#endif
-
-#undef NOT_RUBY
-#undef RUBY
-#undef RUBY_EXPORT
-
-#undef MEMCPY
-#define MEMCPY(p1,p2,type,n) nonempty_memcpy((p1), (p2), (sizeof(type) * (n)))
-/* The multiplication should not overflow since this macro is used
- * only with the already allocated size. */
-static inline void *
-nonempty_memcpy(void *dest, const void *src, size_t n)
-{
- if (n) {
- return memcpy(dest, src, n);
- }
- else {
- return dest;
- }
-}
-
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <string.h>
-#include <assert.h>
-
-#ifdef __GNUC__
-#define PREFETCH(addr, write_p) __builtin_prefetch(addr, write_p)
-#define EXPECT(expr, val) __builtin_expect(expr, val)
-#define ATTRIBUTE_UNUSED __attribute__((unused))
-#else
-#define PREFETCH(addr, write_p)
-#define EXPECT(expr, val) (expr)
-#define ATTRIBUTE_UNUSED
-#endif
-
-
-#define st_index_t parser_st_index_t
-#define st_hash_t parser_st_hash_t
-#define st_data_t parser_st_data_t
-#define st_hash_type parser_st_hash_type
-#define st_table parser_st_table
-#define st_table_entry parser_st_table_entry
-#define st_update_callback_func parser_st_update_callback_func
-#define st_foreach_check_callback_func parser_st_foreach_check_callback_func
-#define st_foreach_callback_func parser_st_foreach_callback_func
-#define st_retval parser_st_retval
-
-#define ST_CONTINUE ST2_CONTINUE
-#define ST_STOP ST2_STOP
-#define ST_DELETE ST2_DELETE
-#define ST_CHECK ST2_CHECK
-#define ST_REPLACE ST2_REPLACE
-
-#undef st_numcmp
-#define st_numcmp rb_parser_st_numcmp
-#undef st_numhash
-#define st_numhash rb_parser_st_numhash
-#undef st_free_table
-#define st_free_table rb_parser_st_free_table
-#define rb_st_hash_start rb_parser_st_hash_start
-#undef st_delete
-#define st_delete rb_parser_st_delete
-#undef st_foreach
-#define st_foreach rb_parser_st_foreach
-#undef st_init_numtable
-#define st_init_numtable rb_parser_st_init_numtable
-#undef st_init_table_with_size
-#define st_init_table_with_size rb_parser_st_init_table_with_size
-#undef st_init_existing_table_with_size
-#define st_init_existing_table_with_size rb_parser_st_init_existing_table_with_size
-#undef st_insert
-#define st_insert rb_parser_st_insert
-#undef st_lookup
-#define st_lookup rb_parser_st_lookup
-
-#undef st_table_size
-#define st_table_size rb_parser_st_table_size
-#undef st_clear
-#define st_clear rb_parser_st_clear
-#undef st_init_strtable
-#define st_init_strtable rb_parser_st_init_strtable
-#undef st_init_table
-#define st_init_table rb_parser_st_init_table
-#undef st_init_strcasetable
-#define st_init_strcasetable rb_parser_st_init_strcasetable
-#undef st_init_strtable_with_size
-#define st_init_strtable_with_size rb_parser_st_init_strtable_with_size
-#undef st_init_numtable_with_size
-#define st_init_numtable_with_size rb_parser_st_init_numtable_with_size
-#undef st_init_strcasetable_with_size
-#define st_init_strcasetable_with_size rb_parser_st_init_strcasetable_with_size
-#undef st_memsize
-#define st_memsize rb_parser_st_memsize
-#undef st_get_key
-#define st_get_key rb_parser_st_get_key
-#undef st_add_direct
-#define st_add_direct rb_parser_st_add_direct
-#undef st_insert2
-#define st_insert2 rb_parser_st_insert2
-#undef st_replace
-#define st_replace rb_parser_st_replace
-#undef st_copy
-#define st_copy rb_parser_st_copy
-#undef st_delete_safe
-#define st_delete_safe rb_parser_st_delete_safe
-#undef st_shift
-#define st_shift rb_parser_st_shift
-#undef st_cleanup_safe
-#define st_cleanup_safe rb_parser_st_cleanup_safe
-#undef st_update
-#define st_update rb_parser_st_update
-#undef st_foreach_with_replace
-#define st_foreach_with_replace rb_parser_st_foreach_with_replace
-#undef st_foreach_check
-#define st_foreach_check rb_parser_st_foreach_check
-#undef st_keys
-#define st_keys rb_parser_st_keys
-#undef st_keys_check
-#define st_keys_check rb_parser_st_keys_check
-#undef st_values
-#define st_values rb_parser_st_values
-#undef st_values_check
-#define st_values_check rb_parser_st_values_check
-#undef st_hash
-#define st_hash rb_parser_st_hash
-#undef st_hash_uint32
-#define st_hash_uint32 rb_parser_st_hash_uint32
-#undef st_hash_uint
-#define st_hash_uint rb_parser_st_hash_uint
-#undef st_hash_end
-#define st_hash_end rb_parser_st_hash_end
-#undef st_locale_insensitive_strcasecmp
-#define st_locale_insensitive_strcasecmp rb_parser_st_locale_insensitive_strcasecmp
-#undef st_locale_insensitive_strncasecmp
-#define st_locale_insensitive_strncasecmp rb_parser_st_locale_insensitive_strncasecmp
-
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-/* GCC warns about unknown sanitizer, which is annoying. */
-# undef NO_SANITIZE
-# define NO_SANITIZE(x, y) \
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
- __attribute__((__no_sanitize__(x))) y; \
- _Pragma("GCC diagnostic pop")
-#endif
-
-#ifndef NO_SANITIZE
-# define NO_SANITIZE(x, y) y
-#endif
-
-#include "st.c"
diff --git a/parser_st.h b/parser_st.h
deleted file mode 100644
index 877b1e9051..0000000000
--- a/parser_st.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* This is a public domain general purpose hash table package
- originally written by Peter Moore @ UCB.
-
- The hash table data structures were redesigned and the package was
- rewritten by Vladimir Makarov <vmakarov@redhat.com>. */
-
-#ifndef RUBY_ST2_H
-#define RUBY_ST2_H 1
-
-#if defined(__cplusplus)
-extern "C" {
-#if 0
-} /* satisfy cc-mode */
-#endif
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-#include "ruby/config.h"
-#include "ruby/backward/2/long_long.h"
-#include "ruby/defines.h"
-
-RUBY_SYMBOL_EXPORT_BEGIN
-
-#if SIZEOF_LONG == SIZEOF_VOIDP
-typedef unsigned long parser_st_data_t;
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-typedef unsigned LONG_LONG parser_st_data_t;
-#else
-# error ---->> parser_st.c requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
-#endif
-#define ST2_DATA_T_DEFINED
-
-#ifndef CHAR_BIT
-# ifdef HAVE_LIMITS_H
-# include <limits.h>
-# else
-# define CHAR_BIT 8
-# endif
-#endif
-#ifndef _
-# define _(args) args
-#endif
-#ifndef ANYARGS
-# ifdef __cplusplus
-# define ANYARGS ...
-# else
-# define ANYARGS
-# endif
-#endif
-
-typedef struct parser_st_table parser_st_table;
-
-typedef parser_st_data_t parser_st_index_t;
-
-/* Maximal value of unsigned integer type parser_st_index_t. */
-#define MAX_ST2_INDEX_VAL (~(parser_st_index_t) 0)
-
-typedef int parser_st_compare_func(parser_st_data_t, parser_st_data_t);
-typedef parser_st_index_t parser_st_hash_func(parser_st_data_t);
-
-typedef char st_check_for_sizeof_parser_st_index_t[SIZEOF_VOIDP == (int)sizeof(parser_st_index_t) ? 1 : -1];
-#define SIZEOF_ST_INDEX_T SIZEOF_VOIDP
-
-struct parser_st_hash_type {
- int (*compare)(parser_st_data_t, parser_st_data_t); /* parser_st_compare_func* */
- parser_st_index_t (*hash)(parser_st_data_t); /* parser_st_hash_func* */
-};
-
-#define ST_INDEX_BITS (SIZEOF_ST_INDEX_T * CHAR_BIT)
-
-#if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR) && defined(HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P)
-# define ST2_DATA_COMPATIBLE_P(type) \
- __builtin_choose_expr(__builtin_types_compatible_p(type, parser_st_data_t), 1, 0)
-#else
-# define ST2_DATA_COMPATIBLE_P(type) 0
-#endif
-
-typedef struct parser_st_table_entry parser_st_table_entry;
-
-struct parser_st_table_entry; /* defined in parser_st.c */
-
-struct parser_st_table {
- /* Cached features of the table -- see st.c for more details. */
- unsigned char entry_power, bin_power, size_ind;
- /* How many times the table was rebuilt. */
- unsigned int rebuilds_num;
- const struct parser_st_hash_type *type;
- /* Number of entries currently in the table. */
- parser_st_index_t num_entries;
- /* Array of bins used for access by keys. */
- parser_st_index_t *bins;
- /* Start and bound index of entries in array entries.
- entries_starts and entries_bound are in interval
- [0,allocated_entries]. */
- parser_st_index_t entries_start, entries_bound;
- /* Array of size 2^entry_power. */
- parser_st_table_entry *entries;
-};
-
-#define parser_st_is_member(table,key) rb_parser_st_lookup((table),(key),(parser_st_data_t *)0)
-
-enum parser_st_retval {ST2_CONTINUE, ST2_STOP, ST2_DELETE, ST2_CHECK, ST2_REPLACE};
-
-size_t rb_parser_st_table_size(const struct parser_st_table *tbl);
-parser_st_table *rb_parser_st_init_table(const struct parser_st_hash_type *);
-parser_st_table *rb_parser_st_init_table_with_size(const struct parser_st_hash_type *, parser_st_index_t);
-parser_st_table *rb_parser_st_init_existing_table_with_size(parser_st_table *, const struct parser_st_hash_type *, parser_st_index_t);
-parser_st_table *rb_parser_st_init_numtable(void);
-parser_st_table *rb_parser_st_init_numtable_with_size(parser_st_index_t);
-parser_st_table *rb_parser_st_init_strtable(void);
-parser_st_table *rb_parser_st_init_strtable_with_size(parser_st_index_t);
-parser_st_table *rb_parser_st_init_strcasetable(void);
-parser_st_table *rb_parser_st_init_strcasetable_with_size(parser_st_index_t);
-int rb_parser_st_delete(parser_st_table *, parser_st_data_t *, parser_st_data_t *); /* returns 0:notfound 1:deleted */
-int rb_parser_st_delete_safe(parser_st_table *, parser_st_data_t *, parser_st_data_t *, parser_st_data_t);
-int rb_parser_st_shift(parser_st_table *, parser_st_data_t *, parser_st_data_t *); /* returns 0:notfound 1:deleted */
-int rb_parser_st_insert(parser_st_table *, parser_st_data_t, parser_st_data_t);
-int rb_parser_st_insert2(parser_st_table *, parser_st_data_t, parser_st_data_t, parser_st_data_t (*)(parser_st_data_t));
-int rb_parser_st_lookup(parser_st_table *, parser_st_data_t, parser_st_data_t *);
-int rb_parser_st_get_key(parser_st_table *, parser_st_data_t, parser_st_data_t *);
-typedef int parser_st_update_callback_func(parser_st_data_t *key, parser_st_data_t *value, parser_st_data_t arg, int existing);
-/* *key may be altered, but must equal to the old key, i.e., the
- * results of hash() are same and compare() returns 0, otherwise the
- * behavior is undefined */
-int rb_parser_st_update(parser_st_table *table, parser_st_data_t key, parser_st_update_callback_func *func, parser_st_data_t arg);
-typedef int parser_st_foreach_callback_func(parser_st_data_t, parser_st_data_t, parser_st_data_t);
-typedef int parser_st_foreach_check_callback_func(parser_st_data_t, parser_st_data_t, parser_st_data_t, int);
-int rb_parser_st_foreach_with_replace(parser_st_table *tab, parser_st_foreach_check_callback_func *func, parser_st_update_callback_func *replace, parser_st_data_t arg);
-int rb_parser_st_foreach(parser_st_table *, parser_st_foreach_callback_func *, parser_st_data_t);
-int rb_parser_st_foreach_check(parser_st_table *, parser_st_foreach_check_callback_func *, parser_st_data_t, parser_st_data_t);
-parser_st_index_t rb_parser_st_keys(parser_st_table *table, parser_st_data_t *keys, parser_st_index_t size);
-parser_st_index_t rb_parser_st_keys_check(parser_st_table *table, parser_st_data_t *keys, parser_st_index_t size, parser_st_data_t never);
-parser_st_index_t rb_parser_st_values(parser_st_table *table, parser_st_data_t *values, parser_st_index_t size);
-parser_st_index_t rb_parser_st_values_check(parser_st_table *table, parser_st_data_t *values, parser_st_index_t size, parser_st_data_t never);
-void rb_parser_st_add_direct(parser_st_table *, parser_st_data_t, parser_st_data_t);
-void rb_parser_st_free_table(parser_st_table *);
-void rb_parser_st_cleanup_safe(parser_st_table *, parser_st_data_t);
-void rb_parser_st_clear(parser_st_table *);
-parser_st_table *rb_parser_st_replace(parser_st_table *, parser_st_table *);
-parser_st_table *rb_parser_st_copy(parser_st_table *);
-CONSTFUNC(int rb_parser_st_numcmp(parser_st_data_t, parser_st_data_t));
-CONSTFUNC(parser_st_index_t rb_parser_st_numhash(parser_st_data_t));
-PUREFUNC(int rb_parser_st_locale_insensitive_strcasecmp(const char *s1, const char *s2));
-PUREFUNC(int rb_parser_st_locale_insensitive_strncasecmp(const char *s1, const char *s2, size_t n));
-PUREFUNC(size_t rb_parser_st_memsize(const parser_st_table *));
-PUREFUNC(parser_st_index_t rb_parser_st_hash(const void *ptr, size_t len, parser_st_index_t h));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_uint32(parser_st_index_t h, uint32_t i));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_uint(parser_st_index_t h, parser_st_index_t i));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_end(parser_st_index_t h));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_start(parser_st_index_t h));
-
-RUBY_SYMBOL_EXPORT_END
-
-#if defined(__cplusplus)
-#if 0
-{ /* satisfy cc-mode */
-#endif
-} /* extern "C" { */
-#endif
-
-#endif /* RUBY_ST2_H */
diff --git a/parser_value.h b/parser_value.h
deleted file mode 100644
index 4fe444e82f..0000000000
--- a/parser_value.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef EXTERNAL_VALUE_H
-#define EXTERNAL_VALUE_H
-
-#include "ruby/config.h"
-
-#if defined(__DOXYGEN__)
-
-/**
- * Type that represents a Ruby object. It is an unsigned integer of some kind,
- * depending on platforms.
- *
- * ```CXX
- * VALUE value = rb_eval_string("ARGF.readlines.map.with_index");
- * ```
- *
- * @warning ::VALUE is not a pointer.
- * @warning ::VALUE can be wider than `long`.
- */
-typedef uintptr_t VALUE;
-
-/**
- * Type that represents a Ruby identifier such as a variable name.
- *
- * ```CXX
- * ID method = rb_intern("method");
- * VALUE result = rb_funcall(obj, method, 0);
- * ```
- *
- * @note ::rb_cSymbol is a Ruby-level data type for the same thing.
- */
-typedef uintptr_t ID;
-
-/**
- * A signed integer type that has the same width with ::VALUE.
- *
- * @internal
- *
- * @shyouhei wonders: is it guaranteed that `uintptr_t` and `intptr_t` are the
- * same width? As far as I read ISO/IEC 9899:2018 section 7.20.1.4 paragraph 1
- * no such description is given... or defined elsewhere?
- */
-typedef intptr_t SIGNED_VALUE;
-
-/**
- * Identical to `sizeof(VALUE)`, except it is a macro that can also be used
- * inside of preprocessor directives such as `#if`. Handy on occasions.
- */
-#define SIZEOF_VALUE SIZEOF_UINTPTR_T
-
-/**
- * @private
- *
- * A compile-time constant of type ::VALUE whose value is 0.
- */
-#define RBIMPL_VALUE_NULL UINTPTR_C(0)
-
-/**
- * @private
- *
- * A compile-time constant of type ::VALUE whose value is 1.
- */
-#define RBIMPL_VALUE_ONE UINTPTR_C(1)
-
-/**
- * @private
- *
- * Maximum possible value that a ::VALUE can take.
- */
-#define RBIMPL_VALUE_FULL UINTPTR_MAX
-
-#elif defined HAVE_UINTPTR_T && 0
-typedef uintptr_t VALUE;
-typedef uintptr_t ID;
-# define SIGNED_VALUE intptr_t
-# define SIZEOF_VALUE SIZEOF_UINTPTR_T
-# undef PRI_VALUE_PREFIX
-# define RBIMPL_VALUE_NULL UINTPTR_C(0)
-# define RBIMPL_VALUE_ONE UINTPTR_C(1)
-# define RBIMPL_VALUE_FULL UINTPTR_MAX
-
-#elif SIZEOF_LONG == SIZEOF_VOIDP
-typedef unsigned long VALUE;
-typedef unsigned long ID;
-# define SIGNED_VALUE long
-# define SIZEOF_VALUE SIZEOF_LONG
-# define PRI_VALUE_PREFIX "l"
-# define RBIMPL_VALUE_NULL 0UL
-# define RBIMPL_VALUE_ONE 1UL
-# define RBIMPL_VALUE_FULL ULONG_MAX
-
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-typedef unsigned LONG_LONG VALUE;
-typedef unsigned LONG_LONG ID;
-# define SIGNED_VALUE LONG_LONG
-# define LONG_LONG_VALUE 1
-# define SIZEOF_VALUE SIZEOF_LONG_LONG
-# define PRI_VALUE_PREFIX PRI_LL_PREFIX
-# define RBIMPL_VALUE_NULL 0ULL
-# define RBIMPL_VALUE_ONE 1ULL
-# define RBIMPL_VALUE_FULL ULLONG_MAX
-
-#else
-# error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
-#endif
-
-#endif /* EXTERNAL_VALUE_H */
diff --git a/prelude.rb b/prelude.rb
index ee78b44cc5..8fd6e6cb77 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -27,5 +27,5 @@ module Enumerable
# Makes a set from the enumerable object with given arguments.
def to_set(klass = Set, *args, &block)
klass.new(self, *args, &block)
- end unless instance_methods.include?(:to_set) # RJIT could already load this from builtin prelude
+ end
end
diff --git a/prism/api_pack.c b/prism/api_pack.c
deleted file mode 100644
index c9f0b18a39..0000000000
--- a/prism/api_pack.c
+++ /dev/null
@@ -1,267 +0,0 @@
-#include "prism/extension.h"
-
-static VALUE rb_cPrism;
-static VALUE rb_cPrismPack;
-static VALUE rb_cPrismPackDirective;
-static VALUE rb_cPrismPackFormat;
-
-static VALUE v3_2_0_symbol;
-static VALUE pack_symbol;
-static VALUE unpack_symbol;
-
-#if SIZEOF_UINT64_T == SIZEOF_LONG_LONG
-# define UINT64T2NUM(x) ULL2NUM(x)
-# define NUM2UINT64T(x) (uint64_t)NUM2ULL(x)
-#elif SIZEOF_UINT64_T == SIZEOF_LONG
-# define UINT64T2NUM(x) ULONG2NUM(x)
-# define NUM2UINT64T(x) (uint64_t)NUM2ULONG(x)
-#else
-// error No uint64_t conversion
-#endif
-
-static VALUE
-pack_type_to_symbol(pm_pack_type type) {
- switch (type) {
- case PM_PACK_SPACE:
- return ID2SYM(rb_intern("SPACE"));
- case PM_PACK_COMMENT:
- return ID2SYM(rb_intern("COMMENT"));
- case PM_PACK_INTEGER:
- return ID2SYM(rb_intern("INTEGER"));
- case PM_PACK_UTF8:
- return ID2SYM(rb_intern("UTF8"));
- case PM_PACK_BER:
- return ID2SYM(rb_intern("BER"));
- case PM_PACK_FLOAT:
- return ID2SYM(rb_intern("FLOAT"));
- case PM_PACK_STRING_SPACE_PADDED:
- return ID2SYM(rb_intern("STRING_SPACE_PADDED"));
- case PM_PACK_STRING_NULL_PADDED:
- return ID2SYM(rb_intern("STRING_NULL_PADDED"));
- case PM_PACK_STRING_NULL_TERMINATED:
- return ID2SYM(rb_intern("STRING_NULL_TERMINATED"));
- case PM_PACK_STRING_MSB:
- return ID2SYM(rb_intern("STRING_MSB"));
- case PM_PACK_STRING_LSB:
- return ID2SYM(rb_intern("STRING_LSB"));
- case PM_PACK_STRING_HEX_HIGH:
- return ID2SYM(rb_intern("STRING_HEX_HIGH"));
- case PM_PACK_STRING_HEX_LOW:
- return ID2SYM(rb_intern("STRING_HEX_LOW"));
- case PM_PACK_STRING_UU:
- return ID2SYM(rb_intern("STRING_UU"));
- case PM_PACK_STRING_MIME:
- return ID2SYM(rb_intern("STRING_MIME"));
- case PM_PACK_STRING_BASE64:
- return ID2SYM(rb_intern("STRING_BASE64"));
- case PM_PACK_STRING_FIXED:
- return ID2SYM(rb_intern("STRING_FIXED"));
- case PM_PACK_STRING_POINTER:
- return ID2SYM(rb_intern("STRING_POINTER"));
- case PM_PACK_MOVE:
- return ID2SYM(rb_intern("MOVE"));
- case PM_PACK_BACK:
- return ID2SYM(rb_intern("BACK"));
- case PM_PACK_NULL:
- return ID2SYM(rb_intern("NULL"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_signed_to_symbol(pm_pack_signed signed_type) {
- switch (signed_type) {
- case PM_PACK_UNSIGNED:
- return ID2SYM(rb_intern("UNSIGNED"));
- case PM_PACK_SIGNED:
- return ID2SYM(rb_intern("SIGNED"));
- case PM_PACK_SIGNED_NA:
- return ID2SYM(rb_intern("SIGNED_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_endian_to_symbol(pm_pack_endian endian) {
- switch (endian) {
- case PM_PACK_AGNOSTIC_ENDIAN:
- return ID2SYM(rb_intern("AGNOSTIC_ENDIAN"));
- case PM_PACK_LITTLE_ENDIAN:
- return ID2SYM(rb_intern("LITTLE_ENDIAN"));
- case PM_PACK_BIG_ENDIAN:
- return ID2SYM(rb_intern("BIG_ENDIAN"));
- case PM_PACK_NATIVE_ENDIAN:
- return ID2SYM(rb_intern("NATIVE_ENDIAN"));
- case PM_PACK_ENDIAN_NA:
- return ID2SYM(rb_intern("ENDIAN_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_size_to_symbol(pm_pack_size size) {
- switch (size) {
- case PM_PACK_SIZE_SHORT:
- return ID2SYM(rb_intern("SIZE_SHORT"));
- case PM_PACK_SIZE_INT:
- return ID2SYM(rb_intern("SIZE_INT"));
- case PM_PACK_SIZE_LONG:
- return ID2SYM(rb_intern("SIZE_LONG"));
- case PM_PACK_SIZE_LONG_LONG:
- return ID2SYM(rb_intern("SIZE_LONG_LONG"));
- case PM_PACK_SIZE_8:
- return ID2SYM(rb_intern("SIZE_8"));
- case PM_PACK_SIZE_16:
- return ID2SYM(rb_intern("SIZE_16"));
- case PM_PACK_SIZE_32:
- return ID2SYM(rb_intern("SIZE_32"));
- case PM_PACK_SIZE_64:
- return ID2SYM(rb_intern("SIZE_64"));
- case PM_PACK_SIZE_P:
- return ID2SYM(rb_intern("SIZE_P"));
- case PM_PACK_SIZE_NA:
- return ID2SYM(rb_intern("SIZE_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_length_type_to_symbol(pm_pack_length_type length_type) {
- switch (length_type) {
- case PM_PACK_LENGTH_FIXED:
- return ID2SYM(rb_intern("LENGTH_FIXED"));
- case PM_PACK_LENGTH_MAX:
- return ID2SYM(rb_intern("LENGTH_MAX"));
- case PM_PACK_LENGTH_RELATIVE:
- return ID2SYM(rb_intern("LENGTH_RELATIVE"));
- case PM_PACK_LENGTH_NA:
- return ID2SYM(rb_intern("LENGTH_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_encoding_to_ruby(pm_pack_encoding encoding) {
- int index;
- switch (encoding) {
- case PM_PACK_ENCODING_ASCII_8BIT:
- index = rb_ascii8bit_encindex();
- break;
- case PM_PACK_ENCODING_US_ASCII:
- index = rb_usascii_encindex();
- break;
- case PM_PACK_ENCODING_UTF_8:
- index = rb_utf8_encindex();
- break;
- default:
- return Qnil;
- }
- return rb_enc_from_encoding(rb_enc_from_index(index));
-}
-
-/**
- * call-seq:
- * Pack::parse(version, variant, source) -> Format
- *
- * Parse the given source and return a format object.
- */
-static VALUE
-pack_parse(VALUE self, VALUE version_symbol, VALUE variant_symbol, VALUE format_string) {
- if (version_symbol != v3_2_0_symbol) {
- rb_raise(rb_eArgError, "invalid version");
- }
-
- pm_pack_variant variant;
- if (variant_symbol == pack_symbol) {
- variant = PM_PACK_VARIANT_PACK;
- } else if (variant_symbol == unpack_symbol) {
- variant = PM_PACK_VARIANT_UNPACK;
- } else {
- rb_raise(rb_eArgError, "invalid variant");
- }
-
- StringValue(format_string);
-
- const char *format = RSTRING_PTR(format_string);
- const char *format_end = format + RSTRING_LEN(format_string);
- pm_pack_encoding encoding = PM_PACK_ENCODING_START;
-
- VALUE directives_array = rb_ary_new();
-
- while (format < format_end) {
- pm_pack_type type;
- pm_pack_signed signed_type;
- pm_pack_endian endian;
- pm_pack_size size;
- pm_pack_length_type length_type;
- uint64_t length;
-
- const char *directive_start = format;
-
- pm_pack_result parse_result = pm_pack_parse(variant, &format, format_end, &type, &signed_type, &endian,
- &size, &length_type, &length, &encoding);
-
- const char *directive_end = format;
-
- switch (parse_result) {
- case PM_PACK_OK:
- break;
- case PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE:
- rb_raise(rb_eArgError, "unsupported directive");
- case PM_PACK_ERROR_UNKNOWN_DIRECTIVE:
- rb_raise(rb_eArgError, "unsupported directive");
- case PM_PACK_ERROR_LENGTH_TOO_BIG:
- rb_raise(rb_eRangeError, "pack length too big");
- case PM_PACK_ERROR_BANG_NOT_ALLOWED:
- rb_raise(rb_eRangeError, "bang not allowed");
- case PM_PACK_ERROR_DOUBLE_ENDIAN:
- rb_raise(rb_eRangeError, "double endian");
- default:
- rb_bug("parse result");
- }
-
- if (type == PM_PACK_END) {
- break;
- }
-
- VALUE directive_args[9] = {
- version_symbol,
- variant_symbol,
- rb_usascii_str_new(directive_start, directive_end - directive_start),
- pack_type_to_symbol(type),
- pack_signed_to_symbol(signed_type),
- pack_endian_to_symbol(endian),
- pack_size_to_symbol(size),
- pack_length_type_to_symbol(length_type),
- UINT64T2NUM(length)
- };
-
- rb_ary_push(directives_array, rb_class_new_instance(9, directive_args, rb_cPrismPackDirective));
- }
-
- VALUE format_args[2];
- format_args[0] = directives_array;
- format_args[1] = pack_encoding_to_ruby(encoding);
- return rb_class_new_instance(2, format_args, rb_cPrismPackFormat);
-}
-
-/**
- * The function that gets called when Ruby initializes the prism extension.
- */
-void
-Init_prism_pack(void) {
- rb_cPrism = rb_define_module("Prism");
- rb_cPrismPack = rb_define_module_under(rb_cPrism, "Pack");
- rb_cPrismPackDirective = rb_define_class_under(rb_cPrismPack, "Directive", rb_cObject);
- rb_cPrismPackFormat = rb_define_class_under(rb_cPrismPack, "Format", rb_cObject);
- rb_define_singleton_method(rb_cPrismPack, "parse", pack_parse, 3);
-
- v3_2_0_symbol = ID2SYM(rb_intern("v3_2_0"));
- pack_symbol = ID2SYM(rb_intern("pack"));
- unpack_symbol = ID2SYM(rb_intern("unpack"));
-}
diff --git a/prism/config.yml b/prism/config.yml
deleted file mode 100644
index bd5afc7d4e..0000000000
--- a/prism/config.yml
+++ /dev/null
@@ -1,2558 +0,0 @@
-tokens:
- - name: EOF
- value: 1
- comment: final token in the file
- - name: MISSING
- comment: "a token that was expected but not found"
- - name: NOT_PROVIDED
- comment: "a token that was not present but it is okay"
- - name: AMPERSAND
- comment: "&"
- - name: AMPERSAND_AMPERSAND
- comment: "&&"
- - name: AMPERSAND_AMPERSAND_EQUAL
- comment: "&&="
- - name: AMPERSAND_DOT
- comment: "&."
- - name: AMPERSAND_EQUAL
- comment: "&="
- - name: BACKTICK
- comment: "`"
- - name: BACK_REFERENCE
- comment: "a back reference"
- - name: BANG
- comment: "! or !@"
- - name: BANG_EQUAL
- comment: "!="
- - name: BANG_TILDE
- comment: "!~"
- - name: BRACE_LEFT
- comment: "{"
- - name: BRACE_RIGHT
- comment: "}"
- - name: BRACKET_LEFT
- comment: "["
- - name: BRACKET_LEFT_ARRAY
- comment: "[ for the beginning of an array"
- - name: BRACKET_LEFT_RIGHT
- comment: "[]"
- - name: BRACKET_LEFT_RIGHT_EQUAL
- comment: "[]="
- - name: BRACKET_RIGHT
- comment: "]"
- - name: CARET
- comment: "^"
- - name: CARET_EQUAL
- comment: "^="
- - name: CHARACTER_LITERAL
- comment: "a character literal"
- - name: CLASS_VARIABLE
- comment: "a class variable"
- - name: COLON
- comment: ":"
- - name: COLON_COLON
- comment: "::"
- - name: COMMA
- comment: ","
- - name: COMMENT
- comment: "a comment"
- - name: CONSTANT
- comment: "a constant"
- - name: DOT
- comment: "the . call operator"
- - name: DOT_DOT
- comment: "the .. range operator"
- - name: DOT_DOT_DOT
- comment: "the ... range operator or forwarding parameter"
- - name: EMBDOC_BEGIN
- comment: "=begin"
- - name: EMBDOC_END
- comment: "=end"
- - name: EMBDOC_LINE
- comment: "a line inside of embedded documentation"
- - name: EMBEXPR_BEGIN
- comment: "#{"
- - name: EMBEXPR_END
- comment: "}"
- - name: EMBVAR
- comment: "#"
- - name: EQUAL
- comment: "="
- - name: EQUAL_EQUAL
- comment: "=="
- - name: EQUAL_EQUAL_EQUAL
- comment: "==="
- - name: EQUAL_GREATER
- comment: "=>"
- - name: EQUAL_TILDE
- comment: "=~"
- - name: FLOAT
- comment: "a floating point number"
- - name: FLOAT_IMAGINARY
- comment: "a floating pointer number with an imaginary suffix"
- - name: FLOAT_RATIONAL
- comment: "a floating pointer number with a rational suffix"
- - name: FLOAT_RATIONAL_IMAGINARY
- comment: "a floating pointer number with a rational and imaginary suffix"
- - name: GLOBAL_VARIABLE
- comment: "a global variable"
- - name: GREATER
- comment: ">"
- - name: GREATER_EQUAL
- comment: ">="
- - name: GREATER_GREATER
- comment: ">>"
- - name: GREATER_GREATER_EQUAL
- comment: ">>="
- - name: HEREDOC_END
- comment: "the end of a heredoc"
- - name: HEREDOC_START
- comment: "the start of a heredoc"
- - name: IDENTIFIER
- comment: "an identifier"
- - name: IGNORED_NEWLINE
- comment: "an ignored newline"
- - name: INSTANCE_VARIABLE
- comment: "an instance variable"
- - name: INTEGER
- comment: "an integer (any base)"
- - name: INTEGER_IMAGINARY
- comment: "an integer with an imaginary suffix"
- - name: INTEGER_RATIONAL
- comment: "an integer with a rational suffix"
- - name: INTEGER_RATIONAL_IMAGINARY
- comment: "an integer with a rational and imaginary suffix"
- - name: KEYWORD_ALIAS
- comment: "alias"
- - name: KEYWORD_AND
- comment: "and"
- - name: KEYWORD_BEGIN
- comment: "begin"
- - name: KEYWORD_BEGIN_UPCASE
- comment: "BEGIN"
- - name: KEYWORD_BREAK
- comment: "break"
- - name: KEYWORD_CASE
- comment: "case"
- - name: KEYWORD_CLASS
- comment: "class"
- - name: KEYWORD_DEF
- comment: "def"
- - name: KEYWORD_DEFINED
- comment: "defined?"
- - name: KEYWORD_DO
- comment: "do"
- - name: KEYWORD_DO_LOOP
- comment: "do keyword for a predicate in a while, until, or for loop"
- - name: KEYWORD_ELSE
- comment: "else"
- - name: KEYWORD_ELSIF
- comment: "elsif"
- - name: KEYWORD_END
- comment: "end"
- - name: KEYWORD_END_UPCASE
- comment: "END"
- - name: KEYWORD_ENSURE
- comment: "ensure"
- - name: KEYWORD_FALSE
- comment: "false"
- - name: KEYWORD_FOR
- comment: "for"
- - name: KEYWORD_IF
- comment: "if"
- - name: KEYWORD_IF_MODIFIER
- comment: "if in the modifier form"
- - name: KEYWORD_IN
- comment: "in"
- - name: KEYWORD_MODULE
- comment: "module"
- - name: KEYWORD_NEXT
- comment: "next"
- - name: KEYWORD_NIL
- comment: "nil"
- - name: KEYWORD_NOT
- comment: "not"
- - name: KEYWORD_OR
- comment: "or"
- - name: KEYWORD_REDO
- comment: "redo"
- - name: KEYWORD_RESCUE
- comment: "rescue"
- - name: KEYWORD_RESCUE_MODIFIER
- comment: "rescue in the modifier form"
- - name: KEYWORD_RETRY
- comment: "retry"
- - name: KEYWORD_RETURN
- comment: "return"
- - name: KEYWORD_SELF
- comment: "self"
- - name: KEYWORD_SUPER
- comment: "super"
- - name: KEYWORD_THEN
- comment: "then"
- - name: KEYWORD_TRUE
- comment: "true"
- - name: KEYWORD_UNDEF
- comment: "undef"
- - name: KEYWORD_UNLESS
- comment: "unless"
- - name: KEYWORD_UNLESS_MODIFIER
- comment: "unless in the modifier form"
- - name: KEYWORD_UNTIL
- comment: "until"
- - name: KEYWORD_UNTIL_MODIFIER
- comment: "until in the modifier form"
- - name: KEYWORD_WHEN
- comment: "when"
- - name: KEYWORD_WHILE
- comment: "while"
- - name: KEYWORD_WHILE_MODIFIER
- comment: "while in the modifier form"
- - name: KEYWORD_YIELD
- comment: "yield"
- - name: KEYWORD___ENCODING__
- comment: "__ENCODING__"
- - name: KEYWORD___FILE__
- comment: "__FILE__"
- - name: KEYWORD___LINE__
- comment: "__LINE__"
- - name: LABEL
- comment: "a label"
- - name: LABEL_END
- comment: "the end of a label"
- - name: LAMBDA_BEGIN
- comment: "{"
- - name: LESS
- comment: "<"
- - name: LESS_EQUAL
- comment: "<="
- - name: LESS_EQUAL_GREATER
- comment: "<=>"
- - name: LESS_LESS
- comment: "<<"
- - name: LESS_LESS_EQUAL
- comment: "<<="
- - name: METHOD_NAME
- comment: "a method name"
- - name: MINUS
- comment: "-"
- - name: MINUS_EQUAL
- comment: "-="
- - name: MINUS_GREATER
- comment: "->"
- - name: NEWLINE
- comment: "a newline character outside of other tokens"
- - name: NUMBERED_REFERENCE
- comment: "a numbered reference to a capture group in the previous regular expression match"
- - name: PARENTHESIS_LEFT
- comment: "("
- - name: PARENTHESIS_LEFT_PARENTHESES
- comment: "( for a parentheses node"
- - name: PARENTHESIS_RIGHT
- comment: ")"
- - name: PERCENT
- comment: "%"
- - name: PERCENT_EQUAL
- comment: "%="
- - name: PERCENT_LOWER_I
- comment: "%i"
- - name: PERCENT_LOWER_W
- comment: "%w"
- - name: PERCENT_LOWER_X
- comment: "%x"
- - name: PERCENT_UPPER_I
- comment: "%I"
- - name: PERCENT_UPPER_W
- comment: "%W"
- - name: PIPE
- comment: "|"
- - name: PIPE_EQUAL
- comment: "|="
- - name: PIPE_PIPE
- comment: "||"
- - name: PIPE_PIPE_EQUAL
- comment: "||="
- - name: PLUS
- comment: "+"
- - name: PLUS_EQUAL
- comment: "+="
- - name: QUESTION_MARK
- comment: "?"
- - name: REGEXP_BEGIN
- comment: "the beginning of a regular expression"
- - name: REGEXP_END
- comment: "the end of a regular expression"
- - name: SEMICOLON
- comment: ";"
- - name: SLASH
- comment: "/"
- - name: SLASH_EQUAL
- comment: "/="
- - name: STAR
- comment: "*"
- - name: STAR_EQUAL
- comment: "*="
- - name: STAR_STAR
- comment: "**"
- - name: STAR_STAR_EQUAL
- comment: "**="
- - name: STRING_BEGIN
- comment: "the beginning of a string"
- - name: STRING_CONTENT
- comment: "the contents of a string"
- - name: STRING_END
- comment: "the end of a string"
- - name: SYMBOL_BEGIN
- comment: "the beginning of a symbol"
- - name: TILDE
- comment: "~ or ~@"
- - name: UAMPERSAND
- comment: "unary &"
- - name: UCOLON_COLON
- comment: "unary ::"
- - name: UDOT_DOT
- comment: "unary .. operator"
- - name: UDOT_DOT_DOT
- comment: "unary ... operator"
- - name: UMINUS
- comment: "-@"
- - name: UMINUS_NUM
- comment: "-@ for a number"
- - name: UPLUS
- comment: "+@"
- - name: USTAR
- comment: "unary *"
- - name: USTAR_STAR
- comment: "unary **"
- - name: WORDS_SEP
- comment: "a separator between words in a list"
- - name: __END__
- comment: "marker for the point in the file at which the parser should stop"
-flags:
- - name: ArgumentsNodeFlags
- values:
- - name: KEYWORD_SPLAT
- comment: "if arguments contain keyword splat"
- comment: Flags for arguments nodes.
- - name: CallNodeFlags
- values:
- - name: SAFE_NAVIGATION
- comment: "&. operator"
- - name: VARIABLE_CALL
- comment: "a call that could have been a local variable"
- comment: Flags for call nodes.
- - name: IntegerBaseFlags
- values:
- - name: BINARY
- comment: "0b prefix"
- - name: OCTAL
- comment: "0o or 0 prefix"
- - name: DECIMAL
- comment: "0d or no prefix"
- - name: HEXADECIMAL
- comment: "0x prefix"
- comment: Flags for integer nodes that correspond to the base of the integer.
- - name: LoopFlags
- values:
- - name: BEGIN_MODIFIER
- comment: "a loop after a begin statement, so the body is executed first before the condition"
- comment: Flags for while and until loop nodes.
- - name: RangeFlags
- values:
- - name: EXCLUDE_END
- comment: "... operator"
- comment: Flags for range and flip-flop nodes.
- - name: RegularExpressionFlags
- values:
- - name: IGNORE_CASE
- comment: "i - ignores the case of characters when matching"
- - name: EXTENDED
- comment: "x - ignores whitespace and allows comments in regular expressions"
- - name: MULTI_LINE
- comment: "m - allows $ to match the end of lines within strings"
- - name: ONCE
- comment: "o - only interpolates values into the regular expression once"
- - name: EUC_JP
- comment: "e - forces the EUC-JP encoding"
- - name: ASCII_8BIT
- comment: "n - forces the ASCII-8BIT encoding"
- - name: WINDOWS_31J
- comment: "s - forces the Windows-31J encoding"
- - name: UTF_8
- comment: "u - forces the UTF-8 encoding"
- comment: Flags for regular expression and match last line nodes.
- - name: StringFlags
- values:
- - name: FROZEN
- comment: "frozen by virtue of a `frozen_string_literal` comment"
- comment: Flags for string nodes.
-nodes:
- - name: AliasGlobalVariableNode
- fields:
- - name: new_name
- type: node
- - name: old_name
- type: node
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `alias` keyword to alias a global variable.
-
- alias $foo $bar
- ^^^^^^^^^^^^^^^
- - name: AliasMethodNode
- fields:
- - name: new_name
- type: node
- - name: old_name
- type: node
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `alias` keyword to alias a method.
-
- alias foo bar
- ^^^^^^^^^^^^^
- - name: AlternationPatternNode
- fields:
- - name: left
- type: node
- - name: right
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents an alternation pattern in pattern matching.
-
- foo => bar | baz
- ^^^^^^^^^
- - name: AndNode
- fields:
- - name: left
- type: node
- - name: right
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the `&&` operator or the `and` keyword.
-
- left and right
- ^^^^^^^^^^^^^^
- - name: ArgumentsNode
- fields:
- - name: arguments
- type: node[]
- - name: flags
- type: flags
- kind: ArgumentsNodeFlags
- comment: |
- Represents a set of arguments to a method or a keyword.
-
- return foo, bar, baz
- ^^^^^^^^^^^^^
- - name: ArrayNode
- fields:
- - name: elements
- type: node[]
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents an array literal. This can be a regular array using brackets or
- a special array using % like %w or %i.
-
- [1, 2, 3]
- ^^^^^^^^^
- - name: ArrayPatternNode
- fields:
- - name: constant
- type: node?
- - name: requireds
- type: node[]
- - name: rest
- type: node?
- - name: posts
- type: node[]
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents an array pattern in pattern matching.
-
- foo in 1, 2
- ^^^^^^^^^^^
-
- foo in [1, 2]
- ^^^^^^^^^^^^^
-
- foo in *1
- ^^^^^^^^^
-
- foo in Bar[]
- ^^^^^^^^^^^^
-
- foo in Bar[1, 2, 3]
- ^^^^^^^^^^^^^^^^^^^
- - name: AssocNode
- fields:
- - name: key
- type: node
- - name: value
- type: node?
- - name: operator_loc
- type: location?
- comment: |
- Represents a hash key/value pair.
-
- { a => b }
- ^^^^^^
- - name: AssocSplatNode
- fields:
- - name: value
- type: node?
- - name: operator_loc
- type: location
- comment: |
- Represents a splat in a hash literal.
-
- { **foo }
- ^^^^^
- - name: BackReferenceReadNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents reading a reference to a field in the previous match.
-
- $'
- ^^
- - name: BeginNode
- fields:
- - name: begin_keyword_loc
- type: location?
- - name: statements
- type: node?
- kind: StatementsNode
- - name: rescue_clause
- type: node?
- kind: RescueNode
- - name: else_clause
- type: node?
- kind: ElseNode
- - name: ensure_clause
- type: node?
- kind: EnsureNode
- - name: end_keyword_loc
- type: location?
- newline: false
- comment: |
- Represents a begin statement.
-
- begin
- foo
- end
- ^^^^^
- - name: BlockArgumentNode
- fields:
- - name: expression
- type: node?
- - name: operator_loc
- type: location
- comment: |
- Represents block method arguments.
-
- bar(&args)
- ^^^^^^^^^^
- - name: BlockLocalVariableNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents a block local variable.
-
- a { |; b| }
- ^
- - name: BlockNode
- fields:
- - name: locals
- type: constant[]
- - name: parameters
- type: node?
- kind: BlockParametersNode
- - name: body
- type: node?
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- comment: |
- Represents a block of ruby code.
-
- [1, 2, 3].each { |i| puts x }
- ^^^^^^^^^^^^^^
- - name: BlockParameterNode
- fields:
- - name: name
- type: constant?
- - name: name_loc
- type: location?
- - name: operator_loc
- type: location
- comment: |
- Represents a block parameter to a method, block, or lambda definition.
-
- def a(&b)
- ^^
- end
- - name: BlockParametersNode
- fields:
- - name: parameters
- type: node?
- kind: ParametersNode
- - name: locals
- type: node[]
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents a block's parameters declaration.
-
- -> (a, b = 1; local) { }
- ^^^^^^^^^^^^^^^^^
-
- foo do |a, b = 1; local|
- ^^^^^^^^^^^^^^^^^
- end
- - name: BreakNode
- fields:
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `break` keyword.
-
- break foo
- ^^^^^^^^^
- - name: CallAndWriteNode
- fields:
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: read_name
- type: constant
- - name: write_name
- type: constant
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `&&=` operator on a call.
-
- foo.bar &&= value
- ^^^^^^^^^^^^^^^^^
- - name: CallNode
- fields:
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - name: opening_loc
- type: location?
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location?
- - name: block
- type: node?
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: name
- type: constant
- comment: |
- Represents a method call, in all of the various forms that can take.
-
- foo
- ^^^
-
- foo()
- ^^^^^
-
- +foo
- ^^^^
-
- foo + bar
- ^^^^^^^^^
-
- foo.bar
- ^^^^^^^
-
- foo&.bar
- ^^^^^^^^
- - name: CallOperatorWriteNode
- fields:
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: read_name
- type: constant
- - name: write_name
- type: constant
- - name: operator
- type: constant
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of an assignment operator on a call.
-
- foo.bar += baz
- ^^^^^^^^^^^^^^
- - name: CallOrWriteNode
- fields:
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: read_name
- type: constant
- - name: write_name
- type: constant
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator on a call.
-
- foo.bar ||= value
- ^^^^^^^^^^^^^^^^^
- - name: CapturePatternNode
- fields:
- - name: value
- type: node
- - name: target
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents assigning to a local variable in pattern matching.
-
- foo => [bar => baz]
- ^^^^^^^^^^^^
- - name: CaseNode
- fields:
- - name: predicate
- type: node?
- - name: conditions
- type: node[]
- - name: consequent
- type: node?
- kind: ElseNode
- - name: case_keyword_loc
- type: location
- - name: end_keyword_loc
- type: location
- comment: |
- Represents the use of a case statement.
-
- case true
- when false
- end
- ^^^^^^^^^^
- - name: ClassNode
- fields:
- - name: locals
- type: constant[]
- - name: class_keyword_loc
- type: location
- - name: constant_path
- type: node
- - name: inheritance_operator_loc
- type: location?
- - name: superclass
- type: node?
- - name: body
- type: node?
- - name: end_keyword_loc
- type: location
- - name: name
- type: constant
- comment: |
- Represents a class declaration involving the `class` keyword.
-
- class Foo end
- ^^^^^^^^^^^^^
- - name: ClassVariableAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `&&=` operator for assignment to a class variable.
-
- @@target &&= value
- ^^^^^^^^^^^^^^^^^^
- - name: ClassVariableOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: operator
- type: constant
- comment: |
- Represents assigning to a class variable using an operator that isn't `=`.
-
- @@target += value
- ^^^^^^^^^^^^^^^^^
- - name: ClassVariableOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator for assignment to a class variable.
-
- @@target ||= value
- ^^^^^^^^^^^^^^^^^^
- - name: ClassVariableReadNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents referencing a class variable.
-
- @@foo
- ^^^^^
- - name: ClassVariableTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to a class variable in a context that doesn't have an explicit value.
-
- @@foo, @@bar = baz
- ^^^^^ ^^^^^
- - name: ClassVariableWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: value
- type: node
- - name: operator_loc
- type: location?
- comment: |
- Represents writing to a class variable.
-
- @@foo = 1
- ^^^^^^^^^
- - name: ConstantAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `&&=` operator for assignment to a constant.
-
- Target &&= value
- ^^^^^^^^^^^^^^^^
- - name: ConstantOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: operator
- type: constant
- comment: |
- Represents assigning to a constant using an operator that isn't `=`.
-
- Target += value
- ^^^^^^^^^^^^^^^
- - name: ConstantOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator for assignment to a constant.
-
- Target ||= value
- ^^^^^^^^^^^^^^^^
- - name: ConstantPathAndWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `&&=` operator for assignment to a constant path.
-
- Parent::Child &&= value
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: ConstantPathNode
- fields:
- - name: parent
- type: node?
- - name: child
- type: node
- - name: delimiter_loc
- type: location
- comment: |
- Represents accessing a constant through a path of `::` operators.
-
- Foo::Bar
- ^^^^^^^^
- - name: ConstantPathOperatorWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: operator
- type: constant
- comment: |
- Represents assigning to a constant path using an operator that isn't `=`.
-
- Parent::Child += value
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: ConstantPathOrWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator for assignment to a constant path.
-
- Parent::Child ||= value
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: ConstantPathTargetNode
- fields:
- - name: parent
- type: node?
- - name: child
- type: node
- - name: delimiter_loc
- type: location
- comment: |
- Represents writing to a constant path in a context that doesn't have an explicit value.
-
- Foo::Foo, Bar::Bar = baz
- ^^^^^^^^ ^^^^^^^^
- - name: ConstantPathWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents writing to a constant path.
-
- ::Foo = 1
- ^^^^^^^^^
-
- Foo::Bar = 1
- ^^^^^^^^^^^^
-
- ::Foo::Bar = 1
- ^^^^^^^^^^^^^^
- - name: ConstantReadNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents referencing a constant.
-
- Foo
- ^^^
- - name: ConstantTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to a constant in a context that doesn't have an explicit value.
-
- Foo, Bar = baz
- ^^^ ^^^
- - name: ConstantWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: value
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents writing to a constant.
-
- Foo = 1
- ^^^^^^^
- - name: DefNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: receiver
- type: node?
- - name: parameters
- type: node?
- kind: ParametersNode
- - name: body
- type: node?
- - name: locals
- type: constant[]
- - name: def_keyword_loc
- type: location
- - name: operator_loc
- type: location?
- - name: lparen_loc
- type: location?
- - name: rparen_loc
- type: location?
- - name: equal_loc
- type: location?
- - name: end_keyword_loc
- type: location?
- comment: |
- Represents a method definition.
-
- def method
- end
- ^^^^^^^^^^
- - name: DefinedNode
- fields:
- - name: lparen_loc
- type: location?
- - name: value
- type: node
- - name: rparen_loc
- type: location?
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `defined?` keyword.
-
- defined?(a)
- ^^^^^^^^^^^
- - name: ElseNode
- fields:
- - name: else_keyword_loc
- type: location
- - name: statements
- type: node?
- kind: StatementsNode
- - name: end_keyword_loc
- type: location?
- comment: |
- Represents an `else` clause in a `case`, `if`, or `unless` statement.
-
- if a then b else c end
- ^^^^^^^^^^
- - name: EmbeddedStatementsNode
- fields:
- - name: opening_loc
- type: location
- - name: statements
- type: node?
- kind: StatementsNode
- - name: closing_loc
- type: location
- comment: |
- Represents an interpolated set of statements.
-
- "foo #{bar}"
- ^^^^^^
- - name: EmbeddedVariableNode
- fields:
- - name: operator_loc
- type: location
- - name: variable
- type: node
- comment: |
- Represents an interpolated variable.
-
- "foo #@bar"
- ^^^^^
- - name: EnsureNode
- fields:
- - name: ensure_keyword_loc
- type: location
- - name: statements
- type: node?
- kind: StatementsNode
- - name: end_keyword_loc
- type: location
- comment: |
- Represents an `ensure` clause in a `begin` statement.
-
- begin
- foo
- ensure
- ^^^^^^
- bar
- end
- - name: FalseNode
- comment: |
- Represents the use of the literal `false` keyword.
-
- false
- ^^^^^
- - name: FindPatternNode
- fields:
- - name: constant
- type: node?
- - name: left
- type: node
- - name: requireds
- type: node[]
- - name: right
- type: node
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents a find pattern in pattern matching.
-
- foo in *bar, baz, *qux
- ^^^^^^^^^^^^^^^
-
- foo in [*bar, baz, *qux]
- ^^^^^^^^^^^^^^^^^
-
- foo in Foo(*bar, baz, *qux)
- ^^^^^^^^^^^^^^^^^^^^
- - name: FlipFlopNode
- fields:
- - name: left
- type: node?
- - name: right
- type: node?
- - name: operator_loc
- type: location
- - name: flags
- type: flags
- kind: RangeFlags
- comment: |
- Represents the use of the `..` or `...` operators to create flip flops.
-
- baz if foo .. bar
- ^^^^^^^^^^
- - name: FloatNode
- comment: |
- Represents a floating point number literal.
-
- 1.0
- ^^^
- - name: ForNode
- fields:
- - name: index
- type: node
- - name: collection
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- - name: for_keyword_loc
- type: location
- - name: in_keyword_loc
- type: location
- - name: do_keyword_loc
- type: location?
- - name: end_keyword_loc
- type: location
- comment: |
- Represents the use of the `for` keyword.
-
- for i in a end
- ^^^^^^^^^^^^^^
- - name: ForwardingArgumentsNode
- comment: |
- Represents forwarding all arguments to this method to another method.
-
- def foo(...)
- bar(...)
- ^^^
- end
- - name: ForwardingParameterNode
- comment: |
- Represents the use of the forwarding parameter in a method, block, or lambda declaration.
-
- def foo(...)
- ^^^
- end
- - name: ForwardingSuperNode
- fields:
- - name: block
- type: node?
- kind: BlockNode
- comment: |
- Represents the use of the `super` keyword without parentheses or arguments.
-
- super
- ^^^^^
- - name: GlobalVariableAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `&&=` operator for assignment to a global variable.
-
- $target &&= value
- ^^^^^^^^^^^^^^^^^
- - name: GlobalVariableOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: operator
- type: constant
- comment: |
- Represents assigning to a global variable using an operator that isn't `=`.
-
- $target += value
- ^^^^^^^^^^^^^^^^
- - name: GlobalVariableOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator for assignment to a global variable.
-
- $target ||= value
- ^^^^^^^^^^^^^^^^^
- - name: GlobalVariableReadNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents referencing a global variable.
-
- $foo
- ^^^^
- - name: GlobalVariableTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to a global variable in a context that doesn't have an explicit value.
-
- $foo, $bar = baz
- ^^^^ ^^^^
- - name: GlobalVariableWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: value
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents writing to a global variable.
-
- $foo = 1
- ^^^^^^^^
- - name: HashNode
- fields:
- - name: opening_loc
- type: location
- - name: elements
- type: node[]
- - name: closing_loc
- type: location
- comment: |
- Represents a hash literal.
-
- { a => b }
- ^^^^^^^^^^
- - name: HashPatternNode
- fields:
- - name: constant
- type: node?
- - name: elements
- type: node[]
- - name: rest
- type: node?
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents a hash pattern in pattern matching.
-
- foo => { a: 1, b: 2 }
- ^^^^^^^^^^^^^^
-
- foo => { a: 1, b: 2, **c }
- ^^^^^^^^^^^^^^^^^^^
- - name: IfNode
- fields:
- - name: if_keyword_loc
- type: location?
- - name: predicate
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- - name: consequent
- type: node?
- - name: end_keyword_loc
- type: location?
- newline: predicate
- comment: |
- Represents the use of the `if` keyword, either in the block form or the modifier form.
-
- bar if foo
- ^^^^^^^^^^
-
- if foo then bar end
- ^^^^^^^^^^^^^^^^^^^
- - name: ImaginaryNode
- fields:
- - name: numeric
- type: node
- comment: |
- Represents an imaginary number literal.
-
- 1.0i
- ^^^^
- - name: ImplicitNode
- fields:
- - name: value
- type: node
- comment: |
- Represents a node that is implicitly being added to the tree but doesn't
- correspond directly to a node in the source.
-
- { foo: }
- ^^^^
-
- { Foo: }
- ^^^^
- - name: InNode
- fields:
- - name: pattern
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- - name: in_loc
- type: location
- - name: then_loc
- type: location?
- comment: |
- Represents the use of the `in` keyword in a case statement.
-
- case a; in b then c end
- ^^^^^^^^^^^
- - name: IndexAndWriteNode
- fields:
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `&&=` operator on a call to the `[]` method.
-
- foo.bar[baz] &&= value
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: IndexOperatorWriteNode
- fields:
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: operator
- type: constant
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of an assignment operator on a call to `[]`.
-
- foo.bar[baz] += value
- ^^^^^^^^^^^^^^^^^^^^^
- - name: IndexOrWriteNode
- fields:
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator on a call to `[]`.
-
- foo.bar[baz] ||= value
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: InstanceVariableAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `&&=` operator for assignment to an instance variable.
-
- @target &&= value
- ^^^^^^^^^^^^^^^^^
- - name: InstanceVariableOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: operator
- type: constant
- comment: |
- Represents assigning to an instance variable using an operator that isn't `=`.
-
- @target += value
- ^^^^^^^^^^^^^^^^
- - name: InstanceVariableOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator for assignment to an instance variable.
-
- @target ||= value
- ^^^^^^^^^^^^^^^^^
- - name: InstanceVariableReadNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents referencing an instance variable.
-
- @foo
- ^^^^
- - name: InstanceVariableTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to an instance variable in a context that doesn't have an explicit value.
-
- @foo, @bar = baz
- ^^^^ ^^^^
- - name: InstanceVariableWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: value
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents writing to an instance variable.
-
- @foo = 1
- ^^^^^^^^
- - name: IntegerNode
- fields:
- - name: flags
- type: flags
- kind: IntegerBaseFlags
- comment: |
- Represents an integer number literal.
-
- 1
- ^
- - name: InterpolatedMatchLastLineNode
- fields:
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- - name: closing_loc
- type: location
- - name: flags
- type: flags
- kind: RegularExpressionFlags
- newline: parts
- comment: |
- Represents a regular expression literal that contains interpolation that
- is being used in the predicate of a conditional to implicitly match
- against the last line read by an IO object.
-
- if /foo #{bar} baz/ then end
- ^^^^^^^^^^^^^^^^
- - name: InterpolatedRegularExpressionNode
- fields:
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- - name: closing_loc
- type: location
- - name: flags
- type: flags
- kind: RegularExpressionFlags
- newline: parts
- comment: |
- Represents a regular expression literal that contains interpolation.
-
- /foo #{bar} baz/
- ^^^^^^^^^^^^^^^^
- - name: InterpolatedStringNode
- fields:
- - name: opening_loc
- type: location?
- - name: parts
- type: node[]
- - name: closing_loc
- type: location?
- newline: parts
- comment: |
- Represents a string literal that contains interpolation.
-
- "foo #{bar} baz"
- ^^^^^^^^^^^^^^^^
- - name: InterpolatedSymbolNode
- fields:
- - name: opening_loc
- type: location?
- - name: parts
- type: node[]
- - name: closing_loc
- type: location?
- newline: parts
- comment: |
- Represents a symbol literal that contains interpolation.
-
- :"foo #{bar} baz"
- ^^^^^^^^^^^^^^^^^
- - name: InterpolatedXStringNode
- fields:
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- - name: closing_loc
- type: location
- newline: parts
- comment: |
- Represents an xstring literal that contains interpolation.
-
- `foo #{bar} baz`
- ^^^^^^^^^^^^^^^^
- - name: KeywordHashNode
- fields:
- - name: elements
- type: node[]
- comment: |
- Represents a hash literal without opening and closing braces.
-
- foo(a: b)
- ^^^^
- - name: KeywordRestParameterNode
- fields:
- - name: name
- type: constant?
- - name: name_loc
- type: location?
- - name: operator_loc
- type: location
- comment: |
- Represents a keyword rest parameter to a method, block, or lambda definition.
-
- def a(**b)
- ^^^
- end
- - name: LambdaNode
- fields:
- - name: locals
- type: constant[]
- - name: operator_loc
- type: location
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- - name: parameters
- type: node?
- kind: BlockParametersNode
- - name: body
- type: node?
- comment: |
- Represents using a lambda literal (not the lambda method call).
-
- ->(value) { value * 2 }
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: LocalVariableAndWriteNode
- fields:
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: name
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents the use of the `&&=` operator for assignment to a local variable.
-
- target &&= value
- ^^^^^^^^^^^^^^^^
- - name: LocalVariableOperatorWriteNode
- fields:
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: name
- type: constant
- - name: operator
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents assigning to a local variable using an operator that isn't `=`.
-
- target += value
- ^^^^^^^^^^^^^^^
- - name: LocalVariableOrWriteNode
- fields:
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- - name: name
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents the use of the `||=` operator for assignment to a local variable.
-
- target ||= value
- ^^^^^^^^^^^^^^^^
- - name: LocalVariableReadNode
- fields:
- - name: name
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents reading a local variable. Note that this requires that a local
- variable of the same name has already been written to in the same scope,
- otherwise it is parsed as a method call.
-
- foo
- ^^^
- - name: LocalVariableTargetNode
- fields:
- - name: name
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents writing to a local variable in a context that doesn't have an explicit value.
-
- foo, bar = baz
- ^^^ ^^^
- - name: LocalVariableWriteNode
- fields:
- - name: name
- type: constant
- - name: depth
- type: uint32
- - name: name_loc
- type: location
- - name: value
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents writing to a local variable.
-
- foo = 1
- ^^^^^^^
- - name: MatchLastLineNode
- fields:
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- - name: flags
- type: flags
- kind: RegularExpressionFlags
- comment: |
- Represents a regular expression literal used in the predicate of a
- conditional to implicitly match against the last line read by an IO
- object.
-
- if /foo/i then end
- ^^^^^^
- - name: MatchPredicateNode
- fields:
- - name: value
- type: node
- - name: pattern
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the modifier `in` operator.
-
- foo in bar
- ^^^^^^^^^^
- - name: MatchRequiredNode
- fields:
- - name: value
- type: node
- - name: pattern
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the `=>` operator.
-
- foo => bar
- ^^^^^^^^^^
- - name: MatchWriteNode
- fields:
- - name: call
- type: node
- kind: CallNode
- - name: locals
- type: constant[]
- comment: |
- Represents writing local variables using a regular expression match with
- named capture groups.
-
- /(?<foo>bar)/ =~ baz
- ^^^^^^^^^^^^^^^^^^^^
- - name: MissingNode
- comment: |
- Represents a node that is missing from the source and results in a syntax
- error.
- - name: ModuleNode
- fields:
- - name: locals
- type: constant[]
- - name: module_keyword_loc
- type: location
- - name: constant_path
- type: node
- - name: body
- type: node?
- - name: end_keyword_loc
- type: location
- - name: name
- type: constant
- comment: |
- Represents a module declaration involving the `module` keyword.
-
- module Foo end
- ^^^^^^^^^^^^^^
- - name: MultiTargetNode
- fields:
- - name: lefts
- type: node[]
- - name: rest
- type: node?
- - name: rights
- type: node[]
- - name: lparen_loc
- type: location?
- - name: rparen_loc
- type: location?
- comment: |
- Represents a multi-target expression.
-
- a, (b, c) = 1, 2, 3
- ^^^^^^
- - name: MultiWriteNode
- fields:
- - name: lefts
- type: node[]
- - name: rest
- type: node?
- - name: rights
- type: node[]
- - name: lparen_loc
- type: location?
- - name: rparen_loc
- type: location?
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents a write to a multi-target expression.
-
- a, b, c = 1, 2, 3
- ^^^^^^^^^^^^^^^^^
- - name: NextNode
- fields:
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `next` keyword.
-
- next 1
- ^^^^^^
- - name: NilNode
- comment: |
- Represents the use of the `nil` keyword.
-
- nil
- ^^^
- - name: NoKeywordsParameterNode
- fields:
- - name: operator_loc
- type: location
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of `**nil` inside method arguments.
-
- def a(**nil)
- ^^^^^
- end
- - name: NumberedReferenceReadNode
- fields:
- - name: number
- type: uint32
- comment: |
- Represents reading a numbered reference to a capture in the previous match.
-
- $1
- ^^
- - name: OptionalKeywordParameterNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents an optional keyword parameter to a method, block, or lambda definition.
-
- def a(b: 1)
- ^^^^
- end
- - name: OptionalParameterNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents an optional parameter to a method, block, or lambda definition.
-
- def a(b = 1)
- ^^^^^
- end
- - name: OrNode
- fields:
- - name: left
- type: node
- - name: right
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the `||` operator or the `or` keyword.
-
- left or right
- ^^^^^^^^^^^^^
- - name: ParametersNode
- fields:
- - name: requireds
- type: node[]
- - name: optionals
- type: node[]
- - name: rest
- type: node?
- kind: RestParameterNode
- - name: posts
- type: node[]
- - name: keywords
- type: node[]
- - name: keyword_rest
- type: node?
- - name: block
- type: node?
- kind: BlockParameterNode
- comment: |
- Represents the list of parameters on a method, block, or lambda definition.
-
- def a(b, c, d)
- ^^^^^^^
- end
- - name: ParenthesesNode
- fields:
- - name: body
- type: node?
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- newline: false
- comment: |
- Represents a parenthesized expression
-
- (10 + 34)
- ^^^^^^^^^
- - name: PinnedExpressionNode
- fields:
- - name: expression
- type: node
- - name: operator_loc
- type: location
- - name: lparen_loc
- type: location
- - name: rparen_loc
- type: location
- comment: |
- Represents the use of the `^` operator for pinning an expression in a
- pattern matching expression.
-
- foo in ^(bar)
- ^^^^^^
- - name: PinnedVariableNode
- fields:
- - name: variable
- type: node
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the `^` operator for pinning a variable in a pattern
- matching expression.
-
- foo in ^bar
- ^^^^
- - name: PostExecutionNode
- fields:
- - name: statements
- type: node?
- kind: StatementsNode
- - name: keyword_loc
- type: location
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- comment: |
- Represents the use of the `END` keyword.
-
- END { foo }
- ^^^^^^^^^^^
- - name: PreExecutionNode
- fields:
- - name: statements
- type: node?
- kind: StatementsNode
- - name: keyword_loc
- type: location
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- comment: |
- Represents the use of the `BEGIN` keyword.
-
- BEGIN { foo }
- ^^^^^^^^^^^^^
- - name: ProgramNode
- fields:
- - name: locals
- type: constant[]
- - name: statements
- type: node
- kind: StatementsNode
- comment: The top level node of any parse tree.
- - name: RangeNode
- fields:
- - name: left
- type: node?
- - name: right
- type: node?
- - name: operator_loc
- type: location
- - name: flags
- type: flags
- kind: RangeFlags
- comment: |
- Represents the use of the `..` or `...` operators.
-
- 1..2
- ^^^^
-
- c if a =~ /left/ ... b =~ /right/
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- - name: RationalNode
- fields:
- - name: numeric
- type: node
- comment: |
- Represents a rational number literal.
-
- 1.0r
- ^^^^
- - name: RedoNode
- comment: |
- Represents the use of the `redo` keyword.
-
- redo
- ^^^^
- - name: RegularExpressionNode
- fields:
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- - name: flags
- type: flags
- kind: RegularExpressionFlags
- comment: |
- Represents a regular expression literal with no interpolation.
-
- /foo/i
- ^^^^^^
- - name: RequiredKeywordParameterNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- comment: |
- Represents a required keyword parameter to a method, block, or lambda definition.
-
- def a(b: )
- ^^
- end
- - name: RequiredParameterNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents a required parameter to a method, block, or lambda definition.
-
- def a(b)
- ^
- end
- - name: RescueModifierNode
- fields:
- - name: expression
- type: node
- - name: keyword_loc
- type: location
- - name: rescue_expression
- type: node
- newline: expression
- comment: |
- Represents an expression modified with a rescue.
-
- foo rescue nil
- ^^^^^^^^^^^^^^
- - name: RescueNode
- fields:
- - name: keyword_loc
- type: location
- - name: exceptions
- type: node[]
- - name: operator_loc
- type: location?
- - name: reference
- type: node?
- - name: statements
- type: node?
- kind: StatementsNode
- - name: consequent
- type: node?
- kind: RescueNode
- comment: |
- Represents a rescue statement.
-
- begin
- rescue Foo, *splat, Bar => ex
- foo
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- end
-
- `Foo, *splat, Bar` are in the `exceptions` field.
- `ex` is in the `exception` field.
- - name: RestParameterNode
- fields:
- - name: name
- type: constant?
- - name: name_loc
- type: location?
- - name: operator_loc
- type: location
- comment: |
- Represents a rest parameter to a method, block, or lambda definition.
-
- def a(*b)
- ^^
- end
- - name: RetryNode
- comment: |
- Represents the use of the `retry` keyword.
-
- retry
- ^^^^^
- - name: ReturnNode
- fields:
- - name: keyword_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- comment: |
- Represents the use of the `return` keyword.
-
- return 1
- ^^^^^^^^
- - name: SelfNode
- comment: |
- Represents the `self` keyword.
-
- self
- ^^^^
- - name: SingletonClassNode
- fields:
- - name: locals
- type: constant[]
- - name: class_keyword_loc
- type: location
- - name: operator_loc
- type: location
- - name: expression
- type: node
- - name: body
- type: node?
- - name: end_keyword_loc
- type: location
- comment: |
- Represents a singleton class declaration involving the `class` keyword.
-
- class << self end
- ^^^^^^^^^^^^^^^^^
- - name: SourceEncodingNode
- comment: |
- Represents the use of the `__ENCODING__` keyword.
-
- __ENCODING__
- ^^^^^^^^^^^^
- - name: SourceFileNode
- fields:
- - name: filepath
- type: string
- comment: |
- Represents the use of the `__FILE__` keyword.
-
- __FILE__
- ^^^^^^^^
- - name: SourceLineNode
- comment: |
- Represents the use of the `__LINE__` keyword.
-
- __LINE__
- ^^^^^^^^
- - name: SplatNode
- fields:
- - name: operator_loc
- type: location
- - name: expression
- type: node?
- comment: |
- Represents the use of the splat operator.
-
- [*a]
- ^^
- - name: StatementsNode
- fields:
- - name: body
- type: node[]
- comment: |
- Represents a set of statements contained within some scope.
-
- foo; bar; baz
- ^^^^^^^^^^^^^
- - name: StringConcatNode
- fields:
- - name: left
- type: node
- - name: right
- type: node
- comment: |
- Represents the use of compile-time string concatenation.
-
- "foo" "bar"
- ^^^^^^^^^^^
- - name: StringNode
- fields:
- - name: flags
- type: flags
- kind: StringFlags
- - name: opening_loc
- type: location?
- - name: content_loc
- type: location
- - name: closing_loc
- type: location?
- - name: unescaped
- type: string
- comment: |
- Represents a string literal, a string contained within a `%w` list, or
- plain string content within an interpolated string.
-
- "foo"
- ^^^^^
-
- %w[foo]
- ^^^
-
- "foo #{bar} baz"
- ^^^^ ^^^^
- - name: SuperNode
- fields:
- - name: keyword_loc
- type: location
- - name: lparen_loc
- type: location?
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: rparen_loc
- type: location?
- - name: block
- type: node?
- comment: |
- Represents the use of the `super` keyword with parentheses or arguments.
-
- super()
- ^^^^^^^
-
- super foo, bar
- ^^^^^^^^^^^^^^
- - name: SymbolNode
- fields:
- - name: opening_loc
- type: location?
- - name: value_loc
- type: location?
- - name: closing_loc
- type: location?
- - name: unescaped
- type: string
- comment: |
- Represents a symbol literal or a symbol contained within a `%i` list.
-
- :foo
- ^^^^
-
- %i[foo]
- ^^^
- - name: TrueNode
- comment: |
- Represents the use of the literal `true` keyword.
-
- true
- ^^^^
- - name: UndefNode
- fields:
- - name: names
- type: node[]
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `undef` keyword.
-
- undef :foo, :bar, :baz
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: UnlessNode
- fields:
- - name: keyword_loc
- type: location
- - name: predicate
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- - name: consequent
- type: node?
- kind: ElseNode
- - name: end_keyword_loc
- type: location?
- newline: predicate
- comment: |
- Represents the use of the `unless` keyword, either in the block form or the modifier form.
-
- bar unless foo
- ^^^^^^^^^^^^^^
-
- unless foo then bar end
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: UntilNode
- fields:
- - name: keyword_loc
- type: location
- - name: closing_loc
- type: location?
- - name: predicate
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- - name: flags
- type: flags
- kind: LoopFlags
- newline: predicate
- comment: |
- Represents the use of the `until` keyword, either in the block form or the modifier form.
-
- bar until foo
- ^^^^^^^^^^^^^
-
- until foo do bar end
- ^^^^^^^^^^^^^^^^^^^^
- - name: WhenNode
- fields:
- - name: keyword_loc
- type: location
- - name: conditions
- type: node[]
- - name: statements
- type: node?
- kind: StatementsNode
- comment: |
- Represents the use of the `when` keyword within a case statement.
-
- case true
- when true
- ^^^^^^^^^
- end
- - name: WhileNode
- fields:
- - name: keyword_loc
- type: location
- - name: closing_loc
- type: location?
- - name: predicate
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- - name: flags
- type: flags
- kind: LoopFlags
- newline: predicate
- comment: |
- Represents the use of the `while` keyword, either in the block form or the modifier form.
-
- bar while foo
- ^^^^^^^^^^^^^
-
- while foo do bar end
- ^^^^^^^^^^^^^^^^^^^^
- - name: XStringNode
- fields:
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- comment: |
- Represents an xstring literal with no interpolation.
-
- `foo`
- ^^^^^
- - name: YieldNode
- fields:
- - name: keyword_loc
- type: location
- - name: lparen_loc
- type: location?
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: rparen_loc
- type: location?
- comment: |
- Represents the use of the `yield` keyword.
-
- yield 1
- ^^^^^^^
diff --git a/prism/defines.h b/prism/defines.h
deleted file mode 100644
index f89a0bed8e..0000000000
--- a/prism/defines.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * @file defines.h
- *
- * Macro definitions used throughout the prism library.
- *
- * This file should be included first by any *.h or *.c in prism for consistency
- * and to ensure that the macros are defined before they are used.
- */
-#ifndef PRISM_DEFINES_H
-#define PRISM_DEFINES_H
-
-#include <ctype.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-/**
- * By default, we compile with -fvisibility=hidden. When this is enabled, we
- * need to mark certain functions as being publically-visible. This macro does
- * that in a compiler-agnostic way.
- */
-#ifndef PRISM_EXPORTED_FUNCTION
-# ifdef PRISM_EXPORT_SYMBOLS
-# ifdef _WIN32
-# define PRISM_EXPORTED_FUNCTION __declspec(dllexport) extern
-# else
-# define PRISM_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern
-# endif
-# else
-# define PRISM_EXPORTED_FUNCTION
-# endif
-#endif
-
-/**
- * Certain compilers support specifying that a function accepts variadic
- * parameters that look like printf format strings to provide a better developer
- * experience when someone is using the function. This macro does that in a
- * compiler-agnostic way.
- */
-#if defined(__GNUC__)
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(printf, string_index, argument_index)))
-#elif defined(__clang__)
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((__format__(__printf__, string_index, argument_index)))
-#else
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index)
-#endif
-
-/**
- * GCC will warn if you specify a function or parameter that is unused at
- * runtime. This macro allows you to mark a function or parameter as unused in a
- * compiler-agnostic way.
- */
-#if defined(__GNUC__)
-# define PRISM_ATTRIBUTE_UNUSED __attribute__((unused))
-#else
-# define PRISM_ATTRIBUTE_UNUSED
-#endif
-
-/**
- * Old Visual Studio versions do not support the inline keyword, so we need to
- * define it to be __inline.
- */
-#if defined(_MSC_VER) && !defined(inline)
-# define inline __inline
-#endif
-
-/**
- * Old Visual Studio versions before 2015 do not implement sprintf, but instead
- * implement _snprintf. We standard that here.
- */
-#if !defined(snprintf) && defined(_MSC_VER) && (_MSC_VER < 1900)
-# define snprintf _snprintf
-#endif
-
-#endif
diff --git a/prism/diagnostic.c b/prism/diagnostic.c
deleted file mode 100644
index fdeb9cab12..0000000000
--- a/prism/diagnostic.c
+++ /dev/null
@@ -1,291 +0,0 @@
-#include "prism/diagnostic.h"
-
-/**
- * ## Message composition
- *
- * When composing an error message, use sentence fragments.
- *
- * Try describing the property of the code that caused the error, rather than the rule that is being
- * violated. It may help to use a fragment that completes a sentence beginning, "The parser
- * encountered (a) ...". If appropriate, add a description of the rule violation (or other helpful
- * context) after a semicolon.
- *
- * For example:, instead of "Control escape sequence cannot be doubled", prefer:
- *
- * > "Invalid control escape sequence; control cannot be repeated"
- *
- * In some cases, where the failure is more general or syntax expectations are violated, it may make
- * more sense to use a fragment that completes a sentence beginning, "The parser ...".
- *
- * For example:
- *
- * > "Expected an expression after `(`"
- * > "Cannot parse the expression"
- *
- *
- * ## Message style guide
- *
- * - Use articles like "a", "an", and "the" when appropriate.
- * - e.g., prefer "Cannot parse the expression" to "Cannot parse expression".
- * - Use the common name for tokens and nodes.
- * - e.g., prefer "keyword splat" to "assoc splat"
- * - e.g., prefer "embedded document" to "embdoc"
- * - Capitalize the initial word of the message.
- * - Use back ticks around token literals
- * - e.g., "Expected a `=>` between the hash key and value"
- * - Do not use `.` or other punctuation at the end of the message.
- * - Do not use contractions like "can't". Prefer "cannot" to "can not".
- * - For tokens that can have multiple meanings, reference the token and its meaning.
- * - e.g., "`*` splat argument" is clearer and more complete than "splat argument" or "`*` argument"
- *
- *
- * ## Error names (PM_ERR_*)
- *
- * - When appropriate, prefer node name to token name.
- * - e.g., prefer "SPLAT" to "STAR" in the context of argument parsing.
- * - Prefer token name to common name.
- * - e.g., prefer "STAR" to "ASTERISK".
- * - Try to order the words in the name from more general to more specific,
- * - e.g., "INVALID_NUMBER_DECIMAL" is better than "DECIMAL_INVALID_NUMBER".
- * - When in doubt, look for similar patterns and name them so that they are grouped when lexically
- * sorted. See PM_ERR_ARGUMENT_NO_FORWARDING_* for an example.
- */
-static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
- [PM_ERR_ALIAS_ARGUMENT] = "Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable",
- [PM_ERR_AMPAMPEQ_MULTI_ASSIGN] = "Unexpected `&&=` in a multiple assignment",
- [PM_ERR_ARGUMENT_AFTER_BLOCK] = "Unexpected argument after a block argument",
- [PM_ERR_ARGUMENT_BARE_HASH] = "Unexpected bare hash argument",
- [PM_ERR_ARGUMENT_BLOCK_MULTI] = "Multiple block arguments; only one block is allowed",
- [PM_ERR_ARGUMENT_FORMAL_CLASS] = "Invalid formal argument; formal argument cannot be a class variable",
- [PM_ERR_ARGUMENT_FORMAL_CONSTANT] = "Invalid formal argument; formal argument cannot be a constant",
- [PM_ERR_ARGUMENT_FORMAL_GLOBAL] = "Invalid formal argument; formal argument cannot be a global variable",
- [PM_ERR_ARGUMENT_FORMAL_IVAR] = "Invalid formal argument; formal argument cannot be an instance variable",
- [PM_ERR_ARGUMENT_NO_FORWARDING_AMP] = "Unexpected `&` when the parent method is not forwarding",
- [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = "Unexpected `...` when the parent method is not forwarding",
- [PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = "Unexpected `*` when the parent method is not forwarding",
- [PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = "Unexpected `*` splat argument after a `**` keyword splat argument",
- [PM_ERR_ARGUMENT_SPLAT_AFTER_SPLAT] = "Unexpected `*` splat argument after a `*` splat argument",
- [PM_ERR_ARGUMENT_TERM_PAREN] = "Expected a `)` to close the arguments",
- [PM_ERR_ARGUMENT_UNEXPECTED_BLOCK] = "Unexpected `{` after a method call without parenthesis",
- [PM_ERR_ARRAY_ELEMENT] = "Expected an element for the array",
- [PM_ERR_ARRAY_EXPRESSION] = "Expected an expression for the array element",
- [PM_ERR_ARRAY_EXPRESSION_AFTER_STAR] = "Expected an expression after `*` in the array",
- [PM_ERR_ARRAY_SEPARATOR] = "Expected a `,` separator for the array elements",
- [PM_ERR_ARRAY_TERM] = "Expected a `]` to close the array",
- [PM_ERR_BEGIN_LONELY_ELSE] = "Unexpected `else` in `begin` block; a `rescue` clause must precede `else`",
- [PM_ERR_BEGIN_TERM] = "Expected an `end` to close the `begin` statement",
- [PM_ERR_BEGIN_UPCASE_BRACE] = "Expected a `{` after `BEGIN`",
- [PM_ERR_BEGIN_UPCASE_TERM] = "Expected a `}` to close the `BEGIN` statement",
- [PM_ERR_BEGIN_UPCASE_TOPLEVEL] = "BEGIN is permitted only at toplevel",
- [PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE] = "Expected a local variable name in the block parameters",
- [PM_ERR_BLOCK_PARAM_PIPE_TERM] = "Expected the block parameters to end with `|`",
- [PM_ERR_BLOCK_TERM_BRACE] = "Expected a block beginning with `{` to end with `}`",
- [PM_ERR_BLOCK_TERM_END] = "Expected a block beginning with `do` to end with `end`",
- [PM_ERR_CANNOT_PARSE_EXPRESSION] = "Cannot parse the expression",
- [PM_ERR_CANNOT_PARSE_STRING_PART] = "Cannot parse the string part",
- [PM_ERR_CASE_EXPRESSION_AFTER_CASE] = "Expected an expression after `case`",
- [PM_ERR_CASE_EXPRESSION_AFTER_WHEN] = "Expected an expression after `when`",
- [PM_ERR_CASE_MISSING_CONDITIONS] = "Expected a `when` or `in` clause after `case`",
- [PM_ERR_CASE_TERM] = "Expected an `end` to close the `case` statement",
- [PM_ERR_CLASS_IN_METHOD] = "Unexpected class definition in a method body",
- [PM_ERR_CLASS_NAME] = "Expected a constant name after `class`",
- [PM_ERR_CLASS_SUPERCLASS] = "Expected a superclass after `<`",
- [PM_ERR_CLASS_TERM] = "Expected an `end` to close the `class` statement",
- [PM_ERR_CLASS_UNEXPECTED_END] = "Unexpected `end`, expecting ';' or '\n'",
- [PM_ERR_CONDITIONAL_ELSIF_PREDICATE] = "Expected a predicate expression for the `elsif` statement",
- [PM_ERR_CONDITIONAL_IF_PREDICATE] = "Expected a predicate expression for the `if` statement",
- [PM_ERR_CONDITIONAL_PREDICATE_TERM] = "Expected `then` or `;` or '\n'",
- [PM_ERR_CONDITIONAL_TERM] = "Expected an `end` to close the conditional clause",
- [PM_ERR_CONDITIONAL_TERM_ELSE] = "Expected an `end` to close the `else` clause",
- [PM_ERR_CONDITIONAL_UNLESS_PREDICATE] = "Expected a predicate expression for the `unless` statement",
- [PM_ERR_CONDITIONAL_UNTIL_PREDICATE] = "Expected a predicate expression for the `until` statement",
- [PM_ERR_CONDITIONAL_WHILE_PREDICATE] = "Expected a predicate expression for the `while` statement",
- [PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT] = "Expected a constant after the `::` operator",
- [PM_ERR_DEF_ENDLESS] = "Could not parse the endless method body",
- [PM_ERR_DEF_ENDLESS_SETTER] = "Invalid method name; a setter method cannot be defined in an endless method definition",
- [PM_ERR_DEF_NAME] = "Expected a method name",
- [PM_ERR_DEF_NAME_AFTER_RECEIVER] = "Expected a method name after the receiver",
- [PM_ERR_DEF_PARAMS_TERM] = "Expected a delimiter to close the parameters",
- [PM_ERR_DEF_PARAMS_TERM_PAREN] = "Expected a `)` to close the parameters",
- [PM_ERR_DEF_RECEIVER] = "Expected a receiver for the method definition",
- [PM_ERR_DEF_RECEIVER_TERM] = "Expected a `.` or `::` after the receiver in a method definition",
- [PM_ERR_DEF_TERM] = "Expected an `end` to close the `def` statement",
- [PM_ERR_DEFINED_EXPRESSION] = "Expected an expression after `defined?`",
- [PM_ERR_EMBDOC_TERM] = "Could not find a terminator for the embedded document",
- [PM_ERR_EMBEXPR_END] = "Expected a `}` to close the embedded expression",
- [PM_ERR_EMBVAR_INVALID] = "Invalid embedded variable",
- [PM_ERR_END_UPCASE_BRACE] = "Expected a `{` after `END`",
- [PM_ERR_END_UPCASE_TERM] = "Expected a `}` to close the `END` statement",
- [PM_ERR_ESCAPE_INVALID_CONTROL] = "Invalid control escape sequence",
- [PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT] = "Invalid control escape sequence; control cannot be repeated",
- [PM_ERR_ESCAPE_INVALID_HEXADECIMAL] = "Invalid hexadecimal escape sequence",
- [PM_ERR_ESCAPE_INVALID_META] = "Invalid meta escape sequence",
- [PM_ERR_ESCAPE_INVALID_META_REPEAT] = "Invalid meta escape sequence; meta cannot be repeated",
- [PM_ERR_ESCAPE_INVALID_UNICODE] = "Invalid Unicode escape sequence",
- [PM_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS] = "Invalid Unicode escape sequence; Unicode cannot be combined with control or meta flags",
- [PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL] = "Invalid Unicode escape sequence; multiple codepoints are not allowed in a character literal",
- [PM_ERR_ESCAPE_INVALID_UNICODE_LONG] = "Invalid Unicode escape sequence; maximum length is 6 digits",
- [PM_ERR_ESCAPE_INVALID_UNICODE_TERM] = "Invalid Unicode escape sequence; needs closing `}`",
- [PM_ERR_EXPECT_ARGUMENT] = "Expected an argument",
- [PM_ERR_EXPECT_EOL_AFTER_STATEMENT] = "Expected a newline or semicolon after the statement",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ] = "Expected an expression after `&&=`",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ] = "Expected an expression after `||=`",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA] = "Expected an expression after `,`",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL] = "Expected an expression after `=`",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS] = "Expected an expression after `<<`",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_LPAREN] = "Expected an expression after `(`",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR] = "Expected an expression after the operator",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT] = "Expected an expression after `*` splat in an argument",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = "Expected an expression after `**` in a hash",
- [PM_ERR_EXPECT_EXPRESSION_AFTER_STAR] = "Expected an expression after `*`",
- [PM_ERR_EXPECT_IDENT_REQ_PARAMETER] = "Expected an identifier for the required parameter",
- [PM_ERR_EXPECT_LPAREN_REQ_PARAMETER] = "Expected a `(` to start a required parameter",
- [PM_ERR_EXPECT_RBRACKET] = "Expected a matching `]`",
- [PM_ERR_EXPECT_RPAREN] = "Expected a matching `)`",
- [PM_ERR_EXPECT_RPAREN_AFTER_MULTI] = "Expected a `)` after multiple assignment",
- [PM_ERR_EXPECT_RPAREN_REQ_PARAMETER] = "Expected a `)` to end a required parameter",
- [PM_ERR_EXPECT_STRING_CONTENT] = "Expected string content after opening string delimiter",
- [PM_ERR_EXPECT_WHEN_DELIMITER] = "Expected a delimiter after the predicates of a `when` clause",
- [PM_ERR_EXPRESSION_BARE_HASH] = "Unexpected bare hash in expression",
- [PM_ERR_FOR_COLLECTION] = "Expected a collection after the `in` in a `for` statement",
- [PM_ERR_FOR_INDEX] = "Expected an index after `for`",
- [PM_ERR_FOR_IN] = "Expected an `in` after the index in a `for` statement",
- [PM_ERR_FOR_TERM] = "Expected an `end` to close the `for` loop",
- [PM_ERR_HASH_EXPRESSION_AFTER_LABEL] = "Expected an expression after the label in a hash",
- [PM_ERR_HASH_KEY] = "Expected a key in the hash literal",
- [PM_ERR_HASH_ROCKET] = "Expected a `=>` between the hash key and value",
- [PM_ERR_HASH_TERM] = "Expected a `}` to close the hash literal",
- [PM_ERR_HASH_VALUE] = "Expected a value in the hash literal",
- [PM_ERR_HEREDOC_TERM] = "Could not find a terminator for the heredoc",
- [PM_ERR_INCOMPLETE_QUESTION_MARK] = "Incomplete expression at `?`",
- [PM_ERR_INCOMPLETE_VARIABLE_CLASS] = "Incomplete class variable",
- [PM_ERR_INCOMPLETE_VARIABLE_INSTANCE] = "Incomplete instance variable",
- [PM_ERR_INVALID_ENCODING_MAGIC_COMMENT] = "Unknown or invalid encoding in the magic comment",
- [PM_ERR_INVALID_FLOAT_EXPONENT] = "Invalid exponent",
- [PM_ERR_INVALID_NUMBER_BINARY] = "Invalid binary number",
- [PM_ERR_INVALID_NUMBER_DECIMAL] = "Invalid decimal number",
- [PM_ERR_INVALID_NUMBER_HEXADECIMAL] = "Invalid hexadecimal number",
- [PM_ERR_INVALID_NUMBER_OCTAL] = "Invalid octal number",
- [PM_ERR_INVALID_NUMBER_UNDERSCORE] = "Invalid underscore placement in number",
- [PM_ERR_INVALID_PERCENT] = "Invalid `%` token", // TODO WHAT?
- [PM_ERR_INVALID_TOKEN] = "Invalid token", // TODO WHAT?
- [PM_ERR_INVALID_VARIABLE_GLOBAL] = "Invalid global variable",
- [PM_ERR_LAMBDA_OPEN] = "Expected a `do` keyword or a `{` to open the lambda block",
- [PM_ERR_LAMBDA_TERM_BRACE] = "Expected a lambda block beginning with `{` to end with `}`",
- [PM_ERR_LAMBDA_TERM_END] = "Expected a lambda block beginning with `do` to end with `end`",
- [PM_ERR_LIST_I_LOWER_ELEMENT] = "Expected a symbol in a `%i` list",
- [PM_ERR_LIST_I_LOWER_TERM] = "Expected a closing delimiter for the `%i` list",
- [PM_ERR_LIST_I_UPPER_ELEMENT] = "Expected a symbol in a `%I` list",
- [PM_ERR_LIST_I_UPPER_TERM] = "Expected a closing delimiter for the `%I` list",
- [PM_ERR_LIST_W_LOWER_ELEMENT] = "Expected a string in a `%w` list",
- [PM_ERR_LIST_W_LOWER_TERM] = "Expected a closing delimiter for the `%w` list",
- [PM_ERR_LIST_W_UPPER_ELEMENT] = "Expected a string in a `%W` list",
- [PM_ERR_LIST_W_UPPER_TERM] = "Expected a closing delimiter for the `%W` list",
- [PM_ERR_MALLOC_FAILED] = "Failed to allocate memory",
- [PM_ERR_MODULE_IN_METHOD] = "Unexpected module definition in a method body",
- [PM_ERR_MODULE_NAME] = "Expected a constant name after `module`",
- [PM_ERR_MODULE_TERM] = "Expected an `end` to close the `module` statement",
- [PM_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "Multiple splats in multiple assignment",
- [PM_ERR_NOT_EXPRESSION] = "Expected an expression after `not`",
- [PM_ERR_NUMBER_LITERAL_UNDERSCORE] = "Number literal ending with a `_`",
- [PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = "Numbered parameters are not allowed alongside explicit parameters",
- [PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE] = "Numbered parameter is already used in outer scope",
- [PM_ERR_OPERATOR_MULTI_ASSIGN] = "Unexpected operator for a multiple assignment",
- [PM_ERR_OPERATOR_WRITE_ARGUMENTS] = "Unexpected operator after a call with arguments",
- [PM_ERR_OPERATOR_WRITE_BLOCK] = "Unexpected operator after a call with a block",
- [PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI] = "Unexpected multiple `**` splat parameters",
- [PM_ERR_PARAMETER_BLOCK_MULTI] = "Multiple block parameters; only one block is allowed",
- [PM_ERR_PARAMETER_METHOD_NAME] = "Unexpected name for a parameter",
- [PM_ERR_PARAMETER_NAME_REPEAT] = "Repeated parameter name",
- [PM_ERR_PARAMETER_NO_DEFAULT] = "Expected a default value for the parameter",
- [PM_ERR_PARAMETER_NO_DEFAULT_KW] = "Expected a default value for the keyword parameter",
- [PM_ERR_PARAMETER_NUMBERED_RESERVED] = "Token reserved for a numbered parameter",
- [PM_ERR_PARAMETER_ORDER] = "Unexpected parameter order",
- [PM_ERR_PARAMETER_SPLAT_MULTI] = "Unexpected multiple `*` splat parameters",
- [PM_ERR_PARAMETER_STAR] = "Unexpected parameter `*`",
- [PM_ERR_PARAMETER_UNEXPECTED_FWD] = "Unexpected `...` in parameters",
- [PM_ERR_PARAMETER_WILD_LOOSE_COMMA] = "Unexpected `,` in parameters",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = "Expected a pattern expression after the `[` operator",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = "Expected a pattern expression after `,`",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = "Expected a pattern expression after `=>`",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_IN] = "Expected a pattern expression after the `in` keyword",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_KEY] = "Expected a pattern expression after the key",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN] = "Expected a pattern expression after the `(` operator",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_PIN] = "Expected a pattern expression after the `^` pin operator",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE] = "Expected a pattern expression after the `|` operator",
- [PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE] = "Expected a pattern expression after the range operator",
- [PM_ERR_PATTERN_HASH_KEY] = "Expected a key in the hash pattern",
- [PM_ERR_PATTERN_HASH_KEY_LABEL] = "Expected a label as the key in the hash pattern", // TODO // THIS // AND // ABOVE // IS WEIRD
- [PM_ERR_PATTERN_IDENT_AFTER_HROCKET] = "Expected an identifier after the `=>` operator",
- [PM_ERR_PATTERN_LABEL_AFTER_COMMA] = "Expected a label after the `,` in the hash pattern",
- [PM_ERR_PATTERN_REST] = "Unexpected rest pattern",
- [PM_ERR_PATTERN_TERM_BRACE] = "Expected a `}` to close the pattern expression",
- [PM_ERR_PATTERN_TERM_BRACKET] = "Expected a `]` to close the pattern expression",
- [PM_ERR_PATTERN_TERM_PAREN] = "Expected a `)` to close the pattern expression",
- [PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN] = "Unexpected `||=` in a multiple assignment",
- [PM_ERR_REGEXP_TERM] = "Expected a closing delimiter for the regular expression",
- [PM_ERR_RESCUE_EXPRESSION] = "Expected a rescued expression",
- [PM_ERR_RESCUE_MODIFIER_VALUE] = "Expected a value after the `rescue` modifier",
- [PM_ERR_RESCUE_TERM] = "Expected a closing delimiter for the `rescue` clause",
- [PM_ERR_RESCUE_VARIABLE] = "Expected an exception variable after `=>` in a rescue statement",
- [PM_ERR_RETURN_INVALID] = "Invalid `return` in a class or module body",
- [PM_ERR_STRING_CONCATENATION] = "Expected a string for concatenation",
- [PM_ERR_STRING_INTERPOLATED_TERM] = "Expected a closing delimiter for the interpolated string",
- [PM_ERR_STRING_LITERAL_TERM] = "Expected a closing delimiter for the string literal",
- [PM_ERR_SYMBOL_INVALID] = "Invalid symbol", // TODO expected symbol? prism.c ~9719
- [PM_ERR_SYMBOL_TERM_DYNAMIC] = "Expected a closing delimiter for the dynamic symbol",
- [PM_ERR_SYMBOL_TERM_INTERPOLATED] = "Expected a closing delimiter for the interpolated symbol",
- [PM_ERR_TERNARY_COLON] = "Expected a `:` after the true expression of a ternary operator",
- [PM_ERR_TERNARY_EXPRESSION_FALSE] = "Expected an expression after `:` in the ternary operator",
- [PM_ERR_TERNARY_EXPRESSION_TRUE] = "Expected an expression after `?` in the ternary operator",
- [PM_ERR_UNDEF_ARGUMENT] = "Invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument",
- [PM_ERR_UNARY_RECEIVER_BANG] = "Expected a receiver for unary `!`",
- [PM_ERR_UNARY_RECEIVER_MINUS] = "Expected a receiver for unary `-`",
- [PM_ERR_UNARY_RECEIVER_PLUS] = "Expected a receiver for unary `+`",
- [PM_ERR_UNARY_RECEIVER_TILDE] = "Expected a receiver for unary `~`",
- [PM_ERR_UNTIL_TERM] = "Expected an `end` to close the `until` statement",
- [PM_ERR_WHILE_TERM] = "Expected an `end` to close the `while` statement",
- [PM_ERR_WRITE_TARGET_READONLY] = "Immutable variable as a write target",
- [PM_ERR_WRITE_TARGET_UNEXPECTED] = "Unexpected write target",
- [PM_ERR_XSTRING_TERM] = "Expected a closing delimiter for the `%x` or backtick string",
- [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS] = "Ambiguous first argument; put parentheses or a space even after `-` operator",
- [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = "Ambiguous first argument; put parentheses or a space even after `+` operator",
- [PM_WARN_AMBIGUOUS_PREFIX_STAR] = "Ambiguous `*` has been interpreted as an argument prefix",
- [PM_WARN_AMBIGUOUS_SLASH] = "Ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator",
-};
-
-static const char*
-pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
- assert(diag_id < PM_DIAGNOSTIC_ID_LEN);
- const char *message = diagnostic_messages[diag_id];
- assert(message);
- return message;
-}
-
-/**
- * Append an error to the given list of diagnostic.
- */
-bool
-pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id) {
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) calloc(sizeof(pm_diagnostic_t), 1);
- if (diagnostic == NULL) return false;
-
- *diagnostic = (pm_diagnostic_t) { .start = start, .end = end, .message = pm_diagnostic_message(diag_id) };
- pm_list_append(list, (pm_list_node_t *) diagnostic);
- return true;
-}
-
-/**
- * Deallocate the internal state of the given diagnostic list.
- */
-void
-pm_diagnostic_list_free(pm_list_t *list) {
- pm_list_node_t *node, *next;
-
- for (node = list->head; node != NULL; node = next) {
- next = node->next;
-
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) node;
- free(diagnostic);
- }
-}
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
deleted file mode 100644
index 97bd83fdf7..0000000000
--- a/prism/diagnostic.h
+++ /dev/null
@@ -1,265 +0,0 @@
-/**
- * @file diagnostic.h
- *
- * A list of diagnostics generated during parsing.
- */
-#ifndef PRISM_DIAGNOSTIC_H
-#define PRISM_DIAGNOSTIC_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_list.h"
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <assert.h>
-
-/**
- * This struct represents a diagnostic generated during parsing.
- *
- * @extends pm_list_node_t
- */
-typedef struct {
- /** The embedded base node. */
- pm_list_node_t node;
-
- /** A pointer to the start of the source that generated the diagnostic. */
- const uint8_t *start;
-
- /** A pointer to the end of the source that generated the diagnostic. */
- const uint8_t *end;
-
- /** The message associated with the diagnostic. */
- const char *message;
-} pm_diagnostic_t;
-
-/**
- * The diagnostic IDs of all of the diagnostics, used to communicate the types
- * of errors between the parser and the user.
- */
-typedef enum {
- PM_ERR_ALIAS_ARGUMENT,
- PM_ERR_AMPAMPEQ_MULTI_ASSIGN,
- PM_ERR_ARGUMENT_AFTER_BLOCK,
- PM_ERR_ARGUMENT_BARE_HASH,
- PM_ERR_ARGUMENT_BLOCK_MULTI,
- PM_ERR_ARGUMENT_FORMAL_CLASS,
- PM_ERR_ARGUMENT_FORMAL_CONSTANT,
- PM_ERR_ARGUMENT_FORMAL_GLOBAL,
- PM_ERR_ARGUMENT_FORMAL_IVAR,
- PM_ERR_ARGUMENT_NO_FORWARDING_AMP,
- PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
- PM_ERR_ARGUMENT_NO_FORWARDING_STAR,
- PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT,
- PM_ERR_ARGUMENT_SPLAT_AFTER_SPLAT,
- PM_ERR_ARGUMENT_TERM_PAREN,
- PM_ERR_ARGUMENT_UNEXPECTED_BLOCK,
- PM_ERR_ARRAY_ELEMENT,
- PM_ERR_ARRAY_EXPRESSION,
- PM_ERR_ARRAY_EXPRESSION_AFTER_STAR,
- PM_ERR_ARRAY_SEPARATOR,
- PM_ERR_ARRAY_TERM,
- PM_ERR_BEGIN_LONELY_ELSE,
- PM_ERR_BEGIN_TERM,
- PM_ERR_BEGIN_UPCASE_BRACE,
- PM_ERR_BEGIN_UPCASE_TERM,
- PM_ERR_BEGIN_UPCASE_TOPLEVEL,
- PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE,
- PM_ERR_BLOCK_PARAM_PIPE_TERM,
- PM_ERR_BLOCK_TERM_BRACE,
- PM_ERR_BLOCK_TERM_END,
- PM_ERR_CANNOT_PARSE_EXPRESSION,
- PM_ERR_CANNOT_PARSE_STRING_PART,
- PM_ERR_CASE_EXPRESSION_AFTER_CASE,
- PM_ERR_CASE_EXPRESSION_AFTER_WHEN,
- PM_ERR_CASE_MISSING_CONDITIONS,
- PM_ERR_CASE_TERM,
- PM_ERR_CLASS_IN_METHOD,
- PM_ERR_CLASS_NAME,
- PM_ERR_CLASS_SUPERCLASS,
- PM_ERR_CLASS_TERM,
- PM_ERR_CLASS_UNEXPECTED_END,
- PM_ERR_CONDITIONAL_ELSIF_PREDICATE,
- PM_ERR_CONDITIONAL_IF_PREDICATE,
- PM_ERR_CONDITIONAL_PREDICATE_TERM,
- PM_ERR_CONDITIONAL_TERM,
- PM_ERR_CONDITIONAL_TERM_ELSE,
- PM_ERR_CONDITIONAL_UNLESS_PREDICATE,
- PM_ERR_CONDITIONAL_UNTIL_PREDICATE,
- PM_ERR_CONDITIONAL_WHILE_PREDICATE,
- PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT,
- PM_ERR_DEF_ENDLESS,
- PM_ERR_DEF_ENDLESS_SETTER,
- PM_ERR_DEF_NAME,
- PM_ERR_DEF_NAME_AFTER_RECEIVER,
- PM_ERR_DEF_PARAMS_TERM,
- PM_ERR_DEF_PARAMS_TERM_PAREN,
- PM_ERR_DEF_RECEIVER,
- PM_ERR_DEF_RECEIVER_TERM,
- PM_ERR_DEF_TERM,
- PM_ERR_DEFINED_EXPRESSION,
- PM_ERR_EMBDOC_TERM,
- PM_ERR_EMBEXPR_END,
- PM_ERR_EMBVAR_INVALID,
- PM_ERR_END_UPCASE_BRACE,
- PM_ERR_END_UPCASE_TERM,
- PM_ERR_ESCAPE_INVALID_CONTROL,
- PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT,
- PM_ERR_ESCAPE_INVALID_HEXADECIMAL,
- PM_ERR_ESCAPE_INVALID_META,
- PM_ERR_ESCAPE_INVALID_META_REPEAT,
- PM_ERR_ESCAPE_INVALID_UNICODE,
- PM_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS,
- PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL,
- PM_ERR_ESCAPE_INVALID_UNICODE_LONG,
- PM_ERR_ESCAPE_INVALID_UNICODE_TERM,
- PM_ERR_EXPECT_ARGUMENT,
- PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
- PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ,
- PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ,
- PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA,
- PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL,
- PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS,
- PM_ERR_EXPECT_EXPRESSION_AFTER_LPAREN,
- PM_ERR_EXPECT_EXPRESSION_AFTER_QUESTION,
- PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR,
- PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT,
- PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH,
- PM_ERR_EXPECT_EXPRESSION_AFTER_STAR,
- PM_ERR_EXPECT_IDENT_REQ_PARAMETER,
- PM_ERR_EXPECT_LPAREN_REQ_PARAMETER,
- PM_ERR_EXPECT_RBRACKET,
- PM_ERR_EXPECT_RPAREN,
- PM_ERR_EXPECT_RPAREN_AFTER_MULTI,
- PM_ERR_EXPECT_RPAREN_REQ_PARAMETER,
- PM_ERR_EXPECT_STRING_CONTENT,
- PM_ERR_EXPECT_WHEN_DELIMITER,
- PM_ERR_EXPRESSION_BARE_HASH,
- PM_ERR_FOR_COLLECTION,
- PM_ERR_FOR_IN,
- PM_ERR_FOR_INDEX,
- PM_ERR_FOR_TERM,
- PM_ERR_HASH_EXPRESSION_AFTER_LABEL,
- PM_ERR_HASH_KEY,
- PM_ERR_HASH_ROCKET,
- PM_ERR_HASH_TERM,
- PM_ERR_HASH_VALUE,
- PM_ERR_HEREDOC_TERM,
- PM_ERR_INCOMPLETE_QUESTION_MARK,
- PM_ERR_INCOMPLETE_VARIABLE_CLASS,
- PM_ERR_INCOMPLETE_VARIABLE_INSTANCE,
- PM_ERR_INVALID_ENCODING_MAGIC_COMMENT,
- PM_ERR_INVALID_FLOAT_EXPONENT,
- PM_ERR_INVALID_NUMBER_BINARY,
- PM_ERR_INVALID_NUMBER_DECIMAL,
- PM_ERR_INVALID_NUMBER_HEXADECIMAL,
- PM_ERR_INVALID_NUMBER_OCTAL,
- PM_ERR_INVALID_NUMBER_UNDERSCORE,
- PM_ERR_INVALID_PERCENT,
- PM_ERR_INVALID_TOKEN,
- PM_ERR_INVALID_VARIABLE_GLOBAL,
- PM_ERR_LAMBDA_OPEN,
- PM_ERR_LAMBDA_TERM_BRACE,
- PM_ERR_LAMBDA_TERM_END,
- PM_ERR_LIST_I_LOWER_ELEMENT,
- PM_ERR_LIST_I_LOWER_TERM,
- PM_ERR_LIST_I_UPPER_ELEMENT,
- PM_ERR_LIST_I_UPPER_TERM,
- PM_ERR_LIST_W_LOWER_ELEMENT,
- PM_ERR_LIST_W_LOWER_TERM,
- PM_ERR_LIST_W_UPPER_ELEMENT,
- PM_ERR_LIST_W_UPPER_TERM,
- PM_ERR_MALLOC_FAILED,
- PM_ERR_MODULE_IN_METHOD,
- PM_ERR_MODULE_NAME,
- PM_ERR_MODULE_TERM,
- PM_ERR_MULTI_ASSIGN_MULTI_SPLATS,
- PM_ERR_NOT_EXPRESSION,
- PM_ERR_NUMBER_LITERAL_UNDERSCORE,
- PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED,
- PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE,
- PM_ERR_OPERATOR_MULTI_ASSIGN,
- PM_ERR_OPERATOR_WRITE_ARGUMENTS,
- PM_ERR_OPERATOR_WRITE_BLOCK,
- PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI,
- PM_ERR_PARAMETER_BLOCK_MULTI,
- PM_ERR_PARAMETER_METHOD_NAME,
- PM_ERR_PARAMETER_NAME_REPEAT,
- PM_ERR_PARAMETER_NO_DEFAULT,
- PM_ERR_PARAMETER_NO_DEFAULT_KW,
- PM_ERR_PARAMETER_NUMBERED_RESERVED,
- PM_ERR_PARAMETER_ORDER,
- PM_ERR_PARAMETER_SPLAT_MULTI,
- PM_ERR_PARAMETER_STAR,
- PM_ERR_PARAMETER_UNEXPECTED_FWD,
- PM_ERR_PARAMETER_WILD_LOOSE_COMMA,
- PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET,
- PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET,
- PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA,
- PM_ERR_PATTERN_EXPRESSION_AFTER_IN,
- PM_ERR_PATTERN_EXPRESSION_AFTER_KEY,
- PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN,
- PM_ERR_PATTERN_EXPRESSION_AFTER_PIN,
- PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE,
- PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE,
- PM_ERR_PATTERN_HASH_KEY,
- PM_ERR_PATTERN_HASH_KEY_LABEL,
- PM_ERR_PATTERN_IDENT_AFTER_HROCKET,
- PM_ERR_PATTERN_LABEL_AFTER_COMMA,
- PM_ERR_PATTERN_REST,
- PM_ERR_PATTERN_TERM_BRACE,
- PM_ERR_PATTERN_TERM_BRACKET,
- PM_ERR_PATTERN_TERM_PAREN,
- PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN,
- PM_ERR_REGEXP_TERM,
- PM_ERR_RESCUE_EXPRESSION,
- PM_ERR_RESCUE_MODIFIER_VALUE,
- PM_ERR_RESCUE_TERM,
- PM_ERR_RESCUE_VARIABLE,
- PM_ERR_RETURN_INVALID,
- PM_ERR_STRING_CONCATENATION,
- PM_ERR_STRING_INTERPOLATED_TERM,
- PM_ERR_STRING_LITERAL_TERM,
- PM_ERR_SYMBOL_INVALID,
- PM_ERR_SYMBOL_TERM_DYNAMIC,
- PM_ERR_SYMBOL_TERM_INTERPOLATED,
- PM_ERR_TERNARY_COLON,
- PM_ERR_TERNARY_EXPRESSION_FALSE,
- PM_ERR_TERNARY_EXPRESSION_TRUE,
- PM_ERR_UNARY_RECEIVER_BANG,
- PM_ERR_UNARY_RECEIVER_MINUS,
- PM_ERR_UNARY_RECEIVER_PLUS,
- PM_ERR_UNARY_RECEIVER_TILDE,
- PM_ERR_UNDEF_ARGUMENT,
- PM_ERR_UNTIL_TERM,
- PM_ERR_WHILE_TERM,
- PM_ERR_WRITE_TARGET_READONLY,
- PM_ERR_WRITE_TARGET_UNEXPECTED,
- PM_ERR_XSTRING_TERM,
- PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS,
- PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS,
- PM_WARN_AMBIGUOUS_PREFIX_STAR,
- PM_WARN_AMBIGUOUS_SLASH,
-
- /* This must be the last member. */
- PM_DIAGNOSTIC_ID_LEN,
-} pm_diagnostic_id_t;
-
-/**
- * Append a diagnostic to the given list of diagnostics.
- *
- * @param list The list to append to.
- * @param start The start of the diagnostic.
- * @param end The end of the diagnostic.
- * @param diag_id The diagnostic ID.
- * @return Whether the diagnostic was successfully appended.
- */
-bool pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id);
-
-/**
- * Deallocate the internal state of the given diagnostic list.
- *
- * @param list The list to deallocate.
- */
-void pm_diagnostic_list_free(pm_list_t *list);
-
-#endif
diff --git a/prism/enc/pm_big5.c b/prism/enc/pm_big5.c
deleted file mode 100644
index fc5c4e73f0..0000000000
--- a/prism/enc/pm_big5.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "prism/enc/pm_encoding.h"
-
-static size_t
-pm_encoding_big5_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if ((n > 1) && (b[0] >= 0xA1 && b[0] <= 0xFE) && (b[1] >= 0x40 && b[1] <= 0xFE)) {
- return 2;
- }
-
- return 0;
-}
-
-static size_t
-pm_encoding_big5_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_big5_char_width(b, n) == 1) {
- return pm_encoding_ascii_alpha_char(b, n);
- } else {
- return 0;
- }
-}
-
-static size_t
-pm_encoding_big5_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_big5_char_width(b, n) == 1) {
- return pm_encoding_ascii_alnum_char(b, n);
- } else {
- return 0;
- }
-}
-
-static bool
-pm_encoding_big5_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_big5_char_width(b, n) == 1) {
- return pm_encoding_ascii_isupper_char(b, n);
- } else {
- return false;
- }
-}
-
-/** Big5 encoding */
-pm_encoding_t pm_encoding_big5 = {
- .name = "big5",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_big5_alnum_char,
- .alpha_char = pm_encoding_big5_alpha_char,
- .isupper_char = pm_encoding_big5_isupper_char,
- .multibyte = true
-};
diff --git a/prism/enc/pm_encoding.h b/prism/enc/pm_encoding.h
deleted file mode 100644
index a42be774bc..0000000000
--- a/prism/enc/pm_encoding.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/**
- * @file pm_encoding.h
- *
- * The encoding interface and implementations used by the parser.
- */
-#ifndef PRISM_ENCODING_H
-#define PRISM_ENCODING_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * This struct defines the functions necessary to implement the encoding
- * interface so we can determine how many bytes the subsequent character takes.
- * Each callback should return the number of bytes, or 0 if the next bytes are
- * invalid for the encoding and type.
- */
-typedef struct {
- /**
- * Return the number of bytes that the next character takes if it is valid
- * in the encoding. Does not read more than n bytes. It is assumed that n is
- * at least 1.
- */
- size_t (*char_width)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * Return the number of bytes that the next character takes if it is valid
- * in the encoding and is alphabetical. Does not read more than n bytes. It
- * is assumed that n is at least 1.
- */
- size_t (*alpha_char)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * Return the number of bytes that the next character takes if it is valid
- * in the encoding and is alphanumeric. Does not read more than n bytes. It
- * is assumed that n is at least 1.
- */
- size_t (*alnum_char)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * Return true if the next character is valid in the encoding and is an
- * uppercase character. Does not read more than n bytes. It is assumed that
- * n is at least 1.
- */
- bool (*isupper_char)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * The name of the encoding. This should correspond to a value that can be
- * passed to Encoding.find in Ruby.
- */
- const char *name;
-
- /**
- * Return true if the encoding is a multibyte encoding.
- */
- bool multibyte;
-} pm_encoding_t;
-
-/**
- * All of the lookup tables use the first bit of each embedded byte to indicate
- * whether the codepoint is alphabetical.
- */
-#define PRISM_ENCODING_ALPHABETIC_BIT 1 << 0
-
-/**
- * All of the lookup tables use the second bit of each embedded byte to indicate
- * whether the codepoint is alphanumeric.
- */
-#define PRISM_ENCODING_ALPHANUMERIC_BIT 1 << 1
-
-/**
- * All of the lookup tables use the third bit of each embedded byte to indicate
- * whether the codepoint is uppercase.
- */
-#define PRISM_ENCODING_UPPERCASE_BIT 1 << 2
-
-/**
- * Return the size of the next character in the ASCII encoding if it is an
- * alphabetical character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_ascii_alpha_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n);
-
-/**
- * Return the size of the next character in the ASCII encoding if it is an
- * alphanumeric character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_ascii_alnum_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n);
-
-/**
- * Return true if the next character in the ASCII encoding if it is an uppercase
- * character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns True if the next character is valid in the encoding and is an
- * uppercase character, or false if it is not.
- */
-bool pm_encoding_ascii_isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n);
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphabetical character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphanumeric character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return true if the next character in the UTF-8 encoding if it is an uppercase
- * character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns True if the next character is valid in the encoding and is an
- * uppercase character, or false if it is not.
- */
-bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * This lookup table is referenced in both the UTF-8 encoding file and the
- * parser directly in order to speed up the default encoding processing. It is
- * used to indicate whether a character is alphabetical, alphanumeric, or
- * uppercase in unicode mappings.
- */
-extern const uint8_t pm_encoding_unicode_table[256];
-
-// Below are the encodings that are supported by the parser. They are defined in
-// their own files in the src/enc directory.
-
-extern pm_encoding_t pm_encoding_ascii;
-extern pm_encoding_t pm_encoding_ascii_8bit;
-extern pm_encoding_t pm_encoding_big5;
-extern pm_encoding_t pm_encoding_euc_jp;
-extern pm_encoding_t pm_encoding_gbk;
-extern pm_encoding_t pm_encoding_iso_8859_1;
-extern pm_encoding_t pm_encoding_iso_8859_2;
-extern pm_encoding_t pm_encoding_iso_8859_3;
-extern pm_encoding_t pm_encoding_iso_8859_4;
-extern pm_encoding_t pm_encoding_iso_8859_5;
-extern pm_encoding_t pm_encoding_iso_8859_6;
-extern pm_encoding_t pm_encoding_iso_8859_7;
-extern pm_encoding_t pm_encoding_iso_8859_8;
-extern pm_encoding_t pm_encoding_iso_8859_9;
-extern pm_encoding_t pm_encoding_iso_8859_10;
-extern pm_encoding_t pm_encoding_iso_8859_11;
-extern pm_encoding_t pm_encoding_iso_8859_13;
-extern pm_encoding_t pm_encoding_iso_8859_14;
-extern pm_encoding_t pm_encoding_iso_8859_15;
-extern pm_encoding_t pm_encoding_iso_8859_16;
-extern pm_encoding_t pm_encoding_koi8_r;
-extern pm_encoding_t pm_encoding_shift_jis;
-extern pm_encoding_t pm_encoding_utf_8;
-extern pm_encoding_t pm_encoding_utf8_mac;
-extern pm_encoding_t pm_encoding_windows_31j;
-extern pm_encoding_t pm_encoding_windows_1251;
-extern pm_encoding_t pm_encoding_windows_1252;
-
-#endif
diff --git a/prism/enc/pm_euc_jp.c b/prism/enc/pm_euc_jp.c
deleted file mode 100644
index 6babcae347..0000000000
--- a/prism/enc/pm_euc_jp.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include "prism/enc/pm_encoding.h"
-
-static size_t
-pm_encoding_euc_jp_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if (
- (n > 1) &&
- (
- ((b[0] == 0x8E) && (b[1] >= 0xA1 && b[1] <= 0xFE)) ||
- ((b[0] >= 0xA1 && b[0] <= 0xFE) && (b[1] >= 0xA1 && b[1] <= 0xFE))
- )
- ) {
- return 2;
- }
-
- return 0;
-}
-
-static size_t
-pm_encoding_euc_jp_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_euc_jp_char_width(b, n) == 1) {
- return pm_encoding_ascii_alpha_char(b, n);
- } else {
- return 0;
- }
-}
-
-static size_t
-pm_encoding_euc_jp_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_euc_jp_char_width(b, n) == 1) {
- return pm_encoding_ascii_alnum_char(b, n);
- } else {
- return 0;
- }
-}
-
-static bool
-pm_encoding_euc_jp_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_euc_jp_char_width(b, n) == 1) {
- return pm_encoding_ascii_isupper_char(b, n);
- } else {
- return 0;
- }
-}
-
-/** EUC-JP encoding */
-pm_encoding_t pm_encoding_euc_jp = {
- .name = "euc-jp",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_euc_jp_alnum_char,
- .alpha_char = pm_encoding_euc_jp_alpha_char,
- .isupper_char = pm_encoding_euc_jp_isupper_char,
- .multibyte = true
-};
diff --git a/prism/enc/pm_gbk.c b/prism/enc/pm_gbk.c
deleted file mode 100644
index 250b98b33b..0000000000
--- a/prism/enc/pm_gbk.c
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "prism/enc/pm_encoding.h"
-
-static size_t
-pm_encoding_gbk_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if (
- (n > 1) &&
- (
- ((b[0] >= 0xA1 && b[0] <= 0xA9) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // GBK/1
- ((b[0] >= 0xB0 && b[0] <= 0xF7) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // GBK/2
- ((b[0] >= 0x81 && b[0] <= 0xA0) && (b[1] >= 0x40 && b[1] <= 0xFE) && (b[1] != 0x7F)) || // GBK/3
- ((b[0] >= 0xAA && b[0] <= 0xFE) && (b[1] >= 0x40 && b[1] <= 0xA0) && (b[1] != 0x7F)) || // GBK/4
- ((b[0] >= 0xA8 && b[0] <= 0xA9) && (b[1] >= 0x40 && b[1] <= 0xA0) && (b[1] != 0x7F)) // GBK/5
- )
- ) {
- return 2;
- }
-
- return 0;
-}
-
-static size_t
-pm_encoding_gbk_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_gbk_char_width(b, n) == 1) {
- return pm_encoding_ascii_alpha_char(b, n);
- } else {
- return 0;
- }
-}
-
-static size_t
-pm_encoding_gbk_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_gbk_char_width(b, n) == 1) {
- return pm_encoding_ascii_alnum_char(b, n);
- } else {
- return 0;
- }
-}
-
-static bool
-pm_encoding_gbk_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_gbk_char_width(b, n) == 1) {
- return pm_encoding_ascii_isupper_char(b, n);
- } else {
- return false;
- }
-}
-
-/** GBK encoding */
-pm_encoding_t pm_encoding_gbk = {
- .name = "gbk",
- .char_width = pm_encoding_gbk_char_width,
- .alnum_char = pm_encoding_gbk_alnum_char,
- .alpha_char = pm_encoding_gbk_alpha_char,
- .isupper_char = pm_encoding_gbk_isupper_char,
- .multibyte = true
-};
diff --git a/prism/enc/pm_shift_jis.c b/prism/enc/pm_shift_jis.c
deleted file mode 100644
index f92956e08b..0000000000
--- a/prism/enc/pm_shift_jis.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "prism/enc/pm_encoding.h"
-
-static size_t
-pm_encoding_shift_jis_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80 || (*b >= 0xA1 && *b <= 0xDF)) {
- return 1;
- }
-
- // These are the double byte characters.
- if (
- (n > 1) &&
- ((b[0] >= 0x81 && b[0] <= 0x9F) || (b[0] >= 0xE0 && b[0] <= 0xFC)) &&
- (b[1] >= 0x40 && b[1] <= 0xFC)
- ) {
- return 2;
- }
-
- return 0;
-}
-
-static size_t
-pm_encoding_shift_jis_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_shift_jis_char_width(b, n) == 1) {
- return pm_encoding_ascii_alpha_char(b, n);
- } else {
- return 0;
- }
-}
-
-static size_t
-pm_encoding_shift_jis_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_shift_jis_char_width(b, n) == 1) {
- return pm_encoding_ascii_alnum_char(b, n);
- } else {
- return 0;
- }
-}
-
-static bool
-pm_encoding_shift_jis_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_shift_jis_char_width(b, n) == 1) {
- return pm_encoding_ascii_isupper_char(b, n);
- } else {
- return 0;
- }
-}
-
-/** Shift_JIS encoding */
-pm_encoding_t pm_encoding_shift_jis = {
- .name = "shift_jis",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_shift_jis_alnum_char,
- .alpha_char = pm_encoding_shift_jis_alpha_char,
- .isupper_char = pm_encoding_shift_jis_isupper_char,
- .multibyte = true
-};
diff --git a/prism/enc/pm_tables.c b/prism/enc/pm_tables.c
deleted file mode 100644
index 7b840acfaa..0000000000
--- a/prism/enc/pm_tables.c
+++ /dev/null
@@ -1,743 +0,0 @@
-#include "prism/enc/pm_encoding.h"
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ASCII character.
- */
-static uint8_t pm_encoding_ascii_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-1 character.
- */
-static uint8_t pm_encoding_iso_8859_1_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-2 character.
- */
-static uint8_t pm_encoding_iso_8859_2_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 0, 7, 0, 7, 7, 0, 0, 7, 7, 7, 7, 0, 7, 7, // Ax
- 0, 3, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-3 character.
- */
-static uint8_t pm_encoding_iso_8859_3_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 0, 0, 0, 0, 7, 0, 0, 7, 7, 7, 7, 0, 0, 7, // Ax
- 0, 3, 0, 0, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0, 0, 3, // Bx
- 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 0, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-4 character.
- */
-static uint8_t pm_encoding_iso_8859_4_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 3, 7, 0, 7, 7, 0, 0, 7, 7, 7, 7, 0, 7, 0, // Ax
- 0, 3, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 7, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-5 character.
- */
-static uint8_t pm_encoding_iso_8859_5_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, // Ax
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-6 character.
- */
-static uint8_t pm_encoding_iso_8859_6_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-7 character.
- */
-static uint8_t pm_encoding_iso_8859_7_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 7, 0, 7, 7, 7, 0, 7, 0, 7, 7, // Bx
- 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-8 character.
- */
-static uint8_t pm_encoding_iso_8859_8_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-9 character.
- */
-static uint8_t pm_encoding_iso_8859_9_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-10 character.
- */
-static uint8_t pm_encoding_iso_8859_10_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, // Ax
- 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-11 character.
- */
-static uint8_t pm_encoding_iso_8859_11_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ax
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Bx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-13 character.
- */
-static uint8_t pm_encoding_iso_8859_13_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 0, 0, 0, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-14 character.
- */
-static uint8_t pm_encoding_iso_8859_14_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 3, 0, 7, 3, 7, 0, 7, 0, 7, 3, 7, 0, 0, 7, // Ax
- 7, 3, 7, 3, 7, 3, 0, 7, 3, 3, 3, 7, 3, 7, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-15 character.
- */
-static uint8_t pm_encoding_iso_8859_15_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 7, 0, 3, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 7, 3, 0, 0, 3, 0, 3, 0, 7, 3, 7, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-16 character.
- */
-static uint8_t pm_encoding_iso_8859_16_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 3, 7, 0, 0, 7, 0, 3, 0, 7, 0, 7, 0, 3, 7, // Ax
- 0, 0, 7, 3, 7, 0, 0, 0, 3, 3, 3, 0, 7, 3, 7, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding KOI8-R character.
- */
-static uint8_t pm_encoding_koi8_r_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Dx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Ex
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1251 character.
- */
-static uint8_t pm_encoding_windows_1251_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 7, 7, 0, 3, 0, 0, 0, 0, 0, 0, 7, 0, 7, 7, 7, 7, // 8x
- 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, // 9x
- 0, 7, 3, 7, 0, 7, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, // Ax
- 0, 0, 7, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 7, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1252 character.
- */
-static uint8_t pm_encoding_windows_1252_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 7, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Returns the size of the next character in the ASCII encoding. This basically
- * means that if the top bit is not set, the character is 1 byte long.
- */
-static size_t
-pm_encoding_ascii_char_width(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return *b < 0x80 ? 1 : 0;
-}
-
-/**
- * Return the size of the next character in the ASCII encoding if it is an
- * alphabetical character.
- */
-size_t
-pm_encoding_ascii_alpha_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT);
-}
-
-/**
- * Return the size of the next character in the ASCII encoding if it is an
- * alphanumeric character.
- */
-size_t
-pm_encoding_ascii_alnum_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT) ? 1 : 0;
-}
-
-/**
- * Return true if the next character in the ASCII encoding if it is an uppercase
- * character.
- */
-bool
-pm_encoding_ascii_isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return (pm_encoding_ascii_table[*b] & PRISM_ENCODING_UPPERCASE_BIT);
-}
-
-/**
- * For a lot of encodings the default is that they are a single byte long no
- * matter what the codepoint, so this function is shared between them.
- */
-static size_t
-pm_encoding_single_char_width(PRISM_ATTRIBUTE_UNUSED const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return 1;
-}
-
-/**
- * Returns the size of the next character in the KOI-8 encoding. This means
- * checking if it's a valid codepoint in KOI-8 and if it is returning 1.
- */
-static size_t
-pm_encoding_koi8_r_char_width(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return ((*b >= 0x20 && *b <= 0x7E) || (*b >= 0x80)) ? 1 : 0;
-}
-
-#define PRISM_ENCODING_TABLE(name) \
- static size_t pm_encoding_ ##name ## _alpha_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { \
- return (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_ALPHABETIC_BIT); \
- } \
- static size_t pm_encoding_ ##name ## _alnum_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { \
- return (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT) ? 1 : 0; \
- } \
- static bool pm_encoding_ ##name ## _isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { \
- return (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_UPPERCASE_BIT); \
- }
-
-PRISM_ENCODING_TABLE(iso_8859_1)
-PRISM_ENCODING_TABLE(iso_8859_2)
-PRISM_ENCODING_TABLE(iso_8859_3)
-PRISM_ENCODING_TABLE(iso_8859_4)
-PRISM_ENCODING_TABLE(iso_8859_5)
-PRISM_ENCODING_TABLE(iso_8859_6)
-PRISM_ENCODING_TABLE(iso_8859_7)
-PRISM_ENCODING_TABLE(iso_8859_8)
-PRISM_ENCODING_TABLE(iso_8859_9)
-PRISM_ENCODING_TABLE(iso_8859_10)
-PRISM_ENCODING_TABLE(iso_8859_11)
-PRISM_ENCODING_TABLE(iso_8859_13)
-PRISM_ENCODING_TABLE(iso_8859_14)
-PRISM_ENCODING_TABLE(iso_8859_15)
-PRISM_ENCODING_TABLE(iso_8859_16)
-PRISM_ENCODING_TABLE(koi8_r)
-PRISM_ENCODING_TABLE(windows_1251)
-PRISM_ENCODING_TABLE(windows_1252)
-
-#undef PRISM_ENCODING_TABLE
-
-/** ASCII encoding */
-pm_encoding_t pm_encoding_ascii = {
- .name = "ascii",
- .char_width = pm_encoding_ascii_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char,
- .alpha_char = pm_encoding_ascii_alpha_char,
- .isupper_char = pm_encoding_ascii_isupper_char,
- .multibyte = false
-};
-
-/** ASCII-8BIT encoding */
-pm_encoding_t pm_encoding_ascii_8bit = {
- .name = "ascii-8bit",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char,
- .alpha_char = pm_encoding_ascii_alpha_char,
- .isupper_char = pm_encoding_ascii_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-1 */
-pm_encoding_t pm_encoding_iso_8859_1 = {
- .name = "iso-8859-1",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_1_alnum_char,
- .alpha_char = pm_encoding_iso_8859_1_alpha_char,
- .isupper_char = pm_encoding_iso_8859_1_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-2 */
-pm_encoding_t pm_encoding_iso_8859_2 = {
- .name = "iso-8859-2",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_2_alnum_char,
- .alpha_char = pm_encoding_iso_8859_2_alpha_char,
- .isupper_char = pm_encoding_iso_8859_2_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-3 */
-pm_encoding_t pm_encoding_iso_8859_3 = {
- .name = "iso-8859-3",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_3_alnum_char,
- .alpha_char = pm_encoding_iso_8859_3_alpha_char,
- .isupper_char = pm_encoding_iso_8859_3_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-4 */
-pm_encoding_t pm_encoding_iso_8859_4 = {
- .name = "iso-8859-4",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_4_alnum_char,
- .alpha_char = pm_encoding_iso_8859_4_alpha_char,
- .isupper_char = pm_encoding_iso_8859_4_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-5 */
-pm_encoding_t pm_encoding_iso_8859_5 = {
- .name = "iso-8859-5",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_5_alnum_char,
- .alpha_char = pm_encoding_iso_8859_5_alpha_char,
- .isupper_char = pm_encoding_iso_8859_5_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-6 */
-pm_encoding_t pm_encoding_iso_8859_6 = {
- .name = "iso-8859-6",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_6_alnum_char,
- .alpha_char = pm_encoding_iso_8859_6_alpha_char,
- .isupper_char = pm_encoding_iso_8859_6_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-7 */
-pm_encoding_t pm_encoding_iso_8859_7 = {
- .name = "iso-8859-7",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_7_alnum_char,
- .alpha_char = pm_encoding_iso_8859_7_alpha_char,
- .isupper_char = pm_encoding_iso_8859_7_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-8 */
-pm_encoding_t pm_encoding_iso_8859_8 = {
- .name = "iso-8859-8",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_8_alnum_char,
- .alpha_char = pm_encoding_iso_8859_8_alpha_char,
- .isupper_char = pm_encoding_iso_8859_8_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-9 */
-pm_encoding_t pm_encoding_iso_8859_9 = {
- .name = "iso-8859-9",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_9_alnum_char,
- .alpha_char = pm_encoding_iso_8859_9_alpha_char,
- .isupper_char = pm_encoding_iso_8859_9_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-10 */
-pm_encoding_t pm_encoding_iso_8859_10 = {
- .name = "iso-8859-10",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_10_alnum_char,
- .alpha_char = pm_encoding_iso_8859_10_alpha_char,
- .isupper_char = pm_encoding_iso_8859_10_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-11 */
-pm_encoding_t pm_encoding_iso_8859_11 = {
- .name = "iso-8859-11",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_11_alnum_char,
- .alpha_char = pm_encoding_iso_8859_11_alpha_char,
- .isupper_char = pm_encoding_iso_8859_11_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-13 */
-pm_encoding_t pm_encoding_iso_8859_13 = {
- .name = "iso-8859-13",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_13_alnum_char,
- .alpha_char = pm_encoding_iso_8859_13_alpha_char,
- .isupper_char = pm_encoding_iso_8859_13_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-14 */
-pm_encoding_t pm_encoding_iso_8859_14 = {
- .name = "iso-8859-14",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_14_alnum_char,
- .alpha_char = pm_encoding_iso_8859_14_alpha_char,
- .isupper_char = pm_encoding_iso_8859_14_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-15 */
-pm_encoding_t pm_encoding_iso_8859_15 = {
- .name = "iso-8859-15",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_15_alnum_char,
- .alpha_char = pm_encoding_iso_8859_15_alpha_char,
- .isupper_char = pm_encoding_iso_8859_15_isupper_char,
- .multibyte = false
-};
-
-/** ISO-8859-16 */
-pm_encoding_t pm_encoding_iso_8859_16 = {
- .name = "iso-8859-16",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_16_alnum_char,
- .alpha_char = pm_encoding_iso_8859_16_alpha_char,
- .isupper_char = pm_encoding_iso_8859_16_isupper_char,
- .multibyte = false
-};
-
-/** KOI8-R */
-pm_encoding_t pm_encoding_koi8_r = {
- .name = "koi8-r",
- .char_width = pm_encoding_koi8_r_char_width,
- .alnum_char = pm_encoding_koi8_r_alnum_char,
- .alpha_char = pm_encoding_koi8_r_alpha_char,
- .isupper_char = pm_encoding_koi8_r_isupper_char,
- .multibyte = false
-};
-
-/** Windows-1251 */
-pm_encoding_t pm_encoding_windows_1251 = {
- .name = "windows-1251",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1251_alnum_char,
- .alpha_char = pm_encoding_windows_1251_alpha_char,
- .isupper_char = pm_encoding_windows_1251_isupper_char,
- .multibyte = false
-};
-
-/** Windows-1252 */
-pm_encoding_t pm_encoding_windows_1252 = {
- .name = "windows-1252",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1252_alnum_char,
- .alpha_char = pm_encoding_windows_1252_alpha_char,
- .isupper_char = pm_encoding_windows_1252_isupper_char,
- .multibyte = false
-};
diff --git a/prism/enc/pm_unicode.c b/prism/enc/pm_unicode.c
deleted file mode 100644
index 41c1f25812..0000000000
--- a/prism/enc/pm_unicode.c
+++ /dev/null
@@ -1,2369 +0,0 @@
-#include "prism/enc/pm_encoding.h"
-
-typedef uint32_t pm_unicode_codepoint_t;
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding unicode codepoint. Note that
- * this table is different from other encodings where we used a lookup table
- * because the indices of those tables are the byte representations, not the
- * codepoints themselves.
- */
-const uint8_t pm_encoding_unicode_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-#define UNICODE_ALPHA_CODEPOINTS_LENGTH 1450
-static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = {
- 0x100, 0x2C1,
- 0x2C6, 0x2D1,
- 0x2E0, 0x2E4,
- 0x2EC, 0x2EC,
- 0x2EE, 0x2EE,
- 0x345, 0x345,
- 0x370, 0x374,
- 0x376, 0x377,
- 0x37A, 0x37D,
- 0x37F, 0x37F,
- 0x386, 0x386,
- 0x388, 0x38A,
- 0x38C, 0x38C,
- 0x38E, 0x3A1,
- 0x3A3, 0x3F5,
- 0x3F7, 0x481,
- 0x48A, 0x52F,
- 0x531, 0x556,
- 0x559, 0x559,
- 0x560, 0x588,
- 0x5B0, 0x5BD,
- 0x5BF, 0x5BF,
- 0x5C1, 0x5C2,
- 0x5C4, 0x5C5,
- 0x5C7, 0x5C7,
- 0x5D0, 0x5EA,
- 0x5EF, 0x5F2,
- 0x610, 0x61A,
- 0x620, 0x657,
- 0x659, 0x65F,
- 0x66E, 0x6D3,
- 0x6D5, 0x6DC,
- 0x6E1, 0x6E8,
- 0x6ED, 0x6EF,
- 0x6FA, 0x6FC,
- 0x6FF, 0x6FF,
- 0x710, 0x73F,
- 0x74D, 0x7B1,
- 0x7CA, 0x7EA,
- 0x7F4, 0x7F5,
- 0x7FA, 0x7FA,
- 0x800, 0x817,
- 0x81A, 0x82C,
- 0x840, 0x858,
- 0x860, 0x86A,
- 0x870, 0x887,
- 0x889, 0x88E,
- 0x8A0, 0x8C9,
- 0x8D4, 0x8DF,
- 0x8E3, 0x8E9,
- 0x8F0, 0x93B,
- 0x93D, 0x94C,
- 0x94E, 0x950,
- 0x955, 0x963,
- 0x971, 0x983,
- 0x985, 0x98C,
- 0x98F, 0x990,
- 0x993, 0x9A8,
- 0x9AA, 0x9B0,
- 0x9B2, 0x9B2,
- 0x9B6, 0x9B9,
- 0x9BD, 0x9C4,
- 0x9C7, 0x9C8,
- 0x9CB, 0x9CC,
- 0x9CE, 0x9CE,
- 0x9D7, 0x9D7,
- 0x9DC, 0x9DD,
- 0x9DF, 0x9E3,
- 0x9F0, 0x9F1,
- 0x9FC, 0x9FC,
- 0xA01, 0xA03,
- 0xA05, 0xA0A,
- 0xA0F, 0xA10,
- 0xA13, 0xA28,
- 0xA2A, 0xA30,
- 0xA32, 0xA33,
- 0xA35, 0xA36,
- 0xA38, 0xA39,
- 0xA3E, 0xA42,
- 0xA47, 0xA48,
- 0xA4B, 0xA4C,
- 0xA51, 0xA51,
- 0xA59, 0xA5C,
- 0xA5E, 0xA5E,
- 0xA70, 0xA75,
- 0xA81, 0xA83,
- 0xA85, 0xA8D,
- 0xA8F, 0xA91,
- 0xA93, 0xAA8,
- 0xAAA, 0xAB0,
- 0xAB2, 0xAB3,
- 0xAB5, 0xAB9,
- 0xABD, 0xAC5,
- 0xAC7, 0xAC9,
- 0xACB, 0xACC,
- 0xAD0, 0xAD0,
- 0xAE0, 0xAE3,
- 0xAF9, 0xAFC,
- 0xB01, 0xB03,
- 0xB05, 0xB0C,
- 0xB0F, 0xB10,
- 0xB13, 0xB28,
- 0xB2A, 0xB30,
- 0xB32, 0xB33,
- 0xB35, 0xB39,
- 0xB3D, 0xB44,
- 0xB47, 0xB48,
- 0xB4B, 0xB4C,
- 0xB56, 0xB57,
- 0xB5C, 0xB5D,
- 0xB5F, 0xB63,
- 0xB71, 0xB71,
- 0xB82, 0xB83,
- 0xB85, 0xB8A,
- 0xB8E, 0xB90,
- 0xB92, 0xB95,
- 0xB99, 0xB9A,
- 0xB9C, 0xB9C,
- 0xB9E, 0xB9F,
- 0xBA3, 0xBA4,
- 0xBA8, 0xBAA,
- 0xBAE, 0xBB9,
- 0xBBE, 0xBC2,
- 0xBC6, 0xBC8,
- 0xBCA, 0xBCC,
- 0xBD0, 0xBD0,
- 0xBD7, 0xBD7,
- 0xC00, 0xC0C,
- 0xC0E, 0xC10,
- 0xC12, 0xC28,
- 0xC2A, 0xC39,
- 0xC3D, 0xC44,
- 0xC46, 0xC48,
- 0xC4A, 0xC4C,
- 0xC55, 0xC56,
- 0xC58, 0xC5A,
- 0xC5D, 0xC5D,
- 0xC60, 0xC63,
- 0xC80, 0xC83,
- 0xC85, 0xC8C,
- 0xC8E, 0xC90,
- 0xC92, 0xCA8,
- 0xCAA, 0xCB3,
- 0xCB5, 0xCB9,
- 0xCBD, 0xCC4,
- 0xCC6, 0xCC8,
- 0xCCA, 0xCCC,
- 0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
- 0xCE0, 0xCE3,
- 0xCF1, 0xCF3,
- 0xD00, 0xD0C,
- 0xD0E, 0xD10,
- 0xD12, 0xD3A,
- 0xD3D, 0xD44,
- 0xD46, 0xD48,
- 0xD4A, 0xD4C,
- 0xD4E, 0xD4E,
- 0xD54, 0xD57,
- 0xD5F, 0xD63,
- 0xD7A, 0xD7F,
- 0xD81, 0xD83,
- 0xD85, 0xD96,
- 0xD9A, 0xDB1,
- 0xDB3, 0xDBB,
- 0xDBD, 0xDBD,
- 0xDC0, 0xDC6,
- 0xDCF, 0xDD4,
- 0xDD6, 0xDD6,
- 0xDD8, 0xDDF,
- 0xDF2, 0xDF3,
- 0xE01, 0xE3A,
- 0xE40, 0xE46,
- 0xE4D, 0xE4D,
- 0xE81, 0xE82,
- 0xE84, 0xE84,
- 0xE86, 0xE8A,
- 0xE8C, 0xEA3,
- 0xEA5, 0xEA5,
- 0xEA7, 0xEB9,
- 0xEBB, 0xEBD,
- 0xEC0, 0xEC4,
- 0xEC6, 0xEC6,
- 0xECD, 0xECD,
- 0xEDC, 0xEDF,
- 0xF00, 0xF00,
- 0xF40, 0xF47,
- 0xF49, 0xF6C,
- 0xF71, 0xF83,
- 0xF88, 0xF97,
- 0xF99, 0xFBC,
- 0x1000, 0x1036,
- 0x1038, 0x1038,
- 0x103B, 0x103F,
- 0x1050, 0x108F,
- 0x109A, 0x109D,
- 0x10A0, 0x10C5,
- 0x10C7, 0x10C7,
- 0x10CD, 0x10CD,
- 0x10D0, 0x10FA,
- 0x10FC, 0x1248,
- 0x124A, 0x124D,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125A, 0x125D,
- 0x1260, 0x1288,
- 0x128A, 0x128D,
- 0x1290, 0x12B0,
- 0x12B2, 0x12B5,
- 0x12B8, 0x12BE,
- 0x12C0, 0x12C0,
- 0x12C2, 0x12C5,
- 0x12C8, 0x12D6,
- 0x12D8, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x135A,
- 0x1380, 0x138F,
- 0x13A0, 0x13F5,
- 0x13F8, 0x13FD,
- 0x1401, 0x166C,
- 0x166F, 0x167F,
- 0x1681, 0x169A,
- 0x16A0, 0x16EA,
- 0x16EE, 0x16F8,
- 0x1700, 0x1713,
- 0x171F, 0x1733,
- 0x1740, 0x1753,
- 0x1760, 0x176C,
- 0x176E, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17B3,
- 0x17B6, 0x17C8,
- 0x17D7, 0x17D7,
- 0x17DC, 0x17DC,
- 0x1820, 0x1878,
- 0x1880, 0x18AA,
- 0x18B0, 0x18F5,
- 0x1900, 0x191E,
- 0x1920, 0x192B,
- 0x1930, 0x1938,
- 0x1950, 0x196D,
- 0x1970, 0x1974,
- 0x1980, 0x19AB,
- 0x19B0, 0x19C9,
- 0x1A00, 0x1A1B,
- 0x1A20, 0x1A5E,
- 0x1A61, 0x1A74,
- 0x1AA7, 0x1AA7,
- 0x1ABF, 0x1AC0,
- 0x1ACC, 0x1ACE,
- 0x1B00, 0x1B33,
- 0x1B35, 0x1B43,
- 0x1B45, 0x1B4C,
- 0x1B80, 0x1BA9,
- 0x1BAC, 0x1BAF,
- 0x1BBA, 0x1BE5,
- 0x1BE7, 0x1BF1,
- 0x1C00, 0x1C36,
- 0x1C4D, 0x1C4F,
- 0x1C5A, 0x1C7D,
- 0x1C80, 0x1C88,
- 0x1C90, 0x1CBA,
- 0x1CBD, 0x1CBF,
- 0x1CE9, 0x1CEC,
- 0x1CEE, 0x1CF3,
- 0x1CF5, 0x1CF6,
- 0x1CFA, 0x1CFA,
- 0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
- 0x1E00, 0x1F15,
- 0x1F18, 0x1F1D,
- 0x1F20, 0x1F45,
- 0x1F48, 0x1F4D,
- 0x1F50, 0x1F57,
- 0x1F59, 0x1F59,
- 0x1F5B, 0x1F5B,
- 0x1F5D, 0x1F5D,
- 0x1F5F, 0x1F7D,
- 0x1F80, 0x1FB4,
- 0x1FB6, 0x1FBC,
- 0x1FBE, 0x1FBE,
- 0x1FC2, 0x1FC4,
- 0x1FC6, 0x1FCC,
- 0x1FD0, 0x1FD3,
- 0x1FD6, 0x1FDB,
- 0x1FE0, 0x1FEC,
- 0x1FF2, 0x1FF4,
- 0x1FF6, 0x1FFC,
- 0x2071, 0x2071,
- 0x207F, 0x207F,
- 0x2090, 0x209C,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210A, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211D,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212A, 0x212D,
- 0x212F, 0x2139,
- 0x213C, 0x213F,
- 0x2145, 0x2149,
- 0x214E, 0x214E,
- 0x2160, 0x2188,
- 0x24B6, 0x24E9,
- 0x2C00, 0x2CE4,
- 0x2CEB, 0x2CEE,
- 0x2CF2, 0x2CF3,
- 0x2D00, 0x2D25,
- 0x2D27, 0x2D27,
- 0x2D2D, 0x2D2D,
- 0x2D30, 0x2D67,
- 0x2D6F, 0x2D6F,
- 0x2D80, 0x2D96,
- 0x2DA0, 0x2DA6,
- 0x2DA8, 0x2DAE,
- 0x2DB0, 0x2DB6,
- 0x2DB8, 0x2DBE,
- 0x2DC0, 0x2DC6,
- 0x2DC8, 0x2DCE,
- 0x2DD0, 0x2DD6,
- 0x2DD8, 0x2DDE,
- 0x2DE0, 0x2DFF,
- 0x2E2F, 0x2E2F,
- 0x3005, 0x3007,
- 0x3021, 0x3029,
- 0x3031, 0x3035,
- 0x3038, 0x303C,
- 0x3041, 0x3096,
- 0x309D, 0x309F,
- 0x30A1, 0x30FA,
- 0x30FC, 0x30FF,
- 0x3105, 0x312F,
- 0x3131, 0x318E,
- 0x31A0, 0x31BF,
- 0x31F0, 0x31FF,
- 0x3400, 0x4DBF,
- 0x4E00, 0xA48C,
- 0xA4D0, 0xA4FD,
- 0xA500, 0xA60C,
- 0xA610, 0xA61F,
- 0xA62A, 0xA62B,
- 0xA640, 0xA66E,
- 0xA674, 0xA67B,
- 0xA67F, 0xA6EF,
- 0xA717, 0xA71F,
- 0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
- 0xA807, 0xA827,
- 0xA840, 0xA873,
- 0xA880, 0xA8C3,
- 0xA8C5, 0xA8C5,
- 0xA8F2, 0xA8F7,
- 0xA8FB, 0xA8FB,
- 0xA8FD, 0xA8FF,
- 0xA90A, 0xA92A,
- 0xA930, 0xA952,
- 0xA960, 0xA97C,
- 0xA980, 0xA9B2,
- 0xA9B4, 0xA9BF,
- 0xA9CF, 0xA9CF,
- 0xA9E0, 0xA9EF,
- 0xA9FA, 0xA9FE,
- 0xAA00, 0xAA36,
- 0xAA40, 0xAA4D,
- 0xAA60, 0xAA76,
- 0xAA7A, 0xAABE,
- 0xAAC0, 0xAAC0,
- 0xAAC2, 0xAAC2,
- 0xAADB, 0xAADD,
- 0xAAE0, 0xAAEF,
- 0xAAF2, 0xAAF5,
- 0xAB01, 0xAB06,
- 0xAB09, 0xAB0E,
- 0xAB11, 0xAB16,
- 0xAB20, 0xAB26,
- 0xAB28, 0xAB2E,
- 0xAB30, 0xAB5A,
- 0xAB5C, 0xAB69,
- 0xAB70, 0xABEA,
- 0xAC00, 0xD7A3,
- 0xD7B0, 0xD7C6,
- 0xD7CB, 0xD7FB,
- 0xF900, 0xFA6D,
- 0xFA70, 0xFAD9,
- 0xFB00, 0xFB06,
- 0xFB13, 0xFB17,
- 0xFB1D, 0xFB28,
- 0xFB2A, 0xFB36,
- 0xFB38, 0xFB3C,
- 0xFB3E, 0xFB3E,
- 0xFB40, 0xFB41,
- 0xFB43, 0xFB44,
- 0xFB46, 0xFBB1,
- 0xFBD3, 0xFD3D,
- 0xFD50, 0xFD8F,
- 0xFD92, 0xFDC7,
- 0xFDF0, 0xFDFB,
- 0xFE70, 0xFE74,
- 0xFE76, 0xFEFC,
- 0xFF21, 0xFF3A,
- 0xFF41, 0xFF5A,
- 0xFF66, 0xFFBE,
- 0xFFC2, 0xFFC7,
- 0xFFCA, 0xFFCF,
- 0xFFD2, 0xFFD7,
- 0xFFDA, 0xFFDC,
- 0x10000, 0x1000B,
- 0x1000D, 0x10026,
- 0x10028, 0x1003A,
- 0x1003C, 0x1003D,
- 0x1003F, 0x1004D,
- 0x10050, 0x1005D,
- 0x10080, 0x100FA,
- 0x10140, 0x10174,
- 0x10280, 0x1029C,
- 0x102A0, 0x102D0,
- 0x10300, 0x1031F,
- 0x1032D, 0x1034A,
- 0x10350, 0x1037A,
- 0x10380, 0x1039D,
- 0x103A0, 0x103C3,
- 0x103C8, 0x103CF,
- 0x103D1, 0x103D5,
- 0x10400, 0x1049D,
- 0x104B0, 0x104D3,
- 0x104D8, 0x104FB,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x10570, 0x1057A,
- 0x1057C, 0x1058A,
- 0x1058C, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105A1,
- 0x105A3, 0x105B1,
- 0x105B3, 0x105B9,
- 0x105BB, 0x105BC,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107B0,
- 0x107B2, 0x107BA,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080A, 0x10835,
- 0x10837, 0x10838,
- 0x1083C, 0x1083C,
- 0x1083F, 0x10855,
- 0x10860, 0x10876,
- 0x10880, 0x1089E,
- 0x108E0, 0x108F2,
- 0x108F4, 0x108F5,
- 0x10900, 0x10915,
- 0x10920, 0x10939,
- 0x10980, 0x109B7,
- 0x109BE, 0x109BF,
- 0x10A00, 0x10A03,
- 0x10A05, 0x10A06,
- 0x10A0C, 0x10A13,
- 0x10A15, 0x10A17,
- 0x10A19, 0x10A35,
- 0x10A60, 0x10A7C,
- 0x10A80, 0x10A9C,
- 0x10AC0, 0x10AC7,
- 0x10AC9, 0x10AE4,
- 0x10B00, 0x10B35,
- 0x10B40, 0x10B55,
- 0x10B60, 0x10B72,
- 0x10B80, 0x10B91,
- 0x10C00, 0x10C48,
- 0x10C80, 0x10CB2,
- 0x10CC0, 0x10CF2,
- 0x10D00, 0x10D27,
- 0x10E80, 0x10EA9,
- 0x10EAB, 0x10EAC,
- 0x10EB0, 0x10EB1,
- 0x10F00, 0x10F1C,
- 0x10F27, 0x10F27,
- 0x10F30, 0x10F45,
- 0x10F70, 0x10F81,
- 0x10FB0, 0x10FC4,
- 0x10FE0, 0x10FF6,
- 0x11000, 0x11045,
- 0x11071, 0x11075,
- 0x11080, 0x110B8,
- 0x110C2, 0x110C2,
- 0x110D0, 0x110E8,
- 0x11100, 0x11132,
- 0x11144, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11180, 0x111BF,
- 0x111C1, 0x111C4,
- 0x111CE, 0x111CF,
- 0x111DA, 0x111DA,
- 0x111DC, 0x111DC,
- 0x11200, 0x11211,
- 0x11213, 0x11234,
- 0x11237, 0x11237,
- 0x1123E, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128A, 0x1128D,
- 0x1128F, 0x1129D,
- 0x1129F, 0x112A8,
- 0x112B0, 0x112E8,
- 0x11300, 0x11303,
- 0x11305, 0x1130C,
- 0x1130F, 0x11310,
- 0x11313, 0x11328,
- 0x1132A, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133D, 0x11344,
- 0x11347, 0x11348,
- 0x1134B, 0x1134C,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135D, 0x11363,
- 0x11400, 0x11441,
- 0x11443, 0x11445,
- 0x11447, 0x1144A,
- 0x1145F, 0x11461,
- 0x11480, 0x114C1,
- 0x114C4, 0x114C5,
- 0x114C7, 0x114C7,
- 0x11580, 0x115B5,
- 0x115B8, 0x115BE,
- 0x115D8, 0x115DD,
- 0x11600, 0x1163E,
- 0x11640, 0x11640,
- 0x11644, 0x11644,
- 0x11680, 0x116B5,
- 0x116B8, 0x116B8,
- 0x11700, 0x1171A,
- 0x1171D, 0x1172A,
- 0x11740, 0x11746,
- 0x11800, 0x11838,
- 0x118A0, 0x118DF,
- 0x118FF, 0x11906,
- 0x11909, 0x11909,
- 0x1190C, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193B, 0x1193C,
- 0x1193F, 0x11942,
- 0x119A0, 0x119A7,
- 0x119AA, 0x119D7,
- 0x119DA, 0x119DF,
- 0x119E1, 0x119E1,
- 0x119E3, 0x119E4,
- 0x11A00, 0x11A32,
- 0x11A35, 0x11A3E,
- 0x11A50, 0x11A97,
- 0x11A9D, 0x11A9D,
- 0x11AB0, 0x11AF8,
- 0x11C00, 0x11C08,
- 0x11C0A, 0x11C36,
- 0x11C38, 0x11C3E,
- 0x11C40, 0x11C40,
- 0x11C72, 0x11C8F,
- 0x11C92, 0x11CA7,
- 0x11CA9, 0x11CB6,
- 0x11D00, 0x11D06,
- 0x11D08, 0x11D09,
- 0x11D0B, 0x11D36,
- 0x11D3A, 0x11D3A,
- 0x11D3C, 0x11D3D,
- 0x11D3F, 0x11D41,
- 0x11D43, 0x11D43,
- 0x11D46, 0x11D47,
- 0x11D60, 0x11D65,
- 0x11D67, 0x11D68,
- 0x11D6A, 0x11D8E,
- 0x11D90, 0x11D91,
- 0x11D93, 0x11D96,
- 0x11D98, 0x11D98,
- 0x11EE0, 0x11EF6,
- 0x11F00, 0x11F10,
- 0x11F12, 0x11F3A,
- 0x11F3E, 0x11F40,
- 0x11FB0, 0x11FB0,
- 0x12000, 0x12399,
- 0x12400, 0x1246E,
- 0x12480, 0x12543,
- 0x12F90, 0x12FF0,
- 0x13000, 0x1342F,
- 0x13441, 0x13446,
- 0x14400, 0x14646,
- 0x16800, 0x16A38,
- 0x16A40, 0x16A5E,
- 0x16A70, 0x16ABE,
- 0x16AD0, 0x16AED,
- 0x16B00, 0x16B2F,
- 0x16B40, 0x16B43,
- 0x16B63, 0x16B77,
- 0x16B7D, 0x16B8F,
- 0x16E40, 0x16E7F,
- 0x16F00, 0x16F4A,
- 0x16F4F, 0x16F87,
- 0x16F8F, 0x16F9F,
- 0x16FE0, 0x16FE1,
- 0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
- 0x1AFF0, 0x1AFF3,
- 0x1AFF5, 0x1AFFB,
- 0x1AFFD, 0x1AFFE,
- 0x1B000, 0x1B122,
- 0x1B132, 0x1B132,
- 0x1B150, 0x1B152,
- 0x1B155, 0x1B155,
- 0x1B164, 0x1B167,
- 0x1B170, 0x1B2FB,
- 0x1BC00, 0x1BC6A,
- 0x1BC70, 0x1BC7C,
- 0x1BC80, 0x1BC88,
- 0x1BC90, 0x1BC99,
- 0x1BC9E, 0x1BC9E,
- 0x1D400, 0x1D454,
- 0x1D456, 0x1D49C,
- 0x1D49E, 0x1D49F,
- 0x1D4A2, 0x1D4A2,
- 0x1D4A5, 0x1D4A6,
- 0x1D4A9, 0x1D4AC,
- 0x1D4AE, 0x1D4B9,
- 0x1D4BB, 0x1D4BB,
- 0x1D4BD, 0x1D4C3,
- 0x1D4C5, 0x1D505,
- 0x1D507, 0x1D50A,
- 0x1D50D, 0x1D514,
- 0x1D516, 0x1D51C,
- 0x1D51E, 0x1D539,
- 0x1D53B, 0x1D53E,
- 0x1D540, 0x1D544,
- 0x1D546, 0x1D546,
- 0x1D54A, 0x1D550,
- 0x1D552, 0x1D6A5,
- 0x1D6A8, 0x1D6C0,
- 0x1D6C2, 0x1D6DA,
- 0x1D6DC, 0x1D6FA,
- 0x1D6FC, 0x1D714,
- 0x1D716, 0x1D734,
- 0x1D736, 0x1D74E,
- 0x1D750, 0x1D76E,
- 0x1D770, 0x1D788,
- 0x1D78A, 0x1D7A8,
- 0x1D7AA, 0x1D7C2,
- 0x1D7C4, 0x1D7CB,
- 0x1DF00, 0x1DF1E,
- 0x1DF25, 0x1DF2A,
- 0x1E000, 0x1E006,
- 0x1E008, 0x1E018,
- 0x1E01B, 0x1E021,
- 0x1E023, 0x1E024,
- 0x1E026, 0x1E02A,
- 0x1E030, 0x1E06D,
- 0x1E08F, 0x1E08F,
- 0x1E100, 0x1E12C,
- 0x1E137, 0x1E13D,
- 0x1E14E, 0x1E14E,
- 0x1E290, 0x1E2AD,
- 0x1E2C0, 0x1E2EB,
- 0x1E4D0, 0x1E4EB,
- 0x1E7E0, 0x1E7E6,
- 0x1E7E8, 0x1E7EB,
- 0x1E7ED, 0x1E7EE,
- 0x1E7F0, 0x1E7FE,
- 0x1E800, 0x1E8C4,
- 0x1E900, 0x1E943,
- 0x1E947, 0x1E947,
- 0x1E94B, 0x1E94B,
- 0x1EE00, 0x1EE03,
- 0x1EE05, 0x1EE1F,
- 0x1EE21, 0x1EE22,
- 0x1EE24, 0x1EE24,
- 0x1EE27, 0x1EE27,
- 0x1EE29, 0x1EE32,
- 0x1EE34, 0x1EE37,
- 0x1EE39, 0x1EE39,
- 0x1EE3B, 0x1EE3B,
- 0x1EE42, 0x1EE42,
- 0x1EE47, 0x1EE47,
- 0x1EE49, 0x1EE49,
- 0x1EE4B, 0x1EE4B,
- 0x1EE4D, 0x1EE4F,
- 0x1EE51, 0x1EE52,
- 0x1EE54, 0x1EE54,
- 0x1EE57, 0x1EE57,
- 0x1EE59, 0x1EE59,
- 0x1EE5B, 0x1EE5B,
- 0x1EE5D, 0x1EE5D,
- 0x1EE5F, 0x1EE5F,
- 0x1EE61, 0x1EE62,
- 0x1EE64, 0x1EE64,
- 0x1EE67, 0x1EE6A,
- 0x1EE6C, 0x1EE72,
- 0x1EE74, 0x1EE77,
- 0x1EE79, 0x1EE7C,
- 0x1EE7E, 0x1EE7E,
- 0x1EE80, 0x1EE89,
- 0x1EE8B, 0x1EE9B,
- 0x1EEA1, 0x1EEA3,
- 0x1EEA5, 0x1EEA9,
- 0x1EEAB, 0x1EEBB,
- 0x1F130, 0x1F149,
- 0x1F150, 0x1F169,
- 0x1F170, 0x1F189,
- 0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
- 0x2CEB0, 0x2EBE0,
- 0x2F800, 0x2FA1D,
- 0x30000, 0x3134A,
- 0x31350, 0x323AF,
-};
-
-#define UNICODE_ALNUM_CODEPOINTS_LENGTH 1528
-static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = {
- 0x100, 0x2C1,
- 0x2C6, 0x2D1,
- 0x2E0, 0x2E4,
- 0x2EC, 0x2EC,
- 0x2EE, 0x2EE,
- 0x345, 0x345,
- 0x370, 0x374,
- 0x376, 0x377,
- 0x37A, 0x37D,
- 0x37F, 0x37F,
- 0x386, 0x386,
- 0x388, 0x38A,
- 0x38C, 0x38C,
- 0x38E, 0x3A1,
- 0x3A3, 0x3F5,
- 0x3F7, 0x481,
- 0x48A, 0x52F,
- 0x531, 0x556,
- 0x559, 0x559,
- 0x560, 0x588,
- 0x5B0, 0x5BD,
- 0x5BF, 0x5BF,
- 0x5C1, 0x5C2,
- 0x5C4, 0x5C5,
- 0x5C7, 0x5C7,
- 0x5D0, 0x5EA,
- 0x5EF, 0x5F2,
- 0x610, 0x61A,
- 0x620, 0x657,
- 0x659, 0x669,
- 0x66E, 0x6D3,
- 0x6D5, 0x6DC,
- 0x6E1, 0x6E8,
- 0x6ED, 0x6FC,
- 0x6FF, 0x6FF,
- 0x710, 0x73F,
- 0x74D, 0x7B1,
- 0x7C0, 0x7EA,
- 0x7F4, 0x7F5,
- 0x7FA, 0x7FA,
- 0x800, 0x817,
- 0x81A, 0x82C,
- 0x840, 0x858,
- 0x860, 0x86A,
- 0x870, 0x887,
- 0x889, 0x88E,
- 0x8A0, 0x8C9,
- 0x8D4, 0x8DF,
- 0x8E3, 0x8E9,
- 0x8F0, 0x93B,
- 0x93D, 0x94C,
- 0x94E, 0x950,
- 0x955, 0x963,
- 0x966, 0x96F,
- 0x971, 0x983,
- 0x985, 0x98C,
- 0x98F, 0x990,
- 0x993, 0x9A8,
- 0x9AA, 0x9B0,
- 0x9B2, 0x9B2,
- 0x9B6, 0x9B9,
- 0x9BD, 0x9C4,
- 0x9C7, 0x9C8,
- 0x9CB, 0x9CC,
- 0x9CE, 0x9CE,
- 0x9D7, 0x9D7,
- 0x9DC, 0x9DD,
- 0x9DF, 0x9E3,
- 0x9E6, 0x9F1,
- 0x9FC, 0x9FC,
- 0xA01, 0xA03,
- 0xA05, 0xA0A,
- 0xA0F, 0xA10,
- 0xA13, 0xA28,
- 0xA2A, 0xA30,
- 0xA32, 0xA33,
- 0xA35, 0xA36,
- 0xA38, 0xA39,
- 0xA3E, 0xA42,
- 0xA47, 0xA48,
- 0xA4B, 0xA4C,
- 0xA51, 0xA51,
- 0xA59, 0xA5C,
- 0xA5E, 0xA5E,
- 0xA66, 0xA75,
- 0xA81, 0xA83,
- 0xA85, 0xA8D,
- 0xA8F, 0xA91,
- 0xA93, 0xAA8,
- 0xAAA, 0xAB0,
- 0xAB2, 0xAB3,
- 0xAB5, 0xAB9,
- 0xABD, 0xAC5,
- 0xAC7, 0xAC9,
- 0xACB, 0xACC,
- 0xAD0, 0xAD0,
- 0xAE0, 0xAE3,
- 0xAE6, 0xAEF,
- 0xAF9, 0xAFC,
- 0xB01, 0xB03,
- 0xB05, 0xB0C,
- 0xB0F, 0xB10,
- 0xB13, 0xB28,
- 0xB2A, 0xB30,
- 0xB32, 0xB33,
- 0xB35, 0xB39,
- 0xB3D, 0xB44,
- 0xB47, 0xB48,
- 0xB4B, 0xB4C,
- 0xB56, 0xB57,
- 0xB5C, 0xB5D,
- 0xB5F, 0xB63,
- 0xB66, 0xB6F,
- 0xB71, 0xB71,
- 0xB82, 0xB83,
- 0xB85, 0xB8A,
- 0xB8E, 0xB90,
- 0xB92, 0xB95,
- 0xB99, 0xB9A,
- 0xB9C, 0xB9C,
- 0xB9E, 0xB9F,
- 0xBA3, 0xBA4,
- 0xBA8, 0xBAA,
- 0xBAE, 0xBB9,
- 0xBBE, 0xBC2,
- 0xBC6, 0xBC8,
- 0xBCA, 0xBCC,
- 0xBD0, 0xBD0,
- 0xBD7, 0xBD7,
- 0xBE6, 0xBEF,
- 0xC00, 0xC0C,
- 0xC0E, 0xC10,
- 0xC12, 0xC28,
- 0xC2A, 0xC39,
- 0xC3D, 0xC44,
- 0xC46, 0xC48,
- 0xC4A, 0xC4C,
- 0xC55, 0xC56,
- 0xC58, 0xC5A,
- 0xC5D, 0xC5D,
- 0xC60, 0xC63,
- 0xC66, 0xC6F,
- 0xC80, 0xC83,
- 0xC85, 0xC8C,
- 0xC8E, 0xC90,
- 0xC92, 0xCA8,
- 0xCAA, 0xCB3,
- 0xCB5, 0xCB9,
- 0xCBD, 0xCC4,
- 0xCC6, 0xCC8,
- 0xCCA, 0xCCC,
- 0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
- 0xCE0, 0xCE3,
- 0xCE6, 0xCEF,
- 0xCF1, 0xCF3,
- 0xD00, 0xD0C,
- 0xD0E, 0xD10,
- 0xD12, 0xD3A,
- 0xD3D, 0xD44,
- 0xD46, 0xD48,
- 0xD4A, 0xD4C,
- 0xD4E, 0xD4E,
- 0xD54, 0xD57,
- 0xD5F, 0xD63,
- 0xD66, 0xD6F,
- 0xD7A, 0xD7F,
- 0xD81, 0xD83,
- 0xD85, 0xD96,
- 0xD9A, 0xDB1,
- 0xDB3, 0xDBB,
- 0xDBD, 0xDBD,
- 0xDC0, 0xDC6,
- 0xDCF, 0xDD4,
- 0xDD6, 0xDD6,
- 0xDD8, 0xDDF,
- 0xDE6, 0xDEF,
- 0xDF2, 0xDF3,
- 0xE01, 0xE3A,
- 0xE40, 0xE46,
- 0xE4D, 0xE4D,
- 0xE50, 0xE59,
- 0xE81, 0xE82,
- 0xE84, 0xE84,
- 0xE86, 0xE8A,
- 0xE8C, 0xEA3,
- 0xEA5, 0xEA5,
- 0xEA7, 0xEB9,
- 0xEBB, 0xEBD,
- 0xEC0, 0xEC4,
- 0xEC6, 0xEC6,
- 0xECD, 0xECD,
- 0xED0, 0xED9,
- 0xEDC, 0xEDF,
- 0xF00, 0xF00,
- 0xF20, 0xF29,
- 0xF40, 0xF47,
- 0xF49, 0xF6C,
- 0xF71, 0xF83,
- 0xF88, 0xF97,
- 0xF99, 0xFBC,
- 0x1000, 0x1036,
- 0x1038, 0x1038,
- 0x103B, 0x1049,
- 0x1050, 0x109D,
- 0x10A0, 0x10C5,
- 0x10C7, 0x10C7,
- 0x10CD, 0x10CD,
- 0x10D0, 0x10FA,
- 0x10FC, 0x1248,
- 0x124A, 0x124D,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125A, 0x125D,
- 0x1260, 0x1288,
- 0x128A, 0x128D,
- 0x1290, 0x12B0,
- 0x12B2, 0x12B5,
- 0x12B8, 0x12BE,
- 0x12C0, 0x12C0,
- 0x12C2, 0x12C5,
- 0x12C8, 0x12D6,
- 0x12D8, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x135A,
- 0x1380, 0x138F,
- 0x13A0, 0x13F5,
- 0x13F8, 0x13FD,
- 0x1401, 0x166C,
- 0x166F, 0x167F,
- 0x1681, 0x169A,
- 0x16A0, 0x16EA,
- 0x16EE, 0x16F8,
- 0x1700, 0x1713,
- 0x171F, 0x1733,
- 0x1740, 0x1753,
- 0x1760, 0x176C,
- 0x176E, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17B3,
- 0x17B6, 0x17C8,
- 0x17D7, 0x17D7,
- 0x17DC, 0x17DC,
- 0x17E0, 0x17E9,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18AA,
- 0x18B0, 0x18F5,
- 0x1900, 0x191E,
- 0x1920, 0x192B,
- 0x1930, 0x1938,
- 0x1946, 0x196D,
- 0x1970, 0x1974,
- 0x1980, 0x19AB,
- 0x19B0, 0x19C9,
- 0x19D0, 0x19D9,
- 0x1A00, 0x1A1B,
- 0x1A20, 0x1A5E,
- 0x1A61, 0x1A74,
- 0x1A80, 0x1A89,
- 0x1A90, 0x1A99,
- 0x1AA7, 0x1AA7,
- 0x1ABF, 0x1AC0,
- 0x1ACC, 0x1ACE,
- 0x1B00, 0x1B33,
- 0x1B35, 0x1B43,
- 0x1B45, 0x1B4C,
- 0x1B50, 0x1B59,
- 0x1B80, 0x1BA9,
- 0x1BAC, 0x1BE5,
- 0x1BE7, 0x1BF1,
- 0x1C00, 0x1C36,
- 0x1C40, 0x1C49,
- 0x1C4D, 0x1C7D,
- 0x1C80, 0x1C88,
- 0x1C90, 0x1CBA,
- 0x1CBD, 0x1CBF,
- 0x1CE9, 0x1CEC,
- 0x1CEE, 0x1CF3,
- 0x1CF5, 0x1CF6,
- 0x1CFA, 0x1CFA,
- 0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
- 0x1E00, 0x1F15,
- 0x1F18, 0x1F1D,
- 0x1F20, 0x1F45,
- 0x1F48, 0x1F4D,
- 0x1F50, 0x1F57,
- 0x1F59, 0x1F59,
- 0x1F5B, 0x1F5B,
- 0x1F5D, 0x1F5D,
- 0x1F5F, 0x1F7D,
- 0x1F80, 0x1FB4,
- 0x1FB6, 0x1FBC,
- 0x1FBE, 0x1FBE,
- 0x1FC2, 0x1FC4,
- 0x1FC6, 0x1FCC,
- 0x1FD0, 0x1FD3,
- 0x1FD6, 0x1FDB,
- 0x1FE0, 0x1FEC,
- 0x1FF2, 0x1FF4,
- 0x1FF6, 0x1FFC,
- 0x2071, 0x2071,
- 0x207F, 0x207F,
- 0x2090, 0x209C,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210A, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211D,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212A, 0x212D,
- 0x212F, 0x2139,
- 0x213C, 0x213F,
- 0x2145, 0x2149,
- 0x214E, 0x214E,
- 0x2160, 0x2188,
- 0x24B6, 0x24E9,
- 0x2C00, 0x2CE4,
- 0x2CEB, 0x2CEE,
- 0x2CF2, 0x2CF3,
- 0x2D00, 0x2D25,
- 0x2D27, 0x2D27,
- 0x2D2D, 0x2D2D,
- 0x2D30, 0x2D67,
- 0x2D6F, 0x2D6F,
- 0x2D80, 0x2D96,
- 0x2DA0, 0x2DA6,
- 0x2DA8, 0x2DAE,
- 0x2DB0, 0x2DB6,
- 0x2DB8, 0x2DBE,
- 0x2DC0, 0x2DC6,
- 0x2DC8, 0x2DCE,
- 0x2DD0, 0x2DD6,
- 0x2DD8, 0x2DDE,
- 0x2DE0, 0x2DFF,
- 0x2E2F, 0x2E2F,
- 0x3005, 0x3007,
- 0x3021, 0x3029,
- 0x3031, 0x3035,
- 0x3038, 0x303C,
- 0x3041, 0x3096,
- 0x309D, 0x309F,
- 0x30A1, 0x30FA,
- 0x30FC, 0x30FF,
- 0x3105, 0x312F,
- 0x3131, 0x318E,
- 0x31A0, 0x31BF,
- 0x31F0, 0x31FF,
- 0x3400, 0x4DBF,
- 0x4E00, 0xA48C,
- 0xA4D0, 0xA4FD,
- 0xA500, 0xA60C,
- 0xA610, 0xA62B,
- 0xA640, 0xA66E,
- 0xA674, 0xA67B,
- 0xA67F, 0xA6EF,
- 0xA717, 0xA71F,
- 0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
- 0xA807, 0xA827,
- 0xA840, 0xA873,
- 0xA880, 0xA8C3,
- 0xA8C5, 0xA8C5,
- 0xA8D0, 0xA8D9,
- 0xA8F2, 0xA8F7,
- 0xA8FB, 0xA8FB,
- 0xA8FD, 0xA92A,
- 0xA930, 0xA952,
- 0xA960, 0xA97C,
- 0xA980, 0xA9B2,
- 0xA9B4, 0xA9BF,
- 0xA9CF, 0xA9D9,
- 0xA9E0, 0xA9FE,
- 0xAA00, 0xAA36,
- 0xAA40, 0xAA4D,
- 0xAA50, 0xAA59,
- 0xAA60, 0xAA76,
- 0xAA7A, 0xAABE,
- 0xAAC0, 0xAAC0,
- 0xAAC2, 0xAAC2,
- 0xAADB, 0xAADD,
- 0xAAE0, 0xAAEF,
- 0xAAF2, 0xAAF5,
- 0xAB01, 0xAB06,
- 0xAB09, 0xAB0E,
- 0xAB11, 0xAB16,
- 0xAB20, 0xAB26,
- 0xAB28, 0xAB2E,
- 0xAB30, 0xAB5A,
- 0xAB5C, 0xAB69,
- 0xAB70, 0xABEA,
- 0xABF0, 0xABF9,
- 0xAC00, 0xD7A3,
- 0xD7B0, 0xD7C6,
- 0xD7CB, 0xD7FB,
- 0xF900, 0xFA6D,
- 0xFA70, 0xFAD9,
- 0xFB00, 0xFB06,
- 0xFB13, 0xFB17,
- 0xFB1D, 0xFB28,
- 0xFB2A, 0xFB36,
- 0xFB38, 0xFB3C,
- 0xFB3E, 0xFB3E,
- 0xFB40, 0xFB41,
- 0xFB43, 0xFB44,
- 0xFB46, 0xFBB1,
- 0xFBD3, 0xFD3D,
- 0xFD50, 0xFD8F,
- 0xFD92, 0xFDC7,
- 0xFDF0, 0xFDFB,
- 0xFE70, 0xFE74,
- 0xFE76, 0xFEFC,
- 0xFF10, 0xFF19,
- 0xFF21, 0xFF3A,
- 0xFF41, 0xFF5A,
- 0xFF66, 0xFFBE,
- 0xFFC2, 0xFFC7,
- 0xFFCA, 0xFFCF,
- 0xFFD2, 0xFFD7,
- 0xFFDA, 0xFFDC,
- 0x10000, 0x1000B,
- 0x1000D, 0x10026,
- 0x10028, 0x1003A,
- 0x1003C, 0x1003D,
- 0x1003F, 0x1004D,
- 0x10050, 0x1005D,
- 0x10080, 0x100FA,
- 0x10140, 0x10174,
- 0x10280, 0x1029C,
- 0x102A0, 0x102D0,
- 0x10300, 0x1031F,
- 0x1032D, 0x1034A,
- 0x10350, 0x1037A,
- 0x10380, 0x1039D,
- 0x103A0, 0x103C3,
- 0x103C8, 0x103CF,
- 0x103D1, 0x103D5,
- 0x10400, 0x1049D,
- 0x104A0, 0x104A9,
- 0x104B0, 0x104D3,
- 0x104D8, 0x104FB,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x10570, 0x1057A,
- 0x1057C, 0x1058A,
- 0x1058C, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105A1,
- 0x105A3, 0x105B1,
- 0x105B3, 0x105B9,
- 0x105BB, 0x105BC,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107B0,
- 0x107B2, 0x107BA,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080A, 0x10835,
- 0x10837, 0x10838,
- 0x1083C, 0x1083C,
- 0x1083F, 0x10855,
- 0x10860, 0x10876,
- 0x10880, 0x1089E,
- 0x108E0, 0x108F2,
- 0x108F4, 0x108F5,
- 0x10900, 0x10915,
- 0x10920, 0x10939,
- 0x10980, 0x109B7,
- 0x109BE, 0x109BF,
- 0x10A00, 0x10A03,
- 0x10A05, 0x10A06,
- 0x10A0C, 0x10A13,
- 0x10A15, 0x10A17,
- 0x10A19, 0x10A35,
- 0x10A60, 0x10A7C,
- 0x10A80, 0x10A9C,
- 0x10AC0, 0x10AC7,
- 0x10AC9, 0x10AE4,
- 0x10B00, 0x10B35,
- 0x10B40, 0x10B55,
- 0x10B60, 0x10B72,
- 0x10B80, 0x10B91,
- 0x10C00, 0x10C48,
- 0x10C80, 0x10CB2,
- 0x10CC0, 0x10CF2,
- 0x10D00, 0x10D27,
- 0x10D30, 0x10D39,
- 0x10E80, 0x10EA9,
- 0x10EAB, 0x10EAC,
- 0x10EB0, 0x10EB1,
- 0x10F00, 0x10F1C,
- 0x10F27, 0x10F27,
- 0x10F30, 0x10F45,
- 0x10F70, 0x10F81,
- 0x10FB0, 0x10FC4,
- 0x10FE0, 0x10FF6,
- 0x11000, 0x11045,
- 0x11066, 0x1106F,
- 0x11071, 0x11075,
- 0x11080, 0x110B8,
- 0x110C2, 0x110C2,
- 0x110D0, 0x110E8,
- 0x110F0, 0x110F9,
- 0x11100, 0x11132,
- 0x11136, 0x1113F,
- 0x11144, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11180, 0x111BF,
- 0x111C1, 0x111C4,
- 0x111CE, 0x111DA,
- 0x111DC, 0x111DC,
- 0x11200, 0x11211,
- 0x11213, 0x11234,
- 0x11237, 0x11237,
- 0x1123E, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128A, 0x1128D,
- 0x1128F, 0x1129D,
- 0x1129F, 0x112A8,
- 0x112B0, 0x112E8,
- 0x112F0, 0x112F9,
- 0x11300, 0x11303,
- 0x11305, 0x1130C,
- 0x1130F, 0x11310,
- 0x11313, 0x11328,
- 0x1132A, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133D, 0x11344,
- 0x11347, 0x11348,
- 0x1134B, 0x1134C,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135D, 0x11363,
- 0x11400, 0x11441,
- 0x11443, 0x11445,
- 0x11447, 0x1144A,
- 0x11450, 0x11459,
- 0x1145F, 0x11461,
- 0x11480, 0x114C1,
- 0x114C4, 0x114C5,
- 0x114C7, 0x114C7,
- 0x114D0, 0x114D9,
- 0x11580, 0x115B5,
- 0x115B8, 0x115BE,
- 0x115D8, 0x115DD,
- 0x11600, 0x1163E,
- 0x11640, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116B5,
- 0x116B8, 0x116B8,
- 0x116C0, 0x116C9,
- 0x11700, 0x1171A,
- 0x1171D, 0x1172A,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x11838,
- 0x118A0, 0x118E9,
- 0x118FF, 0x11906,
- 0x11909, 0x11909,
- 0x1190C, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193B, 0x1193C,
- 0x1193F, 0x11942,
- 0x11950, 0x11959,
- 0x119A0, 0x119A7,
- 0x119AA, 0x119D7,
- 0x119DA, 0x119DF,
- 0x119E1, 0x119E1,
- 0x119E3, 0x119E4,
- 0x11A00, 0x11A32,
- 0x11A35, 0x11A3E,
- 0x11A50, 0x11A97,
- 0x11A9D, 0x11A9D,
- 0x11AB0, 0x11AF8,
- 0x11C00, 0x11C08,
- 0x11C0A, 0x11C36,
- 0x11C38, 0x11C3E,
- 0x11C40, 0x11C40,
- 0x11C50, 0x11C59,
- 0x11C72, 0x11C8F,
- 0x11C92, 0x11CA7,
- 0x11CA9, 0x11CB6,
- 0x11D00, 0x11D06,
- 0x11D08, 0x11D09,
- 0x11D0B, 0x11D36,
- 0x11D3A, 0x11D3A,
- 0x11D3C, 0x11D3D,
- 0x11D3F, 0x11D41,
- 0x11D43, 0x11D43,
- 0x11D46, 0x11D47,
- 0x11D50, 0x11D59,
- 0x11D60, 0x11D65,
- 0x11D67, 0x11D68,
- 0x11D6A, 0x11D8E,
- 0x11D90, 0x11D91,
- 0x11D93, 0x11D96,
- 0x11D98, 0x11D98,
- 0x11DA0, 0x11DA9,
- 0x11EE0, 0x11EF6,
- 0x11F00, 0x11F10,
- 0x11F12, 0x11F3A,
- 0x11F3E, 0x11F40,
- 0x11F50, 0x11F59,
- 0x11FB0, 0x11FB0,
- 0x12000, 0x12399,
- 0x12400, 0x1246E,
- 0x12480, 0x12543,
- 0x12F90, 0x12FF0,
- 0x13000, 0x1342F,
- 0x13441, 0x13446,
- 0x14400, 0x14646,
- 0x16800, 0x16A38,
- 0x16A40, 0x16A5E,
- 0x16A60, 0x16A69,
- 0x16A70, 0x16ABE,
- 0x16AC0, 0x16AC9,
- 0x16AD0, 0x16AED,
- 0x16B00, 0x16B2F,
- 0x16B40, 0x16B43,
- 0x16B50, 0x16B59,
- 0x16B63, 0x16B77,
- 0x16B7D, 0x16B8F,
- 0x16E40, 0x16E7F,
- 0x16F00, 0x16F4A,
- 0x16F4F, 0x16F87,
- 0x16F8F, 0x16F9F,
- 0x16FE0, 0x16FE1,
- 0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
- 0x1AFF0, 0x1AFF3,
- 0x1AFF5, 0x1AFFB,
- 0x1AFFD, 0x1AFFE,
- 0x1B000, 0x1B122,
- 0x1B132, 0x1B132,
- 0x1B150, 0x1B152,
- 0x1B155, 0x1B155,
- 0x1B164, 0x1B167,
- 0x1B170, 0x1B2FB,
- 0x1BC00, 0x1BC6A,
- 0x1BC70, 0x1BC7C,
- 0x1BC80, 0x1BC88,
- 0x1BC90, 0x1BC99,
- 0x1BC9E, 0x1BC9E,
- 0x1D400, 0x1D454,
- 0x1D456, 0x1D49C,
- 0x1D49E, 0x1D49F,
- 0x1D4A2, 0x1D4A2,
- 0x1D4A5, 0x1D4A6,
- 0x1D4A9, 0x1D4AC,
- 0x1D4AE, 0x1D4B9,
- 0x1D4BB, 0x1D4BB,
- 0x1D4BD, 0x1D4C3,
- 0x1D4C5, 0x1D505,
- 0x1D507, 0x1D50A,
- 0x1D50D, 0x1D514,
- 0x1D516, 0x1D51C,
- 0x1D51E, 0x1D539,
- 0x1D53B, 0x1D53E,
- 0x1D540, 0x1D544,
- 0x1D546, 0x1D546,
- 0x1D54A, 0x1D550,
- 0x1D552, 0x1D6A5,
- 0x1D6A8, 0x1D6C0,
- 0x1D6C2, 0x1D6DA,
- 0x1D6DC, 0x1D6FA,
- 0x1D6FC, 0x1D714,
- 0x1D716, 0x1D734,
- 0x1D736, 0x1D74E,
- 0x1D750, 0x1D76E,
- 0x1D770, 0x1D788,
- 0x1D78A, 0x1D7A8,
- 0x1D7AA, 0x1D7C2,
- 0x1D7C4, 0x1D7CB,
- 0x1D7CE, 0x1D7FF,
- 0x1DF00, 0x1DF1E,
- 0x1DF25, 0x1DF2A,
- 0x1E000, 0x1E006,
- 0x1E008, 0x1E018,
- 0x1E01B, 0x1E021,
- 0x1E023, 0x1E024,
- 0x1E026, 0x1E02A,
- 0x1E030, 0x1E06D,
- 0x1E08F, 0x1E08F,
- 0x1E100, 0x1E12C,
- 0x1E137, 0x1E13D,
- 0x1E140, 0x1E149,
- 0x1E14E, 0x1E14E,
- 0x1E290, 0x1E2AD,
- 0x1E2C0, 0x1E2EB,
- 0x1E2F0, 0x1E2F9,
- 0x1E4D0, 0x1E4EB,
- 0x1E4F0, 0x1E4F9,
- 0x1E7E0, 0x1E7E6,
- 0x1E7E8, 0x1E7EB,
- 0x1E7ED, 0x1E7EE,
- 0x1E7F0, 0x1E7FE,
- 0x1E800, 0x1E8C4,
- 0x1E900, 0x1E943,
- 0x1E947, 0x1E947,
- 0x1E94B, 0x1E94B,
- 0x1E950, 0x1E959,
- 0x1EE00, 0x1EE03,
- 0x1EE05, 0x1EE1F,
- 0x1EE21, 0x1EE22,
- 0x1EE24, 0x1EE24,
- 0x1EE27, 0x1EE27,
- 0x1EE29, 0x1EE32,
- 0x1EE34, 0x1EE37,
- 0x1EE39, 0x1EE39,
- 0x1EE3B, 0x1EE3B,
- 0x1EE42, 0x1EE42,
- 0x1EE47, 0x1EE47,
- 0x1EE49, 0x1EE49,
- 0x1EE4B, 0x1EE4B,
- 0x1EE4D, 0x1EE4F,
- 0x1EE51, 0x1EE52,
- 0x1EE54, 0x1EE54,
- 0x1EE57, 0x1EE57,
- 0x1EE59, 0x1EE59,
- 0x1EE5B, 0x1EE5B,
- 0x1EE5D, 0x1EE5D,
- 0x1EE5F, 0x1EE5F,
- 0x1EE61, 0x1EE62,
- 0x1EE64, 0x1EE64,
- 0x1EE67, 0x1EE6A,
- 0x1EE6C, 0x1EE72,
- 0x1EE74, 0x1EE77,
- 0x1EE79, 0x1EE7C,
- 0x1EE7E, 0x1EE7E,
- 0x1EE80, 0x1EE89,
- 0x1EE8B, 0x1EE9B,
- 0x1EEA1, 0x1EEA3,
- 0x1EEA5, 0x1EEA9,
- 0x1EEAB, 0x1EEBB,
- 0x1F130, 0x1F149,
- 0x1F150, 0x1F169,
- 0x1F170, 0x1F189,
- 0x1FBF0, 0x1FBF9,
- 0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
- 0x2CEB0, 0x2EBE0,
- 0x2F800, 0x2FA1D,
- 0x30000, 0x3134A,
- 0x31350, 0x323AF,
-};
-
-#define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1296
-static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = {
- 0x100, 0x100,
- 0x102, 0x102,
- 0x104, 0x104,
- 0x106, 0x106,
- 0x108, 0x108,
- 0x10A, 0x10A,
- 0x10C, 0x10C,
- 0x10E, 0x10E,
- 0x110, 0x110,
- 0x112, 0x112,
- 0x114, 0x114,
- 0x116, 0x116,
- 0x118, 0x118,
- 0x11A, 0x11A,
- 0x11C, 0x11C,
- 0x11E, 0x11E,
- 0x120, 0x120,
- 0x122, 0x122,
- 0x124, 0x124,
- 0x126, 0x126,
- 0x128, 0x128,
- 0x12A, 0x12A,
- 0x12C, 0x12C,
- 0x12E, 0x12E,
- 0x130, 0x130,
- 0x132, 0x132,
- 0x134, 0x134,
- 0x136, 0x136,
- 0x139, 0x139,
- 0x13B, 0x13B,
- 0x13D, 0x13D,
- 0x13F, 0x13F,
- 0x141, 0x141,
- 0x143, 0x143,
- 0x145, 0x145,
- 0x147, 0x147,
- 0x14A, 0x14A,
- 0x14C, 0x14C,
- 0x14E, 0x14E,
- 0x150, 0x150,
- 0x152, 0x152,
- 0x154, 0x154,
- 0x156, 0x156,
- 0x158, 0x158,
- 0x15A, 0x15A,
- 0x15C, 0x15C,
- 0x15E, 0x15E,
- 0x160, 0x160,
- 0x162, 0x162,
- 0x164, 0x164,
- 0x166, 0x166,
- 0x168, 0x168,
- 0x16A, 0x16A,
- 0x16C, 0x16C,
- 0x16E, 0x16E,
- 0x170, 0x170,
- 0x172, 0x172,
- 0x174, 0x174,
- 0x176, 0x176,
- 0x178, 0x179,
- 0x17B, 0x17B,
- 0x17D, 0x17D,
- 0x181, 0x182,
- 0x184, 0x184,
- 0x186, 0x187,
- 0x189, 0x18B,
- 0x18E, 0x191,
- 0x193, 0x194,
- 0x196, 0x198,
- 0x19C, 0x19D,
- 0x19F, 0x1A0,
- 0x1A2, 0x1A2,
- 0x1A4, 0x1A4,
- 0x1A6, 0x1A7,
- 0x1A9, 0x1A9,
- 0x1AC, 0x1AC,
- 0x1AE, 0x1AF,
- 0x1B1, 0x1B3,
- 0x1B5, 0x1B5,
- 0x1B7, 0x1B8,
- 0x1BC, 0x1BC,
- 0x1C4, 0x1C4,
- 0x1C7, 0x1C7,
- 0x1CA, 0x1CA,
- 0x1CD, 0x1CD,
- 0x1CF, 0x1CF,
- 0x1D1, 0x1D1,
- 0x1D3, 0x1D3,
- 0x1D5, 0x1D5,
- 0x1D7, 0x1D7,
- 0x1D9, 0x1D9,
- 0x1DB, 0x1DB,
- 0x1DE, 0x1DE,
- 0x1E0, 0x1E0,
- 0x1E2, 0x1E2,
- 0x1E4, 0x1E4,
- 0x1E6, 0x1E6,
- 0x1E8, 0x1E8,
- 0x1EA, 0x1EA,
- 0x1EC, 0x1EC,
- 0x1EE, 0x1EE,
- 0x1F1, 0x1F1,
- 0x1F4, 0x1F4,
- 0x1F6, 0x1F8,
- 0x1FA, 0x1FA,
- 0x1FC, 0x1FC,
- 0x1FE, 0x1FE,
- 0x200, 0x200,
- 0x202, 0x202,
- 0x204, 0x204,
- 0x206, 0x206,
- 0x208, 0x208,
- 0x20A, 0x20A,
- 0x20C, 0x20C,
- 0x20E, 0x20E,
- 0x210, 0x210,
- 0x212, 0x212,
- 0x214, 0x214,
- 0x216, 0x216,
- 0x218, 0x218,
- 0x21A, 0x21A,
- 0x21C, 0x21C,
- 0x21E, 0x21E,
- 0x220, 0x220,
- 0x222, 0x222,
- 0x224, 0x224,
- 0x226, 0x226,
- 0x228, 0x228,
- 0x22A, 0x22A,
- 0x22C, 0x22C,
- 0x22E, 0x22E,
- 0x230, 0x230,
- 0x232, 0x232,
- 0x23A, 0x23B,
- 0x23D, 0x23E,
- 0x241, 0x241,
- 0x243, 0x246,
- 0x248, 0x248,
- 0x24A, 0x24A,
- 0x24C, 0x24C,
- 0x24E, 0x24E,
- 0x370, 0x370,
- 0x372, 0x372,
- 0x376, 0x376,
- 0x37F, 0x37F,
- 0x386, 0x386,
- 0x388, 0x38A,
- 0x38C, 0x38C,
- 0x38E, 0x38F,
- 0x391, 0x3A1,
- 0x3A3, 0x3AB,
- 0x3CF, 0x3CF,
- 0x3D2, 0x3D4,
- 0x3D8, 0x3D8,
- 0x3DA, 0x3DA,
- 0x3DC, 0x3DC,
- 0x3DE, 0x3DE,
- 0x3E0, 0x3E0,
- 0x3E2, 0x3E2,
- 0x3E4, 0x3E4,
- 0x3E6, 0x3E6,
- 0x3E8, 0x3E8,
- 0x3EA, 0x3EA,
- 0x3EC, 0x3EC,
- 0x3EE, 0x3EE,
- 0x3F4, 0x3F4,
- 0x3F7, 0x3F7,
- 0x3F9, 0x3FA,
- 0x3FD, 0x42F,
- 0x460, 0x460,
- 0x462, 0x462,
- 0x464, 0x464,
- 0x466, 0x466,
- 0x468, 0x468,
- 0x46A, 0x46A,
- 0x46C, 0x46C,
- 0x46E, 0x46E,
- 0x470, 0x470,
- 0x472, 0x472,
- 0x474, 0x474,
- 0x476, 0x476,
- 0x478, 0x478,
- 0x47A, 0x47A,
- 0x47C, 0x47C,
- 0x47E, 0x47E,
- 0x480, 0x480,
- 0x48A, 0x48A,
- 0x48C, 0x48C,
- 0x48E, 0x48E,
- 0x490, 0x490,
- 0x492, 0x492,
- 0x494, 0x494,
- 0x496, 0x496,
- 0x498, 0x498,
- 0x49A, 0x49A,
- 0x49C, 0x49C,
- 0x49E, 0x49E,
- 0x4A0, 0x4A0,
- 0x4A2, 0x4A2,
- 0x4A4, 0x4A4,
- 0x4A6, 0x4A6,
- 0x4A8, 0x4A8,
- 0x4AA, 0x4AA,
- 0x4AC, 0x4AC,
- 0x4AE, 0x4AE,
- 0x4B0, 0x4B0,
- 0x4B2, 0x4B2,
- 0x4B4, 0x4B4,
- 0x4B6, 0x4B6,
- 0x4B8, 0x4B8,
- 0x4BA, 0x4BA,
- 0x4BC, 0x4BC,
- 0x4BE, 0x4BE,
- 0x4C0, 0x4C1,
- 0x4C3, 0x4C3,
- 0x4C5, 0x4C5,
- 0x4C7, 0x4C7,
- 0x4C9, 0x4C9,
- 0x4CB, 0x4CB,
- 0x4CD, 0x4CD,
- 0x4D0, 0x4D0,
- 0x4D2, 0x4D2,
- 0x4D4, 0x4D4,
- 0x4D6, 0x4D6,
- 0x4D8, 0x4D8,
- 0x4DA, 0x4DA,
- 0x4DC, 0x4DC,
- 0x4DE, 0x4DE,
- 0x4E0, 0x4E0,
- 0x4E2, 0x4E2,
- 0x4E4, 0x4E4,
- 0x4E6, 0x4E6,
- 0x4E8, 0x4E8,
- 0x4EA, 0x4EA,
- 0x4EC, 0x4EC,
- 0x4EE, 0x4EE,
- 0x4F0, 0x4F0,
- 0x4F2, 0x4F2,
- 0x4F4, 0x4F4,
- 0x4F6, 0x4F6,
- 0x4F8, 0x4F8,
- 0x4FA, 0x4FA,
- 0x4FC, 0x4FC,
- 0x4FE, 0x4FE,
- 0x500, 0x500,
- 0x502, 0x502,
- 0x504, 0x504,
- 0x506, 0x506,
- 0x508, 0x508,
- 0x50A, 0x50A,
- 0x50C, 0x50C,
- 0x50E, 0x50E,
- 0x510, 0x510,
- 0x512, 0x512,
- 0x514, 0x514,
- 0x516, 0x516,
- 0x518, 0x518,
- 0x51A, 0x51A,
- 0x51C, 0x51C,
- 0x51E, 0x51E,
- 0x520, 0x520,
- 0x522, 0x522,
- 0x524, 0x524,
- 0x526, 0x526,
- 0x528, 0x528,
- 0x52A, 0x52A,
- 0x52C, 0x52C,
- 0x52E, 0x52E,
- 0x531, 0x556,
- 0x10A0, 0x10C5,
- 0x10C7, 0x10C7,
- 0x10CD, 0x10CD,
- 0x13A0, 0x13F5,
- 0x1C90, 0x1CBA,
- 0x1CBD, 0x1CBF,
- 0x1E00, 0x1E00,
- 0x1E02, 0x1E02,
- 0x1E04, 0x1E04,
- 0x1E06, 0x1E06,
- 0x1E08, 0x1E08,
- 0x1E0A, 0x1E0A,
- 0x1E0C, 0x1E0C,
- 0x1E0E, 0x1E0E,
- 0x1E10, 0x1E10,
- 0x1E12, 0x1E12,
- 0x1E14, 0x1E14,
- 0x1E16, 0x1E16,
- 0x1E18, 0x1E18,
- 0x1E1A, 0x1E1A,
- 0x1E1C, 0x1E1C,
- 0x1E1E, 0x1E1E,
- 0x1E20, 0x1E20,
- 0x1E22, 0x1E22,
- 0x1E24, 0x1E24,
- 0x1E26, 0x1E26,
- 0x1E28, 0x1E28,
- 0x1E2A, 0x1E2A,
- 0x1E2C, 0x1E2C,
- 0x1E2E, 0x1E2E,
- 0x1E30, 0x1E30,
- 0x1E32, 0x1E32,
- 0x1E34, 0x1E34,
- 0x1E36, 0x1E36,
- 0x1E38, 0x1E38,
- 0x1E3A, 0x1E3A,
- 0x1E3C, 0x1E3C,
- 0x1E3E, 0x1E3E,
- 0x1E40, 0x1E40,
- 0x1E42, 0x1E42,
- 0x1E44, 0x1E44,
- 0x1E46, 0x1E46,
- 0x1E48, 0x1E48,
- 0x1E4A, 0x1E4A,
- 0x1E4C, 0x1E4C,
- 0x1E4E, 0x1E4E,
- 0x1E50, 0x1E50,
- 0x1E52, 0x1E52,
- 0x1E54, 0x1E54,
- 0x1E56, 0x1E56,
- 0x1E58, 0x1E58,
- 0x1E5A, 0x1E5A,
- 0x1E5C, 0x1E5C,
- 0x1E5E, 0x1E5E,
- 0x1E60, 0x1E60,
- 0x1E62, 0x1E62,
- 0x1E64, 0x1E64,
- 0x1E66, 0x1E66,
- 0x1E68, 0x1E68,
- 0x1E6A, 0x1E6A,
- 0x1E6C, 0x1E6C,
- 0x1E6E, 0x1E6E,
- 0x1E70, 0x1E70,
- 0x1E72, 0x1E72,
- 0x1E74, 0x1E74,
- 0x1E76, 0x1E76,
- 0x1E78, 0x1E78,
- 0x1E7A, 0x1E7A,
- 0x1E7C, 0x1E7C,
- 0x1E7E, 0x1E7E,
- 0x1E80, 0x1E80,
- 0x1E82, 0x1E82,
- 0x1E84, 0x1E84,
- 0x1E86, 0x1E86,
- 0x1E88, 0x1E88,
- 0x1E8A, 0x1E8A,
- 0x1E8C, 0x1E8C,
- 0x1E8E, 0x1E8E,
- 0x1E90, 0x1E90,
- 0x1E92, 0x1E92,
- 0x1E94, 0x1E94,
- 0x1E9E, 0x1E9E,
- 0x1EA0, 0x1EA0,
- 0x1EA2, 0x1EA2,
- 0x1EA4, 0x1EA4,
- 0x1EA6, 0x1EA6,
- 0x1EA8, 0x1EA8,
- 0x1EAA, 0x1EAA,
- 0x1EAC, 0x1EAC,
- 0x1EAE, 0x1EAE,
- 0x1EB0, 0x1EB0,
- 0x1EB2, 0x1EB2,
- 0x1EB4, 0x1EB4,
- 0x1EB6, 0x1EB6,
- 0x1EB8, 0x1EB8,
- 0x1EBA, 0x1EBA,
- 0x1EBC, 0x1EBC,
- 0x1EBE, 0x1EBE,
- 0x1EC0, 0x1EC0,
- 0x1EC2, 0x1EC2,
- 0x1EC4, 0x1EC4,
- 0x1EC6, 0x1EC6,
- 0x1EC8, 0x1EC8,
- 0x1ECA, 0x1ECA,
- 0x1ECC, 0x1ECC,
- 0x1ECE, 0x1ECE,
- 0x1ED0, 0x1ED0,
- 0x1ED2, 0x1ED2,
- 0x1ED4, 0x1ED4,
- 0x1ED6, 0x1ED6,
- 0x1ED8, 0x1ED8,
- 0x1EDA, 0x1EDA,
- 0x1EDC, 0x1EDC,
- 0x1EDE, 0x1EDE,
- 0x1EE0, 0x1EE0,
- 0x1EE2, 0x1EE2,
- 0x1EE4, 0x1EE4,
- 0x1EE6, 0x1EE6,
- 0x1EE8, 0x1EE8,
- 0x1EEA, 0x1EEA,
- 0x1EEC, 0x1EEC,
- 0x1EEE, 0x1EEE,
- 0x1EF0, 0x1EF0,
- 0x1EF2, 0x1EF2,
- 0x1EF4, 0x1EF4,
- 0x1EF6, 0x1EF6,
- 0x1EF8, 0x1EF8,
- 0x1EFA, 0x1EFA,
- 0x1EFC, 0x1EFC,
- 0x1EFE, 0x1EFE,
- 0x1F08, 0x1F0F,
- 0x1F18, 0x1F1D,
- 0x1F28, 0x1F2F,
- 0x1F38, 0x1F3F,
- 0x1F48, 0x1F4D,
- 0x1F59, 0x1F59,
- 0x1F5B, 0x1F5B,
- 0x1F5D, 0x1F5D,
- 0x1F5F, 0x1F5F,
- 0x1F68, 0x1F6F,
- 0x1FB8, 0x1FBB,
- 0x1FC8, 0x1FCB,
- 0x1FD8, 0x1FDB,
- 0x1FE8, 0x1FEC,
- 0x1FF8, 0x1FFB,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210B, 0x210D,
- 0x2110, 0x2112,
- 0x2115, 0x2115,
- 0x2119, 0x211D,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212A, 0x212D,
- 0x2130, 0x2133,
- 0x213E, 0x213F,
- 0x2145, 0x2145,
- 0x2160, 0x216F,
- 0x2183, 0x2183,
- 0x24B6, 0x24CF,
- 0x2C00, 0x2C2F,
- 0x2C60, 0x2C60,
- 0x2C62, 0x2C64,
- 0x2C67, 0x2C67,
- 0x2C69, 0x2C69,
- 0x2C6B, 0x2C6B,
- 0x2C6D, 0x2C70,
- 0x2C72, 0x2C72,
- 0x2C75, 0x2C75,
- 0x2C7E, 0x2C80,
- 0x2C82, 0x2C82,
- 0x2C84, 0x2C84,
- 0x2C86, 0x2C86,
- 0x2C88, 0x2C88,
- 0x2C8A, 0x2C8A,
- 0x2C8C, 0x2C8C,
- 0x2C8E, 0x2C8E,
- 0x2C90, 0x2C90,
- 0x2C92, 0x2C92,
- 0x2C94, 0x2C94,
- 0x2C96, 0x2C96,
- 0x2C98, 0x2C98,
- 0x2C9A, 0x2C9A,
- 0x2C9C, 0x2C9C,
- 0x2C9E, 0x2C9E,
- 0x2CA0, 0x2CA0,
- 0x2CA2, 0x2CA2,
- 0x2CA4, 0x2CA4,
- 0x2CA6, 0x2CA6,
- 0x2CA8, 0x2CA8,
- 0x2CAA, 0x2CAA,
- 0x2CAC, 0x2CAC,
- 0x2CAE, 0x2CAE,
- 0x2CB0, 0x2CB0,
- 0x2CB2, 0x2CB2,
- 0x2CB4, 0x2CB4,
- 0x2CB6, 0x2CB6,
- 0x2CB8, 0x2CB8,
- 0x2CBA, 0x2CBA,
- 0x2CBC, 0x2CBC,
- 0x2CBE, 0x2CBE,
- 0x2CC0, 0x2CC0,
- 0x2CC2, 0x2CC2,
- 0x2CC4, 0x2CC4,
- 0x2CC6, 0x2CC6,
- 0x2CC8, 0x2CC8,
- 0x2CCA, 0x2CCA,
- 0x2CCC, 0x2CCC,
- 0x2CCE, 0x2CCE,
- 0x2CD0, 0x2CD0,
- 0x2CD2, 0x2CD2,
- 0x2CD4, 0x2CD4,
- 0x2CD6, 0x2CD6,
- 0x2CD8, 0x2CD8,
- 0x2CDA, 0x2CDA,
- 0x2CDC, 0x2CDC,
- 0x2CDE, 0x2CDE,
- 0x2CE0, 0x2CE0,
- 0x2CE2, 0x2CE2,
- 0x2CEB, 0x2CEB,
- 0x2CED, 0x2CED,
- 0x2CF2, 0x2CF2,
- 0xA640, 0xA640,
- 0xA642, 0xA642,
- 0xA644, 0xA644,
- 0xA646, 0xA646,
- 0xA648, 0xA648,
- 0xA64A, 0xA64A,
- 0xA64C, 0xA64C,
- 0xA64E, 0xA64E,
- 0xA650, 0xA650,
- 0xA652, 0xA652,
- 0xA654, 0xA654,
- 0xA656, 0xA656,
- 0xA658, 0xA658,
- 0xA65A, 0xA65A,
- 0xA65C, 0xA65C,
- 0xA65E, 0xA65E,
- 0xA660, 0xA660,
- 0xA662, 0xA662,
- 0xA664, 0xA664,
- 0xA666, 0xA666,
- 0xA668, 0xA668,
- 0xA66A, 0xA66A,
- 0xA66C, 0xA66C,
- 0xA680, 0xA680,
- 0xA682, 0xA682,
- 0xA684, 0xA684,
- 0xA686, 0xA686,
- 0xA688, 0xA688,
- 0xA68A, 0xA68A,
- 0xA68C, 0xA68C,
- 0xA68E, 0xA68E,
- 0xA690, 0xA690,
- 0xA692, 0xA692,
- 0xA694, 0xA694,
- 0xA696, 0xA696,
- 0xA698, 0xA698,
- 0xA69A, 0xA69A,
- 0xA722, 0xA722,
- 0xA724, 0xA724,
- 0xA726, 0xA726,
- 0xA728, 0xA728,
- 0xA72A, 0xA72A,
- 0xA72C, 0xA72C,
- 0xA72E, 0xA72E,
- 0xA732, 0xA732,
- 0xA734, 0xA734,
- 0xA736, 0xA736,
- 0xA738, 0xA738,
- 0xA73A, 0xA73A,
- 0xA73C, 0xA73C,
- 0xA73E, 0xA73E,
- 0xA740, 0xA740,
- 0xA742, 0xA742,
- 0xA744, 0xA744,
- 0xA746, 0xA746,
- 0xA748, 0xA748,
- 0xA74A, 0xA74A,
- 0xA74C, 0xA74C,
- 0xA74E, 0xA74E,
- 0xA750, 0xA750,
- 0xA752, 0xA752,
- 0xA754, 0xA754,
- 0xA756, 0xA756,
- 0xA758, 0xA758,
- 0xA75A, 0xA75A,
- 0xA75C, 0xA75C,
- 0xA75E, 0xA75E,
- 0xA760, 0xA760,
- 0xA762, 0xA762,
- 0xA764, 0xA764,
- 0xA766, 0xA766,
- 0xA768, 0xA768,
- 0xA76A, 0xA76A,
- 0xA76C, 0xA76C,
- 0xA76E, 0xA76E,
- 0xA779, 0xA779,
- 0xA77B, 0xA77B,
- 0xA77D, 0xA77E,
- 0xA780, 0xA780,
- 0xA782, 0xA782,
- 0xA784, 0xA784,
- 0xA786, 0xA786,
- 0xA78B, 0xA78B,
- 0xA78D, 0xA78D,
- 0xA790, 0xA790,
- 0xA792, 0xA792,
- 0xA796, 0xA796,
- 0xA798, 0xA798,
- 0xA79A, 0xA79A,
- 0xA79C, 0xA79C,
- 0xA79E, 0xA79E,
- 0xA7A0, 0xA7A0,
- 0xA7A2, 0xA7A2,
- 0xA7A4, 0xA7A4,
- 0xA7A6, 0xA7A6,
- 0xA7A8, 0xA7A8,
- 0xA7AA, 0xA7AE,
- 0xA7B0, 0xA7B4,
- 0xA7B6, 0xA7B6,
- 0xA7B8, 0xA7B8,
- 0xA7BA, 0xA7BA,
- 0xA7BC, 0xA7BC,
- 0xA7BE, 0xA7BE,
- 0xA7C0, 0xA7C0,
- 0xA7C2, 0xA7C2,
- 0xA7C4, 0xA7C7,
- 0xA7C9, 0xA7C9,
- 0xA7D0, 0xA7D0,
- 0xA7D6, 0xA7D6,
- 0xA7D8, 0xA7D8,
- 0xA7F5, 0xA7F5,
- 0xFF21, 0xFF3A,
- 0x10400, 0x10427,
- 0x104B0, 0x104D3,
- 0x10570, 0x1057A,
- 0x1057C, 0x1058A,
- 0x1058C, 0x10592,
- 0x10594, 0x10595,
- 0x10C80, 0x10CB2,
- 0x118A0, 0x118BF,
- 0x16E40, 0x16E5F,
- 0x1D400, 0x1D419,
- 0x1D434, 0x1D44D,
- 0x1D468, 0x1D481,
- 0x1D49C, 0x1D49C,
- 0x1D49E, 0x1D49F,
- 0x1D4A2, 0x1D4A2,
- 0x1D4A5, 0x1D4A6,
- 0x1D4A9, 0x1D4AC,
- 0x1D4AE, 0x1D4B5,
- 0x1D4D0, 0x1D4E9,
- 0x1D504, 0x1D505,
- 0x1D507, 0x1D50A,
- 0x1D50D, 0x1D514,
- 0x1D516, 0x1D51C,
- 0x1D538, 0x1D539,
- 0x1D53B, 0x1D53E,
- 0x1D540, 0x1D544,
- 0x1D546, 0x1D546,
- 0x1D54A, 0x1D550,
- 0x1D56C, 0x1D585,
- 0x1D5A0, 0x1D5B9,
- 0x1D5D4, 0x1D5ED,
- 0x1D608, 0x1D621,
- 0x1D63C, 0x1D655,
- 0x1D670, 0x1D689,
- 0x1D6A8, 0x1D6C0,
- 0x1D6E2, 0x1D6FA,
- 0x1D71C, 0x1D734,
- 0x1D756, 0x1D76E,
- 0x1D790, 0x1D7A8,
- 0x1D7CA, 0x1D7CA,
- 0x1E900, 0x1E921,
- 0x1F130, 0x1F149,
- 0x1F150, 0x1F169,
- 0x1F170, 0x1F189,
-};
-
-/**
- * Binary search through the given list of codepoints to see if the given
- * codepoint is in the list.
- */
-static bool
-pm_unicode_codepoint_match(pm_unicode_codepoint_t codepoint, const pm_unicode_codepoint_t *codepoints, size_t size) {
- size_t start = 0;
- size_t end = size;
-
- while (start < end) {
- size_t middle = start + (end - start) / 2;
- if ((middle % 2) != 0) middle--;
-
- if (codepoint >= codepoints[middle] && codepoint <= codepoints[middle + 1]) {
- return true;
- }
-
- if (codepoint < codepoints[middle]) {
- end = middle;
- } else {
- start = middle + 2;
- }
- }
-
- return false;
-}
-
-/**
- * A state transition table for decoding UTF-8.
- *
- * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-static const uint8_t pm_utf_8_dfa[] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
- 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
- 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
- 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
- 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
- 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
- 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
- 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
-};
-
-/**
- * Given a pointer to a string and the number of bytes remaining in the string,
- * decode the next UTF-8 codepoint and return it. The number of bytes consumed
- * is returned in the width out parameter.
- */
-static pm_unicode_codepoint_t
-pm_utf_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
- assert(n >= 1);
- size_t maximum = (size_t) n;
-
- uint32_t codepoint;
- uint32_t state = 0;
-
- for (size_t index = 0; index < 4 && index < maximum; index++) {
- uint32_t byte = b[index];
- uint32_t type = pm_utf_8_dfa[byte];
-
- codepoint = (state != 0) ?
- (byte & 0x3fu) | (codepoint << 6) :
- (0xffu >> type) & (byte);
-
- state = pm_utf_8_dfa[256 + (state * 16) + type];
- if (!state) {
- *width = index + 1;
- return (pm_unicode_codepoint_t) codepoint;
- }
- }
-
- *width = 0;
- return 0;
-}
-
-static size_t
-pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n) {
- size_t width;
- pm_utf_8_codepoint(b, n, &width);
- return width;
-}
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphabetical character.
- */
-size_t
-pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) ? 1 : 0;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_utf_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & PRISM_ENCODING_ALPHABETIC_BIT) ? width : 0;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_alpha_codepoints, UNICODE_ALPHA_CODEPOINTS_LENGTH) ? width : 0;
- }
-}
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphanumeric character.
- */
-size_t
-pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_utf_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? width : 0;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_alnum_codepoints, UNICODE_ALNUM_CODEPOINTS_LENGTH) ? width : 0;
- }
-}
-
-/**
- * Return true if the next character in the UTF-8 encoding if it is an uppercase
- * character.
- */
-bool
-pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_utf_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_isupper_codepoints, UNICODE_ISUPPER_CODEPOINTS_LENGTH) ? true : false;
- }
-}
-
-#undef UNICODE_ALPHA_CODEPOINTS_LENGTH
-#undef UNICODE_ALNUM_CODEPOINTS_LENGTH
-#undef UNICODE_ISUPPER_CODEPOINTS_LENGTH
-
-/** UTF-8 */
-pm_encoding_t pm_encoding_utf_8 = {
- .name = "utf-8",
- .char_width = pm_encoding_utf_8_char_width,
- .alnum_char = pm_encoding_utf_8_alnum_char,
- .alpha_char = pm_encoding_utf_8_alpha_char,
- .isupper_char = pm_encoding_utf_8_isupper_char,
- .multibyte = true
-};
-
-/** UTF8-mac */
-pm_encoding_t pm_encoding_utf8_mac = {
- .name = "utf8-mac",
- .char_width = pm_encoding_utf_8_char_width,
- .alnum_char = pm_encoding_utf_8_alnum_char,
- .alpha_char = pm_encoding_utf_8_alpha_char,
- .isupper_char = pm_encoding_utf_8_isupper_char,
- .multibyte = true
-};
diff --git a/prism/enc/pm_windows_31j.c b/prism/enc/pm_windows_31j.c
deleted file mode 100644
index 848a9efd36..0000000000
--- a/prism/enc/pm_windows_31j.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "prism/enc/pm_encoding.h"
-
-static size_t
-pm_encoding_windows_31j_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80 || (*b >= 0xA1 && *b <= 0xDF)) {
- return 1;
- }
-
- // These are the double byte characters.
- if (
- (n > 1) &&
- ((b[0] >= 0x81 && b[0] <= 0x9F) || (b[0] >= 0xE0 && b[0] <= 0xFC)) &&
- (b[1] >= 0x40 && b[1] <= 0xFC)
- ) {
- return 2;
- }
-
- return 0;
-}
-
-static size_t
-pm_encoding_windows_31j_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_windows_31j_char_width(b, n) == 1) {
- return pm_encoding_ascii_alpha_char(b, n);
- } else {
- return 0;
- }
-}
-
-static size_t
-pm_encoding_windows_31j_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_windows_31j_char_width(b, n) == 1) {
- return pm_encoding_ascii_alnum_char(b, n);
- } else {
- return 0;
- }
-}
-
-static bool
-pm_encoding_windows_31j_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (pm_encoding_windows_31j_char_width(b, n) == 1) {
- return pm_encoding_ascii_isupper_char(b, n);
- } else {
- return false;
- }
-}
-
-/** Windows-31J */
-pm_encoding_t pm_encoding_windows_31j = {
- .name = "windows-31j",
- .char_width = pm_encoding_windows_31j_char_width,
- .alnum_char = pm_encoding_windows_31j_alnum_char,
- .alpha_char = pm_encoding_windows_31j_alpha_char,
- .isupper_char = pm_encoding_windows_31j_isupper_char,
- .multibyte = true
-};
diff --git a/prism/extension.c b/prism/extension.c
deleted file mode 100644
index 7046154320..0000000000
--- a/prism/extension.c
+++ /dev/null
@@ -1,991 +0,0 @@
-#include "prism/extension.h"
-
-// NOTE: this file should contain only bindings. All non-trivial logic should be
-// in librubyparser so it can be shared its the various callers.
-
-VALUE rb_cPrism;
-VALUE rb_cPrismNode;
-VALUE rb_cPrismSource;
-VALUE rb_cPrismToken;
-VALUE rb_cPrismLocation;
-
-VALUE rb_cPrismComment;
-VALUE rb_cPrismInlineComment;
-VALUE rb_cPrismEmbDocComment;
-VALUE rb_cPrismDATAComment;
-VALUE rb_cPrismMagicComment;
-VALUE rb_cPrismParseError;
-VALUE rb_cPrismParseWarning;
-VALUE rb_cPrismParseResult;
-
-ID rb_option_id_filepath;
-ID rb_option_id_encoding;
-ID rb_option_id_line;
-ID rb_option_id_frozen_string_literal;
-ID rb_option_id_verbose;
-ID rb_option_id_scopes;
-
-/******************************************************************************/
-/* IO of Ruby code */
-/******************************************************************************/
-
-/**
- * Check if the given VALUE is a string. If it's nil, then return NULL. If it's
- * not a string, then raise a type error. Otherwise return the VALUE as a C
- * string.
- */
-static const char *
-check_string(VALUE value) {
- // If the value is nil, then we don't need to do anything.
- if (NIL_P(value)) {
- return NULL;
- }
-
- // Check if the value is a string. If it's not, then raise a type error.
- if (!RB_TYPE_P(value, T_STRING)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(value));
- }
-
- // Otherwise, return the value as a C string.
- return RSTRING_PTR(value);
-}
-
-/**
- * Load the contents and size of the given string into the given pm_string_t.
- */
-static void
-input_load_string(pm_string_t *input, VALUE string) {
- // Check if the string is a string. If it's not, then raise a type error.
- if (!RB_TYPE_P(string, T_STRING)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(string));
- }
-
- pm_string_constant_init(input, RSTRING_PTR(string), RSTRING_LEN(string));
-}
-
-/******************************************************************************/
-/* Building C options from Ruby options */
-/******************************************************************************/
-
-/**
- * Build the scopes associated with the provided Ruby keyword value.
- */
-static void
-build_options_scopes(pm_options_t *options, VALUE scopes) {
- // Check if the value is an array. If it's not, then raise a type error.
- if (!RB_TYPE_P(scopes, T_ARRAY)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(scopes));
- }
-
- // Initialize the scopes array.
- size_t scopes_count = RARRAY_LEN(scopes);
- pm_options_scopes_init(options, scopes_count);
-
- // Iterate over the scopes and add them to the options.
- for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
- VALUE scope = rb_ary_entry(scopes, scope_index);
-
- // Check that the scope is an array. If it's not, then raise a type
- // error.
- if (!RB_TYPE_P(scope, T_ARRAY)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(scope));
- }
-
- // Initialize the scope array.
- size_t locals_count = RARRAY_LEN(scope);
- pm_options_scope_t *options_scope = &options->scopes[scope_index];
- pm_options_scope_init(options_scope, locals_count);
-
- // Iterate over the locals and add them to the scope.
- for (size_t local_index = 0; local_index < locals_count; local_index++) {
- VALUE local = rb_ary_entry(scope, local_index);
-
- // Check that the local is a symbol. If it's not, then raise a
- // type error.
- if (!RB_TYPE_P(local, T_SYMBOL)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Symbol)", rb_obj_class(local));
- }
-
- // Add the local to the scope.
- pm_string_t *scope_local = &options_scope->locals[local_index];
- const char *name = rb_id2name(SYM2ID(local));
- pm_string_constant_init(scope_local, name, strlen(name));
- }
- }
-}
-
-/**
- * An iterator function that is called for each key-value in the keywords hash.
- */
-static int
-build_options_i(VALUE key, VALUE value, VALUE argument) {
- pm_options_t *options = (pm_options_t *) argument;
- ID key_id = SYM2ID(key);
-
- if (key_id == rb_option_id_filepath) {
- if (!NIL_P(value)) pm_options_filepath_set(options, check_string(value));
- } else if (key_id == rb_option_id_encoding) {
- if (!NIL_P(value)) pm_options_encoding_set(options, rb_enc_name(rb_to_encoding(value)));
- } else if (key_id == rb_option_id_line) {
- if (!NIL_P(value)) pm_options_line_set(options, NUM2UINT(value));
- } else if (key_id == rb_option_id_frozen_string_literal) {
- if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, value == Qtrue);
- } else if (key_id == rb_option_id_verbose) {
- pm_options_suppress_warnings_set(options, value != Qtrue);
- } else if (key_id == rb_option_id_scopes) {
- if (!NIL_P(value)) build_options_scopes(options, value);
- } else {
- rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, key);
- }
-
- return ST_CONTINUE;
-}
-
-/**
- * We need a struct here to pass through rb_protect and it has to be a single
- * value. Because the sizeof(VALUE) == sizeof(void *), we're going to pass this
- * through as an opaque pointer and cast it on both sides.
- */
-struct build_options_data {
- pm_options_t *options;
- VALUE keywords;
-};
-
-/**
- * Build the set of options from the given keywords. Note that this can raise a
- * Ruby error if the options are not valid.
- */
-static VALUE
-build_options(VALUE argument) {
- struct build_options_data *data = (struct build_options_data *) argument;
- rb_hash_foreach(data->keywords, build_options_i, (VALUE) data->options);
- return Qnil;
-}
-
-/**
- * Extract the options from the given keyword arguments.
- */
-static void
-extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
- if (!NIL_P(keywords)) {
- struct build_options_data data = { .options = options, .keywords = keywords };
- struct build_options_data *argument = &data;
-
- int state = 0;
- rb_protect(build_options, (VALUE) argument, &state);
-
- if (state != 0) {
- pm_options_free(options);
- rb_jump_tag(state);
- }
- }
-
- if (!NIL_P(filepath)) {
- if (!RB_TYPE_P(filepath, T_STRING)) {
- pm_options_free(options);
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(filepath));
- }
-
- pm_options_filepath_set(options, RSTRING_PTR(filepath));
- }
-}
-
-/**
- * Read options for methods that look like (source, **options).
- */
-static void
-string_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) {
- VALUE string;
- VALUE keywords;
- rb_scan_args(argc, argv, "1:", &string, &keywords);
-
- extract_options(options, Qnil, keywords);
- input_load_string(input, string);
-}
-
-/**
- * Read options for methods that look like (filepath, **options).
- */
-static bool
-file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) {
- VALUE filepath;
- VALUE keywords;
- rb_scan_args(argc, argv, "1:", &filepath, &keywords);
-
- extract_options(options, filepath, keywords);
-
- if (!pm_string_mapped_init(input, (const char *) pm_string_source(&options->filepath))) {
- pm_options_free(options);
- return false;
- }
-
- return true;
-}
-
-/******************************************************************************/
-/* Serializing the AST */
-/******************************************************************************/
-
-/**
- * Dump the AST corresponding to the given input to a string.
- */
-static VALUE
-dump_input(pm_string_t *input, const pm_options_t *options) {
- pm_buffer_t buffer;
- if (!pm_buffer_init(&buffer)) {
- rb_raise(rb_eNoMemError, "failed to allocate memory");
- }
-
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_serialize(&parser, node, &buffer);
-
- VALUE result = rb_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer));
- pm_node_destroy(&parser, node);
- pm_buffer_free(&buffer);
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::dump(source, **options) -> String
- *
- * Dump the AST corresponding to the given string to a string. For supported
- * options, see Prism::parse.
- */
-static VALUE
-dump(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
-#ifdef PRISM_DEBUG_MODE_BUILD
- size_t length = pm_string_length(&input);
- char* dup = malloc(length);
- memcpy(dup, pm_string_source(&input), length);
- pm_string_constant_init(&input, dup, length);
-#endif
-
- VALUE value = dump_input(&input, &options);
-
-#ifdef PRISM_DEBUG_MODE_BUILD
- free(dup);
-#endif
-
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * call-seq:
- * Prism::dump_file(filepath, **options) -> String
- *
- * Dump the AST corresponding to the given file to a string. For supported
- * options, see Prism::parse.
- */
-static VALUE
-dump_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- if (!file_options(argc, argv, &input, &options)) return Qnil;
-
- VALUE value = dump_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/******************************************************************************/
-/* Extracting values for the parse result */
-/******************************************************************************/
-
-/**
- * Extract the comments out of the parser into an array.
- */
-static VALUE
-parser_comments(pm_parser_t *parser, VALUE source) {
- VALUE comments = rb_ary_new();
-
- for (pm_comment_t *comment = (pm_comment_t *) parser->comment_list.head; comment != NULL; comment = (pm_comment_t *) comment->node.next) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(comment->start - parser->start),
- LONG2FIX(comment->end - comment->start)
- };
-
- VALUE type;
- switch (comment->type) {
- case PM_COMMENT_INLINE:
- type = rb_cPrismInlineComment;
- break;
- case PM_COMMENT_EMBDOC:
- type = rb_cPrismEmbDocComment;
- break;
- case PM_COMMENT___END__:
- type = rb_cPrismDATAComment;
- break;
- default:
- type = rb_cPrismInlineComment;
- break;
- }
-
- VALUE comment_argv[] = { rb_class_new_instance(3, location_argv, rb_cPrismLocation) };
- rb_ary_push(comments, rb_class_new_instance(1, comment_argv, type));
- }
-
- return comments;
-}
-
-/**
- * Extract the magic comments out of the parser into an array.
- */
-static VALUE
-parser_magic_comments(pm_parser_t *parser, VALUE source) {
- VALUE magic_comments = rb_ary_new();
-
- for (pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) parser->magic_comment_list.head; magic_comment != NULL; magic_comment = (pm_magic_comment_t *) magic_comment->node.next) {
- VALUE key_loc_argv[] = {
- source,
- LONG2FIX(magic_comment->key_start - parser->start),
- LONG2FIX(magic_comment->key_length)
- };
-
- VALUE value_loc_argv[] = {
- source,
- LONG2FIX(magic_comment->value_start - parser->start),
- LONG2FIX(magic_comment->value_length)
- };
-
- VALUE magic_comment_argv[] = {
- rb_class_new_instance(3, key_loc_argv, rb_cPrismLocation),
- rb_class_new_instance(3, value_loc_argv, rb_cPrismLocation)
- };
-
- rb_ary_push(magic_comments, rb_class_new_instance(2, magic_comment_argv, rb_cPrismMagicComment));
- }
-
- return magic_comments;
-}
-
-/**
- * Extract the errors out of the parser into an array.
- */
-static VALUE
-parser_errors(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
- VALUE errors = rb_ary_new();
- pm_diagnostic_t *error;
-
- for (error = (pm_diagnostic_t *) parser->error_list.head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(error->start - parser->start),
- LONG2FIX(error->end - error->start)
- };
-
- VALUE error_argv[] = {
- rb_enc_str_new_cstr(error->message, encoding),
- rb_class_new_instance(3, location_argv, rb_cPrismLocation)
- };
-
- rb_ary_push(errors, rb_class_new_instance(2, error_argv, rb_cPrismParseError));
- }
-
- return errors;
-}
-
-/**
- * Extract the warnings out of the parser into an array.
- */
-static VALUE
-parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
- VALUE warnings = rb_ary_new();
- pm_diagnostic_t *warning;
-
- for (warning = (pm_diagnostic_t *) parser->warning_list.head; warning != NULL; warning = (pm_diagnostic_t *) warning->node.next) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(warning->start - parser->start),
- LONG2FIX(warning->end - warning->start)
- };
-
- VALUE warning_argv[] = {
- rb_enc_str_new_cstr(warning->message, encoding),
- rb_class_new_instance(3, location_argv, rb_cPrismLocation)
- };
-
- rb_ary_push(warnings, rb_class_new_instance(2, warning_argv, rb_cPrismParseWarning));
- }
-
- return warnings;
-}
-
-/******************************************************************************/
-/* Lexing Ruby code */
-/******************************************************************************/
-
-/**
- * This struct gets stored in the parser and passed in to the lex callback any
- * time a new token is found. We use it to store the necessary information to
- * initialize a Token instance.
- */
-typedef struct {
- VALUE source;
- VALUE tokens;
- rb_encoding *encoding;
-} parse_lex_data_t;
-
-/**
- * This is passed as a callback to the parser. It gets called every time a new
- * token is found. Once found, we initialize a new instance of Token and push it
- * onto the tokens array.
- */
-static void
-parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) {
- parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data;
-
- VALUE yields = rb_ary_new_capa(2);
- rb_ary_push(yields, pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source));
- rb_ary_push(yields, INT2FIX(parser->lex_state));
-
- rb_ary_push(parse_lex_data->tokens, yields);
-}
-
-/**
- * This is called whenever the encoding changes based on the magic comment at
- * the top of the file. We use it to update the encoding that we are using to
- * create tokens.
- */
-static void
-parse_lex_encoding_changed_callback(pm_parser_t *parser) {
- parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data;
- parse_lex_data->encoding = rb_enc_find(parser->encoding.name);
-
- // Since the encoding changed, we need to go back and change the encoding of
- // the tokens that were already lexed. This is only going to end up being
- // one or two tokens, since the encoding can only change at the top of the
- // file.
- VALUE tokens = parse_lex_data->tokens;
- for (long index = 0; index < RARRAY_LEN(tokens); index++) {
- VALUE yields = rb_ary_entry(tokens, index);
- VALUE token = rb_ary_entry(yields, 0);
-
- VALUE value = rb_ivar_get(token, rb_intern("@value"));
- rb_enc_associate(value, parse_lex_data->encoding);
- ENC_CODERANGE_CLEAR(value);
- }
-}
-
-/**
- * Parse the given input and return a ParseResult containing just the tokens or
- * the nodes and tokens.
- */
-static VALUE
-parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nodes) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
- pm_parser_register_encoding_changed_callback(&parser, parse_lex_encoding_changed_callback);
-
- VALUE offsets = rb_ary_new();
- VALUE source_argv[] = { rb_str_new((const char *) pm_string_source(input), pm_string_length(input)), ULONG2NUM(parser.start_line), offsets };
- VALUE source = rb_class_new_instance(3, source_argv, rb_cPrismSource);
-
- parse_lex_data_t parse_lex_data = {
- .source = source,
- .tokens = rb_ary_new(),
- .encoding = rb_utf8_encoding()
- };
-
- parse_lex_data_t *data = &parse_lex_data;
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
- .data = (void *) data,
- .callback = parse_lex_token,
- };
-
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
-
- // Here we need to update the source range to have the correct newline
- // offsets. We do it here because we've already created the object and given
- // it over to all of the tokens.
- for (size_t index = 0; index < parser.newline_list.size; index++) {
- rb_ary_push(offsets, INT2FIX(parser.newline_list.offsets[index]));
- }
-
- VALUE value;
- if (return_nodes) {
- value = rb_ary_new_capa(2);
- rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding));
- rb_ary_push(value, parse_lex_data.tokens);
- } else {
- value = parse_lex_data.tokens;
- }
-
- VALUE result_argv[] = {
- value,
- parser_comments(&parser, source),
- parser_magic_comments(&parser, source),
- parser_errors(&parser, parse_lex_data.encoding, source),
- parser_warnings(&parser, parse_lex_data.encoding, source),
- source
- };
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- return rb_class_new_instance(6, result_argv, rb_cPrismParseResult);
-}
-
-/**
- * call-seq:
- * Prism::lex(source, **options) -> Array
- *
- * Return an array of Token instances corresponding to the given string. For
- * supported options, see Prism::parse.
- */
-static VALUE
-lex(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
- VALUE result = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::lex_file(filepath, **options) -> Array
- *
- * Return an array of Token instances corresponding to the given file. For
- * supported options, see Prism::parse.
- */
-static VALUE
-lex_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- if (!file_options(argc, argv, &input, &options)) return Qnil;
-
- VALUE value = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/******************************************************************************/
-/* Parsing Ruby code */
-/******************************************************************************/
-
-/**
- * Parse the given input and return a ParseResult instance.
- */
-static VALUE
-parse_input(pm_string_t *input, const pm_options_t *options) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding.name);
-
- VALUE source = pm_source_new(&parser, encoding);
- VALUE result_argv[] = {
- pm_ast_new(&parser, node, encoding),
- parser_comments(&parser, source),
- parser_magic_comments(&parser, source),
- parser_errors(&parser, encoding, source),
- parser_warnings(&parser, encoding, source),
- source
- };
-
- VALUE result = rb_class_new_instance(6, result_argv, rb_cPrismParseResult);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse(source, **options) -> ParseResult
- *
- * Parse the given string and return a ParseResult instance. The options that
- * are supported are:
- *
- * * `filepath` - the filepath of the source being parsed. This should be a
- * string or nil
- * * `encoding` - the encoding of the source being parsed. This should be an
- * encoding or nil
- * * `line` - the line number that the parse starts on. This should be an
- * integer or nil. Note that this is 1-indexed.
- * * `frozen_string_literal` - whether or not the frozen string literal pragma
- * has been set. This should be a boolean or nil.
- * * `verbose` - the current level of verbosity. This controls whether or not
- * the parser emits warnings. This should be a boolean or nil.
- * * `scopes` - the locals that are in scope surrounding the code that is being
- * parsed. This should be an array of arrays of symbols or nil.
- */
-static VALUE
-parse(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
-#ifdef PRISM_DEBUG_MODE_BUILD
- size_t length = pm_string_length(&input);
- char* dup = malloc(length);
- memcpy(dup, pm_string_source(&input), length);
- pm_string_constant_init(&input, dup, length);
-#endif
-
- VALUE value = parse_input(&input, &options);
-
-#ifdef PRISM_DEBUG_MODE_BUILD
- free(dup);
-#endif
-
- pm_string_free(&input);
- pm_options_free(&options);
- return value;
-}
-
-/**
- * call-seq:
- * Prism::parse_file(filepath, **options) -> ParseResult
- *
- * Parse the given file and return a ParseResult instance. For supported
- * options, see Prism::parse.
- */
-static VALUE
-parse_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- if (!file_options(argc, argv, &input, &options)) return Qnil;
-
- VALUE value = parse_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * Parse the given input and return an array of Comment objects.
- */
-static VALUE
-parse_input_comments(pm_string_t *input, const pm_options_t *options) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding.name);
-
- VALUE source = pm_source_new(&parser, encoding);
- VALUE comments = parser_comments(&parser, source);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- return comments;
-}
-
-/**
- * call-seq:
- * Prism::parse_comments(source, **options) -> Array
- *
- * Parse the given string and return an array of Comment objects. For supported
- * options, see Prism::parse.
- */
-static VALUE
-parse_comments(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
- VALUE result = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse_file_comments(filepath, **options) -> Array
- *
- * Parse the given file and return an array of Comment objects. For supported
- * options, see Prism::parse.
- */
-static VALUE
-parse_file_comments(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- if (!file_options(argc, argv, &input, &options)) return Qnil;
-
- VALUE value = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * call-seq:
- * Prism::parse_lex(source, **options) -> ParseResult
- *
- * Parse the given string and return a ParseResult instance that contains a
- * 2-element array, where the first element is the AST and the second element is
- * an array of Token instances.
- *
- * This API is only meant to be used in the case where you need both the AST and
- * the tokens. If you only need one or the other, use either Prism::parse or
- * Prism::lex.
- *
- * For supported options, see Prism::parse.
- */
-static VALUE
-parse_lex(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * call-seq:
- * Prism::parse_lex_file(filepath, **options) -> ParseResult
- *
- * Parse the given file and return a ParseResult instance that contains a
- * 2-element array, where the first element is the AST and the second element is
- * an array of Token instances.
- *
- * This API is only meant to be used in the case where you need both the AST and
- * the tokens. If you only need one or the other, use either Prism::parse_file
- * or Prism::lex_file.
- *
- * For supported options, see Prism::parse.
- */
-static VALUE
-parse_lex_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- if (!file_options(argc, argv, &input, &options)) return Qnil;
-
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/******************************************************************************/
-/* Utility functions exposed to make testing easier */
-/******************************************************************************/
-
-/**
- * call-seq:
- * Debug::named_captures(source) -> Array
- *
- * Returns an array of strings corresponding to the named capture groups in the
- * given source string. If prism was unable to parse the regular expression,
- * this function returns nil.
- */
-static VALUE
-named_captures(VALUE self, VALUE source) {
- pm_string_list_t string_list = { 0 };
-
- if (!pm_regexp_named_capture_group_names((const uint8_t *) RSTRING_PTR(source), RSTRING_LEN(source), &string_list, false, &pm_encoding_utf_8)) {
- pm_string_list_free(&string_list);
- return Qnil;
- }
-
- VALUE names = rb_ary_new();
- for (size_t index = 0; index < string_list.length; index++) {
- const pm_string_t *string = &string_list.strings[index];
- rb_ary_push(names, rb_str_new((const char *) pm_string_source(string), pm_string_length(string)));
- }
-
- pm_string_list_free(&string_list);
- return names;
-}
-
-/**
- * call-seq:
- * Debug::memsize(source) -> { length: xx, memsize: xx, node_count: xx }
- *
- * Return a hash of information about the given source string's memory usage.
- */
-static VALUE
-memsize(VALUE self, VALUE string) {
- pm_parser_t parser;
- size_t length = RSTRING_LEN(string);
- pm_parser_init(&parser, (const uint8_t *) RSTRING_PTR(string), length, NULL);
-
- pm_node_t *node = pm_parse(&parser);
- pm_memsize_t memsize;
- pm_node_memsize(node, &memsize);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- VALUE result = rb_hash_new();
- rb_hash_aset(result, ID2SYM(rb_intern("length")), INT2FIX(length));
- rb_hash_aset(result, ID2SYM(rb_intern("memsize")), INT2FIX(memsize.memsize));
- rb_hash_aset(result, ID2SYM(rb_intern("node_count")), INT2FIX(memsize.node_count));
- return result;
-}
-
-/**
- * call-seq:
- * Debug::profile_file(filepath) -> nil
- *
- * Parse the file, but do nothing with the result. This is used to profile the
- * parser for memory and speed.
- */
-static VALUE
-profile_file(VALUE self, VALUE filepath) {
- pm_string_t input;
-
- const char *checked = check_string(filepath);
- if (!pm_string_mapped_init(&input, checked)) return Qnil;
-
- pm_options_t options = { 0 };
- pm_options_filepath_set(&options, checked);
-
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
- pm_string_free(&input);
-
- return Qnil;
-}
-
-/**
- * call-seq:
- * Debug::inspect_node(source) -> inspected
- *
- * Inspect the AST that represents the given source using the prism pretty print
- * as opposed to the Ruby implementation.
- */
-static VALUE
-inspect_node(VALUE self, VALUE source) {
- pm_string_t input;
- input_load_string(&input, source);
-
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), NULL);
-
- pm_node_t *node = pm_parse(&parser);
- pm_buffer_t buffer = { 0 };
-
- pm_prettyprint(&buffer, &parser, node);
-
- rb_encoding *encoding = rb_enc_find(parser.encoding.name);
- VALUE string = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), encoding);
-
- pm_buffer_free(&buffer);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- return string;
-}
-
-/******************************************************************************/
-/* Initialization of the extension */
-/******************************************************************************/
-
-/**
- * The init function that Ruby calls when loading this extension.
- */
-RUBY_FUNC_EXPORTED void
-Init_prism(void) {
- // Make sure that the prism library version matches the expected version.
- // Otherwise something was compiled incorrectly.
- if (strcmp(pm_version(), EXPECTED_PRISM_VERSION) != 0) {
- rb_raise(
- rb_eRuntimeError,
- "The prism library version (%s) does not match the expected version (%s)",
- pm_version(),
- EXPECTED_PRISM_VERSION
- );
- }
-
- // Grab up references to all of the constants that we're going to need to
- // reference throughout this extension.
- rb_cPrism = rb_define_module("Prism");
- rb_cPrismNode = rb_define_class_under(rb_cPrism, "Node", rb_cObject);
- rb_cPrismSource = rb_define_class_under(rb_cPrism, "Source", rb_cObject);
- rb_cPrismToken = rb_define_class_under(rb_cPrism, "Token", rb_cObject);
- rb_cPrismLocation = rb_define_class_under(rb_cPrism, "Location", rb_cObject);
- rb_cPrismComment = rb_define_class_under(rb_cPrism, "Comment", rb_cObject);
- rb_cPrismInlineComment = rb_define_class_under(rb_cPrism, "InlineComment", rb_cPrismComment);
- rb_cPrismEmbDocComment = rb_define_class_under(rb_cPrism, "EmbDocComment", rb_cPrismComment);
- rb_cPrismDATAComment = rb_define_class_under(rb_cPrism, "DATAComment", rb_cPrismComment);
- rb_cPrismMagicComment = rb_define_class_under(rb_cPrism, "MagicComment", rb_cObject);
- rb_cPrismParseError = rb_define_class_under(rb_cPrism, "ParseError", rb_cObject);
- rb_cPrismParseWarning = rb_define_class_under(rb_cPrism, "ParseWarning", rb_cObject);
- rb_cPrismParseResult = rb_define_class_under(rb_cPrism, "ParseResult", rb_cObject);
-
- // Intern all of the options that we support so that we don't have to do it
- // every time we parse.
- rb_option_id_filepath = rb_intern_const("filepath");
- rb_option_id_encoding = rb_intern_const("encoding");
- rb_option_id_line = rb_intern_const("line");
- rb_option_id_frozen_string_literal = rb_intern_const("frozen_string_literal");
- rb_option_id_verbose = rb_intern_const("verbose");
- rb_option_id_scopes = rb_intern_const("scopes");
-
- /**
- * The version of the prism library.
- */
- rb_define_const(rb_cPrism, "VERSION", rb_str_new2(EXPECTED_PRISM_VERSION));
-
- /**
- * The backend of the parser that prism is using to parse Ruby code. This
- * can be either :CEXT or :FFI. On runtimes that support C extensions, we
- * default to :CEXT. Otherwise we use :FFI.
- */
- rb_define_const(rb_cPrism, "BACKEND", ID2SYM(rb_intern("CEXT")));
-
- // First, the functions that have to do with lexing and parsing.
- rb_define_singleton_method(rb_cPrism, "dump", dump, -1);
- rb_define_singleton_method(rb_cPrism, "dump_file", dump_file, -1);
- rb_define_singleton_method(rb_cPrism, "lex", lex, -1);
- rb_define_singleton_method(rb_cPrism, "lex_file", lex_file, -1);
- rb_define_singleton_method(rb_cPrism, "parse", parse, -1);
- rb_define_singleton_method(rb_cPrism, "parse_file", parse_file, -1);
- rb_define_singleton_method(rb_cPrism, "parse_comments", parse_comments, -1);
- rb_define_singleton_method(rb_cPrism, "parse_file_comments", parse_file_comments, -1);
- rb_define_singleton_method(rb_cPrism, "parse_lex", parse_lex, -1);
- rb_define_singleton_method(rb_cPrism, "parse_lex_file", parse_lex_file, -1);
-
- // Next, the functions that will be called by the parser to perform various
- // internal tasks. We expose these to make them easier to test.
- VALUE rb_cPrismDebug = rb_define_module_under(rb_cPrism, "Debug");
- rb_define_singleton_method(rb_cPrismDebug, "named_captures", named_captures, 1);
- rb_define_singleton_method(rb_cPrismDebug, "memsize", memsize, 1);
- rb_define_singleton_method(rb_cPrismDebug, "profile_file", profile_file, 1);
- rb_define_singleton_method(rb_cPrismDebug, "inspect_node", inspect_node, 1);
-
- // Next, initialize the other APIs.
- Init_prism_api_node();
- Init_prism_pack();
-}
diff --git a/prism/extension.h b/prism/extension.h
deleted file mode 100644
index 4803aabe5e..0000000000
--- a/prism/extension.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef PRISM_EXT_NODE_H
-#define PRISM_EXT_NODE_H
-
-#define EXPECTED_PRISM_VERSION "0.17.1"
-
-#include <ruby.h>
-#include <ruby/encoding.h>
-#include "prism.h"
-
-VALUE pm_source_new(pm_parser_t *parser, rb_encoding *encoding);
-VALUE pm_token_new(pm_parser_t *parser, pm_token_t *token, rb_encoding *encoding, VALUE source);
-VALUE pm_ast_new(pm_parser_t *parser, pm_node_t *node, rb_encoding *encoding);
-
-void Init_prism_api_node(void);
-void Init_prism_pack(void);
-PRISM_EXPORTED_FUNCTION void Init_prism(void);
-
-#endif
diff --git a/prism/node.h b/prism/node.h
deleted file mode 100644
index 3e15d18552..0000000000
--- a/prism/node.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @file node.h
- *
- * Functions related to nodes in the AST.
- */
-#ifndef PRISM_NODE_H
-#define PRISM_NODE_H
-
-#include "prism/defines.h"
-#include "prism/parser.h"
-
-/**
- * Append a new node onto the end of the node list.
- *
- * @param list The list to append to.
- * @param node The node to append.
- */
-void pm_node_list_append(pm_node_list_t *list, pm_node_t *node);
-
-/**
- * Deallocate a node and all of its children.
- *
- * @param parser The parser that owns the node.
- * @param node The node to deallocate.
- */
-PRISM_EXPORTED_FUNCTION void pm_node_destroy(pm_parser_t *parser, struct pm_node *node);
-
-/**
- * This struct stores the information gathered by the pm_node_memsize function.
- * It contains both the memory footprint and additionally metadata about the
- * shape of the tree.
- */
-typedef struct {
- /** The total memory footprint of the node and all of its children. */
- size_t memsize;
-
- /** The number of children the node has. */
- size_t node_count;
-} pm_memsize_t;
-
-/**
- * Calculates the memory footprint of a given node.
- *
- * @param node The node to calculate the memory footprint of.
- * @param memsize The memory footprint of the node and all of its children.
- */
-PRISM_EXPORTED_FUNCTION void pm_node_memsize(pm_node_t *node, pm_memsize_t *memsize);
-
-/**
- * Returns a string representation of the given node type.
- *
- * @param node_type The node type to convert to a string.
- * @return A string representation of the given node type.
- */
-PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_type);
-
-#endif
diff --git a/prism/options.c b/prism/options.c
deleted file mode 100644
index 84c1fcbb39..0000000000
--- a/prism/options.c
+++ /dev/null
@@ -1,170 +0,0 @@
-#include "prism/options.h"
-
-/**
- * Set the filepath option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_filepath_set(pm_options_t *options, const char *filepath) {
- pm_string_constant_init(&options->filepath, filepath, strlen(filepath));
-}
-
-/**
- * Set the encoding option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_encoding_set(pm_options_t *options, const char *encoding) {
- pm_string_constant_init(&options->encoding, encoding, strlen(encoding));
-}
-
-/**
- * Set the line option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_line_set(pm_options_t *options, uint32_t line) {
- options->line = line;
-}
-
-/**
- * Set the frozen string literal option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) {
- options->frozen_string_literal = frozen_string_literal;
-}
-
-/**
- * Set the suppress warnings option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_suppress_warnings_set(pm_options_t *options, bool suppress_warnings) {
- options->suppress_warnings = suppress_warnings;
-}
-
-/**
- * Allocate and zero out the scopes array on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_scopes_init(pm_options_t *options, size_t scopes_count) {
- options->scopes_count = scopes_count;
- options->scopes = calloc(scopes_count, sizeof(pm_options_scope_t));
- if (options->scopes == NULL) abort();
-}
-
-/**
- * Return a pointer to the scope at the given index within the given options.
- */
-PRISM_EXPORTED_FUNCTION const pm_options_scope_t *
-pm_options_scope_get(const pm_options_t *options, size_t index) {
- return &options->scopes[index];
-}
-
-/**
- * Create a new options scope struct. This will hold a set of locals that are in
- * scope surrounding the code that is being parsed.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
- scope->locals_count = locals_count;
- scope->locals = calloc(locals_count, sizeof(pm_string_t));
- if (scope->locals == NULL) abort();
-}
-
-/**
- * Return a pointer to the local at the given index within the given scope.
- */
-PRISM_EXPORTED_FUNCTION const pm_string_t *
-pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index) {
- return &scope->locals[index];
-}
-
-/**
- * Free the internal memory associated with the options.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_free(pm_options_t *options) {
- pm_string_free(&options->filepath);
- pm_string_free(&options->encoding);
-
- for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
- pm_options_scope_t *scope = &options->scopes[scope_index];
-
- for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
- pm_string_free(&scope->locals[local_index]);
- }
-
- free(scope->locals);
- }
-
- free(options->scopes);
-}
-
-/**
- * Read a 32-bit unsigned integer from a pointer. This function is used to read
- * the options that are passed into the parser from the Ruby implementation. It
- * handles aligned and unaligned reads.
- */
-static uint32_t
-pm_options_read_u32(const char *data) {
- if (((uintptr_t) data) % sizeof(uint32_t) == 0) {
- return *((uint32_t *) data);
- } else {
- uint32_t value;
- memcpy(&value, data, sizeof(uint32_t));
- return value;
- }
-}
-
-/**
- * Deserialize an options struct from the given binary string. This is used to
- * pass options to the parser from an FFI call so that consumers of the library
- * from an FFI perspective don't have to worry about the structure of our
- * options structs. Since the source of these calls will be from Ruby
- * implementation internals we assume it is from a trusted source.
- */
-void
-pm_options_read(pm_options_t *options, const char *data) {
- uint32_t filepath_length = pm_options_read_u32(data);
- data += 4;
-
- if (filepath_length > 0) {
- pm_string_constant_init(&options->filepath, data, filepath_length);
- data += filepath_length;
- }
-
- options->line = pm_options_read_u32(data);
- data += 4;
-
- uint32_t encoding_length = pm_options_read_u32(data);
- data += 4;
-
- if (encoding_length > 0) {
- pm_string_constant_init(&options->encoding, data, encoding_length);
- data += encoding_length;
- }
-
- options->frozen_string_literal = *data++;
- options->suppress_warnings = *data++;
-
- uint32_t scopes_count = pm_options_read_u32(data);
- data += 4;
-
- if (scopes_count > 0) {
- pm_options_scopes_init(options, scopes_count);
-
- for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
- uint32_t locals_count = pm_options_read_u32(data);
- data += 4;
-
- pm_options_scope_t *scope = &options->scopes[scope_index];
- pm_options_scope_init(scope, locals_count);
-
- for (size_t local_index = 0; local_index < locals_count; local_index++) {
- uint32_t local_length = pm_options_read_u32(data);
- data += 4;
-
- pm_string_constant_init(&scope->locals[local_index], data, local_length);
- data += local_length;
- }
- }
- }
-}
diff --git a/prism/options.h b/prism/options.h
deleted file mode 100644
index 2ea85c838c..0000000000
--- a/prism/options.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * @file options.h
- *
- * The options that can be passed to parsing.
- */
-#ifndef PRISM_OPTIONS_H
-#define PRISM_OPTIONS_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_string.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * A scope of locals surrounding the code that is being parsed.
- */
-typedef struct pm_options_scope {
- /** The number of locals in the scope. */
- size_t locals_count;
-
- /** The names of the locals in the scope. */
- pm_string_t *locals;
-} pm_options_scope_t;
-
-/**
- * The options that can be passed to the parser.
- */
-typedef struct {
- /** The name of the file that is currently being parsed. */
- pm_string_t filepath;
-
- /**
- * The line within the file that the parse starts on. This value is
- * 0-indexed.
- */
- uint32_t line;
-
- /**
- * The name of the encoding that the source file is in. Note that this must
- * correspond to a name that can be found with Encoding.find in Ruby.
- */
- pm_string_t encoding;
-
- /**
- * The number of scopes surrounding the code that is being parsed.
- */
- size_t scopes_count;
-
- /**
- * The scopes surrounding the code that is being parsed. For most parses
- * this will be NULL, but for evals it will be the locals that are in scope
- * surrounding the eval.
- */
- pm_options_scope_t *scopes;
-
- /** Whether or not the frozen string literal option has been set. */
- bool frozen_string_literal;
-
- /**
- * Whether or not we should suppress warnings. This is purposefully negated
- * so that the default is to not suppress warnings, which allows us to still
- * create an options struct with zeroed memory.
- */
- bool suppress_warnings;
-} pm_options_t;
-
-/**
- * Set the filepath option on the given options struct.
- *
- * @param options The options struct to set the filepath on.
- * @param filepath The filepath to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath);
-
-/**
- * Set the line option on the given options struct.
- *
- * @param options The options struct to set the line on.
- * @param line The line to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, uint32_t line);
-
-/**
- * Set the encoding option on the given options struct.
- *
- * @param options The options struct to set the encoding on.
- * @param encoding The encoding to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding);
-
-/**
- * Set the frozen string literal option on the given options struct.
- *
- * @param options The options struct to set the frozen string literal value on.
- * @param frozen_string_literal The frozen string literal value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal);
-
-/**
- * Set the suppress warnings option on the given options struct.
- *
- * @param options The options struct to set the suppress warnings value on.
- * @param suppress_warnings The suppress warnings value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_suppress_warnings_set(pm_options_t *options, bool suppress_warnings);
-
-/**
- * Allocate and zero out the scopes array on the given options struct.
- *
- * @param options The options struct to initialize the scopes array on.
- * @param scopes_count The number of scopes to allocate.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_scopes_init(pm_options_t *options, size_t scopes_count);
-
-/**
- * Return a pointer to the scope at the given index within the given options.
- *
- * @param options The options struct to get the scope from.
- * @param index The index of the scope to get.
- * @return A pointer to the scope at the given index.
- */
-PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index);
-
-/**
- * Create a new options scope struct. This will hold a set of locals that are in
- * scope surrounding the code that is being parsed.
- *
- * @param scope The scope struct to initialize.
- * @param locals_count The number of locals to allocate.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count);
-
-/**
- * Return a pointer to the local at the given index within the given scope.
- *
- * @param scope The scope struct to get the local from.
- * @param index The index of the local to get.
- * @return A pointer to the local at the given index.
- */
-PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index);
-
-/**
- * Free the internal memory associated with the options.
- *
- * @param options The options struct whose internal memory should be freed.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
-
-/**
- * Deserialize an options struct from the given binary string. This is used to
- * pass options to the parser from an FFI call so that consumers of the library
- * from an FFI perspective don't have to worry about the structure of our
- * options structs. Since the source of these calls will be from Ruby
- * implementation internals we assume it is from a trusted source.
- *
- * `data` is assumed to be a valid pointer pointing to well-formed data. The
- * layout of this data should be the same every time, and is described below:
- *
- * | # bytes | field |
- * | ------- | -------------------------- |
- * | `4` | the length of the filepath |
- * | ... | the filepath bytes |
- * | `4` | the line number |
- * | `4` | the length the encoding |
- * | ... | the encoding bytes |
- * | `1` | frozen string literal |
- * | `1` | suppress warnings |
- * | `4` | the number of scopes |
- * | ... | the scopes |
- *
- * Each scope is layed out as follows:
- *
- * | # bytes | field |
- * | ------- | -------------------------- |
- * | `4` | the number of locals |
- * | ... | the locals |
- *
- * Each local is layed out as follows:
- *
- * | # bytes | field |
- * | ------- | -------------------------- |
- * | `4` | the length of the local |
- * | ... | the local bytes |
- *
- * Some additional things to note about this layout:
- *
- * * The filepath can have a length of 0, in which case we'll consider it an
- * empty string.
- * * The line number should be 0-indexed.
- * * The encoding can have a length of 0, in which case we'll use the default
- * encoding (UTF-8). If it's not 0, it should correspond to a name of an
- * encoding that can be passed to `Encoding.find` in Ruby.
- * * The frozen string literal and suppress warnings fields are booleans, so
- * their values should be either 0 or 1.
- * * The number of scopes can be 0.
- *
- * @param options The options struct to deserialize into.
- * @param data The binary string to deserialize from.
- */
-void pm_options_read(pm_options_t *options, const char *data);
-
-#endif
diff --git a/prism/pack.c b/prism/pack.c
deleted file mode 100644
index d5bfc4d6fd..0000000000
--- a/prism/pack.c
+++ /dev/null
@@ -1,493 +0,0 @@
-#include "prism/pack.h"
-
-#include <stdbool.h>
-#include <errno.h>
-
-static uintmax_t
-strtoumaxc(const char **format);
-
-PRISM_EXPORTED_FUNCTION pm_pack_result
-pm_pack_parse(pm_pack_variant variant, const char **format, const char *format_end,
- pm_pack_type *type, pm_pack_signed *signed_type, pm_pack_endian *endian, pm_pack_size *size,
- pm_pack_length_type *length_type, uint64_t *length, pm_pack_encoding *encoding) {
-
- if (*encoding == PM_PACK_ENCODING_START) {
- *encoding = PM_PACK_ENCODING_US_ASCII;
- }
-
- if (*format == format_end) {
- *type = PM_PACK_END;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- *length_type = PM_PACK_LENGTH_NA;
- return PM_PACK_OK;
- }
-
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 1;
- bool length_changed_allowed = true;
-
- char directive = **format;
- (*format)++;
- switch (directive) {
- case ' ':
- case '\t':
- case '\n':
- case '\v':
- case '\f':
- case '\r':
- *type = PM_PACK_SPACE;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- *length_type = PM_PACK_LENGTH_NA;
- *length = 0;
- return PM_PACK_OK;
- case '#':
- while ((*format < format_end) && (**format != '\n')) {
- (*format)++;
- }
- *type = PM_PACK_COMMENT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- *length_type = PM_PACK_LENGTH_NA;
- *length = 0;
- return PM_PACK_OK;
- case 'C':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_AGNOSTIC_ENDIAN;
- *size = PM_PACK_SIZE_8;
- break;
- case 'S':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_16;
- break;
- case 'L':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'Q':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'J':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_P;
- break;
- case 'c':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_AGNOSTIC_ENDIAN;
- *size = PM_PACK_SIZE_8;
- break;
- case 's':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_16;
- break;
- case 'l':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'q':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'j':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_P;
- break;
- case 'I':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_INT;
- break;
- case 'i':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_INT;
- break;
- case 'n':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_16;
- length_changed_allowed = false;
- break;
- case 'N':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_32;
- length_changed_allowed = false;
- break;
- case 'v':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_16;
- length_changed_allowed = false;
- break;
- case 'V':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- length_changed_allowed = false;
- break;
- case 'U':
- *type = PM_PACK_UTF8;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'w':
- *type = PM_PACK_BER;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'D':
- case 'd':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'F':
- case 'f':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'E':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'e':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'G':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'g':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'A':
- *type = PM_PACK_STRING_SPACE_PADDED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'a':
- *type = PM_PACK_STRING_NULL_PADDED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'Z':
- *type = PM_PACK_STRING_NULL_TERMINATED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'B':
- *type = PM_PACK_STRING_MSB;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'b':
- *type = PM_PACK_STRING_LSB;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'H':
- *type = PM_PACK_STRING_HEX_HIGH;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'h':
- *type = PM_PACK_STRING_HEX_LOW;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'u':
- *type = PM_PACK_STRING_UU;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'M':
- *type = PM_PACK_STRING_MIME;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'm':
- *type = PM_PACK_STRING_BASE64;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'P':
- *type = PM_PACK_STRING_FIXED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'p':
- *type = PM_PACK_STRING_POINTER;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case '@':
- *type = PM_PACK_MOVE;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'X':
- *type = PM_PACK_BACK;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'x':
- *type = PM_PACK_NULL;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case '%':
- return PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE;
- default:
- return PM_PACK_ERROR_UNKNOWN_DIRECTIVE;
- }
-
- bool explicit_endian = false;
-
- while (*format < format_end) {
- switch (**format) {
- case '_':
- case '!':
- (*format)++;
- if (*type != PM_PACK_INTEGER || !length_changed_allowed) {
- return PM_PACK_ERROR_BANG_NOT_ALLOWED;
- }
- switch (*size) {
- case PM_PACK_SIZE_SHORT:
- case PM_PACK_SIZE_INT:
- case PM_PACK_SIZE_LONG:
- case PM_PACK_SIZE_LONG_LONG:
- break;
- case PM_PACK_SIZE_16:
- *size = PM_PACK_SIZE_SHORT;
- break;
- case PM_PACK_SIZE_32:
- *size = PM_PACK_SIZE_LONG;
- break;
- case PM_PACK_SIZE_64:
- *size = PM_PACK_SIZE_LONG_LONG;
- break;
- case PM_PACK_SIZE_P:
- break;
- default:
- return PM_PACK_ERROR_BANG_NOT_ALLOWED;
- }
- break;
- case '<':
- (*format)++;
- if (explicit_endian) {
- return PM_PACK_ERROR_DOUBLE_ENDIAN;
- }
- *endian = PM_PACK_LITTLE_ENDIAN;
- explicit_endian = true;
- break;
- case '>':
- (*format)++;
- if (explicit_endian) {
- return PM_PACK_ERROR_DOUBLE_ENDIAN;
- }
- *endian = PM_PACK_BIG_ENDIAN;
- explicit_endian = true;
- break;
- default:
- goto exit_modifier_loop;
- }
- }
-
-exit_modifier_loop:
-
- if (variant == PM_PACK_VARIANT_UNPACK && *type == PM_PACK_MOVE) {
- *length = 0;
- }
-
- if (*format < format_end) {
- if (**format == '*') {
- switch (*type) {
- case PM_PACK_NULL:
- case PM_PACK_BACK:
- switch (variant) {
- case PM_PACK_VARIANT_PACK:
- *length_type = PM_PACK_LENGTH_FIXED;
- break;
- case PM_PACK_VARIANT_UNPACK:
- *length_type = PM_PACK_LENGTH_MAX;
- break;
- }
- *length = 0;
- break;
-
- case PM_PACK_MOVE:
- switch (variant) {
- case PM_PACK_VARIANT_PACK:
- *length_type = PM_PACK_LENGTH_FIXED;
- break;
- case PM_PACK_VARIANT_UNPACK:
- *length_type = PM_PACK_LENGTH_RELATIVE;
- break;
- }
- *length = 0;
- break;
-
- case PM_PACK_STRING_UU:
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 0;
- break;
-
- case PM_PACK_STRING_FIXED:
- switch (variant) {
- case PM_PACK_VARIANT_PACK:
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 1;
- break;
- case PM_PACK_VARIANT_UNPACK:
- *length_type = PM_PACK_LENGTH_MAX;
- *length = 0;
- break;
- }
- break;
-
- case PM_PACK_STRING_MIME:
- case PM_PACK_STRING_BASE64:
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 1;
- break;
-
- default:
- *length_type = PM_PACK_LENGTH_MAX;
- *length = 0;
- break;
- }
-
- (*format)++;
- } else if (**format >= '0' && **format <= '9') {
- errno = 0;
- *length_type = PM_PACK_LENGTH_FIXED;
- #if UINTMAX_MAX < UINT64_MAX
- #error "prism's design assumes uintmax_t is at least as large as uint64_t"
- #endif
- uintmax_t length_max = strtoumaxc(format);
- if (errno || length_max > UINT64_MAX) {
- return PM_PACK_ERROR_LENGTH_TOO_BIG;
- }
- *length = (uint64_t) length_max;
- }
- }
-
- switch (*type) {
- case PM_PACK_UTF8:
- /* if encoding is US-ASCII, upgrade to UTF-8 */
- if (*encoding == PM_PACK_ENCODING_US_ASCII) {
- *encoding = PM_PACK_ENCODING_UTF_8;
- }
- break;
- case PM_PACK_STRING_MIME:
- case PM_PACK_STRING_BASE64:
- case PM_PACK_STRING_UU:
- /* keep US-ASCII (do nothing) */
- break;
- default:
- /* fall back to BINARY */
- *encoding = PM_PACK_ENCODING_ASCII_8BIT;
- break;
- }
-
- return PM_PACK_OK;
-}
-
-PRISM_EXPORTED_FUNCTION size_t
-pm_size_to_native(pm_pack_size size) {
- switch (size) {
- case PM_PACK_SIZE_SHORT:
- return sizeof(short);
- case PM_PACK_SIZE_INT:
- return sizeof(int);
- case PM_PACK_SIZE_LONG:
- return sizeof(long);
- case PM_PACK_SIZE_LONG_LONG:
- return sizeof(long long);
- case PM_PACK_SIZE_8:
- return 1;
- case PM_PACK_SIZE_16:
- return 2;
- case PM_PACK_SIZE_32:
- return 4;
- case PM_PACK_SIZE_64:
- return 8;
- case PM_PACK_SIZE_P:
- return sizeof(void *);
- default:
- return 0;
- }
-}
-
-static uintmax_t
-strtoumaxc(const char **format) {
- uintmax_t value = 0;
- while (**format >= '0' && **format <= '9') {
- if (value > UINTMAX_MAX / 10) {
- errno = ERANGE;
- }
- value = value * 10 + ((uintmax_t) (**format - '0'));
- (*format)++;
- }
- return value;
-}
diff --git a/prism/pack.h b/prism/pack.h
deleted file mode 100644
index e494848389..0000000000
--- a/prism/pack.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * @file pack.h
- *
- * A pack template string parser.
- */
-#ifndef PRISM_PACK_H
-#define PRISM_PACK_H
-
-#include "prism/defines.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-
-/** The version of the pack template language that we are parsing. */
-typedef enum pm_pack_version {
- PM_PACK_VERSION_3_2_0
-} pm_pack_version;
-
-/** The type of pack template we are parsing. */
-typedef enum pm_pack_variant {
- PM_PACK_VARIANT_PACK,
- PM_PACK_VARIANT_UNPACK
-} pm_pack_variant;
-
-/** A directive within the pack template. */
-typedef enum pm_pack_type {
- PM_PACK_SPACE,
- PM_PACK_COMMENT,
- PM_PACK_INTEGER,
- PM_PACK_UTF8,
- PM_PACK_BER,
- PM_PACK_FLOAT,
- PM_PACK_STRING_SPACE_PADDED,
- PM_PACK_STRING_NULL_PADDED,
- PM_PACK_STRING_NULL_TERMINATED,
- PM_PACK_STRING_MSB,
- PM_PACK_STRING_LSB,
- PM_PACK_STRING_HEX_HIGH,
- PM_PACK_STRING_HEX_LOW,
- PM_PACK_STRING_UU,
- PM_PACK_STRING_MIME,
- PM_PACK_STRING_BASE64,
- PM_PACK_STRING_FIXED,
- PM_PACK_STRING_POINTER,
- PM_PACK_MOVE,
- PM_PACK_BACK,
- PM_PACK_NULL,
- PM_PACK_END
-} pm_pack_type;
-
-/** The signness of a pack directive. */
-typedef enum pm_pack_signed {
- PM_PACK_UNSIGNED,
- PM_PACK_SIGNED,
- PM_PACK_SIGNED_NA
-} pm_pack_signed;
-
-/** The endianness of a pack directive. */
-typedef enum pm_pack_endian {
- PM_PACK_AGNOSTIC_ENDIAN,
- PM_PACK_LITTLE_ENDIAN, // aka 'VAX', or 'V'
- PM_PACK_BIG_ENDIAN, // aka 'network', or 'N'
- PM_PACK_NATIVE_ENDIAN,
- PM_PACK_ENDIAN_NA
-} pm_pack_endian;
-
-/** The size of an integer pack directive. */
-typedef enum pm_pack_size {
- PM_PACK_SIZE_SHORT,
- PM_PACK_SIZE_INT,
- PM_PACK_SIZE_LONG,
- PM_PACK_SIZE_LONG_LONG,
- PM_PACK_SIZE_8,
- PM_PACK_SIZE_16,
- PM_PACK_SIZE_32,
- PM_PACK_SIZE_64,
- PM_PACK_SIZE_P,
- PM_PACK_SIZE_NA
-} pm_pack_size;
-
-/** The type of length of a pack directive. */
-typedef enum pm_pack_length_type {
- PM_PACK_LENGTH_FIXED,
- PM_PACK_LENGTH_MAX,
- PM_PACK_LENGTH_RELATIVE, // special case for unpack @*
- PM_PACK_LENGTH_NA
-} pm_pack_length_type;
-
-/** The type of encoding for a pack template string. */
-typedef enum pm_pack_encoding {
- PM_PACK_ENCODING_START,
- PM_PACK_ENCODING_ASCII_8BIT,
- PM_PACK_ENCODING_US_ASCII,
- PM_PACK_ENCODING_UTF_8
-} pm_pack_encoding;
-
-/** The result of parsing a pack template. */
-typedef enum pm_pack_result {
- PM_PACK_OK,
- PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE,
- PM_PACK_ERROR_UNKNOWN_DIRECTIVE,
- PM_PACK_ERROR_LENGTH_TOO_BIG,
- PM_PACK_ERROR_BANG_NOT_ALLOWED,
- PM_PACK_ERROR_DOUBLE_ENDIAN
-} pm_pack_result;
-
-/**
- * Parse a single directive from a pack or unpack format string.
- *
- * @param variant (in) pack or unpack
- * @param format (in, out) the start of the next directive to parse on calling,
- * and advanced beyond the parsed directive on return, or as much of it as
- * was consumed until an error was encountered
- * @param format_end (in) the end of the format string
- * @param type (out) the type of the directive
- * @param signed_type (out) whether the value is signed
- * @param endian (out) the endianness of the value
- * @param size (out) the size of the value
- * @param length_type (out) what kind of length is specified
- * @param length (out) the length of the directive
- * @param encoding (in, out) takes the current encoding of the string which
- * would result from parsing the whole format string, and returns a possibly
- * changed directive - the encoding should be `PM_PACK_ENCODING_START` when
- * pm_pack_parse is called for the first directive in a format string
- *
- * @return `PM_PACK_OK` on success or `PM_PACK_ERROR_*` on error
- * @note Consult Ruby documentation for the meaning of directives.
- */
-PRISM_EXPORTED_FUNCTION pm_pack_result
-pm_pack_parse(
- pm_pack_variant variant,
- const char **format,
- const char *format_end,
- pm_pack_type *type,
- pm_pack_signed *signed_type,
- pm_pack_endian *endian,
- pm_pack_size *size,
- pm_pack_length_type *length_type,
- uint64_t *length,
- pm_pack_encoding *encoding
-);
-
-/**
- * Prism abstracts sizes away from the native system - this converts an abstract
- * size to a native size.
- *
- * @param size The abstract size to convert.
- * @return The native size.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_size_to_native(pm_pack_size size);
-
-#endif
diff --git a/prism/parser.h b/prism/parser.h
deleted file mode 100644
index edefe70f25..0000000000
--- a/prism/parser.h
+++ /dev/null
@@ -1,690 +0,0 @@
-/**
- * @file parser.h
- *
- * The parser used to parse Ruby source.
- */
-#ifndef PRISM_PARSER_H
-#define PRISM_PARSER_H
-
-#include "prism/ast.h"
-#include "prism/defines.h"
-#include "prism/enc/pm_encoding.h"
-#include "prism/util/pm_constant_pool.h"
-#include "prism/util/pm_list.h"
-#include "prism/util/pm_newline_list.h"
-#include "prism/util/pm_state_stack.h"
-#include "prism/util/pm_string.h"
-
-#include <stdbool.h>
-
-/**
- * This enum provides various bits that represent different kinds of states that
- * the lexer can track. This is used to determine which kind of token to return
- * based on the context of the parser.
- */
-typedef enum {
- PM_LEX_STATE_BIT_BEG,
- PM_LEX_STATE_BIT_END,
- PM_LEX_STATE_BIT_ENDARG,
- PM_LEX_STATE_BIT_ENDFN,
- PM_LEX_STATE_BIT_ARG,
- PM_LEX_STATE_BIT_CMDARG,
- PM_LEX_STATE_BIT_MID,
- PM_LEX_STATE_BIT_FNAME,
- PM_LEX_STATE_BIT_DOT,
- PM_LEX_STATE_BIT_CLASS,
- PM_LEX_STATE_BIT_LABEL,
- PM_LEX_STATE_BIT_LABELED,
- PM_LEX_STATE_BIT_FITEM
-} pm_lex_state_bit_t;
-
-/**
- * This enum combines the various bits from the above enum into individual
- * values that represent the various states of the lexer.
- */
-typedef enum {
- PM_LEX_STATE_NONE = 0,
- PM_LEX_STATE_BEG = (1 << PM_LEX_STATE_BIT_BEG),
- PM_LEX_STATE_END = (1 << PM_LEX_STATE_BIT_END),
- PM_LEX_STATE_ENDARG = (1 << PM_LEX_STATE_BIT_ENDARG),
- PM_LEX_STATE_ENDFN = (1 << PM_LEX_STATE_BIT_ENDFN),
- PM_LEX_STATE_ARG = (1 << PM_LEX_STATE_BIT_ARG),
- PM_LEX_STATE_CMDARG = (1 << PM_LEX_STATE_BIT_CMDARG),
- PM_LEX_STATE_MID = (1 << PM_LEX_STATE_BIT_MID),
- PM_LEX_STATE_FNAME = (1 << PM_LEX_STATE_BIT_FNAME),
- PM_LEX_STATE_DOT = (1 << PM_LEX_STATE_BIT_DOT),
- PM_LEX_STATE_CLASS = (1 << PM_LEX_STATE_BIT_CLASS),
- PM_LEX_STATE_LABEL = (1 << PM_LEX_STATE_BIT_LABEL),
- PM_LEX_STATE_LABELED = (1 << PM_LEX_STATE_BIT_LABELED),
- PM_LEX_STATE_FITEM = (1 << PM_LEX_STATE_BIT_FITEM),
- PM_LEX_STATE_BEG_ANY = PM_LEX_STATE_BEG | PM_LEX_STATE_MID | PM_LEX_STATE_CLASS,
- PM_LEX_STATE_ARG_ANY = PM_LEX_STATE_ARG | PM_LEX_STATE_CMDARG,
- PM_LEX_STATE_END_ANY = PM_LEX_STATE_END | PM_LEX_STATE_ENDARG | PM_LEX_STATE_ENDFN
-} pm_lex_state_t;
-
-/**
- * The type of quote that a heredoc uses.
- */
-typedef enum {
- PM_HEREDOC_QUOTE_NONE,
- PM_HEREDOC_QUOTE_SINGLE = '\'',
- PM_HEREDOC_QUOTE_DOUBLE = '"',
- PM_HEREDOC_QUOTE_BACKTICK = '`',
-} pm_heredoc_quote_t;
-
-/**
- * The type of indentation that a heredoc uses.
- */
-typedef enum {
- PM_HEREDOC_INDENT_NONE,
- PM_HEREDOC_INDENT_DASH,
- PM_HEREDOC_INDENT_TILDE,
-} pm_heredoc_indent_t;
-
-/**
- * When lexing Ruby source, the lexer has a small amount of state to tell which
- * kind of token it is currently lexing. For example, when we find the start of
- * a string, the first token that we return is a TOKEN_STRING_BEGIN token. After
- * that the lexer is now in the PM_LEX_STRING mode, and will return tokens that
- * are found as part of a string.
- */
-typedef struct pm_lex_mode {
- /** The type of this lex mode. */
- enum {
- /** This state is used when any given token is being lexed. */
- PM_LEX_DEFAULT,
-
- /**
- * This state is used when we're lexing as normal but inside an embedded
- * expression of a string.
- */
- PM_LEX_EMBEXPR,
-
- /**
- * This state is used when we're lexing a variable that is embedded
- * directly inside of a string with the # shorthand.
- */
- PM_LEX_EMBVAR,
-
- /** This state is used when you are inside the content of a heredoc. */
- PM_LEX_HEREDOC,
-
- /**
- * This state is used when we are lexing a list of tokens, as in a %w
- * word list literal or a %i symbol list literal.
- */
- PM_LEX_LIST,
-
- /**
- * This state is used when a regular expression has been begun and we
- * are looking for the terminator.
- */
- PM_LEX_REGEXP,
-
- /**
- * This state is used when we are lexing a string or a string-like
- * token, as in string content with either quote or an xstring.
- */
- PM_LEX_STRING
- } mode;
-
- /** The data associated with this type of lex mode. */
- union {
- struct {
- /** This keeps track of the nesting level of the list. */
- size_t nesting;
-
- /** Whether or not interpolation is allowed in this list. */
- bool interpolation;
-
- /**
- * When lexing a list, it takes into account balancing the
- * terminator if the terminator is one of (), [], {}, or <>.
- */
- uint8_t incrementor;
-
- /** This is the terminator of the list literal. */
- uint8_t terminator;
-
- /**
- * This is the character set that should be used to delimit the
- * tokens within the list.
- */
- uint8_t breakpoints[11];
- } list;
-
- struct {
- /**
- * This keeps track of the nesting level of the regular expression.
- */
- size_t nesting;
-
- /**
- * When lexing a regular expression, it takes into account balancing
- * the terminator if the terminator is one of (), [], {}, or <>.
- */
- uint8_t incrementor;
-
- /** This is the terminator of the regular expression. */
- uint8_t terminator;
-
- /**
- * This is the character set that should be used to delimit the
- * tokens within the regular expression.
- */
- uint8_t breakpoints[6];
- } regexp;
-
- struct {
- /** This keeps track of the nesting level of the string. */
- size_t nesting;
-
- /** Whether or not interpolation is allowed in this string. */
- bool interpolation;
-
- /**
- * Whether or not at the end of the string we should allow a :,
- * which would indicate this was a dynamic symbol instead of a
- * string.
- */
- bool label_allowed;
-
- /**
- * When lexing a string, it takes into account balancing the
- * terminator if the terminator is one of (), [], {}, or <>.
- */
- uint8_t incrementor;
-
- /**
- * This is the terminator of the string. It is typically either a
- * single or double quote.
- */
- uint8_t terminator;
-
- /**
- * This is the character set that should be used to delimit the
- * tokens within the string.
- */
- uint8_t breakpoints[6];
- } string;
-
- struct {
- /** A pointer to the start of the heredoc identifier. */
- const uint8_t *ident_start;
-
- /** The length of the heredoc identifier. */
- size_t ident_length;
-
- /** The type of quote that the heredoc uses. */
- pm_heredoc_quote_t quote;
-
- /** The type of indentation that the heredoc uses. */
- pm_heredoc_indent_t indent;
-
- /**
- * This is the pointer to the character where lexing should resume
- * once the heredoc has been completely processed.
- */
- const uint8_t *next_start;
-
- /**
- * This is used to track the amount of common whitespace on each
- * line so that we know how much to dedent each line in the case of
- * a tilde heredoc.
- */
- size_t common_whitespace;
- } heredoc;
- } as;
-
- /** The previous lex state so that it knows how to pop. */
- struct pm_lex_mode *prev;
-} pm_lex_mode_t;
-
-/**
- * We pre-allocate a certain number of lex states in order to avoid having to
- * call malloc too many times while parsing. You really shouldn't need more than
- * this because you only really nest deeply when doing string interpolation.
- */
-#define PM_LEX_STACK_SIZE 4
-
-/**
- * The parser used to parse Ruby source.
- */
-typedef struct pm_parser pm_parser_t;
-
-/**
- * While parsing, we keep track of a stack of contexts. This is helpful for
- * error recovery so that we can pop back to a previous context when we hit a
- * token that is understood by a parent context but not by the current context.
- */
-typedef enum {
- /** a begin statement */
- PM_CONTEXT_BEGIN,
-
- /** expressions in block arguments using braces */
- PM_CONTEXT_BLOCK_BRACES,
-
- /** expressions in block arguments using do..end */
- PM_CONTEXT_BLOCK_KEYWORDS,
-
- /** a case when statements */
- PM_CONTEXT_CASE_WHEN,
-
- /** a case in statements */
- PM_CONTEXT_CASE_IN,
-
- /** a class declaration */
- PM_CONTEXT_CLASS,
-
- /** a method definition */
- PM_CONTEXT_DEF,
-
- /** a method definition's parameters */
- PM_CONTEXT_DEF_PARAMS,
-
- /** a method definition's default parameter */
- PM_CONTEXT_DEFAULT_PARAMS,
-
- /** an else clause */
- PM_CONTEXT_ELSE,
-
- /** an elsif clause */
- PM_CONTEXT_ELSIF,
-
- /** an interpolated expression */
- PM_CONTEXT_EMBEXPR,
-
- /** an ensure statement */
- PM_CONTEXT_ENSURE,
-
- /** a for loop */
- PM_CONTEXT_FOR,
-
- /** a for loop's index */
- PM_CONTEXT_FOR_INDEX,
-
- /** an if statement */
- PM_CONTEXT_IF,
-
- /** a lambda expression with braces */
- PM_CONTEXT_LAMBDA_BRACES,
-
- /** a lambda expression with do..end */
- PM_CONTEXT_LAMBDA_DO_END,
-
- /** the top level context */
- PM_CONTEXT_MAIN,
-
- /** a module declaration */
- PM_CONTEXT_MODULE,
-
- /** a parenthesized expression */
- PM_CONTEXT_PARENS,
-
- /** an END block */
- PM_CONTEXT_POSTEXE,
-
- /** a predicate inside an if/elsif/unless statement */
- PM_CONTEXT_PREDICATE,
-
- /** a BEGIN block */
- PM_CONTEXT_PREEXE,
-
- /** a rescue else statement */
- PM_CONTEXT_RESCUE_ELSE,
-
- /** a rescue statement */
- PM_CONTEXT_RESCUE,
-
- /** a singleton class definition */
- PM_CONTEXT_SCLASS,
-
- /** an unless statement */
- PM_CONTEXT_UNLESS,
-
- /** an until statement */
- PM_CONTEXT_UNTIL,
-
- /** a while statement */
- PM_CONTEXT_WHILE,
-} pm_context_t;
-
-/** This is a node in a linked list of contexts. */
-typedef struct pm_context_node {
- /** The context that this node represents. */
- pm_context_t context;
-
- /** A pointer to the previous context in the linked list. */
- struct pm_context_node *prev;
-} pm_context_node_t;
-
-/** This is the type of a comment that we've found while parsing. */
-typedef enum {
- PM_COMMENT_INLINE,
- PM_COMMENT_EMBDOC,
- PM_COMMENT___END__
-} pm_comment_type_t;
-
-/**
- * This is a node in the linked list of comments that we've found while parsing.
- *
- * @extends pm_list_node_t
- */
-typedef struct pm_comment {
- /** The embedded base node. */
- pm_list_node_t node;
-
- /** A pointer to the start of the comment in the source. */
- const uint8_t *start;
-
- /** A pointer to the end of the comment in the source. */
- const uint8_t *end;
-
- /** The type of comment that we've found. */
- pm_comment_type_t type;
-} pm_comment_t;
-
-/**
- * This is a node in the linked list of magic comments that we've found while
- * parsing.
- *
- * @extends pm_list_node_t
- */
-typedef struct {
- /** The embedded base node. */
- pm_list_node_t node;
-
- /** A pointer to the start of the key in the source. */
- const uint8_t *key_start;
-
- /** A pointer to the start of the value in the source. */
- const uint8_t *value_start;
-
- /** The length of the key in the source. */
- uint32_t key_length;
-
- /** The length of the value in the source. */
- uint32_t value_length;
-} pm_magic_comment_t;
-
-/**
- * When the encoding that is being used to parse the source is changed by prism,
- * we provide the ability here to call out to a user-defined function.
- */
-typedef void (*pm_encoding_changed_callback_t)(pm_parser_t *parser);
-
-/**
- * When an encoding is encountered that isn't understood by prism, we provide
- * the ability here to call out to a user-defined function to get an encoding
- * struct. If the function returns something that isn't NULL, we set that to
- * our encoding and use it to parse identifiers.
- */
-typedef pm_encoding_t *(*pm_encoding_decode_callback_t)(pm_parser_t *parser, const uint8_t *name, size_t width);
-
-/**
- * When you are lexing through a file, the lexer needs all of the information
- * that the parser additionally provides (for example, the local table). So if
- * you want to properly lex Ruby, you need to actually lex it in the context of
- * the parser. In order to provide this functionality, we optionally allow a
- * struct to be attached to the parser that calls back out to a user-provided
- * callback when each token is lexed.
- */
-typedef struct {
- /**
- * This opaque pointer is used to provide whatever information the user
- * deemed necessary to the callback. In our case we use it to pass the array
- * that the tokens get appended into.
- */
- void *data;
-
- /**
- * This is the callback that is called when a token is lexed. It is passed
- * the opaque data pointer, the parser, and the token that was lexed.
- */
- void (*callback)(void *data, pm_parser_t *parser, pm_token_t *token);
-} pm_lex_callback_t;
-
-/**
- * This struct represents a node in a linked list of scopes. Some scopes can see
- * into their parent scopes, while others cannot.
- */
-typedef struct pm_scope {
- /** The IDs of the locals in the given scope. */
- pm_constant_id_list_t locals;
-
- /** A pointer to the previous scope in the linked list. */
- struct pm_scope *previous;
-
- /**
- * A boolean indicating whether or not this scope can see into its parent.
- * If closed is true, then the scope cannot see into its parent.
- */
- bool closed;
-
- /**
- * A boolean indicating whether or not this scope has explicit parameters.
- * This is necessary to determine whether or not numbered parameters are
- * allowed.
- */
- bool explicit_params;
-
- /**
- * A boolean indicating whether or not this scope has numbered parameters.
- * This is necessary to determine if child blocks are allowed to use
- * numbered parameters.
- */
- bool numbered_params;
-
- /**
- * A transparent scope is a scope that cannot have locals set on itself.
- * When a local is set on this scope, it will instead be set on the parent
- * scope's local table.
- */
- bool transparent;
-} pm_scope_t;
-
-/**
- * This struct represents the overall parser. It contains a reference to the
- * source file, as well as pointers that indicate where in the source it's
- * currently parsing. It also contains the most recent and current token that
- * it's considering.
- */
-struct pm_parser {
- /** The current state of the lexer. */
- pm_lex_state_t lex_state;
-
- /** Tracks the current nesting of (), [], and {}. */
- int enclosure_nesting;
-
- /**
- * Used to temporarily track the nesting of enclosures to determine if a {
- * is the beginning of a lambda following the parameters of a lambda.
- */
- int lambda_enclosure_nesting;
-
- /**
- * Used to track the nesting of braces to ensure we get the correct value
- * when we are interpolating blocks with braces.
- */
- int brace_nesting;
-
- /**
- * The stack used to determine if a do keyword belongs to the predicate of a
- * while, until, or for loop.
- */
- pm_state_stack_t do_loop_stack;
-
- /**
- * The stack used to determine if a do keyword belongs to the beginning of a
- * block.
- */
- pm_state_stack_t accepts_block_stack;
-
- /** A stack of lex modes. */
- struct {
- /** The current mode of the lexer. */
- pm_lex_mode_t *current;
-
- /** The stack of lexer modes. */
- pm_lex_mode_t stack[PM_LEX_STACK_SIZE];
-
- /** The current index into the lexer mode stack. */
- size_t index;
- } lex_modes;
-
- /** The pointer to the start of the source. */
- const uint8_t *start;
-
- /** The pointer to the end of the source. */
- const uint8_t *end;
-
- /** The previous token we were considering. */
- pm_token_t previous;
-
- /** The current token we're considering. */
- pm_token_t current;
-
- /**
- * This is a special field set on the parser when we need the parser to jump
- * to a specific location when lexing the next token, as opposed to just
- * using the end of the previous token. Normally this is NULL.
- */
- const uint8_t *next_start;
-
- /**
- * This field indicates the end of a heredoc whose identifier was found on
- * the current line. If another heredoc is found on the same line, then this
- * will be moved forward to the end of that heredoc. If no heredocs are
- * found on a line then this is NULL.
- */
- const uint8_t *heredoc_end;
-
- /** The list of comments that have been found while parsing. */
- pm_list_t comment_list;
-
- /** The list of magic comments that have been found while parsing. */
- pm_list_t magic_comment_list;
-
- /** The list of warnings that have been found while parsing. */
- pm_list_t warning_list;
-
- /** The list of errors that have been found while parsing. */
- pm_list_t error_list;
-
- /** The current local scope. */
- pm_scope_t *current_scope;
-
- /** The current parsing context. */
- pm_context_node_t *current_context;
-
- /**
- * The encoding functions for the current file is attached to the parser as
- * it's parsing so that it can change with a magic comment.
- */
- pm_encoding_t encoding;
-
- /**
- * When the encoding that is being used to parse the source is changed by
- * prism, we provide the ability here to call out to a user-defined
- * function.
- */
- pm_encoding_changed_callback_t encoding_changed_callback;
-
- /**
- * When an encoding is encountered that isn't understood by prism, we
- * provide the ability here to call out to a user-defined function to get an
- * encoding struct. If the function returns something that isn't NULL, we
- * set that to our encoding and use it to parse identifiers.
- */
- pm_encoding_decode_callback_t encoding_decode_callback;
-
- /**
- * This pointer indicates where a comment must start if it is to be
- * considered an encoding comment.
- */
- const uint8_t *encoding_comment_start;
-
- /**
- * This is an optional callback that can be attached to the parser that will
- * be called whenever a new token is lexed by the parser.
- */
- pm_lex_callback_t *lex_callback;
-
- /**
- * This is the path of the file being parsed. We use the filepath when
- * constructing SourceFileNodes.
- */
- pm_string_t filepath_string;
-
- /**
- * This constant pool keeps all of the constants defined throughout the file
- * so that we can reference them later.
- */
- pm_constant_pool_t constant_pool;
-
- /** This is the list of newline offsets in the source file. */
- pm_newline_list_t newline_list;
-
- /**
- * We want to add a flag to integer nodes that indicates their base. We only
- * want to parse these once, but we don't have space on the token itself to
- * communicate this information. So we store it here and pass it through
- * when we find tokens that we need it for.
- */
- pm_node_flags_t integer_base;
-
- /**
- * This string is used to pass information from the lexer to the parser. It
- * is particularly necessary because of escape sequences.
- */
- pm_string_t current_string;
-
- /**
- * The line number at the start of the parse. This will be used to offset
- * the line numbers of all of the locations.
- */
- uint32_t start_line;
-
- /** Whether or not we're at the beginning of a command. */
- bool command_start;
-
- /** Whether or not we're currently recovering from a syntax error. */
- bool recovering;
-
- /**
- * Whether or not the encoding has been changed by a magic comment. We use
- * this to provide a fast path for the lexer instead of going through the
- * function pointer.
- */
- bool encoding_changed;
-
- /**
- * This flag indicates that we are currently parsing a pattern matching
- * expression and impacts that calculation of newlines.
- */
- bool pattern_matching_newlines;
-
- /** This flag indicates that we are currently parsing a keyword argument. */
- bool in_keyword_arg;
-
- /**
- * Whether or not the parser has seen a token that has semantic meaning
- * (i.e., a token that is not a comment or whitespace).
- */
- bool semantic_token_seen;
-
- /**
- * Whether or not we have found a frozen_string_literal magic comment with
- * a true value.
- */
- bool frozen_string_literal;
-
- /**
- * Whether or not we should emit warnings. This will be set to false if the
- * consumer of the library specified it, usually because they are parsing
- * when $VERBOSE is nil.
- */
- bool suppress_warnings;
-};
-
-#endif
diff --git a/prism/prettyprint.h b/prism/prettyprint.h
deleted file mode 100644
index 351b92df39..0000000000
--- a/prism/prettyprint.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * @file prettyprint.h
- *
- * An AST node pretty-printer.
- */
-#ifndef PRISM_PRETTYPRINT_H
-#define PRISM_PRETTYPRINT_H
-
-#include "prism/defines.h"
-
-#include <stdio.h>
-
-#include "prism/ast.h"
-#include "prism/parser.h"
-#include "prism/util/pm_buffer.h"
-
-/**
- * Pretty-prints the AST represented by the given node to the given buffer.
- *
- * @param output_buffer The buffer to write the pretty-printed AST to.
- * @param parser The parser that parsed the AST.
- * @param node The root node of the AST to pretty-print.
- */
-PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node);
-
-#endif
diff --git a/prism/prism.c b/prism/prism.c
deleted file mode 100644
index cbf0d19356..0000000000
--- a/prism/prism.c
+++ /dev/null
@@ -1,16543 +0,0 @@
-#include "prism.h"
-
-/**
- * The prism version and the serialization format.
- */
-const char *
-pm_version(void) {
- return PRISM_VERSION;
-}
-
-/**
- * In heredocs, tabs automatically complete up to the next 8 spaces. This is
- * defined in CRuby as TAB_WIDTH.
- */
-#define PM_TAB_WHITESPACE_SIZE 8
-
-#ifndef PM_DEBUG_LOGGING
-/**
- * Debugging logging will provide you will additional debugging functions as
- * well as automatically replace some functions with their debugging
- * counterparts.
- */
-#define PM_DEBUG_LOGGING 0
-#endif
-
-#if PM_DEBUG_LOGGING
-
-/******************************************************************************/
-/* Debugging */
-/******************************************************************************/
-
-PRISM_ATTRIBUTE_UNUSED static const char *
-debug_context(pm_context_t context) {
- switch (context) {
- case PM_CONTEXT_BEGIN: return "BEGIN";
- case PM_CONTEXT_CLASS: return "CLASS";
- case PM_CONTEXT_CASE_IN: return "CASE_IN";
- case PM_CONTEXT_CASE_WHEN: return "CASE_WHEN";
- case PM_CONTEXT_DEF: return "DEF";
- case PM_CONTEXT_DEF_PARAMS: return "DEF_PARAMS";
- case PM_CONTEXT_DEFAULT_PARAMS: return "DEFAULT_PARAMS";
- case PM_CONTEXT_ENSURE: return "ENSURE";
- case PM_CONTEXT_ELSE: return "ELSE";
- case PM_CONTEXT_ELSIF: return "ELSIF";
- case PM_CONTEXT_EMBEXPR: return "EMBEXPR";
- case PM_CONTEXT_BLOCK_BRACES: return "BLOCK_BRACES";
- case PM_CONTEXT_BLOCK_KEYWORDS: return "BLOCK_KEYWORDS";
- case PM_CONTEXT_FOR: return "FOR";
- case PM_CONTEXT_FOR_INDEX: return "FOR_INDEX";
- case PM_CONTEXT_IF: return "IF";
- case PM_CONTEXT_MAIN: return "MAIN";
- case PM_CONTEXT_MODULE: return "MODULE";
- case PM_CONTEXT_PARENS: return "PARENS";
- case PM_CONTEXT_POSTEXE: return "POSTEXE";
- case PM_CONTEXT_PREDICATE: return "PREDICATE";
- case PM_CONTEXT_PREEXE: return "PREEXE";
- case PM_CONTEXT_RESCUE: return "RESCUE";
- case PM_CONTEXT_RESCUE_ELSE: return "RESCUE_ELSE";
- case PM_CONTEXT_SCLASS: return "SCLASS";
- case PM_CONTEXT_UNLESS: return "UNLESS";
- case PM_CONTEXT_UNTIL: return "UNTIL";
- case PM_CONTEXT_WHILE: return "WHILE";
- case PM_CONTEXT_LAMBDA_BRACES: return "LAMBDA_BRACES";
- case PM_CONTEXT_LAMBDA_DO_END: return "LAMBDA_DO_END";
- }
- return NULL;
-}
-
-PRISM_ATTRIBUTE_UNUSED static void
-debug_contexts(pm_parser_t *parser) {
- pm_context_node_t *context_node = parser->current_context;
- fprintf(stderr, "CONTEXTS: ");
-
- if (context_node != NULL) {
- while (context_node != NULL) {
- fprintf(stderr, "%s", debug_context(context_node->context));
- context_node = context_node->prev;
- if (context_node != NULL) {
- fprintf(stderr, " <- ");
- }
- }
- } else {
- fprintf(stderr, "NONE");
- }
-
- fprintf(stderr, "\n");
-}
-
-PRISM_ATTRIBUTE_UNUSED static void
-debug_node(const pm_parser_t *parser, const pm_node_t *node) {
- pm_buffer_t output_buffer = { 0 };
- pm_prettyprint(&output_buffer, parser, node);
-
- fprintf(stderr, "%.*s", (int) output_buffer.length, output_buffer.value);
- pm_buffer_free(&output_buffer);
-}
-
-PRISM_ATTRIBUTE_UNUSED static void
-debug_lex_mode(pm_parser_t *parser) {
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- bool first = true;
-
- while (lex_mode != NULL) {
- if (first) {
- first = false;
- } else {
- fprintf(stderr, " <- ");
- }
-
- switch (lex_mode->mode) {
- case PM_LEX_DEFAULT: fprintf(stderr, "DEFAULT"); break;
- case PM_LEX_EMBEXPR: fprintf(stderr, "EMBEXPR"); break;
- case PM_LEX_EMBVAR: fprintf(stderr, "EMBVAR"); break;
- case PM_LEX_HEREDOC: fprintf(stderr, "HEREDOC"); break;
- case PM_LEX_LIST: fprintf(stderr, "LIST (terminator=%c, interpolation=%d)", lex_mode->as.list.terminator, lex_mode->as.list.interpolation); break;
- case PM_LEX_REGEXP: fprintf(stderr, "REGEXP (terminator=%c)", lex_mode->as.regexp.terminator); break;
- case PM_LEX_STRING: fprintf(stderr, "STRING (terminator=%c, interpolation=%d)", lex_mode->as.string.terminator, lex_mode->as.string.interpolation); break;
- }
-
- lex_mode = lex_mode->prev;
- }
-
- fprintf(stderr, "\n");
-}
-
-PRISM_ATTRIBUTE_UNUSED static void
-debug_state(pm_parser_t *parser) {
- fprintf(stderr, "STATE: ");
- bool first = true;
-
- if (parser->lex_state == PM_LEX_STATE_NONE) {
- fprintf(stderr, "NONE\n");
- return;
- }
-
-#define CHECK_STATE(state) \
- if (parser->lex_state & state) { \
- if (!first) fprintf(stderr, "|"); \
- fprintf(stderr, "%s", #state); \
- first = false; \
- }
-
- CHECK_STATE(PM_LEX_STATE_BEG)
- CHECK_STATE(PM_LEX_STATE_END)
- CHECK_STATE(PM_LEX_STATE_ENDARG)
- CHECK_STATE(PM_LEX_STATE_ENDFN)
- CHECK_STATE(PM_LEX_STATE_ARG)
- CHECK_STATE(PM_LEX_STATE_CMDARG)
- CHECK_STATE(PM_LEX_STATE_MID)
- CHECK_STATE(PM_LEX_STATE_FNAME)
- CHECK_STATE(PM_LEX_STATE_DOT)
- CHECK_STATE(PM_LEX_STATE_CLASS)
- CHECK_STATE(PM_LEX_STATE_LABEL)
- CHECK_STATE(PM_LEX_STATE_LABELED)
- CHECK_STATE(PM_LEX_STATE_FITEM)
-
-#undef CHECK_STATE
-
- fprintf(stderr, "\n");
-}
-
-PRISM_ATTRIBUTE_UNUSED static void
-debug_token(pm_token_t * token) {
- fprintf(stderr, "%s: \"%.*s\"\n", pm_token_type_to_str(token->type), (int) (token->end - token->start), token->start);
-}
-
-#endif
-
-// Macros for min/max.
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
-/******************************************************************************/
-/* Lex mode manipulations */
-/******************************************************************************/
-
-/**
- * Returns the incrementor character that should be used to increment the
- * nesting count if one is possible.
- */
-static inline uint8_t
-lex_mode_incrementor(const uint8_t start) {
- switch (start) {
- case '(':
- case '[':
- case '{':
- case '<':
- return start;
- default:
- return '\0';
- }
-}
-
-/**
- * Returns the matching character that should be used to terminate a list
- * beginning with the given character.
- */
-static inline uint8_t
-lex_mode_terminator(const uint8_t start) {
- switch (start) {
- case '(':
- return ')';
- case '[':
- return ']';
- case '{':
- return '}';
- case '<':
- return '>';
- default:
- return start;
- }
-}
-
-/**
- * Push a new lex state onto the stack. If we're still within the pre-allocated
- * space of the lex state stack, then we'll just use a new slot. Otherwise we'll
- * allocate a new pointer and use that.
- */
-static bool
-lex_mode_push(pm_parser_t *parser, pm_lex_mode_t lex_mode) {
- lex_mode.prev = parser->lex_modes.current;
- parser->lex_modes.index++;
-
- if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
- parser->lex_modes.current = (pm_lex_mode_t *) malloc(sizeof(pm_lex_mode_t));
- if (parser->lex_modes.current == NULL) return false;
-
- *parser->lex_modes.current = lex_mode;
- } else {
- parser->lex_modes.stack[parser->lex_modes.index] = lex_mode;
- parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
- }
-
- return true;
-}
-
-/**
- * Push on a new list lex mode.
- */
-static inline bool
-lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) {
- uint8_t incrementor = lex_mode_incrementor(delimiter);
- uint8_t terminator = lex_mode_terminator(delimiter);
-
- pm_lex_mode_t lex_mode = {
- .mode = PM_LEX_LIST,
- .as.list = {
- .nesting = 0,
- .interpolation = interpolation,
- .incrementor = incrementor,
- .terminator = terminator
- }
- };
-
- // These are the places where we need to split up the content of the list.
- // We'll use strpbrk to find the first of these characters.
- uint8_t *breakpoints = lex_mode.as.list.breakpoints;
- memcpy(breakpoints, "\\ \t\f\r\v\n\0\0\0", sizeof(lex_mode.as.list.breakpoints));
-
- // Now we'll add the terminator to the list of breakpoints.
- size_t index = 7;
- breakpoints[index++] = terminator;
-
- // If interpolation is allowed, then we're going to check for the #
- // character. Otherwise we'll only look for escapes and the terminator.
- if (interpolation) {
- breakpoints[index++] = '#';
- }
-
- // If there is an incrementor, then we'll check for that as well.
- if (incrementor != '\0') {
- breakpoints[index++] = incrementor;
- }
-
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Push on a new regexp lex mode.
- */
-static inline bool
-lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
- pm_lex_mode_t lex_mode = {
- .mode = PM_LEX_REGEXP,
- .as.regexp = {
- .nesting = 0,
- .incrementor = incrementor,
- .terminator = terminator
- }
- };
-
- // These are the places where we need to split up the content of the
- // regular expression. We'll use strpbrk to find the first of these
- // characters.
- uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
- memcpy(breakpoints, "\n\\#\0\0", sizeof(lex_mode.as.regexp.breakpoints));
-
- // First we'll add the terminator.
- breakpoints[3] = terminator;
-
- // Next, if there is an incrementor, then we'll check for that as well.
- if (incrementor != '\0') {
- breakpoints[4] = incrementor;
- }
-
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Push on a new string lex mode.
- */
-static inline bool
-lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed, uint8_t incrementor, uint8_t terminator) {
- pm_lex_mode_t lex_mode = {
- .mode = PM_LEX_STRING,
- .as.string = {
- .nesting = 0,
- .interpolation = interpolation,
- .label_allowed = label_allowed,
- .incrementor = incrementor,
- .terminator = terminator
- }
- };
-
- // These are the places where we need to split up the content of the
- // string. We'll use strpbrk to find the first of these characters.
- uint8_t *breakpoints = lex_mode.as.string.breakpoints;
- memcpy(breakpoints, "\n\\\0\0\0", sizeof(lex_mode.as.string.breakpoints));
-
- // Now add in the terminator.
- size_t index = 2;
- breakpoints[index++] = terminator;
-
- // If interpolation is allowed, then we're going to check for the #
- // character. Otherwise we'll only look for escapes and the terminator.
- if (interpolation) {
- breakpoints[index++] = '#';
- }
-
- // If we have an incrementor, then we'll add that in as a breakpoint as
- // well.
- if (incrementor != '\0') {
- breakpoints[index++] = incrementor;
- }
-
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Pop the current lex state off the stack. If we're within the pre-allocated
- * space of the lex state stack, then we'll just decrement the index. Otherwise
- * we'll free the current pointer and use the previous pointer.
- */
-static void
-lex_mode_pop(pm_parser_t *parser) {
- if (parser->lex_modes.index == 0) {
- parser->lex_modes.current->mode = PM_LEX_DEFAULT;
- } else if (parser->lex_modes.index < PM_LEX_STACK_SIZE) {
- parser->lex_modes.index--;
- parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
- } else {
- parser->lex_modes.index--;
- pm_lex_mode_t *prev = parser->lex_modes.current->prev;
- free(parser->lex_modes.current);
- parser->lex_modes.current = prev;
- }
-}
-
-/**
- * This is the equivalent of IS_lex_state is CRuby.
- */
-static inline bool
-lex_state_p(pm_parser_t *parser, pm_lex_state_t state) {
- return parser->lex_state & state;
-}
-
-typedef enum {
- PM_IGNORED_NEWLINE_NONE = 0,
- PM_IGNORED_NEWLINE_ALL,
- PM_IGNORED_NEWLINE_PATTERN
-} pm_ignored_newline_type_t;
-
-static inline pm_ignored_newline_type_t
-lex_state_ignored_p(pm_parser_t *parser) {
- bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
-
- if (ignored) {
- return PM_IGNORED_NEWLINE_ALL;
- } else if ((parser->lex_state & ~((unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
- return PM_IGNORED_NEWLINE_PATTERN;
- } else {
- return PM_IGNORED_NEWLINE_NONE;
- }
-}
-
-static inline bool
-lex_state_beg_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || (parser->lex_state == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
-}
-
-static inline bool
-lex_state_arg_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
-}
-
-static inline bool
-lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) {
- if (parser->current.end >= parser->end) {
- return false;
- }
- return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
-}
-
-static inline bool
-lex_state_end_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_END_ANY);
-}
-
-/**
- * This is the equivalent of IS_AFTER_OPERATOR in CRuby.
- */
-static inline bool
-lex_state_operator_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
-}
-
-/**
- * Set the state of the lexer. This is defined as a function to be able to put a
- * breakpoint in it.
- */
-static inline void
-lex_state_set(pm_parser_t *parser, pm_lex_state_t state) {
- parser->lex_state = state;
-}
-
-#if PM_DEBUG_LOGGING
-static inline void
-debug_lex_state_set(pm_parser_t *parser, pm_lex_state_t state, char const * caller_name, int line_number) {
- fprintf(stderr, "Caller: %s:%d\nPrevious: ", caller_name, line_number);
- debug_state(parser);
- lex_state_set(parser, state);
- fprintf(stderr, "Now: ");
- debug_state(parser);
- fprintf(stderr, "\n");
-}
-
-#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
-#endif
-
-/******************************************************************************/
-/* Diagnostic-related functions */
-/******************************************************************************/
-
-/**
- * Append an error to the list of errors on the parser.
- */
-static inline void
-pm_parser_err(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id) {
- pm_diagnostic_list_append(&parser->error_list, start, end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * current token.
- */
-static inline void
-pm_parser_err_current(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, parser->current.start, parser->current.end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the given location.
- */
-static inline void
-pm_parser_err_location(pm_parser_t *parser, const pm_location_t *location, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, location->start, location->end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given node.
- */
-static inline void
-pm_parser_err_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, node->location.start, node->location.end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * previous token.
- */
-static inline void
-pm_parser_err_previous(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, parser->previous.start, parser->previous.end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given token.
- */
-static inline void
-pm_parser_err_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, token->start, token->end, diag_id);
-}
-
-/**
- * Append a warning to the list of warnings on the parser.
- */
-static inline void
-pm_parser_warn(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id) {
- if (!parser->suppress_warnings) {
- pm_diagnostic_list_append(&parser->warning_list, start, end, diag_id);
- }
-}
-
-/**
- * Append a warning to the list of warnings on the parser using the location of
- * the given token.
- */
-static inline void
-pm_parser_warn_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_id_t diag_id) {
- pm_parser_warn(parser, token->start, token->end, diag_id);
-}
-
-/******************************************************************************/
-/* Node-related functions */
-/******************************************************************************/
-
-/**
- * Retrieve the constant pool id for the given location.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- return pm_constant_pool_insert_shared(&parser->constant_pool, start, (size_t) (end - start));
-}
-
-/**
- * Retrieve the constant pool id for the given string.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_owned(pm_parser_t *parser, const uint8_t *start, size_t length) {
- return pm_constant_pool_insert_owned(&parser->constant_pool, start, length);
-}
-
-/**
- * Retrieve the constant pool id for the given static literal C string.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_constant(pm_parser_t *parser, const char *start, size_t length) {
- return pm_constant_pool_insert_constant(&parser->constant_pool, (const uint8_t *) start, length);
-}
-
-/**
- * Retrieve the constant pool id for the given token.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_token(pm_parser_t *parser, const pm_token_t *token) {
- return pm_parser_constant_id_location(parser, token->start, token->end);
-}
-
-/**
- * Retrieve the constant pool id for the given token. If the token is not
- * provided, then return 0.
- */
-static inline pm_constant_id_t
-pm_parser_optional_constant_id_token(pm_parser_t *parser, const pm_token_t *token) {
- return token->type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
-}
-
-/**
- * The predicate of conditional nodes can change what would otherwise be regular
- * nodes into specialized nodes. For example:
- *
- * if foo .. bar => RangeNode becomes FlipFlopNode
- * if foo and bar .. baz => RangeNode becomes FlipFlopNode
- * if /foo/ => RegularExpressionNode becomes MatchLastLineNode
- * if /foo #{bar}/ => InterpolatedRegularExpressionNode becomes InterpolatedMatchLastLineNode
- */
-static void
-pm_conditional_predicate(pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_AND_NODE: {
- pm_and_node_t *cast = (pm_and_node_t *) node;
- pm_conditional_predicate(cast->left);
- pm_conditional_predicate(cast->right);
- break;
- }
- case PM_OR_NODE: {
- pm_or_node_t *cast = (pm_or_node_t *) node;
- pm_conditional_predicate(cast->left);
- pm_conditional_predicate(cast->right);
- break;
- }
- case PM_PARENTHESES_NODE: {
- pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
-
- if ((cast->body != NULL) && PM_NODE_TYPE_P(cast->body, PM_STATEMENTS_NODE)) {
- pm_statements_node_t *statements = (pm_statements_node_t *) cast->body;
- if (statements->body.size == 1) pm_conditional_predicate(statements->body.nodes[0]);
- }
-
- break;
- }
- case PM_RANGE_NODE: {
- pm_range_node_t *cast = (pm_range_node_t *) node;
- if (cast->left) {
- pm_conditional_predicate(cast->left);
- }
- if (cast->right) {
- pm_conditional_predicate(cast->right);
- }
-
- // Here we change the range node into a flip flop node. We can do
- // this since the nodes are exactly the same except for the type.
- // We're only asserting against the size when we should probably
- // assert against the entire layout, but we'll assume tests will
- // catch this.
- assert(sizeof(pm_range_node_t) == sizeof(pm_flip_flop_node_t));
- node->type = PM_FLIP_FLOP_NODE;
-
- break;
- }
- case PM_REGULAR_EXPRESSION_NODE:
- // Here we change the regular expression node into a match last line
- // node. We can do this since the nodes are exactly the same except
- // for the type.
- assert(sizeof(pm_regular_expression_node_t) == sizeof(pm_match_last_line_node_t));
- node->type = PM_MATCH_LAST_LINE_NODE;
- break;
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- // Here we change the interpolated regular expression node into an
- // interpolated match last line node. We can do this since the nodes
- // are exactly the same except for the type.
- assert(sizeof(pm_interpolated_regular_expression_node_t) == sizeof(pm_interpolated_match_last_line_node_t));
- node->type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
- break;
- default:
- break;
- }
-}
-
-/**
- * In a lot of places in the tree you can have tokens that are not provided but
- * that do not cause an error. For example, in a method call without
- * parentheses. In these cases we set the token to the "not provided" type. For
- * example:
- *
- * pm_token_t token;
- * not_provided(&token, parser->previous.end);
- */
-static inline pm_token_t
-not_provided(pm_parser_t *parser) {
- return (pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->start, .end = parser->start };
-}
-
-#define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = parser->start, .end = parser->start })
-#define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
-#define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
-#define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
-#define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
-#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
-
-/**
- * This is a special out parameter to the parse_arguments_list function that
- * includes opening and closing parentheses in addition to the arguments since
- * it's so common. It is handy to use when passing argument information to one
- * of the call node creation functions.
- */
-typedef struct {
- /** The optional location of the opening parenthesis or bracket. */
- pm_location_t opening_loc;
-
- /** The lazily-allocated optional arguments node. */
- pm_arguments_node_t *arguments;
-
- /** The optional location of the closing parenthesis or bracket. */
- pm_location_t closing_loc;
-
- /** The optional block attached to the call. */
- pm_node_t *block;
-} pm_arguments_t;
-
-/**
- * Check that we're not about to attempt to attach a brace block to a call that
- * has arguments without parentheses.
- */
-static void
-pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_block_node_t *block) {
- // First, check that we have arguments and that we don't have a closing
- // location for them.
- if (arguments->arguments == NULL || arguments->closing_loc.start != NULL) {
- return;
- }
-
- // Next, check that we don't have a single parentheses argument. This would
- // look like:
- //
- // foo (1) {}
- //
- // In this case, it's actually okay for the block to be attached to the
- // call, even though it looks like it's attached to the argument.
- if (arguments->arguments->arguments.size == 1 && PM_NODE_TYPE_P(arguments->arguments->arguments.nodes[0], PM_PARENTHESES_NODE)) {
- return;
- }
-
- // If we didn't hit a case before this check, then at this point we need to
- // add a syntax error.
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
-}
-
-/******************************************************************************/
-/* Node creation functions */
-/******************************************************************************/
-
-/**
- * Parse the decimal number represented by the range of bytes. returns
- * UINT32_MAX if the number fails to parse. This function assumes that the range
- * of bytes has already been validated to contain only decimal digits.
- */
-static uint32_t
-parse_decimal_number(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- ptrdiff_t diff = end - start;
- assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
- size_t length = (size_t) diff;
-
- char *digits = calloc(length + 1, sizeof(char));
- memcpy(digits, start, length);
- digits[length] = '\0';
-
- char *endptr;
- errno = 0;
- unsigned long value = strtoul(digits, &endptr, 10);
-
- if ((digits == endptr) || (*endptr != '\0') || (errno == ERANGE)) {
- pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
- value = UINT32_MAX;
- }
-
- free(digits);
-
- if (value > UINT32_MAX) {
- pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
- value = UINT32_MAX;
- }
-
- return (uint32_t) value;
-}
-
-/**
- * When you have an encoding flag on a regular expression, it takes precedence
- * over all of the previously set encoding flags. So we need to mask off any
- * previously set encoding flags before setting the new one.
- */
-#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
-
-/**
- * Parse out the options for a regular expression.
- */
-static inline pm_node_flags_t
-pm_regular_expression_flags_create(const pm_token_t *closing) {
- pm_node_flags_t flags = 0;
-
- if (closing->type == PM_TOKEN_REGEXP_END) {
- for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
- switch (*flag) {
- case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
- case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
- case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
- case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
-
- case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
- case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
- case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
- case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
-
- default: assert(false && "unreachable");
- }
- }
- }
-
- return flags;
-}
-
-#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
-
-static pm_statements_node_t *
-pm_statements_node_create(pm_parser_t *parser);
-
-static void
-pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement);
-
-static size_t
-pm_statements_node_body_length(pm_statements_node_t *node);
-
-/**
- * This function is here to allow us a place to extend in the future when we
- * implement our own arena allocation.
- */
-static inline void *
-pm_alloc_node(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
- void *memory = calloc(1, size);
- if (memory == NULL) {
- fprintf(stderr, "Failed to allocate %zu bytes\n", size);
- abort();
- }
- return memory;
-}
-
-#define PM_ALLOC_NODE(parser, type) (type *) pm_alloc_node(parser, sizeof(type))
-
-/**
- * Allocate a new MissingNode node.
- */
-static pm_missing_node_t *
-pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- pm_missing_node_t *node = PM_ALLOC_NODE(parser, pm_missing_node_t);
- *node = (pm_missing_node_t) {{ .type = PM_MISSING_NODE, .location = { .start = start, .end = end } }};
- return node;
-}
-
-/**
- * Allocate and initialize a new AliasGlobalVariableNode node.
- */
-static pm_alias_global_variable_node_t *
-pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
- assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
- pm_alias_global_variable_node_t *node = PM_ALLOC_NODE(parser, pm_alias_global_variable_node_t);
-
- *node = (pm_alias_global_variable_node_t) {
- {
- .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
- .location = {
- .start = keyword->start,
- .end = old_name->location.end
- },
- },
- .new_name = new_name,
- .old_name = old_name,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new AliasMethodNode node.
- */
-static pm_alias_method_node_t *
-pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
- assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
- pm_alias_method_node_t *node = PM_ALLOC_NODE(parser, pm_alias_method_node_t);
-
- *node = (pm_alias_method_node_t) {
- {
- .type = PM_ALIAS_METHOD_NODE,
- .location = {
- .start = keyword->start,
- .end = old_name->location.end
- },
- },
- .new_name = new_name,
- .old_name = old_name,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate a new AlternationPatternNode node.
- */
-static pm_alternation_pattern_node_t *
-pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
- pm_alternation_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_alternation_pattern_node_t);
-
- *node = (pm_alternation_pattern_node_t) {
- {
- .type = PM_ALTERNATION_PATTERN_NODE,
- .location = {
- .start = left->location.start,
- .end = right->location.end
- },
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new and node.
- */
-static pm_and_node_t *
-pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
- pm_and_node_t *node = PM_ALLOC_NODE(parser, pm_and_node_t);
-
- *node = (pm_and_node_t) {
- {
- .type = PM_AND_NODE,
- .location = {
- .start = left->location.start,
- .end = right->location.end
- },
- },
- .left = left,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .right = right
- };
-
- return node;
-}
-
-/**
- * Allocate an initialize a new arguments node.
- */
-static pm_arguments_node_t *
-pm_arguments_node_create(pm_parser_t *parser) {
- pm_arguments_node_t *node = PM_ALLOC_NODE(parser, pm_arguments_node_t);
-
- *node = (pm_arguments_node_t) {
- {
- .type = PM_ARGUMENTS_NODE,
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .arguments = { 0 }
- };
-
- return node;
-}
-
-/**
- * Return the size of the given arguments node.
- */
-static size_t
-pm_arguments_node_size(pm_arguments_node_t *node) {
- return node->arguments.size;
-}
-
-/**
- * Append an argument to an arguments node.
- */
-static void
-pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
- if (pm_arguments_node_size(node) == 0) {
- node->base.location.start = argument->location.start;
- }
-
- node->base.location.end = argument->location.end;
- pm_node_list_append(&node->arguments, argument);
-}
-
-/**
- * Allocate and initialize a new ArrayNode node.
- */
-static pm_array_node_t *
-pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
- pm_array_node_t *node = PM_ALLOC_NODE(parser, pm_array_node_t);
-
- *node = (pm_array_node_t) {
- {
- .type = PM_ARRAY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(opening)
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .elements = { 0 }
- };
-
- return node;
-}
-
-/**
- * Return the size of the given array node.
- */
-static inline size_t
-pm_array_node_size(pm_array_node_t *node) {
- return node->elements.size;
-}
-
-/**
- * Append an argument to an array node.
- */
-static inline void
-pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
- if (!node->elements.size && !node->opening_loc.start) {
- node->base.location.start = element->location.start;
- }
-
- pm_node_list_append(&node->elements, element);
- node->base.location.end = element->location.end;
-
- // If the element is not a static literal, then the array is not a static
- // literal. Turn that flag off.
- if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || (element->flags & PM_NODE_FLAG_STATIC_LITERAL) == 0) {
- node->base.flags &= (pm_node_flags_t) ~PM_NODE_FLAG_STATIC_LITERAL;
- }
-}
-
-/**
- * Set the closing token and end location of an array node.
- */
-static void
-pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
- assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
- node->base.location.end = closing->end;
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
-}
-
-/**
- * Allocate and initialize a new array pattern node. The node list given in the
- * nodes parameter is guaranteed to have at least two nodes.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
- pm_array_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .location = {
- .start = nodes->nodes[0]->location.start,
- .end = nodes->nodes[nodes->size - 1]->location.end
- },
- },
- .constant = NULL,
- .rest = NULL,
- .requireds = { 0 },
- .posts = { 0 },
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- // For now we're going to just copy over each pointer manually. This could be
- // much more efficient, as we could instead resize the node list.
- bool found_rest = false;
- for (size_t index = 0; index < nodes->size; index++) {
- pm_node_t *child = nodes->nodes[index];
-
- if (!found_rest && PM_NODE_TYPE_P(child, PM_SPLAT_NODE)) {
- node->rest = child;
- found_rest = true;
- } else if (found_rest) {
- pm_node_list_append(&node->posts, child);
- } else {
- pm_node_list_append(&node->requireds, child);
- }
- }
-
- return node;
-}
-
-/**
- * Allocate and initialize a new array pattern node from a single rest node.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
- pm_array_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .location = rest->location,
- },
- .constant = NULL,
- .rest = rest,
- .requireds = { 0 },
- .posts = { 0 },
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new array pattern node from a constant and opening
- * and closing tokens.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
- pm_array_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .location = {
- .start = constant->location.start,
- .end = closing->end
- },
- },
- .constant = constant,
- .rest = NULL,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .requireds = { 0 },
- .posts = { 0 }
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new array pattern node from an opening and closing
- * token.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_array_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .constant = NULL,
- .rest = NULL,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .requireds = { 0 },
- .posts = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
- pm_node_list_append(&node->requireds, inner);
-}
-
-/**
- * Allocate and initialize a new assoc node.
- */
-static pm_assoc_node_t *
-pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
- pm_assoc_node_t *node = PM_ALLOC_NODE(parser, pm_assoc_node_t);
- const uint8_t *end;
-
- if (value != NULL) {
- end = value->location.end;
- } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
- end = operator->end;
- } else {
- end = key->location.end;
- }
-
- // If the key and value of this assoc node are both static literals, then
- // we can mark this node as a static literal.
- pm_node_flags_t flags = 0;
- if (value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)) {
- flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
- }
-
- *node = (pm_assoc_node_t) {
- {
- .type = PM_ASSOC_NODE,
- .flags = flags,
- .location = {
- .start = key->location.start,
- .end = end
- },
- },
- .key = key,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new assoc splat node.
- */
-static pm_assoc_splat_node_t *
-pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
- assert(operator->type == PM_TOKEN_USTAR_STAR);
- pm_assoc_splat_node_t *node = PM_ALLOC_NODE(parser, pm_assoc_splat_node_t);
-
- *node = (pm_assoc_splat_node_t) {
- {
- .type = PM_ASSOC_SPLAT_NODE,
- .location = {
- .start = operator->start,
- .end = value == NULL ? operator->end : value->location.end
- },
- },
- .value = value,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate a new BackReferenceReadNode node.
- */
-static pm_back_reference_read_node_t *
-pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- assert(name->type == PM_TOKEN_BACK_REFERENCE);
- pm_back_reference_read_node_t *node = PM_ALLOC_NODE(parser, pm_back_reference_read_node_t);
-
- *node = (pm_back_reference_read_node_t) {
- {
- .type = PM_BACK_REFERENCE_READ_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new a begin node.
- */
-static pm_begin_node_t *
-pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
- pm_begin_node_t *node = PM_ALLOC_NODE(parser, pm_begin_node_t);
-
- *node = (pm_begin_node_t) {
- {
- .type = PM_BEGIN_NODE,
- .location = {
- .start = begin_keyword->start,
- .end = statements == NULL ? begin_keyword->end : statements->base.location.end
- },
- },
- .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
- .statements = statements,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Set the rescue clause, optionally start, and end location of a begin node.
- */
-static void
-pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
- // If the begin keyword doesn't exist, we set the start on the begin_node
- if (!node->begin_keyword_loc.start) {
- node->base.location.start = rescue_clause->base.location.start;
- }
- node->base.location.end = rescue_clause->base.location.end;
- node->rescue_clause = rescue_clause;
-}
-
-/**
- * Set the else clause and end location of a begin node.
- */
-static void
-pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
- node->base.location.end = else_clause->base.location.end;
- node->else_clause = else_clause;
-}
-
-/**
- * Set the ensure clause and end location of a begin node.
- */
-static void
-pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
- node->base.location.end = ensure_clause->base.location.end;
- node->ensure_clause = ensure_clause;
-}
-
-/**
- * Set the end keyword and end location of a begin node.
- */
-static void
-pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
- assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
-
- node->base.location.end = end_keyword->end;
- node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
-}
-
-/**
- * Allocate and initialize a new BlockArgumentNode node.
- */
-static pm_block_argument_node_t *
-pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
- pm_block_argument_node_t *node = PM_ALLOC_NODE(parser, pm_block_argument_node_t);
-
- *node = (pm_block_argument_node_t) {
- {
- .type = PM_BLOCK_ARGUMENT_NODE,
- .location = {
- .start = operator->start,
- .end = expression == NULL ? operator->end : expression->location.end
- },
- },
- .expression = expression,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new BlockNode node.
- */
-static pm_block_node_t *
-pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_block_parameters_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
- pm_block_node_t *node = PM_ALLOC_NODE(parser, pm_block_node_t);
-
- *node = (pm_block_node_t) {
- {
- .type = PM_BLOCK_NODE,
- .location = { .start = opening->start, .end = closing->end },
- },
- .locals = *locals,
- .parameters = parameters,
- .body = body,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new BlockParameterNode node.
- */
-static pm_block_parameter_node_t *
-pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
- assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
- pm_block_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_block_parameter_node_t);
-
- *node = (pm_block_parameter_node_t) {
- {
- .type = PM_BLOCK_PARAMETER_NODE,
- .location = {
- .start = operator->start,
- .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
- },
- },
- .name = pm_parser_optional_constant_id_token(parser, name),
- .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new BlockParametersNode node.
- */
-static pm_block_parameters_node_t *
-pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
- pm_block_parameters_node_t *node = PM_ALLOC_NODE(parser, pm_block_parameters_node_t);
-
- const uint8_t *start;
- if (opening->type != PM_TOKEN_NOT_PROVIDED) {
- start = opening->start;
- } else if (parameters != NULL) {
- start = parameters->base.location.start;
- } else {
- start = NULL;
- }
-
- const uint8_t *end;
- if (parameters != NULL) {
- end = parameters->base.location.end;
- } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
- end = opening->end;
- } else {
- end = NULL;
- }
-
- *node = (pm_block_parameters_node_t) {
- {
- .type = PM_BLOCK_PARAMETERS_NODE,
- .location = {
- .start = start,
- .end = end
- }
- },
- .parameters = parameters,
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .locals = { 0 }
- };
-
- return node;
-}
-
-/**
- * Set the closing location of a BlockParametersNode node.
- */
-static void
-pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
- assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
-
- node->base.location.end = closing->end;
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
-}
-
-/**
- * Allocate and initialize a new BlockLocalVariableNode node.
- */
-static pm_block_local_variable_node_t *
-pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
- assert(name->type == PM_TOKEN_IDENTIFIER || name->type == PM_TOKEN_MISSING);
- pm_block_local_variable_node_t *node = PM_ALLOC_NODE(parser, pm_block_local_variable_node_t);
-
- *node = (pm_block_local_variable_node_t) {
- {
- .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Append a new block-local variable to a BlockParametersNode node.
- */
-static void
-pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
- pm_node_list_append(&node->locals, (pm_node_t *) local);
-
- if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
- node->base.location.end = local->base.location.end;
-}
-
-/**
- * Allocate and initialize a new BreakNode node.
- */
-static pm_break_node_t *
-pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
- assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
- pm_break_node_t *node = PM_ALLOC_NODE(parser, pm_break_node_t);
-
- *node = (pm_break_node_t) {
- {
- .type = PM_BREAK_NODE,
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- },
- },
- .arguments = arguments,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node. This sets everything to NULL or
- * PM_TOKEN_NOT_PROVIDED as appropriate such that its values can be overridden
- * in the various specializations of this function.
- */
-static pm_call_node_t *
-pm_call_node_create(pm_parser_t *parser) {
- pm_call_node_t *node = PM_ALLOC_NODE(parser, pm_call_node_t);
-
- *node = (pm_call_node_t) {
- {
- .type = PM_CALL_NODE,
- .location = PM_LOCATION_NULL_VALUE(parser),
- },
- .receiver = NULL,
- .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .arguments = NULL,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .block = NULL,
- .name = 0
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from an aref or an aset
- * expression.
- */
-static pm_call_node_t *
-pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = receiver->location.start;
- if (arguments->block != NULL) {
- node->base.location.end = arguments->block->location.end;
- } else {
- node->base.location.end = arguments->closing_loc.end;
- }
-
- node->receiver = receiver;
- node->message_loc.start = arguments->opening_loc.start;
- node->message_loc.end = arguments->closing_loc.end;
-
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- node->name = pm_parser_constant_id_constant(parser, "[]", 2);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a binary expression.
- */
-static pm_call_node_t *
-pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = MIN(receiver->location.start, argument->location.start);
- node->base.location.end = MAX(receiver->location.end, argument->location.end);
-
- node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
-
- pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- pm_arguments_node_arguments_append(arguments, argument);
- node->arguments = arguments;
-
- node->name = pm_parser_constant_id_token(parser, operator);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call expression.
- */
-static pm_call_node_t *
-pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = receiver->location.start;
- if (arguments->block != NULL) {
- node->base.location.end = arguments->block->location.end;
- } else if (arguments->closing_loc.start != NULL) {
- node->base.location.end = arguments->closing_loc.end;
- } else if (arguments->arguments != NULL) {
- node->base.location.end = arguments->arguments->base.location.end;
- } else {
- node->base.location.end = message->end;
- }
-
- node->receiver = receiver;
- node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
- node->base.flags |= PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
- }
-
- node->name = pm_parser_constant_id_token(parser, message);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call to a method name
- * without a receiver that could not have been a local variable read.
- */
-static pm_call_node_t *
-pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = message->start;
- if (arguments->block != NULL) {
- node->base.location.end = arguments->block->location.end;
- } else if (arguments->closing_loc.start != NULL) {
- node->base.location.end = arguments->closing_loc.end;
- } else if (arguments->arguments != NULL) {
- node->base.location.end = arguments->arguments->base.location.end;
- } else {
- node->base.location.end = arguments->closing_loc.end;
- }
-
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- node->name = pm_parser_constant_id_token(parser, message);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a not expression.
- */
-static pm_call_node_t *
-pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = message->start;
- if (arguments->closing_loc.start != NULL) {
- node->base.location.end = arguments->closing_loc.end;
- } else {
- node->base.location.end = receiver->location.end;
- }
-
- node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
-
- node->name = pm_parser_constant_id_constant(parser, "!", 1);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call shorthand expression.
- */
-static pm_call_node_t *
-pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = receiver->location.start;
- if (arguments->block != NULL) {
- node->base.location.end = arguments->block->location.end;
- } else {
- node->base.location.end = arguments->closing_loc.end;
- }
-
- node->receiver = receiver;
- node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
- node->base.flags |= PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
- }
-
- node->name = pm_parser_constant_id_constant(parser, "call", 4);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a unary operator expression.
- */
-static pm_call_node_t *
-pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = operator->start;
- node->base.location.end = receiver->location.end;
-
- node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
-
- node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call to a method name
- * without a receiver that could also have been a local variable read.
- */
-static pm_call_node_t *
-pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location = PM_LOCATION_TOKEN_VALUE(message);
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
-
- node->name = pm_parser_constant_id_token(parser, message);
- return node;
-}
-
-/**
- * Returns whether or not this call node is a "vcall" (a call to a method name
- * without a receiver that could also have been a local variable read).
- */
-static inline bool
-pm_call_node_variable_call_p(pm_call_node_t *node) {
- return node->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL;
-}
-
-/**
- * Returns whether or not this call is to the [] method in the index form (as
- * opposed to `foo.[]`).
- */
-static inline bool
-pm_call_node_index_p(pm_call_node_t *node) {
- return (
- (node->call_operator_loc.start == NULL) &&
- (node->message_loc.start != NULL) &&
- (node->message_loc.start[0] == '[') &&
- (node->message_loc.end[-1] == ']')
- );
-}
-
-/**
- * Returns whether or not this call can be used on the left-hand side of an
- * operator assignment.
- */
-static inline bool
-pm_call_node_writable_p(pm_call_node_t *node) {
- return (
- (node->message_loc.start != NULL) &&
- (node->message_loc.end[-1] != '!') &&
- (node->message_loc.end[-1] != '?') &&
- (node->opening_loc.start == NULL) &&
- (node->arguments == NULL) &&
- (node->block == NULL)
- );
-}
-
-/**
- * Initialize the read name by reading the write name and chopping off the '='.
- */
-static void
-pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
- pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
-
- if (write_constant->length > 0) {
- size_t length = write_constant->length - 1;
-
- void *memory = malloc(length);
- memcpy(memory, write_constant->start, length);
-
- *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
- } else {
- // We can get here if the message was missing because of a syntax error.
- *read_name = pm_parser_constant_id_constant(parser, "", 0);
- }
-}
-
-/**
- * Allocate and initialize a new CallAndWriteNode node.
- */
-static pm_call_and_write_node_t *
-pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(target->block == NULL);
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_call_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_call_and_write_node_t);
-
- *node = (pm_call_and_write_node_t) {
- {
- .type = PM_CALL_AND_WRITE_NODE,
- .flags = target->base.flags,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .message_loc = target->message_loc,
- .read_name = 0,
- .write_name = target->name,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- free(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IndexAndWriteNode node.
- */
-static pm_index_and_write_node_t *
-pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_index_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_and_write_node_t);
-
- *node = (pm_index_and_write_node_t) {
- {
- .type = PM_INDEX_AND_WRITE_NODE,
- .flags = target->base.flags,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = target->block,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- free(target);
-
- return node;
-}
-
-/**
- * Allocate a new CallOperatorWriteNode node.
- */
-static pm_call_operator_write_node_t *
-pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(target->block == NULL);
- pm_call_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_call_operator_write_node_t);
-
- *node = (pm_call_operator_write_node_t) {
- {
- .type = PM_CALL_OPERATOR_WRITE_NODE,
- .flags = target->base.flags,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .message_loc = target->message_loc,
- .read_name = 0,
- .write_name = target->name,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- free(target);
-
- return node;
-}
-
-/**
- * Allocate a new IndexOperatorWriteNode node.
- */
-static pm_index_operator_write_node_t *
-pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_index_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_operator_write_node_t);
-
- *node = (pm_index_operator_write_node_t) {
- {
- .type = PM_INDEX_OPERATOR_WRITE_NODE,
- .flags = target->base.flags,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = target->block,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- free(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CallOrWriteNode node.
- */
-static pm_call_or_write_node_t *
-pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(target->block == NULL);
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_call_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_call_or_write_node_t);
-
- *node = (pm_call_or_write_node_t) {
- {
- .type = PM_CALL_OR_WRITE_NODE,
- .flags = target->base.flags,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .message_loc = target->message_loc,
- .read_name = 0,
- .write_name = target->name,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- free(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IndexOrWriteNode node.
- */
-static pm_index_or_write_node_t *
-pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_index_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_or_write_node_t);
-
- *node = (pm_index_or_write_node_t) {
- {
- .type = PM_INDEX_OR_WRITE_NODE,
- .flags = target->base.flags,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = target->block,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- free(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CapturePatternNode node.
- */
-static pm_capture_pattern_node_t *
-pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *target, const pm_token_t *operator) {
- pm_capture_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_capture_pattern_node_t);
-
- *node = (pm_capture_pattern_node_t) {
- {
- .type = PM_CAPTURE_PATTERN_NODE,
- .location = {
- .start = value->location.start,
- .end = target->location.end
- },
- },
- .value = value,
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CaseNode node.
- */
-static pm_case_node_t *
-pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, pm_else_node_t *consequent, const pm_token_t *end_keyword) {
- pm_case_node_t *node = PM_ALLOC_NODE(parser, pm_case_node_t);
-
- *node = (pm_case_node_t) {
- {
- .type = PM_CASE_NODE,
- .location = {
- .start = case_keyword->start,
- .end = end_keyword->end
- },
- },
- .predicate = predicate,
- .consequent = consequent,
- .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .conditions = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a new condition to a CaseNode node.
- */
-static void
-pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
- assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE) || PM_NODE_TYPE_P(condition, PM_IN_NODE));
-
- pm_node_list_append(&node->conditions, condition);
- node->base.location.end = condition->location.end;
-}
-
-/**
- * Set the consequent of a CaseNode node.
- */
-static void
-pm_case_node_consequent_set(pm_case_node_t *node, pm_else_node_t *consequent) {
- node->consequent = consequent;
- node->base.location.end = consequent->base.location.end;
-}
-
-/**
- * Set the end location for a CaseNode node.
- */
-static void
-pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
- node->base.location.end = end_keyword->end;
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
-}
-
-/**
- * Allocate a new ClassNode node.
- */
-static pm_class_node_t *
-pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
- pm_class_node_t *node = PM_ALLOC_NODE(parser, pm_class_node_t);
-
- *node = (pm_class_node_t) {
- {
- .type = PM_CLASS_NODE,
- .location = { .start = class_keyword->start, .end = end_keyword->end },
- },
- .locals = *locals,
- .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
- .constant_path = constant_path,
- .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
- .superclass = superclass,
- .body = body,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableAndWriteNode node.
- */
-static pm_class_variable_and_write_node_t *
-pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_class_variable_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_class_variable_and_write_node_t);
-
- *node = (pm_class_variable_and_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableOperatorWriteNode node.
- */
-static pm_class_variable_operator_write_node_t *
-pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_class_variable_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_class_variable_operator_write_node_t);
-
- *node = (pm_class_variable_operator_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableOrWriteNode node.
- */
-static pm_class_variable_or_write_node_t *
-pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_class_variable_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_class_variable_or_write_node_t);
-
- *node = (pm_class_variable_or_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableReadNode node.
- */
-static pm_class_variable_read_node_t *
-pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_CLASS_VARIABLE);
- pm_class_variable_read_node_t *node = PM_ALLOC_NODE(parser, pm_class_variable_read_node_t);
-
- *node = (pm_class_variable_read_node_t) {
- {
- .type = PM_CLASS_VARIABLE_READ_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
-
- return node;
-}
-
-/**
- * Initialize a new ClassVariableWriteNode node from a ClassVariableRead node.
- */
-static pm_class_variable_write_node_t *
-pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
- pm_class_variable_write_node_t *node = PM_ALLOC_NODE(parser, pm_class_variable_write_node_t);
-
- *node = (pm_class_variable_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_WRITE_NODE,
- .location = {
- .start = read_node->base.location.start,
- .end = value->location.end
- },
- },
- .name = read_node->name,
- .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathAndWriteNode node.
- */
-static pm_constant_path_and_write_node_t *
-pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_constant_path_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_path_and_write_node_t);
-
- *node = (pm_constant_path_and_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathOperatorWriteNode node.
- */
-static pm_constant_path_operator_write_node_t *
-pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_path_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_path_operator_write_node_t);
-
- *node = (pm_constant_path_operator_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathOrWriteNode node.
- */
-static pm_constant_path_or_write_node_t *
-pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_constant_path_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_path_or_write_node_t);
-
- *node = (pm_constant_path_or_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathNode node.
- */
-static pm_constant_path_node_t *
-pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, pm_node_t *child) {
- pm_constant_path_node_t *node = PM_ALLOC_NODE(parser, pm_constant_path_node_t);
-
- *node = (pm_constant_path_node_t) {
- {
- .type = PM_CONSTANT_PATH_NODE,
- .location = {
- .start = parent == NULL ? delimiter->start : parent->location.start,
- .end = child->location.end
- },
- },
- .parent = parent,
- .child = child,
- .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter)
- };
-
- return node;
-}
-
-/**
- * Allocate a new ConstantPathWriteNode node.
- */
-static pm_constant_path_write_node_t *
-pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_path_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_path_write_node_t);
-
- *node = (pm_constant_path_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- },
- },
- .target = target,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantAndWriteNode node.
- */
-static pm_constant_and_write_node_t *
-pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_constant_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_and_write_node_t);
-
- *node = (pm_constant_and_write_node_t) {
- {
- .type = PM_CONSTANT_AND_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantOperatorWriteNode node.
- */
-static pm_constant_operator_write_node_t *
-pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_operator_write_node_t);
-
- *node = (pm_constant_operator_write_node_t) {
- {
- .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantOrWriteNode node.
- */
-static pm_constant_or_write_node_t *
-pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_constant_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_or_write_node_t);
-
- *node = (pm_constant_or_write_node_t) {
- {
- .type = PM_CONSTANT_OR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantReadNode node.
- */
-static pm_constant_read_node_t *
-pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
- pm_constant_read_node_t *node = PM_ALLOC_NODE(parser, pm_constant_read_node_t);
-
- *node = (pm_constant_read_node_t) {
- {
- .type = PM_CONSTANT_READ_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(name)
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate a new ConstantWriteNode node.
- */
-static pm_constant_write_node_t *
-pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_write_node_t *node = PM_ALLOC_NODE(parser, pm_constant_write_node_t);
-
- *node = (pm_constant_write_node_t) {
- {
- .type = PM_CONSTANT_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new DefNode node.
- */
-static pm_def_node_t *
-pm_def_node_create(
- pm_parser_t *parser,
- const pm_token_t *name,
- pm_node_t *receiver,
- pm_parameters_node_t *parameters,
- pm_node_t *body,
- pm_constant_id_list_t *locals,
- const pm_token_t *def_keyword,
- const pm_token_t *operator,
- const pm_token_t *lparen,
- const pm_token_t *rparen,
- const pm_token_t *equal,
- const pm_token_t *end_keyword
-) {
- pm_def_node_t *node = PM_ALLOC_NODE(parser, pm_def_node_t);
- const uint8_t *end;
-
- if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
- end = body->location.end;
- } else {
- end = end_keyword->end;
- }
-
- *node = (pm_def_node_t) {
- {
- .type = PM_DEF_NODE,
- .location = { .start = def_keyword->start, .end = end },
- },
- .name = pm_parser_constant_id_token(parser, name),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
- .receiver = receiver,
- .parameters = parameters,
- .body = body,
- .locals = *locals,
- .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
- .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
- .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate a new DefinedNode node.
- */
-static pm_defined_node_t *
-pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
- pm_defined_node_t *node = PM_ALLOC_NODE(parser, pm_defined_node_t);
-
- *node = (pm_defined_node_t) {
- {
- .type = PM_DEFINED_NODE,
- .location = {
- .start = keyword_loc->start,
- .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
- },
- },
- .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
- .value = value,
- .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
- .keyword_loc = *keyword_loc
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ElseNode node.
- */
-static pm_else_node_t *
-pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
- pm_else_node_t *node = PM_ALLOC_NODE(parser, pm_else_node_t);
- const uint8_t *end = NULL;
- if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
- end = statements->base.location.end;
- } else {
- end = end_keyword->end;
- }
-
- *node = (pm_else_node_t) {
- {
- .type = PM_ELSE_NODE,
- .location = {
- .start = else_keyword->start,
- .end = end,
- },
- },
- .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
- .statements = statements,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new EmbeddedStatementsNode node.
- */
-static pm_embedded_statements_node_t *
-pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
- pm_embedded_statements_node_t *node = PM_ALLOC_NODE(parser, pm_embedded_statements_node_t);
-
- *node = (pm_embedded_statements_node_t) {
- {
- .type = PM_EMBEDDED_STATEMENTS_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .statements = statements,
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new EmbeddedVariableNode node.
- */
-static pm_embedded_variable_node_t *
-pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
- pm_embedded_variable_node_t *node = PM_ALLOC_NODE(parser, pm_embedded_variable_node_t);
-
- *node = (pm_embedded_variable_node_t) {
- {
- .type = PM_EMBEDDED_VARIABLE_NODE,
- .location = {
- .start = operator->start,
- .end = variable->location.end
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .variable = variable
- };
-
- return node;
-}
-
-/**
- * Allocate a new EnsureNode node.
- */
-static pm_ensure_node_t *
-pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
- pm_ensure_node_t *node = PM_ALLOC_NODE(parser, pm_ensure_node_t);
-
- *node = (pm_ensure_node_t) {
- {
- .type = PM_ENSURE_NODE,
- .location = {
- .start = ensure_keyword->start,
- .end = end_keyword->end
- },
- },
- .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
- .statements = statements,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new FalseNode node.
- */
-static pm_false_node_t *
-pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_FALSE);
- pm_false_node_t *node = PM_ALLOC_NODE(parser, pm_false_node_t);
-
- *node = (pm_false_node_t) {{
- .type = PM_FALSE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new find pattern node. The node list given in the
- * nodes parameter is guaranteed to have at least two nodes.
- */
-static pm_find_pattern_node_t *
-pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
- pm_find_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_find_pattern_node_t);
-
- pm_node_t *left = nodes->nodes[0];
- pm_node_t *right;
-
- if (nodes->size == 1) {
- right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
- } else {
- right = nodes->nodes[nodes->size - 1];
- }
-
- *node = (pm_find_pattern_node_t) {
- {
- .type = PM_FIND_PATTERN_NODE,
- .location = {
- .start = left->location.start,
- .end = right->location.end,
- },
- },
- .constant = NULL,
- .left = left,
- .right = right,
- .requireds = { 0 },
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- // For now we're going to just copy over each pointer manually. This could be
- // much more efficient, as we could instead resize the node list to only point
- // to 1...-1.
- for (size_t index = 1; index < nodes->size - 1; index++) {
- pm_node_list_append(&node->requireds, nodes->nodes[index]);
- }
-
- return node;
-}
-
-/**
- * Allocate and initialize a new FloatNode node.
- */
-static pm_float_node_t *
-pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT);
- pm_float_node_t *node = PM_ALLOC_NODE(parser, pm_float_node_t);
-
- *node = (pm_float_node_t) {{
- .type = PM_FLOAT_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new FloatNode node from a FLOAT_IMAGINARY token.
- */
-static pm_imaginary_node_t *
-pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_ALLOC_NODE(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
- .type = PM_TOKEN_FLOAT,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new FloatNode node from a FLOAT_RATIONAL token.
- */
-static pm_rational_node_t *
-pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
-
- pm_rational_node_t *node = PM_ALLOC_NODE(parser, pm_rational_node_t);
- *node = (pm_rational_node_t) {
- {
- .type = PM_RATIONAL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
- .type = PM_TOKEN_FLOAT,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new FloatNode node from a FLOAT_RATIONAL_IMAGINARY
- * token.
- */
-static pm_imaginary_node_t *
-pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_ALLOC_NODE(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
- .type = PM_TOKEN_FLOAT_RATIONAL,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ForNode node.
- */
-static pm_for_node_t *
-pm_for_node_create(
- pm_parser_t *parser,
- pm_node_t *index,
- pm_node_t *collection,
- pm_statements_node_t *statements,
- const pm_token_t *for_keyword,
- const pm_token_t *in_keyword,
- const pm_token_t *do_keyword,
- const pm_token_t *end_keyword
-) {
- pm_for_node_t *node = PM_ALLOC_NODE(parser, pm_for_node_t);
-
- *node = (pm_for_node_t) {
- {
- .type = PM_FOR_NODE,
- .location = {
- .start = for_keyword->start,
- .end = end_keyword->end
- },
- },
- .index = index,
- .collection = collection,
- .statements = statements,
- .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
- .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ForwardingArgumentsNode node.
- */
-static pm_forwarding_arguments_node_t *
-pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
- pm_forwarding_arguments_node_t *node = PM_ALLOC_NODE(parser, pm_forwarding_arguments_node_t);
- *node = (pm_forwarding_arguments_node_t) {{ .type = PM_FORWARDING_ARGUMENTS_NODE, .location = PM_LOCATION_TOKEN_VALUE(token) }};
- return node;
-}
-
-/**
- * Allocate and initialize a new ForwardingParameterNode node.
- */
-static pm_forwarding_parameter_node_t *
-pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
- pm_forwarding_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_forwarding_parameter_node_t);
- *node = (pm_forwarding_parameter_node_t) {{ .type = PM_FORWARDING_PARAMETER_NODE, .location = PM_LOCATION_TOKEN_VALUE(token) }};
- return node;
-}
-
-/**
- * Allocate and initialize a new ForwardingSuper node.
- */
-static pm_forwarding_super_node_t *
-pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
- assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
- assert(token->type == PM_TOKEN_KEYWORD_SUPER);
- pm_forwarding_super_node_t *node = PM_ALLOC_NODE(parser, pm_forwarding_super_node_t);
-
- pm_block_node_t *block = NULL;
- if (arguments->block != NULL) {
- block = (pm_block_node_t *) arguments->block;
- }
-
- *node = (pm_forwarding_super_node_t) {
- {
- .type = PM_FORWARDING_SUPER_NODE,
- .location = {
- .start = token->start,
- .end = block != NULL ? block->base.location.end : token->end
- },
- },
- .block = block
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new hash pattern node from an opening and closing
- * token.
- */
-static pm_hash_pattern_node_t *
-pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_hash_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_hash_pattern_node_t);
-
- *node = (pm_hash_pattern_node_t) {
- {
- .type = PM_HASH_PATTERN_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .constant = NULL,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .elements = { 0 },
- .rest = NULL
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new hash pattern node.
- */
-static pm_hash_pattern_node_t *
-pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
- pm_hash_pattern_node_t *node = PM_ALLOC_NODE(parser, pm_hash_pattern_node_t);
-
- const uint8_t *start;
- const uint8_t *end;
-
- if (elements->size > 0) {
- if (rest) {
- start = elements->nodes[0]->location.start;
- end = rest->location.end;
- } else {
- start = elements->nodes[0]->location.start;
- end = elements->nodes[elements->size - 1]->location.end;
- }
- } else {
- assert(rest != NULL);
- start = rest->location.start;
- end = rest->location.end;
- }
-
- *node = (pm_hash_pattern_node_t) {
- {
- .type = PM_HASH_PATTERN_NODE,
- .location = {
- .start = start,
- .end = end
- },
- },
- .constant = NULL,
- .elements = { 0 },
- .rest = rest,
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- for (size_t index = 0; index < elements->size; index++) {
- pm_node_t *element = elements->nodes[index];
- pm_node_list_append(&node->elements, element);
- }
-
- return node;
-}
-
-/**
- * Retrieve the name from a node that will become a global variable write node.
- */
-static pm_constant_id_t
-pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
- switch (PM_NODE_TYPE(target)) {
- case PM_GLOBAL_VARIABLE_READ_NODE:
- return ((pm_global_variable_read_node_t *) target)->name;
- case PM_BACK_REFERENCE_READ_NODE:
- return ((pm_back_reference_read_node_t *) target)->name;
- case PM_NUMBERED_REFERENCE_READ_NODE:
- // This will only ever happen in the event of a syntax error, but we
- // still need to provide something for the node.
- return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
- default:
- assert(false && "unreachable");
- return (pm_constant_id_t) -1;
- }
-}
-
-/**
- * Allocate and initialize a new GlobalVariableAndWriteNode node.
- */
-static pm_global_variable_and_write_node_t *
-pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_global_variable_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_global_variable_and_write_node_t);
-
- *node = (pm_global_variable_and_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new GlobalVariableOperatorWriteNode node.
- */
-static pm_global_variable_operator_write_node_t *
-pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_global_variable_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_global_variable_operator_write_node_t);
-
- *node = (pm_global_variable_operator_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new GlobalVariableOrWriteNode node.
- */
-static pm_global_variable_or_write_node_t *
-pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_global_variable_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_global_variable_or_write_node_t);
-
- *node = (pm_global_variable_or_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate a new GlobalVariableReadNode node.
- */
-static pm_global_variable_read_node_t *
-pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_global_variable_read_node_t *node = PM_ALLOC_NODE(parser, pm_global_variable_read_node_t);
-
- *node = (pm_global_variable_read_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_READ_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate a new GlobalVariableWriteNode node.
- */
-static pm_global_variable_write_node_t *
-pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_global_variable_write_node_t *node = PM_ALLOC_NODE(parser, pm_global_variable_write_node_t);
-
- *node = (pm_global_variable_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
- .location = {
- .start = target->location.start,
- .end = value->location.end
- },
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = PM_LOCATION_NODE_VALUE(target),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate a new HashNode node.
- */
-static pm_hash_node_t *
-pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
- assert(opening != NULL);
- pm_hash_node_t *node = PM_ALLOC_NODE(parser, pm_hash_node_t);
-
- *node = (pm_hash_node_t) {
- {
- .type = PM_HASH_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(opening)
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_NULL_VALUE(parser),
- .elements = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a new element to a hash node.
- */
-static inline void
-pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
- pm_node_list_append(&hash->elements, element);
-
- // If the element is not a static literal, then the hash is not a static
- // literal. Turn that flag off.
- if ((element->flags & PM_NODE_FLAG_STATIC_LITERAL) == 0) {
- hash->base.flags &= (pm_node_flags_t) ~PM_NODE_FLAG_STATIC_LITERAL;
- }
-}
-
-static inline void
-pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
- hash->base.location.end = token->end;
- hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
-}
-
-/**
- * Allocate a new IfNode node.
- */
-static pm_if_node_t *
-pm_if_node_create(pm_parser_t *parser,
- const pm_token_t *if_keyword,
- pm_node_t *predicate,
- pm_statements_node_t *statements,
- pm_node_t *consequent,
- const pm_token_t *end_keyword
-) {
- pm_conditional_predicate(predicate);
- pm_if_node_t *node = PM_ALLOC_NODE(parser, pm_if_node_t);
-
- const uint8_t *end;
- if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
- end = end_keyword->end;
- } else if (consequent != NULL) {
- end = consequent->location.end;
- } else if (pm_statements_node_body_length(statements) != 0) {
- end = statements->base.location.end;
- } else {
- end = predicate->location.end;
- }
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .location = {
- .start = if_keyword->start,
- .end = end
- },
- },
- .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
- .predicate = predicate,
- .statements = statements,
- .consequent = consequent,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new IfNode node in the modifier form.
- */
-static pm_if_node_t *
-pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
- pm_conditional_predicate(predicate);
- pm_if_node_t *node = PM_ALLOC_NODE(parser, pm_if_node_t);
-
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .location = {
- .start = statement->location.start,
- .end = predicate->location.end
- },
- },
- .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
- .predicate = predicate,
- .statements = statements,
- .consequent = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize an if node from a ternary expression.
- */
-static pm_if_node_t *
-pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
- pm_conditional_predicate(predicate);
-
- pm_statements_node_t *if_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(if_statements, true_expression);
-
- pm_statements_node_t *else_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(else_statements, false_expression);
-
- pm_token_t end_keyword = not_provided(parser);
- pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
-
- pm_if_node_t *node = PM_ALLOC_NODE(parser, pm_if_node_t);
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .location = {
- .start = predicate->location.start,
- .end = false_expression->location.end,
- },
- },
- .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = if_statements,
- .consequent = (pm_node_t *)else_node,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-
-}
-
-static inline void
-pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
- node->base.location.end = keyword->end;
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
-}
-
-static inline void
-pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
- node->base.location.end = keyword->end;
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
-}
-
-/**
- * Allocate and initialize a new ImplicitNode node.
- */
-static pm_implicit_node_t *
-pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
- pm_implicit_node_t *node = PM_ALLOC_NODE(parser, pm_implicit_node_t);
-
- *node = (pm_implicit_node_t) {
- {
- .type = PM_IMPLICIT_NODE,
- .location = value->location
- },
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IntegerNode node.
- */
-static pm_integer_node_t *
-pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER);
- pm_integer_node_t *node = PM_ALLOC_NODE(parser, pm_integer_node_t);
-
- *node = (pm_integer_node_t) {{
- .type = PM_INTEGER_NODE,
- .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IntegerNode node from an INTEGER_IMAGINARY
- * token.
- */
-static pm_imaginary_node_t *
-pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_ALLOC_NODE(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
- .type = PM_TOKEN_INTEGER,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IntegerNode node from an INTEGER_RATIONAL
- * token.
- */
-static pm_rational_node_t *
-pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
-
- pm_rational_node_t *node = PM_ALLOC_NODE(parser, pm_rational_node_t);
- *node = (pm_rational_node_t) {
- {
- .type = PM_RATIONAL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
- .type = PM_TOKEN_INTEGER,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IntegerNode node from an
- * INTEGER_RATIONAL_IMAGINARY token.
- */
-static pm_imaginary_node_t *
-pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_ALLOC_NODE(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
- .type = PM_TOKEN_INTEGER_RATIONAL,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InNode node.
- */
-static pm_in_node_t *
-pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t *statements, const pm_token_t *in_keyword, const pm_token_t *then_keyword) {
- pm_in_node_t *node = PM_ALLOC_NODE(parser, pm_in_node_t);
-
- const uint8_t *end;
- if (statements != NULL) {
- end = statements->base.location.end;
- } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
- end = then_keyword->end;
- } else {
- end = pattern->location.end;
- }
-
- *node = (pm_in_node_t) {
- {
- .type = PM_IN_NODE,
- .location = {
- .start = in_keyword->start,
- .end = end
- },
- },
- .pattern = pattern,
- .statements = statements,
- .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
- .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableAndWriteNode node.
- */
-static pm_instance_variable_and_write_node_t *
-pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_instance_variable_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_instance_variable_and_write_node_t);
-
- *node = (pm_instance_variable_and_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableOperatorWriteNode node.
- */
-static pm_instance_variable_operator_write_node_t *
-pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_instance_variable_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_instance_variable_operator_write_node_t);
-
- *node = (pm_instance_variable_operator_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableOrWriteNode node.
- */
-static pm_instance_variable_or_write_node_t *
-pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_instance_variable_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_instance_variable_or_write_node_t);
-
- *node = (pm_instance_variable_or_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableReadNode node.
- */
-static pm_instance_variable_read_node_t *
-pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
- pm_instance_variable_read_node_t *node = PM_ALLOC_NODE(parser, pm_instance_variable_read_node_t);
-
- *node = (pm_instance_variable_read_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_READ_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
-
- return node;
-}
-
-/**
- * Initialize a new InstanceVariableWriteNode node from an InstanceVariableRead
- * node.
- */
-static pm_instance_variable_write_node_t *
-pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
- pm_instance_variable_write_node_t *node = PM_ALLOC_NODE(parser, pm_instance_variable_write_node_t);
- *node = (pm_instance_variable_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
- .location = {
- .start = read_node->base.location.start,
- .end = value->location.end
- }
- },
- .name = read_node->name,
- .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate a new InterpolatedRegularExpressionNode node.
- */
-static pm_interpolated_regular_expression_node_t *
-pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
- pm_interpolated_regular_expression_node_t *node = PM_ALLOC_NODE(parser, pm_interpolated_regular_expression_node_t);
-
- *node = (pm_interpolated_regular_expression_node_t) {
- {
- .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
- .location = {
- .start = opening->start,
- .end = NULL,
- },
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .parts = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
- if (node->base.location.start > part->location.start) {
- node->base.location.start = part->location.start;
- }
- if (node->base.location.end < part->location.end) {
- node->base.location.end = part->location.end;
- }
- pm_node_list_append(&node->parts, part);
-}
-
-static inline void
-pm_interpolated_regular_expression_node_closing_set(pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
- node->base.flags |= pm_regular_expression_flags_create(closing);
-}
-
-/**
- * Allocate and initialize a new InterpolatedStringNode node.
- */
-static pm_interpolated_string_node_t *
-pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
- pm_interpolated_string_node_t *node = PM_ALLOC_NODE(parser, pm_interpolated_string_node_t);
-
- *node = (pm_interpolated_string_node_t) {
- {
- .type = PM_INTERPOLATED_STRING_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end,
- },
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .parts = { 0 }
- };
-
- if (parts != NULL) {
- node->parts = *parts;
- }
-
- return node;
-}
-
-/**
- * Append a part to an InterpolatedStringNode node.
- */
-static inline void
-pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
- if (node->parts.size == 0 && node->opening_loc.start == NULL) {
- node->base.location.start = part->location.start;
- }
-
- pm_node_list_append(&node->parts, part);
- node->base.location.end = part->location.end;
-}
-
-/**
- * Set the closing token of the given InterpolatedStringNode node.
- */
-static void
-pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
-}
-
-/**
- * Allocate and initialize a new InterpolatedSymbolNode node.
- */
-static pm_interpolated_symbol_node_t *
-pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
- pm_interpolated_symbol_node_t *node = PM_ALLOC_NODE(parser, pm_interpolated_symbol_node_t);
-
- *node = (pm_interpolated_symbol_node_t) {
- {
- .type = PM_INTERPOLATED_SYMBOL_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end,
- },
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .parts = { 0 }
- };
-
- if (parts != NULL) {
- node->parts = *parts;
- }
-
- return node;
-}
-
-static inline void
-pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
- if (node->parts.size == 0 && node->opening_loc.start == NULL) {
- node->base.location.start = part->location.start;
- }
-
- pm_node_list_append(&node->parts, part);
- node->base.location.end = part->location.end;
-}
-
-/**
- * Allocate a new InterpolatedXStringNode node.
- */
-static pm_interpolated_x_string_node_t *
-pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_interpolated_x_string_node_t *node = PM_ALLOC_NODE(parser, pm_interpolated_x_string_node_t);
-
- *node = (pm_interpolated_x_string_node_t) {
- {
- .type = PM_INTERPOLATED_X_STRING_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .parts = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
- pm_node_list_append(&node->parts, part);
- node->base.location.end = part->location.end;
-}
-
-static inline void
-pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
-}
-
-/**
- * Allocate a new KeywordHashNode node.
- */
-static pm_keyword_hash_node_t *
-pm_keyword_hash_node_create(pm_parser_t *parser) {
- pm_keyword_hash_node_t *node = PM_ALLOC_NODE(parser, pm_keyword_hash_node_t);
-
- *node = (pm_keyword_hash_node_t) {
- .base = {
- .type = PM_KEYWORD_HASH_NODE,
- .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- },
- .elements = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append an element to a KeywordHashNode node.
- */
-static void
-pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
- pm_node_list_append(&hash->elements, element);
- if (hash->base.location.start == NULL) {
- hash->base.location.start = element->location.start;
- }
- hash->base.location.end = element->location.end;
-}
-
-/**
- * Allocate and initialize a new RequiredKeywordParameterNode node.
- */
-static pm_required_keyword_parameter_node_t *
-pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_required_keyword_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_required_keyword_parameter_node_t);
-
- *node = (pm_required_keyword_parameter_node_t) {
- {
- .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
- .location = {
- .start = name->start,
- .end = name->end
- },
- },
- .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
- };
-
- return node;
-}
-
-/**
- * Allocate a new OptionalKeywordParameterNode node.
- */
-static pm_optional_keyword_parameter_node_t *
-pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
- pm_optional_keyword_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_optional_keyword_parameter_node_t);
-
- *node = (pm_optional_keyword_parameter_node_t) {
- {
- .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
- .location = {
- .start = name->start,
- .end = value->location.end
- },
- },
- .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate a new KeywordRestParameterNode node.
- */
-static pm_keyword_rest_parameter_node_t *
-pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
- pm_keyword_rest_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_keyword_rest_parameter_node_t);
-
- *node = (pm_keyword_rest_parameter_node_t) {
- {
- .type = PM_KEYWORD_REST_PARAMETER_NODE,
- .location = {
- .start = operator->start,
- .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
- },
- },
- .name = pm_parser_optional_constant_id_token(parser, name),
- .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate a new LambdaNode node.
- */
-static pm_lambda_node_t *
-pm_lambda_node_create(
- pm_parser_t *parser,
- pm_constant_id_list_t *locals,
- const pm_token_t *operator,
- const pm_token_t *opening,
- const pm_token_t *closing,
- pm_block_parameters_node_t *parameters,
- pm_node_t *body
-) {
- pm_lambda_node_t *node = PM_ALLOC_NODE(parser, pm_lambda_node_t);
-
- *node = (pm_lambda_node_t) {
- {
- .type = PM_LAMBDA_NODE,
- .location = {
- .start = operator->start,
- .end = closing->end
- },
- },
- .locals = *locals,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .parameters = parameters,
- .body = body
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableAndWriteNode node.
- */
-static pm_local_variable_and_write_node_t *
-pm_local_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
- assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_local_variable_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_local_variable_and_write_node_t);
-
- *node = (pm_local_variable_and_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .name = name,
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableOperatorWriteNode node.
- */
-static pm_local_variable_operator_write_node_t *
-pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
- pm_local_variable_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_local_variable_operator_write_node_t);
-
- *node = (pm_local_variable_operator_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .name = name,
- .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableOrWriteNode node.
- */
-static pm_local_variable_or_write_node_t *
-pm_local_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
- assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_local_variable_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_local_variable_or_write_node_t);
-
- *node = (pm_local_variable_or_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .name = name,
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate a new LocalVariableReadNode node.
- */
-static pm_local_variable_read_node_t *
-pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
- pm_local_variable_read_node_t *node = PM_ALLOC_NODE(parser, pm_local_variable_read_node_t);
-
- *node = (pm_local_variable_read_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_READ_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(name)
- },
- .name = pm_parser_constant_id_token(parser, name),
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableWriteNode node.
- */
-static pm_local_variable_write_node_t *
-pm_local_variable_write_node_create(pm_parser_t *parser, pm_constant_id_t name, uint32_t depth, pm_node_t *value, const pm_location_t *name_loc, const pm_token_t *operator) {
- pm_local_variable_write_node_t *node = PM_ALLOC_NODE(parser, pm_local_variable_write_node_t);
-
- *node = (pm_local_variable_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_WRITE_NODE,
- .location = {
- .start = name_loc->start,
- .end = value->location.end
- }
- },
- .name = name,
- .depth = depth,
- .value = value,
- .name_loc = *name_loc,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-static inline bool
-token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
- return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
-}
-
-/**
- * Allocate and initialize a new LocalVariableTargetNode node.
- */
-static pm_local_variable_target_node_t *
-pm_local_variable_target_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_local_variable_target_node_t *node = PM_ALLOC_NODE(parser, pm_local_variable_target_node_t);
-
- if (token_is_numbered_parameter(name->start, name->end)) {
- pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- *node = (pm_local_variable_target_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_TARGET_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(name)
- },
- .name = pm_parser_constant_id_token(parser, name),
- .depth = 0
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new MatchPredicateNode node.
- */
-static pm_match_predicate_node_t *
-pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
- pm_match_predicate_node_t *node = PM_ALLOC_NODE(parser, pm_match_predicate_node_t);
-
- *node = (pm_match_predicate_node_t) {
- {
- .type = PM_MATCH_PREDICATE_NODE,
- .location = {
- .start = value->location.start,
- .end = pattern->location.end
- }
- },
- .value = value,
- .pattern = pattern,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new MatchRequiredNode node.
- */
-static pm_match_required_node_t *
-pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
- pm_match_required_node_t *node = PM_ALLOC_NODE(parser, pm_match_required_node_t);
-
- *node = (pm_match_required_node_t) {
- {
- .type = PM_MATCH_REQUIRED_NODE,
- .location = {
- .start = value->location.start,
- .end = pattern->location.end
- }
- },
- .value = value,
- .pattern = pattern,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new MatchWriteNode node.
- */
-static pm_match_write_node_t *
-pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
- pm_match_write_node_t *node = PM_ALLOC_NODE(parser, pm_match_write_node_t);
-
- *node = (pm_match_write_node_t) {
- {
- .type = PM_MATCH_WRITE_NODE,
- .location = call->base.location
- },
- .call = call
- };
-
- pm_constant_id_list_init(&node->locals);
- return node;
-}
-
-/**
- * Allocate a new ModuleNode node.
- */
-static pm_module_node_t *
-pm_module_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *module_keyword, pm_node_t *constant_path, const pm_token_t *name, pm_node_t *body, const pm_token_t *end_keyword) {
- pm_module_node_t *node = PM_ALLOC_NODE(parser, pm_module_node_t);
-
- *node = (pm_module_node_t) {
- {
- .type = PM_MODULE_NODE,
- .location = {
- .start = module_keyword->start,
- .end = end_keyword->end
- }
- },
- .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
- .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
- .constant_path = constant_path,
- .body = body,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new MultiTargetNode node.
- */
-static pm_multi_target_node_t *
-pm_multi_target_node_create(pm_parser_t *parser) {
- pm_multi_target_node_t *node = PM_ALLOC_NODE(parser, pm_multi_target_node_t);
-
- *node = (pm_multi_target_node_t) {
- {
- .type = PM_MULTI_TARGET_NODE,
- .location = { .start = NULL, .end = NULL }
- },
- .lefts = { 0 },
- .rest = NULL,
- .rights = { 0 },
- .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Append a target to a MultiTargetNode node.
- */
-static void
-pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
- if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
- if (node->rest == NULL) {
- node->rest = target;
- } else {
- pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
- pm_node_list_append(&node->rights, target);
- }
- } else if (node->rest == NULL) {
- pm_node_list_append(&node->lefts, target);
- } else {
- pm_node_list_append(&node->rights, target);
- }
-
- if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
- node->base.location.start = target->location.start;
- }
-
- if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
- node->base.location.end = target->location.end;
- }
-}
-
-/**
- * Set the opening of a MultiTargetNode node.
- */
-static void
-pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
- node->base.location.start = lparen->start;
- node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
-}
-
-/**
- * Set the closing of a MultiTargetNode node.
- */
-static void
-pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
- node->base.location.end = rparen->end;
- node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
-}
-
-/**
- * Allocate a new MultiWriteNode node.
- */
-static pm_multi_write_node_t *
-pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_multi_write_node_t *node = PM_ALLOC_NODE(parser, pm_multi_write_node_t);
-
- *node = (pm_multi_write_node_t) {
- {
- .type = PM_MULTI_WRITE_NODE,
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .lefts = target->lefts,
- .rest = target->rest,
- .rights = target->rights,
- .lparen_loc = target->lparen_loc,
- .rparen_loc = target->rparen_loc,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Explicitly do not call pm_node_destroy here because we want to keep
- // around all of the information within the MultiWriteNode node.
- free(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new NextNode node.
- */
-static pm_next_node_t *
-pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
- assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
- pm_next_node_t *node = PM_ALLOC_NODE(parser, pm_next_node_t);
-
- *node = (pm_next_node_t) {
- {
- .type = PM_NEXT_NODE,
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .arguments = arguments
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new NilNode node.
- */
-static pm_nil_node_t *
-pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_NIL);
- pm_nil_node_t *node = PM_ALLOC_NODE(parser, pm_nil_node_t);
-
- *node = (pm_nil_node_t) {{
- .type = PM_NIL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new NoKeywordsParameterNode node.
- */
-static pm_no_keywords_parameter_node_t *
-pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
- assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
- assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
- pm_no_keywords_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_no_keywords_parameter_node_t);
-
- *node = (pm_no_keywords_parameter_node_t) {
- {
- .type = PM_NO_KEYWORDS_PARAMETER_NODE,
- .location = {
- .start = operator->start,
- .end = keyword->end
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate a new NthReferenceReadNode node.
- */
-static pm_numbered_reference_read_node_t *
-pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
- pm_numbered_reference_read_node_t *node = PM_ALLOC_NODE(parser, pm_numbered_reference_read_node_t);
-
- *node = (pm_numbered_reference_read_node_t) {
- {
- .type = PM_NUMBERED_REFERENCE_READ_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .number = parse_decimal_number(parser, name->start + 1, name->end)
- };
-
- return node;
-}
-
-/**
- * Allocate a new OptionalParameterNode node.
- */
-static pm_optional_parameter_node_t *
-pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
- pm_optional_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_optional_parameter_node_t);
-
- *node = (pm_optional_parameter_node_t) {
- {
- .type = PM_OPTIONAL_PARAMETER_NODE,
- .location = {
- .start = name->start,
- .end = value->location.end
- }
- },
- .name = pm_parser_constant_id_token(parser, name),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new OrNode node.
- */
-static pm_or_node_t *
-pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
- pm_or_node_t *node = PM_ALLOC_NODE(parser, pm_or_node_t);
-
- *node = (pm_or_node_t) {
- {
- .type = PM_OR_NODE,
- .location = {
- .start = left->location.start,
- .end = right->location.end
- }
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ParametersNode node.
- */
-static pm_parameters_node_t *
-pm_parameters_node_create(pm_parser_t *parser) {
- pm_parameters_node_t *node = PM_ALLOC_NODE(parser, pm_parameters_node_t);
-
- *node = (pm_parameters_node_t) {
- {
- .type = PM_PARAMETERS_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
- },
- .rest = NULL,
- .keyword_rest = NULL,
- .block = NULL,
- .requireds = { 0 },
- .optionals = { 0 },
- .posts = { 0 },
- .keywords = { 0 }
- };
-
- return node;
-}
-
-/**
- * Set the location properly for the parameters node.
- */
-static void
-pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
- if (params->base.location.start == NULL) {
- params->base.location.start = param->location.start;
- } else {
- params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
- }
-
- if (params->base.location.end == NULL) {
- params->base.location.end = param->location.end;
- } else {
- params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
- }
-}
-
-/**
- * Append a required parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
- pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->requireds, param);
-}
-
-/**
- * Append an optional parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
- pm_parameters_node_location_set(params, (pm_node_t *) param);
- pm_node_list_append(&params->optionals, (pm_node_t *) param);
-}
-
-/**
- * Append a post optional arguments parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
- pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->posts, param);
-}
-
-/**
- * Set the rest parameter on a ParametersNode node.
- */
-static void
-pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_rest_parameter_node_t *param) {
- assert(params->rest == NULL);
- pm_parameters_node_location_set(params, (pm_node_t *) param);
- params->rest = param;
-}
-
-/**
- * Append a keyword parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
- pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->keywords, param);
-}
-
-/**
- * Set the keyword rest parameter on a ParametersNode node.
- */
-static void
-pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
- assert(params->keyword_rest == NULL);
- pm_parameters_node_location_set(params, param);
- params->keyword_rest = param;
-}
-
-/**
- * Set the block parameter on a ParametersNode node.
- */
-static void
-pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
- assert(params->block == NULL);
- pm_parameters_node_location_set(params, (pm_node_t *) param);
- params->block = param;
-}
-
-/**
- * Allocate a new ProgramNode node.
- */
-static pm_program_node_t *
-pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
- pm_program_node_t *node = PM_ALLOC_NODE(parser, pm_program_node_t);
-
- *node = (pm_program_node_t) {
- {
- .type = PM_PROGRAM_NODE,
- .location = {
- .start = statements == NULL ? parser->start : statements->base.location.start,
- .end = statements == NULL ? parser->end : statements->base.location.end
- }
- },
- .locals = *locals,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new ParenthesesNode node.
- */
-static pm_parentheses_node_t *
-pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
- pm_parentheses_node_t *node = PM_ALLOC_NODE(parser, pm_parentheses_node_t);
-
- *node = (pm_parentheses_node_t) {
- {
- .type = PM_PARENTHESES_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- },
- .body = body,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PinnedExpressionNode node.
- */
-static pm_pinned_expression_node_t *
-pm_pinned_expression_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *operator, const pm_token_t *lparen, const pm_token_t *rparen) {
- pm_pinned_expression_node_t *node = PM_ALLOC_NODE(parser, pm_pinned_expression_node_t);
-
- *node = (pm_pinned_expression_node_t) {
- {
- .type = PM_PINNED_EXPRESSION_NODE,
- .location = {
- .start = operator->start,
- .end = rparen->end
- }
- },
- .expression = expression,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
- .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PinnedVariableNode node.
- */
-static pm_pinned_variable_node_t *
-pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
- pm_pinned_variable_node_t *node = PM_ALLOC_NODE(parser, pm_pinned_variable_node_t);
-
- *node = (pm_pinned_variable_node_t) {
- {
- .type = PM_PINNED_VARIABLE_NODE,
- .location = {
- .start = operator->start,
- .end = variable->location.end
- }
- },
- .variable = variable,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PostExecutionNode node.
- */
-static pm_post_execution_node_t *
-pm_post_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
- pm_post_execution_node_t *node = PM_ALLOC_NODE(parser, pm_post_execution_node_t);
-
- *node = (pm_post_execution_node_t) {
- {
- .type = PM_POST_EXECUTION_NODE,
- .location = {
- .start = keyword->start,
- .end = closing->end
- }
- },
- .statements = statements,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PreExecutionNode node.
- */
-static pm_pre_execution_node_t *
-pm_pre_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
- pm_pre_execution_node_t *node = PM_ALLOC_NODE(parser, pm_pre_execution_node_t);
-
- *node = (pm_pre_execution_node_t) {
- {
- .type = PM_PRE_EXECUTION_NODE,
- .location = {
- .start = keyword->start,
- .end = closing->end
- }
- },
- .statements = statements,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new RangeNode node.
- */
-static pm_range_node_t *
-pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
- pm_range_node_t *node = PM_ALLOC_NODE(parser, pm_range_node_t);
- pm_node_flags_t flags = 0;
-
- // Indicate that this node an exclusive range if the operator is `...`.
- if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
- flags |= PM_RANGE_FLAGS_EXCLUDE_END;
- }
-
- // Indicate that this node is a static literal (i.e., can be compiled with
- // a putobject in CRuby) if the left and right are implicit nil, explicit
- // nil, or integers.
- if (
- (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
- (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
- ) {
- flags |= PM_NODE_FLAG_STATIC_LITERAL;
- }
-
- *node = (pm_range_node_t) {
- {
- .type = PM_RANGE_NODE,
- .flags = flags,
- .location = {
- .start = (left == NULL ? operator->start : left->location.start),
- .end = (right == NULL ? operator->end : right->location.end)
- }
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new RedoNode node.
- */
-static pm_redo_node_t *
-pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_REDO);
- pm_redo_node_t *node = PM_ALLOC_NODE(parser, pm_redo_node_t);
-
- *node = (pm_redo_node_t) {{ .type = PM_REDO_NODE, .location = PM_LOCATION_TOKEN_VALUE(token) }};
- return node;
-}
-
-/**
- * Allocate a new initialize a new RegularExpressionNode node with the given
- * unescaped string.
- */
-static pm_regular_expression_node_t *
-pm_regular_expression_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
- pm_regular_expression_node_t *node = PM_ALLOC_NODE(parser, pm_regular_expression_node_t);
-
- *node = (pm_regular_expression_node_t) {
- {
- .type = PM_REGULAR_EXPRESSION_NODE,
- .flags = pm_regular_expression_flags_create(closing) | PM_NODE_FLAG_STATIC_LITERAL,
- .location = {
- .start = MIN(opening->start, closing->start),
- .end = MAX(opening->end, closing->end)
- }
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .content_loc = PM_LOCATION_TOKEN_VALUE(content),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *unescaped
- };
-
- return node;
-}
-
-/**
- * Allocate a new initialize a new RegularExpressionNode node.
- */
-static inline pm_regular_expression_node_t *
-pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
-}
-
-/**
- * Allocate a new RequiredParameterNode node.
- */
-static pm_required_parameter_node_t *
-pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
- pm_required_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_required_parameter_node_t);
-
- *node = (pm_required_parameter_node_t) {
- {
- .type = PM_REQUIRED_PARAMETER_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
-
- return node;
-}
-
-/**
- * Allocate a new RescueModifierNode node.
- */
-static pm_rescue_modifier_node_t *
-pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
- pm_rescue_modifier_node_t *node = PM_ALLOC_NODE(parser, pm_rescue_modifier_node_t);
-
- *node = (pm_rescue_modifier_node_t) {
- {
- .type = PM_RESCUE_MODIFIER_NODE,
- .location = {
- .start = expression->location.start,
- .end = rescue_expression->location.end
- }
- },
- .expression = expression,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .rescue_expression = rescue_expression
- };
-
- return node;
-}
-
-/**
- * Allocate and initiliaze a new RescueNode node.
- */
-static pm_rescue_node_t *
-pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
- pm_rescue_node_t *node = PM_ALLOC_NODE(parser, pm_rescue_node_t);
-
- *node = (pm_rescue_node_t) {
- {
- .type = PM_RESCUE_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(keyword)
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .reference = NULL,
- .statements = NULL,
- .consequent = NULL,
- .exceptions = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
- node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
-}
-
-/**
- * Set the reference of a rescue node, and update the location of the node.
- */
-static void
-pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
- node->reference = reference;
- node->base.location.end = reference->location.end;
-}
-
-/**
- * Set the statements of a rescue node, and update the location of the node.
- */
-static void
-pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
- node->statements = statements;
- if (pm_statements_node_body_length(statements) > 0) {
- node->base.location.end = statements->base.location.end;
- }
-}
-
-/**
- * Set the consequent of a rescue node, and update the location.
- */
-static void
-pm_rescue_node_consequent_set(pm_rescue_node_t *node, pm_rescue_node_t *consequent) {
- node->consequent = consequent;
- node->base.location.end = consequent->base.location.end;
-}
-
-/**
- * Append an exception node to a rescue node, and update the location.
- */
-static void
-pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
- pm_node_list_append(&node->exceptions, exception);
- node->base.location.end = exception->location.end;
-}
-
-/**
- * Allocate a new RestParameterNode node.
- */
-static pm_rest_parameter_node_t *
-pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
- pm_rest_parameter_node_t *node = PM_ALLOC_NODE(parser, pm_rest_parameter_node_t);
-
- *node = (pm_rest_parameter_node_t) {
- {
- .type = PM_REST_PARAMETER_NODE,
- .location = {
- .start = operator->start,
- .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
- }
- },
- .name = pm_parser_optional_constant_id_token(parser, name),
- .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new RetryNode node.
- */
-static pm_retry_node_t *
-pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_RETRY);
- pm_retry_node_t *node = PM_ALLOC_NODE(parser, pm_retry_node_t);
-
- *node = (pm_retry_node_t) {{ .type = PM_RETRY_NODE, .location = PM_LOCATION_TOKEN_VALUE(token) }};
- return node;
-}
-
-/**
- * Allocate a new ReturnNode node.
- */
-static pm_return_node_t *
-pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
- pm_return_node_t *node = PM_ALLOC_NODE(parser, pm_return_node_t);
-
- *node = (pm_return_node_t) {
- {
- .type = PM_RETURN_NODE,
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .arguments = arguments
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SelfNode node.
- */
-static pm_self_node_t *
-pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_SELF);
- pm_self_node_t *node = PM_ALLOC_NODE(parser, pm_self_node_t);
-
- *node = (pm_self_node_t) {{
- .type = PM_SELF_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate a new SingletonClassNode node.
- */
-static pm_singleton_class_node_t *
-pm_singleton_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, const pm_token_t *operator, pm_node_t *expression, pm_node_t *body, const pm_token_t *end_keyword) {
- pm_singleton_class_node_t *node = PM_ALLOC_NODE(parser, pm_singleton_class_node_t);
-
- *node = (pm_singleton_class_node_t) {
- {
- .type = PM_SINGLETON_CLASS_NODE,
- .location = {
- .start = class_keyword->start,
- .end = end_keyword->end
- }
- },
- .locals = *locals,
- .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .expression = expression,
- .body = body,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SourceEncodingNode node.
- */
-static pm_source_encoding_node_t *
-pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
- pm_source_encoding_node_t *node = PM_ALLOC_NODE(parser, pm_source_encoding_node_t);
-
- *node = (pm_source_encoding_node_t) {{
- .type = PM_SOURCE_ENCODING_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SourceFileNode node.
- */
-static pm_source_file_node_t*
-pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
- pm_source_file_node_t *node = PM_ALLOC_NODE(parser, pm_source_file_node_t);
- assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
-
- *node = (pm_source_file_node_t) {
- {
- .type = PM_SOURCE_FILE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
- },
- .filepath = parser->filepath_string,
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SourceLineNode node.
- */
-static pm_source_line_node_t *
-pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD___LINE__);
- pm_source_line_node_t *node = PM_ALLOC_NODE(parser, pm_source_line_node_t);
-
- *node = (pm_source_line_node_t) {{
- .type = PM_SOURCE_LINE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate a new SplatNode node.
- */
-static pm_splat_node_t *
-pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
- pm_splat_node_t *node = PM_ALLOC_NODE(parser, pm_splat_node_t);
-
- *node = (pm_splat_node_t) {
- {
- .type = PM_SPLAT_NODE,
- .location = {
- .start = operator->start,
- .end = (expression == NULL ? operator->end : expression->location.end)
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .expression = expression
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new StatementsNode node.
- */
-static pm_statements_node_t *
-pm_statements_node_create(pm_parser_t *parser) {
- pm_statements_node_t *node = PM_ALLOC_NODE(parser, pm_statements_node_t);
-
- *node = (pm_statements_node_t) {
- {
- .type = PM_STATEMENTS_NODE,
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .body = { 0 }
- };
-
- return node;
-}
-
-/**
- * Get the length of the given StatementsNode node's body.
- */
-static size_t
-pm_statements_node_body_length(pm_statements_node_t *node) {
- return node && node->body.size;
-}
-
-/**
- * Set the location of the given StatementsNode.
- */
-static void
-pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
- node->base.location = (pm_location_t) { .start = start, .end = end };
-}
-
-/**
- * Append a new node to the given StatementsNode node's body.
- */
-static void
-pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement) {
- if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
- node->base.location.start = statement->location.start;
- }
- if (statement->location.end > node->base.location.end) {
- node->base.location.end = statement->location.end;
- }
-
- pm_node_list_append(&node->body, statement);
-
- // Every statement gets marked as a place where a newline can occur.
- statement->flags |= PM_NODE_FLAG_NEWLINE;
-}
-
-/**
- * Allocate a new StringConcatNode node.
- */
-static pm_string_concat_node_t *
-pm_string_concat_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right) {
- pm_string_concat_node_t *node = PM_ALLOC_NODE(parser, pm_string_concat_node_t);
-
- *node = (pm_string_concat_node_t) {
- {
- .type = PM_STRING_CONCAT_NODE,
- .location = {
- .start = left->location.start,
- .end = right->location.end
- }
- },
- .left = left,
- .right = right
- };
-
- return node;
-}
-
-/**
- * Allocate a new StringNode node with the current string on the parser.
- */
-static inline pm_string_node_t *
-pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *string) {
- pm_string_node_t *node = PM_ALLOC_NODE(parser, pm_string_node_t);
- pm_node_flags_t flags = 0;
-
- if (parser->frozen_string_literal) {
- flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
- }
-
- *node = (pm_string_node_t) {
- {
- .type = PM_STRING_NODE,
- .flags = flags,
- .location = {
- .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
- .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
- }
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .content_loc = PM_LOCATION_TOKEN_VALUE(content),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *string
- };
-
- return node;
-}
-
-/**
- * Allocate a new StringNode node.
- */
-static pm_string_node_t *
-pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
-}
-
-/**
- * Allocate a new StringNode node and create it using the current string on the
- * parser.
- */
-static pm_string_node_t *
-pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
- parser->current_string = PM_STRING_EMPTY;
- return node;
-}
-
-/**
- * Allocate and initialize a new SuperNode node.
- */
-static pm_super_node_t *
-pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
- assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
- pm_super_node_t *node = PM_ALLOC_NODE(parser, pm_super_node_t);
-
- const uint8_t *end;
- if (arguments->block != NULL) {
- end = arguments->block->location.end;
- } else if (arguments->closing_loc.start != NULL) {
- end = arguments->closing_loc.end;
- } else if (arguments->arguments != NULL) {
- end = arguments->arguments->base.location.end;
- } else {
- assert(false && "unreachable");
- end = NULL;
- }
-
- *node = (pm_super_node_t) {
- {
- .type = PM_SUPER_NODE,
- .location = {
- .start = keyword->start,
- .end = end,
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .lparen_loc = arguments->opening_loc,
- .arguments = arguments->arguments,
- .rparen_loc = arguments->closing_loc,
- .block = arguments->block
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SymbolNode node with the given unescaped
- * string.
- */
-static pm_symbol_node_t *
-pm_symbol_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing, const pm_string_t *unescaped) {
- pm_symbol_node_t *node = PM_ALLOC_NODE(parser, pm_symbol_node_t);
-
- *node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = {
- .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
- .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
- }
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .value_loc = PM_LOCATION_TOKEN_VALUE(value),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *unescaped
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SymbolNode node.
- */
-static inline pm_symbol_node_t *
-pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
- return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY);
-}
-
-/**
- * Allocate and initialize a new SymbolNode node with the current string.
- */
-static pm_symbol_node_t *
-pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
- pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string);
- parser->current_string = PM_STRING_EMPTY;
- return node;
-}
-
-/**
- * Allocate and initialize a new SymbolNode node from a label.
- */
-static pm_symbol_node_t *
-pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
- pm_symbol_node_t *node;
-
- switch (token->type) {
- case PM_TOKEN_LABEL: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
-
- pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
- node = pm_symbol_node_create(parser, &opening, &label, &closing);
-
- assert((label.end - label.start) >= 0);
- pm_string_shared_init(&node->unescaped, label.start, label.end);
- break;
- }
- case PM_TOKEN_MISSING: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
- node = pm_symbol_node_create(parser, &opening, &label, &closing);
- break;
- }
- default:
- assert(false && "unreachable");
- node = NULL;
- break;
- }
-
- return node;
-}
-
-/**
- * Check if the given node is a label in a hash.
- */
-static bool
-pm_symbol_node_label_p(pm_node_t *node) {
- const uint8_t *end = NULL;
-
- switch (PM_NODE_TYPE(node)) {
- case PM_SYMBOL_NODE:
- end = ((pm_symbol_node_t *) node)->closing_loc.end;
- break;
- case PM_INTERPOLATED_SYMBOL_NODE:
- end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
- break;
- default:
- return false;
- }
-
- return (end != NULL) && (end[-1] == ':');
-}
-
-/**
- * Convert the given StringNode node to a SymbolNode node.
- */
-static pm_symbol_node_t *
-pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
- pm_symbol_node_t *new_node = PM_ALLOC_NODE(parser, pm_symbol_node_t);
-
- *new_node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .value_loc = node->content_loc,
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .unescaped = node->unescaped
- };
-
- // We are explicitly _not_ using pm_node_destroy here because we don't want
- // to trash the unescaped string. We could instead copy the string if we
- // know that it is owned, but we're taking the fast path for now.
- free(node);
-
- return new_node;
-}
-
-/**
- * Convert the given SymbolNode node to a StringNode node.
- */
-static pm_string_node_t *
-pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
- pm_string_node_t *new_node = PM_ALLOC_NODE(parser, pm_string_node_t);
- pm_node_flags_t flags = 0;
-
- if (parser->frozen_string_literal) {
- flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
- }
-
- *new_node = (pm_string_node_t) {
- {
- .type = PM_STRING_NODE,
- .flags = flags,
- .location = node->base.location
- },
- .opening_loc = node->opening_loc,
- .content_loc = node->value_loc,
- .closing_loc = node->closing_loc,
- .unescaped = node->unescaped
- };
-
- // We are explicitly _not_ using pm_node_destroy here because we don't want
- // to trash the unescaped string. We could instead copy the string if we
- // know that it is owned, but we're taking the fast path for now.
- free(node);
-
- return new_node;
-}
-
-/**
- * Allocate and initialize a new TrueNode node.
- */
-static pm_true_node_t *
-pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_TRUE);
- pm_true_node_t *node = PM_ALLOC_NODE(parser, pm_true_node_t);
-
- *node = (pm_true_node_t) {{
- .type = PM_TRUE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new UndefNode node.
- */
-static pm_undef_node_t *
-pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
- pm_undef_node_t *node = PM_ALLOC_NODE(parser, pm_undef_node_t);
-
- *node = (pm_undef_node_t) {
- {
- .type = PM_UNDEF_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(token),
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
- .names = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a name to an undef node.
- */
-static void
-pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
- node->base.location.end = name->location.end;
- pm_node_list_append(&node->names, name);
-}
-
-/**
- * Allocate a new UnlessNode node.
- */
-static pm_unless_node_t *
-pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements) {
- pm_conditional_predicate(predicate);
- pm_unless_node_t *node = PM_ALLOC_NODE(parser, pm_unless_node_t);
-
- const uint8_t *end;
- if (statements != NULL) {
- end = statements->base.location.end;
- } else {
- end = predicate->location.end;
- }
-
- *node = (pm_unless_node_t) {
- {
- .type = PM_UNLESS_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .location = {
- .start = keyword->start,
- .end = end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .predicate = predicate,
- .statements = statements,
- .consequent = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new UnlessNode node in the modifier form.
- */
-static pm_unless_node_t *
-pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
- pm_conditional_predicate(predicate);
- pm_unless_node_t *node = PM_ALLOC_NODE(parser, pm_unless_node_t);
-
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
-
- *node = (pm_unless_node_t) {
- {
- .type = PM_UNLESS_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .location = {
- .start = statement->location.start,
- .end = predicate->location.end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
- .predicate = predicate,
- .statements = statements,
- .consequent = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-static inline void
-pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
- node->base.location.end = end_keyword->end;
-}
-
-/**
- * Allocate a new UntilNode node.
- */
-static pm_until_node_t *
-pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_until_node_t *node = PM_ALLOC_NODE(parser, pm_until_node_t);
-
- *node = (pm_until_node_t) {
- {
- .type = PM_UNTIL_NODE,
- .flags = flags,
- .location = {
- .start = keyword->start,
- .end = closing->end,
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate a new UntilNode node.
- */
-static pm_until_node_t *
-pm_until_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_until_node_t *node = PM_ALLOC_NODE(parser, pm_until_node_t);
-
- *node = (pm_until_node_t) {
- {
- .type = PM_UNTIL_NODE,
- .flags = flags,
- .location = {
- .start = statements->base.location.start,
- .end = predicate->location.end,
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new WhenNode node.
- */
-static pm_when_node_t *
-pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
- pm_when_node_t *node = PM_ALLOC_NODE(parser, pm_when_node_t);
-
- *node = (pm_when_node_t) {
- {
- .type = PM_WHEN_NODE,
- .location = {
- .start = keyword->start,
- .end = NULL
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .statements = NULL,
- .conditions = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a new condition to a when node.
- */
-static void
-pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
- node->base.location.end = condition->location.end;
- pm_node_list_append(&node->conditions, condition);
-}
-
-/**
- * Set the statements list of a when node.
- */
-static void
-pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
- if (statements->base.location.end > node->base.location.end) {
- node->base.location.end = statements->base.location.end;
- }
-
- node->statements = statements;
-}
-
-/**
- * Allocate a new WhileNode node.
- */
-static pm_while_node_t *
-pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_while_node_t *node = PM_ALLOC_NODE(parser, pm_while_node_t);
-
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .flags = flags,
- .location = {
- .start = keyword->start,
- .end = closing->end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate a new WhileNode node.
- */
-static pm_while_node_t *
-pm_while_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_while_node_t *node = PM_ALLOC_NODE(parser, pm_while_node_t);
-
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .flags = flags,
- .location = {
- .start = statements->base.location.start,
- .end = predicate->location.end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new XStringNode node with the given unescaped
- * string.
- */
-static pm_x_string_node_t *
-pm_xstring_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
- pm_x_string_node_t *node = PM_ALLOC_NODE(parser, pm_x_string_node_t);
-
- *node = (pm_x_string_node_t) {
- {
- .type = PM_X_STRING_NODE,
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .content_loc = PM_LOCATION_TOKEN_VALUE(content),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *unescaped
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new XStringNode node.
- */
-static inline pm_x_string_node_t *
-pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
-}
-
-/**
- * Allocate a new YieldNode node.
- */
-static pm_yield_node_t *
-pm_yield_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_location_t *lparen_loc, pm_arguments_node_t *arguments, const pm_location_t *rparen_loc) {
- pm_yield_node_t *node = PM_ALLOC_NODE(parser, pm_yield_node_t);
-
- const uint8_t *end;
- if (rparen_loc->start != NULL) {
- end = rparen_loc->end;
- } else if (arguments != NULL) {
- end = arguments->base.location.end;
- } else if (lparen_loc->start != NULL) {
- end = lparen_loc->end;
- } else {
- end = keyword->end;
- }
-
- *node = (pm_yield_node_t) {
- {
- .type = PM_YIELD_NODE,
- .location = {
- .start = keyword->start,
- .end = end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .lparen_loc = *lparen_loc,
- .arguments = arguments,
- .rparen_loc = *rparen_loc
- };
-
- return node;
-}
-
-#undef PM_ALLOC_NODE
-
-/******************************************************************************/
-/* Scope-related functions */
-/******************************************************************************/
-
-/**
- * Allocate and initialize a new scope. Push it onto the scope stack.
- */
-static bool
-pm_parser_scope_push(pm_parser_t *parser, bool closed) {
- pm_scope_t *scope = (pm_scope_t *) malloc(sizeof(pm_scope_t));
- if (scope == NULL) return false;
-
- *scope = (pm_scope_t) {
- .previous = parser->current_scope,
- .closed = closed,
- .explicit_params = false,
- .numbered_params = false,
- .transparent = false
- };
-
- pm_constant_id_list_init(&scope->locals);
- parser->current_scope = scope;
-
- return true;
-}
-
-/**
- * Allocate and initialize a new scope. Push it onto the scope stack.
- */
-static bool
-pm_parser_scope_push_transparent(pm_parser_t *parser) {
- pm_scope_t *scope = (pm_scope_t *) malloc(sizeof(pm_scope_t));
- if (scope == NULL) return false;
-
- *scope = (pm_scope_t) {
- .previous = parser->current_scope,
- .closed = false,
- .explicit_params = false,
- .numbered_params = false,
- .transparent = true
- };
-
- parser->current_scope = scope;
-
- return true;
-}
-
-/**
- * Check if the current scope has a given local variables.
- */
-static int
-pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
- pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, token);
- pm_scope_t *scope = parser->current_scope;
- int depth = 0;
-
- while (scope != NULL) {
- if (!scope->transparent &&
- pm_constant_id_list_includes(&scope->locals, constant_id)) return depth;
- if (scope->closed) break;
-
- scope = scope->previous;
- depth++;
- }
-
- return -1;
-}
-
-/**
- * Add a constant id to the local table of the current scope.
- */
-static inline void
-pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id) {
- pm_scope_t *scope = parser->current_scope;
- while (scope && scope->transparent) scope = scope->previous;
-
- assert(scope != NULL);
- if (!pm_constant_id_list_includes(&scope->locals, constant_id)) {
- pm_constant_id_list_append(&scope->locals, constant_id);
- }
-}
-
-/**
- * Add a local variable from a location to the current scope.
- */
-static pm_constant_id_t
-pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
- if (constant_id != 0) pm_parser_local_add(parser, constant_id);
- return constant_id;
-}
-
-/**
- * Add a local variable from a token to the current scope.
- */
-static inline void
-pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token) {
- pm_parser_local_add_location(parser, token->start, token->end);
-}
-
-/**
- * Add a local variable from an owned string to the current scope.
- */
-static pm_constant_id_t
-pm_parser_local_add_owned(pm_parser_t *parser, const uint8_t *start, size_t length) {
- pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
- if (constant_id != 0) pm_parser_local_add(parser, constant_id);
- return constant_id;
-}
-
-/**
- * Add a parameter name to the current scope and check whether the name of the
- * parameter is unique or not.
- */
-static void
-pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
- // We want to check whether the parameter name is a numbered parameter or
- // not.
- if (token_is_numbered_parameter(name->start, name->end)) {
- pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- // We want to ignore any parameter name that starts with an underscore.
- if ((*name->start == '_')) return;
-
- // Otherwise we'll fetch the constant id for the parameter name and check
- // whether it's already in the current scope.
- pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
-
- if (pm_constant_id_list_includes(&parser->current_scope->locals, constant_id)) {
- pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_REPEAT);
- }
-}
-
-/**
- * Pop the current scope off the scope stack. Note that we specifically do not
- * free the associated constant list because we assume that we have already
- * transferred ownership of the list to the AST somewhere.
- */
-static void
-pm_parser_scope_pop(pm_parser_t *parser) {
- pm_scope_t *scope = parser->current_scope;
- parser->current_scope = scope->previous;
- free(scope);
-}
-
-/******************************************************************************/
-/* Basic character checks */
-/******************************************************************************/
-
-/**
- * This function is used extremely frequently to lex all of the identifiers in a
- * source file, so it's important that it be as fast as possible. For this
- * reason we have the encoding_changed boolean to check if we need to go through
- * the function pointer or can just directly use the UTF-8 functions.
- */
-static inline size_t
-char_is_identifier_start(pm_parser_t *parser, const uint8_t *b) {
- if (parser->encoding_changed) {
- return parser->encoding.alpha_char(b, parser->end - b) || (*b == '_') || (*b >= 0x80);
- } else if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b == '_');
- } else {
- return (size_t) (pm_encoding_utf_8_alpha_char(b, parser->end - b) || 1u);
- }
-}
-
-/**
- * Like the above, this function is also used extremely frequently to lex all of
- * the identifiers in a source file once the first character has been found. So
- * it's important that it be as fast as possible.
- */
-static inline size_t
-char_is_identifier(pm_parser_t *parser, const uint8_t *b) {
- if (parser->encoding_changed) {
- return parser->encoding.alnum_char(b, parser->end - b) || (*b == '_') || (*b >= 0x80);
- } else if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0) || (*b == '_');
- } else {
- return (size_t) (pm_encoding_utf_8_alnum_char(b, parser->end - b) || 1u);
- }
-}
-
-// Here we're defining a perfect hash for the characters that are allowed in
-// global names. This is used to quickly check the next character after a $ to
-// see if it's a valid character for a global name.
-#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
-#define PUNCT(idx) ( \
- BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
- BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
- BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
- BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
- BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
- BIT('0', idx))
-
-const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
-
-#undef BIT
-#undef PUNCT
-
-static inline bool
-char_is_global_name_punctuation(const uint8_t b) {
- const unsigned int i = (const unsigned int) b;
- if (i <= 0x20 || 0x7e < i) return false;
-
- return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
-}
-
-static inline bool
-token_is_setter_name(pm_token_t *token) {
- return (
- (token->type == PM_TOKEN_IDENTIFIER) &&
- (token->end - token->start >= 2) &&
- (token->end[-1] == '=')
- );
-}
-
-/******************************************************************************/
-/* Stack helpers */
-/******************************************************************************/
-
-static inline void
-pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
- // Use the negation of the value to prevent stack overflow.
- pm_state_stack_push(&parser->accepts_block_stack, !value);
-}
-
-static inline void
-pm_accepts_block_stack_pop(pm_parser_t *parser) {
- pm_state_stack_pop(&parser->accepts_block_stack);
-}
-
-static inline bool
-pm_accepts_block_stack_p(pm_parser_t *parser) {
- return !pm_state_stack_p(&parser->accepts_block_stack);
-}
-
-static inline void
-pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
- pm_state_stack_push(&parser->do_loop_stack, value);
-}
-
-static inline void
-pm_do_loop_stack_pop(pm_parser_t *parser) {
- pm_state_stack_pop(&parser->do_loop_stack);
-}
-
-static inline bool
-pm_do_loop_stack_p(pm_parser_t *parser) {
- return pm_state_stack_p(&parser->do_loop_stack);
-}
-
-/******************************************************************************/
-/* Lexer check helpers */
-/******************************************************************************/
-
-/**
- * Get the next character in the source starting from +cursor+. If that position
- * is beyond the end of the source then return '\0'.
- */
-static inline uint8_t
-peek_at(pm_parser_t *parser, const uint8_t *cursor) {
- if (cursor < parser->end) {
- return *cursor;
- } else {
- return '\0';
- }
-}
-
-/**
- * Get the next character in the source starting from parser->current.end and
- * adding the given offset. If that position is beyond the end of the source
- * then return '\0'.
- */
-static inline uint8_t
-peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
- return peek_at(parser, parser->current.end + offset);
-}
-
-/**
- * Get the next character in the source starting from parser->current.end. If
- * that position is beyond the end of the source then return '\0'.
- */
-static inline uint8_t
-peek(pm_parser_t *parser) {
- return peek_at(parser, parser->current.end);
-}
-
-/**
- * If the character to be read matches the given value, then returns true and
- * advanced the current pointer.
- */
-static inline bool
-match(pm_parser_t *parser, uint8_t value) {
- if (peek(parser) == value) {
- parser->current.end++;
- return true;
- }
- return false;
-}
-
-/**
- * Return the length of the line ending string starting at +cursor+, or 0 if it
- * is not a line ending. This function is intended to be CRLF/LF agnostic.
- */
-static inline size_t
-match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
- if (peek_at(parser, cursor) == '\n') {
- return 1;
- }
- if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
- return 2;
- }
- return 0;
-}
-
-/**
- * Return the length of the line ending string starting at
- * `parser->current.end + offset`, or 0 if it is not a line ending. This
- * function is intended to be CRLF/LF agnostic.
- */
-static inline size_t
-match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
- return match_eol_at(parser, parser->current.end + offset);
-}
-
-/**
- * Return the length of the line ending string starting at parser->current.end,
- * or 0 if it is not a line ending. This function is intended to be CRLF/LF
- * agnostic.
- */
-static inline size_t
-match_eol(pm_parser_t *parser) {
- return match_eol_at(parser, parser->current.end);
-}
-
-/**
- * Skip to the next newline character or NUL byte.
- */
-static inline const uint8_t *
-next_newline(const uint8_t *cursor, ptrdiff_t length) {
- assert(length >= 0);
-
- // Note that it's okay for us to use memchr here to look for \n because none
- // of the encodings that we support have \n as a component of a multi-byte
- // character.
- return memchr(cursor, '\n', (size_t) length);
-}
-
-/**
- * Here we're going to check if this is a "magic" comment, and perform whatever
- * actions are necessary for it here.
- */
-static bool
-parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- size_t width = (size_t) (end - start);
-
- // First, we're going to call out to a user-defined callback if one was
- // provided. If they return an encoding struct that we can use, then we'll
- // use that here.
- if (parser->encoding_decode_callback != NULL) {
- pm_encoding_t *encoding = parser->encoding_decode_callback(parser, start, width);
-
- if (encoding != NULL) {
- parser->encoding = *encoding;
- return true;
- }
- }
-
- // Next, we're going to check for UTF-8. This is the most common encoding.
- // Extensions like utf-8 can contain extra encoding details like,
- // utf-8-dos, utf-8-linux, utf-8-mac. We treat these all as utf-8 should
- // treat any encoding starting utf-8 as utf-8.
- if ((start + 5 <= end) && (pm_strncasecmp(start, (const uint8_t *) "utf-8", 5) == 0)) {
- // We don't need to do anything here because the default encoding is
- // already UTF-8. We'll just return.
- return true;
- }
-
- // Next, we're going to loop through each of the encodings that we handle
- // explicitly. If we found one that we understand, we'll use that value.
-#define ENCODING(value, prebuilt) \
- if (width == sizeof(value) - 1 && start + width <= end && pm_strncasecmp(start, (const uint8_t *) value, width) == 0) { \
- parser->encoding = prebuilt; \
- parser->encoding_changed |= true; \
- if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser); \
- return true; \
- }
-
- // Check most common first. (This is pretty arbitrary.)
- ENCODING("ascii", pm_encoding_ascii);
- ENCODING("ascii-8bit", pm_encoding_ascii_8bit);
- ENCODING("us-ascii", pm_encoding_ascii);
- ENCODING("binary", pm_encoding_ascii_8bit);
- ENCODING("shift_jis", pm_encoding_shift_jis);
- ENCODING("euc-jp", pm_encoding_euc_jp);
-
- // Then check all the others.
- ENCODING("big5", pm_encoding_big5);
- ENCODING("gbk", pm_encoding_gbk);
- ENCODING("iso-8859-1", pm_encoding_iso_8859_1);
- ENCODING("iso-8859-2", pm_encoding_iso_8859_2);
- ENCODING("iso-8859-3", pm_encoding_iso_8859_3);
- ENCODING("iso-8859-4", pm_encoding_iso_8859_4);
- ENCODING("iso-8859-5", pm_encoding_iso_8859_5);
- ENCODING("iso-8859-6", pm_encoding_iso_8859_6);
- ENCODING("iso-8859-7", pm_encoding_iso_8859_7);
- ENCODING("iso-8859-8", pm_encoding_iso_8859_8);
- ENCODING("iso-8859-9", pm_encoding_iso_8859_9);
- ENCODING("iso-8859-10", pm_encoding_iso_8859_10);
- ENCODING("iso-8859-11", pm_encoding_iso_8859_11);
- ENCODING("iso-8859-13", pm_encoding_iso_8859_13);
- ENCODING("iso-8859-14", pm_encoding_iso_8859_14);
- ENCODING("iso-8859-15", pm_encoding_iso_8859_15);
- ENCODING("iso-8859-16", pm_encoding_iso_8859_16);
- ENCODING("koi8-r", pm_encoding_koi8_r);
- ENCODING("windows-31j", pm_encoding_windows_31j);
- ENCODING("windows-1251", pm_encoding_windows_1251);
- ENCODING("windows-1252", pm_encoding_windows_1252);
- ENCODING("cp1251", pm_encoding_windows_1251);
- ENCODING("cp1252", pm_encoding_windows_1252);
- ENCODING("cp932", pm_encoding_windows_31j);
- ENCODING("sjis", pm_encoding_windows_31j);
- ENCODING("utf8-mac", pm_encoding_utf8_mac);
-
-#undef ENCODING
-
- return false;
-}
-
-/**
- * Look for a specific pattern of "coding" and potentially set the encoding on
- * the parser.
- */
-static void
-parser_lex_magic_comment_encoding(pm_parser_t *parser) {
- const uint8_t *cursor = parser->current.start + 1;
- const uint8_t *end = parser->current.end;
-
- bool separator = false;
- while (true) {
- if (end - cursor <= 6) return;
- switch (cursor[6]) {
- case 'C': case 'c': cursor += 6; continue;
- case 'O': case 'o': cursor += 5; continue;
- case 'D': case 'd': cursor += 4; continue;
- case 'I': case 'i': cursor += 3; continue;
- case 'N': case 'n': cursor += 2; continue;
- case 'G': case 'g': cursor += 1; continue;
- case '=': case ':':
- separator = true;
- cursor += 6;
- break;
- default:
- cursor += 6;
- if (pm_char_is_whitespace(*cursor)) break;
- continue;
- }
- if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
- separator = false;
- }
-
- while (true) {
- do {
- if (++cursor >= end) return;
- } while (pm_char_is_whitespace(*cursor));
-
- if (separator) break;
- if (*cursor != '=' && *cursor != ':') return;
-
- separator = true;
- cursor++;
- }
-
- const uint8_t *value_start = cursor;
- while ((*cursor == '-' || *cursor == '_' || parser->encoding.alnum_char(cursor, 1)) && ++cursor < end);
-
- if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
- // If we were unable to parse the encoding value, then we've got an
- // issue because we didn't understand the encoding that the user was
- // trying to use. In this case we'll keep using the default encoding but
- // add an error to the parser to indicate an unsuccessful parse.
- pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
- }
-}
-
-/**
- * Check if this is a magic comment that includes the frozen_string_literal
- * pragma. If it does, set that field on the parser.
- */
-static void
-parser_lex_magic_comment_frozen_string_literal_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- if (start + 4 <= end && pm_strncasecmp(start, (const uint8_t *) "true", 4) == 0) {
- parser->frozen_string_literal = true;
- }
-}
-
-static inline bool
-pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
- return b == '\'' || b == '"' || b == ':' || b == ';';
-}
-
-/**
- * Find an emacs magic comment marker (-*-) within the given bounds. If one is
- * found, it returns a pointer to the start of the marker. Otherwise it returns
- * NULL.
- */
-static inline const uint8_t *
-parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor, const uint8_t *end) {
- while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor, '-', (size_t) (end - cursor), parser->encoding_changed, &parser->encoding)) != NULL) {
- if (cursor + 3 <= end && cursor[1] == '*' && cursor[2] == '-') {
- return cursor;
- }
- cursor++;
- }
- return NULL;
-}
-
-/**
- * Parse the current token on the parser to see if it's a magic comment and
- * potentially perform some action based on that. A regular expression that this
- * function is effectively matching is:
- *
- * %r"([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*"
- *
- * It returns true if it consumes the entire comment. Otherwise it returns
- * false.
- */
-static inline bool
-parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
- const uint8_t *start = parser->current.start + 1;
- const uint8_t *end = parser->current.end;
- if (end - start <= 7) return false;
-
- const uint8_t *cursor;
- bool indicator = false;
-
- if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
- start = cursor + 3;
-
- if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
- end = cursor;
- indicator = true;
- } else {
- // If we have a start marker but not an end marker, then we cannot
- // have a magic comment.
- return false;
- }
- }
-
- cursor = start;
- while (cursor < end) {
- while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
-
- const uint8_t *key_start = cursor;
- while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
-
- const uint8_t *key_end = cursor;
- while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
- if (cursor == end) break;
-
- if (*cursor == ':') {
- cursor++;
- } else {
- if (!indicator) return false;
- continue;
- }
-
- while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
- if (cursor == end) break;
-
- const uint8_t *value_start;
- const uint8_t *value_end;
-
- if (*cursor == '"') {
- value_start = ++cursor;
- for (; cursor < end && *cursor != '"'; cursor++) {
- if (*cursor == '\\' && (cursor + 1 < end)) cursor++;
- }
- value_end = cursor;
- } else {
- value_start = cursor;
- while (cursor < end && *cursor != '"' && *cursor != ';' && !pm_char_is_whitespace(*cursor)) cursor++;
- value_end = cursor;
- }
-
- if (indicator) {
- while (cursor < end && (*cursor == ';' || pm_char_is_whitespace(*cursor))) cursor++;
- } else {
- while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
- if (cursor != end) return false;
- }
-
- // Here, we need to do some processing on the key to swap out dashes for
- // underscores. We only need to do this if there _is_ a dash in the key.
- pm_string_t key;
- const size_t key_length = (size_t) (key_end - key_start);
- const uint8_t *dash = pm_memchr(key_start, '-', (size_t) key_length, parser->encoding_changed, &parser->encoding);
-
- if (dash == NULL) {
- pm_string_shared_init(&key, key_start, key_end);
- } else {
- size_t width = (size_t) (key_end - key_start);
- uint8_t *buffer = malloc(width);
- if (buffer == NULL) break;
-
- memcpy(buffer, key_start, width);
- buffer[dash - key_start] = '_';
-
- while ((dash = pm_memchr(dash + 1, '-', (size_t) (key_end - dash - 1), parser->encoding_changed, &parser->encoding)) != NULL) {
- buffer[dash - key_start] = '_';
- }
-
- pm_string_owned_init(&key, buffer, width);
- }
-
- // Finally, we can start checking the key against the list of known
- // magic comment keys, and potentially change state based on that.
- const uint8_t *key_source = pm_string_source(&key);
-
- // We only want to attempt to compare against encoding comments if it's
- // the first line in the file (or the second in the case of a shebang).
- if (parser->current.start == parser->encoding_comment_start) {
- if (
- (key_length == 8 && pm_strncasecmp(key_source, (const uint8_t *) "encoding", 8) == 0) ||
- (key_length == 6 && pm_strncasecmp(key_source, (const uint8_t *) "coding", 6) == 0)
- ) {
- parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
- }
- }
-
- // We only want to handle frozen string literal comments if it's before
- // any semantic tokens have been seen.
- if (!semantic_token_seen) {
- if (key_length == 21 && pm_strncasecmp(key_source, (const uint8_t *) "frozen_string_literal", 21) == 0) {
- parser_lex_magic_comment_frozen_string_literal_value(parser, value_start, value_end);
- }
- }
-
- // When we're done, we want to free the string in case we had to
- // allocate memory for it.
- pm_string_free(&key);
-
- // Allocate a new magic comment node to append to the parser's list.
- pm_magic_comment_t *magic_comment;
- if ((magic_comment = (pm_magic_comment_t *) calloc(sizeof(pm_magic_comment_t), 1)) != NULL) {
- magic_comment->key_start = key_start;
- magic_comment->value_start = value_start;
- magic_comment->key_length = (uint32_t) key_length;
- magic_comment->value_length = (uint32_t) (value_end - value_start);
- pm_list_append(&parser->magic_comment_list, (pm_list_node_t *) magic_comment);
- }
- }
-
- return true;
-}
-
-/******************************************************************************/
-/* Context manipulations */
-/******************************************************************************/
-
-static bool
-context_terminator(pm_context_t context, pm_token_t *token) {
- switch (context) {
- case PM_CONTEXT_MAIN:
- case PM_CONTEXT_DEF_PARAMS:
- return token->type == PM_TOKEN_EOF;
- case PM_CONTEXT_DEFAULT_PARAMS:
- return token->type == PM_TOKEN_COMMA || token->type == PM_TOKEN_PARENTHESIS_RIGHT;
- case PM_CONTEXT_PREEXE:
- case PM_CONTEXT_POSTEXE:
- return token->type == PM_TOKEN_BRACE_RIGHT;
- case PM_CONTEXT_MODULE:
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_SCLASS:
- case PM_CONTEXT_LAMBDA_DO_END:
- case PM_CONTEXT_DEF:
- case PM_CONTEXT_BLOCK_KEYWORDS:
- return token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ENSURE;
- case PM_CONTEXT_WHILE:
- case PM_CONTEXT_UNTIL:
- case PM_CONTEXT_ELSE:
- case PM_CONTEXT_FOR:
- case PM_CONTEXT_ENSURE:
- return token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_FOR_INDEX:
- return token->type == PM_TOKEN_KEYWORD_IN;
- case PM_CONTEXT_CASE_WHEN:
- return token->type == PM_TOKEN_KEYWORD_WHEN || token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_ELSE;
- case PM_CONTEXT_CASE_IN:
- return token->type == PM_TOKEN_KEYWORD_IN || token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_ELSE;
- case PM_CONTEXT_IF:
- case PM_CONTEXT_ELSIF:
- return token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_ELSIF || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_UNLESS:
- return token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_EMBEXPR:
- return token->type == PM_TOKEN_EMBEXPR_END;
- case PM_CONTEXT_BLOCK_BRACES:
- return token->type == PM_TOKEN_BRACE_RIGHT;
- case PM_CONTEXT_PARENS:
- return token->type == PM_TOKEN_PARENTHESIS_RIGHT;
- case PM_CONTEXT_BEGIN:
- case PM_CONTEXT_RESCUE:
- return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_RESCUE_ELSE:
- return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_LAMBDA_BRACES:
- return token->type == PM_TOKEN_BRACE_RIGHT;
- case PM_CONTEXT_PREDICATE:
- return token->type == PM_TOKEN_KEYWORD_THEN || token->type == PM_TOKEN_NEWLINE || token->type == PM_TOKEN_SEMICOLON;
- }
-
- return false;
-}
-
-static bool
-context_recoverable(pm_parser_t *parser, pm_token_t *token) {
- pm_context_node_t *context_node = parser->current_context;
-
- while (context_node != NULL) {
- if (context_terminator(context_node->context, token)) return true;
- context_node = context_node->prev;
- }
-
- return false;
-}
-
-static bool
-context_push(pm_parser_t *parser, pm_context_t context) {
- pm_context_node_t *context_node = (pm_context_node_t *) malloc(sizeof(pm_context_node_t));
- if (context_node == NULL) return false;
-
- *context_node = (pm_context_node_t) { .context = context, .prev = NULL };
-
- if (parser->current_context == NULL) {
- parser->current_context = context_node;
- } else {
- context_node->prev = parser->current_context;
- parser->current_context = context_node;
- }
-
- return true;
-}
-
-static void
-context_pop(pm_parser_t *parser) {
- pm_context_node_t *prev = parser->current_context->prev;
- free(parser->current_context);
- parser->current_context = prev;
-}
-
-static bool
-context_p(pm_parser_t *parser, pm_context_t context) {
- pm_context_node_t *context_node = parser->current_context;
-
- while (context_node != NULL) {
- if (context_node->context == context) return true;
- context_node = context_node->prev;
- }
-
- return false;
-}
-
-static bool
-context_def_p(pm_parser_t *parser) {
- pm_context_node_t *context_node = parser->current_context;
-
- while (context_node != NULL) {
- switch (context_node->context) {
- case PM_CONTEXT_DEF:
- return true;
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_MODULE:
- case PM_CONTEXT_SCLASS:
- return false;
- default:
- context_node = context_node->prev;
- }
- }
-
- return false;
-}
-
-/******************************************************************************/
-/* Specific token lexers */
-/******************************************************************************/
-
-static void
-pm_strspn_number_validate(pm_parser_t *parser, const uint8_t *invalid) {
- if (invalid != NULL) {
- pm_parser_err(parser, invalid, invalid + 1, PM_ERR_INVALID_NUMBER_UNDERSCORE);
- }
-}
-
-static size_t
-pm_strspn_binary_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_binary_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
- return length;
-}
-
-static size_t
-pm_strspn_octal_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_octal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
- return length;
-}
-
-static size_t
-pm_strspn_decimal_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_decimal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
- return length;
-}
-
-static size_t
-pm_strspn_hexadecimal_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_hexadecimal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, invalid);
- return length;
-}
-
-static pm_token_type_t
-lex_optional_float_suffix(pm_parser_t *parser) {
- pm_token_type_t type = PM_TOKEN_INTEGER;
-
- // Here we're going to attempt to parse the optional decimal portion of a
- // float. If it's not there, then it's okay and we'll just continue on.
- if (peek(parser) == '.') {
- if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
- parser->current.end += 2;
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
- type = PM_TOKEN_FLOAT;
- } else {
- // If we had a . and then something else, then it's not a float suffix on
- // a number it's a method call or something else.
- return type;
- }
- }
-
- // Here we're going to attempt to parse the optional exponent portion of a
- // float. If it's not there, it's okay and we'll just continue on.
- if (match(parser, 'e') || match(parser, 'E')) {
- (void) (match(parser, '+') || match(parser, '-'));
-
- if (pm_char_is_decimal_digit(*parser->current.end)) {
- parser->current.end++;
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
- type = PM_TOKEN_FLOAT;
- } else {
- pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
- type = PM_TOKEN_FLOAT;
- }
- }
-
- return type;
-}
-
-static pm_token_type_t
-lex_numeric_prefix(pm_parser_t *parser) {
- pm_token_type_t type = PM_TOKEN_INTEGER;
-
- if (peek_offset(parser, -1) == '0') {
- switch (*parser->current.end) {
- // 0d1111 is a decimal number
- case 'd':
- case 'D':
- parser->current.end++;
- if (pm_char_is_decimal_digit(peek(parser))) {
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
- } else {
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
- }
-
- break;
-
- // 0b1111 is a binary number
- case 'b':
- case 'B':
- parser->current.end++;
- if (pm_char_is_binary_digit(peek(parser))) {
- parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
- } else {
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
- }
-
- parser->integer_base = PM_INTEGER_BASE_FLAGS_BINARY;
- break;
-
- // 0o1111 is an octal number
- case 'o':
- case 'O':
- parser->current.end++;
- if (pm_char_is_octal_digit(peek(parser))) {
- parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
- } else {
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
- }
-
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
- break;
-
- // 01111 is an octal number
- case '_':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
- break;
-
- // 0x1111 is a hexadecimal number
- case 'x':
- case 'X':
- parser->current.end++;
- if (pm_char_is_hexadecimal_digit(peek(parser))) {
- parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
- } else {
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
- }
-
- parser->integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
- break;
-
- // 0.xxx is a float
- case '.': {
- type = lex_optional_float_suffix(parser);
- break;
- }
-
- // 0exxx is a float
- case 'e':
- case 'E': {
- type = lex_optional_float_suffix(parser);
- break;
- }
- }
- } else {
- // If it didn't start with a 0, then we'll lex as far as we can into a
- // decimal number.
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
-
- // Afterward, we'll lex as far as we can into an optional float suffix.
- type = lex_optional_float_suffix(parser);
- }
-
- return type;
-}
-
-static pm_token_type_t
-lex_numeric(pm_parser_t *parser) {
- pm_token_type_t type = PM_TOKEN_INTEGER;
- parser->integer_base = PM_INTEGER_BASE_FLAGS_DECIMAL;
-
- if (parser->current.end < parser->end) {
- type = lex_numeric_prefix(parser);
-
- const uint8_t *end = parser->current.end;
- pm_token_type_t suffix_type = type;
-
- if (type == PM_TOKEN_INTEGER) {
- if (match(parser, 'r')) {
- suffix_type = PM_TOKEN_INTEGER_RATIONAL;
-
- if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
- }
- } else if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
- }
- } else {
- if (match(parser, 'r')) {
- suffix_type = PM_TOKEN_FLOAT_RATIONAL;
-
- if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
- }
- } else if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
- }
- }
-
- const uint8_t b = peek(parser);
- if (b != '\0' && (b >= 0x80 || ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')) || b == '_')) {
- parser->current.end = end;
- } else {
- type = suffix_type;
- }
- }
-
- return type;
-}
-
-static pm_token_type_t
-lex_global_variable(pm_parser_t *parser) {
- if (parser->current.end >= parser->end) {
- pm_parser_err_current(parser, PM_ERR_INVALID_VARIABLE_GLOBAL);
- return PM_TOKEN_GLOBAL_VARIABLE;
- }
-
- switch (*parser->current.end) {
- case '~': // $~: match-data
- case '*': // $*: argv
- case '$': // $$: pid
- case '?': // $?: last status
- case '!': // $!: error string
- case '@': // $@: error position
- case '/': // $/: input record separator
- case '\\': // $\: output record separator
- case ';': // $;: field separator
- case ',': // $,: output field separator
- case '.': // $.: last read line number
- case '=': // $=: ignorecase
- case ':': // $:: load path
- case '<': // $<: reading filename
- case '>': // $>: default output handle
- case '\"': // $": already loaded files
- parser->current.end++;
- return PM_TOKEN_GLOBAL_VARIABLE;
-
- case '&': // $&: last match
- case '`': // $`: string before last match
- case '\'': // $': string after last match
- case '+': // $+: string matches last paren.
- parser->current.end++;
- return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
-
- case '0': {
- parser->current.end++;
- size_t width;
-
- if (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0) {
- do {
- parser->current.end += width;
- } while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
-
- // $0 isn't allowed to be followed by anything.
- pm_parser_err_current(parser, PM_ERR_INVALID_VARIABLE_GLOBAL);
- }
-
- return PM_TOKEN_GLOBAL_VARIABLE;
- }
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
- return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
-
- case '-':
- parser->current.end++;
- /* fallthrough */
- default: {
- size_t width;
-
- if ((width = char_is_identifier(parser, parser->current.end)) > 0) {
- do {
- parser->current.end += width;
- } while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
- } else {
- // If we get here, then we have a $ followed by something that isn't
- // recognized as a global variable.
- pm_parser_err_current(parser, PM_ERR_INVALID_VARIABLE_GLOBAL);
- }
-
- return PM_TOKEN_GLOBAL_VARIABLE;
- }
- }
-}
-
-/**
- * This function checks if the current token matches a keyword. If it does, it
- * returns true. Otherwise, it returns false. The arguments are as follows:
- *
- * * `value` - the literal string that we're checking for
- * * `width` - the length of the token
- * * `state` - the state that we should transition to if the token matches
- */
-static inline pm_token_type_t
-lex_keyword(pm_parser_t *parser, const char *value, size_t vlen, pm_lex_state_t state, pm_token_type_t type, pm_token_type_t modifier_type) {
- pm_lex_state_t last_state = parser->lex_state;
-
- if (parser->current.start + vlen <= parser->end && memcmp(parser->current.start, value, vlen) == 0) {
- if (parser->lex_state & PM_LEX_STATE_FNAME) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- } else {
- lex_state_set(parser, state);
- if (state == PM_LEX_STATE_BEG) {
- parser->command_start = true;
- }
-
- if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- return modifier_type;
- }
- }
-
- return type;
- }
-
- return PM_TOKEN_EOF;
-}
-
-static pm_token_type_t
-lex_identifier(pm_parser_t *parser, bool previous_command_start) {
- // Lex as far as we can into the current identifier.
- size_t width;
- const uint8_t *end = parser->end;
- const uint8_t *current_start = parser->current.start;
- const uint8_t *current_end = parser->current.end;
-
- while (current_end < end && (width = char_is_identifier(parser, current_end)) > 0) {
- current_end += width;
- }
- parser->current.end = current_end;
-
- // Now cache the length of the identifier so that we can quickly compare it
- // against known keywords.
- width = (size_t) (current_end - current_start);
-
- if (current_end < end) {
- if (((current_end + 1 >= end) || (current_end[1] != '=')) && (match(parser, '!') || match(parser, '?'))) {
- // First we'll attempt to extend the identifier by a ! or ?. Then we'll
- // check if we're returning the defined? keyword or just an identifier.
- width++;
-
- if (
- ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
- (peek(parser) == ':') && (peek_offset(parser, 1) != ':')
- ) {
- // If we're in a position where we can accept a : at the end of an
- // identifier, then we'll optionally accept it.
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
- (void) match(parser, ':');
- return PM_TOKEN_LABEL;
- }
-
- if (parser->lex_state != PM_LEX_STATE_DOT) {
- if (width == 8 && (lex_keyword(parser, "defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
- return PM_TOKEN_KEYWORD_DEFINED;
- }
- }
-
- return PM_TOKEN_METHOD_NAME;
- }
-
- if (lex_state_p(parser, PM_LEX_STATE_FNAME) && peek_offset(parser, 1) != '~' && peek_offset(parser, 1) != '>' && (peek_offset(parser, 1) != '=' || peek_offset(parser, 2) == '>') && match(parser, '=')) {
- // If we're in a position where we can accept a = at the end of an
- // identifier, then we'll optionally accept it.
- return PM_TOKEN_IDENTIFIER;
- }
-
- if (
- ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
- peek(parser) == ':' && peek_offset(parser, 1) != ':'
- ) {
- // If we're in a position where we can accept a : at the end of an
- // identifier, then we'll optionally accept it.
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
- (void) match(parser, ':');
- return PM_TOKEN_LABEL;
- }
- }
-
- if (parser->lex_state != PM_LEX_STATE_DOT) {
- pm_token_type_t type;
-
- switch (width) {
- case 2:
- if (lex_keyword(parser, "do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
- if (pm_do_loop_stack_p(parser)) {
- return PM_TOKEN_KEYWORD_DO_LOOP;
- }
- return PM_TOKEN_KEYWORD_DO;
- }
-
- if ((type = lex_keyword(parser, "if", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "in", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "or", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 3:
- if ((type = lex_keyword(parser, "and", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "def", width, PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "end", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "END", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "for", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "nil", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "not", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 4:
- if ((type = lex_keyword(parser, "case", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "else", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "next", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "redo", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "self", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "then", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "true", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "when", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 5:
- if ((type = lex_keyword(parser, "alias", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "begin", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "BEGIN", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "break", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "class", width, PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "elsif", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "false", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "retry", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "super", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "undef", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "until", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "while", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "yield", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 6:
- if ((type = lex_keyword(parser, "ensure", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "module", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "rescue", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "return", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "unless", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) != PM_TOKEN_EOF) return type;
- break;
- case 8:
- if ((type = lex_keyword(parser, "__LINE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, "__FILE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 12:
- if ((type = lex_keyword(parser, "__ENCODING__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- }
- }
-
- if (parser->encoding_changed) {
- return parser->encoding.isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
- }
- return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
-}
-
-/**
- * Returns true if the current token that the parser is considering is at the
- * beginning of a line or the beginning of the source.
- */
-static bool
-current_token_starts_line(pm_parser_t *parser) {
- return (parser->current.start == parser->start) || (parser->current.start[-1] == '\n');
-}
-
-/**
- * When we hit a # while lexing something like a string, we need to potentially
- * handle interpolation. This function performs that check. It returns a token
- * type representing what it found. Those cases are:
- *
- * * PM_TOKEN_NOT_PROVIDED - No interpolation was found at this point. The
- * caller should keep lexing.
- * * PM_TOKEN_STRING_CONTENT - No interpolation was found at this point. The
- * caller should return this token type.
- * * PM_TOKEN_EMBEXPR_BEGIN - An embedded expression was found. The caller
- * should return this token type.
- * * PM_TOKEN_EMBVAR - An embedded variable was found. The caller should return
- * this token type.
- */
-static pm_token_type_t
-lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
- // If there is no content following this #, then we're at the end of
- // the string and we can safely return string content.
- if (pound + 1 >= parser->end) {
- parser->current.end = pound + 1;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // Now we'll check against the character the follows the #. If it constitutes
- // valid interplation, we'll handle that, otherwise we'll return
- // PM_TOKEN_NOT_PROVIDED.
- switch (pound[1]) {
- case '@': {
- // In this case we may have hit an embedded instance or class variable.
- if (pound + 2 >= parser->end) {
- parser->current.end = pound + 1;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // If we're looking at a @ and there's another @, then we'll skip past the
- // second @.
- const uint8_t *variable = pound + 2;
- if (*variable == '@' && pound + 3 < parser->end) variable++;
-
- if (char_is_identifier_start(parser, variable)) {
- // At this point we're sure that we've either hit an embedded instance
- // or class variable. In this case we'll first need to check if we've
- // already consumed content.
- if (pound > parser->current.start) {
- parser->current.end = pound;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // Otherwise we need to return the embedded variable token
- // and then switch to the embedded variable lex mode.
- lex_mode_push(parser, (pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
- parser->current.end = pound + 1;
- return PM_TOKEN_EMBVAR;
- }
-
- // If we didn't get an valid interpolation, then this is just regular
- // string content. This is like if we get "#@-". In this case the caller
- // should keep lexing.
- parser->current.end = pound + 1;
- return PM_TOKEN_NOT_PROVIDED;
- }
- case '$':
- // In this case we may have hit an embedded global variable. If there's
- // not enough room, then we'll just return string content.
- if (pound + 2 >= parser->end) {
- parser->current.end = pound + 1;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // This is the character that we're going to check to see if it is the
- // start of an identifier that would indicate that this is a global
- // variable.
- const uint8_t *check = pound + 2;
-
- if (pound[2] == '-') {
- if (pound + 3 >= parser->end) {
- parser->current.end = pound + 2;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- check++;
- }
-
- // If the character that we're going to check is the start of an
- // identifier, or we don't have a - and the character is a decimal number
- // or a global name punctuation character, then we've hit an embedded
- // global variable.
- if (
- char_is_identifier_start(parser, check) ||
- (pound[2] != '-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
- ) {
- // In this case we've hit an embedded global variable. First check to
- // see if we've already consumed content. If we have, then we need to
- // return that content as string content first.
- if (pound > parser->current.start) {
- parser->current.end = pound;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // Otherwise, we need to return the embedded variable token and switch
- // to the embedded variable lex mode.
- lex_mode_push(parser, (pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
- parser->current.end = pound + 1;
- return PM_TOKEN_EMBVAR;
- }
-
- // In this case we've hit a #$ that does not indicate a global variable.
- // In this case we'll continue lexing past it.
- parser->current.end = pound + 1;
- return PM_TOKEN_NOT_PROVIDED;
- case '{':
- // In this case it's the start of an embedded expression. If we have
- // already consumed content, then we need to return that content as string
- // content first.
- if (pound > parser->current.start) {
- parser->current.end = pound;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- parser->enclosure_nesting++;
-
- // Otherwise we'll skip past the #{ and begin lexing the embedded
- // expression.
- lex_mode_push(parser, (pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
- parser->current.end = pound + 2;
- parser->command_start = true;
- pm_do_loop_stack_push(parser, false);
- return PM_TOKEN_EMBEXPR_BEGIN;
- default:
- // In this case we've hit a # that doesn't constitute interpolation. We'll
- // mark that by returning the not provided token type. This tells the
- // consumer to keep lexing forward.
- parser->current.end = pound + 1;
- return PM_TOKEN_NOT_PROVIDED;
- }
-}
-
-static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
-static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
-static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
-static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
-static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
-
-/**
- * This is a lookup table for whether or not an ASCII character is printable.
- */
-static const bool ascii_printable_chars[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
-};
-
-static inline bool
-char_is_ascii_printable(const uint8_t b) {
- return (b < 0x80) && ascii_printable_chars[b];
-}
-
-/**
- * Return the value that a hexadecimal digit character represents. For example,
- * transform 'a' into 10, 'b' into 11, etc.
- */
-static inline uint8_t
-escape_hexadecimal_digit(const uint8_t value) {
- return (uint8_t) ((value <= '9') ? (value - '0') : (value & 0x7) + 9);
-}
-
-/**
- * Scan the 4 digits of a Unicode escape into the value. Returns the number of
- * digits scanned. This function assumes that the characters have already been
- * validated.
- */
-static inline uint32_t
-escape_unicode(const uint8_t *string, size_t length) {
- uint32_t value = 0;
- for (size_t index = 0; index < length; index++) {
- if (index != 0) value <<= 4;
- value |= escape_hexadecimal_digit(string[index]);
- }
- return value;
-}
-
-/**
- * Escape a single character value based on the given flags.
- */
-static inline uint8_t
-escape_byte(uint8_t value, const uint8_t flags) {
- if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x1f;
- if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
- return value;
-}
-
-/**
- * Write a unicode codepoint to the given buffer.
- */
-static inline void
-escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t *start, const uint8_t *end, uint32_t value) {
- if (value <= 0x7F) { // 0xxxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) value);
- } else if (value <= 0x7FF) { // 110xxxxx 10xxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) (0xC0 | (value >> 6)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
- } else if (value <= 0xFFFF) { // 1110xxxx 10xxxxxx 10xxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) (0xE0 | (value >> 12)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
- } else if (value <= 0x10FFFF) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) (0xF0 | (value >> 18)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 12) & 0x3F)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
- } else {
- pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
- pm_buffer_append_byte(buffer, 0xEF);
- pm_buffer_append_byte(buffer, 0xBF);
- pm_buffer_append_byte(buffer, 0xBD);
- }
-}
-
-/**
- * The regular expression engine doesn't support the same escape sequences as
- * Ruby does. So first we have to read the escape sequence, and then we have to
- * format it like the regular expression engine expects it. For example, in Ruby
- * if we have:
- *
- * /\M-\C-?/
- *
- * then the first byte is actually 255, so we have to rewrite this as:
- *
- * /\xFF/
- *
- * Note that in this case there is a literal \ byte in the regular expression
- * source so that the regular expression engine will perform its own unescaping.
- */
-static inline void
-escape_write_byte(pm_buffer_t *buffer, uint8_t flags, uint8_t byte) {
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(buffer, (const uint8_t *) "\\x", 2);
-
- uint8_t byte1 = (uint8_t) ((byte >> 4) & 0xF);
- uint8_t byte2 = (uint8_t) (byte & 0xF);
-
- if (byte1 >= 0xA) {
- pm_buffer_append_byte(buffer, (uint8_t) ((byte1 - 0xA) + 'A'));
- } else {
- pm_buffer_append_byte(buffer, (uint8_t) (byte1 + '0'));
- }
-
- if (byte2 >= 0xA) {
- pm_buffer_append_byte(buffer, (uint8_t) (byte2 - 0xA + 'A'));
- } else {
- pm_buffer_append_byte(buffer, (uint8_t) (byte2 + '0'));
- }
- } else {
- pm_buffer_append_byte(buffer, byte);
- }
-}
-
-/**
- * Read the value of an escape into the buffer.
- */
-static void
-escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) {
- switch (peek(parser)) {
- case '\\': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\\');
- return;
- }
- case '\'': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\'');
- return;
- }
- case 'a': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\a');
- return;
- }
- case 'b': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\b');
- return;
- }
- case 'e': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\033');
- return;
- }
- case 'f': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\f');
- return;
- }
- case 'n': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\n');
- return;
- }
- case 'r': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\r');
- return;
- }
- case 's': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, ' ');
- return;
- }
- case 't': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\t');
- return;
- }
- case 'v': {
- parser->current.end++;
- pm_buffer_append_byte(buffer, '\v');
- return;
- }
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': {
- uint8_t value = (uint8_t) (*parser->current.end - '0');
- parser->current.end++;
-
- if (pm_char_is_octal_digit(peek(parser))) {
- value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end - '0'));
- parser->current.end++;
-
- if (pm_char_is_octal_digit(peek(parser))) {
- value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end - '0'));
- parser->current.end++;
- }
- }
-
- pm_buffer_append_byte(buffer, value);
- return;
- }
- case 'x': {
- const uint8_t *start = parser->current.end - 1;
-
- parser->current.end++;
- uint8_t byte = peek(parser);
-
- if (pm_char_is_hexadecimal_digit(byte)) {
- uint8_t value = escape_hexadecimal_digit(byte);
- parser->current.end++;
-
- byte = peek(parser);
- if (pm_char_is_hexadecimal_digit(byte)) {
- value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(byte));
- parser->current.end++;
- }
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(buffer, start, (size_t) (parser->current.end - start));
- } else {
- pm_buffer_append_byte(buffer, value);
- }
- } else {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
- }
-
- return;
- }
- case 'u': {
- const uint8_t *start = parser->current.end - 1;
- parser->current.end++;
-
- if (
- (parser->current.end + 4 <= parser->end) &&
- pm_char_is_hexadecimal_digit(parser->current.end[0]) &&
- pm_char_is_hexadecimal_digit(parser->current.end[1]) &&
- pm_char_is_hexadecimal_digit(parser->current.end[2]) &&
- pm_char_is_hexadecimal_digit(parser->current.end[3])
- ) {
- uint32_t value = escape_unicode(parser->current.end, 4);
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(buffer, start, (size_t) (parser->current.end + 4 - start));
- } else {
- escape_write_unicode(parser, buffer, start, parser->current.end + 4, value);
- }
-
- parser->current.end += 4;
- } else if (peek(parser) == '{') {
- const uint8_t *unicode_codepoints_start = parser->current.end - 2;
-
- parser->current.end++;
- parser->current.end += pm_strspn_whitespace(parser->current.end, parser->end - parser->current.end);
-
- const uint8_t *extra_codepoints_start = NULL;
- int codepoints_count = 0;
-
- while ((parser->current.end < parser->end) && (*parser->current.end != '}')) {
- const uint8_t *unicode_start = parser->current.end;
- size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
-
- if (hexadecimal_length > 6) {
- // \u{nnnn} character literal allows only 1-6 hexadecimal digits
- pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
- } else if (hexadecimal_length == 0) {
- // there are not hexadecimal characters
- pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE);
- return;
- }
-
- parser->current.end += hexadecimal_length;
- codepoints_count++;
- if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
- extra_codepoints_start = unicode_start;
- }
-
- if (!(flags & PM_ESCAPE_FLAG_REGEXP)) {
- uint32_t value = escape_unicode(unicode_start, hexadecimal_length);
- escape_write_unicode(parser, buffer, unicode_start, parser->current.end, value);
- }
-
- parser->current.end += pm_strspn_whitespace(parser->current.end, parser->end - parser->current.end);
- }
-
- // ?\u{nnnn} character literal should contain only one codepoint and cannot be like ?\u{nnnn mmmm}
- if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
- pm_parser_err(parser, extra_codepoints_start, parser->current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
- }
-
- if (peek(parser) == '}') {
- parser->current.end++;
- } else {
- pm_parser_err(parser, unicode_codepoints_start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
- }
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(buffer, unicode_codepoints_start, (size_t) (parser->current.end - unicode_codepoints_start));
- }
- } else {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
- }
-
- return;
- }
- case 'c': {
- parser->current.end++;
- if (parser->current.end == parser->end) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- uint8_t peeked = peek(parser);
- switch (peeked) {
- case '?': {
- parser->current.end++;
- escape_write_byte(buffer, flags, escape_byte(0x7f, flags));
- return;
- }
- case '\\':
- if (flags & PM_ESCAPE_FLAG_CONTROL) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
- return;
- }
- parser->current.end++;
- escape_read(parser, buffer, flags | PM_ESCAPE_FLAG_CONTROL);
- return;
- default: {
- if (!char_is_ascii_printable(peeked)) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- parser->current.end++;
- escape_write_byte(buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- }
- }
- }
- case 'C': {
- parser->current.end++;
- if (peek(parser) != '-') {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- parser->current.end++;
- if (parser->current.end == parser->end) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- uint8_t peeked = peek(parser);
- switch (peeked) {
- case '?': {
- parser->current.end++;
- escape_write_byte(buffer, flags, escape_byte(0x7f, flags));
- return;
- }
- case '\\':
- if (flags & PM_ESCAPE_FLAG_CONTROL) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
- return;
- }
- parser->current.end++;
- escape_read(parser, buffer, flags | PM_ESCAPE_FLAG_CONTROL);
- return;
- default: {
- if (!char_is_ascii_printable(peeked)) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- parser->current.end++;
- escape_write_byte(buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- }
- }
- }
- case 'M': {
- parser->current.end++;
- if (peek(parser) != '-') {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
- return;
- }
-
- parser->current.end++;
- if (parser->current.end == parser->end) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
- return;
- }
-
- uint8_t peeked = peek(parser);
- if (peeked == '\\') {
- if (flags & PM_ESCAPE_FLAG_META) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
- return;
- }
- parser->current.end++;
- escape_read(parser, buffer, flags | PM_ESCAPE_FLAG_META);
- return;
- }
-
- if (!char_is_ascii_printable(peeked)) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
- return;
- }
-
- parser->current.end++;
- escape_write_byte(buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
- return;
- }
- case '\r': {
- if (peek_offset(parser, 1) == '\n') {
- parser->current.end += 2;
- pm_buffer_append_byte(buffer, '\n');
- return;
- }
- }
- /* fallthrough */
- default: {
- if (parser->current.end < parser->end) {
- pm_buffer_append_byte(buffer, *parser->current.end++);
- }
- return;
- }
- }
-}
-
-/**
- * This function is responsible for lexing either a character literal or the ?
- * operator. The supported character literals are described below.
- *
- * \\a bell, ASCII 07h (BEL)
- * \\b backspace, ASCII 08h (BS)
- * \t horizontal tab, ASCII 09h (TAB)
- * \\n newline (line feed), ASCII 0Ah (LF)
- * \v vertical tab, ASCII 0Bh (VT)
- * \f form feed, ASCII 0Ch (FF)
- * \r carriage return, ASCII 0Dh (CR)
- * \\e escape, ASCII 1Bh (ESC)
- * \s space, ASCII 20h (SPC)
- * \\ backslash
- * \nnn octal bit pattern, where nnn is 1-3 octal digits ([0-7])
- * \xnn hexadecimal bit pattern, where nn is 1-2 hexadecimal digits ([0-9a-fA-F])
- * \unnnn Unicode character, where nnnn is exactly 4 hexadecimal digits ([0-9a-fA-F])
- * \u{nnnn ...} Unicode character(s), where each nnnn is 1-6 hexadecimal digits ([0-9a-fA-F])
- * \cx or \C-x control character, where x is an ASCII printable character
- * \M-x meta character, where x is an ASCII printable character
- * \M-\C-x meta control character, where x is an ASCII printable character
- * \M-\cx same as above
- * \\c\M-x same as above
- * \\c? or \C-? delete, ASCII 7Fh (DEL)
- */
-static pm_token_type_t
-lex_question_mark(pm_parser_t *parser) {
- if (lex_state_end_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- return PM_TOKEN_QUESTION_MARK;
- }
-
- if (parser->current.end >= parser->end) {
- pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
- pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
- return PM_TOKEN_CHARACTER_LITERAL;
- }
-
- if (pm_char_is_whitespace(*parser->current.end)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- return PM_TOKEN_QUESTION_MARK;
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- if (match(parser, '\\')) {
- lex_state_set(parser, PM_LEX_STATE_END);
-
- pm_buffer_t buffer;
- pm_buffer_init_capacity(&buffer, 3);
-
- escape_read(parser, &buffer, PM_ESCAPE_FLAG_SINGLE);
- pm_string_owned_init(&parser->current_string, (uint8_t *) buffer.value, buffer.length);
-
- return PM_TOKEN_CHARACTER_LITERAL;
- } else {
- size_t encoding_width = parser->encoding.char_width(parser->current.end, parser->end - parser->current.end);
-
- // Ternary operators can have a ? immediately followed by an identifier which starts with
- // an underscore. We check for this case
- if (
- !(parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
- peek(parser) == '_') ||
- (
- (parser->current.end + encoding_width >= parser->end) ||
- !char_is_identifier(parser, parser->current.end + encoding_width)
- )
- ) {
- lex_state_set(parser, PM_LEX_STATE_END);
- parser->current.end += encoding_width;
- pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
- return PM_TOKEN_CHARACTER_LITERAL;
- }
- }
-
- return PM_TOKEN_QUESTION_MARK;
-}
-
-/**
- * Lex a variable that starts with an @ sign (either an instance or class
- * variable).
- */
-static pm_token_type_t
-lex_at_variable(pm_parser_t *parser) {
- pm_token_type_t type = match(parser, '@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
- size_t width;
-
- if (parser->current.end < parser->end && (width = char_is_identifier_start(parser, parser->current.end)) > 0) {
- parser->current.end += width;
-
- while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0) {
- parser->current.end += width;
- }
- } else if (type == PM_TOKEN_CLASS_VARIABLE) {
- pm_parser_err_current(parser, PM_ERR_INCOMPLETE_VARIABLE_CLASS);
- } else {
- pm_parser_err_current(parser, PM_ERR_INCOMPLETE_VARIABLE_INSTANCE);
- }
-
- // If we're lexing an embedded variable, then we need to pop back into the
- // parent lex context.
- if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
- lex_mode_pop(parser);
- }
-
- return type;
-}
-
-/**
- * Optionally call out to the lex callback if one is provided.
- */
-static inline void
-parser_lex_callback(pm_parser_t *parser) {
- if (parser->lex_callback) {
- parser->lex_callback->callback(parser->lex_callback->data, parser, &parser->current);
- }
-}
-
-/**
- * Return a new comment node of the specified type.
- */
-static inline pm_comment_t *
-parser_comment(pm_parser_t *parser, pm_comment_type_t type) {
- pm_comment_t *comment = (pm_comment_t *) calloc(sizeof(pm_comment_t), 1);
- if (comment == NULL) return NULL;
-
- *comment = (pm_comment_t) {
- .type = type,
- .start = parser->current.start,
- .end = parser->current.end
- };
-
- return comment;
-}
-
-/**
- * Lex out embedded documentation, and return when we have either hit the end of
- * the file or the end of the embedded documentation. This calls the callback
- * manually because only the lexer should see these tokens, not the parser.
- */
-static pm_token_type_t
-lex_embdoc(pm_parser_t *parser) {
- // First, lex out the EMBDOC_BEGIN token.
- const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (newline == NULL) {
- parser->current.end = parser->end;
- } else {
- pm_newline_list_append(&parser->newline_list, newline);
- parser->current.end = newline + 1;
- }
-
- parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
- parser_lex_callback(parser);
-
- // Now, create a comment that is going to be attached to the parser.
- pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
- if (comment == NULL) return PM_TOKEN_EOF;
-
- // Now, loop until we find the end of the embedded documentation or the end of
- // the file.
- while (parser->current.end + 4 <= parser->end) {
- parser->current.start = parser->current.end;
-
- // If we've hit the end of the embedded documentation then we'll return that
- // token here.
- if (memcmp(parser->current.end, "=end", 4) == 0 &&
- (parser->current.end + 4 == parser->end || pm_char_is_whitespace(parser->current.end[4]))) {
- const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (newline == NULL) {
- parser->current.end = parser->end;
- } else {
- pm_newline_list_append(&parser->newline_list, newline);
- parser->current.end = newline + 1;
- }
-
- parser->current.type = PM_TOKEN_EMBDOC_END;
- parser_lex_callback(parser);
-
- comment->end = parser->current.end;
- pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
-
- return PM_TOKEN_EMBDOC_END;
- }
-
- // Otherwise, we'll parse until the end of the line and return a line of
- // embedded documentation.
- const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (newline == NULL) {
- parser->current.end = parser->end;
- } else {
- pm_newline_list_append(&parser->newline_list, newline);
- parser->current.end = newline + 1;
- }
-
- parser->current.type = PM_TOKEN_EMBDOC_LINE;
- parser_lex_callback(parser);
- }
-
- pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
-
- comment->end = parser->current.end;
- pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
-
- return PM_TOKEN_EOF;
-}
-
-/**
- * Set the current type to an ignored newline and then call the lex callback.
- * This happens in a couple places depending on whether or not we have already
- * lexed a comment.
- */
-static inline void
-parser_lex_ignored_newline(pm_parser_t *parser) {
- parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
- parser_lex_callback(parser);
-}
-
-/**
- * This function will be called when a newline is encountered. In some newlines,
- * we need to check if there is a heredoc or heredocs that we have already lexed
- * the body of that we need to now skip past. That will be indicated by the
- * heredoc_end field on the parser.
- *
- * If it is set, then we need to skip past the heredoc body and then clear the
- * heredoc_end field.
- */
-static inline void
-parser_flush_heredoc_end(pm_parser_t *parser) {
- assert(parser->heredoc_end <= parser->end);
- parser->next_start = parser->heredoc_end;
- parser->heredoc_end = NULL;
-}
-
-/**
- * When we're lexing certain types (strings, symbols, lists, etc.) we have
- * string content associated with the tokens. For example:
- *
- * "foo"
- *
- * In this case, the string content is foo. Since there is no escaping, there's
- * no need to track additional information and the token can be returned as
- * normal. However, if we have escape sequences:
- *
- * "foo\n"
- *
- * then the bytes in the string are "f", "o", "o", "\", "n", but we want to
- * provide out consumers with the string content "f", "o", "o", "\n". In these
- * cases, when we find the first escape sequence, we initialize a pm_buffer_t
- * to keep track of the string content. Then in the parser, it will
- * automatically attach the string content to the node that it belongs to.
- */
-typedef struct {
- /**
- * The buffer that we're using to keep track of the string content. It will
- * only be initialized if we receive an escape sequence.
- */
- pm_buffer_t buffer;
-
- /**
- * The cursor into the source string that points to how far we have
- * currently copied into the buffer.
- */
- const uint8_t *cursor;
-} pm_token_buffer_t;
-
-/**
- * Push the given byte into the token buffer.
- */
-static inline void
-pm_token_buffer_push(pm_token_buffer_t *token_buffer, uint8_t byte) {
- pm_buffer_append_byte(&token_buffer->buffer, byte);
-}
-
-/**
- * When we're about to return from lexing the current token and we know for sure
- * that we have found an escape sequence, this function is called to copy the
- *
- * contents of the token buffer into the current string on the parser so that it
- * can be attached to the correct node.
- */
-static inline void
-pm_token_buffer_copy(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
- pm_string_owned_init(&parser->current_string, (uint8_t *) token_buffer->buffer.value, token_buffer->buffer.length);
-}
-
-/**
- * When we're about to return from lexing the current token, we need to flush
- * all of the content that we have pushed into the buffer into the current
- * string. If we haven't pushed anything into the buffer, this means that we
- * never found an escape sequence, so we can directly reference the bounds of
- * the current string. Either way, at the return of this function it is expected
- *
- * that parser->current_string is established in such a way that it can be
- * attached to a node.
- */
-static void
-pm_token_buffer_flush(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
- if (token_buffer->cursor == NULL) {
- pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
- } else {
- pm_buffer_append_bytes(&token_buffer->buffer, token_buffer->cursor, (size_t) (parser->current.end - token_buffer->cursor));
- pm_token_buffer_copy(parser, token_buffer);
- }
-}
-
-/**
- * When we've found an escape sequence, we need to copy everything up to this
- * point into the buffer because we're about to provide a string that has
- * different content than a direct slice of the source.
- *
- *
- * It is expected that the parser's current token end will be pointing at one
- * byte past the backslash that starts the escape sequence.
- */
-static void
-pm_token_buffer_escape(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
- const uint8_t *start;
- if (token_buffer->cursor == NULL) {
- pm_buffer_init_capacity(&token_buffer->buffer, 16);
- start = parser->current.start;
- } else {
- start = token_buffer->cursor;
- }
-
- const uint8_t *end = parser->current.end - 1;
- pm_buffer_append_bytes(&token_buffer->buffer, start, (size_t) (end - start));
-}
-
-/**
- * Effectively the same thing as pm_strspn_inline_whitespace, but in the case of
- * a tilde heredoc expands out tab characters to the nearest tab boundaries.
- */
-static inline size_t
-pm_heredoc_strspn_inline_whitespace(pm_parser_t *parser, const uint8_t **cursor, pm_heredoc_indent_t indent) {
- size_t whitespace = 0;
-
- switch (indent) {
- case PM_HEREDOC_INDENT_NONE:
- // Do nothing, we can't match a terminator with
- // indentation and there's no need to calculate common
- // whitespace.
- break;
- case PM_HEREDOC_INDENT_DASH:
- // Skip past inline whitespace.
- *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
- break;
- case PM_HEREDOC_INDENT_TILDE:
- // Skip past inline whitespace and calculate common
- // whitespace.
- while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
- if (**cursor == '\t') {
- whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
- } else {
- whitespace++;
- }
- (*cursor)++;
- }
-
- break;
- }
-
- return whitespace;
-}
-
-/**
- * This is a convenience macro that will set the current token type, call the
- * lex callback, and then return from the parser_lex function.
- */
-#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
-
-/**
- * Called when the parser requires a new token. The parser maintains a moving
- * window of two tokens at a time: parser.previous and parser.current. This
- * function will move the current token into the previous token and then
- * lex a new token into the current token.
- */
-static void
-parser_lex(pm_parser_t *parser) {
- assert(parser->current.end <= parser->end);
- parser->previous = parser->current;
-
- // This value mirrors cmd_state from CRuby.
- bool previous_command_start = parser->command_start;
- parser->command_start = false;
-
- // This is used to communicate to the newline lexing function that we've
- // already seen a comment.
- bool lexed_comment = false;
-
- // Here we cache the current value of the semantic token seen flag. This is
- // used to reset it in case we find a token that shouldn't flip this flag.
- unsigned int semantic_token_seen = parser->semantic_token_seen;
- parser->semantic_token_seen = true;
-
- switch (parser->lex_modes.current->mode) {
- case PM_LEX_DEFAULT:
- case PM_LEX_EMBEXPR:
- case PM_LEX_EMBVAR:
-
- // We have a specific named label here because we are going to jump back to
- // this location in the event that we have lexed a token that should not be
- // returned to the parser. This includes comments, ignored newlines, and
- // invalid tokens of some form.
- lex_next_token: {
- // If we have the special next_start pointer set, then we're going to jump
- // to that location and start lexing from there.
- if (parser->next_start != NULL) {
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // This value mirrors space_seen from CRuby. It tracks whether or not
- // space has been eaten before the start of the next token.
- bool space_seen = false;
-
- // First, we're going to skip past any whitespace at the front of the next
- // token.
- bool chomping = true;
- while (parser->current.end < parser->end && chomping) {
- switch (*parser->current.end) {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- parser->current.end++;
- space_seen = true;
- break;
- case '\r':
- if (match_eol_offset(parser, 1)) {
- chomping = false;
- } else {
- parser->current.end++;
- space_seen = true;
- }
- break;
- case '\\': {
- size_t eol_length = match_eol_offset(parser, 1);
- if (eol_length) {
- if (parser->heredoc_end) {
- parser->current.end = parser->heredoc_end;
- parser->heredoc_end = NULL;
- } else {
- parser->current.end += eol_length + 1;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- space_seen = true;
- }
- } else if (pm_char_is_inline_whitespace(*parser->current.end)) {
- parser->current.end += 2;
- } else {
- chomping = false;
- }
-
- break;
- }
- default:
- chomping = false;
- break;
- }
- }
-
- // Next, we'll set to start of this token to be the current end.
- parser->current.start = parser->current.end;
-
- // We'll check if we're at the end of the file. If we are, then we
- // need to return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // Finally, we'll check the current character to determine the next
- // token.
- switch (*parser->current.end++) {
- case '\0': // NUL or end of script
- case '\004': // ^D
- case '\032': // ^Z
- parser->current.end--;
- LEX(PM_TOKEN_EOF);
-
- case '#': { // comments
- const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
- parser->current.end = ending == NULL ? parser->end : ending;
-
- // If we found a comment while lexing, then we're going to
- // add it to the list of comments in the file and keep
- // lexing.
- pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
- pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
-
- if (ending) parser->current.end++;
- parser->current.type = PM_TOKEN_COMMENT;
- parser_lex_callback(parser);
-
- // Here, parse the comment to see if it's a magic comment
- // and potentially change state on the parser.
- if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
- ptrdiff_t length = parser->current.end - parser->current.start;
-
- // If we didn't find a magic comment within the first
- // pass and we're at the start of the file, then we need
- // to do another pass to potentially find other patterns
- // for encoding comments.
- if (length >= 10) parser_lex_magic_comment_encoding(parser);
- }
-
- lexed_comment = true;
- }
- /* fallthrough */
- case '\r':
- case '\n': {
- parser->semantic_token_seen = semantic_token_seen & 0x1;
- size_t eol_length = match_eol_at(parser, parser->current.end - 1);
-
- if (eol_length) {
- // The only way you can have carriage returns in this
- // particular loop is if you have a carriage return
- // followed by a newline. In that case we'll just skip
- // over the carriage return and continue lexing, in
- // order to make it so that the newline token
- // encapsulates both the carriage return and the
- // newline. Note that we need to check that we haven't
- // already lexed a comment here because that falls
- // through into here as well.
- if (!lexed_comment) {
- parser->current.end += eol_length - 1; // skip CR
- }
-
- if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- }
- }
-
- if (parser->heredoc_end) {
- parser_flush_heredoc_end(parser);
- }
-
- // If this is an ignored newline, then we can continue lexing after
- // calling the callback with the ignored newline token.
- switch (lex_state_ignored_p(parser)) {
- case PM_IGNORED_NEWLINE_NONE:
- break;
- case PM_IGNORED_NEWLINE_PATTERN:
- if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- parser->current.type = PM_TOKEN_NEWLINE;
- return;
- }
- /* fallthrough */
- case PM_IGNORED_NEWLINE_ALL:
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lexed_comment = false;
- goto lex_next_token;
- }
-
- // Here we need to look ahead and see if there is a call operator
- // (either . or &.) that starts the next line. If there is, then this
- // is going to become an ignored newline and we're going to instead
- // return the call operator.
- const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
- next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
-
- if (next_content < parser->end) {
- // If we hit a comment after a newline, then we're going to check
- // if it's ignored or if it's followed by a method call ('.').
- // If it is, then we're going to call the
- // callback with an ignored newline and then continue lexing.
- // Otherwise we'll return a regular newline.
- if (next_content[0] == '#') {
- // Here we look for a "." or "&." following a "\n".
- const uint8_t *following = next_newline(next_content, parser->end - next_content);
-
- while (following && (following + 1 < parser->end)) {
- following++;
- following += pm_strspn_inline_whitespace(following, parser->end - following);
-
- // If this is not followed by a comment, then we can break out
- // of this loop.
- if (peek_at(parser, following) != '#') break;
-
- // If there is a comment, then we need to find the end of the
- // comment and continue searching from there.
- following = next_newline(following, parser->end - following);
- }
-
- // If the lex state was ignored, or we hit a '.' or a '&.',
- // we will lex the ignored newline
- if (
- lex_state_ignored_p(parser) ||
- (following && (
- (peek_at(parser, following) == '.') ||
- (peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '.')
- ))
- ) {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lexed_comment = false;
- goto lex_next_token;
- }
- }
-
- // If we hit a . after a newline, then we're in a call chain and
- // we need to return the call operator.
- if (next_content[0] == '.') {
- // To match ripper, we need to emit an ignored newline even though
- // its a real newline in the case that we have a beginless range
- // on a subsequent line.
- if (peek_at(parser, next_content + 1) == '.') {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- parser->current.type = PM_TOKEN_NEWLINE;
- return;
- }
-
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_DOT);
- parser->current.start = next_content;
- parser->current.end = next_content + 1;
- parser->next_start = NULL;
- LEX(PM_TOKEN_DOT);
- }
-
- // If we hit a &. after a newline, then we're in a call chain and
- // we need to return the call operator.
- if (peek_at(parser, next_content) == '&' && peek_at(parser, next_content + 1) == '.') {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_DOT);
- parser->current.start = next_content;
- parser->current.end = next_content + 2;
- parser->next_start = NULL;
- LEX(PM_TOKEN_AMPERSAND_DOT);
- }
- }
-
- // At this point we know this is a regular newline, and we can set the
- // necessary state and return the token.
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- parser->current.type = PM_TOKEN_NEWLINE;
- if (!lexed_comment) parser_lex_callback(parser);
- return;
- }
-
- // ,
- case ',':
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- LEX(PM_TOKEN_COMMA);
-
- // (
- case '(': {
- pm_token_type_t type = PM_TOKEN_PARENTHESIS_LEFT;
-
- if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
- type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
- }
-
- parser->enclosure_nesting++;
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- pm_do_loop_stack_push(parser, false);
- LEX(type);
- }
-
- // )
- case ')':
- parser->enclosure_nesting--;
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- pm_do_loop_stack_pop(parser);
- LEX(PM_TOKEN_PARENTHESIS_RIGHT);
-
- // ;
- case ';':
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- LEX(PM_TOKEN_SEMICOLON);
-
- // [ [] []=
- case '[':
- parser->enclosure_nesting++;
- pm_token_type_t type = PM_TOKEN_BRACKET_LEFT;
-
- if (lex_state_operator_p(parser)) {
- if (match(parser, ']')) {
- parser->enclosure_nesting--;
- lex_state_set(parser, PM_LEX_STATE_ARG);
- LEX(match(parser, '=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
- }
-
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
- LEX(type);
- }
-
- if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
- type = PM_TOKEN_BRACKET_LEFT_ARRAY;
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- pm_do_loop_stack_push(parser, false);
- LEX(type);
-
- // ]
- case ']':
- parser->enclosure_nesting--;
- lex_state_set(parser, PM_LEX_STATE_END);
- pm_do_loop_stack_pop(parser);
- LEX(PM_TOKEN_BRACKET_RIGHT);
-
- // {
- case '{': {
- pm_token_type_t type = PM_TOKEN_BRACE_LEFT;
-
- if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
- // This { begins a lambda
- parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- type = PM_TOKEN_LAMBDA_BEGIN;
- } else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
- // This { begins a hash literal
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- } else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
- // This { begins a block
- parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- } else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
- // This { begins a block on a command
- parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- } else {
- // This { begins a hash literal
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- }
-
- parser->enclosure_nesting++;
- parser->brace_nesting++;
- pm_do_loop_stack_push(parser, false);
-
- LEX(type);
- }
-
- // }
- case '}':
- parser->enclosure_nesting--;
- pm_do_loop_stack_pop(parser);
-
- if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
- lex_mode_pop(parser);
- LEX(PM_TOKEN_EMBEXPR_END);
- }
-
- parser->brace_nesting--;
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(PM_TOKEN_BRACE_RIGHT);
-
- // * ** **= *=
- case '*': {
- if (match(parser, '*')) {
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_STAR_STAR_EQUAL);
- }
-
- pm_token_type_t type = PM_TOKEN_STAR_STAR;
-
- if (lex_state_spcarg_p(parser, space_seen) || lex_state_beg_p(parser)) {
- type = PM_TOKEN_USTAR_STAR;
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(type);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_STAR_EQUAL);
- }
-
- pm_token_type_t type = PM_TOKEN_STAR;
-
- if (lex_state_spcarg_p(parser, space_seen)) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
- type = PM_TOKEN_USTAR;
- } else if (lex_state_beg_p(parser)) {
- type = PM_TOKEN_USTAR;
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(type);
- }
-
- // ! != !~ !@
- case '!':
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- if (match(parser, '@')) {
- LEX(PM_TOKEN_BANG);
- }
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- if (match(parser, '=')) {
- LEX(PM_TOKEN_BANG_EQUAL);
- }
-
- if (match(parser, '~')) {
- LEX(PM_TOKEN_BANG_TILDE);
- }
-
- LEX(PM_TOKEN_BANG);
-
- // = => =~ == === =begin
- case '=':
- if (current_token_starts_line(parser) && (parser->current.end + 5 <= parser->end) && memcmp(parser->current.end, "begin", 5) == 0 && pm_char_is_whitespace(peek_offset(parser, 5))) {
- pm_token_type_t type = lex_embdoc(parser);
-
- if (type == PM_TOKEN_EOF) {
- LEX(type);
- }
-
- goto lex_next_token;
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- if (match(parser, '>')) {
- LEX(PM_TOKEN_EQUAL_GREATER);
- }
-
- if (match(parser, '~')) {
- LEX(PM_TOKEN_EQUAL_TILDE);
- }
-
- if (match(parser, '=')) {
- LEX(match(parser, '=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
- }
-
- LEX(PM_TOKEN_EQUAL);
-
- // < << <<= <= <=>
- case '<':
- if (match(parser, '<')) {
- if (
- !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
- !lex_state_end_p(parser) &&
- (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
- ) {
- const uint8_t *end = parser->current.end;
-
- pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
- pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
-
- if (match(parser, '-')) {
- indent = PM_HEREDOC_INDENT_DASH;
- }
- else if (match(parser, '~')) {
- indent = PM_HEREDOC_INDENT_TILDE;
- }
-
- if (match(parser, '`')) {
- quote = PM_HEREDOC_QUOTE_BACKTICK;
- }
- else if (match(parser, '"')) {
- quote = PM_HEREDOC_QUOTE_DOUBLE;
- }
- else if (match(parser, '\'')) {
- quote = PM_HEREDOC_QUOTE_SINGLE;
- }
-
- const uint8_t *ident_start = parser->current.end;
- size_t width = 0;
-
- if (parser->current.end >= parser->end) {
- parser->current.end = end;
- } else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end)) == 0) {
- parser->current.end = end;
- } else {
- if (quote == PM_HEREDOC_QUOTE_NONE) {
- parser->current.end += width;
-
- while ((parser->current.end < parser->end) && (width = char_is_identifier(parser, parser->current.end))) {
- parser->current.end += width;
- }
- } else {
- // If we have quotes, then we're going to go until we find the
- // end quote.
- while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
- parser->current.end++;
- }
- }
-
- size_t ident_length = (size_t) (parser->current.end - ident_start);
- if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
- // TODO: handle unterminated heredoc
- }
-
- lex_mode_push(parser, (pm_lex_mode_t) {
- .mode = PM_LEX_HEREDOC,
- .as.heredoc = {
- .ident_start = ident_start,
- .ident_length = ident_length,
- .next_start = parser->current.end,
- .quote = quote,
- .indent = indent,
- .common_whitespace = (size_t) -1
- }
- });
-
- if (parser->heredoc_end == NULL) {
- const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (body_start == NULL) {
- // If there is no newline after the heredoc identifier, then
- // this is not a valid heredoc declaration. In this case we
- // will add an error, but we will still return a heredoc
- // start.
- pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
- body_start = parser->end;
- } else {
- // Otherwise, we want to indicate that the body of the
- // heredoc starts on the character after the next newline.
- pm_newline_list_append(&parser->newline_list, body_start);
- body_start++;
- }
-
- parser->next_start = body_start;
- } else {
- parser->next_start = parser->heredoc_end;
- }
-
- LEX(PM_TOKEN_HEREDOC_START);
- }
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_LESS_LESS_EQUAL);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(PM_TOKEN_LESS_LESS);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- if (match(parser, '=')) {
- if (match(parser, '>')) {
- LEX(PM_TOKEN_LESS_EQUAL_GREATER);
- }
-
- LEX(PM_TOKEN_LESS_EQUAL);
- }
-
- LEX(PM_TOKEN_LESS);
-
- // > >> >>= >=
- case '>':
- if (match(parser, '>')) {
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
- LEX(match(parser, '=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(match(parser, '=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
-
- // double-quoted string literal
- case '"': {
- bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
- lex_mode_push_string(parser, true, label_allowed, '\0', '"');
- LEX(PM_TOKEN_STRING_BEGIN);
- }
-
- // xstring literal
- case '`': {
- if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- LEX(PM_TOKEN_BACKTICK);
- }
-
- if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
- if (previous_command_start) {
- lex_state_set(parser, PM_LEX_STATE_CMDARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- }
-
- LEX(PM_TOKEN_BACKTICK);
- }
-
- lex_mode_push_string(parser, true, false, '\0', '`');
- LEX(PM_TOKEN_BACKTICK);
- }
-
- // single-quoted string literal
- case '\'': {
- bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
- lex_mode_push_string(parser, false, label_allowed, '\0', '\'');
- LEX(PM_TOKEN_STRING_BEGIN);
- }
-
- // ? character literal
- case '?':
- LEX(lex_question_mark(parser));
-
- // & && &&= &=
- case '&': {
- if (match(parser, '&')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- if (match(parser, '=')) {
- LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- }
-
- LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_AMPERSAND_EQUAL);
- }
-
- if (match(parser, '.')) {
- lex_state_set(parser, PM_LEX_STATE_DOT);
- LEX(PM_TOKEN_AMPERSAND_DOT);
- }
-
- pm_token_type_t type = PM_TOKEN_AMPERSAND;
- if (lex_state_spcarg_p(parser, space_seen) || lex_state_beg_p(parser)) {
- type = PM_TOKEN_UAMPERSAND;
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(type);
- }
-
- // | || ||= |=
- case '|':
- if (match(parser, '|')) {
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
- }
-
- if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
- parser->current.end--;
- LEX(PM_TOKEN_PIPE);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PIPE_PIPE);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PIPE_EQUAL);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- }
-
- LEX(PM_TOKEN_PIPE);
-
- // + += +@
- case '+': {
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
-
- if (match(parser, '@')) {
- LEX(PM_TOKEN_UPLUS);
- }
-
- LEX(PM_TOKEN_PLUS);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PLUS_EQUAL);
- }
-
- bool spcarg = lex_state_spcarg_p(parser, space_seen);
- if (spcarg) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS);
- }
-
- if (lex_state_beg_p(parser) || spcarg) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- if (pm_char_is_decimal_digit(peek(parser))) {
- parser->current.end++;
- pm_token_type_t type = lex_numeric(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(type);
- }
-
- LEX(PM_TOKEN_UPLUS);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PLUS);
- }
-
- // - -= -@
- case '-': {
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
-
- if (match(parser, '@')) {
- LEX(PM_TOKEN_UMINUS);
- }
-
- LEX(PM_TOKEN_MINUS);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_MINUS_EQUAL);
- }
-
- if (match(parser, '>')) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- LEX(PM_TOKEN_MINUS_GREATER);
- }
-
- bool spcarg = lex_state_spcarg_p(parser, space_seen);
- if (spcarg) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
- }
-
- if (lex_state_beg_p(parser) || spcarg) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_MINUS);
- }
-
- // . .. ...
- case '.': {
- bool beg_p = lex_state_beg_p(parser);
-
- if (match(parser, '.')) {
- if (match(parser, '.')) {
- // If we're _not_ inside a range within default parameters
- if (
- !context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) &&
- context_p(parser, PM_CONTEXT_DEF_PARAMS)
- ) {
- if (lex_state_p(parser, PM_LEX_STATE_END)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_ENDARG);
- }
- LEX(PM_TOKEN_UDOT_DOT_DOT);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
- }
-
- lex_state_set(parser, PM_LEX_STATE_DOT);
- LEX(PM_TOKEN_DOT);
- }
-
- // integer
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- pm_token_type_t type = lex_numeric(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(type);
- }
-
- // :: symbol
- case ':':
- if (match(parser, ':')) {
- if (lex_state_beg_p(parser) || lex_state_p(parser, PM_LEX_STATE_CLASS) || (lex_state_p(parser, PM_LEX_STATE_ARG_ANY) && space_seen)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_UCOLON_COLON);
- }
-
- lex_state_set(parser, PM_LEX_STATE_DOT);
- LEX(PM_TOKEN_COLON_COLON);
- }
-
- if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) == '#') {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_COLON);
- }
-
- if (peek(parser) == '"' || peek(parser) == '\'') {
- lex_mode_push_string(parser, peek(parser) == '"', false, '\0', *parser->current.end);
- parser->current.end++;
- }
-
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- LEX(PM_TOKEN_SYMBOL_BEGIN);
-
- // / /=
- case '/':
- if (lex_state_beg_p(parser)) {
- lex_mode_push_regexp(parser, '\0', '/');
- LEX(PM_TOKEN_REGEXP_BEGIN);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_SLASH_EQUAL);
- }
-
- if (lex_state_spcarg_p(parser, space_seen)) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
- lex_mode_push_regexp(parser, '\0', '/');
- LEX(PM_TOKEN_REGEXP_BEGIN);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(PM_TOKEN_SLASH);
-
- // ^ ^=
- case '^':
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
- LEX(match(parser, '=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
-
- // ~ ~@
- case '~':
- if (lex_state_operator_p(parser)) {
- (void) match(parser, '@');
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(PM_TOKEN_TILDE);
-
- // % %= %i %I %q %Q %w %W
- case '%': {
- // If there is no subsequent character then we have an
- // invalid token. We're going to say it's the percent
- // operator because we don't want to move into the string
- // lex mode unnecessarily.
- if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
- LEX(PM_TOKEN_PERCENT);
- }
-
- if (!lex_state_beg_p(parser) && match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PERCENT_EQUAL);
- } else if (
- lex_state_beg_p(parser) ||
- (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) == 's')) ||
- lex_state_spcarg_p(parser, space_seen)
- ) {
- if (!parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end)) {
- if (*parser->current.end >= 0x80) {
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
- }
-
- lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
-
- size_t eol_length = match_eol(parser);
- if (eol_length) {
- parser->current.end += eol_length;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- } else {
- parser->current.end++;
- }
-
- if (parser->current.end < parser->end) {
- LEX(PM_TOKEN_STRING_BEGIN);
- }
- }
-
- // Delimiters for %-literals cannot be alphanumeric. We
- // validate that here.
- uint8_t delimiter = peek_offset(parser, 1);
- if (delimiter >= 0x80 || parser->encoding.alnum_char(&delimiter, 1)) {
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
- goto lex_next_token;
- }
-
- switch (peek(parser)) {
- case 'i': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, false, *parser->current.end++);
- }
-
- LEX(PM_TOKEN_PERCENT_LOWER_I);
- }
- case 'I': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, true, *parser->current.end++);
- }
-
- LEX(PM_TOKEN_PERCENT_UPPER_I);
- }
- case 'r': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_regexp(parser, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
- pm_newline_list_check_append(&parser->newline_list, parser->current.end);
- parser->current.end++;
- }
-
- LEX(PM_TOKEN_REGEXP_BEGIN);
- }
- case 'q': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_string(parser, false, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
- pm_newline_list_check_append(&parser->newline_list, parser->current.end);
- parser->current.end++;
- }
-
- LEX(PM_TOKEN_STRING_BEGIN);
- }
- case 'Q': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
- pm_newline_list_check_append(&parser->newline_list, parser->current.end);
- parser->current.end++;
- }
-
- LEX(PM_TOKEN_STRING_BEGIN);
- }
- case 's': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_string(parser, false, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
- lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
- parser->current.end++;
- }
-
- LEX(PM_TOKEN_SYMBOL_BEGIN);
- }
- case 'w': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, false, *parser->current.end++);
- }
-
- LEX(PM_TOKEN_PERCENT_LOWER_W);
- }
- case 'W': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, true, *parser->current.end++);
- }
-
- LEX(PM_TOKEN_PERCENT_UPPER_W);
- }
- case 'x': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
- parser->current.end++;
- }
-
- LEX(PM_TOKEN_PERCENT_LOWER_X);
- }
- default:
- // If we get to this point, then we have a % that is completely
- // unparseable. In this case we'll just drop it from the parser
- // and skip past it and hope that the next token is something
- // that we can parse.
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
- goto lex_next_token;
- }
- }
-
- lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PERCENT);
- }
-
- // global variable
- case '$': {
- pm_token_type_t type = lex_global_variable(parser);
-
- // If we're lexing an embedded variable, then we need to pop back into
- // the parent lex context.
- if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
- lex_mode_pop(parser);
- }
-
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(type);
- }
-
- // instance variable, class variable
- case '@':
- lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
- LEX(lex_at_variable(parser));
-
- default: {
- if (*parser->current.start != '_') {
- size_t width = char_is_identifier_start(parser, parser->current.start);
-
- // If this isn't the beginning of an identifier, then it's an invalid
- // token as we've exhausted all of the other options. We'll skip past
- // it and return the next token.
- if (!width) {
- pm_parser_err_current(parser, PM_ERR_INVALID_TOKEN);
- goto lex_next_token;
- }
-
- parser->current.end = parser->current.start + width;
- }
-
- pm_token_type_t type = lex_identifier(parser, previous_command_start);
-
- // If we've hit a __END__ and it was at the start of the line or the
- // start of the file and it is followed by either a \n or a \r\n, then
- // this is the last token of the file.
- if (
- ((parser->current.end - parser->current.start) == 7) &&
- current_token_starts_line(parser) &&
- (memcmp(parser->current.start, "__END__", 7) == 0) &&
- (parser->current.end == parser->end || match_eol(parser))
- )
- {
- // Since we know we're about to add an __END__ comment, we know we
- // need at add all of the newlines to get the correct column
- // information for it.
- const uint8_t *cursor = parser->current.end;
- while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
- pm_newline_list_append(&parser->newline_list, cursor++);
- }
-
- parser->current.end = parser->end;
- parser->current.type = PM_TOKEN___END__;
- parser_lex_callback(parser);
-
- pm_comment_t *comment = parser_comment(parser, PM_COMMENT___END__);
- pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
-
- LEX(PM_TOKEN_EOF);
- }
-
- pm_lex_state_t last_state = parser->lex_state;
-
- if (type == PM_TOKEN_IDENTIFIER || type == PM_TOKEN_CONSTANT || type == PM_TOKEN_METHOD_NAME) {
- if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
- if (previous_command_start) {
- lex_state_set(parser, PM_LEX_STATE_CMDARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- }
- } else if (parser->lex_state == PM_LEX_STATE_FNAME) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- } else {
- lex_state_set(parser, PM_LEX_STATE_END);
- }
- }
-
- if (
- !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
- (type == PM_TOKEN_IDENTIFIER) &&
- ((pm_parser_local_depth(parser, &parser->current) != -1) ||
- token_is_numbered_parameter(parser->current.start, parser->current.end))
- ) {
- lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
- }
-
- LEX(type);
- }
- }
- }
- case PM_LEX_LIST: {
- if (parser->next_start != NULL) {
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // First we'll set the beginning of the token.
- parser->current.start = parser->current.end;
-
- // If there's any whitespace at the start of the list, then we're
- // going to trim it off the beginning and create a new token.
- size_t whitespace;
-
- if (parser->heredoc_end) {
- whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
- if (peek_offset(parser, (ptrdiff_t)whitespace) == '\n') {
- whitespace += 1;
- }
- } else {
- whitespace = pm_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list);
- }
-
- if (whitespace > 0) {
- parser->current.end += whitespace;
- if (peek_offset(parser, -1) == '\n') {
- // mutates next_start
- parser_flush_heredoc_end(parser);
- }
- LEX(PM_TOKEN_WORDS_SEP);
- }
-
- // We'll check if we're at the end of the file. If we are, then we
- // need to return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // Here we'll get a list of the places where strpbrk should break,
- // and then find the first one.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
-
- // If we haven't found an escape yet, then this buffer will be
- // unallocated since we can refer directly to the source string.
- pm_token_buffer_t token_buffer = { { 0 }, 0 };
-
- while (breakpoint != NULL) {
- // If we hit a null byte, skip directly past it.
- if (*breakpoint == '\0') {
- breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1));
- continue;
- }
-
- // If we hit whitespace, then we must have received content by
- // now, so we can return an element of the list.
- if (pm_char_is_whitespace(*breakpoint)) {
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we hit the terminator, we need to check which token to
- // return.
- if (*breakpoint == lex_mode->as.list.terminator) {
- // If this terminator doesn't actually close the list, then
- // we need to continue on past it.
- if (lex_mode->as.list.nesting > 0) {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- lex_mode->as.list.nesting--;
- continue;
- }
-
- // If we've hit the terminator and we've already skipped
- // past content, then we can return a list node.
- if (breakpoint > parser->current.start) {
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // Otherwise, switch back to the default state and return
- // the end of the list.
- parser->current.end = breakpoint + 1;
- lex_mode_pop(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(PM_TOKEN_STRING_END);
- }
-
- // If we hit escapes, then we need to treat the next token
- // literally. In this case we'll skip past the next character
- // and find the next breakpoint.
- if (*breakpoint == '\\') {
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of the
- // loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- continue;
- }
-
- pm_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- switch (peeked) {
- case ' ':
- case '\f':
- case '\t':
- case '\v':
- case '\\':
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- break;
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- pm_token_buffer_push(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- pm_token_buffer_push(&token_buffer, '\n');
-
- if (parser->heredoc_end) {
- // ... if we are on the same line as a heredoc,
- // flush the heredoc and continue parsing after
- // heredoc_end.
- parser_flush_heredoc_end(parser);
- pm_token_buffer_copy(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- } else {
- // ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
- }
-
- parser->current.end++;
- break;
- default:
- if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- } else if (lex_mode->as.list.interpolation) {
- escape_read(parser, &token_buffer.buffer, PM_ESCAPE_FLAG_NONE);
- } else {
- pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- }
-
- break;
- }
-
- token_buffer.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- }
-
- // If we hit a #, then we will attempt to lex interpolation.
- if (*breakpoint == '#') {
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had something
- // that looked like an interpolated class or instance variable
- // like "#@" but wasn't actually. In this case we'll just skip
- // to the next breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
-
- // If we've hit the incrementor, then we need to skip past it
- // and find the next breakpoint.
- assert(*breakpoint == lex_mode->as.list.incrementor);
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- lex_mode->as.list.nesting++;
- continue;
- }
-
- if (parser->current.end > parser->current.start) {
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we were unable to find a breakpoint, then this token hits the
- // end of the file.
- LEX(PM_TOKEN_EOF);
- }
- case PM_LEX_REGEXP: {
- // First, we'll set to start of this token to be the current end.
- if (parser->next_start == NULL) {
- parser->current.start = parser->current.end;
- } else {
- parser->current.start = parser->next_start;
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // We'll check if we're at the end of the file. If we are, then we need to
- // return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // Get a reference to the current mode.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
-
- // These are the places where we need to split up the content of the
- // regular expression. We'll use strpbrk to find the first of these
- // characters.
- const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- pm_token_buffer_t token_buffer = { { 0 }, 0 };
-
- while (breakpoint != NULL) {
- // If we hit a null byte, skip directly past it.
- if (*breakpoint == '\0') {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- }
-
- // If we've hit a newline, then we need to track that in the
- // list of newlines.
- if (*breakpoint == '\n') {
- // For the special case of a newline-terminated regular expression, we will pass
- // through this branch twice -- once with PM_TOKEN_REGEXP_BEGIN and then again
- // with PM_TOKEN_STRING_CONTENT. Let's avoid tracking the newline twice, by
- // tracking it only in the REGEXP_BEGIN case.
- if (
- !(lex_mode->as.regexp.terminator == '\n' && parser->current.type != PM_TOKEN_REGEXP_BEGIN)
- && parser->heredoc_end == NULL
- ) {
- pm_newline_list_append(&parser->newline_list, breakpoint);
- }
-
- if (lex_mode->as.regexp.terminator != '\n') {
- // If the terminator is not a newline, then we can set
- // the next breakpoint and continue.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- }
- }
-
- // If we hit the terminator, we need to determine what kind of
- // token to return.
- if (*breakpoint == lex_mode->as.regexp.terminator) {
- if (lex_mode->as.regexp.nesting > 0) {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- lex_mode->as.regexp.nesting--;
- continue;
- }
-
- // Here we've hit the terminator. If we have already consumed
- // content then we need to return that content as string content
- // first.
- if (breakpoint > parser->current.start) {
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // Since we've hit the terminator of the regular expression,
- // we now need to parse the options.
- parser->current.end = breakpoint + 1;
- parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
-
- lex_mode_pop(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(PM_TOKEN_REGEXP_END);
- }
-
- // If we hit escapes, then we need to treat the next token
- // literally. In this case we'll skip past the next character
- // and find the next breakpoint.
- if (*breakpoint == '\\') {
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of the
- // loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- continue;
- }
-
- pm_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- switch (peeked) {
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- if (parser->heredoc_end) {
- // ... if we are on the same line as a heredoc,
- // flush the heredoc and continue parsing after
- // heredoc_end.
- parser_flush_heredoc_end(parser);
- pm_token_buffer_copy(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- } else {
- // ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
- }
-
- parser->current.end++;
- break;
- case 'c':
- case 'C':
- case 'M':
- case 'u':
- case 'x':
- escape_read(parser, &token_buffer.buffer, PM_ESCAPE_FLAG_REGEXP);
- break;
- default:
- if (lex_mode->as.regexp.terminator == '/' && peeked == '/') {
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- break;
- }
-
- if (peeked < 0x80) pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- break;
- }
-
- token_buffer.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- }
-
- // If we hit a #, then we will attempt to lex interpolation.
- if (*breakpoint == '#') {
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had
- // something that looked like an interpolated class or
- // instance variable like "#@" but wasn't actually. In
- // this case we'll just skip to the next breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
-
- // If we've hit the incrementor, then we need to skip past it
- // and find the next breakpoint.
- assert(*breakpoint == lex_mode->as.regexp.incrementor);
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- lex_mode->as.regexp.nesting++;
- continue;
- }
-
- if (parser->current.end > parser->current.start) {
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we were unable to find a breakpoint, then this token hits the
- // end of the file.
- LEX(PM_TOKEN_EOF);
- }
- case PM_LEX_STRING: {
- // First, we'll set to start of this token to be the current end.
- if (parser->next_start == NULL) {
- parser->current.start = parser->current.end;
- } else {
- parser->current.start = parser->next_start;
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // We'll check if we're at the end of the file. If we are, then we need to
- // return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // These are the places where we need to split up the content of the
- // string. We'll use strpbrk to find the first of these characters.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
-
- // If we haven't found an escape yet, then this buffer will be
- // unallocated since we can refer directly to the source string.
- pm_token_buffer_t token_buffer = { { 0 }, 0 };
-
- while (breakpoint != NULL) {
- // If we hit the incrementor, then we'll increment then nesting and
- // continue lexing.
- if (lex_mode->as.string.incrementor != '\0' && *breakpoint == lex_mode->as.string.incrementor) {
- lex_mode->as.string.nesting++;
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- }
-
- // Note that we have to check the terminator here first because we could
- // potentially be parsing a % string that has a # character as the
- // terminator.
- if (*breakpoint == lex_mode->as.string.terminator) {
- // If this terminator doesn't actually close the string, then we need
- // to continue on past it.
- if (lex_mode->as.string.nesting > 0) {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- lex_mode->as.string.nesting--;
- continue;
- }
-
- // Here we've hit the terminator. If we have already consumed content
- // then we need to return that content as string content first.
- if (breakpoint > parser->current.start) {
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // Otherwise we need to switch back to the parent lex mode and
- // return the end of the string.
- size_t eol_length = match_eol_at(parser, breakpoint);
- if (eol_length) {
- parser->current.end = breakpoint + eol_length;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- } else {
- parser->current.end = breakpoint + 1;
- }
-
- if (lex_mode->as.string.label_allowed && (peek(parser) == ':') && (peek_offset(parser, 1) != ':')) {
- parser->current.end++;
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
- lex_mode_pop(parser);
- LEX(PM_TOKEN_LABEL_END);
- }
-
- lex_state_set(parser, PM_LEX_STATE_END);
- lex_mode_pop(parser);
- LEX(PM_TOKEN_STRING_END);
- }
-
- // When we hit a newline, we need to flush any potential heredocs. Note
- // that this has to happen after we check for the terminator in case the
- // terminator is a newline character.
- if (*breakpoint == '\n') {
- if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, breakpoint);
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- continue;
- } else {
- parser->current.end = breakpoint + 1;
- parser_flush_heredoc_end(parser);
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- }
-
- switch (*breakpoint) {
- case '\0':
- // Skip directly past the null character.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- break;
- case '\\': {
- // Here we hit escapes.
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of
- // the loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- continue;
- }
-
- pm_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- switch (peeked) {
- case '\\':
- pm_token_buffer_push(&token_buffer, '\\');
- parser->current.end++;
- break;
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- if (!lex_mode->as.string.interpolation) {
- pm_token_buffer_push(&token_buffer, '\\');
- }
- pm_token_buffer_push(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- if (!lex_mode->as.string.interpolation) {
- pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, '\n');
- }
-
- if (parser->heredoc_end) {
- // ... if we are on the same line as a heredoc,
- // flush the heredoc and continue parsing after
- // heredoc_end.
- parser_flush_heredoc_end(parser);
- pm_token_buffer_copy(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- } else {
- // ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
- }
-
- parser->current.end++;
- break;
- default:
- if (lex_mode->as.string.incrementor != '\0' && peeked == lex_mode->as.string.incrementor) {
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- } else if (lex_mode->as.string.terminator != '\0' && peeked == lex_mode->as.string.terminator) {
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- } else if (lex_mode->as.string.interpolation) {
- escape_read(parser, &token_buffer.buffer, PM_ESCAPE_FLAG_NONE);
- } else {
- pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, peeked);
- parser->current.end++;
- }
-
- break;
- }
-
- token_buffer.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- break;
- }
- case '#': {
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had something that
- // looked like an interpolated class or instance variable like "#@"
- // but wasn't actually. In this case we'll just skip to the next
- // breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- break;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
- default:
- assert(false && "unreachable");
- }
- }
-
- if (parser->current.end > parser->current.start) {
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we've hit the end of the string, then this is an unterminated
- // string. In that case we'll return the EOF token.
- LEX(PM_TOKEN_EOF);
- }
- case PM_LEX_HEREDOC: {
- // First, we'll set to start of this token.
- if (parser->next_start == NULL) {
- parser->current.start = parser->current.end;
- } else {
- parser->current.start = parser->next_start;
- parser->current.end = parser->next_start;
- parser->heredoc_end = NULL;
- parser->next_start = NULL;
- }
-
- // We'll check if we're at the end of the file. If we are, then we need to
- // return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // Now let's grab the information about the identifier off of the current
- // lex mode.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- const uint8_t *ident_start = lex_mode->as.heredoc.ident_start;
- size_t ident_length = lex_mode->as.heredoc.ident_length;
-
- // If we are immediately following a newline and we have hit the
- // terminator, then we need to return the ending of the heredoc.
- if (current_token_starts_line(parser)) {
- const uint8_t *start = parser->current.start;
- size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.indent);
-
- if ((start + ident_length <= parser->end) && (memcmp(start, ident_start, ident_length) == 0)) {
- bool matched = true;
- bool at_end = false;
-
- size_t eol_length = match_eol_at(parser, start + ident_length);
- if (eol_length) {
- parser->current.end = start + ident_length + eol_length;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- } else if (parser->end == (start + ident_length)) {
- parser->current.end = start + ident_length;
- at_end = true;
- } else {
- matched = false;
- }
-
- if (matched) {
- if (*lex_mode->as.heredoc.next_start == '\\') {
- parser->next_start = NULL;
- } else {
- parser->next_start = lex_mode->as.heredoc.next_start;
- parser->heredoc_end = parser->current.end;
- }
-
- lex_mode_pop(parser);
- if (!at_end) {
- lex_state_set(parser, PM_LEX_STATE_END);
- }
- LEX(PM_TOKEN_HEREDOC_END);
- }
- }
-
- if (
- lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE &&
- (lex_mode->as.heredoc.common_whitespace > whitespace) &&
- peek_at(parser, start) != '\n'
- ) {
- lex_mode->as.heredoc.common_whitespace = whitespace;
- }
- }
-
- // Otherwise we'll be parsing string content. These are the places
- // where we need to split up the content of the heredoc. We'll use
- // strpbrk to find the first of these characters.
- uint8_t breakpoints[] = "\n\\#";
-
- pm_heredoc_quote_t quote = lex_mode->as.heredoc.quote;
- if (quote == PM_HEREDOC_QUOTE_SINGLE) {
- breakpoints[2] = '\0';
- }
-
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- pm_token_buffer_t token_buffer = { { 0 }, 0 };
- bool was_escaped_newline = false;
-
- while (breakpoint != NULL) {
- switch (*breakpoint) {
- case '\0':
- // Skip directly past the null character.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- break;
- case '\n': {
- if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
- parser_flush_heredoc_end(parser);
- parser->current.end = breakpoint + 1;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- pm_newline_list_append(&parser->newline_list, breakpoint);
-
- // If we have a - or ~ heredoc, then we can match after
- // some leading whitespace.
- const uint8_t *start = breakpoint + 1;
- size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.indent);
-
- // If we have hit a newline that is followed by a valid
- // terminator, then we need to return the content of the
- // heredoc here as string content. Then, the next time a
- // token is lexed, it will match again and return the
- // end of the heredoc.
- if (
- !was_escaped_newline &&
- (start + ident_length <= parser->end) &&
- (memcmp(start, ident_start, ident_length) == 0)
- ) {
- // Heredoc terminators must be followed by a
- // newline, CRLF, or EOF to be valid.
- if (
- start + ident_length == parser->end ||
- match_eol_at(parser, start + ident_length)
- ) {
- parser->current.end = breakpoint + 1;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- }
-
- if (lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE) {
- if ((lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) != '\n') {
- lex_mode->as.heredoc.common_whitespace = whitespace;
- }
-
- parser->current.end = breakpoint + 1;
-
- if (!was_escaped_newline) {
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- }
-
- // Otherwise we hit a newline and it wasn't followed by
- // a terminator, so we can continue parsing.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- break;
- }
- case '\\': {
- // If we hit an escape, then we need to skip past
- // however many characters the escape takes up. However
- // it's important that if \n or \r\n are escaped that we
- // stop looping before the newline and not after the
- // newline so that we can still potentially find the
- // terminator of the heredoc.
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of
- // the loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- continue;
- }
-
- pm_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- if (quote == PM_HEREDOC_QUOTE_SINGLE) {
- switch (peeked) {
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, '\n');
- token_buffer.cursor = parser->current.end + 1;
- breakpoint = parser->current.end;
- continue;
- default:
- parser->current.end++;
- pm_token_buffer_push(&token_buffer, '\\');
- pm_token_buffer_push(&token_buffer, peeked);
- break;
- }
- } else {
- switch (peeked) {
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- pm_token_buffer_push(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- was_escaped_newline = true;
- token_buffer.cursor = parser->current.end + 1;
- breakpoint = parser->current.end;
- continue;
- default:
- escape_read(parser, &token_buffer.buffer, PM_ESCAPE_FLAG_NONE);
- break;
- }
- }
-
- token_buffer.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- break;
- }
- case '#': {
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had
- // something that looked like an interpolated class
- // or instance variable like "#@" but wasn't
- // actually. In this case we'll just skip to the
- // next breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
- break;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
- default:
- assert(false && "unreachable");
- }
-
- was_escaped_newline = false;
- }
-
- if (parser->current.end > parser->current.start) {
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we've hit the end of the string, then this is an unterminated
- // heredoc. In that case we'll return the EOF token.
- LEX(PM_TOKEN_EOF);
- }
- }
-
- assert(false && "unreachable");
-}
-
-#undef LEX
-
-/******************************************************************************/
-/* Parse functions */
-/******************************************************************************/
-
-/**
- * These are the various precedence rules. Because we are using a Pratt parser,
- * they are named binding power to represent the manner in which nodes are bound
- * together in the stack.
- *
- * We increment by 2 because we want to leave room for the infix operators to
- * specify their associativity by adding or subtracting one.
- */
-typedef enum {
- PM_BINDING_POWER_UNSET = 0, // used to indicate this token cannot be used as an infix operator
- PM_BINDING_POWER_STATEMENT = 2,
- PM_BINDING_POWER_MODIFIER = 4, // if unless until while in
- PM_BINDING_POWER_MODIFIER_RESCUE = 6, // rescue
- PM_BINDING_POWER_COMPOSITION = 8, // and or
- PM_BINDING_POWER_NOT = 10, // not
- PM_BINDING_POWER_MATCH = 12, // =>
- PM_BINDING_POWER_DEFINED = 14, // defined?
- PM_BINDING_POWER_ASSIGNMENT = 16, // = += -= *= /= %= &= |= ^= &&= ||= <<= >>= **=
- PM_BINDING_POWER_TERNARY = 18, // ?:
- PM_BINDING_POWER_RANGE = 20, // .. ...
- PM_BINDING_POWER_LOGICAL_OR = 22, // ||
- PM_BINDING_POWER_LOGICAL_AND = 24, // &&
- PM_BINDING_POWER_EQUALITY = 26, // <=> == === != =~ !~
- PM_BINDING_POWER_COMPARISON = 28, // > >= < <=
- PM_BINDING_POWER_BITWISE_OR = 30, // | ^
- PM_BINDING_POWER_BITWISE_AND = 32, // &
- PM_BINDING_POWER_SHIFT = 34, // << >>
- PM_BINDING_POWER_TERM = 36, // + -
- PM_BINDING_POWER_FACTOR = 38, // * / %
- PM_BINDING_POWER_UMINUS = 40, // -@
- PM_BINDING_POWER_EXPONENT = 42, // **
- PM_BINDING_POWER_UNARY = 44, // ! ~ +@
- PM_BINDING_POWER_INDEX = 46, // [] []=
- PM_BINDING_POWER_CALL = 48, // :: .
- PM_BINDING_POWER_MAX = 50
-} pm_binding_power_t;
-
-/**
- * This struct represents a set of binding powers used for a given token. They
- * are combined in this way to make it easier to represent associativity.
- */
-typedef struct {
- /** The left binding power. */
- pm_binding_power_t left;
-
- /** The right binding power. */
- pm_binding_power_t right;
-
- /** Whether or not this token can be used as a binary operator. */
- bool binary;
-} pm_binding_powers_t;
-
-#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true }
-#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true }
-#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true }
-#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false }
-
-pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
- // if unless until while in rescue
- [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_IN] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
-
- // rescue modifier
- [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = {
- PM_BINDING_POWER_ASSIGNMENT,
- PM_BINDING_POWER_MODIFIER_RESCUE + 1,
- true
- },
-
- // and or
- [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
- [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
-
- // =>
- [PM_TOKEN_EQUAL_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
-
- // &&= &= ^= = >>= <<= -= %= |= += /= *= **=
- [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
-
- // ?:
- [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
-
- // .. ...
- [PM_TOKEN_DOT_DOT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
- [PM_TOKEN_DOT_DOT_DOT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
-
- // ||
- [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
-
- // &&
- [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
-
- // != !~ == === =~ <=>
- [PM_TOKEN_BANG_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_BANG_TILDE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_EQUAL_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_TILDE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_LESS_EQUAL_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
-
- // > >= < <=
- [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
- [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
- [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
- [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
-
- // ^ |
- [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
- [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
-
- // &
- [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
-
- // >> <<
- [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
- [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
-
- // - +
- [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
- [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
-
- // % / *
- [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
- [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
- [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
- [PM_TOKEN_USTAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
-
- // -@
- [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
- [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX, false },
-
- // **
- [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
- [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
-
- // ! ~ +@
- [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
- [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
- [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
-
- // [
- [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
-
- // :: . &.
- [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
- [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
- [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
-};
-
-#undef BINDING_POWER_ASSIGNMENT
-#undef LEFT_ASSOCIATIVE
-#undef RIGHT_ASSOCIATIVE
-#undef RIGHT_ASSOCIATIVE_UNARY
-
-/**
- * Returns true if the current token is of the given type.
- */
-static inline bool
-match1(const pm_parser_t *parser, pm_token_type_t type) {
- return parser->current.type == type;
-}
-
-/**
- * Returns true if the current token is of either of the given types.
- */
-static inline bool
-match2(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
- return match1(parser, type1) || match1(parser, type2);
-}
-
-/**
- * Returns true if the current token is any of the three given types.
- */
-static inline bool
-match3(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
-}
-
-/**
- * Returns true if the current token is any of the five given types.
- */
-static inline bool
-match5(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5);
-}
-
-/**
- * Returns true if the current token is any of the six given types.
- */
-static inline bool
-match6(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
-}
-
-/**
- * Returns true if the current token is any of the seven given types.
- */
-static inline bool
-match7(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
-}
-
-/**
- * Returns true if the current token is any of the eight given types.
- */
-static inline bool
-match8(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7, pm_token_type_t type8) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8);
-}
-
-/**
- * If the current token is of the specified type, lex forward by one token and
- * return true. Otherwise, return false. For example:
- *
- * if (accept1(parser, PM_TOKEN_COLON)) { ... }
- */
-static bool
-accept1(pm_parser_t *parser, pm_token_type_t type) {
- if (match1(parser, type)) {
- parser_lex(parser);
- return true;
- }
- return false;
-}
-
-/**
- * If the current token is either of the two given types, lex forward by one
- * token and return true. Otherwise return false.
- */
-static inline bool
-accept2(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
- if (match2(parser, type1, type2)) {
- parser_lex(parser);
- return true;
- }
- return false;
-}
-
-/**
- * If the current token is any of the three given types, lex forward by one
- * token and return true. Otherwise return false.
- */
-static inline bool
-accept3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
- if (match3(parser, type1, type2, type3)) {
- parser_lex(parser);
- return true;
- }
- return false;
-}
-
-/**
- * This function indicates that the parser expects a token in a specific
- * position. For example, if you're parsing a BEGIN block, you know that a { is
- * expected immediately after the keyword. In that case you would call this
- * function to indicate that that token should be found.
- *
- * If we didn't find the token that we were expecting, then we're going to add
- * an error to the parser's list of errors (to indicate that the tree is not
- * valid) and create an artificial token instead. This allows us to recover from
- * the fact that the token isn't present and continue parsing.
- */
-static void
-expect1(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t diag_id) {
- if (accept1(parser, type)) return;
-
- const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
-}
-
-/**
- * This function is the same as expect1, but it expects either of two token
- * types.
- */
-static void
-expect2(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
- if (accept2(parser, type1, type2)) return;
-
- const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
-}
-
-/**
- * This function is the same as expect2, but it expects one of three token types.
- */
-static void
-expect3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_diagnostic_id_t diag_id) {
- if (accept3(parser, type1, type2, type3)) return;
-
- const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
-}
-
-static pm_node_t *
-parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id);
-
-/**
- * This function controls whether or not we will attempt to parse an expression
- * beginning at the subsequent token. It is used when we are in a context where
- * an expression is optional.
- *
- * For example, looking at a range object when we've already lexed the operator,
- * we need to know if we should attempt to parse an expression on the right.
- *
- * For another example, if we've parsed an identifier or a method call and we do
- * not have parentheses, then the next token may be the start of an argument or
- * it may not.
- *
- * CRuby parsers that are generated would resolve this by using a lookahead and
- * potentially backtracking. We attempt to do this by just looking at the next
- * token and making a decision based on that. I am not sure if this is going to
- *
- * work in all cases, it may need to be refactored later. But it appears to work
- * for now.
- */
-static inline bool
-token_begins_expression_p(pm_token_type_t type) {
- switch (type) {
- case PM_TOKEN_EQUAL_GREATER:
- case PM_TOKEN_KEYWORD_IN:
- // We need to special case this because it is a binary operator that
- // should not be marked as beginning an expression.
- return false;
- case PM_TOKEN_BRACE_RIGHT:
- case PM_TOKEN_BRACKET_RIGHT:
- case PM_TOKEN_COLON:
- case PM_TOKEN_COMMA:
- case PM_TOKEN_EMBEXPR_END:
- case PM_TOKEN_EOF:
- case PM_TOKEN_LAMBDA_BEGIN:
- case PM_TOKEN_KEYWORD_DO:
- case PM_TOKEN_KEYWORD_DO_LOOP:
- case PM_TOKEN_KEYWORD_END:
- case PM_TOKEN_KEYWORD_ELSE:
- case PM_TOKEN_KEYWORD_ELSIF:
- case PM_TOKEN_KEYWORD_ENSURE:
- case PM_TOKEN_KEYWORD_THEN:
- case PM_TOKEN_KEYWORD_RESCUE:
- case PM_TOKEN_KEYWORD_WHEN:
- case PM_TOKEN_NEWLINE:
- case PM_TOKEN_PARENTHESIS_RIGHT:
- case PM_TOKEN_SEMICOLON:
- // The reason we need this short-circuit is because we're using the
- // binding powers table to tell us if the subsequent token could
- // potentially be the start of an expression . If there _is_ a binding
- // power for one of these tokens, then we should remove it from this list
- // and let it be handled by the default case below.
- assert(pm_binding_powers[type].left == PM_BINDING_POWER_UNSET);
- return false;
- case PM_TOKEN_UAMPERSAND:
- // This is a special case because this unary operator cannot appear
- // as a general operator, it only appears in certain circumstances.
- return false;
- case PM_TOKEN_UCOLON_COLON:
- case PM_TOKEN_UMINUS:
- case PM_TOKEN_UMINUS_NUM:
- case PM_TOKEN_UPLUS:
- case PM_TOKEN_BANG:
- case PM_TOKEN_TILDE:
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT:
- // These unary tokens actually do have binding power associated with them
- // so that we can correctly place them into the precedence order. But we
- // want them to be marked as beginning an expression, so we need to
- // special case them here.
- return true;
- default:
- return pm_binding_powers[type].left == PM_BINDING_POWER_UNSET;
- }
-}
-
-/**
- * Parse an expression with the given binding power that may be optionally
- * prefixed by the * operator.
- */
-static pm_node_t *
-parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) {
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
- return (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
- }
-
- return parse_expression(parser, binding_power, diag_id);
-}
-
-/**
- * Convert the name of a method into the corresponding write method name. For
- * example, foo would be turned into foo=.
- */
-static void
-parse_write_name(pm_parser_t *parser, pm_constant_id_t *name_field) {
- // The method name needs to change. If we previously had
- // foo, we now need foo=. In this case we'll allocate a new
- // owned string, copy the previous method name in, and
- // append an =.
- pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
- size_t length = constant->length;
- uint8_t *name = calloc(length + 1, sizeof(uint8_t));
- if (name == NULL) return;
-
- memcpy(name, constant->start, length);
- name[length] = '=';
-
- // Now switch the name to the new string.
- *name_field = pm_constant_pool_insert_owned(&parser->constant_pool, name, length + 1);
-}
-
-/**
- * Convert the given node into a valid target node.
- */
-static pm_node_t *
-parse_target(pm_parser_t *parser, pm_node_t *target) {
- switch (PM_NODE_TYPE(target)) {
- case PM_MISSING_NODE:
- return target;
- case PM_CLASS_VARIABLE_READ_NODE:
- assert(sizeof(pm_class_variable_target_node_t) == sizeof(pm_class_variable_read_node_t));
- target->type = PM_CLASS_VARIABLE_TARGET_NODE;
- return target;
- case PM_CONSTANT_PATH_NODE:
- assert(sizeof(pm_constant_path_target_node_t) == sizeof(pm_constant_path_node_t));
- target->type = PM_CONSTANT_PATH_TARGET_NODE;
- return target;
- case PM_CONSTANT_READ_NODE:
- assert(sizeof(pm_constant_target_node_t) == sizeof(pm_constant_read_node_t));
- target->type = PM_CONSTANT_TARGET_NODE;
- return target;
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_READONLY);
- return target;
- case PM_GLOBAL_VARIABLE_READ_NODE:
- assert(sizeof(pm_global_variable_target_node_t) == sizeof(pm_global_variable_read_node_t));
- target->type = PM_GLOBAL_VARIABLE_TARGET_NODE;
- return target;
- case PM_LOCAL_VARIABLE_READ_NODE:
- if (token_is_numbered_parameter(target->location.start, target->location.end)) {
- pm_parser_err_node(parser, target, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- } else {
- assert(sizeof(pm_local_variable_target_node_t) == sizeof(pm_local_variable_read_node_t));
- target->type = PM_LOCAL_VARIABLE_TARGET_NODE;
- }
-
- return target;
- case PM_INSTANCE_VARIABLE_READ_NODE:
- assert(sizeof(pm_instance_variable_target_node_t) == sizeof(pm_instance_variable_read_node_t));
- target->type = PM_INSTANCE_VARIABLE_TARGET_NODE;
- return target;
- case PM_MULTI_TARGET_NODE:
- return target;
- case PM_SPLAT_NODE: {
- pm_splat_node_t *splat = (pm_splat_node_t *) target;
-
- if (splat->expression != NULL) {
- splat->expression = parse_target(parser, splat->expression);
- }
-
- return (pm_node_t *) splat;
- }
- case PM_CALL_NODE: {
- pm_call_node_t *call = (pm_call_node_t *) target;
-
- // If we have no arguments to the call node and we need this to be a
- // target then this is either a method call or a local variable write.
- if (
- (call->message_loc.start != NULL) &&
- (call->message_loc.end[-1] != '!') &&
- (call->message_loc.end[-1] != '?') &&
- (call->opening_loc.start == NULL) &&
- (call->arguments == NULL) &&
- (call->block == NULL)
- ) {
- if (call->receiver == NULL) {
- // When we get here, we have a local variable write, because it
- // was previously marked as a method call but now we have an =.
- // This looks like:
- //
- // foo = 1
- //
- // When it was parsed in the prefix position, foo was seen as a
- // method call with no receiver and no arguments. Now we have an
- // =, so we know it's a local variable write.
- const pm_location_t message = call->message_loc;
-
- pm_parser_local_add_location(parser, message.start, message.end);
- pm_node_destroy(parser, target);
-
- uint32_t depth = 0;
- for (pm_scope_t *scope = parser->current_scope; scope && scope->transparent; depth++, scope = scope->previous);
- const pm_token_t name = { .type = PM_TOKEN_IDENTIFIER, .start = message.start, .end = message.end };
- target = (pm_node_t *) pm_local_variable_read_node_create(parser, &name, depth);
-
- assert(sizeof(pm_local_variable_target_node_t) == sizeof(pm_local_variable_read_node_t));
- target->type = PM_LOCAL_VARIABLE_TARGET_NODE;
-
- if (token_is_numbered_parameter(message.start, message.end)) {
- pm_parser_err_location(parser, &message, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- return target;
- }
-
- if (*call->message_loc.start == '_' || parser->encoding.alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) {
- parse_write_name(parser, &call->name);
- return (pm_node_t *) call;
- }
- }
-
- // If there is no call operator and the message is "[]" then this is
- // an aref expression, and we can transform it into an aset
- // expression.
- if (
- (call->call_operator_loc.start == NULL) &&
- (call->message_loc.start != NULL) &&
- (call->message_loc.start[0] == '[') &&
- (call->message_loc.end[-1] == ']') &&
- (call->block == NULL)
- ) {
- // Replace the name with "[]=".
- call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
- return target;
- }
- }
- /* fallthrough */
- default:
- // In this case we have a node that we don't know how to convert
- // into a target. We need to treat it as an error. For now, we'll
- // mark it as an error and just skip right past it.
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
- return target;
- }
-}
-
-/**
- * Parse a write target and validate that it is in a valid position for
- * assignment.
- */
-static pm_node_t *
-parse_target_validate(pm_parser_t *parser, pm_node_t *target) {
- pm_node_t *result = parse_target(parser, target);
-
- // Ensure that we have either an = or a ) after the targets.
- if (!match3(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_KEYWORD_IN)) {
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- return result;
-}
-
-/**
- * Convert the given node into a valid write node.
- */
-static pm_node_t *
-parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_node_t *value) {
- switch (PM_NODE_TYPE(target)) {
- case PM_MISSING_NODE:
- return target;
- case PM_CLASS_VARIABLE_READ_NODE: {
- pm_class_variable_write_node_t *node = pm_class_variable_write_node_create(parser, (pm_class_variable_read_node_t *) target, operator, value);
- pm_node_destroy(parser, target);
- return (pm_node_t *) node;
- }
- case PM_CONSTANT_PATH_NODE:
- return (pm_node_t *) pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target, operator, value);
- case PM_CONSTANT_READ_NODE: {
- pm_constant_write_node_t *node = pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target, operator, value);
- pm_node_destroy(parser, target);
- return (pm_node_t *) node;
- }
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target, operator, value);
- pm_node_destroy(parser, target);
- return (pm_node_t *) node;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- if (token_is_numbered_parameter(target->location.start, target->location.end)) {
- pm_parser_err_node(parser, target, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- pm_local_variable_read_node_t *local_read = (pm_local_variable_read_node_t *) target;
-
- pm_constant_id_t constant_id = local_read->name;
- uint32_t depth = local_read->depth;
-
- pm_location_t name_loc = target->location;
- pm_node_destroy(parser, target);
-
- return (pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, depth, value, &name_loc, operator);
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- pm_node_t *write_node = (pm_node_t *) pm_instance_variable_write_node_create(parser, (pm_instance_variable_read_node_t *) target, operator, value);
- pm_node_destroy(parser, target);
- return write_node;
- }
- case PM_MULTI_TARGET_NODE:
- return (pm_node_t *) pm_multi_write_node_create(parser, (pm_multi_target_node_t *) target, operator, value);
- case PM_SPLAT_NODE: {
- pm_splat_node_t *splat = (pm_splat_node_t *) target;
-
- if (splat->expression != NULL) {
- splat->expression = parse_write(parser, splat->expression, operator, value);
- }
-
- pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, multi_target, (pm_node_t *) splat);
-
- return (pm_node_t *) pm_multi_write_node_create(parser, multi_target, operator, value);
- }
- case PM_CALL_NODE: {
- pm_call_node_t *call = (pm_call_node_t *) target;
-
- // If we have no arguments to the call node and we need this to be a
- // target then this is either a method call or a local variable
- // write.
- if (
- (call->message_loc.start != NULL) &&
- (call->message_loc.end[-1] != '!') &&
- (call->message_loc.end[-1] != '?') &&
- (call->opening_loc.start == NULL) &&
- (call->arguments == NULL) &&
- (call->block == NULL)
- ) {
- if (call->receiver == NULL) {
- // When we get here, we have a local variable write, because it
- // was previously marked as a method call but now we have an =.
- // This looks like:
- //
- // foo = 1
- //
- // When it was parsed in the prefix position, foo was seen as a
- // method call with no receiver and no arguments. Now we have an
- // =, so we know it's a local variable write.
- const pm_location_t message = call->message_loc;
-
- pm_parser_local_add_location(parser, message.start, message.end);
- pm_node_destroy(parser, target);
-
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, message.start, message.end);
- target = (pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message, operator);
-
- if (token_is_numbered_parameter(message.start, message.end)) {
- pm_parser_err_location(parser, &message, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- return target;
- }
-
- if (*call->message_loc.start == '_' || parser->encoding.alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) {
- // When we get here, we have a method call, because it was
- // previously marked as a method call but now we have an =. This
- // looks like:
- //
- // foo.bar = 1
- //
- // When it was parsed in the prefix position, foo.bar was seen as a
- // method call with no arguments. Now we have an =, so we know it's
- // a method call with an argument. In this case we will create the
- // arguments node, parse the argument, and add it to the list.
- pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- call->arguments = arguments;
-
- pm_arguments_node_arguments_append(arguments, value);
- call->base.location.end = arguments->base.location.end;
-
- parse_write_name(parser, &call->name);
- return (pm_node_t *) call;
- }
- }
-
- // If there is no call operator and the message is "[]" then this is
- // an aref expression, and we can transform it into an aset
- // expression.
- if (
- (call->call_operator_loc.start == NULL) &&
- (call->message_loc.start != NULL) &&
- (call->message_loc.start[0] == '[') &&
- (call->message_loc.end[-1] == ']') &&
- (call->block == NULL)
- ) {
- if (call->arguments == NULL) {
- call->arguments = pm_arguments_node_create(parser);
- }
-
- pm_arguments_node_arguments_append(call->arguments, value);
- target->location.end = value->location.end;
-
- // Replace the name with "[]=".
- call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
- return target;
- }
-
- // If there are arguments on the call node, then it can't be a method
- // call ending with = or a local variable write, so it must be a
- // syntax error. In this case we'll fall through to our default
- // handling. We need to free the value that we parsed because there
- // is no way for us to attach it to the tree at this point.
- pm_node_destroy(parser, value);
- }
- /* fallthrough */
- default:
- // In this case we have a node that we don't know how to convert into a
- // target. We need to treat it as an error. For now, we'll mark it as an
- // error and just skip right past it.
- pm_parser_err_token(parser, operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
- return target;
- }
-}
-
-/**
- * Parse a list of targets for assignment. This is used in the case of a for
- * loop or a multi-assignment. For example, in the following code:
- *
- * for foo, bar in baz
- * ^^^^^^^^
- *
- * The targets are `foo` and `bar`. This function will either return a single
- * target node or a multi-target node.
- */
-static pm_node_t *
-parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power) {
- bool has_splat = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
-
- pm_multi_target_node_t *result = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target));
-
- while (accept1(parser, PM_TOKEN_COMMA)) {
- if (accept1(parser, PM_TOKEN_USTAR)) {
- // Here we have a splat operator. It can have a name or be
- // anonymous. It can be the final target or be in the middle if
- // there haven't been any others yet.
- if (has_splat) {
- pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
- }
-
- pm_token_t star_operator = parser->previous;
- pm_node_t *name = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
- name = parse_target(parser, name);
- }
-
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
- pm_multi_target_node_targets_append(parser, result, splat);
- has_splat = true;
- } else if (token_begins_expression_p(parser->current.type)) {
- pm_node_t *target = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA);
- target = parse_target(parser, target);
-
- pm_multi_target_node_targets_append(parser, result, target);
- } else if (!match1(parser, PM_TOKEN_EOF)) {
- // If we get here, then we have a trailing , in a multi target node.
- // We need to indicate this somehow in the tree, so we'll add an
- // anonymous splat.
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &parser->previous, NULL);
- pm_multi_target_node_targets_append(parser, result, splat);
- break;
- }
- }
-
- return (pm_node_t *) result;
-}
-
-/**
- * Parse a list of targets and validate that it is in a valid position for
- * assignment.
- */
-static pm_node_t *
-parse_targets_validate(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power) {
- pm_node_t *result = parse_targets(parser, first_target, binding_power);
-
- // Ensure that we have either an = or a ) after the targets.
- if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- return result;
-}
-
-/**
- * Parse a list of statements separated by newlines or semicolons.
- */
-static pm_statements_node_t *
-parse_statements(pm_parser_t *parser, pm_context_t context) {
- // First, skip past any optional terminators that might be at the beginning of
- // the statements.
- while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
-
- // If we have a terminator, then we can just return NULL.
- if (context_terminator(context, &parser->current)) return NULL;
-
- pm_statements_node_t *statements = pm_statements_node_create(parser);
-
- // At this point we know we have at least one statement, and that it
- // immediately follows the current token.
- context_push(parser, context);
-
- while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION);
- pm_statements_node_body_append(statements, node);
-
- // If we're recovering from a syntax error, then we need to stop parsing the
- // statements now.
- if (parser->recovering) {
- // If this is the level of context where the recovery has happened, then
- // we can mark the parser as done recovering.
- if (context_terminator(context, &parser->current)) parser->recovering = false;
- break;
- }
-
- // If we have a terminator, then we will parse all consequtive terminators
- // and then continue parsing the statements list.
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- // If we have a terminator, then we will continue parsing the statements
- // list.
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- if (context_terminator(context, &parser->current)) break;
-
- // Now we can continue parsing the list of statements.
- continue;
- }
-
- // At this point we have a list of statements that are not terminated by a
- // newline or semicolon. At this point we need to check if we're at the end
- // of the statements list. If we are, then we should break out of the loop.
- if (context_terminator(context, &parser->current)) break;
-
- // At this point, we have a syntax error, because the statement was not
- // terminated by a newline or semicolon, and we're not at the end of the
- // statements list. Ideally we should scan forward to determine if we should
- // insert a missing terminator or break out of parsing the statements list
- // at this point.
- //
- // We don't have that yet, so instead we'll do a more naive approach. If we
- // were unable to parse an expression, then we will skip past this token and
- // continue parsing the statements list. Otherwise we'll add an error and
- // continue parsing the statements list.
- if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
- parser_lex(parser);
-
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- if (context_terminator(context, &parser->current)) break;
- } else {
- expect1(parser, PM_TOKEN_NEWLINE, PM_ERR_EXPECT_EOL_AFTER_STATEMENT);
- }
- }
-
- context_pop(parser);
- return statements;
-}
-
-/**
- * Parse all of the elements of a hash. eturns true if a double splat was found.
- */
-static bool
-parse_assocs(pm_parser_t *parser, pm_node_t *node) {
- assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
- bool contains_keyword_splat = false;
-
- while (true) {
- pm_node_t *element;
-
- switch (parser->current.type) {
- case PM_TOKEN_USTAR_STAR: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
- pm_node_t *value = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- value = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH);
- } else if (pm_parser_local_depth(parser, &operator) == -1) {
- pm_parser_err_token(parser, &operator, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH);
- }
-
- element = (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
- contains_keyword_splat = true;
- break;
- }
- case PM_TOKEN_LABEL: {
- pm_token_t label = parser->current;
- parser_lex(parser);
-
- pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &label);
- pm_token_t operator = not_provided(parser);
- pm_node_t *value = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- value = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_EXPRESSION_AFTER_LABEL);
- } else {
- if (parser->encoding.isupper_char(label.start, (label.end - 1) - label.start)) {
- pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.start, .end = label.end - 1 };
- value = (pm_node_t *) pm_constant_read_node_create(parser, &constant);
- } else {
- int depth = pm_parser_local_depth(parser, &((pm_token_t) { .type = PM_TOKEN_IDENTIFIER, .start = label.start, .end = label.end - 1 }));
- pm_token_t identifier = { .type = PM_TOKEN_IDENTIFIER, .start = label.start, .end = label.end - 1 };
-
- if (depth == -1) {
- value = (pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
- } else {
- value = (pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
- }
- }
-
- value->location.end++;
- value = (pm_node_t *) pm_implicit_node_create(parser, value);
- }
-
- element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
- break;
- }
- default: {
- pm_node_t *key = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_KEY);
- pm_token_t operator;
-
- if (pm_symbol_node_label_p(key)) {
- operator = not_provided(parser);
- } else {
- expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
- operator = parser->previous;
- }
-
- pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE);
- element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
- break;
- }
- }
-
- if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
- pm_hash_node_elements_append((pm_hash_node_t *) node, element);
- } else {
- pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element);
- }
-
- // If there's no comma after the element, then we're done.
- if (!accept1(parser, PM_TOKEN_COMMA)) break;
-
- // If the next element starts with a label or a **, then we know we have
- // another element in the hash, so we'll continue parsing.
- if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)) continue;
-
- // Otherwise we need to check if the subsequent token begins an expression.
- // If it does, then we'll continue parsing.
- if (token_begins_expression_p(parser->current.type)) continue;
-
- // Otherwise by default we will exit out of this loop.
- break;
- }
- return contains_keyword_splat;
-}
-
-/**
- * Append an argument to a list of arguments.
- */
-static inline void
-parse_arguments_append(pm_parser_t *parser, pm_arguments_t *arguments, pm_node_t *argument) {
- if (arguments->arguments == NULL) {
- arguments->arguments = pm_arguments_node_create(parser);
- }
-
- pm_arguments_node_arguments_append(arguments->arguments, argument);
-}
-
-/**
- * Parse a list of arguments.
- */
-static void
-parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_forwarding, pm_token_type_t terminator) {
- pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
-
- // First we need to check if the next token is one that could be the start of
- // an argument. If it's not, then we can just return.
- if (
- match2(parser, terminator, PM_TOKEN_EOF) ||
- (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
- context_terminator(parser->current_context->context, &parser->current)
- ) {
- return;
- }
-
- bool parsed_bare_hash = false;
- bool parsed_block_argument = false;
-
- while (!match1(parser, PM_TOKEN_EOF)) {
- if (parsed_block_argument) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
- }
-
- pm_node_t *argument = NULL;
-
- switch (parser->current.type) {
- case PM_TOKEN_USTAR_STAR:
- case PM_TOKEN_LABEL: {
- if (parsed_bare_hash) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
- }
-
- pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
- argument = (pm_node_t *) hash;
-
- bool contains_keyword_splat = false;
- if (!match7(parser, terminator, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
- contains_keyword_splat = parse_assocs(parser, (pm_node_t *) hash);
- }
-
- parsed_bare_hash = true;
- parse_arguments_append(parser, arguments, argument);
- if (contains_keyword_splat) {
- arguments->arguments->base.flags |= PM_ARGUMENTS_NODE_FLAGS_KEYWORD_SPLAT;
- }
- break;
- }
- case PM_TOKEN_UAMPERSAND: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
- pm_node_t *expression = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT);
- } else if (pm_parser_local_depth(parser, &operator) == -1) {
- pm_parser_err_token(parser, &operator, PM_ERR_ARGUMENT_NO_FORWARDING_AMP);
- }
-
- argument = (pm_node_t *) pm_block_argument_node_create(parser, &operator, expression);
- if (parsed_block_argument) {
- parse_arguments_append(parser, arguments, argument);
- } else {
- arguments->block = argument;
- }
-
- parsed_block_argument = true;
- break;
- }
- case PM_TOKEN_USTAR: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
-
- if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA)) {
- if (pm_parser_local_depth(parser, &parser->previous) == -1) {
- pm_parser_err_token(parser, &operator, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
- }
-
- argument = (pm_node_t *) pm_splat_node_create(parser, &operator, NULL);
- } else {
- pm_node_t *expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT);
-
- if (parsed_bare_hash) {
- pm_parser_err(parser, operator.start, expression->location.end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
- }
-
- argument = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
- }
-
- parse_arguments_append(parser, arguments, argument);
- break;
- }
- case PM_TOKEN_UDOT_DOT_DOT: {
- if (accepts_forwarding) {
- parser_lex(parser);
-
- if (token_begins_expression_p(parser->current.type)) {
- // If the token begins an expression then this ... was not actually
- // argument forwarding but was instead a range.
- pm_token_t operator = parser->previous;
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- argument = (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- } else {
- if (pm_parser_local_depth(parser, &parser->previous) == -1) {
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
- }
-
- argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->previous);
- parse_arguments_append(parser, arguments, argument);
- break;
- }
- }
- }
- /* fallthrough */
- default: {
- if (argument == NULL) {
- argument = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT);
- }
-
- bool contains_keyword_splat = false;
- if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- if (parsed_bare_hash) {
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
- }
-
- pm_token_t operator;
- if (parser->previous.type == PM_TOKEN_EQUAL_GREATER) {
- operator = parser->previous;
- } else {
- operator = not_provided(parser);
- }
-
- pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
-
- // Finish parsing the one we are part way through
- pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE);
-
- argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value);
- pm_keyword_hash_node_elements_append(bare_hash, argument);
- argument = (pm_node_t *) bare_hash;
-
- // Then parse more if we have a comma
- if (accept1(parser, PM_TOKEN_COMMA) && (
- token_begins_expression_p(parser->current.type) ||
- match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
- )) {
- contains_keyword_splat = parse_assocs(parser, (pm_node_t *) bare_hash);
- }
-
- parsed_bare_hash = true;
- }
-
- parse_arguments_append(parser, arguments, argument);
- if (contains_keyword_splat) {
- arguments->arguments->base.flags |= PM_ARGUMENTS_NODE_FLAGS_KEYWORD_SPLAT;
- }
- break;
- }
- }
-
- // If parsing the argument failed, we need to stop parsing arguments.
- if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->recovering) break;
-
- // If the terminator of these arguments is not EOF, then we have a specific
- // token we're looking for. In that case we can accept a newline here
- // because it is not functioning as a statement terminator.
- if (terminator != PM_TOKEN_EOF) accept1(parser, PM_TOKEN_NEWLINE);
-
- if (parser->previous.type == PM_TOKEN_COMMA && parsed_bare_hash) {
- // If we previously were on a comma and we just parsed a bare hash, then
- // we want to continue parsing arguments. This is because the comma was
- // grabbed up by the hash parser.
- } else {
- // If there is no comma at the end of the argument list then we're done
- // parsing arguments and can break out of this loop.
- if (!accept1(parser, PM_TOKEN_COMMA)) break;
- }
-
- // If we hit the terminator, then that means we have a trailing comma so we
- // can accept that output as well.
- if (match1(parser, terminator)) break;
- }
-}
-
-/**
- * Required parameters on method, block, and lambda declarations can be
- * destructured using parentheses. This looks like:
- *
- * def foo((bar, baz))
- * end
- *
- *
- * It can recurse infinitely down, and splats are allowed to group arguments.
- */
-static pm_multi_target_node_t *
-parse_required_destructured_parameter(pm_parser_t *parser) {
- expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
-
- pm_multi_target_node_t *node = pm_multi_target_node_create(parser);
- pm_multi_target_node_opening_set(node, &parser->previous);
-
- do {
- pm_node_t *param;
-
- // If we get here then we have a trailing comma. In this case we'll
- // create an implicit splat node.
- if (node->lefts.size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- param = (pm_node_t *) pm_splat_node_create(parser, &parser->previous, NULL);
- pm_multi_target_node_targets_append(parser, node, param);
- break;
- }
-
- if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- param = (pm_node_t *) parse_required_destructured_parameter(parser);
- } else if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t star = parser->previous;
- pm_node_t *value = NULL;
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- pm_token_t name = parser->previous;
- value = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
- pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name);
- }
-
- param = (pm_node_t *) pm_splat_node_create(parser, &star, value);
- } else {
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
- pm_token_t name = parser->previous;
-
- param = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
- pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name);
- }
-
- pm_multi_target_node_targets_append(parser, node, param);
- } while (accept1(parser, PM_TOKEN_COMMA));
-
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
- pm_multi_target_node_closing_set(node, &parser->previous);
-
- return node;
-}
-
-/**
- * This represents the different order states we can be in when parsing
- * method parameters.
- */
-typedef enum {
- PM_PARAMETERS_NO_CHANGE = 0, // Extra state for tokens that should not change the state
- PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
- PM_PARAMETERS_ORDER_KEYWORDS_REST,
- PM_PARAMETERS_ORDER_KEYWORDS,
- PM_PARAMETERS_ORDER_REST,
- PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
- PM_PARAMETERS_ORDER_OPTIONAL,
- PM_PARAMETERS_ORDER_NAMED,
- PM_PARAMETERS_ORDER_NONE,
-
-} pm_parameters_order_t;
-
-/**
- * This matches parameters tokens with parameters state.
- */
-static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
- [0] = PM_PARAMETERS_NO_CHANGE,
- [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
- [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
- [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
- [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
- [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
- [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
- [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
- [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
- [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
- [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
- [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
-};
-
-/**
- * Check if current parameter follows valid parameters ordering. If not it adds
- * an error to the list without stopping the parsing, otherwise sets the
- * parameters state to the one corresponding to the current parameter.
- */
-static void
-update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_order_t *current) {
- pm_parameters_order_t state = parameters_ordering[token->type];
- if (state == PM_PARAMETERS_NO_CHANGE) return;
-
- // If we see another ordered argument after a optional argument
- // we only continue parsing ordered arguments until we stop seeing ordered arguments
- if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
- *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
- return;
- } else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
- return;
- }
-
- if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
- }
-
- if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
- // We know what transition we failed on, so we can provide a better error here.
- pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
- } else if (state < *current) {
- *current = state;
- }
-}
-
-/**
- * Parse a list of parameters on a method definition.
- */
-static pm_parameters_node_t *
-parse_parameters(
- pm_parser_t *parser,
- pm_binding_power_t binding_power,
- bool uses_parentheses,
- bool allows_trailing_comma,
- bool allows_forwarding_parameters
-) {
- pm_parameters_node_t *params = pm_parameters_node_create(parser);
- bool looping = true;
-
- pm_do_loop_stack_push(parser, false);
- pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
-
- do {
- switch (parser->current.type) {
- case PM_TOKEN_PARENTHESIS_LEFT: {
- update_parameter_state(parser, &parser->current, &order);
- pm_node_t *param = (pm_node_t *) parse_required_destructured_parameter(parser);
-
- if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_parameters_node_requireds_append(params, param);
- } else {
- pm_parameters_node_posts_append(params, param);
- }
- break;
- }
- case PM_TOKEN_UAMPERSAND:
- case PM_TOKEN_AMPERSAND: {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_token_t name;
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name);
- } else {
- name = not_provided(parser);
-
- if (allows_forwarding_parameters) {
- pm_parser_local_add_token(parser, &operator);
- }
- }
-
- pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &operator);
- if (params->block == NULL) {
- pm_parameters_node_block_set(params, param);
- } else {
- pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
- }
-
- break;
- }
- case PM_TOKEN_UDOT_DOT_DOT: {
- if (!allows_forwarding_parameters) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
- }
-
- if (order > PM_PARAMETERS_ORDER_NOTHING_AFTER) {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- if (allows_forwarding_parameters) {
- pm_parser_local_add_token(parser, &parser->previous);
- }
-
- pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
- if (params->keyword_rest != NULL) {
- // If we already have a keyword rest parameter, then we replace it with the
- // forwarding parameter and move the keyword rest parameter to the posts list.
- pm_node_t *keyword_rest = params->keyword_rest;
- pm_parameters_node_posts_append(params, keyword_rest);
- pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
- params->keyword_rest = NULL;
- }
- pm_parameters_node_keyword_rest_set(params, (pm_node_t *)param);
- } else {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
- }
-
- break;
- }
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_INSTANCE_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- switch (parser->previous.type) {
- case PM_TOKEN_CONSTANT:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
- break;
- case PM_TOKEN_INSTANCE_VARIABLE:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
- break;
- case PM_TOKEN_GLOBAL_VARIABLE:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
- break;
- case PM_TOKEN_CLASS_VARIABLE:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
- break;
- case PM_TOKEN_METHOD_NAME:
- pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
- break;
- default: break;
- }
-
- if (parser->current.type == PM_TOKEN_EQUAL) {
- update_parameter_state(parser, &parser->current, &order);
- } else {
- update_parameter_state(parser, &parser->previous, &order);
- }
-
- pm_token_t name = parser->previous;
- pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name);
-
- if (accept1(parser, PM_TOKEN_EQUAL)) {
- pm_token_t operator = parser->previous;
- context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT);
-
- pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value);
- pm_parameters_node_optionals_append(params, param);
- context_pop(parser);
-
- // If parsing the value of the parameter resulted in error recovery,
- // then we can put a missing node in its place and stop parsing the
- // parameters entirely now.
- if (parser->recovering) {
- looping = false;
- break;
- }
- } else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
- pm_parameters_node_requireds_append(params, (pm_node_t *) param);
- } else {
- pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
- }
-
- break;
- }
- case PM_TOKEN_LABEL: {
- if (!uses_parentheses) parser->in_keyword_arg = true;
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- pm_token_t name = parser->previous;
- pm_token_t local = name;
- local.end -= 1;
-
- pm_parser_parameter_name_check(parser, &local);
- pm_parser_local_add_token(parser, &local);
-
- switch (parser->current.type) {
- case PM_TOKEN_COMMA:
- case PM_TOKEN_PARENTHESIS_RIGHT:
- case PM_TOKEN_PIPE: {
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
- pm_parameters_node_keywords_append(params, param);
- break;
- }
- case PM_TOKEN_SEMICOLON:
- case PM_TOKEN_NEWLINE: {
- if (uses_parentheses) {
- looping = false;
- break;
- }
-
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
- pm_parameters_node_keywords_append(params, param);
- break;
- }
- default: {
- pm_node_t *param;
-
- if (token_begins_expression_p(parser->current.type)) {
- context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT_KW);
- context_pop(parser);
- param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
- }
- else {
- param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
- }
-
- pm_parameters_node_keywords_append(params, param);
-
- // If parsing the value of the parameter resulted in error recovery,
- // then we can put a missing node in its place and stop parsing the
- // parameters entirely now.
- if (parser->recovering) {
- looping = false;
- break;
- }
- }
- }
-
- parser->in_keyword_arg = false;
- break;
- }
- case PM_TOKEN_USTAR:
- case PM_TOKEN_STAR: {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_token_t name;
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name);
- } else {
- name = not_provided(parser);
-
- if (allows_forwarding_parameters) {
- pm_parser_local_add_token(parser, &operator);
- }
- }
-
- pm_rest_parameter_node_t *param = pm_rest_parameter_node_create(parser, &operator, &name);
- if (params->rest == NULL) {
- pm_parameters_node_rest_set(params, param);
- } else {
- pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
- }
-
- break;
- }
- case PM_TOKEN_STAR_STAR:
- case PM_TOKEN_USTAR_STAR: {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *param;
-
- if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
- param = (pm_node_t *) pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous);
- } else {
- pm_token_t name;
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name);
- } else {
- name = not_provided(parser);
-
- if (allows_forwarding_parameters) {
- pm_parser_local_add_token(parser, &operator);
- }
- }
-
- param = (pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &operator, &name);
- }
-
- if (params->keyword_rest == NULL) {
- pm_parameters_node_keyword_rest_set(params, param);
- } else {
- pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
- pm_parameters_node_posts_append(params, param);
- }
-
- break;
- }
- default:
- if (parser->previous.type == PM_TOKEN_COMMA) {
- if (allows_trailing_comma) {
- // If we get here, then we have a trailing comma in a block
- // parameter list. We need to create an anonymous rest parameter to
- // represent it.
- pm_token_t name = not_provided(parser);
- pm_rest_parameter_node_t *param = pm_rest_parameter_node_create(parser, &parser->previous, &name);
-
- if (params->rest == NULL) {
- pm_parameters_node_rest_set(params, param);
- } else {
- pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
- }
- } else {
- pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
- }
- }
-
- looping = false;
- break;
- }
-
- if (looping && uses_parentheses) {
- accept1(parser, PM_TOKEN_NEWLINE);
- }
- } while (looping && accept1(parser, PM_TOKEN_COMMA));
-
- pm_do_loop_stack_pop(parser);
-
- // If we don't have any parameters, return `NULL` instead of an empty `ParametersNode`.
- if (params->base.location.start == params->base.location.end) {
- pm_node_destroy(parser, (pm_node_t *) params);
- return NULL;
- }
-
- return params;
-}
-
-/**
- * Parse any number of rescue clauses. This will form a linked list of if
- * nodes pointing to each other from the top.
- */
-static inline void
-parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) {
- pm_rescue_node_t *current = NULL;
-
- while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
- pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
-
- switch (parser->current.type) {
- case PM_TOKEN_EQUAL_GREATER: {
- // Here we have an immediate => after the rescue keyword, in which case
- // we're going to have an empty list of exceptions to rescue (which
- // implies StandardError).
- parser_lex(parser);
- pm_rescue_node_operator_set(rescue, &parser->previous);
-
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE);
- reference = parse_target(parser, reference);
-
- pm_rescue_node_reference_set(rescue, reference);
- break;
- }
- case PM_TOKEN_NEWLINE:
- case PM_TOKEN_SEMICOLON:
- case PM_TOKEN_KEYWORD_THEN:
- // Here we have a terminator for the rescue keyword, in which case we're
- // going to just continue on.
- break;
- default: {
- if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
- // Here we have something that could be an exception expression, so
- // we'll attempt to parse it here and any others delimited by commas.
-
- do {
- pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_RESCUE_EXPRESSION);
- pm_rescue_node_exceptions_append(rescue, expression);
-
- // If we hit a newline, then this is the end of the rescue expression. We
- // can continue on to parse the statements.
- if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN)) break;
-
- // If we hit a `=>` then we're going to parse the exception variable. Once
- // we've done that, we'll break out of the loop and parse the statements.
- if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- pm_rescue_node_operator_set(rescue, &parser->previous);
-
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE);
- reference = parse_target(parser, reference);
-
- pm_rescue_node_reference_set(rescue, reference);
- break;
- }
- } while (accept1(parser, PM_TOKEN_COMMA));
- }
- }
- }
-
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- accept1(parser, PM_TOKEN_KEYWORD_THEN);
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
- }
-
- if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_RESCUE);
- if (statements) {
- pm_rescue_node_statements_set(rescue, statements);
- }
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- if (current == NULL) {
- pm_begin_node_rescue_clause_set(parent_node, rescue);
- } else {
- pm_rescue_node_consequent_set(current, rescue);
- }
-
- current = rescue;
- }
-
- // The end node locations on rescue nodes will not be set correctly
- // since we won't know the end until we've found all consequent
- // clauses. This sets the end location on all rescues once we know it
- if (current) {
- const uint8_t *end_to_set = current->base.location.end;
- current = parent_node->rescue_clause;
- while (current) {
- current->base.location.end = end_to_set;
- current = current->consequent;
- }
- }
-
- if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
- pm_token_t else_keyword = parser->previous;
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_statements_node_t *else_statements = NULL;
- if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
- pm_accepts_block_stack_push(parser, true);
- else_statements = parse_statements(parser, PM_CONTEXT_RESCUE_ELSE);
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
- pm_begin_node_else_clause_set(parent_node, else_clause);
- }
-
- if (accept1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
- pm_token_t ensure_keyword = parser->previous;
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_statements_node_t *ensure_statements = NULL;
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- ensure_statements = parse_statements(parser, PM_CONTEXT_ENSURE);
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
- pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
- }
-
- if (parser->current.type == PM_TOKEN_KEYWORD_END) {
- pm_begin_node_end_keyword_set(parent_node, &parser->current);
- } else {
- pm_token_t end_keyword = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- pm_begin_node_end_keyword_set(parent_node, &end_keyword);
- }
-}
-
-static inline pm_begin_node_t *
-parse_rescues_as_begin(pm_parser_t *parser, pm_statements_node_t *statements) {
- pm_token_t no_begin_token = not_provided(parser);
- pm_begin_node_t *begin_node = pm_begin_node_create(parser, &no_begin_token, statements);
- parse_rescues(parser, begin_node);
-
- // All nodes within a begin node are optional, so we look
- // for the earliest possible node that we can use to set
- // the BeginNode's start location
- const uint8_t *start = begin_node->base.location.start;
- if (begin_node->statements) {
- start = begin_node->statements->base.location.start;
- } else if (begin_node->rescue_clause) {
- start = begin_node->rescue_clause->base.location.start;
- } else if (begin_node->else_clause) {
- start = begin_node->else_clause->base.location.start;
- } else if (begin_node->ensure_clause) {
- start = begin_node->ensure_clause->base.location.start;
- }
-
- begin_node->base.location.start = start;
- return begin_node;
-}
-
-/**
- * Parse a list of parameters and local on a block definition.
- */
-static pm_block_parameters_node_t *
-parse_block_parameters(
- pm_parser_t *parser,
- bool allows_trailing_comma,
- const pm_token_t *opening,
- bool is_lambda_literal
-) {
- pm_parameters_node_t *parameters = NULL;
- if (!match1(parser, PM_TOKEN_SEMICOLON)) {
- parameters = parse_parameters(
- parser,
- is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
- false,
- allows_trailing_comma,
- false
- );
- }
-
- pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
- if ((opening->type != PM_TOKEN_NOT_PROVIDED) && accept1(parser, PM_TOKEN_SEMICOLON)) {
- do {
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
- pm_parser_parameter_name_check(parser, &parser->previous);
- pm_parser_local_add_token(parser, &parser->previous);
-
- pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->previous);
- pm_block_parameters_node_append_local(block_parameters, local);
- } while (accept1(parser, PM_TOKEN_COMMA));
- }
-
- return block_parameters;
-}
-
-/**
- * Parse a block.
- */
-static pm_block_node_t *
-parse_block(pm_parser_t *parser) {
- pm_token_t opening = parser->previous;
- accept1(parser, PM_TOKEN_NEWLINE);
-
- pm_accepts_block_stack_push(parser, true);
- pm_parser_scope_push(parser, false);
- pm_block_parameters_node_t *parameters = NULL;
-
- if (accept1(parser, PM_TOKEN_PIPE)) {
- parser->current_scope->explicit_params = true;
- pm_token_t block_parameters_opening = parser->previous;
-
- if (match1(parser, PM_TOKEN_PIPE)) {
- parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
- parser->command_start = true;
- parser_lex(parser);
- } else {
- parameters = parse_block_parameters(parser, true, &block_parameters_opening, false);
- accept1(parser, PM_TOKEN_NEWLINE);
- parser->command_start = true;
- expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
- }
-
- pm_block_parameters_node_closing_set(parameters, &parser->previous);
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- pm_node_t *statements = NULL;
-
- if (opening.type == PM_TOKEN_BRACE_LEFT) {
- if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_BRACES);
- }
-
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
- } else {
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS);
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
- }
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
- }
-
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
- pm_accepts_block_stack_pop(parser);
- return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
-}
-
-/**
- * Parse a list of arguments and their surrounding parentheses if they are
- * present. It returns true if it found any pieces of arguments (parentheses,
- * arguments, or blocks).
- */
-static bool
-parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block) {
- bool found = false;
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- found |= true;
- arguments->opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- } else {
- pm_accepts_block_stack_push(parser, true);
- parse_arguments(parser, arguments, true, PM_TOKEN_PARENTHESIS_RIGHT);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_ARGUMENT_TERM_PAREN);
- pm_accepts_block_stack_pop(parser);
-
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- }
- } else if ((token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
- found |= true;
- pm_accepts_block_stack_push(parser, false);
-
- // If we get here, then the subsequent token cannot be used as an infix
- // operator. In this case we assume the subsequent token is part of an
- // argument to this method call.
- parse_arguments(parser, arguments, true, PM_TOKEN_EOF);
-
- pm_accepts_block_stack_pop(parser);
- }
-
- // If we're at the end of the arguments, we can now check if there is a block
- // node that starts with a {. If there is, then we can parse it and add it to
- // the arguments.
- if (accepts_block) {
- pm_block_node_t *block = NULL;
-
- if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
- found |= true;
- block = parse_block(parser);
- pm_arguments_validate_block(parser, arguments, block);
- } else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
- found |= true;
- block = parse_block(parser);
- }
-
- if (block != NULL) {
- if (arguments->block == NULL) {
- arguments->block = (pm_node_t *) block;
- } else {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
- if (arguments->arguments == NULL) {
- arguments->arguments = pm_arguments_node_create(parser);
- }
- pm_arguments_node_arguments_append(arguments->arguments, arguments->block);
- arguments->block = (pm_node_t *) block;
- }
- }
- }
-
- return found;
-}
-
-static inline pm_node_t *
-parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context) {
- context_push(parser, PM_CONTEXT_PREDICATE);
- pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
- pm_node_t *predicate = parse_expression(parser, binding_power, error_id);
-
- // Predicates are closed by a term, a "then", or a term and then a "then".
- bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- predicate_closed |= accept1(parser, PM_TOKEN_KEYWORD_THEN);
- if (!predicate_closed) {
- pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
- }
-
- context_pop(parser);
- return predicate;
-}
-
-static inline pm_node_t *
-parse_conditional(pm_parser_t *parser, pm_context_t context) {
- pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context);
- pm_statements_node_t *statements = NULL;
-
- if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, context);
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_token_t end_keyword = not_provided(parser);
- pm_node_t *parent = NULL;
-
- switch (context) {
- case PM_CONTEXT_IF:
- parent = (pm_node_t *) pm_if_node_create(parser, &keyword, predicate, statements, NULL, &end_keyword);
- break;
- case PM_CONTEXT_UNLESS:
- parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, statements);
- break;
- default:
- assert(false && "unreachable");
- break;
- }
-
- pm_node_t *current = parent;
-
- // Parse any number of elsif clauses. This will form a linked list of if
- // nodes pointing to each other from the top.
- if (context == PM_CONTEXT_IF) {
- while (accept1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
- pm_token_t elsif_keyword = parser->previous;
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF);
- pm_accepts_block_stack_push(parser, true);
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF);
- pm_accepts_block_stack_pop(parser);
-
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_node_t *elsif = (pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, statements, NULL, &end_keyword);
- ((pm_if_node_t *) current)->consequent = elsif;
- current = elsif;
- }
- }
-
- if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
- parser_lex(parser);
- pm_token_t else_keyword = parser->previous;
-
- pm_accepts_block_stack_push(parser, true);
- pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE);
- pm_accepts_block_stack_pop(parser);
-
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
-
- pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
-
- switch (context) {
- case PM_CONTEXT_IF:
- ((pm_if_node_t *) current)->consequent = (pm_node_t *) else_node;
- break;
- case PM_CONTEXT_UNLESS:
- ((pm_unless_node_t *) parent)->consequent = else_node;
- break;
- default:
- assert(false && "unreachable");
- break;
- }
- } else {
- // We should specialize this error message to refer to 'if' or 'unless' explicitly.
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
- }
-
- // Set the appropriate end location for all of the nodes in the subtree.
- switch (context) {
- case PM_CONTEXT_IF: {
- pm_node_t *current = parent;
- bool recursing = true;
-
- while (recursing) {
- switch (PM_NODE_TYPE(current)) {
- case PM_IF_NODE:
- pm_if_node_end_keyword_loc_set((pm_if_node_t *) current, &parser->previous);
- current = ((pm_if_node_t *) current)->consequent;
- recursing = current != NULL;
- break;
- case PM_ELSE_NODE:
- pm_else_node_end_keyword_loc_set((pm_else_node_t *) current, &parser->previous);
- recursing = false;
- break;
- default: {
- recursing = false;
- break;
- }
- }
- }
- break;
- }
- case PM_CONTEXT_UNLESS:
- pm_unless_node_end_keyword_loc_set((pm_unless_node_t *) parent, &parser->previous);
- break;
- default:
- assert(false && "unreachable");
- break;
- }
-
- return parent;
-}
-
-/**
- * This macro allows you to define a case statement for all of the keywords.
- * It's meant to be used in a switch statement.
- */
-#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
- case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
- case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
- case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
- case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
- case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
- case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
- case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
- case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
- case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
- case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
-
-/**
- * This macro allows you to define a case statement for all of the operators.
- * It's meant to be used in a switch statement.
- */
-#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
- case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
- case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
- case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
- case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
- case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
- case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
- case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
-
-/**
- * This macro allows you to define a case statement for all of the token types
- * that represent the beginning of nodes that are "primitives" in a pattern
- * matching expression.
- */
-#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
- case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
- case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
- case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
- case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
- case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
- case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
- case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
- case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
-
-/**
- * This macro allows you to define a case statement for all of the token types
- * that could begin a parameter.
- */
-#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
- case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
- case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
- case PM_TOKEN_CLASS_VARIABLE
-
-/**
- * This macro allows you to define a case statement for all of the nodes that
- * can be transformed into write targets.
- */
-#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
- case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
- case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
- case PM_NUMBERED_REFERENCE_READ_NODE
-
-/**
- * Parse a node that is part of a string. If the subsequent tokens cannot be
- * parsed as a string part, then NULL is returned.
- */
-static pm_node_t *
-parse_string_part(pm_parser_t *parser) {
- switch (parser->current.type) {
- // Here the lexer has returned to us plain string content. In this case
- // we'll create a string node that has no opening or closing and return that
- // as the part. These kinds of parts look like:
- //
- // "aaa #{bbb} #@ccc ddd"
- // ^^^^ ^ ^^^^
- case PM_TOKEN_STRING_CONTENT: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
-
- parser_lex(parser);
- return node;
- }
- // Here the lexer has returned the beginning of an embedded expression. In
- // that case we'll parse the inner statements and return that as the part.
- // These kinds of parts look like:
- //
- // "aaa #{bbb} #@ccc ddd"
- // ^^^^^^
- case PM_TOKEN_EMBEXPR_BEGIN: {
- pm_lex_state_t state = parser->lex_state;
- int brace_nesting = parser->brace_nesting;
-
- parser->brace_nesting = 0;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser_lex(parser);
-
- pm_token_t opening = parser->previous;
- pm_statements_node_t *statements = NULL;
-
- if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, PM_CONTEXT_EMBEXPR);
- pm_accepts_block_stack_pop(parser);
- }
-
- parser->brace_nesting = brace_nesting;
- lex_state_set(parser, state);
-
- expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
- pm_token_t closing = parser->previous;
-
- return (pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
- }
-
- // Here the lexer has returned the beginning of an embedded variable.
- // In that case we'll parse the variable and create an appropriate node
- // for it and then return that node. These kinds of parts look like:
- //
- // "aaa #{bbb} #@ccc ddd"
- // ^^^^^
- case PM_TOKEN_EMBVAR: {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *variable;
-
- switch (parser->current.type) {
- // In this case a back reference is being interpolated. We'll
- // create a global variable read node.
- case PM_TOKEN_BACK_REFERENCE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
- break;
- // In this case an nth reference is being interpolated. We'll
- // create a global variable read node.
- case PM_TOKEN_NUMBERED_REFERENCE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
- break;
- // In this case a global variable is being interpolated. We'll
- // create a global variable read node.
- case PM_TOKEN_GLOBAL_VARIABLE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
- break;
- // In this case an instance variable is being interpolated.
- // We'll create an instance variable read node.
- case PM_TOKEN_INSTANCE_VARIABLE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
- break;
- // In this case a class variable is being interpolated. We'll
- // create a class variable read node.
- case PM_TOKEN_CLASS_VARIABLE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
- break;
- // We can hit here if we got an invalid token. In that case
- // we'll not attempt to lex this token and instead just return a
- // missing node.
- default:
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
- variable = (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- break;
- }
-
- return (pm_node_t *) pm_embedded_variable_node_create(parser, &operator, variable);
- }
- default:
- parser_lex(parser);
- pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
- return NULL;
- }
-}
-
-static pm_node_t *
-parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_state) {
- pm_token_t opening = parser->previous;
-
- if (lex_mode->mode != PM_LEX_STRING) {
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
-
- switch (parser->current.type) {
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_INSTANCE_VARIABLE:
- case PM_TOKEN_METHOD_NAME:
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- case PM_TOKEN_NUMBERED_REFERENCE:
- case PM_TOKEN_BACK_REFERENCE:
- case PM_CASE_KEYWORD:
- parser_lex(parser);
- break;
- case PM_CASE_OPERATOR:
- lex_state_set(parser, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
- parser_lex(parser);
- break;
- default:
- expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
- break;
- }
-
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
- pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- return (pm_node_t *) symbol;
- }
-
- if (lex_mode->as.string.interpolation) {
- // If we have the end of the symbol, then we can return an empty symbol.
- if (match1(parser, PM_TOKEN_STRING_END)) {
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
- parser_lex(parser);
-
- pm_token_t content = not_provided(parser);
- pm_token_t closing = parser->previous;
- return (pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
- }
-
- // Now we can parse the first part of the symbol.
- pm_node_t *part = parse_string_part(parser);
-
- // If we got a string part, then it's possible that we could transform
- // what looks like an interpolated symbol into a regular symbol.
- if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
-
- return (pm_node_t *) pm_string_node_to_symbol_node(parser, (pm_string_node_t *) part, &opening, &parser->previous);
- }
-
- // Create a node_list first. We'll use this to check if it should be an
- // InterpolatedSymbolNode or a SymbolNode.
- pm_node_list_t node_list = { 0 };
- if (part) pm_node_list_append(&node_list, part);
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser)) != NULL) {
- pm_node_list_append(&node_list, part);
- }
- }
-
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
-
- return (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &node_list, &parser->previous);
- }
-
- pm_token_t content;
- pm_string_t unescaped;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- content = parser->current;
- unescaped = parser->current_string;
- parser_lex(parser);
- } else {
- content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end };
- pm_string_shared_init(&unescaped, content.start, content.end);
- }
-
- if (next_state != PM_LEX_STATE_NONE) {
- lex_state_set(parser, next_state);
- }
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
- return (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
-}
-
-/**
- * Parse an argument to undef which can either be a bare word, a symbol, a
- * constant, or an interpolated symbol.
- */
-static inline pm_node_t *
-parse_undef_argument(pm_parser_t *parser) {
- switch (parser->current.type) {
- case PM_CASE_KEYWORD:
- case PM_CASE_OPERATOR:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
-
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
- pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- return (pm_node_t *) symbol;
- }
- case PM_TOKEN_SYMBOL_BEGIN: {
- pm_lex_mode_t lex_mode = *parser->lex_modes.current;
- parser_lex(parser);
-
- return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE);
- }
- default:
- pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- }
-}
-
-/**
- * Parse an argument to alias which can either be a bare word, a symbol, an
- * interpolated symbol or a global variable. If this is the first argument, then
- * we need to set the lex state to PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM
- * between the first and second arguments.
- */
-static inline pm_node_t *
-parse_alias_argument(pm_parser_t *parser, bool first) {
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- case PM_CASE_KEYWORD:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- if (first) {
- lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
- }
-
- parser_lex(parser);
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
- pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- return (pm_node_t *) symbol;
- }
- case PM_TOKEN_SYMBOL_BEGIN: {
- pm_lex_mode_t lex_mode = *parser->lex_modes.current;
- parser_lex(parser);
-
- return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
- }
- case PM_TOKEN_BACK_REFERENCE:
- parser_lex(parser);
- return (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
- case PM_TOKEN_NUMBERED_REFERENCE:
- parser_lex(parser);
- return (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
- case PM_TOKEN_GLOBAL_VARIABLE:
- parser_lex(parser);
- return (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
- default:
- pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- }
-}
-
-/**
- * Return true if any of the visible scopes to the current context are using
- * numbered parameters.
- */
-static bool
-outer_scope_using_numbered_params_p(pm_parser_t *parser) {
- for (pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
- if (scope->numbered_params) return true;
- }
-
- return false;
-}
-
-/**
- * Parse an identifier into either a local variable read or a call.
- */
-static pm_node_t *
-parse_variable_call(pm_parser_t *parser) {
- pm_node_flags_t flags = 0;
-
- if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.end[-1] != '!') && (parser->previous.end[-1] != '?')) {
- int depth;
- if ((depth = pm_parser_local_depth(parser, &parser->previous)) != -1) {
- return (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, (uint32_t) depth);
- }
-
- if (!parser->current_scope->closed && token_is_numbered_parameter(parser->previous.start, parser->previous.end)) {
- // Indicate that this scope is using numbered params so that child
- // scopes cannot.
- parser->current_scope->numbered_params = true;
-
- // Now that we know we have a numbered parameter, we need to check
- // if it's allowed in this context. If it is, then we will create a
- // local variable read. If it's not, then we'll create a normal call
- // node but add an error.
- if (parser->current_scope->explicit_params) {
- pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED);
- } else if (outer_scope_using_numbered_params_p(parser)) {
- pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE);
- } else {
- // When you use a numbered parameter, it implies the existence
- // of all of the locals that exist before it. For example,
- // referencing _2 means that _1 must exist. Therefore here we
- // loop through all of the possibilities and add them into the
- // constant pool.
- uint8_t number = parser->previous.start[1];
- uint8_t current = '1';
- uint8_t *value;
-
- while (current < number) {
- value = malloc(2);
- value[0] = '_';
- value[1] = current++;
- pm_parser_local_add_owned(parser, value, 2);
- }
-
- // Now we can add the actual token that is being used. For
- // this one we can add a shared version since it is directly
- // referenced in the source.
- pm_parser_local_add_token(parser, &parser->previous);
- return (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0);
- }
- }
-
- flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
- }
-
- pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
- node->base.flags |= flags;
-
- return (pm_node_t *) node;
-}
-
-static inline pm_token_t
-parse_method_definition_name(pm_parser_t *parser) {
- switch (parser->current.type) {
- case PM_CASE_KEYWORD:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME:
- parser_lex(parser);
- return parser->previous;
- case PM_CASE_OPERATOR:
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- parser_lex(parser);
- return parser->previous;
- default:
- return (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->current.start, .end = parser->current.end };
- }
-}
-
-static void
-parse_heredoc_dedent_string(pm_string_t *string, size_t common_whitespace) {
- // Get a reference to the string struct that is being held by the string
- // node. This is the value we're going to actually manipulate.
- pm_string_ensure_owned(string);
-
- // Now get the bounds of the existing string. We'll use this as a
- // destination to move bytes into. We'll also use it for bounds checking
- // since we don't require that these strings be null terminated.
- size_t dest_length = pm_string_length(string);
- const uint8_t *source_cursor = (uint8_t *) string->source;
- const uint8_t *source_end = source_cursor + dest_length;
-
- // We're going to move bytes backward in the string when we get leading
- // whitespace, so we'll maintain a pointer to the current position in the
- // string that we're writing to.
- size_t trimmed_whitespace = 0;
-
- // While we haven't reached the amount of common whitespace that we need to
- // trim and we haven't reached the end of the string, we'll keep trimming
- // whitespace. Trimming in this context means skipping over these bytes such
- // that they aren't copied into the new string.
- while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
- if (*source_cursor == '\t') {
- trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
- if (trimmed_whitespace > common_whitespace) break;
- } else {
- trimmed_whitespace++;
- }
-
- source_cursor++;
- dest_length--;
- }
-
- memmove((uint8_t *) string->source, source_cursor, (size_t) (source_end - source_cursor));
- string->length = dest_length;
-}
-
-/**
- * Take a heredoc node that is indented by a ~ and trim the leading whitespace.
- */
-static void
-parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_whitespace) {
- // The next node should be dedented if it's the first node in the list or if
- // if follows a string node.
- bool dedent_next = true;
-
- // Iterate over all nodes, and trim whitespace accordingly. We're going to
- // keep around two indices: a read and a write. If we end up trimming all of
- // the whitespace from a node, then we'll drop it from the list entirely.
- size_t write_index = 0;
-
- for (size_t read_index = 0; read_index < nodes->size; read_index++) {
- pm_node_t *node = nodes->nodes[read_index];
-
- // We're not manipulating child nodes that aren't strings. In this case
- // we'll skip past it and indicate that the subsequent node should not
- // be dedented.
- if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
- nodes->nodes[write_index++] = node;
- dedent_next = false;
- continue;
- }
-
- pm_string_node_t *string_node = ((pm_string_node_t *) node);
- if (dedent_next) {
- parse_heredoc_dedent_string(&string_node->unescaped, common_whitespace);
- }
-
- if (string_node->unescaped.length == 0) {
- pm_node_destroy(parser, node);
- } else {
- nodes->nodes[write_index++] = node;
- }
-
- // We always dedent the next node if it follows a string node.
- dedent_next = true;
- }
-
- nodes->size = write_index;
-}
-
-static pm_node_t *
-parse_pattern(pm_parser_t *parser, bool top_pattern, pm_diagnostic_id_t diag_id);
-
-/**
- * Accept any number of constants joined by :: delimiters.
- */
-static pm_node_t *
-parse_pattern_constant_path(pm_parser_t *parser, pm_node_t *node) {
- // Now, if there are any :: operators that follow, parse them as constant
- // path nodes.
- while (accept1(parser, PM_TOKEN_COLON_COLON)) {
- pm_token_t delimiter = parser->previous;
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
-
- pm_node_t *child = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- node = (pm_node_t *)pm_constant_path_node_create(parser, node, &delimiter, child);
- }
-
- // If there is a [ or ( that follows, then this is part of a larger pattern
- // expression. We'll parse the inner pattern here, then modify the returned
- // inner pattern with our constant path attached.
- if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
- return node;
- }
-
- pm_token_t opening;
- pm_token_t closing;
- pm_node_t *inner = NULL;
-
- if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
- opening = parser->previous;
- accept1(parser, PM_TOKEN_NEWLINE);
-
- if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- inner = parse_pattern(parser, true, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
- }
-
- closing = parser->previous;
- } else {
- parser_lex(parser);
- opening = parser->previous;
-
- if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- inner = parse_pattern(parser, true, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
- }
-
- closing = parser->previous;
- }
-
- if (!inner) {
- // If there was no inner pattern, then we have something like Foo() or
- // Foo[]. In that case we'll create an array pattern with no requireds.
- return (pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
- }
-
- // Now that we have the inner pattern, check to see if it's an array, find,
- // or hash pattern. If it is, then we'll attach our constant path to it if
- // it doesn't already have a constant. If it's not one of those node types
- // or it does have a constant, then we'll create an array pattern.
- switch (PM_NODE_TYPE(inner)) {
- case PM_ARRAY_PATTERN_NODE: {
- pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
-
- if (pattern_node->constant == NULL) {
- pattern_node->base.location.start = node->location.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- case PM_FIND_PATTERN_NODE: {
- pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
-
- if (pattern_node->constant == NULL) {
- pattern_node->base.location.start = node->location.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- case PM_HASH_PATTERN_NODE: {
- pm_hash_pattern_node_t *pattern_node = (pm_hash_pattern_node_t *) inner;
-
- if (pattern_node->constant == NULL) {
- pattern_node->base.location.start = node->location.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- default:
- break;
- }
-
- // If we got here, then we didn't return one of the inner patterns by
- // attaching its constant. In this case we'll create an array pattern and
- // attach our constant to it.
- pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
- pm_array_pattern_node_requireds_append(pattern_node, inner);
- return (pm_node_t *) pattern_node;
-}
-
-/**
- * Parse a rest pattern.
- */
-static pm_splat_node_t *
-parse_pattern_rest(pm_parser_t *parser) {
- assert(parser->previous.type == PM_TOKEN_USTAR);
- pm_token_t operator = parser->previous;
- pm_node_t *name = NULL;
-
- // Rest patterns don't necessarily have a name associated with them. So we
- // will check for that here. If they do, then we'll add it to the local table
- // since this pattern will cause it to become a local variable.
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- pm_token_t identifier = parser->previous;
- pm_parser_local_add_token(parser, &identifier);
- name = (pm_node_t *) pm_local_variable_target_node_create(parser, &identifier);
- }
-
- // Finally we can return the created node.
- return pm_splat_node_create(parser, &operator, name);
-}
-
-/**
- * Parse a keyword rest node.
- */
-static pm_node_t *
-parse_pattern_keyword_rest(pm_parser_t *parser) {
- assert(parser->current.type == PM_TOKEN_USTAR_STAR);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *value = NULL;
-
- if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
- return (pm_node_t *) pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous);
- }
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- pm_parser_local_add_token(parser, &parser->previous);
- value = (pm_node_t *) pm_local_variable_target_node_create(parser, &parser->previous);
- }
-
- return (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
-}
-
-/**
- * Parse a hash pattern.
- */
-static pm_hash_pattern_node_t *
-parse_pattern_hash(pm_parser_t *parser, pm_node_t *first_assoc) {
- pm_node_list_t assocs = { 0 };
- pm_node_t *rest = NULL;
-
- switch (PM_NODE_TYPE(first_assoc)) {
- case PM_ASSOC_NODE: {
- if (!match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- // Here we have a value for the first assoc in the list, so we will
- // parse it now and update the first assoc.
- pm_node_t *value = parse_pattern(parser, false, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
-
- pm_assoc_node_t *assoc = (pm_assoc_node_t *) first_assoc;
- assoc->base.location.end = value->location.end;
- assoc->value = value;
- } else {
- pm_node_t *key = ((pm_assoc_node_t *) first_assoc)->key;
-
- if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
- const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
- pm_parser_local_add_location(parser, value_loc->start, value_loc->end);
- }
- }
-
- pm_node_list_append(&assocs, first_assoc);
- break;
- }
- case PM_ASSOC_SPLAT_NODE:
- case PM_NO_KEYWORDS_PARAMETER_NODE:
- rest = first_assoc;
- break;
- default:
- assert(false);
- break;
- }
-
- // If there are any other assocs, then we'll parse them now.
- while (accept1(parser, PM_TOKEN_COMMA)) {
- // Here we need to break to support trailing commas.
- if (match6(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- break;
- }
-
- pm_node_t *assoc;
-
- if (match1(parser, PM_TOKEN_USTAR_STAR)) {
- assoc = parse_pattern_keyword_rest(parser);
- } else {
- expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
- pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
- pm_node_t *value = NULL;
-
- if (!match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- value = parse_pattern(parser, false, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY);
- } else {
- const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
- pm_parser_local_add_location(parser, value_loc->start, value_loc->end);
- }
-
- pm_token_t operator = not_provided(parser);
- assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
- }
-
- pm_node_list_append(&assocs, assoc);
- }
-
- pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest);
- free(assocs.nodes);
-
- return node;
-}
-
-/**
- * Parse a pattern expression primitive.
- */
-static pm_node_t *
-parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
- switch (parser->current.type) {
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- pm_parser_local_add_token(parser, &parser->previous);
- return (pm_node_t *) pm_local_variable_target_node_create(parser, &parser->previous);
- }
- case PM_TOKEN_BRACKET_LEFT_ARRAY: {
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- // If we have an empty array pattern, then we'll just return a new
- // array pattern node.
- return (pm_node_t *)pm_array_pattern_node_empty_create(parser, &opening, &parser->previous);
- }
-
- // Otherwise, we'll parse the inner pattern, then deal with it depending
- // on the type it returns.
- pm_node_t *inner = parse_pattern(parser, true, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET);
-
- accept1(parser, PM_TOKEN_NEWLINE);
-
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
- pm_token_t closing = parser->previous;
-
- switch (PM_NODE_TYPE(inner)) {
- case PM_ARRAY_PATTERN_NODE: {
- pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
- if (pattern_node->opening_loc.start == NULL) {
- pattern_node->base.location.start = opening.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- case PM_FIND_PATTERN_NODE: {
- pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
- if (pattern_node->opening_loc.start == NULL) {
- pattern_node->base.location.start = opening.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- default:
- break;
- }
-
- pm_array_pattern_node_t *node = pm_array_pattern_node_empty_create(parser, &opening, &closing);
- pm_array_pattern_node_requireds_append(node, inner);
- return (pm_node_t *) node;
- }
- case PM_TOKEN_BRACE_LEFT: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = false;
-
- pm_hash_pattern_node_t *node;
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
- // If we have an empty hash pattern, then we'll just return a new hash
- // pattern node.
- node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
- } else {
- pm_node_t *first_assoc;
-
- switch (parser->current.type) {
- case PM_TOKEN_LABEL: {
- parser_lex(parser);
-
- pm_symbol_node_t *key = pm_symbol_node_label_create(parser, &parser->previous);
- pm_token_t operator = not_provided(parser);
-
- first_assoc = (pm_node_t *) pm_assoc_node_create(parser, (pm_node_t *) key, &operator, NULL);
- break;
- }
- case PM_TOKEN_USTAR_STAR:
- first_assoc = parse_pattern_keyword_rest(parser);
- break;
- case PM_TOKEN_STRING_BEGIN: {
- pm_node_t *key = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_HASH_KEY);
- pm_token_t operator = not_provided(parser);
-
- if (!pm_symbol_node_label_p(key)) {
- pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_LABEL);
- }
-
- first_assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, NULL);
- break;
- }
- default: {
- parser_lex(parser);
- pm_parser_err_previous(parser, PM_ERR_PATTERN_HASH_KEY);
-
- pm_missing_node_t *key = pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- pm_token_t operator = not_provided(parser);
-
- first_assoc = (pm_node_t *) pm_assoc_node_create(parser, (pm_node_t *) key, &operator, NULL);
- break;
- }
- }
-
- node = parse_pattern_hash(parser, first_assoc);
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
- pm_token_t closing = parser->previous;
-
- node->base.location.start = opening.start;
- node->base.location.end = closing.end;
-
- node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
- }
-
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- return (pm_node_t *) node;
- }
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT: {
- pm_token_t operator = parser->current;
- parser_lex(parser);
-
- // Since we have a unary range operator, we need to parse the subsequent
- // expression as the right side of the range.
- switch (parser->current.type) {
- case PM_CASE_PRIMITIVE: {
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- }
- default: {
- pm_parser_err_token(parser, &operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
- pm_node_t *right = (pm_node_t *) pm_missing_node_create(parser, operator.start, operator.end);
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- }
- }
- }
- case PM_CASE_PRIMITIVE: {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, diag_id);
-
- // Now that we have a primitive, we need to check if it's part of a range.
- if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
- pm_token_t operator = parser->previous;
-
- // Now that we have the operator, we need to check if this is followed
- // by another expression. If it is, then we will create a full range
- // node. Otherwise, we'll create an endless range.
- switch (parser->current.type) {
- case PM_CASE_PRIMITIVE: {
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
- return (pm_node_t *) pm_range_node_create(parser, node, &operator, right);
- }
- default:
- return (pm_node_t *) pm_range_node_create(parser, node, &operator, NULL);
- }
- }
-
- return node;
- }
- case PM_TOKEN_CARET: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
-
- // At this point we have a pin operator. We need to check the subsequent
- // expression to determine if it's a variable or an expression.
- switch (parser->current.type) {
- case PM_TOKEN_IDENTIFIER: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_INSTANCE_VARIABLE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_CLASS_VARIABLE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_GLOBAL_VARIABLE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_NUMBERED_REFERENCE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_BACK_REFERENCE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_PARENTHESIS_LEFT: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = false;
-
- pm_token_t lparen = parser->current;
- parser_lex(parser);
-
- pm_node_t *expression = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
- return (pm_node_t *) pm_pinned_expression_node_create(parser, expression, &operator, &lparen, &parser->previous);
- }
- default: {
- // If we get here, then we have a pin operator followed by something
- // not understood. We'll create a missing node and return that.
- pm_parser_err_token(parser, &operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
- pm_node_t *variable = (pm_node_t *) pm_missing_node_create(parser, operator.start, operator.end);
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- }
- }
- case PM_TOKEN_UCOLON_COLON: {
- pm_token_t delimiter = parser->current;
- parser_lex(parser);
-
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *child = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, child);
-
- return parse_pattern_constant_path(parser, (pm_node_t *)node);
- }
- case PM_TOKEN_CONSTANT: {
- pm_token_t constant = parser->current;
- parser_lex(parser);
-
- pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &constant);
- return parse_pattern_constant_path(parser, node);
- }
- default:
- pm_parser_err_current(parser, diag_id);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- }
-}
-
-/**
- * Parse any number of primitives joined by alternation and ended optionally by
- * assignment.
- */
-static pm_node_t *
-parse_pattern_primitives(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
- pm_node_t *node = NULL;
-
- do {
- pm_token_t operator = parser->previous;
-
- switch (parser->current.type) {
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_BRACKET_LEFT_ARRAY:
- case PM_TOKEN_BRACE_LEFT:
- case PM_TOKEN_CARET:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_UCOLON_COLON:
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT:
- case PM_CASE_PRIMITIVE: {
- if (node == NULL) {
- node = parse_pattern_primitive(parser, diag_id);
- } else {
- pm_node_t *right = parse_pattern_primitive(parser, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE);
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
- }
-
- break;
- }
- case PM_TOKEN_PARENTHESIS_LEFT: {
- parser_lex(parser);
- if (node != NULL) {
- pm_node_destroy(parser, node);
- }
- node = parse_pattern(parser, false, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN);
-
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
- break;
- }
- default: {
- pm_parser_err_current(parser, diag_id);
- pm_node_t *right = (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
-
- if (node == NULL) {
- node = right;
- } else {
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
- }
-
- break;
- }
- }
- } while (accept1(parser, PM_TOKEN_PIPE));
-
- // If we have an =>, then we are assigning this pattern to a variable.
- // In this case we should create an assignment node.
- while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- pm_token_t operator = parser->previous;
-
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
- pm_token_t identifier = parser->previous;
- pm_parser_local_add_token(parser, &identifier);
-
- pm_node_t *target = (pm_node_t *) pm_local_variable_target_node_create(parser, &identifier);
- node = (pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &operator);
- }
-
- return node;
-}
-
-/**
- * Parse a pattern matching expression.
- */
-static pm_node_t *
-parse_pattern(pm_parser_t *parser, bool top_pattern, pm_diagnostic_id_t diag_id) {
- pm_node_t *node = NULL;
-
- bool leading_rest = false;
- bool trailing_rest = false;
-
- switch (parser->current.type) {
- case PM_TOKEN_LABEL: {
- parser_lex(parser);
- pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
- pm_token_t operator = not_provided(parser);
-
- return (pm_node_t *) parse_pattern_hash(parser, (pm_node_t *) pm_assoc_node_create(parser, key, &operator, NULL));
- }
- case PM_TOKEN_USTAR_STAR: {
- node = parse_pattern_keyword_rest(parser);
- return (pm_node_t *) parse_pattern_hash(parser, node);
- }
- case PM_TOKEN_USTAR: {
- if (top_pattern) {
- parser_lex(parser);
- node = (pm_node_t *) parse_pattern_rest(parser);
- leading_rest = true;
- break;
- }
- }
- /* fallthrough */
- default:
- node = parse_pattern_primitives(parser, diag_id);
- break;
- }
-
- // If we got a dynamic label symbol, then we need to treat it like the
- // beginning of a hash pattern.
- if (pm_symbol_node_label_p(node)) {
- pm_token_t operator = not_provided(parser);
- return (pm_node_t *) parse_pattern_hash(parser, (pm_node_t *) pm_assoc_node_create(parser, node, &operator, NULL));
- }
-
- if (top_pattern && match1(parser, PM_TOKEN_COMMA)) {
- // If we have a comma, then we are now parsing either an array pattern or a
- // find pattern. We need to parse all of the patterns, put them into a big
- // list, and then determine which type of node we have.
- pm_node_list_t nodes = { 0 };
- pm_node_list_append(&nodes, node);
-
- // Gather up all of the patterns into the list.
- while (accept1(parser, PM_TOKEN_COMMA)) {
- // Break early here in case we have a trailing comma.
- if (match5(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- break;
- }
-
- if (accept1(parser, PM_TOKEN_USTAR)) {
- node = (pm_node_t *) parse_pattern_rest(parser);
-
- // If we have already parsed a splat pattern, then this is an error. We
- // will continue to parse the rest of the patterns, but we will indicate
- // it as an error.
- if (trailing_rest) {
- pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
- }
-
- trailing_rest = true;
- } else {
- node = parse_pattern_primitives(parser, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA);
- }
-
- pm_node_list_append(&nodes, node);
- }
-
- // If the first pattern and the last pattern are rest patterns, then we will
- // call this a find pattern, regardless of how many rest patterns are in
- // between because we know we already added the appropriate errors.
- // Otherwise we will create an array pattern.
- if (PM_NODE_TYPE_P(nodes.nodes[0], PM_SPLAT_NODE) && PM_NODE_TYPE_P(nodes.nodes[nodes.size - 1], PM_SPLAT_NODE)) {
- node = (pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
- } else {
- node = (pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
- }
-
- free(nodes.nodes);
- } else if (leading_rest) {
- // Otherwise, if we parsed a single splat pattern, then we know we have an
- // array pattern, so we can go ahead and create that node.
- node = (pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
- }
-
- return node;
-}
-
-/**
- * Incorporate a negative sign into a numeric node by subtracting 1 character
- * from its start bounds. If it's a compound node, then we will recursively
- * apply this function to its value.
- */
-static inline void
-parse_negative_numeric(pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_INTEGER_NODE:
- case PM_FLOAT_NODE:
- node->location.start--;
- break;
- case PM_RATIONAL_NODE:
- node->location.start--;
- parse_negative_numeric(((pm_rational_node_t *) node)->numeric);
- break;
- case PM_IMAGINARY_NODE:
- node->location.start--;
- parse_negative_numeric(((pm_imaginary_node_t *) node)->numeric);
- break;
- default:
- assert(false && "unreachable");
- break;
- }
-}
-
-/**
- * Returns a string content token at a particular location that is empty.
- */
-static pm_token_t
-parse_strings_empty_content(const uint8_t *location) {
- return (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
-}
-
-/**
- * Parse a set of strings that could be concatenated together.
- */
-static inline pm_node_t *
-parse_strings(pm_parser_t *parser) {
- assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
- pm_node_t *result = NULL;
- bool state_is_arg_labeled = lex_state_p(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
-
- while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- pm_node_t *node = NULL;
-
- // Here we have found a string literal. We'll parse it and add it to
- // the list of strings.
- assert(parser->lex_modes.current->mode == PM_LEX_STRING);
- bool lex_interpolation = parser->lex_modes.current->as.string.interpolation;
-
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (accept1(parser, PM_TOKEN_STRING_END)) {
- // If we get here, then we have an end immediately after a
- // start. In that case we'll create an empty content token and
- // return an uninterpolated string.
- pm_token_t content = parse_strings_empty_content(parser->previous.start);
- pm_string_node_t *string = pm_string_node_create(parser, &opening, &content, &parser->previous);
-
- pm_string_shared_init(&string->unescaped, content.start, content.end);
- node = (pm_node_t *) string;
- } else if (accept1(parser, PM_TOKEN_LABEL_END)) {
- // If we get here, then we have an end of a label immediately
- // after a start. In that case we'll create an empty symbol
- // node.
- pm_token_t opening = not_provided(parser);
- pm_token_t content = parse_strings_empty_content(parser->previous.start);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &content, &parser->previous);
-
- pm_string_shared_init(&symbol->unescaped, content.start, content.end);
- node = (pm_node_t *) symbol;
- } else if (!lex_interpolation) {
- // If we don't accept interpolation then we expect the string to
- // start with a single string content node.
- pm_string_t unescaped;
- if (match1(parser, PM_TOKEN_EOF)) {
- unescaped = PM_STRING_EMPTY;
- } else {
- unescaped = parser->current_string;
- }
-
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
- pm_token_t content = parser->previous;
-
- // It is unfortunately possible to have multiple string content
- // nodes in a row in the case that there's heredoc content in
- // the middle of the string, like this cursed example:
- //
- // <<-END+'b
- // a
- // END
- // c'+'d'
- //
- // In that case we need to switch to an interpolated string to
- // be able to contain all of the parts.
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_node_list_t parts = { 0 };
-
- pm_token_t delimiters = not_provided(parser);
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
- pm_node_list_append(&parts, part);
-
- do {
- part = (pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->current, &delimiters);
- pm_node_list_append(&parts, part);
- parser_lex(parser);
- } while (match1(parser, PM_TOKEN_STRING_CONTENT));
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
- } else if (accept1(parser, PM_TOKEN_LABEL_END) && !state_is_arg_labeled) {
- node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- }
- } else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- // In this case we've hit string content so we know the string
- // at least has something in it. We'll need to check if the
- // following token is the end (in which case we can return a
- // plain string) or if it's not then it has interpolation.
- pm_token_t content = parser->current;
- pm_string_t unescaped = parser->current_string;
- parser_lex(parser);
-
- if (match1(parser, PM_TOKEN_STRING_END)) {
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
- parser_lex(parser);
- } else if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- } else {
- // If we get here, then we have interpolation so we'll need
- // to create a string or symbol node with interpolation.
- pm_node_list_t parts = { 0 };
- pm_token_t string_opening = not_provided(parser);
- pm_token_t string_closing = not_provided(parser);
-
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->previous, &string_closing, &unescaped);
- pm_node_list_append(&parts, part);
-
- while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser)) != NULL) {
- pm_node_list_append(&parts, part);
- }
- }
-
- if (accept1(parser, PM_TOKEN_LABEL_END) && !state_is_arg_labeled) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
- }
- }
- } else {
- // If we get here, then the first part of the string is not plain
- // string content, in which case we need to parse the string as an
- // interpolated string.
- pm_node_list_t parts = { 0 };
- pm_node_t *part;
-
- while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser)) != NULL) {
- pm_node_list_append(&parts, part);
- }
- }
-
- if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
- }
- }
-
- if (result == NULL) {
- // If the node we just parsed is a symbol node, then we can't
- // concatenate it with anything else, so we can now return that
- // node.
- if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
- return node;
- }
-
- // If we don't already have a node, then it's fine and we can just
- // set the result to be the node we just parsed.
- result = node;
- } else {
- // Otherwise we need to check the type of the node we just parsed.
- // If it cannot be concatenated with the previous node, then we'll
- // need to add a syntax error.
- if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
- pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
- }
-
- // Either way we will create a concat node to hold the strings
- // together.
- result = (pm_node_t *) pm_string_concat_node_create(parser, result, node);
- }
- }
-
- return result;
-}
-
-/**
- * Parse an expression that begins with the previous node that we just lexed.
- */
-static inline pm_node_t *
-parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
- switch (parser->current.type) {
- case PM_TOKEN_BRACKET_LEFT_ARRAY: {
- parser_lex(parser);
-
- pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
- pm_accepts_block_stack_push(parser, true);
- bool parsed_bare_hash = false;
-
- while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
- // Handle the case where we don't have a comma and we have a
- // newline followed by a right bracket.
- if (accept1(parser, PM_TOKEN_NEWLINE) && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- break;
- }
-
- if (pm_array_node_size(array) != 0) {
- expect1(parser, PM_TOKEN_COMMA, PM_ERR_ARRAY_SEPARATOR);
- }
-
- // If we have a right bracket immediately following a comma,
- // this is allowed since it's a trailing comma. In this case we
- // can break out of the loop.
- if (match1(parser, PM_TOKEN_BRACKET_RIGHT)) break;
-
- pm_node_t *element;
-
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = NULL;
-
- if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
- if (pm_parser_local_depth(parser, &parser->previous) == -1) {
- pm_parser_err_token(parser, &operator, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
- }
- } else {
- expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR);
- }
-
- element = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
- } else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
- if (parsed_bare_hash) {
- pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
- }
-
- pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
- element = (pm_node_t *)hash;
-
- if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
- parse_assocs(parser, (pm_node_t *) hash);
- }
-
- parsed_bare_hash = true;
- } else {
- element = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION);
-
- if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- if (parsed_bare_hash) {
- pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
- }
-
- pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
-
- pm_token_t operator;
- if (parser->previous.type == PM_TOKEN_EQUAL_GREATER) {
- operator = parser->previous;
- } else {
- operator = not_provided(parser);
- }
-
- pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &operator, value);
- pm_keyword_hash_node_elements_append(hash, assoc);
-
- element = (pm_node_t *)hash;
- if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- parse_assocs(parser, (pm_node_t *) hash);
- }
-
- parsed_bare_hash = true;
- }
- }
-
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_ARRAY_TERM);
- pm_array_node_close_set(array, &parser->previous);
- pm_accepts_block_stack_pop(parser);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PARENTHESIS_LEFT:
- case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
- pm_token_t opening = parser->current;
- parser_lex(parser);
- while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
-
- // If this is the end of the file or we match a right parenthesis, then
- // we have an empty parentheses node, and we can immediately return.
- if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous);
- }
-
- // Otherwise, we're going to parse the first statement in the list
- // of statements within the parentheses.
- pm_accepts_block_stack_push(parser, true);
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION);
-
- // Determine if this statement is followed by a terminator. In the
- // case of a single statement, this is fine. But in the case of
- // multiple statements it's required.
- bool terminator_found = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- if (terminator_found) {
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- }
-
- // If we hit a right parenthesis, then we're done parsing the
- // parentheses node, and we can check which kind of node we should
- // return.
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- if (opening.type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
- lex_state_set(parser, PM_LEX_STATE_ENDARG);
- }
- parser_lex(parser);
- pm_accepts_block_stack_pop(parser);
-
- if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
- // If we have a single statement and are ending on a right
- // parenthesis, then we need to check if this is possibly a
- // multiple target node.
- pm_multi_target_node_t *multi_target;
-
- if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
- multi_target = (pm_multi_target_node_t *) statement;
- } else {
- multi_target = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, multi_target, statement);
- }
-
- pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pm_location_t rparen_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- multi_target->lparen_loc = lparen_loc;
- multi_target->rparen_loc = rparen_loc;
- multi_target->base.location.start = lparen_loc.start;
- multi_target->base.location.end = rparen_loc.end;
-
- if (match1(parser, PM_TOKEN_COMMA)) {
- if (binding_power == PM_BINDING_POWER_STATEMENT) {
- return parse_targets_validate(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX);
- }
- return (pm_node_t *) multi_target;
- }
-
- return parse_target_validate(parser, (pm_node_t *) multi_target);
- }
-
- // If we have a single statement and are ending on a right parenthesis
- // and we didn't return a multiple assignment node, then we can return a
- // regular parentheses node now.
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
-
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
- }
-
- // If we have more than one statement in the set of parentheses,
- // then we are going to parse all of them as a list of statements.
- // We'll do that here.
- context_push(parser, PM_CONTEXT_PARENS);
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
-
- // If we didn't find a terminator and we didn't find a right
- // parenthesis, then this is a syntax error.
- if (!terminator_found) {
- pm_parser_err(parser, parser->current.start, parser->current.start, PM_ERR_EXPECT_EOL_AFTER_STATEMENT);
- }
-
- // Parse each statement within the parentheses.
- while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION);
- pm_statements_node_body_append(statements, node);
-
- // If we're recovering from a syntax error, then we need to stop
- // parsing the statements now.
- if (parser->recovering) {
- // If this is the level of context where the recovery has
- // happened, then we can mark the parser as done recovering.
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering = false;
- break;
- }
-
- // If we couldn't parse an expression at all, then we need to
- // bail out of the loop.
- if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) break;
-
- // If we successfully parsed a statement, then we are going to
- // need terminator to delimit them.
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) break;
- } else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- break;
- } else {
- pm_parser_err(parser, parser->current.start, parser->current.start, PM_ERR_EXPECT_EOL_AFTER_STATEMENT);
- }
- }
-
- context_pop(parser);
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
-
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
- }
- case PM_TOKEN_BRACE_LEFT: {
- pm_accepts_block_stack_push(parser, true);
- parser_lex(parser);
- pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous);
-
- if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
- parse_assocs(parser, (pm_node_t *) node);
- accept1(parser, PM_TOKEN_NEWLINE);
- }
-
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
- pm_hash_node_closing_loc_set(node, &parser->previous);
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_CHARACTER_LITERAL: {
- parser_lex(parser);
-
- pm_token_t opening = parser->previous;
- opening.type = PM_TOKEN_STRING_BEGIN;
- opening.end = opening.start + 1;
-
- pm_token_t content = parser->previous;
- content.type = PM_TOKEN_STRING_CONTENT;
- content.start = content.start + 1;
-
- pm_token_t closing = not_provided(parser);
- pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
-
- // Characters can be followed by strings in which case they are
- // automatically concatenated.
- if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- pm_node_t *concat = parse_strings(parser);
- return (pm_node_t *) pm_string_concat_node_create(parser, node, concat);
- }
-
- return node;
- }
- case PM_TOKEN_CLASS_VARIABLE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_CONSTANT: {
- parser_lex(parser);
- pm_token_t constant = parser->previous;
-
- // If a constant is immediately followed by parentheses, then this is in
- // fact a method call, not a constant read.
- if (
- match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
- (binding_power <= PM_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
- (pm_accepts_block_stack_p(parser) && match2(parser, PM_TOKEN_KEYWORD_DO, PM_TOKEN_BRACE_LEFT))
- ) {
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
- return (pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
- }
-
- pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
-
- if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
- // If we get here, then we have a comma immediately following a
- // constant, so we're going to parse this as a multiple assignment.
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_UCOLON_COLON: {
- parser_lex(parser);
-
- pm_token_t delimiter = parser->previous;
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
-
- pm_node_t *constant = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- pm_node_t *node = (pm_node_t *)pm_constant_path_node_create(parser, NULL, &delimiter, constant);
-
- if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT: {
- pm_token_t operator = parser->current;
- parser_lex(parser);
-
- pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- }
- case PM_TOKEN_FLOAT:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_create(parser, &parser->previous);
- case PM_TOKEN_FLOAT_IMAGINARY:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_imaginary_create(parser, &parser->previous);
- case PM_TOKEN_FLOAT_RATIONAL:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_rational_create(parser, &parser->previous);
- case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->previous);
- case PM_TOKEN_NUMBERED_REFERENCE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_GLOBAL_VARIABLE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_BACK_REFERENCE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- pm_token_t identifier = parser->previous;
- pm_node_t *node = parse_variable_call(parser);
-
- if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
- // If parse_variable_call returned with a call node, then we
- // know the identifier is not in the local table. In that case
- // we need to check if there are arguments following the
- // identifier.
- pm_call_node_t *call = (pm_call_node_t *) node;
- pm_arguments_t arguments = { 0 };
-
- if (parse_arguments_list(parser, &arguments, true)) {
- // Since we found arguments, we need to turn off the
- // variable call bit in the flags.
- call->base.flags &= (pm_node_flags_t) ~PM_CALL_NODE_FLAGS_VARIABLE_CALL;
-
- call->opening_loc = arguments.opening_loc;
- call->arguments = arguments.arguments;
- call->closing_loc = arguments.closing_loc;
- call->block = arguments.block;
-
- if (arguments.block != NULL) {
- call->base.location.end = arguments.block->location.end;
- } else if (arguments.closing_loc.start == NULL) {
- if (arguments.arguments != NULL) {
- call->base.location.end = arguments.arguments->base.location.end;
- } else {
- call->base.location.end = call->message_loc.end;
- }
- } else {
- call->base.location.end = arguments.closing_loc.end;
- }
- }
- } else {
- // Otherwise, we know the identifier is in the local table. This
- // can still be a method call if it is followed by arguments or
- // a block, so we need to check for that here.
- if (
- (binding_power <= PM_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
- (pm_accepts_block_stack_p(parser) && match2(parser, PM_TOKEN_KEYWORD_DO, PM_TOKEN_BRACE_LEFT))
- ) {
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
-
- pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
- pm_node_destroy(parser, node);
- return (pm_node_t *) fcall;
- }
- }
-
- if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_HEREDOC_START: {
- // Here we have found a heredoc. We'll parse it and add it to the
- // list of strings.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- assert(lex_mode->mode == PM_LEX_HEREDOC);
- pm_heredoc_quote_t quote = lex_mode->as.heredoc.quote;
- pm_heredoc_indent_t indent = lex_mode->as.heredoc.indent;
-
- parser_lex(parser);
- pm_token_t opening = parser->previous;
-
- pm_node_t *node;
- pm_node_t *part;
-
- if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
- // If we get here, then we have an empty heredoc. We'll create
- // an empty content token and return an empty string node.
- lex_state_set(parser, PM_LEX_STATE_END);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
- pm_token_t content = parse_strings_empty_content(parser->previous.start);
-
- if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
- node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY);
- } else {
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY);
- }
-
- node->location.end = opening.end;
- } else if ((part = parse_string_part(parser)) == NULL) {
- // If we get here, then we tried to find something in the
- // heredoc but couldn't actually parse anything, so we'll just
- // return a missing node.
- node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- } else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
- // If we get here, then the part that we parsed was plain string
- // content and we're at the end of the heredoc, so we can return
- // just a string node with the heredoc opening and closing as
- // its opening and closing.
- pm_string_node_t *cast = (pm_string_node_t *) part;
-
- cast->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- cast->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->current);
- cast->base.location = cast->opening_loc;
-
- if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
- assert(sizeof(pm_string_node_t) == sizeof(pm_x_string_node_t));
- cast->base.type = PM_X_STRING_NODE;
- }
-
- size_t common_whitespace = lex_mode->as.heredoc.common_whitespace;
- if (indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
- parse_heredoc_dedent_string(&cast->unescaped, common_whitespace);
- }
-
- node = (pm_node_t *) cast;
- lex_state_set(parser, PM_LEX_STATE_END);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
- } else {
- // If we get here, then we have multiple parts in the heredoc,
- // so we'll need to create an interpolated string node to hold
- // them all.
- pm_node_list_t parts = { 0 };
- pm_node_list_append(&parts, part);
-
- while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser)) != NULL) {
- pm_node_list_append(&parts, part);
- }
- }
-
- // Now that we have all of the parts, create the correct type of
- // interpolated node.
- if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
- pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening);
- cast->parts = parts;
-
- lex_state_set(parser, PM_LEX_STATE_END);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
-
- pm_interpolated_xstring_node_closing_set(cast, &parser->previous);
- cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
- } else {
- pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
-
- lex_state_set(parser, PM_LEX_STATE_END);
- expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM);
-
- pm_interpolated_string_node_closing_set(cast, &parser->previous);
- cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
- }
-
- // If this is a heredoc that is indented with a ~, then we need
- // to dedent each line by the common leading whitespace.
- size_t common_whitespace = lex_mode->as.heredoc.common_whitespace;
- if (indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
- pm_node_list_t *nodes;
- if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
- nodes = &((pm_interpolated_x_string_node_t *) node)->parts;
- } else {
- nodes = &((pm_interpolated_string_node_t *) node)->parts;
- }
-
- parse_heredoc_dedent(parser, nodes, common_whitespace);
- }
- }
-
- if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- pm_node_t *concat = parse_strings(parser);
- return (pm_node_t *) pm_string_concat_node_create(parser, node, concat);
- }
-
- return node;
- }
- case PM_TOKEN_INSTANCE_VARIABLE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX);
- }
-
- return node;
- }
- case PM_TOKEN_INTEGER: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_INTEGER_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_INTEGER_RATIONAL: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_KEYWORD___ENCODING__:
- parser_lex(parser);
- return (pm_node_t *) pm_source_encoding_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD___FILE__:
- parser_lex(parser);
- return (pm_node_t *) pm_source_file_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD___LINE__:
- parser_lex(parser);
- return (pm_node_t *) pm_source_line_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_ALIAS: {
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- pm_node_t *new_name = parse_alias_argument(parser, true);
- pm_node_t *old_name = parse_alias_argument(parser, false);
-
- switch (PM_NODE_TYPE(new_name)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- if (PM_NODE_TYPE_P(old_name, PM_BACK_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_GLOBAL_VARIABLE_READ_NODE)) {
- if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
- pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
- }
- } else {
- pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
- }
-
- return (pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
- }
- case PM_SYMBOL_NODE:
- case PM_INTERPOLATED_SYMBOL_NODE: {
- if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
- pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
- }
- }
- /* fallthrough */
- default:
- return (pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
- }
- }
- case PM_TOKEN_KEYWORD_CASE: {
- parser_lex(parser);
- pm_token_t case_keyword = parser->previous;
- pm_node_t *predicate = NULL;
-
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- predicate = NULL;
- } else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
- predicate = NULL;
- } else if (!token_begins_expression_p(parser->current.type)) {
- predicate = NULL;
- } else {
- predicate = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CASE_EXPRESSION_AFTER_CASE);
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- }
-
- if (accept1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
- return (pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, NULL, &parser->previous);
- }
-
- // At this point we can create a case node, though we don't yet know if it
- // is a case-in or case-when node.
- pm_token_t end_keyword = not_provided(parser);
- pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL, &end_keyword);
-
- if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
- // At this point we've seen a when keyword, so we know this is a
- // case-when node. We will continue to parse the when nodes until we hit
- // the end of the list.
- while (accept1(parser, PM_TOKEN_KEYWORD_WHEN)) {
- pm_token_t when_keyword = parser->previous;
- pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
-
- do {
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
-
- pm_splat_node_t *splat_node = pm_splat_node_create(parser, &operator, expression);
- pm_when_node_conditions_append(when_node, (pm_node_t *) splat_node);
-
- if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE)) break;
- } else {
- pm_node_t *condition = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CASE_EXPRESSION_AFTER_WHEN);
- pm_when_node_conditions_append(when_node, condition);
-
- if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE)) break;
- }
- } while (accept1(parser, PM_TOKEN_COMMA));
-
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- accept1(parser, PM_TOKEN_KEYWORD_THEN);
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
- }
-
- if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN);
- if (statements != NULL) {
- pm_when_node_statements_set(when_node, statements);
- }
- }
-
- pm_case_node_condition_append(case_node, (pm_node_t *) when_node);
- }
- } else {
- // At this point we expect that we're parsing a case-in node. We will
- // continue to parse the in nodes until we hit the end of the list.
- while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = true;
-
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- parser->command_start = false;
- parser_lex(parser);
-
- pm_token_t in_keyword = parser->previous;
- pm_node_t *pattern = parse_pattern(parser, true, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
-
- // Since we're in the top-level of the case-in node we need to check
- // for guard clauses in the form of `if` or `unless` statements.
- if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
- pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_IF_PREDICATE);
- pattern = (pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
- } else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
- pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_UNLESS_PREDICATE);
- pattern = (pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
- }
-
- // Now we need to check for the terminator of the in node's pattern.
- // It can be a newline or semicolon optionally followed by a `then`
- // keyword.
- pm_token_t then_keyword;
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- then_keyword = parser->previous;
- } else {
- then_keyword = not_provided(parser);
- }
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
- then_keyword = parser->previous;
- }
-
- // Now we can actually parse the statements associated with the in
- // node.
- pm_statements_node_t *statements;
- if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- statements = NULL;
- } else {
- statements = parse_statements(parser, PM_CONTEXT_CASE_IN);
- }
-
- // Now that we have the full pattern and statements, we can create the
- // node and attach it to the case node.
- pm_node_t *condition = (pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
- pm_case_node_condition_append(case_node, condition);
- }
- }
-
- // If we didn't parse any conditions (in or when) then we need to
- // indicate that we have an error.
- if (case_node->conditions.size == 0) {
- pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
- }
-
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
- pm_token_t else_keyword = parser->previous;
- pm_else_node_t *else_node;
-
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE), &parser->current);
- } else {
- else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
- }
-
- pm_case_node_consequent_set(case_node, else_node);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
- pm_case_node_end_keyword_loc_set(case_node, &parser->previous);
- return (pm_node_t *) case_node;
- }
- case PM_TOKEN_KEYWORD_BEGIN: {
- parser_lex(parser);
-
- pm_token_t begin_keyword = parser->previous;
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- pm_statements_node_t *begin_statements = NULL;
-
- if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN);
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
- parse_rescues(parser, begin_node);
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
- begin_node->base.location.end = parser->previous.end;
- pm_begin_node_end_keyword_set(begin_node, &parser->previous);
-
- if ((begin_node->else_clause != NULL) && (begin_node->rescue_clause == NULL)) {
- pm_parser_err_node(parser, (pm_node_t *) begin_node->else_clause, PM_ERR_BEGIN_LONELY_ELSE);
- }
-
- return (pm_node_t *) begin_node;
- }
- case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
- pm_token_t opening = parser->previous;
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE);
-
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
- pm_context_t context = parser->current_context->context;
- if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
- pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
- }
- return (pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_BREAK:
- case PM_TOKEN_KEYWORD_NEXT:
- case PM_TOKEN_KEYWORD_RETURN: {
- parser_lex(parser);
-
- pm_token_t keyword = parser->previous;
- pm_arguments_t arguments = { 0 };
-
- if (
- token_begins_expression_p(parser->current.type) ||
- match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
- ) {
- pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
-
- if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
- parse_arguments(parser, &arguments, false, PM_TOKEN_EOF);
- }
- }
-
- switch (keyword.type) {
- case PM_TOKEN_KEYWORD_BREAK:
- return (pm_node_t *) pm_break_node_create(parser, &keyword, arguments.arguments);
- case PM_TOKEN_KEYWORD_NEXT:
- return (pm_node_t *) pm_next_node_create(parser, &keyword, arguments.arguments);
- case PM_TOKEN_KEYWORD_RETURN: {
- if (
- (parser->current_context->context == PM_CONTEXT_CLASS) ||
- (parser->current_context->context == PM_CONTEXT_MODULE)
- ) {
- pm_parser_err_current(parser, PM_ERR_RETURN_INVALID);
- }
- return (pm_node_t *) pm_return_node_create(parser, &keyword, arguments.arguments);
- }
- default:
- assert(false && "unreachable");
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- }
- }
- case PM_TOKEN_KEYWORD_SUPER: {
- parser_lex(parser);
-
- pm_token_t keyword = parser->previous;
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
-
- if (
- arguments.opening_loc.start == NULL &&
- arguments.arguments == NULL &&
- ((arguments.block == NULL) || PM_NODE_TYPE_P(arguments.block, PM_BLOCK_NODE))
- ) {
- return (pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
- }
-
- return (pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
- }
- case PM_TOKEN_KEYWORD_YIELD: {
- parser_lex(parser);
-
- pm_token_t keyword = parser->previous;
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, false);
-
- return (pm_node_t *) pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc);
- }
- case PM_TOKEN_KEYWORD_CLASS: {
- parser_lex(parser);
- pm_token_t class_keyword = parser->previous;
- pm_do_loop_stack_push(parser, false);
-
- if (accept1(parser, PM_TOKEN_LESS_LESS)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_expression(parser, PM_BINDING_POWER_NOT, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS);
-
- pm_parser_scope_push(parser, true);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_node_t *statements = NULL;
- if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_SCLASS);
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
-
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
- pm_do_loop_stack_pop(parser);
- return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous);
- }
-
- pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_CLASS_NAME);
- pm_token_t name = parser->previous;
- if (name.type != PM_TOKEN_CONSTANT) {
- pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
- }
-
- pm_token_t inheritance_operator;
- pm_node_t *superclass;
-
- if (match1(parser, PM_TOKEN_LESS)) {
- inheritance_operator = parser->current;
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- parser->command_start = true;
- parser_lex(parser);
-
- superclass = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CLASS_SUPERCLASS);
- } else {
- inheritance_operator = not_provided(parser);
- superclass = NULL;
- }
-
- pm_parser_scope_push(parser, true);
- if (inheritance_operator.type != PM_TOKEN_NOT_PROVIDED) {
- expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
- } else {
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
- pm_node_t *statements = NULL;
-
- if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_CLASS);
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
-
- if (context_def_p(parser)) {
- pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
- }
-
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
- pm_do_loop_stack_pop(parser);
-
- if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
- pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
- }
-
- return (pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_DEF: {
- pm_token_t def_keyword = parser->current;
-
- pm_node_t *receiver = NULL;
- pm_token_t operator = not_provided(parser);
- pm_token_t name = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = def_keyword.end, .end = def_keyword.end };
-
- context_push(parser, PM_CONTEXT_DEF_PARAMS);
- parser_lex(parser);
-
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- pm_parser_scope_push(parser, true);
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- parser_lex(parser);
- name = parser->previous;
- break;
- case PM_TOKEN_IDENTIFIER: {
- parser_lex(parser);
-
- if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
- receiver = parse_variable_call(parser);
-
- pm_parser_scope_push(parser, true);
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- parser_lex(parser);
-
- operator = parser->previous;
- name = parse_method_definition_name(parser);
- } else {
- pm_parser_scope_push(parser, true);
- name = parser->previous;
- }
-
- break;
- }
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_INSTANCE_VARIABLE:
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- case PM_TOKEN_KEYWORD_NIL:
- case PM_TOKEN_KEYWORD_SELF:
- case PM_TOKEN_KEYWORD_TRUE:
- case PM_TOKEN_KEYWORD_FALSE:
- case PM_TOKEN_KEYWORD___FILE__:
- case PM_TOKEN_KEYWORD___LINE__:
- case PM_TOKEN_KEYWORD___ENCODING__: {
- pm_parser_scope_push(parser, true);
- parser_lex(parser);
- pm_token_t identifier = parser->previous;
-
- if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- parser_lex(parser);
- operator = parser->previous;
-
- switch (identifier.type) {
- case PM_TOKEN_CONSTANT:
- receiver = (pm_node_t *) pm_constant_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_INSTANCE_VARIABLE:
- receiver = (pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_CLASS_VARIABLE:
- receiver = (pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_GLOBAL_VARIABLE:
- receiver = (pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_NIL:
- receiver = (pm_node_t *) pm_nil_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_SELF:
- receiver = (pm_node_t *) pm_self_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_TRUE:
- receiver = (pm_node_t *) pm_true_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_FALSE:
- receiver = (pm_node_t *)pm_false_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___FILE__:
- receiver = (pm_node_t *) pm_source_file_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___LINE__:
- receiver = (pm_node_t *) pm_source_line_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___ENCODING__:
- receiver = (pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
- break;
- default:
- break;
- }
-
- name = parse_method_definition_name(parser);
- } else {
- name = identifier;
- }
- break;
- }
- case PM_TOKEN_PARENTHESIS_LEFT: {
- parser_lex(parser);
- pm_token_t lparen = parser->previous;
- pm_node_t *expression = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_DEF_RECEIVER);
-
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
- pm_token_t rparen = parser->previous;
-
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
-
- operator = parser->previous;
- receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
-
- pm_parser_scope_push(parser, true);
- name = parse_method_definition_name(parser);
- break;
- }
- default:
- pm_parser_scope_push(parser, true);
- name = parse_method_definition_name(parser);
- break;
- }
-
- // If, after all that, we were unable to find a method name, add an
- // error to the error list.
- if (name.type == PM_TOKEN_MISSING) {
- pm_parser_err_previous(parser, PM_ERR_DEF_NAME);
- }
-
- pm_token_t lparen;
- pm_token_t rparen;
- pm_parameters_node_t *params;
-
- switch (parser->current.type) {
- case PM_TOKEN_PARENTHESIS_LEFT: {
- parser_lex(parser);
- lparen = parser->previous;
-
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- params = NULL;
- } else {
- params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, true, false, true);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
-
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_DEF_PARAMS_TERM_PAREN);
- rparen = parser->previous;
- break;
- }
- case PM_CASE_PARAMETER: {
- // If we're about to lex a label, we need to add the label
- // state to make sure the next newline is ignored.
- if (parser->current.type == PM_TOKEN_LABEL) {
- lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
- }
-
- lparen = not_provided(parser);
- rparen = not_provided(parser);
- params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, false, false, true);
- break;
- }
- default: {
- lparen = not_provided(parser);
- rparen = not_provided(parser);
- params = NULL;
- break;
- }
- }
-
- context_pop(parser);
- pm_node_t *statements = NULL;
- pm_token_t equal;
- pm_token_t end_keyword;
-
- if (accept1(parser, PM_TOKEN_EQUAL)) {
- if (token_is_setter_name(&name)) {
- pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
- }
- equal = parser->previous;
-
- context_push(parser, PM_CONTEXT_DEF);
- pm_do_loop_stack_push(parser, false);
- statements = (pm_node_t *) pm_statements_node_create(parser);
-
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, PM_ERR_DEF_ENDLESS);
-
- if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
- pm_token_t rescue_keyword = parser->previous;
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE);
- pm_rescue_modifier_node_t *rescue_node = pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
- statement = (pm_node_t *)rescue_node;
- }
-
- pm_statements_node_body_append((pm_statements_node_t *) statements, statement);
- pm_do_loop_stack_pop(parser);
- context_pop(parser);
- end_keyword = not_provided(parser);
- } else {
- equal = not_provided(parser);
-
- if (lparen.type == PM_TOKEN_NOT_PROVIDED) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
- } else {
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_accepts_block_stack_push(parser, true);
- pm_do_loop_stack_push(parser, false);
-
- if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_DEF);
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
- }
-
- pm_accepts_block_stack_pop(parser);
- pm_do_loop_stack_pop(parser);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
- end_keyword = parser->previous;
- }
-
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
-
- return (pm_node_t *) pm_def_node_create(
- parser,
- &name,
- receiver,
- params,
- statements,
- &locals,
- &def_keyword,
- &operator,
- &lparen,
- &rparen,
- &equal,
- &end_keyword
- );
- }
- case PM_TOKEN_KEYWORD_DEFINED: {
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- pm_token_t lparen;
- pm_token_t rparen;
- pm_node_t *expression;
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- lparen = parser->previous;
- expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_DEFINED_EXPRESSION);
-
- if (parser->recovering) {
- rparen = not_provided(parser);
- } else {
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
- rparen = parser->previous;
- }
- } else {
- lparen = not_provided(parser);
- rparen = not_provided(parser);
- expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_DEFINED_EXPRESSION);
- }
-
- return (pm_node_t *) pm_defined_node_create(
- parser,
- &lparen,
- expression,
- &rparen,
- &PM_LOCATION_TOKEN_VALUE(&keyword)
- );
- }
- case PM_TOKEN_KEYWORD_END_UPCASE: {
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
- pm_token_t opening = parser->previous;
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE);
-
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
- return (pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_FALSE:
- parser_lex(parser);
- return (pm_node_t *)pm_false_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_FOR: {
- parser_lex(parser);
- pm_token_t for_keyword = parser->previous;
- pm_node_t *index;
-
- pm_parser_scope_push_transparent(parser);
- context_push(parser, PM_CONTEXT_FOR_INDEX);
-
- // First, parse out the first index expression.
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t star_operator = parser->previous;
- pm_node_t *name = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
- }
-
- index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
- } else if (token_begins_expression_p(parser->current.type)) {
- index = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA);
- } else {
- pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
- index = (pm_node_t *) pm_missing_node_create(parser, for_keyword.start, for_keyword.end);
- }
-
- // Now, if there are multiple index expressions, parse them out.
- if (match1(parser, PM_TOKEN_COMMA)) {
- index = parse_targets(parser, index, PM_BINDING_POWER_INDEX);
- } else {
- index = parse_target(parser, index);
- }
-
- context_pop(parser);
- pm_parser_scope_pop(parser);
- pm_do_loop_stack_push(parser, true);
-
- expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
- pm_token_t in_keyword = parser->previous;
-
- pm_node_t *collection = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_FOR_COLLECTION);
- pm_do_loop_stack_pop(parser);
-
- pm_token_t do_keyword;
- if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
- do_keyword = parser->previous;
- } else {
- do_keyword = not_provided(parser);
- }
-
- accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
- pm_statements_node_t *statements = NULL;
-
- if (!accept1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_parser_scope_push_transparent(parser);
- statements = parse_statements(parser, PM_CONTEXT_FOR);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
- pm_parser_scope_pop(parser);
- }
-
- return (pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_IF:
- parser_lex(parser);
- return parse_conditional(parser, PM_CONTEXT_IF);
- case PM_TOKEN_KEYWORD_UNDEF: {
- parser_lex(parser);
- pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
- pm_node_t *name = parse_undef_argument(parser);
-
- if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
- pm_node_destroy(parser, name);
- } else {
- pm_undef_node_append(undef, name);
-
- while (match1(parser, PM_TOKEN_COMMA)) {
- lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
- parser_lex(parser);
- name = parse_undef_argument(parser);
-
- if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
- pm_node_destroy(parser, name);
- break;
- }
-
- pm_undef_node_append(undef, name);
- }
- }
-
- return (pm_node_t *) undef;
- }
- case PM_TOKEN_KEYWORD_NOT: {
- parser_lex(parser);
-
- pm_token_t message = parser->previous;
- pm_arguments_t arguments = { 0 };
- pm_node_t *receiver = NULL;
-
- accept1(parser, PM_TOKEN_NEWLINE);
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- } else {
- receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_NOT_EXPRESSION);
- pm_conditional_predicate(receiver);
-
- if (!parser->recovering) {
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
- arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- }
- }
- } else {
- receiver = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_NOT_EXPRESSION);
- pm_conditional_predicate(receiver);
- }
-
- return (pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
- }
- case PM_TOKEN_KEYWORD_UNLESS:
- parser_lex(parser);
- return parse_conditional(parser, PM_CONTEXT_UNLESS);
- case PM_TOKEN_KEYWORD_MODULE: {
- parser_lex(parser);
-
- pm_token_t module_keyword = parser->previous;
- pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_MODULE_NAME);
- pm_token_t name;
-
- // If we can recover from a syntax error that occurred while parsing
- // the name of the module, then we'll handle that here.
- if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
- pm_token_t missing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- return (pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
- }
-
- while (accept1(parser, PM_TOKEN_COLON_COLON)) {
- pm_token_t double_colon = parser->previous;
-
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *constant = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
-
- constant_path = (pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, constant);
- }
-
- // Here we retrieve the name of the module. If it wasn't a constant,
- // then it's possible that `module foo` was passed, which is a
- // syntax error. We handle that here as well.
- name = parser->previous;
- if (name.type != PM_TOKEN_CONSTANT) {
- pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
- }
-
- pm_parser_scope_push(parser, true);
- accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
- pm_node_t *statements = NULL;
-
- if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_MODULE);
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
- }
-
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
-
- if (context_def_p(parser)) {
- pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
- }
-
- return (pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_NIL:
- parser_lex(parser);
- return (pm_node_t *) pm_nil_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_REDO:
- parser_lex(parser);
- return (pm_node_t *) pm_redo_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_RETRY:
- parser_lex(parser);
- return (pm_node_t *) pm_retry_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_SELF:
- parser_lex(parser);
- return (pm_node_t *) pm_self_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_TRUE:
- parser_lex(parser);
- return (pm_node_t *) pm_true_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_UNTIL: {
- pm_do_loop_stack_push(parser, true);
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- pm_node_t *predicate = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
- pm_do_loop_stack_pop(parser);
-
- expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
- pm_statements_node_t *statements = NULL;
-
- if (!accept1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, PM_CONTEXT_UNTIL);
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
- }
-
- return (pm_node_t *) pm_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
- }
- case PM_TOKEN_KEYWORD_WHILE: {
- pm_do_loop_stack_push(parser, true);
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- pm_node_t *predicate = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
- pm_do_loop_stack_pop(parser);
-
- expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
- pm_statements_node_t *statements = NULL;
-
- if (!accept1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, PM_CONTEXT_WHILE);
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
- }
-
- return (pm_node_t *) pm_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
- }
- case PM_TOKEN_PERCENT_LOWER_I: {
- parser_lex(parser);
- pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- accept1(parser, PM_TOKEN_WORDS_SEP);
- if (match1(parser, PM_TOKEN_STRING_END)) break;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_array_node_elements_append(array, (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->current, &closing));
- }
-
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
- }
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
- pm_array_node_close_set(array, &parser->previous);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_UPPER_I: {
- parser_lex(parser);
- pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
-
- // This is the current node that we are parsing that will be added to the
- // list of elements.
- pm_node_t *current = NULL;
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- switch (parser->current.type) {
- case PM_TOKEN_WORDS_SEP: {
- if (current == NULL) {
- // If we hit a separator before we have any content, then we don't
- // need to do anything.
- } else {
- // If we hit a separator after we've hit content, then we need to
- // append that content to the list and reset the current node.
- pm_array_node_elements_append(array, current);
- current = NULL;
- }
-
- parser_lex(parser);
- break;
- }
- case PM_TOKEN_STRING_CONTENT: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- if (current == NULL) {
- // If we hit content and the current node is NULL, then this is
- // the first string content we've seen. In that case we're going
- // to create a new string node and set that to the current.
- current = (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->current, &closing);
- parser_lex(parser);
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
- // If we hit string content and the current node is an
- // interpolated string, then we need to append the string content
- // to the list of child nodes.
- pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
- parser_lex(parser);
-
- pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, string);
- } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
- // If we hit string content and the current node is a string node,
- // then we need to convert the current node into an interpolated
- // string and add the string content to the list of child nodes.
- pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->previous, &closing);
- parser_lex(parser);
-
- pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_symbol_node_append(interpolated, current);
- pm_interpolated_symbol_node_append(interpolated, string);
- current = (pm_node_t *) interpolated;
- } else {
- assert(false && "unreachable");
- }
-
- break;
- }
- case PM_TOKEN_EMBVAR: {
- bool start_location_set = false;
- if (current == NULL) {
- // If we hit an embedded variable and the current node is NULL,
- // then this is the start of a new string. We'll set the current
- // node to a new interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
- // If we hit an embedded variable and the current node is a string
- // node, then we'll convert the current into an interpolated
- // string and add the string node to the list of parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
-
- current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current);
- pm_interpolated_symbol_node_append(interpolated, current);
- interpolated->base.location.start = current->location.start;
- start_location_set = true;
- current = (pm_node_t *) interpolated;
- } else {
- // If we hit an embedded variable and the current node is an
- // interpolated string, then we'll just add the embedded variable.
- }
-
- pm_node_t *part = parse_string_part(parser);
- pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
- if (!start_location_set) {
- current->location.start = part->location.start;
- }
- break;
- }
- case PM_TOKEN_EMBEXPR_BEGIN: {
- bool start_location_set = false;
- if (current == NULL) {
- // If we hit an embedded expression and the current node is NULL,
- // then this is the start of a new string. We'll set the current
- // node to a new interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
- // If we hit an embedded expression and the current node is a
- // string node, then we'll convert the current into an
- // interpolated string and add the string node to the list of
- // parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
-
- current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current);
- pm_interpolated_symbol_node_append(interpolated, current);
- interpolated->base.location.start = current->location.start;
- start_location_set = true;
- current = (pm_node_t *) interpolated;
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
- // If we hit an embedded expression and the current node is an
- // interpolated string, then we'll just continue on.
- } else {
- assert(false && "unreachable");
- }
-
- pm_node_t *part = parse_string_part(parser);
- pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
- if (!start_location_set) {
- current->location.start = part->location.start;
- }
- break;
- }
- default:
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
- parser_lex(parser);
- break;
- }
- }
-
- // If we have a current node, then we need to append it to the list.
- if (current) {
- pm_array_node_elements_append(array, current);
- }
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
- pm_array_node_close_set(array, &parser->previous);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_LOWER_W: {
- parser_lex(parser);
- pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
-
- // skip all leading whitespaces
- accept1(parser, PM_TOKEN_WORDS_SEP);
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- accept1(parser, PM_TOKEN_WORDS_SEP);
- if (match1(parser, PM_TOKEN_STRING_END)) break;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
- pm_array_node_elements_append(array, string);
- }
-
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
- }
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
- pm_array_node_close_set(array, &parser->previous);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_UPPER_W: {
- parser_lex(parser);
- pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
-
- // This is the current node that we are parsing that will be added to the
- // list of elements.
- pm_node_t *current = NULL;
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- switch (parser->current.type) {
- case PM_TOKEN_WORDS_SEP: {
- if (current == NULL) {
- // If we hit a separator before we have any content, then we don't
- // need to do anything.
- } else {
- // If we hit a separator after we've hit content, then we need to
- // append that content to the list and reset the current node.
- pm_array_node_elements_append(array, current);
- current = NULL;
- }
-
- parser_lex(parser);
- break;
- }
- case PM_TOKEN_STRING_CONTENT: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
- parser_lex(parser);
-
- if (current == NULL) {
- // If we hit content and the current node is NULL, then this is
- // the first string content we've seen. In that case we're going
- // to create a new string node and set that to the current.
- current = string;
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
- // If we hit string content and the current node is an
- // interpolated string, then we need to append the string content
- // to the list of child nodes.
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, string);
- } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
- // If we hit string content and the current node is a string node,
- // then we need to convert the current node into an interpolated
- // string and add the string content to the list of child nodes.
- pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_string_node_append(interpolated, current);
- pm_interpolated_string_node_append(interpolated, string);
- current = (pm_node_t *) interpolated;
- } else {
- assert(false && "unreachable");
- }
-
- break;
- }
- case PM_TOKEN_EMBVAR: {
- if (current == NULL) {
- // If we hit an embedded variable and the current node is NULL,
- // then this is the start of a new string. We'll set the current
- // node to a new interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
- // If we hit an embedded variable and the current node is a string
- // node, then we'll convert the current into an interpolated
- // string and add the string node to the list of parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_string_node_append(interpolated, current);
- current = (pm_node_t *) interpolated;
- } else {
- // If we hit an embedded variable and the current node is an
- // interpolated string, then we'll just add the embedded variable.
- }
-
- pm_node_t *part = parse_string_part(parser);
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
- break;
- }
- case PM_TOKEN_EMBEXPR_BEGIN: {
- if (current == NULL) {
- // If we hit an embedded expression and the current node is NULL,
- // then this is the start of a new string. We'll set the current
- // node to a new interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
- // If we hit an embedded expression and the current node is a
- // string node, then we'll convert the current into an
- // interpolated string and add the string node to the list of
- // parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_string_node_append(interpolated, current);
- current = (pm_node_t *) interpolated;
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
- // If we hit an embedded expression and the current node is an
- // interpolated string, then we'll just continue on.
- } else {
- assert(false && "unreachable");
- }
-
- pm_node_t *part = parse_string_part(parser);
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
- break;
- }
- default:
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
- parser_lex(parser);
- break;
- }
- }
-
- // If we have a current node, then we need to append it to the list.
- if (current) {
- pm_array_node_elements_append(array, current);
- }
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
- pm_array_node_close_set(array, &parser->previous);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_REGEXP_BEGIN: {
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (match1(parser, PM_TOKEN_REGEXP_END)) {
- // If we get here, then we have an end immediately after a start. In
- // that case we'll create an empty content token and return an
- // uninterpolated regular expression.
- pm_token_t content = (pm_token_t) {
- .type = PM_TOKEN_STRING_CONTENT,
- .start = parser->previous.end,
- .end = parser->previous.end
- };
-
- parser_lex(parser);
- return (pm_node_t *) pm_regular_expression_node_create(parser, &opening, &content, &parser->previous);
- }
-
- pm_interpolated_regular_expression_node_t *node;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- // In this case we've hit string content so we know the regular
- // expression at least has something in it. We'll need to check if the
- // following token is the end (in which case we can return a plain
- // regular expression) or if it's not then it has interpolation.
- pm_string_t unescaped = parser->current_string;
- pm_token_t content = parser->current;
- parser_lex(parser);
-
- // If we hit an end, then we can create a regular expression node
- // without interpolation, which can be represented more succinctly and
- // more easily compiled.
- if (accept1(parser, PM_TOKEN_REGEXP_END)) {
- return (pm_node_t *) pm_regular_expression_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- }
-
- // If we get here, then we have interpolation so we'll need to create
- // a regular expression node with interpolation.
- node = pm_interpolated_regular_expression_node_create(parser, &opening);
-
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->previous, &closing, &unescaped);
- pm_interpolated_regular_expression_node_append(node, part);
- } else {
- // If the first part of the body of the regular expression is not a
- // string content, then we have interpolation and we need to create an
- // interpolated regular expression node.
- node = pm_interpolated_regular_expression_node_create(parser, &opening);
- }
-
- // Now that we're here and we have interpolation, we'll parse all of the
- // parts into the list.
- pm_node_t *part;
- while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser)) != NULL) {
- pm_interpolated_regular_expression_node_append(node, part);
- }
- }
-
- expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
- pm_interpolated_regular_expression_node_closing_set(node, &parser->previous);
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_BACKTICK:
- case PM_TOKEN_PERCENT_LOWER_X: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
-
- // When we get here, we don't know if this string is going to have
- // interpolation or not, even though it is allowed. Still, we want to be
- // able to return a string node without interpolation if we can since
- // it'll be faster.
- if (match1(parser, PM_TOKEN_STRING_END)) {
- // If we get here, then we have an end immediately after a start. In
- // that case we'll create an empty content token and return an
- // uninterpolated string.
- pm_token_t content = (pm_token_t) {
- .type = PM_TOKEN_STRING_CONTENT,
- .start = parser->previous.end,
- .end = parser->previous.end
- };
-
- parser_lex(parser);
- return (pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->previous);
- }
-
- pm_interpolated_x_string_node_t *node;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- // In this case we've hit string content so we know the string
- // at least has something in it. We'll need to check if the
- // following token is the end (in which case we can return a
- // plain string) or if it's not then it has interpolation.
- pm_string_t unescaped = parser->current_string;
- pm_token_t content = parser->current;
- parser_lex(parser);
-
- if (accept1(parser, PM_TOKEN_STRING_END)) {
- return (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- }
-
- // If we get here, then we have interpolation so we'll need to
- // create a string node with interpolation.
- node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
-
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->previous, &closing, &unescaped);
-
- pm_interpolated_xstring_node_append(node, part);
- } else {
- // If the first part of the body of the string is not a string
- // content, then we have interpolation and we need to create an
- // interpolated string node.
- node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
- }
-
- pm_node_t *part;
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser)) != NULL) {
- pm_interpolated_xstring_node_append(node, part);
- }
- }
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
- pm_interpolated_xstring_node_closing_set(node, &parser->previous);
- return (pm_node_t *) node;
- }
- case PM_TOKEN_USTAR: {
- parser_lex(parser);
-
- // * operators at the beginning of expressions are only valid in the
- // context of a multiple assignment. We enforce that here. We'll
- // still lex past it though and create a missing node place.
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- }
-
- pm_token_t operator = parser->previous;
- pm_node_t *name = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
- }
-
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &operator, name);
-
- if (match1(parser, PM_TOKEN_COMMA)) {
- return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX);
- } else {
- return parse_target_validate(parser, splat);
- }
- }
- case PM_TOKEN_BANG: {
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_BANG);
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!");
-
- pm_conditional_predicate(receiver);
- return (pm_node_t *) node;
- }
- case PM_TOKEN_TILDE: {
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_TILDE);
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~");
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_UMINUS: {
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS);
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@");
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_UMINUS_NUM: {
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS);
-
- if (accept1(parser, PM_TOKEN_STAR_STAR)) {
- pm_token_t exponent_operator = parser->previous;
- pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, PM_ERR_EXPECT_ARGUMENT);
- node = (pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent);
- node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
- } else {
- switch (PM_NODE_TYPE(node)) {
- case PM_INTEGER_NODE:
- case PM_FLOAT_NODE:
- case PM_RATIONAL_NODE:
- case PM_IMAGINARY_NODE:
- parse_negative_numeric(node);
- break;
- default:
- node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
- break;
- }
- }
-
- return node;
- }
- case PM_TOKEN_MINUS_GREATER: {
- int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
- parser->lambda_enclosure_nesting = parser->enclosure_nesting;
-
- pm_accepts_block_stack_push(parser, true);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_parser_scope_push(parser, false);
- pm_block_parameters_node_t *params;
-
- switch (parser->current.type) {
- case PM_TOKEN_PARENTHESIS_LEFT: {
- parser->current_scope->explicit_params = true;
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- params = pm_block_parameters_node_create(parser, NULL, &opening);
- } else {
- params = parse_block_parameters(parser, false, &opening, true);
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
-
- pm_block_parameters_node_closing_set(params, &parser->previous);
- break;
- }
- case PM_CASE_PARAMETER: {
- parser->current_scope->explicit_params = true;
- pm_accepts_block_stack_push(parser, false);
- pm_token_t opening = not_provided(parser);
- params = parse_block_parameters(parser, false, &opening, true);
- pm_accepts_block_stack_pop(parser);
- break;
- }
- default: {
- params = NULL;
- break;
- }
- }
-
- pm_token_t opening;
- pm_node_t *body = NULL;
- parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
-
- if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
- opening = parser->previous;
-
- if (!accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
- body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
- }
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
- opening = parser->previous;
-
- if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- pm_accepts_block_stack_push(parser, true);
- body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END);
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
- body = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) body);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
- }
-
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
- pm_accepts_block_stack_pop(parser);
- return (pm_node_t *) pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, params, body);
- }
- case PM_TOKEN_UPLUS: {
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_PLUS);
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@");
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_STRING_BEGIN:
- return parse_strings(parser);
- case PM_TOKEN_SYMBOL_BEGIN: {
- pm_lex_mode_t lex_mode = *parser->lex_modes.current;
- parser_lex(parser);
-
- return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END);
- }
- default:
- if (context_recoverable(parser, &parser->current)) {
- parser->recovering = true;
- }
-
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- }
-}
-
-static inline pm_node_t *
-parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) {
- pm_node_t *value = parse_starred_expression(parser, binding_power, diag_id);
-
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
- pm_token_t opening = not_provided(parser);
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- pm_array_node_elements_append(array, value);
- value = (pm_node_t *) array;
-
- while (accept1(parser, PM_TOKEN_COMMA)) {
- pm_node_t *element = parse_starred_expression(parser, binding_power, PM_ERR_ARRAY_ELEMENT);
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
- }
- }
-
- return value;
-}
-
-/**
- * Ensures a call node that is about to become a call operator node does not
- * have arguments or a block attached. If it does, then we'll need to add an
- * error message and destroy the arguments/block. Ideally we would keep the node
- * around so that consumers would still have access to it, but we don't have a
- * great structure for that at the moment.
- */
-static void
-parse_call_operator_write(pm_parser_t *parser, pm_call_node_t *call_node, const pm_token_t *operator) {
- if (call_node->arguments != NULL) {
- pm_parser_err_token(parser, operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
- pm_node_destroy(parser, (pm_node_t *) call_node->arguments);
- call_node->arguments = NULL;
- }
-
- if (call_node->block != NULL) {
- pm_parser_err_token(parser, operator, PM_ERR_OPERATOR_WRITE_BLOCK);
- pm_node_destroy(parser, (pm_node_t *) call_node->block);
- call_node->block = NULL;
- }
-}
-
-/**
- * Potentially change a =~ with a regular expression with named captures into a
- * match write node.
- */
-static pm_node_t *
-parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *content, pm_call_node_t *call) {
- pm_string_list_t named_captures = { 0 };
- pm_node_t *result;
-
- if (pm_regexp_named_capture_group_names(pm_string_source(content), pm_string_length(content), &named_captures, parser->encoding_changed, &parser->encoding) && (named_captures.length > 0)) {
- pm_match_write_node_t *match = pm_match_write_node_create(parser, call);
-
- for (size_t index = 0; index < named_captures.length; index++) {
- pm_string_t *name = &named_captures.strings[index];
-
- const uint8_t *source = pm_string_source(name);
- size_t length = pm_string_length(name);
-
- pm_constant_id_t local;
- if (content->type == PM_STRING_SHARED) {
- // If the unescaped string is a slice of the source, then we can
- // copy the names directly. The pointers will line up.
- local = pm_parser_local_add_location(parser, source, source + length);
-
- if (token_is_numbered_parameter(source, source + length)) {
- pm_parser_err(parser, source, source + length, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
- } else {
- // Otherwise, the name is a slice of the malloc-ed owned string,
- // in which case we need to copy it out into a new string.
- void *memory = malloc(length);
- if (memory == NULL) abort();
-
- memcpy(memory, source, length);
- local = pm_parser_local_add_owned(parser, (const uint8_t *) memory, length);
-
- if (token_is_numbered_parameter(source, source + length)) {
- const pm_location_t *location = &call->receiver->location;
- pm_parser_err_location(parser, location, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
- }
-
- pm_constant_id_list_append(&match->locals, local);
- }
-
- result = (pm_node_t *) match;
- } else {
- result = (pm_node_t *) call;
- }
-
- pm_string_list_free(&named_captures);
- return result;
-}
-
-static inline pm_node_t *
-parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power) {
- pm_token_t token = parser->current;
-
- switch (token.type) {
- case PM_TOKEN_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_CALL_NODE: {
- // If we have no arguments to the call node and we need this
- // to be a target then this is either a method call or a
- // local variable write. This _must_ happen before the value
- // is parsed because it could be referenced in the value.
- pm_call_node_t *call_node = (pm_call_node_t *) node;
- if (pm_call_node_variable_call_p(call_node)) {
- pm_parser_local_add_location(parser, call_node->message_loc.start, call_node->message_loc.end);
- }
- }
- /* fallthrough */
- case PM_CASE_WRITABLE: {
- parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
- return parse_write(parser, node, &token, value);
- }
- case PM_SPLAT_NODE: {
- pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, multi_target, node);
-
- parser_lex(parser);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
- return parse_write(parser, (pm_node_t *) multi_target, &token, value);
- }
- default:
- parser_lex(parser);
-
- // In this case we have an = sign, but we don't know what it's for. We
- // need to treat it as an error. For now, we'll mark it as an error
- // and just skip right past it.
- pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL);
- return node;
- }
- }
- case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- pm_node_t *result = (pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- pm_node_t *result = (pm_node_t *) pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CONSTANT_PATH_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- return (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
- }
- case PM_CONSTANT_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- pm_node_t *result = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- pm_node_t *result = (pm_node_t *) pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CALL_NODE: {
- parser_lex(parser);
- pm_call_node_t *cast = (pm_call_node_t *) node;
-
- // If we have a vcall (a method with no arguments and no
- // receiver that could have been a local variable) then we
- // will transform it into a local variable write.
- if (pm_call_node_variable_call_p(cast)) {
- pm_location_t message_loc = cast->message_loc;
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc.start, message_loc.end);
-
- if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
- pm_parser_err_location(parser, &message_loc, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
-
- pm_node_destroy(parser, (pm_node_t *) cast);
- return result;
- }
-
- // If there is no call operator and the message is "[]" then
- // this is an aref expression, and we can transform it into
- // an aset expression.
- if (pm_call_node_index_p(cast)) {
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
- }
-
- // If this node cannot be writable, then we have an error.
- if (pm_call_node_writable_p(cast)) {
- parse_write_name(parser, &cast->name);
- } else {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
- }
- case PM_MULTI_WRITE_NODE: {
- parser_lex(parser);
- pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
- return node;
- }
- default:
- parser_lex(parser);
-
- // In this case we have an &&= sign, but we don't know what it's for.
- // We need to treat it as an error. For now, we'll mark it as an error
- // and just skip right past it.
- pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- return node;
- }
- }
- case PM_TOKEN_PIPE_PIPE_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- pm_node_t *result = (pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- pm_node_t *result = (pm_node_t *) pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CONSTANT_PATH_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- return (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
- }
- case PM_CONSTANT_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- pm_node_t *result = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- pm_node_t *result = (pm_node_t *) pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CALL_NODE: {
- parser_lex(parser);
- pm_call_node_t *cast = (pm_call_node_t *) node;
-
- // If we have a vcall (a method with no arguments and no
- // receiver that could have been a local variable) then we
- // will transform it into a local variable write.
- if (pm_call_node_variable_call_p(cast)) {
- pm_location_t message_loc = cast->message_loc;
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc.start, message_loc.end);
-
- if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
- pm_parser_err_location(parser, &message_loc, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
-
- pm_node_destroy(parser, (pm_node_t *) cast);
- return result;
- }
-
- // If there is no call operator and the message is "[]" then
- // this is an aref expression, and we can transform it into
- // an aset expression.
- if (pm_call_node_index_p(cast)) {
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
- }
-
- // If this node cannot be writable, then we have an error.
- if (pm_call_node_writable_p(cast)) {
- parse_write_name(parser, &cast->name);
- } else {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
- }
- case PM_MULTI_WRITE_NODE: {
- parser_lex(parser);
- pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
- return node;
- }
- default:
- parser_lex(parser);
-
- // In this case we have an ||= sign, but we don't know what it's for.
- // We need to treat it as an error. For now, we'll mark it as an error
- // and just skip right past it.
- pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- return node;
- }
- }
- case PM_TOKEN_AMPERSAND_EQUAL:
- case PM_TOKEN_CARET_EQUAL:
- case PM_TOKEN_GREATER_GREATER_EQUAL:
- case PM_TOKEN_LESS_LESS_EQUAL:
- case PM_TOKEN_MINUS_EQUAL:
- case PM_TOKEN_PERCENT_EQUAL:
- case PM_TOKEN_PIPE_EQUAL:
- case PM_TOKEN_PLUS_EQUAL:
- case PM_TOKEN_SLASH_EQUAL:
- case PM_TOKEN_STAR_EQUAL:
- case PM_TOKEN_STAR_STAR_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- pm_node_t *result = (pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- pm_node_t *result = (pm_node_t *) pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CONSTANT_PATH_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
- }
- case PM_CONSTANT_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- pm_node_t *result = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- pm_node_t *result = (pm_node_t *) pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
- parser_lex(parser);
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CALL_NODE: {
- parser_lex(parser);
- pm_call_node_t *cast = (pm_call_node_t *) node;
-
- // If we have a vcall (a method with no arguments and no
- // receiver that could have been a local variable) then we
- // will transform it into a local variable write.
- if (pm_call_node_variable_call_p(cast)) {
- pm_location_t message_loc = cast->message_loc;
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc.start, message_loc.end);
-
- if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
- pm_parser_err_location(parser, &message_loc, PM_ERR_PARAMETER_NUMBERED_RESERVED);
- }
-
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
-
- pm_node_destroy(parser, (pm_node_t *) cast);
- return result;
- }
-
- // If there is no call operator and the message is "[]" then
- // this is an aref expression, and we can transform it into
- // an aset expression.
- if (pm_call_node_index_p(cast)) {
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
- }
-
- // If this node cannot be writable, then we have an error.
- if (pm_call_node_writable_p(cast)) {
- parse_write_name(parser, &cast->name);
- } else {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
- }
- case PM_MULTI_WRITE_NODE: {
- parser_lex(parser);
- pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
- return node;
- }
- default:
- parser_lex(parser);
-
- // In this case we have an operator but we don't know what it's for.
- // We need to treat it as an error. For now, we'll mark it as an error
- // and just skip right past it.
- pm_parser_err_previous(parser, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return node;
- }
- }
- case PM_TOKEN_AMPERSAND_AMPERSAND:
- case PM_TOKEN_KEYWORD_AND: {
- parser_lex(parser);
-
- pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return (pm_node_t *) pm_and_node_create(parser, node, &token, right);
- }
- case PM_TOKEN_KEYWORD_OR:
- case PM_TOKEN_PIPE_PIPE: {
- parser_lex(parser);
-
- pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return (pm_node_t *) pm_or_node_create(parser, node, &token, right);
- }
- case PM_TOKEN_EQUAL_TILDE: {
- // Note that we _must_ parse the value before adding the local
- // variables in order to properly mirror the behavior of Ruby. For
- // example,
- //
- // /(?<foo>bar)/ =~ foo
- //
- // In this case, `foo` should be a method call and not a local yet.
- parser_lex(parser);
- pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
-
- // By default, we're going to create a call node and then return it.
- pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument);
- pm_node_t *result = (pm_node_t *) call;
-
- // If the receiver of this =~ is a regular expression node, then we
- // need to introduce local variables for it based on its named
- // capture groups.
- if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
- // It's possible to have an interpolated regular expression node
- // that only contains strings. This is because it can be split
- // up by a heredoc. In this case we need to concat the unescaped
- // strings together and then parse them as a regular expression.
- pm_node_list_t *parts = &((pm_interpolated_regular_expression_node_t *) node)->parts;
-
- bool interpolated = false;
- size_t total_length = 0;
-
- for (size_t index = 0; index < parts->size; index++) {
- pm_node_t *part = parts->nodes[index];
-
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- total_length += pm_string_length(&((pm_string_node_t *) part)->unescaped);
- } else {
- interpolated = true;
- break;
- }
- }
-
- if (!interpolated && total_length > 0) {
- void *memory = malloc(total_length);
- if (!memory) abort();
-
- uint8_t *cursor = memory;
- for (size_t index = 0; index < parts->size; index++) {
- pm_string_t *unescaped = &((pm_string_node_t *) parts->nodes[index])->unescaped;
- size_t length = pm_string_length(unescaped);
-
- memcpy(cursor, pm_string_source(unescaped), length);
- cursor += length;
- }
-
- pm_string_t owned;
- pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
-
- result = parse_regular_expression_named_captures(parser, &owned, call);
- pm_string_free(&owned);
- }
- } else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
- // If we have a regular expression node, then we can just parse
- // the named captures directly off the unescaped string.
- const pm_string_t *content = &((pm_regular_expression_node_t *) node)->unescaped;
- result = parse_regular_expression_named_captures(parser, content, call);
- }
-
- return result;
- }
- case PM_TOKEN_UAMPERSAND:
- case PM_TOKEN_USTAR:
- case PM_TOKEN_USTAR_STAR:
- // The only times this will occur are when we are in an error state,
- // but we'll put them in here so that errors can propagate.
- case PM_TOKEN_BANG_EQUAL:
- case PM_TOKEN_BANG_TILDE:
- case PM_TOKEN_EQUAL_EQUAL:
- case PM_TOKEN_EQUAL_EQUAL_EQUAL:
- case PM_TOKEN_LESS_EQUAL_GREATER:
- case PM_TOKEN_GREATER:
- case PM_TOKEN_GREATER_EQUAL:
- case PM_TOKEN_LESS:
- case PM_TOKEN_LESS_EQUAL:
- case PM_TOKEN_CARET:
- case PM_TOKEN_PIPE:
- case PM_TOKEN_AMPERSAND:
- case PM_TOKEN_GREATER_GREATER:
- case PM_TOKEN_LESS_LESS:
- case PM_TOKEN_MINUS:
- case PM_TOKEN_PLUS:
- case PM_TOKEN_PERCENT:
- case PM_TOKEN_SLASH:
- case PM_TOKEN_STAR:
- case PM_TOKEN_STAR_STAR: {
- parser_lex(parser);
-
- pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument);
- }
- case PM_TOKEN_AMPERSAND_DOT:
- case PM_TOKEN_DOT: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
- pm_arguments_t arguments = { 0 };
-
- // This if statement handles the foo.() syntax.
- if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- parse_arguments_list(parser, &arguments, true);
- return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &operator, &arguments);
- }
-
- pm_token_t message;
-
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- case PM_CASE_KEYWORD:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- message = parser->previous;
- break;
- }
- default: {
- pm_parser_err_current(parser, PM_ERR_DEF_NAME);
- message = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- }
- }
-
- parse_arguments_list(parser, &arguments, true);
- pm_call_node_t *call = pm_call_node_call_create(parser, node, &operator, &message, &arguments);
-
- if (
- (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
- arguments.arguments == NULL &&
- arguments.opening_loc.start == NULL &&
- match1(parser, PM_TOKEN_COMMA)
- ) {
- return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX);
- } else {
- return (pm_node_t *) call;
- }
- }
- case PM_TOKEN_DOT_DOT:
- case PM_TOKEN_DOT_DOT_DOT: {
- parser_lex(parser);
-
- pm_node_t *right = NULL;
- if (token_begins_expression_p(parser->current.type)) {
- right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
- }
-
- return (pm_node_t *) pm_range_node_create(parser, node, &token, right);
- }
- case PM_TOKEN_KEYWORD_IF_MODIFIER: {
- pm_token_t keyword = parser->current;
- parser_lex(parser);
-
- pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_IF_PREDICATE);
- return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
- }
- case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
- pm_token_t keyword = parser->current;
- parser_lex(parser);
-
- pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNLESS_PREDICATE);
- return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
- }
- case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
- parser_lex(parser);
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, node);
-
- pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
- return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
- }
- case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
- parser_lex(parser);
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, node);
-
- pm_node_t *predicate = parse_expression(parser, binding_power, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
- return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
- }
- case PM_TOKEN_QUESTION_MARK: {
- parser_lex(parser);
- pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_TRUE);
-
- if (parser->recovering) {
- // If parsing the true expression of this ternary resulted in a syntax
- // error that we can recover from, then we're going to put missing nodes
- // and tokens into the remaining places. We want to be sure to do this
- // before the `expect` function call to make sure it doesn't
- // accidentally move past a ':' token that occurs after the syntax
- // error.
- pm_token_t colon = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- pm_node_t *false_expression = (pm_node_t *) pm_missing_node_create(parser, colon.start, colon.end);
-
- return (pm_node_t *) pm_if_node_ternary_create(parser, node, true_expression, &colon, false_expression);
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
-
- pm_token_t colon = parser->previous;
- pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_FALSE);
-
- return (pm_node_t *) pm_if_node_ternary_create(parser, node, true_expression, &colon, false_expression);
- }
- case PM_TOKEN_COLON_COLON: {
- parser_lex(parser);
- pm_token_t delimiter = parser->previous;
-
- switch (parser->current.type) {
- case PM_TOKEN_CONSTANT: {
- parser_lex(parser);
- pm_node_t *path;
-
- if (
- (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
- (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))
- ) {
- // If we have a constant immediately following a '::' operator, then
- // this can either be a constant path or a method call, depending on
- // what follows the constant.
- //
- // If we have parentheses, then this is a method call. That would
- // look like Foo::Bar().
- pm_token_t message = parser->previous;
- pm_arguments_t arguments = { 0 };
-
- parse_arguments_list(parser, &arguments, true);
- path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
- } else {
- // Otherwise, this is a constant path. That would look like Foo::Bar.
- pm_node_t *child = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
- path = (pm_node_t *)pm_constant_path_node_create(parser, node, &delimiter, child);
- }
-
- // If this is followed by a comma then it is a multiple assignment.
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX);
- }
-
- return path;
- }
- case PM_CASE_OPERATOR:
- case PM_CASE_KEYWORD:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- pm_token_t message = parser->previous;
-
- // If we have an identifier following a '::' operator, then it is for
- // sure a method call.
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
- pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
-
- // If this is followed by a comma then it is a multiple assignment.
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX);
- }
-
- return (pm_node_t *) call;
- }
- case PM_TOKEN_PARENTHESIS_LEFT: {
- // If we have a parenthesis following a '::' operator, then it is the
- // method call shorthand. That would look like Foo::(bar).
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true);
-
- return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
- }
- default: {
- pm_parser_err_token(parser, &delimiter, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *child = (pm_node_t *) pm_missing_node_create(parser, delimiter.start, delimiter.end);
- return (pm_node_t *)pm_constant_path_node_create(parser, node, &delimiter, child);
- }
- }
- }
- case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
- parser_lex(parser);
- accept1(parser, PM_TOKEN_NEWLINE);
- pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE);
-
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
- }
- case PM_TOKEN_BRACKET_LEFT: {
- parser_lex(parser);
-
- pm_arguments_t arguments = { 0 };
- arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- pm_accepts_block_stack_push(parser, true);
- parse_arguments(parser, &arguments, false, PM_TOKEN_BRACKET_RIGHT);
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
- }
-
- arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- // If we have a comma after the closing bracket then this is a multiple
- // assignment and we should parse the targets.
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
- return parse_targets_validate(parser, (pm_node_t *) aref, PM_BINDING_POWER_INDEX);
- }
-
- // If we're at the end of the arguments, we can now check if there is a
- // block node that starts with a {. If there is, then we can parse it and
- // add it to the arguments.
- pm_block_node_t *block = NULL;
- if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
- block = parse_block(parser);
- pm_arguments_validate_block(parser, &arguments, block);
- } else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
- block = parse_block(parser);
- }
-
- if (block != NULL) {
- if (arguments.block != NULL) {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
- if (arguments.arguments == NULL) {
- arguments.arguments = pm_arguments_node_create(parser);
- }
- pm_arguments_node_arguments_append(arguments.arguments, arguments.block);
- }
-
- arguments.block = (pm_node_t *) block;
- }
-
- return (pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
- }
- case PM_TOKEN_KEYWORD_IN: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = true;
-
- pm_token_t operator = parser->current;
- parser->command_start = false;
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
-
- parser_lex(parser);
-
- pm_node_t *pattern = parse_pattern(parser, true, PM_ERR_PATTERN_EXPRESSION_AFTER_IN);
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
-
- return (pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &operator);
- }
- case PM_TOKEN_EQUAL_GREATER: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = true;
-
- pm_token_t operator = parser->current;
- parser->command_start = false;
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
-
- parser_lex(parser);
-
- pm_node_t *pattern = parse_pattern(parser, true, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET);
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
-
- return (pm_node_t *) pm_match_required_node_create(parser, node, pattern, &operator);
- }
- default:
- assert(false && "unreachable");
- return NULL;
- }
-}
-
-/**
- * Parse an expression at the given point of the parser using the given binding
- * power to parse subsequent chains. If this function finds a syntax error, it
- * will append the error message to the parser's error list.
- *
- * Consumers of this function should always check parser->recovering to
- * determine if they need to perform additional cleanup.
- */
-static pm_node_t *
-parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) {
- pm_token_t recovery = parser->previous;
- pm_node_t *node = parse_expression_prefix(parser, binding_power);
-
- // If we found a syntax error, then the type of node returned by
- // parse_expression_prefix is going to be a missing node. In that case we need
- // to add the error message to the parser's error list.
- if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
- pm_parser_err(parser, recovery.end, recovery.end, diag_id);
- return node;
- }
-
- // Otherwise we'll look and see if the next token can be parsed as an infix
- // operator. If it can, then we'll parse it using parse_expression_infix.
- pm_binding_powers_t current_binding_powers;
- while (
- current_binding_powers = pm_binding_powers[parser->current.type],
- binding_power <= current_binding_powers.left &&
- current_binding_powers.binary
- ) {
- node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right);
- }
-
- return node;
-}
-
-static pm_node_t *
-parse_program(pm_parser_t *parser) {
- pm_parser_scope_push(parser, !parser->current_scope);
- parser_lex(parser);
-
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_MAIN);
- if (!statements) {
- statements = pm_statements_node_create(parser);
- }
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
-
- // If this is an empty file, then we're still going to parse all of the
- // statements in order to gather up all of the comments and such. Here we'll
- // correct the location information.
- if (pm_statements_node_body_length(statements) == 0) {
- pm_statements_node_location_set(statements, parser->start, parser->start);
- }
-
- return (pm_node_t *) pm_program_node_create(parser, &locals, statements);
-}
-
-/******************************************************************************/
-/* External functions */
-/******************************************************************************/
-
-/**
- * Initialize a parser with the given start and end pointers.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options) {
- assert(source != NULL);
-
- *parser = (pm_parser_t) {
- .lex_state = PM_LEX_STATE_BEG,
- .enclosure_nesting = 0,
- .lambda_enclosure_nesting = -1,
- .brace_nesting = 0,
- .do_loop_stack = 0,
- .accepts_block_stack = 0,
- .lex_modes = {
- .index = 0,
- .stack = {{ .mode = PM_LEX_DEFAULT }},
- .current = &parser->lex_modes.stack[0],
- },
- .start = source,
- .end = source + size,
- .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
- .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
- .next_start = NULL,
- .heredoc_end = NULL,
- .comment_list = { 0 },
- .magic_comment_list = { 0 },
- .warning_list = { 0 },
- .error_list = { 0 },
- .current_scope = NULL,
- .current_context = NULL,
- .encoding = pm_encoding_utf_8,
- .encoding_changed_callback = NULL,
- .encoding_decode_callback = NULL,
- .encoding_comment_start = source,
- .lex_callback = NULL,
- .filepath_string = { 0 },
- .constant_pool = { 0 },
- .newline_list = { 0 },
- .integer_base = 0,
- .current_string = PM_STRING_EMPTY,
- .start_line = 1,
- .command_start = true,
- .recovering = false,
- .encoding_changed = false,
- .pattern_matching_newlines = false,
- .in_keyword_arg = false,
- .semantic_token_seen = false,
- .frozen_string_literal = false,
- .suppress_warnings = false
- };
-
- // Initialize the constant pool. We're going to completely guess as to the
- // number of constants that we'll need based on the size of the input. The
- // ratio we chose here is actually less arbitrary than you might think.
- //
- // We took ~50K Ruby files and measured the size of the file versus the
- // number of constants that were found in those files. Then we found the
- // average and standard deviation of the ratios of constants/bytesize. Then
- // we added 1.34 standard deviations to the average to get a ratio that
- // would fit 75% of the files (for a two-tailed distribution). This works
- // because there was about a 0.77 correlation and the distribution was
- // roughly normal.
- //
- // This ratio will need to change if we add more constants to the constant
- // pool for another node type.
- uint32_t constant_size = ((uint32_t) size) / 95;
- pm_constant_pool_init(&parser->constant_pool, constant_size < 4 ? 4 : constant_size);
-
- // Initialize the newline list. Similar to the constant pool, we're going to
- // guess at the number of newlines that we'll need based on the size of the
- // input.
- size_t newline_size = size / 22;
- pm_newline_list_init(&parser->newline_list, source, newline_size < 4 ? 4 : newline_size);
-
- // If options were provided to this parse, establish them here.
- if (options != NULL) {
- // filepath option
- parser->filepath_string = options->filepath;
-
- // line option
- if (options->line > 0) {
- parser->start_line = options->line;
- }
-
- // encoding option
- size_t encoding_length = pm_string_length(&options->encoding);
- if (encoding_length > 0) {
- const uint8_t *encoding_source = pm_string_source(&options->encoding);
- parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
- }
-
- // frozen_string_literal option
- if (options->frozen_string_literal) {
- parser->frozen_string_literal = true;
- }
-
- // suppress_warnings option
- if (options->suppress_warnings) {
- parser->suppress_warnings = true;
- }
-
- // scopes option
- for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
- const pm_options_scope_t *scope = pm_options_scope_get(options, scope_index);
- pm_parser_scope_push(parser, scope_index == 0);
-
- for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
- const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
-
- const uint8_t *source = pm_string_source(local);
- size_t length = pm_string_length(local);
-
- uint8_t *allocated = malloc(length);
- if (allocated == NULL) continue;
-
- memcpy((void *) allocated, source, length);
- pm_parser_local_add_owned(parser, allocated, length);
- }
- }
- }
-
- pm_accepts_block_stack_push(parser, true);
-
- // Skip past the UTF-8 BOM if it exists.
- if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
- parser->current.end += 3;
- parser->encoding_comment_start += 3;
- }
-
- // If the first two bytes of the source are a shebang, then we'll indicate
- // that the encoding comment is at the end of the shebang.
- if (peek(parser) == '#' && peek_offset(parser, 1) == '!') {
- const uint8_t *encoding_comment_start = next_newline(source, (ptrdiff_t) size);
- if (encoding_comment_start) {
- parser->encoding_comment_start = encoding_comment_start + 1;
- }
- }
-}
-
-/**
- * Register a callback that will be called whenever prism changes the encoding
- * it is using to parse based on the magic comment.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback) {
- parser->encoding_changed_callback = callback;
-}
-
-/**
- * Register a callback that will be called when prism encounters a magic comment
- * with an encoding referenced that it doesn't understand. The callback should
- * return NULL if it also doesn't understand the encoding or it should return a
- * pointer to a pm_encoding_t struct that contains the functions necessary to
- * parse identifiers.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_parser_register_encoding_decode_callback(pm_parser_t *parser, pm_encoding_decode_callback_t callback) {
- parser->encoding_decode_callback = callback;
-}
-
-/**
- * Free all of the memory associated with the comment list.
- */
-static inline void
-pm_comment_list_free(pm_list_t *list) {
- pm_list_node_t *node, *next;
-
- for (node = list->head; node != NULL; node = next) {
- next = node->next;
-
- pm_comment_t *comment = (pm_comment_t *) node;
- free(comment);
- }
-}
-
-/**
- * Free all of the memory associated with the magic comment list.
- */
-static inline void
-pm_magic_comment_list_free(pm_list_t *list) {
- pm_list_node_t *node, *next;
-
- for (node = list->head; node != NULL; node = next) {
- next = node->next;
-
- pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) node;
- free(magic_comment);
- }
-}
-
-/**
- * Free any memory associated with the given parser.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_parser_free(pm_parser_t *parser) {
- pm_string_free(&parser->filepath_string);
- pm_diagnostic_list_free(&parser->error_list);
- pm_diagnostic_list_free(&parser->warning_list);
- pm_comment_list_free(&parser->comment_list);
- pm_magic_comment_list_free(&parser->magic_comment_list);
- pm_constant_pool_free(&parser->constant_pool);
- pm_newline_list_free(&parser->newline_list);
-
- while (parser->current_scope != NULL) {
- // Normally, popping the scope doesn't free the locals since it is
- // assumed that ownership has transferred to the AST. However if we have
- // scopes while we're freeing the parser, it's likely they came from
- // eval scopes and we need to free them explicitly here.
- pm_constant_id_list_free(&parser->current_scope->locals);
- pm_parser_scope_pop(parser);
- }
-
- while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
- lex_mode_pop(parser);
- }
-}
-
-/**
- * Parse the Ruby source associated with the given parser and return the tree.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t *
-pm_parse(pm_parser_t *parser) {
- return parse_program(parser);
-}
-
-static inline void
-pm_serialize_header(pm_buffer_t *buffer) {
- pm_buffer_append_string(buffer, "PRISM", 5);
- pm_buffer_append_byte(buffer, PRISM_VERSION_MAJOR);
- pm_buffer_append_byte(buffer, PRISM_VERSION_MINOR);
- pm_buffer_append_byte(buffer, PRISM_VERSION_PATCH);
- pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
-}
-
-/**
- * Serialize the AST represented by the given node to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
- pm_serialize_header(buffer);
- pm_serialize_content(parser, node, buffer);
- pm_buffer_append_byte(buffer, '\0');
-}
-
-/**
- * Parse and serialize the AST represented by the given source to the given
- * buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- if (data != NULL) pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_node_t *node = pm_parse(&parser);
-
- pm_serialize_header(buffer);
- pm_serialize_content(&parser, node, buffer);
- pm_buffer_append_byte(buffer, '\0');
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-/**
- * Parse and serialize the comments in the given source to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- if (data != NULL) pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_serialize_header(buffer);
- pm_serialize_encoding(&parser.encoding, buffer);
- pm_buffer_append_varint(buffer, parser.start_line);
- pm_serialize_comment_list(&parser, &parser.comment_list, buffer);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-#undef PM_CASE_KEYWORD
-#undef PM_CASE_OPERATOR
-#undef PM_CASE_WRITABLE
-#undef PM_STRING_EMPTY
-#undef PM_LOCATION_NODE_BASE_VALUE
-#undef PM_LOCATION_NODE_VALUE
-#undef PM_LOCATION_NULL_VALUE
-#undef PM_LOCATION_TOKEN_VALUE
diff --git a/prism/prism.h b/prism/prism.h
deleted file mode 100644
index 5eec5f49ec..0000000000
--- a/prism/prism.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/**
- * @file prism.h
- *
- * The main header file for the prism parser.
- */
-#ifndef PRISM_H
-#define PRISM_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_buffer.h"
-#include "prism/util/pm_char.h"
-#include "prism/util/pm_memchr.h"
-#include "prism/util/pm_strncasecmp.h"
-#include "prism/util/pm_strpbrk.h"
-#include "prism/ast.h"
-#include "prism/diagnostic.h"
-#include "prism/node.h"
-#include "prism/options.h"
-#include "prism/pack.h"
-#include "prism/parser.h"
-#include "prism/prettyprint.h"
-#include "prism/regexp.h"
-#include "prism/version.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <strings.h>
-#endif
-
-/**
- * The prism version and the serialization format.
- *
- * @returns The prism version as a constant string.
- */
-PRISM_EXPORTED_FUNCTION const char * pm_version(void);
-
-/**
- * Initialize a parser with the given start and end pointers.
- *
- * @param parser The parser to initialize.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param options The optional options to use when parsing.
- */
-PRISM_EXPORTED_FUNCTION void pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options);
-
-/**
- * Register a callback that will be called whenever prism changes the encoding
- * it is using to parse based on the magic comment.
- *
- * @param parser The parser to register the callback with.
- * @param callback The callback to register.
- */
-PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback);
-
-/**
- * Register a callback that will be called when prism encounters a magic comment
- * with an encoding referenced that it doesn't understand. The callback should
- * return NULL if it also doesn't understand the encoding or it should return a
- * pointer to a pm_encoding_t struct that contains the functions necessary to
- * parse identifiers.
- *
- * @param parser The parser to register the callback with.
- * @param callback The callback to register.
- */
-PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_decode_callback(pm_parser_t *parser, pm_encoding_decode_callback_t callback);
-
-/**
- * Free any memory associated with the given parser.
- *
- * @param parser The parser to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser);
-
-/**
- * Initiate the parser with the given parser.
- *
- * @param parser The parser to use.
- * @return The AST representing the source.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser);
-
-/**
- * Serialize the given list of comments to the given buffer.
- *
- * @param parser The parser to serialize.
- * @param list The list of comments to serialize.
- * @param buffer The buffer to serialize to.
- */
-void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer);
-
-/**
- * Serialize the name of the encoding to the buffer.
- *
- * @param encoding The encoding to serialize.
- * @param buffer The buffer to serialize to.
- */
-void pm_serialize_encoding(pm_encoding_t *encoding, pm_buffer_t *buffer);
-
-/**
- * Serialize the encoding, metadata, nodes, and constant pool.
- *
- * @param parser The parser to serialize.
- * @param node The node to serialize.
- * @param buffer The buffer to serialize to.
- */
-void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer);
-
-/**
- * Serialize the AST represented by the given node to the given buffer.
- *
- * @param parser The parser to serialize.
- * @param node The node to serialize.
- * @param buffer The buffer to serialize to.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer);
-
-/**
- * Parse the given source to the AST and dump the AST to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-/**
- * Parse and serialize the comments in the given source to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-/**
- * Lex the given source and serialize to the given buffer.
- *
- * @param source The source to lex.
- * @param size The size of the source.
- * @param buffer The buffer to serialize to.
- * @param data The optional data to pass to the lexer.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-/**
- * Parse and serialize both the AST and the tokens represented by the given
- * source to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-/**
- * Returns a string representation of the given token type.
- *
- * @param token_type The token type to convert to a string.
- * @return A string representation of the given token type.
- */
-PRISM_EXPORTED_FUNCTION const char * pm_token_type_to_str(pm_token_type_t token_type);
-
-/**
- * @mainpage
- *
- * Prism is a parser for the Ruby programming language. It is designed to be
- * portable, error tolerant, and maintainable. It is written in C99 and has no
- * dependencies. It is currently being integrated into
- * [CRuby](https://github.com/ruby/ruby),
- * [JRuby](https://github.com/jruby/jruby),
- * [TruffleRuby](https://github.com/oracle/truffleruby),
- * [Sorbet](https://github.com/sorbet/sorbet), and
- * [Syntax Tree](https://github.com/ruby-syntax-tree/syntax_tree).
- *
- * @section getting-started Getting started
- *
- * If you're vendoring this project and compiling it statically then as long as
- * you have a C99 compiler you will be fine. If you're linking against it as
- * shared library, then you should compile with `-fvisibility=hidden` and
- * `-DPRISM_EXPORT_SYMBOLS` to tell prism to make only its public interface
- * visible.
- *
- * @section parsing Parsing
- *
- * In order to parse Ruby code, the structures and functions that you're going
- * to want to use and be aware of are:
- *
- * * `pm_parser_t` - the main parser structure
- * * `pm_parser_init` - initialize a parser
- * * `pm_parse` - parse and return the root node
- * * `pm_node_destroy` - deallocate the root node returned by `pm_parse`
- * * `pm_parser_free` - free the internal memory of the parser
- *
- * Putting all of this together would look something like:
- *
- * ```c
- * void parse(const uint8_t *source, size_t length) {
- * pm_parser_t parser;
- * pm_parser_init(&parser, source, length, NULL);
- *
- * pm_node_t *root = pm_parse(&parser);
- * printf("PARSED!\n");
- *
- * pm_node_destroy(root);
- * pm_parser_free(&parser);
- * }
- * ```
- *
- * All of the nodes "inherit" from `pm_node_t` by embedding those structures as
- * their first member. This means you can downcast and upcast any node in the
- * tree to a `pm_node_t`.
- *
- * @section serializing Serializing
- *
- * Prism provides the ability to serialize the AST and its related metadata into
- * a binary format. This format is designed to be portable to different
- * languages and runtimes so that you only need to make one FFI call in order to
- * parse Ruby code. The structures and functions that you're going to want to
- * use and be aware of are:
- *
- * * `pm_buffer_t` - a small buffer object that will hold the serialized AST
- * * `pm_buffer_free` - free the memory associated with the buffer
- * * `pm_serialize` - serialize the AST into a buffer
- * * `pm_serialize_parse` - parse and serialize the AST into a buffer
- *
- * Putting all of this together would look something like:
- *
- * ```c
- * void serialize(const uint8_t *source, size_t length) {
- * pm_buffer_t buffer = { 0 };
- *
- * pm_serialize_parse(&buffer, source, length, NULL);
- * printf("SERIALIZED!\n");
- *
- * pm_buffer_free(&buffer);
- * }
- * ```
- *
- * @section inspecting Inspecting
- *
- * Prism provides the ability to inspect the AST by pretty-printing nodes. You
- * can do this with the `pm_prettyprint` function, which you would use like:
- *
- * ```c
- * void prettyprint(const uint8_t *source, size_t length) {
- * pm_parser_t parser;
- * pm_parser_init(&parser, source, length, NULL);
- *
- * pm_node_t *root = pm_parse(&parser);
- * pm_buffer_t buffer = { 0 };
- *
- * pm_prettyprint(&buffer, &parser, root);
- * printf("*.s%\n", (int) buffer.length, buffer.value);
- *
- * pm_buffer_free(&buffer);
- * pm_node_destroy(root);
- * pm_parser_free(&parser);
- * }
- * ```
- */
-
-#endif
diff --git a/prism/regexp.c b/prism/regexp.c
deleted file mode 100644
index cd52857f79..0000000000
--- a/prism/regexp.c
+++ /dev/null
@@ -1,638 +0,0 @@
-#include "prism/regexp.h"
-
-/**
- * This is the parser that is going to handle parsing regular expressions.
- */
-typedef struct {
- /** A pointer to the start of the source that we are parsing. */
- const uint8_t *start;
-
- /** A pointer to the current position in the source. */
- const uint8_t *cursor;
-
- /** A pointer to the end of the source that we are parsing. */
- const uint8_t *end;
-
- /** A list of named captures that we've found. */
- pm_string_list_t *named_captures;
-
- /** Whether the encoding has changed from the default. */
- bool encoding_changed;
-
- /** The encoding of the source. */
- pm_encoding_t *encoding;
-} pm_regexp_parser_t;
-
-/**
- * This initializes a new parser with the given source.
- */
-static void
-pm_regexp_parser_init(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_string_list_t *named_captures, bool encoding_changed, pm_encoding_t *encoding) {
- *parser = (pm_regexp_parser_t) {
- .start = start,
- .cursor = start,
- .end = end,
- .named_captures = named_captures,
- .encoding_changed = encoding_changed,
- .encoding = encoding
- };
-}
-
-/**
- * This appends a new string to the list of named captures.
- */
-static void
-pm_regexp_parser_named_capture(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- pm_string_t string;
- pm_string_shared_init(&string, start, end);
- pm_string_list_append(parser->named_captures, &string);
- pm_string_free(&string);
-}
-
-/**
- * Returns true if the next character is the end of the source.
- */
-static inline bool
-pm_regexp_char_is_eof(pm_regexp_parser_t *parser) {
- return parser->cursor >= parser->end;
-}
-
-/**
- * Optionally accept a char and consume it if it exists.
- */
-static inline bool
-pm_regexp_char_accept(pm_regexp_parser_t *parser, uint8_t value) {
- if (!pm_regexp_char_is_eof(parser) && *parser->cursor == value) {
- parser->cursor++;
- return true;
- }
- return false;
-}
-
-/**
- * Expect a character to be present and consume it.
- */
-static inline bool
-pm_regexp_char_expect(pm_regexp_parser_t *parser, uint8_t value) {
- if (!pm_regexp_char_is_eof(parser) && *parser->cursor == value) {
- parser->cursor++;
- return true;
- }
- return false;
-}
-
-/**
- * This advances the current token to the next instance of the given character.
- */
-static bool
-pm_regexp_char_find(pm_regexp_parser_t *parser, uint8_t value) {
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
-
- const uint8_t *end = (const uint8_t *) pm_memchr(parser->cursor, value, (size_t) (parser->end - parser->cursor), parser->encoding_changed, parser->encoding);
- if (end == NULL) {
- return false;
- }
-
- parser->cursor = end + 1;
- return true;
-}
-
-/**
- * Range quantifiers are a special class of quantifiers that look like
- *
- * * {digit}
- * * {digit,}
- * * {digit,digit}
- * * {,digit}
- *
- * Unfortunately, if there are any spaces in between, then this just becomes a
- * regular character match expression and we have to backtrack. So when this
- * function first starts running, we'll create a "save" point and then attempt
- * to parse the quantifier. If it fails, we'll restore the save point and
- * return.
- *
- * The properly track everything, we're going to build a little state machine.
- * It looks something like the following:
- *
- * +-------+ +---------+ ------------+
- * ---- lbrace ---> | start | ---- digit ---> | minimum | |
- * +-------+ +---------+ <--- digit -+
- * | | |
- * +-------+ | | rbrace
- * | comma | <----- comma +---- comma -------+ |
- * +-------+ V V
- * | +---------+ +---------+
- * +-- digit --> | maximum | -- rbrace --> || final ||
- * +---------+ +---------+
- * | ^
- * +- digit -+
- *
- * Note that by the time we've hit this function, the lbrace has already been
- * consumed so we're in the start state.
- */
-static bool
-pm_regexp_parse_range_quantifier(pm_regexp_parser_t *parser) {
- const uint8_t *savepoint = parser->cursor;
-
- enum {
- PM_REGEXP_RANGE_QUANTIFIER_STATE_START,
- PM_REGEXP_RANGE_QUANTIFIER_STATE_MINIMUM,
- PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM,
- PM_REGEXP_RANGE_QUANTIFIER_STATE_COMMA
- } state = PM_REGEXP_RANGE_QUANTIFIER_STATE_START;
-
- while (1) {
- switch (state) {
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_START:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_MINIMUM;
- break;
- case ',':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_COMMA;
- break;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_MINIMUM:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- break;
- case ',':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM;
- break;
- case '}':
- parser->cursor++;
- return true;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_COMMA:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM;
- break;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- break;
- case '}':
- parser->cursor++;
- return true;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- }
- }
-
- return true;
-}
-
-/**
- * quantifier : star-quantifier
- * | plus-quantifier
- * | optional-quantifier
- * | range-quantifier
- * | <empty>
- * ;
- */
-static bool
-pm_regexp_parse_quantifier(pm_regexp_parser_t *parser) {
- if (pm_regexp_char_is_eof(parser)) return true;
-
- switch (*parser->cursor) {
- case '*':
- case '+':
- case '?':
- parser->cursor++;
- return true;
- case '{':
- parser->cursor++;
- return pm_regexp_parse_range_quantifier(parser);
- default:
- // In this case there is no quantifier.
- return true;
- }
-}
-
-/**
- * match-posix-class : '[' '[' ':' '^'? CHAR+ ':' ']' ']'
- * ;
- */
-static bool
-pm_regexp_parse_posix_class(pm_regexp_parser_t *parser) {
- if (!pm_regexp_char_expect(parser, ':')) {
- return false;
- }
-
- pm_regexp_char_accept(parser, '^');
-
- return (
- pm_regexp_char_find(parser, ':') &&
- pm_regexp_char_expect(parser, ']') &&
- pm_regexp_char_expect(parser, ']')
- );
-}
-
-// Forward declaration because character sets can be nested.
-static bool
-pm_regexp_parse_lbracket(pm_regexp_parser_t *parser);
-
-/**
- * match-char-set : '[' '^'? (match-range | match-char)* ']'
- * ;
- */
-static bool
-pm_regexp_parse_character_set(pm_regexp_parser_t *parser) {
- pm_regexp_char_accept(parser, '^');
-
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ']') {
- switch (*parser->cursor++) {
- case '[':
- pm_regexp_parse_lbracket(parser);
- break;
- case '\\':
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
- break;
- default:
- // do nothing, we've already advanced the cursor
- break;
- }
- }
-
- return pm_regexp_char_expect(parser, ']');
-}
-
-/**
- * A left bracket can either mean a POSIX class or a character set.
- */
-static bool
-pm_regexp_parse_lbracket(pm_regexp_parser_t *parser) {
- const uint8_t *reset = parser->cursor;
-
- if ((parser->cursor + 2 < parser->end) && parser->cursor[0] == '[' && parser->cursor[1] == ':') {
- parser->cursor++;
- if (pm_regexp_parse_posix_class(parser)) return true;
-
- parser->cursor = reset;
- }
-
- return pm_regexp_parse_character_set(parser);
-}
-
-// Forward declaration here since parsing groups needs to go back up the grammar
-// to parse expressions within them.
-static bool
-pm_regexp_parse_expression(pm_regexp_parser_t *parser);
-
-/**
- * These are the states of the options that are configurable on the regular
- * expression (or from within a group).
- */
-typedef enum {
- PM_REGEXP_OPTION_STATE_INVALID,
- PM_REGEXP_OPTION_STATE_TOGGLEABLE,
- PM_REGEXP_OPTION_STATE_ADDABLE,
- PM_REGEXP_OPTION_STATE_ADDED,
- PM_REGEXP_OPTION_STATE_REMOVED
-} pm_regexp_option_state_t;
-
-// These are the options that are configurable on the regular expression (or
-// from within a group).
-
-#define PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM 'a'
-#define PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM 'x'
-#define PRISM_REGEXP_OPTION_STATE_SLOTS (PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM + 1)
-
-/**
- * This is the set of options that are configurable on the regular expression.
- */
-typedef struct {
- /** The current state of each option. */
- uint8_t values[PRISM_REGEXP_OPTION_STATE_SLOTS];
-} pm_regexp_options_t;
-
-/**
- * Initialize a new set of options to their default values.
- */
-static void
-pm_regexp_options_init(pm_regexp_options_t *options) {
- memset(options, PM_REGEXP_OPTION_STATE_INVALID, sizeof(uint8_t) * PRISM_REGEXP_OPTION_STATE_SLOTS);
- options->values['i' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_TOGGLEABLE;
- options->values['m' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_TOGGLEABLE;
- options->values['x' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_TOGGLEABLE;
- options->values['d' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_ADDABLE;
- options->values['a' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_ADDABLE;
- options->values['u' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_ADDABLE;
-}
-
-/**
- * Attempt to add the given option to the set of options. Returns true if it was
- * added, false if it was already present.
- */
-static bool
-pm_regexp_options_add(pm_regexp_options_t *options, uint8_t key) {
- if (key >= PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM && key <= PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM) {
- key = (uint8_t) (key - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM);
-
- switch (options->values[key]) {
- case PM_REGEXP_OPTION_STATE_INVALID:
- case PM_REGEXP_OPTION_STATE_REMOVED:
- return false;
- case PM_REGEXP_OPTION_STATE_TOGGLEABLE:
- case PM_REGEXP_OPTION_STATE_ADDABLE:
- options->values[key] = PM_REGEXP_OPTION_STATE_ADDED;
- return true;
- case PM_REGEXP_OPTION_STATE_ADDED:
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Attempt to remove the given option from the set of options. Returns true if
- * it was removed, false if it was already absent.
- */
-static bool
-pm_regexp_options_remove(pm_regexp_options_t *options, uint8_t key) {
- if (key >= PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM && key <= PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM) {
- key = (uint8_t) (key - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM);
-
- switch (options->values[key]) {
- case PM_REGEXP_OPTION_STATE_INVALID:
- case PM_REGEXP_OPTION_STATE_ADDABLE:
- return false;
- case PM_REGEXP_OPTION_STATE_TOGGLEABLE:
- case PM_REGEXP_OPTION_STATE_ADDED:
- case PM_REGEXP_OPTION_STATE_REMOVED:
- options->values[key] = PM_REGEXP_OPTION_STATE_REMOVED;
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Groups can have quite a few different patterns for syntax. They basically
- * just wrap a set of expressions, but they can potentially have options after a
- * question mark. If there _isn't_ a question mark, then it's just a set of
- * expressions. If there _is_, then here are the options:
- *
- * * (?#...) - inline comments
- * * (?:subexp) - non-capturing group
- * * (?=subexp) - positive lookahead
- * * (?!subexp) - negative lookahead
- * * (?>subexp) - atomic group
- * * (?~subexp) - absence operator
- * * (?<=subexp) - positive lookbehind
- * * (?<!subexp) - negative lookbehind
- * * (?<name>subexp) - named capturing group
- * * (?'name'subexp) - named capturing group
- * * (?(cond)yes-subexp) - conditional expression
- * * (?(cond)yes-subexp|no-subexp) - conditional expression
- * * (?imxdau-imx) - turn on and off configuration
- * * (?imxdau-imx:subexp) - turn on and off configuration for an expression
- */
-static bool
-pm_regexp_parse_group(pm_regexp_parser_t *parser) {
- // First, parse any options for the group.
- if (pm_regexp_char_accept(parser, '?')) {
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
- pm_regexp_options_t options;
- pm_regexp_options_init(&options);
-
- switch (*parser->cursor) {
- case '#': { // inline comments
- if (parser->encoding_changed && parser->encoding->multibyte) {
- bool escaped = false;
-
- // Here we're going to take a slow path and iterate through
- // each multibyte character to find the close paren. We do
- // this because \ can be a trailing byte in some encodings.
- while (parser->cursor < parser->end) {
- if (!escaped && *parser->cursor == ')') {
- parser->cursor++;
- return true;
- }
-
- size_t width = parser->encoding->char_width(parser->cursor, (ptrdiff_t) (parser->end - parser->cursor));
- if (width == 0) return false;
-
- escaped = (width == 1) && (*parser->cursor == '\\');
- parser->cursor += width;
- }
-
- return false;
- } else {
- // Here we can take the fast path and use memchr to find the
- // next ) because we are safe checking backward for \ since
- // it cannot be a trailing character.
- bool found = pm_regexp_char_find(parser, ')');
-
- while (found && (parser->start <= parser->cursor - 2) && (*(parser->cursor - 2) == '\\')) {
- found = pm_regexp_char_find(parser, ')');
- }
-
- return found;
- }
- }
- case ':': // non-capturing group
- case '=': // positive lookahead
- case '!': // negative lookahead
- case '>': // atomic group
- case '~': // absence operator
- parser->cursor++;
- break;
- case '<':
- parser->cursor++;
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
-
- switch (*parser->cursor) {
- case '=': // positive lookbehind
- case '!': // negative lookbehind
- parser->cursor++;
- break;
- default: { // named capture group
- const uint8_t *start = parser->cursor;
- if (!pm_regexp_char_find(parser, '>')) {
- return false;
- }
- pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
- break;
- }
- }
- break;
- case '\'': { // named capture group
- const uint8_t *start = ++parser->cursor;
- if (!pm_regexp_char_find(parser, '\'')) {
- return false;
- }
-
- pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
- break;
- }
- case '(': // conditional expression
- if (!pm_regexp_char_find(parser, ')')) {
- return false;
- }
- break;
- case 'i': case 'm': case 'x': case 'd': case 'a': case 'u': // options
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != '-' && *parser->cursor != ':' && *parser->cursor != ')') {
- if (!pm_regexp_options_add(&options, *parser->cursor)) {
- return false;
- }
- parser->cursor++;
- }
-
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
-
- // If we hit a -, then we're done parsing options.
- if (*parser->cursor != '-') break;
-
- // Otherwise, fallthrough to the - case.
- /* fallthrough */
- case '-':
- parser->cursor++;
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ':' && *parser->cursor != ')') {
- if (!pm_regexp_options_remove(&options, *parser->cursor)) {
- return false;
- }
- parser->cursor++;
- }
-
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
- break;
- default:
- return false;
- }
- }
-
- // Now, parse the expressions within this group.
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ')') {
- if (!pm_regexp_parse_expression(parser)) {
- return false;
- }
- pm_regexp_char_accept(parser, '|');
- }
-
- // Finally, make sure we have a closing parenthesis.
- return pm_regexp_char_expect(parser, ')');
-}
-
-/**
- * item : anchor
- * | match-posix-class
- * | match-char-set
- * | match-char-class
- * | match-char-prop
- * | match-char
- * | match-any
- * | group
- * | quantified
- * ;
- */
-static bool
-pm_regexp_parse_item(pm_regexp_parser_t *parser) {
- switch (*parser->cursor++) {
- case '^':
- case '$':
- return true;
- case '\\':
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
- return pm_regexp_parse_quantifier(parser);
- case '(':
- return pm_regexp_parse_group(parser) && pm_regexp_parse_quantifier(parser);
- case '[':
- return pm_regexp_parse_lbracket(parser) && pm_regexp_parse_quantifier(parser);
- default:
- return pm_regexp_parse_quantifier(parser);
- }
-}
-
-/**
- * expression : item+
- * ;
- */
-static bool
-pm_regexp_parse_expression(pm_regexp_parser_t *parser) {
- if (!pm_regexp_parse_item(parser)) {
- return false;
- }
-
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ')' && *parser->cursor != '|') {
- if (!pm_regexp_parse_item(parser)) {
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * pattern : EOF
- * | expression EOF
- * | expression '|' pattern
- * ;
- */
-static bool
-pm_regexp_parse_pattern(pm_regexp_parser_t *parser) {
- return (
- (
- // Exit early if the pattern is empty.
- pm_regexp_char_is_eof(parser) ||
- // Parse the first expression in the pattern.
- pm_regexp_parse_expression(parser)
- ) &&
- (
- // Return now if we've parsed the entire pattern.
- pm_regexp_char_is_eof(parser) ||
- // Otherwise, we should have a pipe character.
- (pm_regexp_char_expect(parser, '|') && pm_regexp_parse_pattern(parser))
- )
- );
-}
-
-/**
- * Parse a regular expression and extract the names of all of the named capture
- * groups.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_regexp_named_capture_group_names(const uint8_t *source, size_t size, pm_string_list_t *named_captures, bool encoding_changed, pm_encoding_t *encoding) {
- pm_regexp_parser_t parser;
- pm_regexp_parser_init(&parser, source, source + size, named_captures, encoding_changed, encoding);
- return pm_regexp_parse_pattern(&parser);
-}
diff --git a/prism/regexp.h b/prism/regexp.h
deleted file mode 100644
index 09bdaca89a..0000000000
--- a/prism/regexp.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * @file regexp.h
- *
- * A regular expression parser.
- */
-#ifndef PRISM_REGEXP_H
-#define PRISM_REGEXP_H
-
-#include "prism/defines.h"
-#include "prism/parser.h"
-#include "prism/enc/pm_encoding.h"
-#include "prism/util/pm_memchr.h"
-#include "prism/util/pm_string_list.h"
-#include "prism/util/pm_string.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-/**
- * Parse a regular expression and extract the names of all of the named capture
- * groups.
- *
- * @param source The source code to parse.
- * @param size The size of the source code.
- * @param named_captures The list to add the names of the named capture groups.
- * @param encoding_changed Whether or not the encoding changed from the default.
- * @param encoding The encoding of the source code.
- * @return Whether or not the parsing was successful.
- */
-PRISM_EXPORTED_FUNCTION bool pm_regexp_named_capture_group_names(const uint8_t *source, size_t size, pm_string_list_t *named_captures, bool encoding_changed, pm_encoding_t *encoding);
-
-#endif
diff --git a/prism/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb
deleted file mode 100644
index 7bc52c1120..0000000000
--- a/prism/templates/ext/prism/api_node.c.erb
+++ /dev/null
@@ -1,218 +0,0 @@
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
-#include "prism/extension.h"
-
-extern VALUE rb_cPrism;
-extern VALUE rb_cPrismNode;
-extern VALUE rb_cPrismSource;
-extern VALUE rb_cPrismToken;
-extern VALUE rb_cPrismLocation;
-
-<%- nodes.each do |node| -%>
-static VALUE rb_cPrism<%= node.name %>;
-<%- end -%>
-
-static VALUE
-pm_location_new(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, VALUE source) {
- VALUE argv[] = { source, LONG2FIX(start - parser->start), LONG2FIX(end - start) };
- return rb_class_new_instance(3, argv, rb_cPrismLocation);
-}
-
-VALUE
-pm_token_new(pm_parser_t *parser, pm_token_t *token, rb_encoding *encoding, VALUE source) {
- ID type = rb_intern(pm_token_type_to_str(token->type));
- VALUE location = pm_location_new(parser, token->start, token->end, source);
-
- VALUE argv[] = {
- ID2SYM(type),
- rb_enc_str_new((const char *) token->start, token->end - token->start, encoding),
- location
- };
-
- return rb_class_new_instance(3, argv, rb_cPrismToken);
-}
-
-static VALUE
-pm_string_new(pm_string_t *string, rb_encoding *encoding) {
- return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), encoding);
-}
-
-// Create a Prism::Source object from the given parser.
-VALUE
-pm_source_new(pm_parser_t *parser, rb_encoding *encoding) {
- VALUE source = rb_enc_str_new((const char *) parser->start, parser->end - parser->start, encoding);
- VALUE offsets = rb_ary_new_capa(parser->newline_list.size);
-
- for (size_t index = 0; index < parser->newline_list.size; index++) {
- rb_ary_push(offsets, INT2FIX(parser->newline_list.offsets[index]));
- }
-
- VALUE source_argv[] = { source, ULONG2NUM(parser->start_line), offsets };
- return rb_class_new_instance(3, source_argv, rb_cPrismSource);
-}
-
-typedef struct pm_node_stack_node {
- struct pm_node_stack_node *prev;
- pm_node_t *visit;
- bool visited;
-} pm_node_stack_node_t;
-
-static void
-pm_node_stack_push(pm_node_stack_node_t **stack, pm_node_t *visit) {
- pm_node_stack_node_t *node = malloc(sizeof(pm_node_stack_node_t));
- node->prev = *stack;
- node->visit = visit;
- node->visited = false;
- *stack = node;
-}
-
-static pm_node_t *
-pm_node_stack_pop(pm_node_stack_node_t **stack) {
- pm_node_stack_node_t *current = *stack;
- pm_node_t *visit = current->visit;
-
- *stack = current->prev;
- free(current);
-
- return visit;
-}
-
-VALUE
-pm_ast_new(pm_parser_t *parser, pm_node_t *node, rb_encoding *encoding) {
- VALUE source = pm_source_new(parser, encoding);
- ID *constants = calloc(parser->constant_pool.size, sizeof(ID));
-
- for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
- pm_constant_t *constant = &parser->constant_pool.constants[index];
- int state = 0;
-
- VALUE string = rb_enc_str_new((const char *) constant->start, constant->length, encoding);
- ID value = rb_protect(rb_intern_str, string, &state);
-
- if (state != 0) {
- value = rb_intern_const("?");
- rb_set_errinfo(Qnil);
- }
-
- constants[index] = value;
- }
-
- pm_node_stack_node_t *node_stack = NULL;
- pm_node_stack_push(&node_stack, node);
- VALUE value_stack = rb_ary_new();
-
- while (node_stack != NULL) {
- if (!node_stack->visited) {
- if (node_stack->visit == NULL) {
- pm_node_stack_pop(&node_stack);
- rb_ary_push(value_stack, Qnil);
- continue;
- }
-
- pm_node_t *node = node_stack->visit;
- node_stack->visited = true;
-
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
- <%- if node.fields.any? { |field| [Prism::NodeField, Prism::OptionalNodeField, Prism::NodeListField].include?(field.class) } -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::NodeField, Prism::OptionalNodeField -%>
- pm_node_stack_push(&node_stack, (pm_node_t *) cast-><%= field.name %>);
- <%- when Prism::NodeListField -%>
- for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
- pm_node_stack_push(&node_stack, (pm_node_t *) cast-><%= field.name %>.nodes[index]);
- }
- <%- end -%>
- <%- end -%>
- break;
- }
- <%- end -%>
- <%- end -%>
- default:
- break;
- }
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- } else {
- pm_node_t *node = pm_node_stack_pop(&node_stack);
-
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- <%- if node.fields.any? { |field| ![Prism::NodeField, Prism::OptionalNodeField, Prism::FlagsField].include?(field.class) } -%>
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- end -%>
- VALUE argv[<%= node.fields.length + 1 %>];
- <%- node.fields.each_with_index do |field, index| -%>
-
- // <%= field.name %>
- <%- case field -%>
- <%- when Prism::NodeField, Prism::OptionalNodeField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = rb_ary_pop(value_stack);
- <%- when Prism::NodeListField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = rb_ary_new_capa(cast-><%= field.name %>.size);
- for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
- rb_ary_push(argv[<%= index %>], rb_ary_pop(value_stack));
- }
- <%- when Prism::StringField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = pm_string_new(&cast-><%= field.name %>, encoding);
- <%- when Prism::ConstantField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- assert(cast-><%= field.name %> != 0);
- argv[<%= index %>] = rb_id2sym(constants[cast-><%= field.name %> - 1]);
- <%- when Prism::OptionalConstantField -%>
- argv[<%= index %>] = cast-><%= field.name %> == 0 ? Qnil : rb_id2sym(constants[cast-><%= field.name %> - 1]);
- <%- when Prism::ConstantListField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = rb_ary_new_capa(cast-><%= field.name %>.size);
- for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
- assert(cast-><%= field.name %>.ids[index] != 0);
- rb_ary_push(argv[<%= index %>], rb_id2sym(constants[cast-><%= field.name %>.ids[index] - 1]));
- }
- <%- when Prism::LocationField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = pm_location_new(parser, cast-><%= field.name %>.start, cast-><%= field.name %>.end, source);
- <%- when Prism::OptionalLocationField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = cast-><%= field.name %>.start == NULL ? Qnil : pm_location_new(parser, cast-><%= field.name %>.start, cast-><%= field.name %>.end, source);
- <%- when Prism::UInt32Field -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = ULONG2NUM(cast-><%= field.name %>);
- <%- when Prism::FlagsField -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = ULONG2NUM(node->flags & ~PM_NODE_FLAG_COMMON_MASK);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
-
- // location
- argv[<%= node.fields.length %>] = pm_location_new(parser, node->location.start, node->location.end, source);
-
- rb_ary_push(value_stack, rb_class_new_instance(<%= node.fields.length + 1 %>, argv, rb_cPrism<%= node.name %>));
- break;
- }
- <%- end -%>
- default:
- rb_raise(rb_eRuntimeError, "unknown node type: %d", PM_NODE_TYPE(node));
- }
- }
- }
-
- VALUE result = rb_ary_pop(value_stack);
- free(constants);
- return result;
-}
-
-void
-Init_prism_api_node(void) {
- <%- nodes.each do |node| -%>
- rb_cPrism<%= node.name %> = rb_define_class_under(rb_cPrism, "<%= node.name %>", rb_cPrismNode);
- <%- end -%>
-}
diff --git a/prism/templates/include/prism/ast.h.erb b/prism/templates/include/prism/ast.h.erb
deleted file mode 100644
index dd1c6bcd74..0000000000
--- a/prism/templates/include/prism/ast.h.erb
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * @file ast.h
- *
- * The abstract syntax tree.
- */
-#ifndef PRISM_AST_H
-#define PRISM_AST_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_constant_pool.h"
-#include "prism/util/pm_string.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * This enum represents every type of token in the Ruby source.
- */
-typedef enum pm_token_type {
-<%- tokens.each do |token| -%>
- /** <%= token.comment %> */
- PM_TOKEN_<%= token.name %><%= " = #{token.value}" if token.value %>,
-
-<%- end -%>
- /** The maximum token value. */
- PM_TOKEN_MAXIMUM,
-} pm_token_type_t;
-
-/**
- * This struct represents a token in the Ruby source. We use it to track both
- * type and location information.
- */
-typedef struct {
- /** The type of the token. */
- pm_token_type_t type;
-
- /** A pointer to the start location of the token in the source. */
- const uint8_t *start;
-
- /** A pointer to the end location of the token in the source. */
- const uint8_t *end;
-} pm_token_t;
-
-/**
- * This represents a range of bytes in the source string to which a node or
- * token corresponds.
- */
-typedef struct {
- /** A pointer to the start location of the range in the source. */
- const uint8_t *start;
-
- /** A pointer to the end location of the range in the source. */
- const uint8_t *end;
-} pm_location_t;
-
-struct pm_node;
-
-/**
- * A list of nodes in the source, most often used for lists of children.
- */
-typedef struct pm_node_list {
- /** The number of nodes in the list. */
- size_t size;
-
- /** The capacity of the list that has been allocated. */
- size_t capacity;
-
- /** The nodes in the list. */
- struct pm_node **nodes;
-} pm_node_list_t;
-
-/**
- * This enum represents every type of node in the Ruby syntax tree.
- */
-enum pm_node_type {
-<%- nodes.each_with_index do |node, index| -%>
- /** <%= node.name %> */
- <%= node.type %> = <%= index + 1 %>,
-
-<%- end -%>
- /** A special kind of node used for compilation. */
- PM_SCOPE_NODE
-};
-
-/**
- * This is the type of node embedded in the node struct. We explicitly control
- * the size of it here to avoid having the variable-width enum.
- */
-typedef uint16_t pm_node_type_t;
-
-/**
- * These are the flags embedded in the node struct. We explicitly control the
- * size of it here to avoid having the variable-width enum.
- */
-typedef uint16_t pm_node_flags_t;
-
-/**
- * We store the flags enum in every node in the tree. Some flags are common to
- * all nodes (the ones listed below). Others are specific to certain node types.
- */
-#define PM_NODE_FLAG_BITS (sizeof(pm_node_flags_t) * 8)
-
-static const pm_node_flags_t PM_NODE_FLAG_NEWLINE = (1 << (PM_NODE_FLAG_BITS - 1));
-static const pm_node_flags_t PM_NODE_FLAG_STATIC_LITERAL = (1 << (PM_NODE_FLAG_BITS - 2));
-static const pm_node_flags_t PM_NODE_FLAG_COMMON_MASK = (1 << (PM_NODE_FLAG_BITS - 1)) | (1 << (PM_NODE_FLAG_BITS - 2));
-
-/**
- * Cast the type to an enum to allow the compiler to provide exhaustiveness
- * checking.
- */
-#define PM_NODE_TYPE(node) ((enum pm_node_type) node->type)
-
-/**
- * Return true if the type of the given node matches the given type.
- */
-#define PM_NODE_TYPE_P(node, type) (PM_NODE_TYPE(node) == (type))
-
-/**
- * This is the base structure that represents a node in the syntax tree. It is
- * embedded into every node type.
- */
-typedef struct pm_node {
- /**
- * This represents the type of the node. It somewhat maps to the nodes that
- * existed in the original grammar and ripper, but it's not a 1:1 mapping.
- */
- pm_node_type_t type;
-
- /**
- * This represents any flags on the node. Some are common to all nodes, and
- * some are specific to the type of node.
- */
- pm_node_flags_t flags;
-
- /**
- * This is the location of the node in the source. It's a range of bytes
- * containing a start and an end.
- */
- pm_location_t location;
-} pm_node_t;
-<%- nodes.each do |node| -%>
-
-/**
- * <%= node.name %>
- *
- * Type: <%= node.type %>
-<%- if (node_flags = node.fields.find { |field| field.is_a? Prism::FlagsField }) -%>
- * Flags:
-<%- found = flags.find { |flag| flag.name == node_flags.kind }.tap { |found| raise "Expected to find #{field.kind}" unless found } -%>
-<%- found.values.each do |value| -%>
- * PM_<%= found.human.upcase %>_<%= value.name %>
-<%- end -%>
-<%- end -%>
- *
- * @extends pm_node_t
- */
-typedef struct pm_<%= node.human %> {
- /** The embedded base node. */
- pm_node_t base;
-<%- node.fields.grep_v(Prism::FlagsField).each do |field| -%>
-
- /** <%= node.name %>#<%= field.name %> */
- <%= case field
- when Prism::NodeField, Prism::OptionalNodeField then "struct #{field.c_type} *#{field.name}"
- when Prism::NodeListField then "struct pm_node_list #{field.name}"
- when Prism::ConstantField, Prism::OptionalConstantField then "pm_constant_id_t #{field.name}"
- when Prism::ConstantListField then "pm_constant_id_list_t #{field.name}"
- when Prism::StringField then "pm_string_t #{field.name}"
- when Prism::LocationField, Prism::OptionalLocationField then "pm_location_t #{field.name}"
- when Prism::UInt32Field then "uint32_t #{field.name}"
- else raise field.class.name
- end
- %>;
-<%- end -%>
-} pm_<%= node.human %>_t;
-<%- end -%>
-<%- flags.each do |flag| -%>
-
-/**
- * <%= flag.comment %>
- */
-typedef enum pm_<%= flag.human %> {
- <%- flag.values.each_with_index do |value, index| -%>
-<%= "\n" if index > 0 -%>
- /** <%= value.comment %> */
- PM_<%= flag.human.upcase %>_<%= value.name %> = <%= 1 << index %>,
- <%- end -%>
-} pm_<%= flag.human %>_t;
-<%- end -%>
-
-/**
- * When we're serializing to Java, we want to skip serializing the location
- * fields as they won't be used by JRuby or TruffleRuby. This boolean allows us
- * to specify that through the environment. It will never be true except for in
- * those build systems.
- */
-#define PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS <%= Prism::SERIALIZE_ONLY_SEMANTICS_FIELDS %>
-
-#endif
diff --git a/prism/templates/lib/prism/compiler.rb.erb b/prism/templates/lib/prism/compiler.rb.erb
deleted file mode 100644
index 2c947f6ed2..0000000000
--- a/prism/templates/lib/prism/compiler.rb.erb
+++ /dev/null
@@ -1,41 +0,0 @@
-module Prism
- # A compiler is a visitor that returns the value of each node as it visits.
- # This is as opposed to a visitor which will only walk the tree. This can be
- # useful when you are trying to compile a tree into a different format.
- #
- # For example, to build a representation of the tree as s-expressions, you
- # could write:
- #
- # class SExpressions < Prism::Compiler
- # def visit_arguments_node(node) = [:arguments, super]
- # def visit_call_node(node) = [:call, super]
- # def visit_integer_node(node) = [:integer]
- # def visit_program_node(node) = [:program, super]
- # end
- #
- # Prism.parse("1 + 2").value.accept(SExpressions.new)
- # # => [:program, [[[:call, [[:integer], [:arguments, [[:integer]]]]]]]]
- #
- class Compiler
- # Visit an individual node.
- def visit(node)
- node&.accept(self)
- end
-
- # Visit a list of nodes.
- def visit_all(nodes)
- nodes.map { |node| node&.accept(self) }
- end
-
- # Visit the child nodes of the given node.
- def visit_child_nodes(node)
- node.compact_child_nodes.map { |node| node.accept(self) }
- end
-
- <%- nodes.each_with_index do |node, index| -%>
-<%= "\n" if index != 0 -%>
- # Compile a <%= node.name %> node
- alias visit_<%= node.human %> visit_child_nodes
- <%- end -%>
- end
-end
diff --git a/prism/templates/lib/prism/dispatcher.rb.erb b/prism/templates/lib/prism/dispatcher.rb.erb
deleted file mode 100644
index 1370ca7636..0000000000
--- a/prism/templates/lib/prism/dispatcher.rb.erb
+++ /dev/null
@@ -1,89 +0,0 @@
-module Prism
- # The dispatcher class fires events for nodes that are found while walking an
- # AST to all registered listeners. It's useful for performing different types
- # of analysis on the AST while only having to walk the tree once.
- #
- # To use the dispatcher, you would first instantiate it and register listeners
- # for the events you're interested in:
- #
- # class OctalListener
- # def on_integer_node_enter(node)
- # if node.octal? && !node.slice.start_with?("0o")
- # warn("Octal integers should be written with the 0o prefix")
- # end
- # end
- # end
- #
- # dispatcher = Dispatcher.new
- # dispatcher.register(listener, :on_integer_node_enter)
- #
- # Then, you can walk any number of trees and dispatch events to the listeners:
- #
- # result = Prism.parse("001 + 002 + 003")
- # dispatcher.dispatch(result.value)
- #
- # Optionally, you can also use `#dispatch_once` to dispatch enter and leave
- # events for a single node without recursing further down the tree. This can
- # be useful in circumstances where you want to reuse the listeners you already
- # have registers but want to stop walking the tree at a certain point.
- #
- # integer = result.value.statements.body.first.receiver.receiver
- # dispatcher.dispatch_once(integer)
- #
- class Dispatcher < Visitor
- # attr_reader listeners: Hash[Symbol, Array[Listener]]
- attr_reader :listeners
-
- # Initialize a new dispatcher.
- def initialize
- @listeners = {}
- end
-
- # Register a listener for one or more events.
- #
- # def register: (Listener, *Symbol) -> void
- def register(listener, *events)
- events.each { |event| (listeners[event] ||= []) << listener }
- end
-
- # Walks `root` dispatching events to all registered listeners.
- #
- # def dispatch: (Node) -> void
- alias dispatch visit
-
- # Dispatches a single event for `node` to all registered listeners.
- #
- # def dispatch_once: (Node) -> void
- def dispatch_once(node)
- node.accept(DispatchOnce.new(listeners))
- end
- <%- nodes.each do |node| -%>
-
- # Dispatch enter and leave events for <%= node.name %> nodes and continue
- # walking the tree.
- def visit_<%= node.human %>(node)
- listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
- super
- listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
- end
- <%- end -%>
-
- class DispatchOnce < Visitor # :nodoc:
- attr_reader :listeners
-
- def initialize(listeners)
- @listeners = listeners
- end
- <%- nodes.each do |node| -%>
-
- # Dispatch enter and leave events for <%= node.name %> nodes.
- def visit_<%= node.human %>(node)
- listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
- listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
- end
- <%- end -%>
- end
-
- private_constant :DispatchOnce
- end
-end
diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb
deleted file mode 100644
index be18ad45ba..0000000000
--- a/prism/templates/lib/prism/dsl.rb.erb
+++ /dev/null
@@ -1,45 +0,0 @@
-module Prism
- # The DSL module provides a set of methods that can be used to create prism
- # nodes in a more concise manner. For example, instead of writing:
- #
- # source = Prism::Source.new("[1]")
- #
- # Prism::ArrayNode.new(
- # [
- # Prism::IntegerNode.new(
- # Prism::IntegerBaseFlags::DECIMAL,
- # Prism::Location.new(source, 1, 1),
- # )
- # ],
- # Prism::Location.new(source, 0, 1),
- # Prism::Location.new(source, 2, 1)
- # )
- #
- # you could instead write:
- #
- # source = Prism::Source.new("[1]")
- #
- # ArrayNode(
- # IntegerNode(Prism::IntegerBaseFlags::DECIMAL, Location(source, 1, 1))),
- # Location(source, 0, 1),
- # Location(source, 2, 1)
- # )
- #
- # This is mostly helpful in the context of writing tests, but can also be used
- # to generate trees programmatically.
- module DSL
- private
-
- # Create a new Location object
- def Location(source = nil, start_offset = 0, length = 0)
- Location.new(source, start_offset, length)
- end
- <%- nodes.each do |node| -%>
-
- # Create a new <%= node.name %> node
- def <%= node.name %>(<%= (node.fields.map(&:name) + ["location = Location()"]).join(", ") %>)
- <%= node.name %>.new(<%= (node.fields.map(&:name) + ["location"]).join(", ") %>)
- end
- <%- end -%>
- end
-end
diff --git a/prism/templates/lib/prism/mutation_compiler.rb.erb b/prism/templates/lib/prism/mutation_compiler.rb.erb
deleted file mode 100644
index 9a81b704eb..0000000000
--- a/prism/templates/lib/prism/mutation_compiler.rb.erb
+++ /dev/null
@@ -1,19 +0,0 @@
-module Prism
- # This visitor walks through the tree and copies each node as it is being
- # visited. This is useful for consumers that want to mutate the tree, as you
- # can change subtrees in place without effecting the rest of the tree.
- class MutationCompiler < Compiler
- <%- nodes.each_with_index do |node, index| -%>
-<%= "\n" if index != 0 -%>
- # Copy a <%= node.name %> node
- def visit_<%= node.human %>(node)
- <%- fields = node.fields.select { |field| [Prism::NodeField, Prism::OptionalNodeField, Prism::NodeListField].include?(field.class) } -%>
- <%- if fields.any? -%>
- node.copy(<%= fields.map { |field| "#{field.name}: #{field.is_a?(Prism::NodeListField) ? "visit_all" : "visit"}(node.#{field.name})" }.join(", ") %>)
- <%- else -%>
- node.copy
- <%- end -%>
- end
- <%- end -%>
- end
-end
diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb
deleted file mode 100644
index e41383a79b..0000000000
--- a/prism/templates/lib/prism/node.rb.erb
+++ /dev/null
@@ -1,249 +0,0 @@
-module Prism
- # This represents a node in the tree. It is the parent class of all of the
- # various node types.
- class Node
- # A Location instance that represents the location of this node in the
- # source.
- attr_reader :location
-
- def newline? # :nodoc:
- @newline ? true : false
- end
-
- def set_newline_flag(newline_marked) # :nodoc:
- line = location.start_line
- unless newline_marked[line]
- newline_marked[line] = true
- @newline = true
- end
- end
-
- # Slice the location of the node from the source.
- def slice
- location.slice
- end
-
- # Similar to inspect, but respects the current level of indentation given by
- # the pretty print object.
- def pretty_print(q)
- q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line|
- q.text(line.chomp)
- end
- q.current_group.break
- end
- end
- <%- nodes.each do |node| -%>
-
- <%- node.each_comment_line do |line| -%>
- #<%= line %>
- <%- end -%>
- class <%= node.name -%> < Node
- <%- node.fields.each do |field| -%>
- # attr_reader <%= field.name %>: <%= field.rbs_class %>
- <%= "private " if field.is_a?(Prism::FlagsField) %>attr_reader :<%= field.name %>
-
- <%- end -%>
- # def initialize: (<%= (node.fields.map { |field| "#{field.name}: #{field.rbs_class}" } + ["location: Location"]).join(", ") %>) -> void
- def initialize(<%= (node.fields.map(&:name) + ["location"]).join(", ") %>)
- <%- node.fields.each do |field| -%>
- @<%= field.name %> = <%= field.name %>
- <%- end -%>
- @location = location
- end
-
- # def accept: (visitor: Visitor) -> void
- def accept(visitor)
- visitor.visit_<%= node.human %>(self)
- end
- <%- if node.newline == false -%>
-
- def set_newline_flag(newline_marked) # :nodoc:
- # Never mark <%= node.name %> with a newline flag, mark children instead
- end
- <%- elsif node.newline.is_a?(String) -%>
-
- def set_newline_flag(newline_marked) # :nodoc:
- <%- field = node.fields.find { |f| f.name == node.newline } or raise node.newline -%>
- <%- case field -%>
- <%- when Prism::NodeField, Prism::OptionalNodeField -%>
- <%= field.name %>.set_newline_flag(newline_marked)
- <%- when Prism::NodeListField -%>
- first = <%= field.name %>.first
- first.set_newline_flag(newline_marked) if first
- <%- else raise field.class.name -%>
- <%- end -%>
- end
- <%- end -%>
-
- # def child_nodes: () -> Array[nil | Node]
- def child_nodes
- [<%= node.fields.map { |field|
- case field
- when Prism::NodeField, Prism::OptionalNodeField then field.name
- when Prism::NodeListField then "*#{field.name}"
- end
- }.compact.join(", ") %>]
- end
-
- # def compact_child_nodes: () -> Array[Node]
- def compact_child_nodes
- <%- if node.fields.any? { |field| field.is_a?(Prism::OptionalNodeField) } -%>
- compact = []
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::NodeField -%>
- compact << <%= field.name %>
- <%- when Prism::OptionalNodeField -%>
- compact << <%= field.name %> if <%= field.name %>
- <%- when Prism::NodeListField -%>
- compact.concat(<%= field.name %>)
- <%- end -%>
- <%- end -%>
- compact
- <%- else -%>
- [<%= node.fields.map { |field|
- case field
- when Prism::NodeField then field.name
- when Prism::NodeListField then "*#{field.name}"
- end
- }.compact.join(", ") %>]
- <%- end -%>
- end
-
- # def comment_targets: () -> Array[Node | Location]
- def comment_targets
- [<%= node.fields.map { |field|
- case field
- when Prism::NodeField, Prism::LocationField then field.name
- when Prism::OptionalNodeField, Prism::NodeListField, Prism::OptionalLocationField then "*#{field.name}"
- end
- }.compact.join(", ") %>]
- end
-
- # def copy: (**params) -> <%= node.name %>
- def copy(**params)
- <%= node.name %>.new(
- <%- (node.fields.map(&:name) + ["location"]).map do |name| -%>
- params.fetch(:<%= name %>) { <%= name %> },
- <%- end -%>
- )
- end
-
- # def deconstruct: () -> Array[nil | Node]
- alias deconstruct child_nodes
-
- # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
- def deconstruct_keys(keys)
- { <%= (node.fields.map { |field| "#{field.name}: #{field.name}" } + ["location: location"]).join(", ") %> }
- end
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::LocationField -%>
- <%- raise unless field.name.end_with?("_loc") -%>
- <%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>
-
- # def <%= field.name.delete_suffix("_loc") %>: () -> String
- def <%= field.name.delete_suffix("_loc") %>
- <%= field.name %>.slice
- end
- <%- when Prism::OptionalLocationField -%>
- <%- raise unless field.name.end_with?("_loc") -%>
- <%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>
-
- # def <%= field.name.delete_suffix("_loc") %>: () -> String?
- def <%= field.name.delete_suffix("_loc") %>
- <%= field.name %>&.slice
- end
- <%- when Prism::FlagsField -%>
- <%- flags.find { |flag| flag.name == field.kind }.tap { |flag| raise "Expected to find #{field.kind}" unless flag }.values.each do |value| -%>
-
- # def <%= value.name.downcase %>?: () -> bool
- def <%= value.name.downcase %>?
- <%= field.name %>.anybits?(<%= field.kind %>::<%= value.name %>)
- end
- <%- end -%>
- <%- end -%>
- <%- end -%>
-
- # def inspect(inspector: NodeInspector) -> String
- def inspect(inspector = NodeInspector.new)
- inspector << inspector.header(self)
- <%- node.fields.each_with_index do |field, index| -%>
- <%- pointer, preadd = index == node.fields.length - 1 ? ["└── ", " "] : ["├── ", "│ "] -%>
- <%- case field -%>
- <%- when Prism::NodeListField -%>
- inspector << "<%= pointer %><%= field.name %>: #{inspector.list("#{inspector.prefix}<%= preadd %>", <%= field.name %>)}"
- <%- when Prism::ConstantListField -%>
- inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
- <%- when Prism::NodeField -%>
- inspector << "<%= pointer %><%= field.name %>:\n"
- inspector << inspector.child_node(<%= field.name %>, "<%= preadd %>")
- <%- when Prism::OptionalNodeField -%>
- if (<%= field.name %> = self.<%= field.name %>).nil?
- inspector << "<%= pointer %><%= field.name %>: ∅\n"
- else
- inspector << "<%= pointer %><%= field.name %>:\n"
- inspector << <%= field.name %>.inspect(inspector.child_inspector("<%= preadd %>")).delete_prefix(inspector.prefix)
- end
- <%- when Prism::ConstantField, Prism::StringField, Prism::UInt32Field -%>
- inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
- <%- when Prism::OptionalConstantField -%>
- if (<%= field.name %> = self.<%= field.name %>).nil?
- inspector << "<%= pointer %><%= field.name %>: ∅\n"
- else
- inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
- end
- <%- when Prism::FlagsField -%>
- <%- flag = flags.find { |flag| flag.name == field.kind }.tap { |flag| raise unless flag } -%>
- flags = [<%= flag.values.map { |value| "(\"#{value.name.downcase}\" if #{value.name.downcase}?)" }.join(", ") %>].compact
- inspector << "<%= pointer %><%= field.name %>: #{flags.empty? ? "∅" : flags.join(", ")}\n"
- <%- when Prism::LocationField, Prism::OptionalLocationField -%>
- inspector << "<%= pointer %><%= field.name %>: #{inspector.location(<%= field.name %>)}\n"
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- inspector.to_str
- end
-
- # Sometimes you want to check an instance of a node against a list of
- # classes to see what kind of behavior to perform. Usually this is done by
- # calling `[cls1, cls2].include?(node.class)` or putting the node into a
- # case statement and doing `case node; when cls1; when cls2; end`. Both of
- # these approaches are relatively slow because of the constant lookups,
- # method calls, and/or array allocations.
- #
- # Instead, you can call #type, which will return to you a symbol that you
- # can use for comparison. This is faster than the other approaches because
- # it uses a single integer comparison, but also because if you're on CRuby
- # you can take advantage of the fact that case statements with all symbol
- # keys will use a jump table.
- #
- # def type: () -> Symbol
- def type
- :<%= node.human %>
- end
-
- # Similar to #type, this method returns a symbol that you can use for
- # splitting on the type of the node without having to do a long === chain.
- # Note that like #type, it will still be slower than using == for a single
- # class, but should be faster in a case statement or an array comparison.
- #
- # def self.type: () -> Symbol
- def self.type
- :<%= node.human %>
- end
- end
- <%- end -%>
- <%- flags.each_with_index do |flag, flag_index| -%>
-
- # <%= flag.comment %>
- module <%= flag.name %>
- <%- flag.values.each_with_index do |value, index| -%>
- # <%= value.comment %>
- <%= value.name %> = 1 << <%= index %>
-<%= "\n" if value != flag.values.last -%>
- <%- end -%>
- end
- <%- end -%>
-end
diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb
deleted file mode 100644
index 2837504543..0000000000
--- a/prism/templates/lib/prism/serialize.rb.erb
+++ /dev/null
@@ -1,308 +0,0 @@
-require "stringio"
-
-# Polyfill for String#unpack1 with the offset parameter.
-if String.instance_method(:unpack1).parameters.none? { |_, name| name == :offset }
- String.prepend(
- Module.new {
- def unpack1(format, offset: 0) # :nodoc:
- offset == 0 ? super(format) : self[offset..].unpack1(format)
- end
- }
- )
-end
-
-module Prism
- # A module responsible for deserializing parse results.
- module Serialize
- # The major version of prism that we are expecting to find in the serialized
- # strings.
- MAJOR_VERSION = 0
-
- # The minor version of prism that we are expecting to find in the serialized
- # strings.
- MINOR_VERSION = 17
-
- # The patch version of prism that we are expecting to find in the serialized
- # strings.
- PATCH_VERSION = 1
-
- # Deserialize the AST represented by the given string into a parse result.
- def self.load(input, serialized)
- input = input.dup
- source = Source.new(input)
- loader = Loader.new(source, serialized)
- result = loader.load_result
-
- input.force_encoding(loader.encoding)
- result
- end
-
- # Deserialize the tokens represented by the given string into a parse
- # result.
- def self.load_tokens(source, serialized)
- Loader.new(source, serialized).load_tokens_result
- end
-
- class Loader # :nodoc:
- attr_reader :encoding, :input, :serialized, :io
- attr_reader :constant_pool_offset, :constant_pool, :source
- attr_reader :start_line
-
- def initialize(source, serialized)
- @encoding = Encoding::UTF_8
-
- @input = source.source.dup
- @serialized = serialized
- @io = StringIO.new(serialized)
- @io.set_encoding(Encoding::BINARY)
-
- @constant_pool_offset = nil
- @constant_pool = nil
-
- @source = source
- define_load_node_lambdas unless RUBY_ENGINE == "ruby"
- end
-
- def load_header
- raise "Invalid serialization" if io.read(5) != "PRISM"
- raise "Invalid serialization" if io.read(3).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
- only_semantic_fields = io.read(1).unpack1("C")
- unless only_semantic_fields == 0
- raise "Invalid serialization (location fields must be included but are not)"
- end
- end
-
- def load_encoding
- Encoding.find(io.read(load_varint))
- end
-
- def load_force_encoding
- @encoding = load_encoding
- @input = input.force_encoding(@encoding).freeze
- end
-
- def load_start_line
- source.start_line = load_varint
- end
-
- def load_comments
- load_varint.times.map do
- case load_varint
- when 0 then InlineComment.new(load_location)
- when 1 then EmbDocComment.new(load_location)
- when 2 then DATAComment.new(load_location)
- end
- end
- end
-
- def load_metadata
- comments = load_comments
- magic_comments = load_varint.times.map { MagicComment.new(load_location, load_location) }
- errors = load_varint.times.map { ParseError.new(load_embedded_string, load_location) }
- warnings = load_varint.times.map { ParseWarning.new(load_embedded_string, load_location) }
- [comments, magic_comments, errors, warnings]
- end
-
- def load_tokens
- tokens = []
- while type = TOKEN_TYPES.fetch(load_varint)
- start = load_varint
- length = load_varint
- lex_state = load_varint
- location = Location.new(@source, start, length)
- tokens << [Prism::Token.new(type, location.slice, location), lex_state]
- end
-
- tokens
- end
-
- def load_tokens_result
- tokens = load_tokens
- encoding = load_encoding
- load_start_line
- comments, magic_comments, errors, warnings = load_metadata
-
- if encoding != @encoding
- tokens.each { |token,| token.value.force_encoding(encoding) }
- end
-
- raise "Expected to consume all bytes while deserializing" unless @io.eof?
- Prism::ParseResult.new(tokens, comments, magic_comments, errors, warnings, @source)
- end
-
- def load_nodes
- load_header
- load_force_encoding
- load_start_line
-
- comments, magic_comments, errors, warnings = load_metadata
-
- @constant_pool_offset = io.read(4).unpack1("L")
- @constant_pool = Array.new(load_varint, nil)
-
- [load_node, comments, magic_comments, errors, warnings]
- end
-
- def load_result
- node, comments, magic_comments, errors, warnings = load_nodes
- Prism::ParseResult.new(node, comments, magic_comments, errors, warnings, @source)
- end
-
- private
-
- # variable-length integer using https://en.wikipedia.org/wiki/LEB128
- # This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints
- def load_varint
- n = io.getbyte
- if n < 128
- n
- else
- n -= 128
- shift = 0
- while (b = io.getbyte) >= 128
- n += (b - 128) << (shift += 7)
- end
- n + (b << (shift + 7))
- end
- end
-
- def load_serialized_length
- io.read(4).unpack1("L")
- end
-
- def load_optional_node
- if io.getbyte != 0
- io.pos -= 1
- load_node
- end
- end
-
- def load_embedded_string
- io.read(load_varint).force_encoding(encoding)
- end
-
- def load_string
- type = io.getbyte
- case type
- when 1
- input.byteslice(load_varint, load_varint).force_encoding(encoding)
- when 2
- load_embedded_string
- else
- raise "Unknown serialized string type: #{type}"
- end
- end
-
- def load_location
- Location.new(source, load_varint, load_varint)
- end
-
- def load_optional_location
- load_location if io.getbyte != 0
- end
-
- def load_constant(index)
- constant = constant_pool[index]
-
- unless constant
- offset = constant_pool_offset + index * 8
- start = serialized.unpack1("L", offset: offset)
- length = serialized.unpack1("L", offset: offset + 4)
-
- constant =
- if start.nobits?(1 << 31)
- input.byteslice(start, length).to_sym
- else
- serialized.byteslice(start & ((1 << 31) - 1), length).to_sym
- end
-
- constant_pool[index] = constant
- end
-
- constant
- end
-
- def load_required_constant
- load_constant(load_varint - 1)
- end
-
- def load_optional_constant
- index = load_varint
- load_constant(index - 1) if index != 0
- end
-
- if RUBY_ENGINE == 'ruby'
- def load_node
- type = io.getbyte
- location = load_location
-
- case type
- <%- nodes.each_with_index do |node, index| -%>
- when <%= index + 1 %> then
- <%- if node.needs_serialized_length? -%>
- load_serialized_length
- <%- end -%>
- <%= node.name %>.new(<%= (node.fields.map { |field|
- case field
- when Prism::NodeField then "load_node"
- when Prism::OptionalNodeField then "load_optional_node"
- when Prism::StringField then "load_string"
- when Prism::NodeListField then "Array.new(load_varint) { load_node }"
- when Prism::ConstantField then "load_required_constant"
- when Prism::OptionalConstantField then "load_optional_constant"
- when Prism::ConstantListField then "Array.new(load_varint) { load_required_constant }"
- when Prism::LocationField then "load_location"
- when Prism::OptionalLocationField then "load_optional_location"
- when Prism::UInt32Field, Prism::FlagsField then "load_varint"
- else raise
- end
- } + ["location"]).join(", ") -%>)
- <%- end -%>
- end
- end
- else
- def load_node
- type = io.getbyte
- @load_node_lambdas[type].call
- end
-
- def define_load_node_lambdas
- @load_node_lambdas = [
- nil,
- <%- nodes.each do |node| -%>
- -> {
- location = load_location
- <%- if node.needs_serialized_length? -%>
- load_serialized_length
- <%- end -%>
- <%= node.name %>.new(<%= (node.fields.map { |field|
- case field
- when Prism::NodeField then "load_node"
- when Prism::OptionalNodeField then "load_optional_node"
- when Prism::StringField then "load_string"
- when Prism::NodeListField then "Array.new(load_varint) { load_node }"
- when Prism::ConstantField then "load_required_constant"
- when Prism::OptionalConstantField then "load_optional_constant"
- when Prism::ConstantListField then "Array.new(load_varint) { load_required_constant }"
- when Prism::LocationField then "load_location"
- when Prism::OptionalLocationField then "load_optional_location"
- when Prism::UInt32Field, Prism::FlagsField then "load_varint"
- else raise
- end
- } + ["location"]).join(", ") -%>)
- },
- <%- end -%>
- ]
- end
- end
- end
-
- # The token types that can be indexed by their enum values.
- TOKEN_TYPES = [
- nil,
- <%- tokens.each do |token| -%>
- <%= token.name.to_sym.inspect %>,
- <%- end -%>
- ]
- end
-end
diff --git a/prism/templates/lib/prism/visitor.rb.erb b/prism/templates/lib/prism/visitor.rb.erb
deleted file mode 100644
index 04156cc7a9..0000000000
--- a/prism/templates/lib/prism/visitor.rb.erb
+++ /dev/null
@@ -1,50 +0,0 @@
-module Prism
- # A class that knows how to walk down the tree. None of the individual visit
- # methods are implemented on this visitor, so it forces the consumer to
- # implement each one that they need. For a default implementation that
- # continues walking the tree, see the Visitor class.
- class BasicVisitor
- # Calls `accept` on the given node if it is not `nil`, which in turn should
- # call back into this visitor by calling the appropriate `visit_*` method.
- def visit(node)
- node&.accept(self)
- end
-
- # Visits each node in `nodes` by calling `accept` on each one.
- def visit_all(nodes)
- nodes.each { |node| node&.accept(self) }
- end
-
- # Visits the child nodes of `node` by calling `accept` on each one.
- def visit_child_nodes(node)
- node.compact_child_nodes.each { |node| node.accept(self) }
- end
- end
-
- # A visitor is a class that provides a default implementation for every accept
- # method defined on the nodes. This means it can walk a tree without the
- # caller needing to define any special handling. This allows you to handle a
- # subset of the tree, while still walking the whole tree.
- #
- # For example, to find all of the method calls that call the `foo` method, you
- # could write:
- #
- # class FooCalls < Prism::Visitor
- # def visit_call_node(node)
- # if node.name == "foo"
- # # Do something with the node
- # end
- #
- # # Call super so that the visitor continues walking the tree
- # super
- # end
- # end
- #
- class Visitor < BasicVisitor
- <%- nodes.each_with_index do |node, index| -%>
-<%= "\n" if index != 0 -%>
- # Visit a <%= node.name %> node
- alias visit_<%= node.human %> visit_child_nodes
- <%- end -%>
- end
-end
diff --git a/prism/templates/src/node.c.erb b/prism/templates/src/node.c.erb
deleted file mode 100644
index 0f3a6d8af2..0000000000
--- a/prism/templates/src/node.c.erb
+++ /dev/null
@@ -1,162 +0,0 @@
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
-#include "prism/node.h"
-
-static void
-pm_node_memsize_node(pm_node_t *node, pm_memsize_t *memsize);
-
-/**
- * Calculate the size of the node list in bytes.
- */
-static size_t
-pm_node_list_memsize(pm_node_list_t *node_list, pm_memsize_t *memsize) {
- size_t size = sizeof(pm_node_list_t) + (node_list->capacity * sizeof(pm_node_t *));
- for (size_t index = 0; index < node_list->size; index++) {
- pm_node_memsize_node(node_list->nodes[index], memsize);
- }
- return size;
-}
-
-/**
- * Append a new node onto the end of the node list.
- */
-void
-pm_node_list_append(pm_node_list_t *list, pm_node_t *node) {
- if (list->size == list->capacity) {
- list->capacity = list->capacity == 0 ? 4 : list->capacity * 2;
- list->nodes = (pm_node_t **) realloc(list->nodes, sizeof(pm_node_t *) * list->capacity);
- }
- list->nodes[list->size++] = node;
-}
-
-PRISM_EXPORTED_FUNCTION void
-pm_node_destroy(pm_parser_t *parser, pm_node_t *node);
-
-/**
- * Deallocate the inner memory of a list of nodes. The parser argument is not
- * used, but is here for the future possibility of pre-allocating memory pools.
- */
-static void
-pm_node_list_free(pm_parser_t *parser, pm_node_list_t *list) {
- if (list->capacity > 0) {
- for (size_t index = 0; index < list->size; index++) {
- pm_node_destroy(parser, list->nodes[index]);
- }
- free(list->nodes);
- }
-}
-
-/**
- * Deallocate the space for a pm_node_t. Similarly to pm_node_alloc, we're not
- * using the parser argument, but it's there to allow for the future possibility
- * of pre-allocating larger memory pools.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_node_destroy(pm_parser_t *parser, pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- <%- if node.fields.any? { |field| ![Prism::LocationField, Prism::OptionalLocationField, Prism::UInt32Field, Prism::FlagsField, Prism::ConstantField, Prism::OptionalConstantField].include?(field.class) } -%>
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- end -%>
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::LocationField, Prism::OptionalLocationField, Prism::UInt32Field, Prism::FlagsField, Prism::ConstantField, Prism::OptionalConstantField -%>
- <%- when Prism::NodeField -%>
- pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>);
- <%- when Prism::OptionalNodeField -%>
- if (cast-><%= field.name %> != NULL) {
- pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>);
- }
- <%- when Prism::StringField -%>
- pm_string_free(&cast-><%= field.name %>);
- <%- when Prism::NodeListField -%>
- pm_node_list_free(parser, &cast-><%= field.name %>);
- <%- when Prism::ConstantListField -%>
- pm_constant_id_list_free(&cast-><%= field.name %>);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- break;
- }
- <%- end -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- default:
- assert(false && "unreachable");
- break;
- }
- free(node);
-}
-
-static void
-pm_node_memsize_node(pm_node_t *node, pm_memsize_t *memsize) {
- memsize->node_count++;
-
- switch (PM_NODE_TYPE(node)) {
- // We do not calculate memsize of a ScopeNode
- // as it should never be generated
- case PM_SCOPE_NODE:
- return;
- <%- nodes.each do |node| -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- memsize->memsize += sizeof(*cast);
- <%- if node.fields.any? { |f| f.is_a?(Prism::NodeListField) } -%>
- // Node lists will add in their own sizes below.
- memsize->memsize -= sizeof(pm_node_list_t) * <%= node.fields.count { |f| f.is_a?(Prism::NodeListField) } %>;
- <%- end -%>
- <%- if node.fields.any? { |f| f.is_a?(Prism::ConstantListField) } -%>
- // Constant id lists will add in their own sizes below.
- memsize->memsize -= sizeof(pm_constant_id_list_t) * <%= node.fields.count { |f| f.is_a?(Prism::ConstantListField) } %>;
- <%- end -%>
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::ConstantField, Prism::OptionalConstantField, Prism::UInt32Field, Prism::FlagsField, Prism::LocationField, Prism::OptionalLocationField -%>
- <%- when Prism::NodeField -%>
- pm_node_memsize_node((pm_node_t *)cast-><%= field.name %>, memsize);
- <%- when Prism::OptionalNodeField -%>
- if (cast-><%= field.name %> != NULL) {
- pm_node_memsize_node((pm_node_t *)cast-><%= field.name %>, memsize);
- }
- <%- when Prism::StringField -%>
- memsize->memsize += pm_string_memsize(&cast-><%= field.name %>);
- <%- when Prism::NodeListField -%>
- memsize->memsize += pm_node_list_memsize(&cast-><%= field.name %>, memsize);
- <%- when Prism::ConstantListField -%>
- memsize->memsize += pm_constant_id_list_memsize(&cast-><%= field.name %>);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- break;
- }
- <%- end -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- }
-}
-
-/**
- * Calculates the memory footprint of a given node.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_node_memsize(pm_node_t *node, pm_memsize_t *memsize) {
- *memsize = (pm_memsize_t) { .memsize = 0, .node_count = 0 };
- pm_node_memsize_node(node, memsize);
-}
-
-/**
- * Returns a string representation of the given node type.
- */
-PRISM_EXPORTED_FUNCTION const char *
-pm_node_type_to_str(pm_node_type_t node_type)
-{
- switch (node_type) {
-<%- nodes.each do |node| -%>
- case <%= node.type %>:
- return "<%= node.type %>";
-<%- end -%>
- }
- return "";
-}
diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb
deleted file mode 100644
index d5bf196e0b..0000000000
--- a/prism/templates/src/prettyprint.c.erb
+++ /dev/null
@@ -1,188 +0,0 @@
-#include "prism/prettyprint.h"
-
-static void
-prettyprint_source(pm_buffer_t *output_buffer, const uint8_t *source, size_t length) {
- for (size_t index = 0; index < length; index++) {
- const uint8_t byte = source[index];
-
- if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
- pm_buffer_append_format(output_buffer, "\\x%02X", byte);
- } else {
- switch (byte) {
- case '\a': pm_buffer_append_string(output_buffer, "\\a", 2); break;
- case '\b': pm_buffer_append_string(output_buffer, "\\b", 2); break;
- case '\t': pm_buffer_append_string(output_buffer, "\\t", 2); break;
- case '\n': pm_buffer_append_string(output_buffer, "\\n", 2); break;
- case '\v': pm_buffer_append_string(output_buffer, "\\v", 2); break;
- case '\f': pm_buffer_append_string(output_buffer, "\\f", 2); break;
- case '\r': pm_buffer_append_string(output_buffer, "\\r", 2); break;
- case '"': pm_buffer_append_string(output_buffer, "\\\"", 2); break;
- case '#': {
- if (index + 1 < length) {
- const uint8_t next_byte = source[index + 1];
- if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
- pm_buffer_append_byte(output_buffer, '\\');
- }
- }
-
- pm_buffer_append_byte(output_buffer, '#');
- break;
- }
- case '\\': pm_buffer_append_string(output_buffer, "\\\\", 2); break;
- default: pm_buffer_append_byte(output_buffer, byte); break;
- }
- }
- }
-}
-
-static inline void
-prettyprint_location(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_location_t *location) {
- pm_line_column_t start = pm_newline_list_line_column(&parser->newline_list, location->start);
- pm_line_column_t end = pm_newline_list_line_column(&parser->newline_list, location->end);
- pm_buffer_append_format(output_buffer, "(%lu,%lu)-(%lu,%lu)", (unsigned long) (start.line + 1), (unsigned long) start.column, (unsigned long) (end.line + 1), (unsigned long) end.column);
-}
-
-static inline void
-prettyprint_constant(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_constant_id_t constant_id) {
- pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
- pm_buffer_append_format(output_buffer, ":%.*s", (int) constant->length, constant->start);
-}
-
-static void
-prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node, pm_buffer_t *prefix_buffer) {
- switch (PM_NODE_TYPE(node)) {
- case PM_SCOPE_NODE:
- // We do not need to print a ScopeNode as it's not part of the AST.
- return;
- <%- nodes.each do |node| -%>
- case <%= node.type %>: {
- <%- if node.fields.any? -%>
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- end -%>
- pm_buffer_append_string(output_buffer, "@ <%= node.name %> (location: ", <%= node.name.length + 14 %>);
- prettyprint_location(output_buffer, parser, &node->location);
- pm_buffer_append_string(output_buffer, ")\n", 2);
- <%- node.fields.each_with_index do |field, index| -%>
- <%- pointer, preadd = index == node.fields.length - 1 ? ["└── ", " "] : ["├── ", "│ "] -%>
-
- // <%= field.name %>
- {
- pm_buffer_concat(output_buffer, prefix_buffer);
- pm_buffer_append_string(output_buffer, "<%= pointer %><%= field.name %>:", <%= pointer.bytesize + field.name.length + 1 %>);
- <%- case field -%>
- <%- when Prism::NodeField -%>
- pm_buffer_append_byte(output_buffer, '\n');
-
- size_t prefix_length = prefix_buffer->length;
- pm_buffer_append_string(prefix_buffer, "<%= preadd %>", <%= preadd.bytesize %>);
- pm_buffer_concat(output_buffer, prefix_buffer);
- prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>, prefix_buffer);
- prefix_buffer->length = prefix_length;
- <%- when Prism::OptionalNodeField -%>
- if (cast-><%= field.name %> == NULL) {
- pm_buffer_append_string(output_buffer, " ∅\n", 5);
- } else {
- pm_buffer_append_byte(output_buffer, '\n');
-
- size_t prefix_length = prefix_buffer->length;
- pm_buffer_append_string(prefix_buffer, "<%= preadd %>", <%= preadd.bytesize %>);
- pm_buffer_concat(output_buffer, prefix_buffer);
- prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>, prefix_buffer);
- prefix_buffer->length = prefix_length;
- }
- <%- when Prism::StringField -%>
- pm_buffer_append_string(output_buffer, " \"", 2);
- prettyprint_source(output_buffer, pm_string_source(&cast-><%= field.name %>), pm_string_length(&cast-><%= field.name %>));
- pm_buffer_append_string(output_buffer, "\"\n", 2);
- <%- when Prism::NodeListField -%>
- pm_buffer_append_format(output_buffer, " (length: %lu)\n", (unsigned long) (cast-><%= field.name %>.size));
-
- size_t last_index = cast-><%= field.name %>.size;
- for (uint32_t index = 0; index < last_index; index++) {
- size_t prefix_length = prefix_buffer->length;
- pm_buffer_append_string(prefix_buffer, "<%= preadd %>", <%= preadd.bytesize %>);
- pm_buffer_concat(output_buffer, prefix_buffer);
-
- if (index == last_index - 1) {
- pm_buffer_append_string(output_buffer, "└── ", 10);
- pm_buffer_append_string(prefix_buffer, " ", 4);
- } else {
- pm_buffer_append_string(output_buffer, "├── ", 10);
- pm_buffer_append_string(prefix_buffer, "│ ", 6);
- }
-
- prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>.nodes[index], prefix_buffer);
- prefix_buffer->length = prefix_length;
- }
- <%- when Prism::ConstantField -%>
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_constant(output_buffer, parser, cast-><%= field.name %>);
- pm_buffer_append_byte(output_buffer, '\n');
- <%- when Prism::OptionalConstantField -%>
- if (cast-><%= field.name %> == 0) {
- pm_buffer_append_string(output_buffer, " ∅\n", 5);
- } else {
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_constant(output_buffer, parser, cast-><%= field.name %>);
- pm_buffer_append_byte(output_buffer, '\n');
- }
- <%- when Prism::ConstantListField -%>
- pm_buffer_append_string(output_buffer, " [", 2);
- for (uint32_t index = 0; index < cast-><%= field.name %>.size; index++) {
- if (index != 0) pm_buffer_append_string(output_buffer, ", ", 2);
- prettyprint_constant(output_buffer, parser, cast-><%= field.name %>.ids[index]);
- }
- pm_buffer_append_string(output_buffer, "]\n", 2);
- <%- when Prism::LocationField -%>
- pm_location_t *location = &cast-><%= field.name %>;
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_location(output_buffer, parser, location);
- pm_buffer_append_string(output_buffer, " = \"", 4);
- prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start));
- pm_buffer_append_string(output_buffer, "\"\n", 2);
- <%- when Prism::OptionalLocationField -%>
- pm_location_t *location = &cast-><%= field.name %>;
- if (location->start == NULL) {
- pm_buffer_append_string(output_buffer, " ∅\n", 5);
- } else {
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_location(output_buffer, parser, location);
- pm_buffer_append_string(output_buffer, " = \"", 4);
- prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start));
- pm_buffer_append_string(output_buffer, "\"\n", 2);
- }
- <%- when Prism::UInt32Field -%>
- pm_buffer_append_format(output_buffer, " %d\n", cast-><%= field.name %>);
- <%- when Prism::FlagsField -%>
- bool found = false;
- <%- found = flags.find { |flag| flag.name == field.kind }.tap { |found| raise "Expected to find #{field.kind}" unless found } -%>
- <%- found.values.each do |value| -%>
- if (cast->base.<%= field.name %> & PM_<%= found.human.upcase %>_<%= value.name %>) {
- if (found) pm_buffer_append_byte(output_buffer, ',');
- pm_buffer_append_string(output_buffer, " <%= value.name.downcase %>", <%= value.name.bytesize + 1 %>);
- found = true;
- }
- <%- end -%>
- if (!found) pm_buffer_append_string(output_buffer, " ∅", 4);
- pm_buffer_append_byte(output_buffer, '\n');
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- }
- <%- end -%>
-
- break;
- }
- <%- end -%>
- }
-}
-
-/**
- * Pretty-prints the AST represented by the given node to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node) {
- pm_buffer_t prefix_buffer = { 0 };
- prettyprint_node(output_buffer, parser, node, &prefix_buffer);
- pm_buffer_free(&prefix_buffer);
-}
diff --git a/prism/templates/src/serialize.c.erb b/prism/templates/src/serialize.c.erb
deleted file mode 100644
index db4c91e0cd..0000000000
--- a/prism/templates/src/serialize.c.erb
+++ /dev/null
@@ -1,347 +0,0 @@
-#include "prism.h"
-
-#include <stdio.h>
-
-static inline uint32_t
-pm_ptrdifft_to_u32(ptrdiff_t value) {
- assert(value >= 0 && ((unsigned long) value) < UINT32_MAX);
- return (uint32_t) value;
-}
-
-static inline uint32_t
-pm_sizet_to_u32(size_t value) {
- assert(value < UINT32_MAX);
- return (uint32_t) value;
-}
-
-static void
-pm_serialize_location(pm_parser_t *parser, pm_location_t *location, pm_buffer_t *buffer) {
- assert(location->start);
- assert(location->end);
- assert(location->start <= location->end);
-
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(location->start - parser->start));
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(location->end - location->start));
-}
-
-static void
-pm_serialize_string(pm_parser_t *parser, pm_string_t *string, pm_buffer_t *buffer) {
- switch (string->type) {
- case PM_STRING_SHARED: {
- pm_buffer_append_byte(buffer, 1);
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(pm_string_source(string) - parser->start));
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(pm_string_length(string)));
- break;
- }
- case PM_STRING_OWNED:
- case PM_STRING_CONSTANT: {
- uint32_t length = pm_sizet_to_u32(pm_string_length(string));
- pm_buffer_append_byte(buffer, 2);
- pm_buffer_append_varint(buffer, length);
- pm_buffer_append_bytes(buffer, pm_string_source(string), length);
- break;
- }
- case PM_STRING_MAPPED:
- assert(false && "Cannot serialize mapped strings.");
- break;
- }
-}
-
-static void
-pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
- pm_buffer_append_byte(buffer, (uint8_t) PM_NODE_TYPE(node));
-
- size_t offset = buffer->length;
-
- pm_serialize_location(parser, &node->location, buffer);
-
- switch (PM_NODE_TYPE(node)) {
- // We do not need to serialize a ScopeNode ever as
- // it is not part of the AST
- case PM_SCOPE_NODE:
- return;
- <%- nodes.each do |node| -%>
- case <%= node.type %>: {
- <%- if node.needs_serialized_length? -%>
- // serialize length
- // encoding of location u32s make us need to save this offset.
- size_t length_offset = buffer->length;
- pm_buffer_append_string(buffer, "\0\0\0\0", 4); /* consume 4 bytes, updated below */
- <%- end -%>
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::NodeField -%>
- pm_serialize_node(parser, (pm_node_t *)((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- <%- when Prism::OptionalNodeField -%>
- if (((pm_<%= node.human %>_t *)node)-><%= field.name %> == NULL) {
- pm_buffer_append_byte(buffer, 0);
- } else {
- pm_serialize_node(parser, (pm_node_t *)((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- }
- <%- when Prism::StringField -%>
- pm_serialize_string(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- <%- when Prism::NodeListField -%>
- uint32_t <%= field.name %>_size = pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.size);
- pm_buffer_append_varint(buffer, <%= field.name %>_size);
- for (uint32_t index = 0; index < <%= field.name %>_size; index++) {
- pm_serialize_node(parser, (pm_node_t *) ((pm_<%= node.human %>_t *)node)-><%= field.name %>.nodes[index], buffer);
- }
- <%- when Prism::ConstantField, Prism::OptionalConstantField -%>
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>));
- <%- when Prism::ConstantListField -%>
- uint32_t <%= field.name %>_size = pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.size);
- pm_buffer_append_varint(buffer, <%= field.name %>_size);
- for (uint32_t index = 0; index < <%= field.name %>_size; index++) {
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.ids[index]));
- }
- <%- when Prism::LocationField -%>
- <%- if field.should_be_serialized? -%>
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- <%- end -%>
- <%- when Prism::OptionalLocationField -%>
- <%- if field.should_be_serialized? -%>
- if (((pm_<%= node.human %>_t *)node)-><%= field.name %>.start == NULL) {
- pm_buffer_append_byte(buffer, 0);
- } else {
- pm_buffer_append_byte(buffer, 1);
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- }
- <%- end -%>
- <%- when Prism::UInt32Field -%>
- pm_buffer_append_varint(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
- <%- when Prism::FlagsField -%>
- pm_buffer_append_varint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK));
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- <%- if node.needs_serialized_length? -%>
- // serialize length
- uint32_t length = pm_sizet_to_u32(buffer->length - offset - sizeof(uint32_t));
- memcpy(buffer->value + length_offset, &length, sizeof(uint32_t));
- <%- end -%>
- break;
- }
- <%- end -%>
- }
-}
-
-static void
-pm_serialize_comment(pm_parser_t *parser, pm_comment_t *comment, pm_buffer_t *buffer) {
- // serialize type
- pm_buffer_append_byte(buffer, (uint8_t) comment->type);
-
- // serialize location
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(comment->start - parser->start));
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(comment->end - comment->start));
-}
-
-/**
- * Serialize the given list of comments to the given buffer.
- */
-void
-pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(pm_list_size(list)));
-
- pm_comment_t *comment;
- for (comment = (pm_comment_t *) list->head; comment != NULL; comment = (pm_comment_t *) comment->node.next) {
- pm_serialize_comment(parser, comment, buffer);
- }
-}
-
-static void
-pm_serialize_magic_comment(pm_parser_t *parser, pm_magic_comment_t *magic_comment, pm_buffer_t *buffer) {
- // serialize key location
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(magic_comment->key_start - parser->start));
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(magic_comment->key_length));
-
- // serialize value location
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(magic_comment->value_start - parser->start));
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(magic_comment->value_length));
-}
-
-static void
-pm_serialize_magic_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(pm_list_size(list)));
-
- pm_magic_comment_t *magic_comment;
- for (magic_comment = (pm_magic_comment_t *) list->head; magic_comment != NULL; magic_comment = (pm_magic_comment_t *) magic_comment->node.next) {
- pm_serialize_magic_comment(parser, magic_comment, buffer);
- }
-}
-
-static void
-pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
- // serialize message
- size_t message_length = strlen(diagnostic->message);
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(message_length));
- pm_buffer_append_string(buffer, diagnostic->message, message_length);
-
- // serialize location
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(diagnostic->start - parser->start));
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(diagnostic->end - diagnostic->start));
-}
-
-static void
-pm_serialize_diagnostic_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(pm_list_size(list)));
-
- pm_diagnostic_t *diagnostic;
- for (diagnostic = (pm_diagnostic_t *) list->head; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
- pm_serialize_diagnostic(parser, diagnostic, buffer);
- }
-}
-
-/**
- * Serialize the name of the encoding to the buffer.
- */
-void
-pm_serialize_encoding(pm_encoding_t *encoding, pm_buffer_t *buffer) {
- size_t encoding_length = strlen(encoding->name);
- pm_buffer_append_varint(buffer, pm_sizet_to_u32(encoding_length));
- pm_buffer_append_string(buffer, encoding->name, encoding_length);
-}
-
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
-/**
- * Serialize the encoding, metadata, nodes, and constant pool.
- */
-void
-pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
- pm_serialize_encoding(&parser->encoding, buffer);
- pm_buffer_append_varint(buffer, parser->start_line);
-<%- unless Prism::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
- pm_serialize_comment_list(parser, &parser->comment_list, buffer);
-<%- end -%>
- pm_serialize_magic_comment_list(parser, &parser->magic_comment_list, buffer);
- pm_serialize_diagnostic_list(parser, &parser->error_list, buffer);
- pm_serialize_diagnostic_list(parser, &parser->warning_list, buffer);
-
- // Here we're going to leave space for the offset of the constant pool in
- // the buffer.
- size_t offset = buffer->length;
- pm_buffer_append_zeroes(buffer, 4);
-
- // Next, encode the length of the constant pool.
- pm_buffer_append_varint(buffer, parser->constant_pool.size);
-
- // Now we're going to serialize the content of the node.
- pm_serialize_node(parser, node, buffer);
-
- // Now we're going to serialize the offset of the constant pool back where
- // we left space for it.
- uint32_t length = pm_sizet_to_u32(buffer->length);
- memcpy(buffer->value + offset, &length, sizeof(uint32_t));
-
- // Now we're going to serialize the constant pool.
- offset = buffer->length;
- pm_buffer_append_zeroes(buffer, parser->constant_pool.size * 8);
-
- for (uint32_t index = 0; index < parser->constant_pool.capacity; index++) {
- pm_constant_pool_bucket_t *bucket = &parser->constant_pool.buckets[index];
-
- // If we find a constant at this index, serialize it at the correct
- // index in the buffer.
- if (bucket->id != 0) {
- pm_constant_t *constant = &parser->constant_pool.constants[bucket->id - 1];
- size_t buffer_offset = offset + ((((size_t)bucket->id) - 1) * 8);
-
- if (bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED || bucket->type == PM_CONSTANT_POOL_BUCKET_CONSTANT) {
- // Since this is an owned or constant constant, we are going to
- // write its contents into the buffer after the constant pool.
- // So effectively in place of the source offset, we have a
- // buffer offset. We will add a leading 1 to indicate that this
- // is a buffer offset.
- uint32_t content_offset = pm_sizet_to_u32(buffer->length);
- uint32_t owned_mask = (uint32_t) (1 << 31);
-
- assert(content_offset < owned_mask);
- content_offset |= owned_mask;
-
- memcpy(buffer->value + buffer_offset, &content_offset, 4);
- pm_buffer_append_bytes(buffer, constant->start, constant->length);
- } else {
- // Since this is a shared constant, we are going to write its
- // source offset directly into the buffer.
- uint32_t source_offset = pm_ptrdifft_to_u32(constant->start - parser->start);
- memcpy(buffer->value + buffer_offset, &source_offset, 4);
- }
-
- // Now we can write the length of the constant into the buffer.
- uint32_t constant_length = pm_sizet_to_u32(constant->length);
- memcpy(buffer->value + buffer_offset + 4, &constant_length, 4);
- }
- }
-}
-
-static void
-serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
- pm_buffer_t *buffer = (pm_buffer_t *) data;
-
- pm_buffer_append_varint(buffer, token->type);
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(token->start - parser->start));
- pm_buffer_append_varint(buffer, pm_ptrdifft_to_u32(token->end - token->start));
- pm_buffer_append_varint(buffer, parser->lex_state);
-}
-
-/**
- * Lex the given source and serialize to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- if (data != NULL) pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
- .data = (void *) buffer,
- .callback = serialize_token,
- };
-
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
-
- // Append 0 to mark end of tokens.
- pm_buffer_append_byte(buffer, 0);
-
- pm_serialize_encoding(&parser.encoding, buffer);
- pm_buffer_append_varint(buffer, parser.start_line);
- pm_serialize_comment_list(&parser, &parser.comment_list, buffer);
- pm_serialize_magic_comment_list(&parser, &parser.magic_comment_list, buffer);
- pm_serialize_diagnostic_list(&parser, &parser.error_list, buffer);
- pm_serialize_diagnostic_list(&parser, &parser.warning_list, buffer);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-/**
- * Parse and serialize both the AST and the tokens represented by the given
- * source to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- if (data != NULL) pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
- .data = (void *) buffer,
- .callback = serialize_token,
- };
-
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
-
- pm_buffer_append_byte(buffer, 0);
- pm_serialize(&parser, node, buffer);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
diff --git a/prism/templates/src/token_type.c.erb b/prism/templates/src/token_type.c.erb
deleted file mode 100644
index d3c1c3f1b8..0000000000
--- a/prism/templates/src/token_type.c.erb
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <string.h>
-
-#include "prism/ast.h"
-
-/**
- * Returns a string representation of the given token type.
- */
-PRISM_EXPORTED_FUNCTION const char *
-pm_token_type_to_str(pm_token_type_t token_type)
-{
- switch (token_type) {
-<%- tokens.each do |token| -%>
- case PM_TOKEN_<%= token.name %>:
- return "<%= token.name %>";
-<%- end -%>
- case PM_TOKEN_MAXIMUM:
- return "MAXIMUM";
- }
- return "\0";
-}
diff --git a/prism/templates/template.rb b/prism/templates/template.rb
deleted file mode 100755
index 8a9825dfc0..0000000000
--- a/prism/templates/template.rb
+++ /dev/null
@@ -1,449 +0,0 @@
-#!/usr/bin/env ruby
-
-require "erb"
-require "fileutils"
-require "yaml"
-
-module Prism
- SERIALIZE_ONLY_SEMANTICS_FIELDS = ENV.fetch("PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS", false)
-
- JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby"
- JAVA_STRING_TYPE = JAVA_BACKEND == "jruby" ? "org.jruby.RubySymbol" : "String"
-
- # This represents a field on a node. It contains all of the necessary
- # information to template out the code for that field.
- class Field
- attr_reader :name, :options
-
- def initialize(name:, type:, **options)
- @name, @type, @options = name, type, options
- end
-
- def semantic_field?
- true
- end
-
- def should_be_serialized?
- SERIALIZE_ONLY_SEMANTICS_FIELDS ? semantic_field? : true
- end
- end
-
- # Some node fields can be specialized if they point to a specific kind of
- # node and not just a generic node.
- class NodeKindField < Field
- def c_type
- if options[:kind]
- "pm_#{options[:kind].gsub(/(?<=.)[A-Z]/, "_\\0").downcase}"
- else
- "pm_node"
- end
- end
-
- def ruby_type
- options[:kind] || "Node"
- end
-
- def java_type
- options[:kind] || "Node"
- end
-
- def java_cast
- if options[:kind]
- "(Nodes.#{options[:kind]}) "
- else
- ""
- end
- end
- end
-
- # This represents a field on a node that is itself a node. We pass them as
- # references and store them as references.
- class NodeField < NodeKindField
- def rbs_class
- ruby_type
- end
-
- def rbi_class
- "Prism::#{ruby_type}"
- end
- end
-
- # This represents a field on a node that is itself a node and can be
- # optionally null. We pass them as references and store them as references.
- class OptionalNodeField < NodeKindField
- def rbs_class
- "#{ruby_type}?"
- end
-
- def rbi_class
- "T.nilable(Prism::#{ruby_type})"
- end
- end
-
- # This represents a field on a node that is a list of nodes. We pass them as
- # references and store them directly on the struct.
- class NodeListField < Field
- def rbs_class
- "Array[Node]"
- end
-
- def rbi_class
- "T::Array[Prism::Node]"
- end
-
- def java_type
- "Node[]"
- end
- end
-
- # This represents a field on a node that is the ID of a string interned
- # through the parser's constant pool.
- class ConstantField < Field
- def rbs_class
- "Symbol"
- end
-
- def rbi_class
- "Symbol"
- end
-
- def java_type
- JAVA_STRING_TYPE
- end
- end
-
- # This represents a field on a node that is the ID of a string interned
- # through the parser's constant pool and can be optionally null.
- class OptionalConstantField < Field
- def rbs_class
- "Symbol?"
- end
-
- def rbi_class
- "T.nilable(Symbol)"
- end
-
- def java_type
- JAVA_STRING_TYPE
- end
- end
-
- # This represents a field on a node that is a list of IDs that are associated
- # with strings interned through the parser's constant pool.
- class ConstantListField < Field
- def rbs_class
- "Array[Symbol]"
- end
-
- def rbi_class
- "T::Array[Symbol]"
- end
-
- def java_type
- "#{JAVA_STRING_TYPE}[]"
- end
- end
-
- # This represents a field on a node that is a string.
- class StringField < Field
- def rbs_class
- "String"
- end
-
- def rbi_class
- "String"
- end
-
- def java_type
- "byte[]"
- end
- end
-
- # This represents a field on a node that is a location.
- class LocationField < Field
- def semantic_field?
- false
- end
-
- def rbs_class
- "Location"
- end
-
- def rbi_class
- "Prism::Location"
- end
-
- def java_type
- "Location"
- end
- end
-
- # This represents a field on a node that is a location that is optional.
- class OptionalLocationField < Field
- def semantic_field?
- false
- end
-
- def rbs_class
- "Location?"
- end
-
- def rbi_class
- "T.nilable(Prism::Location)"
- end
-
- def java_type
- "Location"
- end
- end
-
- # This represents an integer field.
- class UInt32Field < Field
- def rbs_class
- "Integer"
- end
-
- def rbi_class
- "Integer"
- end
-
- def java_type
- "int"
- end
- end
-
- # This represents a set of flags. It is very similar to the UInt32Field, but
- # can be directly embedded into the flags field on the struct and provides
- # convenient methods for checking if a flag is set.
- class FlagsField < Field
- def rbs_class
- "Integer"
- end
-
- def rbi_class
- "Integer"
- end
-
- def java_type
- "short"
- end
-
- def kind
- options.fetch(:kind)
- end
- end
-
- # This class represents a node in the tree, configured by the config.yml file in
- # YAML format. It contains information about the name of the node and the
- # various child nodes it contains.
- class NodeType
- attr_reader :name, :type, :human, :fields, :newline, :comment
-
- def initialize(config)
- @name = config.fetch("name")
-
- type = @name.gsub(/(?<=.)[A-Z]/, "_\\0")
- @type = "PM_#{type.upcase}"
- @human = type.downcase
-
- @fields =
- config.fetch("fields", []).map do |field|
- field_type_for(field.fetch("type")).new(**field.transform_keys(&:to_sym))
- end
-
- @newline = config.fetch("newline", true)
- @comment = config.fetch("comment")
- end
-
- def each_comment_line
- comment.each_line { |line| yield line.prepend(" ").rstrip }
- end
-
- def semantic_fields
- @semantic_fields ||= @fields.select(&:semantic_field?)
- end
-
- # Should emit serialized length of node so implementations can skip
- # the node to enable lazy parsing.
- def needs_serialized_length?
- name == "DefNode"
- end
-
- private
-
- def field_type_for(name)
- case name
- when "node" then NodeField
- when "node?" then OptionalNodeField
- when "node[]" then NodeListField
- when "string" then StringField
- when "constant" then ConstantField
- when "constant?" then OptionalConstantField
- when "constant[]" then ConstantListField
- when "location" then LocationField
- when "location?" then OptionalLocationField
- when "uint32" then UInt32Field
- when "flags" then FlagsField
- else raise("Unknown field type: #{name.inspect}")
- end
- end
- end
-
- # This represents a token in the lexer.
- class Token
- attr_reader :name, :value, :comment
-
- def initialize(config)
- @name = config.fetch("name")
- @value = config["value"]
- @comment = config.fetch("comment")
- end
- end
-
- # Represents a set of flags that should be internally represented with an enum.
- class Flags
- # Represents an individual flag within a set of flags.
- class Flag
- attr_reader :name, :camelcase, :comment
-
- def initialize(config)
- @name = config.fetch("name")
- @camelcase = @name.split("_").map(&:capitalize).join
- @comment = config.fetch("comment")
- end
- end
-
- attr_reader :name, :human, :values, :comment
-
- def initialize(config)
- @name = config.fetch("name")
- @human = @name.gsub(/(?<=.)[A-Z]/, "_\\0").downcase
- @values = config.fetch("values").map { |flag| Flag.new(flag) }
- @comment = config.fetch("comment")
- end
- end
-
- class << self
- # This templates out a file using ERB with the given locals. The locals are
- # derived from the config.yml file.
- def template(name, write_to: nil)
- filepath = "templates/#{name}.erb"
- template = File.expand_path("../#{filepath}", __dir__)
-
- erb = read_template(template)
- extension = File.extname(filepath.gsub(".erb", ""))
-
- heading = case extension
- when ".rb"
- <<~HEADING
- # frozen_string_literal: true
- =begin
- This file is generated by the templates/template.rb script and should not be
- modified manually. See #{filepath}
- if you are looking to modify the template
- =end
-
- HEADING
- when ".rbs"
- <<~HEADING
- # This file is generated by the templates/template.rb script and should not be
- # modified manually. See #{filepath}
- # if you are looking to modify the template
-
- HEADING
- when ".rbi"
- <<~HEADING
- =begin
- This file is generated by the templates/template.rb script and should not be
- modified manually. See #{filepath}
- if you are looking to modify the template
- =end
- HEADING
- else
- escape = true
- <<~HEADING
- /******************************************************************************/
- /* This file is generated by the templates/template.rb script and should not */
- /* be modified manually. See */
- /* #{filepath + " " * (74 - filepath.size) } */
- /* if you are looking to modify the */
- /* template */
- /******************************************************************************/
- HEADING
- end
-
- write_to ||= File.expand_path("../#{name}", __dir__)
- contents = heading + erb.result_with_hash(locals)
- if escape
- (contents = contents.b).gsub!(/[^\t-~]/) {|c| "\\x%.2x" % c.ord}
- end
-
- FileUtils.mkdir_p(File.dirname(write_to))
- File.write(write_to, contents)
- end
-
- private
-
- def read_template(filepath)
- template = File.read(filepath, encoding: Encoding::UTF_8)
- erb = erb(template)
- erb.filename = filepath
- erb
- end
-
- if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
- def erb(template)
- ERB.new(template, trim_mode: "-")
- end
- else
- def erb(template)
- ERB.new(template, nil, "-")
- end
- end
-
- def locals
- @locals ||=
- begin
- config = YAML.load_file(File.expand_path("../config.yml", __dir__))
-
- {
- nodes: config.fetch("nodes").map { |node| NodeType.new(node) }.sort_by(&:name),
- tokens: config.fetch("tokens").map { |token| Token.new(token) },
- flags: config.fetch("flags").map { |flags| Flags.new(flags) }
- }
- end
- end
- end
-
- TEMPLATES = [
- "ext/prism/api_node.c",
- "include/prism/ast.h",
- "javascript/src/deserialize.js",
- "javascript/src/nodes.js",
- "java/org/prism/Loader.java",
- "java/org/prism/Nodes.java",
- "java/org/prism/AbstractNodeVisitor.java",
- "lib/prism/compiler.rb",
- "lib/prism/dispatcher.rb",
- "lib/prism/dsl.rb",
- "lib/prism/mutation_compiler.rb",
- "lib/prism/node.rb",
- "lib/prism/serialize.rb",
- "lib/prism/visitor.rb",
- "src/node.c",
- "src/prettyprint.c",
- "src/serialize.c",
- "src/token_type.c",
- "rbi/prism.rbi",
- "sig/prism.rbs",
- ]
-end
-
-if __FILE__ == $0
- if ARGV.empty?
- Prism::TEMPLATES.each { |filepath| Prism.template(filepath) }
- else # ruby/ruby
- name, write_to = ARGV
- Prism.template(name, write_to: write_to)
- end
-end
diff --git a/prism/util/pm_buffer.c b/prism/util/pm_buffer.c
deleted file mode 100644
index acc6cad725..0000000000
--- a/prism/util/pm_buffer.c
+++ /dev/null
@@ -1,170 +0,0 @@
-#include "prism/util/pm_buffer.h"
-
-/**
- * Return the size of the pm_buffer_t struct.
- */
-size_t
-pm_buffer_sizeof(void) {
- return sizeof(pm_buffer_t);
-}
-
-/**
- * Initialize a pm_buffer_t with the given capacity.
- */
-bool
-pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity) {
- buffer->length = 0;
- buffer->capacity = capacity;
-
- buffer->value = (char *) malloc(capacity);
- return buffer->value != NULL;
-}
-
-/**
- * Initialize a pm_buffer_t with its default values.
- */
-bool
-pm_buffer_init(pm_buffer_t *buffer) {
- return pm_buffer_init_capacity(buffer, 1024);
-}
-
-/**
- * Return the value of the buffer.
- */
-char *
-pm_buffer_value(pm_buffer_t *buffer) {
- return buffer->value;
-}
-
-/**
- * Return the length of the buffer.
- */
-size_t
-pm_buffer_length(pm_buffer_t *buffer) {
- return buffer->length;
-}
-
-/**
- * Append the given amount of space to the buffer.
- */
-static inline void
-pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
- size_t next_length = buffer->length + length;
-
- if (next_length > buffer->capacity) {
- if (buffer->capacity == 0) {
- buffer->capacity = 1;
- }
-
- while (next_length > buffer->capacity) {
- buffer->capacity *= 2;
- }
-
- buffer->value = realloc(buffer->value, buffer->capacity);
- }
-
- buffer->length = next_length;
-}
-
-/**
- * Append a generic pointer to memory to the buffer.
- */
-static inline void
-pm_buffer_append(pm_buffer_t *buffer, const void *source, size_t length) {
- size_t cursor = buffer->length;
- pm_buffer_append_length(buffer, length);
- memcpy(buffer->value + cursor, source, length);
-}
-
-/**
- * Append the given amount of space as zeroes to the buffer.
- */
-void
-pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length) {
- size_t cursor = buffer->length;
- pm_buffer_append_length(buffer, length);
- memset(buffer->value + cursor, 0, length);
-}
-
-/**
- * Append a formatted string to the buffer.
- */
-void
-pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) {
- va_list arguments;
- va_start(arguments, format);
- int result = vsnprintf(NULL, 0, format, arguments);
- va_end(arguments);
-
- if (result < 0) return;
- size_t length = (size_t) (result + 1);
-
- size_t cursor = buffer->length;
- pm_buffer_append_length(buffer, length);
-
- va_start(arguments, format);
- vsnprintf(buffer->value + cursor, length, format, arguments);
- va_end(arguments);
-
- buffer->length--;
-}
-
-/**
- * Append a string to the buffer.
- */
-void
-pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length) {
- pm_buffer_append(buffer, value, length);
-}
-
-/**
- * Append a list of bytes to the buffer.
- */
-void
-pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length) {
- pm_buffer_append(buffer, (const char *) value, length);
-}
-
-/**
- * Append a single byte to the buffer.
- */
-void
-pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value) {
- const void *source = &value;
- pm_buffer_append(buffer, source, sizeof(uint8_t));
-}
-
-/**
- * Append a 32-bit unsigned integer to the buffer as a variable-length integer.
- */
-void
-pm_buffer_append_varint(pm_buffer_t *buffer, uint32_t value) {
- if (value < 128) {
- pm_buffer_append_byte(buffer, (uint8_t) value);
- } else {
- uint32_t n = value;
- while (n >= 128) {
- pm_buffer_append_byte(buffer, (uint8_t) (n | 128));
- n >>= 7;
- }
- pm_buffer_append_byte(buffer, (uint8_t) n);
- }
-}
-
-/**
- * Concatenate one buffer onto another.
- */
-void
-pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source) {
- if (source->length > 0) {
- pm_buffer_append(destination, source->value, source->length);
- }
-}
-
-/**
- * Free the memory associated with the buffer.
- */
-void
-pm_buffer_free(pm_buffer_t *buffer) {
- free(buffer->value);
-}
diff --git a/prism/util/pm_buffer.h b/prism/util/pm_buffer.h
deleted file mode 100644
index 3c3a6fb688..0000000000
--- a/prism/util/pm_buffer.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * @file pm_buffer.h
- *
- * A wrapper around a contiguous block of allocated memory.
- */
-#ifndef PRISM_BUFFER_H
-#define PRISM_BUFFER_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-/**
- * A pm_buffer_t is a simple memory buffer that stores data in a contiguous
- * block of memory.
- */
-typedef struct {
- /** The length of the buffer in bytes. */
- size_t length;
-
- /** The capacity of the buffer in bytes that has been allocated. */
- size_t capacity;
-
- /** A pointer to the start of the buffer. */
- char *value;
-} pm_buffer_t;
-
-/**
- * Return the size of the pm_buffer_t struct.
- *
- * @returns The size of the pm_buffer_t struct.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_buffer_sizeof(void);
-
-/**
- * Initialize a pm_buffer_t with the given capacity.
- *
- * @param buffer The buffer to initialize.
- * @param capacity The capacity of the buffer.
- * @returns True if the buffer was initialized successfully, false otherwise.
- */
-bool pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity);
-
-/**
- * Initialize a pm_buffer_t with its default values.
- *
- * @param buffer The buffer to initialize.
- * @returns True if the buffer was initialized successfully, false otherwise.
- */
-PRISM_EXPORTED_FUNCTION bool pm_buffer_init(pm_buffer_t *buffer);
-
-/**
- * Return the value of the buffer.
- *
- * @param buffer The buffer to get the value of.
- * @returns The value of the buffer.
- */
-PRISM_EXPORTED_FUNCTION char * pm_buffer_value(pm_buffer_t *buffer);
-
-/**
- * Return the length of the buffer.
- *
- * @param buffer The buffer to get the length of.
- * @returns The length of the buffer.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(pm_buffer_t *buffer);
-
-/**
- * Append the given amount of space as zeroes to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param length The amount of space to append and zero.
- */
-void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length);
-
-/**
- * Append a formatted string to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param format The format string to append.
- * @param ... The arguments to the format string.
- */
-void pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) PRISM_ATTRIBUTE_FORMAT(2, 3);
-
-/**
- * Append a string to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The string to append.
- * @param length The length of the string to append.
- */
-void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length);
-
-/**
- * Append a list of bytes to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The bytes to append.
- * @param length The length of the bytes to append.
- */
-void pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length);
-
-/**
- * Append a single byte to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The byte to append.
- */
-void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value);
-
-/**
- * Append a 32-bit unsigned integer to the buffer as a variable-length integer.
- *
- * @param buffer The buffer to append to.
- * @param value The integer to append.
- */
-void pm_buffer_append_varint(pm_buffer_t *buffer, uint32_t value);
-
-/**
- * Concatenate one buffer onto another.
- *
- * @param destination The buffer to concatenate onto.
- * @param source The buffer to concatenate.
- */
-void pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source);
-
-/**
- * Free the memory associated with the buffer.
- *
- * @param buffer The buffer to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer);
-
-#endif
diff --git a/prism/util/pm_char.c b/prism/util/pm_char.c
deleted file mode 100644
index 13eddbba48..0000000000
--- a/prism/util/pm_char.c
+++ /dev/null
@@ -1,318 +0,0 @@
-#include "prism/util/pm_char.h"
-
-#define PRISM_CHAR_BIT_WHITESPACE (1 << 0)
-#define PRISM_CHAR_BIT_INLINE_WHITESPACE (1 << 1)
-#define PRISM_CHAR_BIT_REGEXP_OPTION (1 << 2)
-
-#define PRISM_NUMBER_BIT_BINARY_DIGIT (1 << 0)
-#define PRISM_NUMBER_BIT_BINARY_NUMBER (1 << 1)
-#define PRISM_NUMBER_BIT_OCTAL_DIGIT (1 << 2)
-#define PRISM_NUMBER_BIT_OCTAL_NUMBER (1 << 3)
-#define PRISM_NUMBER_BIT_DECIMAL_DIGIT (1 << 4)
-#define PRISM_NUMBER_BIT_DECIMAL_NUMBER (1 << 5)
-#define PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT (1 << 6)
-#define PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER (1 << 7)
-
-static const uint8_t pm_byte_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5x
- 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 4, 4, // 6x
- 0, 0, 0, 4, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-static const uint8_t pm_number_table[256] = {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2x
- 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3x
- 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, // 5x
- 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Ax
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bx
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Cx
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dx
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Ex
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fx
-};
-
-/**
- * Returns the number of characters at the start of the string that match the
- * given kind. Disallows searching past the given maximum number of characters.
- */
-static inline size_t
-pm_strspn_char_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- while (size < maximum && (pm_byte_table[string[size]] & kind)) size++;
- return size;
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_WHITESPACE);
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace while also tracking the location of each newline. Disallows
- * searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newline_list_t *newline_list) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- while (size < maximum && (pm_byte_table[string[size]] & PRISM_CHAR_BIT_WHITESPACE)) {
- if (string[size] == '\n') {
- pm_newline_list_append(newline_list, string + size);
- }
-
- size++;
- }
-
- return size;
-}
-
-/**
- * Returns the number of characters at the start of the string that are inline
- * whitespace. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_INLINE_WHITESPACE);
-}
-
-/**
- * Returns the number of characters at the start of the string that are regexp
- * options. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_REGEXP_OPTION);
-}
-
-/**
- * Returns true if the given character matches the given kind.
- */
-static inline bool
-pm_char_is_char_kind(const uint8_t b, uint8_t kind) {
- return (pm_byte_table[b] & kind) != 0;
-}
-
-/**
- * Returns true if the given character is a whitespace character.
- */
-bool
-pm_char_is_whitespace(const uint8_t b) {
- return pm_char_is_char_kind(b, PRISM_CHAR_BIT_WHITESPACE);
-}
-
-/**
- * Returns true if the given character is an inline whitespace character.
- */
-bool
-pm_char_is_inline_whitespace(const uint8_t b) {
- return pm_char_is_char_kind(b, PRISM_CHAR_BIT_INLINE_WHITESPACE);
-}
-
-/**
- * Scan through the string and return the number of characters at the start of
- * the string that match the given kind. Disallows searching past the given
- * maximum number of characters.
- */
-static inline size_t
-pm_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- while (size < maximum && (pm_number_table[string[size]] & kind)) size++;
- return size;
-}
-
-/**
- * Scan through the string and return the number of characters at the start of
- * the string that match the given kind. Disallows searching past the given
- * maximum number of characters.
- *
- * Additionally, report the location of the last invalid underscore character
- * found in the string through the out invalid parameter.
- */
-static inline size_t
-pm_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- bool underscore = false;
- while (size < maximum && (pm_number_table[string[size]] & kind)) {
- if (string[size] == '_') {
- if (underscore) *invalid = string + size;
- underscore = true;
- } else {
- underscore = false;
- }
-
- size++;
- }
-
- if (string[size - 1] == '_') *invalid = string + size - 1;
- return size;
-}
-
-/**
- * Returns the number of characters at the start of the string that are binary
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- */
-size_t
-pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_BINARY_NUMBER);
-}
-
-/**
- * Returns the number of characters at the start of the string that are octal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- */
-size_t
-pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_OCTAL_NUMBER);
-}
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_number_kind(string, length, PRISM_NUMBER_BIT_DECIMAL_DIGIT);
-}
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore
- */
-size_t
-pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_DECIMAL_NUMBER);
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits. Disallows searching past the given maximum number of
- * characters.
- */
-size_t
-pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_number_kind(string, length, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT);
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits or underscores. Disallows searching past the given maximum
- * number of characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- */
-size_t
-pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER);
-}
-
-/**
- * Returns true if the given character matches the given kind.
- */
-static inline bool
-pm_char_is_number_kind(const uint8_t b, uint8_t kind) {
- return (pm_number_table[b] & kind) != 0;
-}
-
-/**
- * Returns true if the given character is a binary digit.
- */
-bool
-pm_char_is_binary_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_BINARY_DIGIT);
-}
-
-/**
- * Returns true if the given character is an octal digit.
- */
-bool
-pm_char_is_octal_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_OCTAL_DIGIT);
-}
-
-/**
- * Returns true if the given character is a decimal digit.
- */
-bool
-pm_char_is_decimal_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_DECIMAL_DIGIT);
-}
-
-/**
- * Returns true if the given character is a hexadecimal digit.
- */
-bool
-pm_char_is_hexadecimal_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT);
-}
-
-#undef PRISM_CHAR_BIT_WHITESPACE
-#undef PRISM_CHAR_BIT_INLINE_WHITESPACE
-#undef PRISM_CHAR_BIT_REGEXP_OPTION
-
-#undef PRISM_NUMBER_BIT_BINARY_DIGIT
-#undef PRISM_NUMBER_BIT_BINARY_NUMBER
-#undef PRISM_NUMBER_BIT_OCTAL_DIGIT
-#undef PRISM_NUMBER_BIT_OCTAL_NUMBER
-#undef PRISM_NUMBER_BIT_DECIMAL_DIGIT
-#undef PRISM_NUMBER_BIT_DECIMAL_NUMBER
-#undef PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER
-#undef PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT
diff --git a/prism/util/pm_char.h b/prism/util/pm_char.h
deleted file mode 100644
index 32f698a42b..0000000000
--- a/prism/util/pm_char.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * @file pm_char.h
- *
- * Functions for working with characters and strings.
- */
-#ifndef PRISM_CHAR_H
-#define PRISM_CHAR_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_newline_list.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are
- * whitespace.
- */
-size_t pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace while also tracking the location of each newline. Disallows
- * searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param newline_list The list of newlines to populate.
- * @return The number of characters at the start of the string that are
- * whitespace.
- */
-size_t
-pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newline_list_t *newline_list);
-
-/**
- * Returns the number of characters at the start of the string that are inline
- * whitespace. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are inline
- * whitespace.
- */
-size_t pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are decimal
- * digits.
- */
-size_t pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits. Disallows searching past the given maximum number of
- * characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are
- * hexadecimal digits.
- */
-size_t pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are octal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are octal
- * digits or underscores.
- */
-size_t pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are decimal
- * digits or underscores.
- */
-size_t pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits or underscores. Disallows searching past the given maximum
- * number of characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are
- * hexadecimal digits or underscores.
- */
-size_t pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns the number of characters at the start of the string that are regexp
- * options. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are regexp
- * options.
- */
-size_t pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are binary
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are binary
- * digits or underscores.
- */
-size_t pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns true if the given character is a whitespace character.
- *
- * @param b The character to check.
- * @return True if the given character is a whitespace character.
- */
-bool pm_char_is_whitespace(const uint8_t b);
-
-/**
- * Returns true if the given character is an inline whitespace character.
- *
- * @param b The character to check.
- * @return True if the given character is an inline whitespace character.
- */
-bool pm_char_is_inline_whitespace(const uint8_t b);
-
-/**
- * Returns true if the given character is a binary digit.
- *
- * @param b The character to check.
- * @return True if the given character is a binary digit.
- */
-bool pm_char_is_binary_digit(const uint8_t b);
-
-/**
- * Returns true if the given character is an octal digit.
- *
- * @param b The character to check.
- * @return True if the given character is an octal digit.
- */
-bool pm_char_is_octal_digit(const uint8_t b);
-
-/**
- * Returns true if the given character is a decimal digit.
- *
- * @param b The character to check.
- * @return True if the given character is a decimal digit.
- */
-bool pm_char_is_decimal_digit(const uint8_t b);
-
-/**
- * Returns true if the given character is a hexadecimal digit.
- *
- * @param b The character to check.
- * @return True if the given character is a hexadecimal digit.
- */
-bool pm_char_is_hexadecimal_digit(const uint8_t b);
-
-#endif
diff --git a/prism/util/pm_constant_pool.c b/prism/util/pm_constant_pool.c
deleted file mode 100644
index e06682eb48..0000000000
--- a/prism/util/pm_constant_pool.c
+++ /dev/null
@@ -1,296 +0,0 @@
-#include "prism/util/pm_constant_pool.h"
-
-/**
- * Initialize a list of constant ids.
- */
-void
-pm_constant_id_list_init(pm_constant_id_list_t *list) {
- list->ids = NULL;
- list->size = 0;
- list->capacity = 0;
-}
-
-/**
- * Append a constant id to a list of constant ids. Returns false if any
- * potential reallocations fail.
- */
-bool
-pm_constant_id_list_append(pm_constant_id_list_t *list, pm_constant_id_t id) {
- if (list->size >= list->capacity) {
- list->capacity = list->capacity == 0 ? 8 : list->capacity * 2;
- list->ids = (pm_constant_id_t *) realloc(list->ids, sizeof(pm_constant_id_t) * list->capacity);
- if (list->ids == NULL) return false;
- }
-
- list->ids[list->size++] = id;
- return true;
-}
-
-/**
- * Checks if the current constant id list includes the given constant id.
- */
-bool
-pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id) {
- for (size_t index = 0; index < list->size; index++) {
- if (list->ids[index] == id) return true;
- }
- return false;
-}
-
-/**
- * Get the memory size of a list of constant ids.
- */
-size_t
-pm_constant_id_list_memsize(pm_constant_id_list_t *list) {
- return sizeof(pm_constant_id_list_t) + (list->capacity * sizeof(pm_constant_id_t));
-}
-
-/**
- * Free the memory associated with a list of constant ids.
- */
-void
-pm_constant_id_list_free(pm_constant_id_list_t *list) {
- if (list->ids != NULL) {
- free(list->ids);
- }
-}
-
-/**
- * A relatively simple hash function (djb2) that is used to hash strings. We are
- * optimizing here for simplicity and speed.
- */
-static inline uint32_t
-pm_constant_pool_hash(const uint8_t *start, size_t length) {
- // This is a prime number used as the initial value for the hash function.
- uint32_t value = 5381;
-
- for (size_t index = 0; index < length; index++) {
- value = ((value << 5) + value) + start[index];
- }
-
- return value;
-}
-
-/**
- * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
- */
-static uint32_t
-next_power_of_two(uint32_t v) {
- // Avoid underflow in subtraction on next line.
- if (v == 0) {
- // 1 is the nearest power of 2 to 0 (2^0)
- return 1;
- }
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- v++;
- return v;
-}
-
-#ifndef NDEBUG
-static bool
-is_power_of_two(uint32_t size) {
- return (size & (size - 1)) == 0;
-}
-#endif
-
-/**
- * Resize a constant pool to a given capacity.
- */
-static inline bool
-pm_constant_pool_resize(pm_constant_pool_t *pool) {
- assert(is_power_of_two(pool->capacity));
-
- uint32_t next_capacity = pool->capacity * 2;
- if (next_capacity < pool->capacity) return false;
-
- const uint32_t mask = next_capacity - 1;
- const size_t element_size = sizeof(pm_constant_pool_bucket_t) + sizeof(pm_constant_t);
-
- void *next = calloc(next_capacity, element_size);
- if (next == NULL) return false;
-
- pm_constant_pool_bucket_t *next_buckets = next;
- pm_constant_t *next_constants = (void *)(((char *) next) + next_capacity * sizeof(pm_constant_pool_bucket_t));
-
- // For each bucket in the current constant pool, find the index in the
- // next constant pool, and insert it.
- for (uint32_t index = 0; index < pool->capacity; index++) {
- pm_constant_pool_bucket_t *bucket = &pool->buckets[index];
-
- // If an id is set on this constant, then we know we have content here.
- // In this case we need to insert it into the next constant pool.
- if (bucket->id != 0) {
- uint32_t next_index = bucket->hash & mask;
-
- // This implements linear scanning to find the next available slot
- // in case this index is already taken. We don't need to bother
- // comparing the values since we know that the hash is unique.
- while (next_buckets[next_index].id != 0) {
- next_index = (next_index + 1) & mask;
- }
-
- // Here we copy over the entire bucket, which includes the id so
- // that they are consistent between resizes.
- next_buckets[next_index] = *bucket;
- }
- }
-
- // The constants are stable with respect to hash table resizes.
- memcpy(next_constants, pool->constants, pool->size * sizeof(pm_constant_t));
-
- // pool->constants and pool->buckets are allocated out of the same chunk
- // of memory, with the buckets coming first.
- free(pool->buckets);
- pool->constants = next_constants;
- pool->buckets = next_buckets;
- pool->capacity = next_capacity;
- return true;
-}
-
-/**
- * Initialize a new constant pool with a given capacity.
- */
-bool
-pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity) {
- const uint32_t maximum = (~((uint32_t) 0));
- if (capacity >= ((maximum / 2) + 1)) return false;
-
- capacity = next_power_of_two(capacity);
- const size_t element_size = sizeof(pm_constant_pool_bucket_t) + sizeof(pm_constant_t);
- void *memory = calloc(capacity, element_size);
- if (memory == NULL) return false;
-
- pool->buckets = memory;
- pool->constants = (void *)(((char *)memory) + capacity * sizeof(pm_constant_pool_bucket_t));
- pool->size = 0;
- pool->capacity = capacity;
- return true;
-}
-
-/**
- * Return a pointer to the constant indicated by the given constant id.
- */
-pm_constant_t *
-pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id) {
- assert(constant_id > 0 && constant_id <= pool->size);
- return &pool->constants[constant_id - 1];
-}
-
-/**
- * Insert a constant into a constant pool and return its index in the pool.
- */
-static inline pm_constant_id_t
-pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t length, pm_constant_pool_bucket_type_t type) {
- if (pool->size >= (pool->capacity / 4 * 3)) {
- if (!pm_constant_pool_resize(pool)) return 0;
- }
-
- assert(is_power_of_two(pool->capacity));
- const uint32_t mask = pool->capacity - 1;
-
- uint32_t hash = pm_constant_pool_hash(start, length);
- uint32_t index = hash & mask;
- pm_constant_pool_bucket_t *bucket;
-
- while (bucket = &pool->buckets[index], bucket->id != 0) {
- // If there is a collision, then we need to check if the content is the
- // same as the content we are trying to insert. If it is, then we can
- // return the id of the existing constant.
- pm_constant_t *constant = &pool->constants[bucket->id - 1];
-
- if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
- // Since we have found a match, we need to check if this is
- // attempting to insert a shared or an owned constant. We want to
- // prefer shared constants since they don't require allocations.
- if (type == PM_CONSTANT_POOL_BUCKET_OWNED) {
- // If we're attempting to insert an owned constant and we have
- // an existing constant, then either way we don't want the given
- // memory. Either it's duplicated with the existing constant or
- // it's not necessary because we have a shared version.
- free((void *) start);
- } else if (bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
- // If we're attempting to insert a shared constant and the
- // existing constant is owned, then we can free the owned
- // constant and replace it with the shared constant.
- free((void *) constant->start);
- constant->start = start;
- bucket->type = (unsigned int) (PM_CONSTANT_POOL_BUCKET_DEFAULT & 0x3);
- }
-
- return bucket->id;
- }
-
- index = (index + 1) & mask;
- }
-
- // IDs are allocated starting at 1, since the value 0 denotes a non-existant
- // constant.
- uint32_t id = ++pool->size;
- assert(pool->size < ((uint32_t) (1 << 30)));
-
- *bucket = (pm_constant_pool_bucket_t) {
- .id = (unsigned int) (id & 0x3fffffff),
- .type = (unsigned int) (type & 0x3),
- .hash = hash
- };
-
- pool->constants[id - 1] = (pm_constant_t) {
- .start = start,
- .length = length,
- };
-
- return id;
-}
-
-/**
- * Insert a constant into a constant pool. Returns the id of the constant, or 0
- * if any potential calls to resize fail.
- */
-pm_constant_id_t
-pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
- return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_DEFAULT);
-}
-
-/**
- * Insert a constant into a constant pool from memory that is now owned by the
- * constant pool. Returns the id of the constant, or 0 if any potential calls to
- * resize fail.
- */
-pm_constant_id_t
-pm_constant_pool_insert_owned(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
- return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_OWNED);
-}
-
-/**
- * Insert a constant into a constant pool from memory that is constant. Returns
- * the id of the constant, or 0 if any potential calls to resize fail.
- */
-pm_constant_id_t
-pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
- return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_CONSTANT);
-}
-
-/**
- * Free the memory associated with a constant pool.
- */
-void
-pm_constant_pool_free(pm_constant_pool_t *pool) {
- // For each constant in the current constant pool, free the contents if the
- // contents are owned.
- for (uint32_t index = 0; index < pool->capacity; index++) {
- pm_constant_pool_bucket_t *bucket = &pool->buckets[index];
-
- // If an id is set on this constant, then we know we have content here.
- if (bucket->id != 0 && bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
- pm_constant_t *constant = &pool->constants[bucket->id - 1];
- free((void *) constant->start);
- }
- }
-
- free(pool->buckets);
-}
diff --git a/prism/util/pm_constant_pool.h b/prism/util/pm_constant_pool.h
deleted file mode 100644
index ae5a88fbde..0000000000
--- a/prism/util/pm_constant_pool.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
- * @file pm_constant_pool.h
- *
- * A data structure that stores a set of strings.
- *
- * Each string is assigned a unique id, which can be used to compare strings for
- * equality. This comparison ends up being much faster than strcmp, since it
- * only requires a single integer comparison.
- */
-#ifndef PRISM_CONSTANT_POOL_H
-#define PRISM_CONSTANT_POOL_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-/**
- * A constant id is a unique identifier for a constant in the constant pool.
- */
-typedef uint32_t pm_constant_id_t;
-
-/**
- * A list of constant IDs. Usually used to represent a set of locals.
- */
-typedef struct {
- /** The number of constant ids in the list. */
- size_t size;
-
- /** The number of constant ids that have been allocated in the list. */
- size_t capacity;
-
- /** The constant ids in the list. */
- pm_constant_id_t *ids;
-} pm_constant_id_list_t;
-
-/**
- * Initialize a list of constant ids.
- *
- * @param list The list to initialize.
- */
-void pm_constant_id_list_init(pm_constant_id_list_t *list);
-
-/**
- * Append a constant id to a list of constant ids. Returns false if any
- * potential reallocations fail.
- *
- * @param list The list to append to.
- * @param id The id to append.
- * @return Whether the append succeeded.
- */
-bool pm_constant_id_list_append(pm_constant_id_list_t *list, pm_constant_id_t id);
-
-/**
- * Checks if the current constant id list includes the given constant id.
- *
- * @param list The list to check.
- * @param id The id to check for.
- * @return Whether the list includes the given id.
- */
-bool pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id);
-
-/**
- * Get the memory size of a list of constant ids.
- *
- * @param list The list to get the memory size of.
- * @return The memory size of the list.
- */
-size_t pm_constant_id_list_memsize(pm_constant_id_list_t *list);
-
-/**
- * Free the memory associated with a list of constant ids.
- *
- * @param list The list to free.
- */
-void pm_constant_id_list_free(pm_constant_id_list_t *list);
-
-/**
- * The type of bucket in the constant pool hash map. This determines how the
- * bucket should be freed.
- */
-typedef unsigned int pm_constant_pool_bucket_type_t;
-
-/** By default, each constant is a slice of the source. */
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_DEFAULT = 0;
-
-/** An owned constant is one for which memory has been allocated. */
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_OWNED = 1;
-
-/** A constant constant is known at compile time. */
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_CONSTANT = 2;
-
-/** A bucket in the hash map. */
-typedef struct {
- /** The incremental ID used for indexing back into the pool. */
- unsigned int id: 30;
-
- /** The type of the bucket, which determines how to free it. */
- pm_constant_pool_bucket_type_t type: 2;
-
- /** The hash of the bucket. */
- uint32_t hash;
-} pm_constant_pool_bucket_t;
-
-/** A constant in the pool which effectively stores a string. */
-typedef struct {
- /** A pointer to the start of the string. */
- const uint8_t *start;
-
- /** The length of the string. */
- size_t length;
-} pm_constant_t;
-
-/** The overall constant pool, which stores constants found while parsing. */
-typedef struct {
- /** The buckets in the hash map. */
- pm_constant_pool_bucket_t *buckets;
-
- /** The constants that are stored in the buckets. */
- pm_constant_t *constants;
-
- /** The number of buckets in the hash map. */
- uint32_t size;
-
- /** The number of buckets that have been allocated in the hash map. */
- uint32_t capacity;
-} pm_constant_pool_t;
-
-/**
- * Initialize a new constant pool with a given capacity.
- *
- * @param pool The pool to initialize.
- * @param capacity The initial capacity of the pool.
- * @return Whether the initialization succeeded.
- */
-bool pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity);
-
-/**
- * Return a pointer to the constant indicated by the given constant id.
- *
- * @param pool The pool to get the constant from.
- * @param constant_id The id of the constant to get.
- * @return A pointer to the constant.
- */
-pm_constant_t * pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id);
-
-/**
- * Insert a constant into a constant pool that is a slice of a source string.
- * Returns the id of the constant, or 0 if any potential calls to resize fail.
- *
- * @param pool The pool to insert the constant into.
- * @param start A pointer to the start of the constant.
- * @param length The length of the constant.
- * @return The id of the constant.
- */
-pm_constant_id_t pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
-/**
- * Insert a constant into a constant pool from memory that is now owned by the
- * constant pool. Returns the id of the constant, or 0 if any potential calls to
- * resize fail.
- *
- * @param pool The pool to insert the constant into.
- * @param start A pointer to the start of the constant.
- * @param length The length of the constant.
- * @return The id of the constant.
- */
-pm_constant_id_t pm_constant_pool_insert_owned(pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
-/**
- * Insert a constant into a constant pool from memory that is constant. Returns
- * the id of the constant, or 0 if any potential calls to resize fail.
- *
- * @param pool The pool to insert the constant into.
- * @param start A pointer to the start of the constant.
- * @param length The length of the constant.
- * @return The id of the constant.
- */
-pm_constant_id_t pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
-/**
- * Free the memory associated with a constant pool.
- *
- * @param pool The pool to free.
- */
-void pm_constant_pool_free(pm_constant_pool_t *pool);
-
-#endif
diff --git a/prism/util/pm_list.c b/prism/util/pm_list.c
deleted file mode 100644
index 62cfe47cfa..0000000000
--- a/prism/util/pm_list.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "prism/util/pm_list.h"
-
-/**
- * Returns true if the given list is empty.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_list_empty_p(pm_list_t *list) {
- return list->head == NULL;
-}
-
-/**
- * Returns the size of the list.
- */
-PRISM_EXPORTED_FUNCTION size_t
-pm_list_size(pm_list_t *list) {
- return list->size;
-}
-
-/**
- * Append a node to the given list.
- */
-void
-pm_list_append(pm_list_t *list, pm_list_node_t *node) {
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
- list->size++;
-}
-
-/**
- * Deallocate the internal state of the given list.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_list_free(pm_list_t *list) {
- pm_list_node_t *node = list->head;
- pm_list_node_t *next;
-
- while (node != NULL) {
- next = node->next;
- free(node);
- node = next;
- }
-
- list->size = 0;
-}
diff --git a/prism/util/pm_list.h b/prism/util/pm_list.h
deleted file mode 100644
index d29fe07c52..0000000000
--- a/prism/util/pm_list.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file pm_list.h
- *
- * An abstract linked list.
- */
-#ifndef PRISM_LIST_H
-#define PRISM_LIST_H
-
-#include "prism/defines.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/**
- * This struct represents an abstract linked list that provides common
- * functionality. It is meant to be used any time a linked list is necessary to
- * store data.
- *
- * The linked list itself operates off a set of pointers. Because the pointers
- * are not necessarily sequential, they can be of any size. We use this fact to
- * allow the consumer of this linked list to extend the node struct to include
- * any data they want. This is done by using the pm_list_node_t as the first
- * member of the struct.
- *
- * For example, if we want to store a list of integers, we can do the following:
- *
- * ```c
- * typedef struct {
- * pm_list_node_t node;
- * int value;
- * } pm_int_node_t;
- *
- * pm_list_t list = { 0 };
- * pm_int_node_t *node = malloc(sizeof(pm_int_node_t));
- * node->value = 5;
- *
- * pm_list_append(&list, &node->node);
- * ```
- *
- * The pm_list_t struct is used to represent the overall linked list. It
- * contains a pointer to the head and tail of the list. This allows for easy
- * iteration and appending of new nodes.
- */
-typedef struct pm_list_node {
- /** A pointer to the next node in the list. */
- struct pm_list_node *next;
-} pm_list_node_t;
-
-/**
- * This represents the overall linked list. It keeps a pointer to the head and
- * tail so that iteration is easy and pushing new nodes is easy.
- */
-typedef struct {
- /** The size of the list. */
- size_t size;
-
- /** A pointer to the head of the list. */
- pm_list_node_t *head;
-
- /** A pointer to the tail of the list. */
- pm_list_node_t *tail;
-} pm_list_t;
-
-/**
- * Returns true if the given list is empty.
- *
- * @param list The list to check.
- * @return True if the given list is empty, otherwise false.
- */
-PRISM_EXPORTED_FUNCTION bool pm_list_empty_p(pm_list_t *list);
-
-/**
- * Returns the size of the list.
- *
- * @param list The list to check.
- * @return The size of the list.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_list_size(pm_list_t *list);
-
-/**
- * Append a node to the given list.
- *
- * @param list The list to append to.
- * @param node The node to append.
- */
-void pm_list_append(pm_list_t *list, pm_list_node_t *node);
-
-/**
- * Deallocate the internal state of the given list.
- *
- * @param list The list to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_list_free(pm_list_t *list);
-
-#endif
diff --git a/prism/util/pm_memchr.c b/prism/util/pm_memchr.c
deleted file mode 100644
index b2049250e4..0000000000
--- a/prism/util/pm_memchr.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "prism/util/pm_memchr.h"
-
-#define PRISM_MEMCHR_TRAILING_BYTE_MINIMUM 0x40
-
-/**
- * We need to roll our own memchr to handle cases where the encoding changes and
- * we need to search for a character in a buffer that could be the trailing byte
- * of a multibyte character.
- */
-void *
-pm_memchr(const void *memory, int character, size_t number, bool encoding_changed, pm_encoding_t *encoding) {
- if (encoding_changed && encoding->multibyte && character >= PRISM_MEMCHR_TRAILING_BYTE_MINIMUM) {
- const uint8_t *source = (const uint8_t *) memory;
- size_t index = 0;
-
- while (index < number) {
- if (source[index] == character) {
- return (void *) (source + index);
- }
-
- size_t width = encoding->char_width(source + index, (ptrdiff_t) (number - index));
- if (width == 0) {
- return NULL;
- }
-
- index += width;
- }
-
- return NULL;
- } else {
- return memchr(memory, character, number);
- }
-}
-
-#undef PRISM_MEMCHR_TRAILING_BYTE_MINIMUM
diff --git a/prism/util/pm_memchr.h b/prism/util/pm_memchr.h
deleted file mode 100644
index 1eae6ab1ba..0000000000
--- a/prism/util/pm_memchr.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * @file pm_memchr.h
- *
- * A custom memchr implementation.
- */
-#ifndef PRISM_MEMCHR_H
-#define PRISM_MEMCHR_H
-
-#include "prism/defines.h"
-#include "prism/enc/pm_encoding.h"
-
-#include <stddef.h>
-
-/**
- * We need to roll our own memchr to handle cases where the encoding changes and
- * we need to search for a character in a buffer that could be the trailing byte
- * of a multibyte character.
- *
- * @param source The source string.
- * @param character The character to search for.
- * @param number The maximum number of bytes to search.
- * @param encoding_changed Whether the encoding changed.
- * @param encoding A pointer to the encoding.
- * @return A pointer to the first occurrence of the character in the source
- * string, or NULL if no such character exists.
- */
-void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, pm_encoding_t *encoding);
-
-#endif
diff --git a/prism/util/pm_newline_list.c b/prism/util/pm_newline_list.c
deleted file mode 100644
index f27bb75b63..0000000000
--- a/prism/util/pm_newline_list.c
+++ /dev/null
@@ -1,96 +0,0 @@
-#include "prism/util/pm_newline_list.h"
-
-/**
- * Initialize a new newline list with the given capacity. Returns true if the
- * allocation of the offsets succeeds, otherwise returns false.
- */
-bool
-pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity) {
- list->offsets = (size_t *) calloc(capacity, sizeof(size_t));
- if (list->offsets == NULL) return false;
-
- list->start = start;
-
- // This is 1 instead of 0 because we want to include the first line of the
- // file as having offset 0, which is set because of calloc.
- list->size = 1;
- list->capacity = capacity;
-
- return true;
-}
-
-/**
- * Append a new offset to the newline list. Returns true if the reallocation of
- * the offsets succeeds (if one was necessary), otherwise returns false.
- */
-bool
-pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor) {
- if (list->size == list->capacity) {
- size_t *original_offsets = list->offsets;
-
- list->capacity = (list->capacity * 3) / 2;
- list->offsets = (size_t *) calloc(list->capacity, sizeof(size_t));
- memcpy(list->offsets, original_offsets, list->size * sizeof(size_t));
- free(original_offsets);
- if (list->offsets == NULL) return false;
- }
-
- assert(*cursor == '\n');
- assert(cursor >= list->start);
- size_t newline_offset = (size_t) (cursor - list->start + 1);
-
- assert(list->size == 0 || newline_offset > list->offsets[list->size - 1]);
- list->offsets[list->size++] = newline_offset;
-
- return true;
-}
-
-/**
- * Conditionally append a new offset to the newline list, if the value passed in
- * is a newline.
- */
-bool
-pm_newline_list_check_append(pm_newline_list_t *list, const uint8_t *cursor) {
- if (*cursor != '\n') {
- return true;
- }
- return pm_newline_list_append(list, cursor);
-}
-
-/**
- * Returns the line and column of the given offset. If the offset is not in the
- * list, the line and column of the closest offset less than the given offset
- * are returned.
- */
-pm_line_column_t
-pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor) {
- assert(cursor >= list->start);
- size_t offset = (size_t) (cursor - list->start);
-
- size_t left = 0;
- size_t right = list->size - 1;
-
- while (left <= right) {
- size_t mid = left + (right - left) / 2;
-
- if (list->offsets[mid] == offset) {
- return ((pm_line_column_t) { mid, 0 });
- }
-
- if (list->offsets[mid] < offset) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
-
- return ((pm_line_column_t) { left - 1, offset - list->offsets[left - 1] });
-}
-
-/**
- * Free the internal memory allocated for the newline list.
- */
-void
-pm_newline_list_free(pm_newline_list_t *list) {
- free(list->offsets);
-}
diff --git a/prism/util/pm_newline_list.h b/prism/util/pm_newline_list.h
deleted file mode 100644
index a31051f4e0..0000000000
--- a/prism/util/pm_newline_list.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * @file pm_newline_list.h
- *
- * A list of byte offsets of newlines in a string.
- *
- * When compiling the syntax tree, it's necessary to know the line and column
- * of many nodes. This is necessary to support things like error messages,
- * tracepoints, etc.
- *
- * It's possible that we could store the start line, start column, end line, and
- * end column on every node in addition to the offsets that we already store,
- * but that would be quite a lot of memory overhead.
- */
-#ifndef PRISM_NEWLINE_LIST_H
-#define PRISM_NEWLINE_LIST_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-/**
- * A list of offsets of newlines in a string. The offsets are assumed to be
- * sorted/inserted in ascending order.
- */
-typedef struct {
- /** A pointer to the start of the source string. */
- const uint8_t *start;
-
- /** The number of offsets in the list. */
- size_t size;
-
- /** The capacity of the list that has been allocated. */
- size_t capacity;
-
- /** The list of offsets. */
- size_t *offsets;
-} pm_newline_list_t;
-
-/**
- * A line and column in a string.
- */
-typedef struct {
- /** The line number. */
- size_t line;
-
- /** The column number. */
- size_t column;
-} pm_line_column_t;
-
-/**
- * Initialize a new newline list with the given capacity. Returns true if the
- * allocation of the offsets succeeds, otherwise returns false.
- *
- * @param list The list to initialize.
- * @param start A pointer to the start of the source string.
- * @param capacity The initial capacity of the list.
- * @return True if the allocation of the offsets succeeds, otherwise false.
- */
-bool pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity);
-
-/**
- * Append a new offset to the newline list. Returns true if the reallocation of
- * the offsets succeeds (if one was necessary), otherwise returns false.
- *
- * @param list The list to append to.
- * @param cursor A pointer to the offset to append.
- * @return True if the reallocation of the offsets succeeds (if one was
- * necessary), otherwise false.
- */
-bool pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor);
-
-/**
- * Conditionally append a new offset to the newline list, if the value passed in
- * is a newline.
- *
- * @param list The list to append to.
- * @param cursor A pointer to the offset to append.
- * @return True if the reallocation of the offsets succeeds (if one was
- * necessary), otherwise false.
- */
-bool pm_newline_list_check_append(pm_newline_list_t *list, const uint8_t *cursor);
-
-/**
- * Returns the line and column of the given offset. If the offset is not in the
- * list, the line and column of the closest offset less than the given offset
- * are returned.
- *
- * @param list The list to search.
- * @param cursor A pointer to the offset to search for.
- * @return The line and column of the given offset.
- */
-pm_line_column_t pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor);
-
-/**
- * Free the internal memory allocated for the newline list.
- *
- * @param list The list to free.
- */
-void pm_newline_list_free(pm_newline_list_t *list);
-
-#endif
diff --git a/prism/util/pm_state_stack.c b/prism/util/pm_state_stack.c
deleted file mode 100644
index 2a424b4c03..0000000000
--- a/prism/util/pm_state_stack.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "prism/util/pm_state_stack.h"
-
-/**
- * Pushes a value onto the stack.
- */
-void
-pm_state_stack_push(pm_state_stack_t *stack, bool value) {
- *stack = (*stack << 1) | (value & 1);
-}
-
-/**
- * Pops a value off the stack.
- */
-void
-pm_state_stack_pop(pm_state_stack_t *stack) {
- *stack >>= 1;
-}
-
-/**
- * Returns the value at the top of the stack.
- */
-bool
-pm_state_stack_p(pm_state_stack_t *stack) {
- return *stack & 1;
-}
diff --git a/prism/util/pm_state_stack.h b/prism/util/pm_state_stack.h
deleted file mode 100644
index 1ce57a2209..0000000000
--- a/prism/util/pm_state_stack.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file pm_state_stack.h
- *
- * A stack of boolean values.
- */
-#ifndef PRISM_STATE_STACK_H
-#define PRISM_STATE_STACK_H
-
-#include "prism/defines.h"
-
-#include <stdbool.h>
-#include <stdint.h>
-
-/**
- * A struct that represents a stack of boolean values.
- */
-typedef uint32_t pm_state_stack_t;
-
-/**
- * Pushes a value onto the stack.
- *
- * @param stack The stack to push the value onto.
- * @param value The value to push onto the stack.
- */
-void pm_state_stack_push(pm_state_stack_t *stack, bool value);
-
-/**
- * Pops a value off the stack.
- *
- * @param stack The stack to pop the value off of.
- */
-void pm_state_stack_pop(pm_state_stack_t *stack);
-
-/**
- * Returns the value at the top of the stack.
- *
- * @param stack The stack to get the value from.
- * @return The value at the top of the stack.
- */
-bool pm_state_stack_p(pm_state_stack_t *stack);
-
-#endif
diff --git a/prism/util/pm_string.c b/prism/util/pm_string.c
deleted file mode 100644
index f4d3033a1b..0000000000
--- a/prism/util/pm_string.c
+++ /dev/null
@@ -1,210 +0,0 @@
-#include "prism/util/pm_string.h"
-
-/**
- * Returns the size of the pm_string_t struct. This is necessary to allocate the
- * correct amount of memory in the FFI backend.
- */
-PRISM_EXPORTED_FUNCTION size_t
-pm_string_sizeof(void) {
- return sizeof(pm_string_t);
-}
-
-/**
- * Initialize a shared string that is based on initial input.
- */
-void
-pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end) {
- assert(start <= end);
-
- *string = (pm_string_t) {
- .type = PM_STRING_SHARED,
- .source = start,
- .length = (size_t) (end - start)
- };
-}
-
-/**
- * Initialize an owned string that is responsible for freeing allocated memory.
- */
-void
-pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) {
- *string = (pm_string_t) {
- .type = PM_STRING_OWNED,
- .source = source,
- .length = length
- };
-}
-
-/**
- * Initialize a constant string that doesn't own its memory source.
- */
-void
-pm_string_constant_init(pm_string_t *string, const char *source, size_t length) {
- *string = (pm_string_t) {
- .type = PM_STRING_CONSTANT,
- .source = (const uint8_t *) source,
- .length = length
- };
-}
-
-/**
- * Read the file indicated by the filepath parameter into source and load its
- * contents and size into the given `pm_string_t`. The given `pm_string_t`
- * should be freed using `pm_string_free` when it is no longer used.
- *
- * We want to use demand paging as much as possible in order to avoid having to
- * read the entire file into memory (which could be detrimental to performance
- * for large files). This means that if we're on windows we'll use
- * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use
- * `mmap`, and on other POSIX systems we'll use `read`.
- */
-bool
-pm_string_mapped_init(pm_string_t *string, const char *filepath) {
-#ifdef _WIN32
- // Open the file for reading.
- HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (file == INVALID_HANDLE_VALUE) {
- perror("CreateFile failed");
- return false;
- }
-
- // Get the file size.
- DWORD file_size = GetFileSize(file, NULL);
- if (file_size == INVALID_FILE_SIZE) {
- CloseHandle(file);
- perror("GetFileSize failed");
- return false;
- }
-
- // If the file is empty, then we don't need to do anything else, we'll set
- // the source to a constant empty string and return.
- if (file_size == 0) {
- CloseHandle(file);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return true;
- }
-
- // Create a mapping of the file.
- HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
- if (mapping == NULL) {
- CloseHandle(file);
- perror("CreateFileMapping failed");
- return false;
- }
-
- // Map the file into memory.
- uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
- CloseHandle(mapping);
- CloseHandle(file);
-
- if (source == NULL) {
- perror("MapViewOfFile failed");
- return false;
- }
-
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
- return true;
-#else
- // Open the file for reading
- int fd = open(filepath, O_RDONLY);
- if (fd == -1) {
- perror("open");
- return false;
- }
-
- // Stat the file to get the file size
- struct stat sb;
- if (fstat(fd, &sb) == -1) {
- close(fd);
- perror("fstat");
- return false;
- }
-
- // mmap the file descriptor to virtually get the contents
- size_t size = (size_t) sb.st_size;
- uint8_t *source = NULL;
-
- if (size == 0) {
- close(fd);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return true;
- }
-
- source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (source == MAP_FAILED) {
- perror("Map failed");
- return false;
- }
-
- close(fd);
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
- return true;
-#endif
-}
-
-/**
- * Returns the memory size associated with the string.
- */
-size_t
-pm_string_memsize(const pm_string_t *string) {
- size_t size = sizeof(pm_string_t);
- if (string->type == PM_STRING_OWNED) {
- size += string->length;
- }
- return size;
-}
-
-/**
- * Ensure the string is owned. If it is not, then reinitialize it as owned and
- * copy over the previous source.
- */
-void
-pm_string_ensure_owned(pm_string_t *string) {
- if (string->type == PM_STRING_OWNED) return;
-
- size_t length = pm_string_length(string);
- const uint8_t *source = pm_string_source(string);
-
- uint8_t *memory = malloc(length);
- if (!memory) return;
-
- pm_string_owned_init(string, memory, length);
- memcpy((void *) string->source, source, length);
-}
-
-/**
- * Returns the length associated with the string.
- */
-PRISM_EXPORTED_FUNCTION size_t
-pm_string_length(const pm_string_t *string) {
- return string->length;
-}
-
-/**
- * Returns the start pointer associated with the string.
- */
-PRISM_EXPORTED_FUNCTION const uint8_t *
-pm_string_source(const pm_string_t *string) {
- return string->source;
-}
-
-/**
- * Free the associated memory of the given string.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_string_free(pm_string_t *string) {
- void *memory = (void *) string->source;
-
- if (string->type == PM_STRING_OWNED) {
- free(memory);
- } else if (string->type == PM_STRING_MAPPED && string->length) {
-#if defined(_WIN32)
- UnmapViewOfFile(memory);
-#else
- munmap(memory, string->length);
-#endif
- }
-}
diff --git a/prism/util/pm_string.h b/prism/util/pm_string.h
deleted file mode 100644
index ddb153784f..0000000000
--- a/prism/util/pm_string.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * @file pm_string.h
- *
- * A generic string type that can have various ownership semantics.
- */
-#ifndef PRISM_STRING_H
-#define PRISM_STRING_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-// The following headers are necessary to read files using demand paging.
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-/**
- * A generic string type that can have various ownership semantics.
- */
-typedef struct {
- /** A pointer to the start of the string. */
- const uint8_t *source;
-
- /** The length of the string in bytes of memory. */
- size_t length;
-
- /** The type of the string. This field determines how the string should be freed. */
- enum {
- /** This string is a constant string, and should not be freed. */
- PM_STRING_CONSTANT,
-
- /** This is a slice of another string, and should not be freed. */
- PM_STRING_SHARED,
-
- /** This string owns its memory, and should be freed using `pm_string_free`. */
- PM_STRING_OWNED,
-
- /** This string is a memory-mapped file, and should be freed using `pm_string_free`. */
- PM_STRING_MAPPED
- } type;
-} pm_string_t;
-
-/**
- * Returns the size of the pm_string_t struct. This is necessary to allocate the
- * correct amount of memory in the FFI backend.
- *
- * @return The size of the pm_string_t struct.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_string_sizeof(void);
-
-/**
- * Defines an empty string. This is useful for initializing a string that will
- * be filled in later.
- */
-#define PM_STRING_EMPTY ((pm_string_t) { .type = PM_STRING_CONSTANT, .source = NULL, .length = 0 })
-
-/**
- * Initialize a shared string that is based on initial input.
- *
- * @param string The string to initialize.
- * @param start The start of the string.
- * @param end The end of the string.
- */
-void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end);
-
-/**
- * Initialize an owned string that is responsible for freeing allocated memory.
- *
- * @param string The string to initialize.
- * @param source The source of the string.
- * @param length The length of the string.
- */
-void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length);
-
-/**
- * Initialize a constant string that doesn't own its memory source.
- *
- * @param string The string to initialize.
- * @param source The source of the string.
- * @param length The length of the string.
- */
-void pm_string_constant_init(pm_string_t *string, const char *source, size_t length);
-
-/**
- * Read the file indicated by the filepath parameter into source and load its
- * contents and size into the given `pm_string_t`. The given `pm_string_t`
- * should be freed using `pm_string_free` when it is no longer used.
- *
- * We want to use demand paging as much as possible in order to avoid having to
- * read the entire file into memory (which could be detrimental to performance
- * for large files). This means that if we're on windows we'll use
- * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use
- * `mmap`, and on other POSIX systems we'll use `read`.
- *
- * @param string The string to initialize.
- * @param filepath The filepath to read.
- * @return Whether or not the file was successfully mapped.
- */
-PRISM_EXPORTED_FUNCTION bool pm_string_mapped_init(pm_string_t *string, const char *filepath);
-
-/**
- * Returns the memory size associated with the string.
- *
- * @param string The string to get the memory size of.
- * @return The size of the memory associated with the string.
- */
-size_t pm_string_memsize(const pm_string_t *string);
-
-/**
- * Ensure the string is owned. If it is not, then reinitialize it as owned and
- * copy over the previous source.
- *
- * @param string The string to ensure is owned.
- */
-void pm_string_ensure_owned(pm_string_t *string);
-
-/**
- * Returns the length associated with the string.
- *
- * @param string The string to get the length of.
- * @return The length of the string.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string);
-
-/**
- * Returns the start pointer associated with the string.
- *
- * @param string The string to get the start pointer of.
- * @return The start pointer of the string.
- */
-PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string);
-
-/**
- * Free the associated memory of the given string.
- *
- * @param string The string to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string);
-
-#endif
diff --git a/prism/util/pm_string_list.c b/prism/util/pm_string_list.c
deleted file mode 100644
index d49e4ed734..0000000000
--- a/prism/util/pm_string_list.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "prism/util/pm_string_list.h"
-
-/**
- * Append a pm_string_t to the given string list.
- */
-void
-pm_string_list_append(pm_string_list_t *string_list, pm_string_t *string) {
- if (string_list->length + 1 > string_list->capacity) {
- if (string_list->capacity == 0) {
- string_list->capacity = 1;
- } else {
- string_list->capacity *= 2;
- }
-
- string_list->strings = realloc(string_list->strings, string_list->capacity * sizeof(pm_string_t));
- if (string_list->strings == NULL) abort();
- }
-
- string_list->strings[string_list->length++] = *string;
-}
-
-/**
- * Free the memory associated with the string list
- */
-void
-pm_string_list_free(pm_string_list_t *string_list) {
- free(string_list->strings);
-}
diff --git a/prism/util/pm_string_list.h b/prism/util/pm_string_list.h
deleted file mode 100644
index 0d406cc5d8..0000000000
--- a/prism/util/pm_string_list.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * @file pm_string_list.h
- *
- * A list of strings.
- */
-#ifndef PRISM_STRING_LIST_H
-#define PRISM_STRING_LIST_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_string.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-
-/**
- * A list of strings.
- */
-typedef struct {
- /** The length of the string list. */
- size_t length;
-
- /** The capacity of the string list that has been allocated. */
- size_t capacity;
-
- /** A pointer to the start of the string list. */
- pm_string_t *strings;
-} pm_string_list_t;
-
-/**
- * Append a pm_string_t to the given string list.
- *
- * @param string_list The string list to append to.
- * @param string The string to append.
- */
-void pm_string_list_append(pm_string_list_t *string_list, pm_string_t *string);
-
-/**
- * Free the memory associated with the string list.
- *
- * @param string_list The string list to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_string_list_free(pm_string_list_t *string_list);
-
-#endif
diff --git a/prism/util/pm_strncasecmp.c b/prism/util/pm_strncasecmp.c
deleted file mode 100644
index 2240bf8110..0000000000
--- a/prism/util/pm_strncasecmp.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "prism/util/pm_strncasecmp.h"
-
-/**
- * Compare two strings, ignoring case, up to the given length. Returns 0 if the
- * strings are equal, a negative number if string1 is less than string2, or a
- * positive number if string1 is greater than string2.
- *
- * Note that this is effectively our own implementation of strncasecmp, but it's
- * not available on all of the platforms we want to support so we're rolling it
- * here.
- */
-int
-pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length) {
- size_t offset = 0;
- int difference = 0;
-
- while (offset < length && string1[offset] != '\0') {
- if (string2[offset] == '\0') return string1[offset];
- if ((difference = tolower(string1[offset]) - tolower(string2[offset])) != 0) return difference;
- offset++;
- }
-
- return difference;
-}
diff --git a/prism/util/pm_strncasecmp.h b/prism/util/pm_strncasecmp.h
deleted file mode 100644
index 5cb88cb5eb..0000000000
--- a/prism/util/pm_strncasecmp.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @file pm_strncasecmp.h
- *
- * A custom strncasecmp implementation.
- */
-#ifndef PRISM_STRNCASECMP_H
-#define PRISM_STRNCASECMP_H
-
-#include "prism/defines.h"
-
-#include <ctype.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * Compare two strings, ignoring case, up to the given length. Returns 0 if the
- * strings are equal, a negative number if string1 is less than string2, or a
- * positive number if string1 is greater than string2.
- *
- * Note that this is effectively our own implementation of strncasecmp, but it's
- * not available on all of the platforms we want to support so we're rolling it
- * here.
- *
- * @param string1 The first string to compare.
- * @param string2 The second string to compare
- * @param length The maximum number of characters to compare.
- * @return 0 if the strings are equal, a negative number if string1 is less than
- * string2, or a positive number if string1 is greater than string2.
- */
-int pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length);
-
-#endif
diff --git a/prism/util/pm_strpbrk.c b/prism/util/pm_strpbrk.c
deleted file mode 100644
index ce1f36910b..0000000000
--- a/prism/util/pm_strpbrk.c
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "prism/util/pm_strpbrk.h"
-
-/**
- * This is the slow path that does care about the encoding.
- */
-static inline const uint8_t *
-pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum) {
- size_t index = 0;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- size_t width = parser->encoding.char_width(source + index, (ptrdiff_t) (maximum - index));
- if (width == 0) {
- return NULL;
- }
-
- index += width;
- }
-
- return NULL;
-}
-
-/**
- * This is the fast path that does not care about the encoding.
- */
-static inline const uint8_t *
-pm_strpbrk_single_byte(const uint8_t *source, const uint8_t *charset, size_t maximum) {
- size_t index = 0;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- index++;
- }
-
- return NULL;
-}
-
-/**
- * Here we have rolled our own version of strpbrk. The standard library strpbrk
- * has undefined behavior when the source string is not null-terminated. We want
- * to support strings that are not null-terminated because pm_parse does not
- * have the contract that the string is null-terminated. (This is desirable
- * because it means the extension can call pm_parse with the result of a call to
- * mmap).
- *
- * The standard library strpbrk also does not support passing a maximum length
- * to search. We want to support this for the reason mentioned above, but we
- * also don't want it to stop on null bytes. Ruby actually allows null bytes
- * within strings, comments, regular expressions, etc. So we need to be able to
- * skip past them.
- *
- * Finally, we want to support encodings wherein the charset could contain
- * characters that are trailing bytes of multi-byte characters. For example, in
- * Shift-JIS, the backslash character can be a trailing byte. In that case we
- * need to take a slower path and iterate one multi-byte character at a time.
- */
-const uint8_t *
-pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length) {
- if (length <= 0) {
- return NULL;
- } else if (parser->encoding_changed && parser->encoding.multibyte) {
- return pm_strpbrk_multi_byte(parser, source, charset, (size_t) length);
- } else {
- return pm_strpbrk_single_byte(source, charset, (size_t) length);
- }
-}
diff --git a/prism/util/pm_strpbrk.h b/prism/util/pm_strpbrk.h
deleted file mode 100644
index 61a443e51a..0000000000
--- a/prism/util/pm_strpbrk.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * @file pm_strpbrk.h
- *
- * A custom strpbrk implementation.
- */
-#ifndef PRISM_STRPBRK_H
-#define PRISM_STRPBRK_H
-
-#include "prism/defines.h"
-#include "prism/parser.h"
-
-#include <stddef.h>
-#include <string.h>
-
-/**
- * Here we have rolled our own version of strpbrk. The standard library strpbrk
- * has undefined behavior when the source string is not null-terminated. We want
- * to support strings that are not null-terminated because pm_parse does not
- * have the contract that the string is null-terminated. (This is desirable
- * because it means the extension can call pm_parse with the result of a call to
- * mmap).
- *
- * The standard library strpbrk also does not support passing a maximum length
- * to search. We want to support this for the reason mentioned above, but we
- * also don't want it to stop on null bytes. Ruby actually allows null bytes
- * within strings, comments, regular expressions, etc. So we need to be able to
- * skip past them.
- *
- * Finally, we want to support encodings wherein the charset could contain
- * characters that are trailing bytes of multi-byte characters. For example, in
- * Shift-JIS, the backslash character can be a trailing byte. In that case we
- * need to take a slower path and iterate one multi-byte character at a time.
- *
- * @param parser The parser.
- * @param source The source string.
- * @param charset The charset to search for.
- * @param length The maximum length to search.
- * @return A pointer to the first character in the source string that is in the
- * charset, or NULL if no such character exists.
- */
-const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length);
-
-#endif
diff --git a/prism/version.h b/prism/version.h
deleted file mode 100644
index 6d0bea616d..0000000000
--- a/prism/version.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * @file version.h
- *
- * The version of the Prism library.
- */
-#ifndef PRISM_VERSION_H
-#define PRISM_VERSION_H
-
-/**
- * The major version of the Prism library as an int.
- */
-#define PRISM_VERSION_MAJOR 0
-
-/**
- * The minor version of the Prism library as an int.
- */
-#define PRISM_VERSION_MINOR 17
-
-/**
- * The patch version of the Prism library as an int.
- */
-#define PRISM_VERSION_PATCH 1
-
-/**
- * The version of the Prism library as a constant string.
- */
-#define PRISM_VERSION "0.17.1"
-
-#endif
diff --git a/prism_compile.c b/prism_compile.c
deleted file mode 100644
index 3f02b858f9..0000000000
--- a/prism_compile.c
+++ /dev/null
@@ -1,3814 +0,0 @@
-#include "prism.h"
-
-#define OLD_ISEQ NEW_ISEQ
-#undef NEW_ISEQ
-
-#define NEW_ISEQ(node, name, type, line_no) \
- pm_new_child_iseq(iseq, (node), parser, rb_fstring(name), 0, (type), (line_no))
-
-#define OLD_CHILD_ISEQ NEW_CHILD_ISEQ
-#undef NEW_CHILD_ISEQ
-
-#define NEW_CHILD_ISEQ(node, name, type, line_no) \
- pm_new_child_iseq(iseq, (node), parser, rb_fstring(name), iseq, (type), (line_no))
-
-#define PM_COMPILE(node) \
- pm_compile_node(iseq, (node), ret, src, popped, scope_node)
-
-#define PM_COMPILE_INTO_ANCHOR(_ret, node) \
- pm_compile_node(iseq, (node), _ret, src, popped, scope_node)
-
-#define PM_COMPILE_POPPED(node) \
- pm_compile_node(iseq, (node), ret, src, true, scope_node)
-
-#define PM_COMPILE_NOT_POPPED(node) \
- pm_compile_node(iseq, (node), ret, src, false, scope_node)
-
-#define PM_POP \
- ADD_INSN(ret, &dummy_line_node, pop);
-
-#define PM_POP_IF_POPPED \
- if (popped) PM_POP;
-
-#define PM_POP_UNLESS_POPPED \
- if (!popped) PM_POP;
-
-#define PM_DUP \
- ADD_INSN(ret, &dummy_line_node, dup);
-
-#define PM_DUP_UNLESS_POPPED \
- if (!popped) PM_DUP;
-
-#define PM_PUTSELF \
- ADD_INSN(ret, &dummy_line_node, putself);
-
-#define PM_PUTNIL \
- ADD_INSN(ret, &dummy_line_node, putnil);
-
-#define PM_PUTNIL_UNLESS_POPPED \
- if (!popped) PM_PUTNIL;
-
-#define PM_SWAP \
- ADD_INSN(ret, &dummy_line_node, swap);
-
-#define PM_SWAP_UNLESS_POPPED \
- if (!popped) PM_SWAP;
-
-/**
- * We're using the top most bit of a pm_constant_id_t as a tag to represent an
- * anonymous local. When a child iseq is created and needs access to a value
- * that has yet to be defined, or is defined by the parent node's iseq. This can
- * be added to it's local table and then handled accordingly when compiling the
- * scope node associated with the child iseq.
- *
- * See the compilation process for PM_FOR_NODE: as an example, where the
- * variable referenced inside the StatementsNode is defined as part of the top
- * level ForLoop node.
-*/
-#define TEMP_CONSTANT_IDENTIFIER ((pm_constant_id_t)(1 << 31))
-
-rb_iseq_t *
-pm_iseq_new_with_opt(pm_scope_node_t *scope_node, pm_parser_t *parser, VALUE name, VALUE path, VALUE realpath,
- int first_lineno, const rb_iseq_t *parent, int isolated_depth,
- enum rb_iseq_type type, const rb_compile_option_t *option);
-
-static VALUE
-parse_integer(const pm_integer_node_t *node)
-{
- const char *start = (const char *) node->base.location.start;
- const char *end = (const char *) node->base.location.end;
-
- size_t length = end - start;
- int base = -10;
-
- switch (node->base.flags & (PM_INTEGER_BASE_FLAGS_BINARY | PM_INTEGER_BASE_FLAGS_DECIMAL | PM_INTEGER_BASE_FLAGS_OCTAL | PM_INTEGER_BASE_FLAGS_HEXADECIMAL)) {
- case PM_INTEGER_BASE_FLAGS_BINARY:
- base = 2;
- break;
- case PM_INTEGER_BASE_FLAGS_DECIMAL:
- base = 10;
- break;
- case PM_INTEGER_BASE_FLAGS_OCTAL:
- base = 8;
- break;
- case PM_INTEGER_BASE_FLAGS_HEXADECIMAL:
- base = 16;
- break;
- default:
- rb_bug("Unexpected integer base");
- }
-
- return rb_int_parse_cstr(start, length, NULL, NULL, base, RB_INT_PARSE_DEFAULT);
-}
-
-static VALUE
-parse_float(const pm_node_t *node)
-{
- const uint8_t *start = node->location.start;
- const uint8_t *end = node->location.end;
- size_t length = end - start;
-
- char *buffer = malloc(length + 1);
- memcpy(buffer, start, length);
-
- buffer[length] = '\0';
- VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 0));
-
- free(buffer);
- return number;
-}
-
-static VALUE
-parse_rational(const pm_node_t *node)
-{
- const uint8_t *start = node->location.start;
- const uint8_t *end = node->location.end - 1;
- size_t length = end - start;
-
- VALUE res;
- if (PM_NODE_TYPE_P(((pm_rational_node_t *)node)->numeric, PM_FLOAT_NODE)) {
- char *buffer = malloc(length + 1);
- memcpy(buffer, start, length);
-
- buffer[length] = '\0';
-
- char *decimal = memchr(buffer, '.', length);
- RUBY_ASSERT(decimal);
- size_t seen_decimal = decimal - buffer;
- size_t fraclen = length - seen_decimal - 1;
- memmove(decimal, decimal + 1, fraclen + 1);
-
- VALUE v = rb_cstr_to_inum(buffer, 10, false);
- res = rb_rational_new(v, rb_int_positive_pow(10, fraclen));
-
- free(buffer);
- }
- else {
- RUBY_ASSERT(PM_NODE_TYPE_P(((pm_rational_node_t *)node)->numeric, PM_INTEGER_NODE));
- VALUE number = rb_int_parse_cstr((const char *)start, length, NULL, NULL, -10, RB_INT_PARSE_DEFAULT);
- res = rb_rational_raw(number, INT2FIX(1));
- }
-
- return res;
-}
-
-static VALUE
-parse_imaginary(pm_imaginary_node_t *node)
-{
- VALUE imaginary_part;
- switch (PM_NODE_TYPE(node->numeric)) {
- case PM_FLOAT_NODE: {
- imaginary_part = parse_float(node->numeric);
- break;
- }
- case PM_INTEGER_NODE: {
- imaginary_part = parse_integer((pm_integer_node_t *) node->numeric);
- break;
- }
- case PM_RATIONAL_NODE: {
- imaginary_part = parse_rational(node->numeric);
- break;
- }
- default:
- rb_bug("Unexpected numeric type on imaginary number");
- }
-
- return rb_complex_raw(INT2FIX(0), imaginary_part);
-}
-
-static inline VALUE
-parse_string(pm_string_t *string, const pm_parser_t *parser)
-{
- rb_encoding *enc = rb_enc_from_index(rb_enc_find_index(parser->encoding.name));
- return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), enc);
-}
-
-static inline ID
-parse_symbol(const uint8_t *start, const uint8_t *end, pm_parser_t *parser)
-{
- rb_encoding *enc = rb_enc_from_index(rb_enc_find_index(parser->encoding.name));
- return rb_intern3((const char *) start, end - start, enc);
-}
-
-static inline ID
-parse_string_symbol(pm_string_t *string, pm_parser_t *parser)
-{
- const uint8_t *start = pm_string_source(string);
- return parse_symbol(start, start + pm_string_length(string), parser);
-}
-
-static inline ID
-parse_location_symbol(pm_location_t *location, pm_parser_t *parser)
-{
- return parse_symbol(location->start, location->end, parser);
-}
-
-static int
-pm_optimizable_range_item_p(pm_node_t *node)
-{
- return (!node || PM_NODE_TYPE_P(node, PM_INTEGER_NODE) || PM_NODE_TYPE_P(node, PM_NIL_NODE));
-}
-
-#define RE_OPTION_ENCODING_SHIFT 8
-
-/**
- * Check the prism flags of a regular expression-like node and return the flags
- * that are expected by the CRuby VM.
- */
-static int
-pm_reg_flags(const pm_node_t *node) {
- int flags = 0;
- int dummy = 0;
-
- // Check "no encoding" first so that flags don't get clobbered
- // We're calling `rb_char_to_option_kcode` in this case so that
- // we don't need to have access to `ARG_ENCODING_NONE`
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
- rb_char_to_option_kcode('n', &flags, &dummy);
- }
-
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
- rb_char_to_option_kcode('e', &flags, &dummy);
- flags |= ('e' << RE_OPTION_ENCODING_SHIFT);
- }
-
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
- rb_char_to_option_kcode('s', &flags, &dummy);
- flags |= ('s' << RE_OPTION_ENCODING_SHIFT);
- }
-
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
- rb_char_to_option_kcode('u', &flags, &dummy);
- flags |= ('u' << RE_OPTION_ENCODING_SHIFT);
- }
-
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE) {
- flags |= ONIG_OPTION_IGNORECASE;
- }
-
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE) {
- flags |= ONIG_OPTION_MULTILINE;
- }
-
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_EXTENDED) {
- flags |= ONIG_OPTION_EXTEND;
- }
-
- return flags;
-}
-
-static rb_encoding *
-pm_reg_enc(const pm_regular_expression_node_t *node, const pm_parser_t *parser) {
- if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
- return rb_ascii8bit_encoding();
- }
-
- if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
- return rb_enc_get_from_index(ENCINDEX_EUC_JP);
- }
-
- if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
- return rb_enc_get_from_index(ENCINDEX_Windows_31J);
- }
-
- if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
- return rb_utf8_encoding();
- }
-
- return rb_enc_from_index(rb_enc_find_index(parser->encoding.name));
-}
-
-/**
- * Certain nodes can be compiled literally, which can lead to further
- * optimizations. These nodes will all have the PM_NODE_FLAG_STATIC_LITERAL flag
- * set.
- */
-static inline bool
-pm_static_literal_p(const pm_node_t *node)
-{
- return node->flags & PM_NODE_FLAG_STATIC_LITERAL;
-}
-
-static VALUE
-pm_new_regex(pm_regular_expression_node_t * cast, const pm_parser_t * parser) {
- VALUE regex_str = parse_string(&cast->unescaped, parser);
- rb_encoding * enc = pm_reg_enc(cast, parser);
-
- return rb_enc_reg_new(RSTRING_PTR(regex_str), RSTRING_LEN(regex_str), enc, pm_reg_flags((const pm_node_t *)cast));
-}
-
-/**
- * Certain nodes can be compiled literally. This function returns the literal
- * value described by the given node. For example, an array node with all static
- * literal values can be compiled into a literal array.
- */
-static inline VALUE
-pm_static_literal_value(const pm_node_t *node, pm_scope_node_t *scope_node, pm_parser_t *parser)
-{
- // Every node that comes into this function should already be marked as
- // static literal. If it's not, then we have a bug somewhere.
- assert(pm_static_literal_p(node));
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ARRAY_NODE: {
- pm_array_node_t *cast = (pm_array_node_t *) node;
- pm_node_list_t *elements = &cast->elements;
-
- VALUE value = rb_ary_hidden_new(elements->size);
- for (size_t index = 0; index < elements->size; index++) {
- rb_ary_push(value, pm_static_literal_value(elements->nodes[index], scope_node, parser));
- }
-
- OBJ_FREEZE(value);
- return value;
- }
- case PM_FALSE_NODE:
- return Qfalse;
- case PM_FLOAT_NODE:
- return parse_float(node);
- case PM_HASH_NODE: {
- pm_hash_node_t *cast = (pm_hash_node_t *) node;
- pm_node_list_t *elements = &cast->elements;
-
- VALUE array = rb_ary_hidden_new(elements->size * 2);
- for (size_t index = 0; index < elements->size; index++) {
- assert(PM_NODE_TYPE_P(elements->nodes[index], PM_ASSOC_NODE));
- pm_assoc_node_t *cast = (pm_assoc_node_t *) elements->nodes[index];
- VALUE pair[2] = { pm_static_literal_value(cast->key, scope_node, parser), pm_static_literal_value(cast->value, scope_node, parser) };
- rb_ary_cat(array, pair, 2);
- }
-
- VALUE value = rb_hash_new_with_size(elements->size);
- rb_hash_bulk_insert(RARRAY_LEN(array), RARRAY_CONST_PTR(array), value);
-
- value = rb_obj_hide(value);
- OBJ_FREEZE(value);
- return value;
- }
- case PM_IMAGINARY_NODE:
- return parse_imaginary((pm_imaginary_node_t *) node);
- case PM_INTEGER_NODE:
- return parse_integer((pm_integer_node_t *) node);
- case PM_NIL_NODE:
- return Qnil;
- case PM_RATIONAL_NODE:
- return parse_rational(node);
- case PM_REGULAR_EXPRESSION_NODE: {
- pm_regular_expression_node_t *cast = (pm_regular_expression_node_t *) node;
-
- return pm_new_regex(cast, parser);
- }
- case PM_SOURCE_ENCODING_NODE: {
- rb_encoding *encoding = rb_find_encoding(rb_str_new_cstr(scope_node->parser->encoding.name));
- if (!encoding) rb_bug("Encoding not found!");
- return rb_enc_from_encoding(encoding);
- }
- case PM_SOURCE_FILE_NODE: {
- pm_source_file_node_t *cast = (pm_source_file_node_t *)node;
- return cast->filepath.length ? parse_string(&cast->filepath, parser) : rb_fstring_lit("<compiled>");
- }
- case PM_SOURCE_LINE_NODE: {
- int source_line = (int) pm_newline_list_line_column(&scope_node->parser->newline_list, node->location.start).line;
- // Ruby treats file lines as 1-indexed
- // TODO: Incorporate options which allow for passing a line number
- source_line += 1;
- return INT2FIX(source_line);
- }
- case PM_STRING_NODE:
- return parse_string(&((pm_string_node_t *) node)->unescaped, parser);
- case PM_SYMBOL_NODE:
- return ID2SYM(parse_string_symbol(&((pm_symbol_node_t *) node)->unescaped, parser));
- case PM_TRUE_NODE:
- return Qtrue;
- default:
- rb_raise(rb_eArgError, "Don't have a literal value for this type");
- return Qfalse;
- }
-}
-
-static void
-pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond,
- LABEL *then_label, LABEL *else_label, const uint8_t *src, bool popped, pm_scope_node_t *scope_node);
-
-static void
-pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond,
- LABEL *then_label, LABEL *else_label, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
-{
- pm_parser_t *parser = scope_node->parser;
- pm_newline_list_t newline_list = parser->newline_list;
- int lineno = (int)pm_newline_list_line_column(&newline_list, cond->location.start).line;
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
-
- DECL_ANCHOR(seq);
- INIT_ANCHOR(seq);
- LABEL *label = NEW_LABEL(lineno);
- if (!then_label) then_label = label;
- else if (!else_label) else_label = label;
-
- pm_compile_branch_condition(iseq, seq, cond, then_label, else_label, src, popped, scope_node);
-
- if (LIST_INSN_SIZE_ONE(seq)) {
- INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
- if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
- return;
- }
- if (!label->refcnt) {
- PM_PUTNIL;
- }
- else {
- ADD_LABEL(seq, label);
- }
- ADD_SEQ(ret, seq);
- return;
-}
-
-static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node);
-
-static void
-pm_compile_flip_flop(pm_flip_flop_node_t *flip_flop_node, LABEL *else_label, LABEL *then_label, rb_iseq_t *iseq, const int lineno, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
-{
- NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
- LABEL *lend = NEW_LABEL(lineno);
-
- int again = !(flip_flop_node->base.flags & PM_RANGE_FLAGS_EXCLUDE_END);
-
- rb_num_t count = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq) + VM_SVAR_FLIPFLOP_START;
- VALUE key = INT2FIX(count);
-
- ADD_INSN2(ret, &dummy_line_node, getspecial, key, INT2FIX(0));
- ADD_INSNL(ret, &dummy_line_node, branchif, lend);
-
- if (flip_flop_node->left) {
- PM_COMPILE(flip_flop_node->left);
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, else_label);
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSN1(ret, &dummy_line_node, setspecial, key);
- if (!again) {
- ADD_INSNL(ret, &dummy_line_node, jump, then_label);
- }
-
- ADD_LABEL(ret, lend);
- if (flip_flop_node->right) {
- PM_COMPILE(flip_flop_node->right);
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, then_label);
- ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
- ADD_INSN1(ret, &dummy_line_node, setspecial, key);
- ADD_INSNL(ret, &dummy_line_node, jump, then_label);
-}
-
-void pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *defined_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition);
-static void
-pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond,
- LABEL *then_label, LABEL *else_label, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
-{
- pm_parser_t *parser = scope_node->parser;
- pm_newline_list_t newline_list = parser->newline_list;
- int lineno = (int) pm_newline_list_line_column(&newline_list, cond->location.start).line;
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
-
-again:
- switch (PM_NODE_TYPE(cond)) {
- case PM_AND_NODE: {
- pm_and_node_t *and_node = (pm_and_node_t *)cond;
- pm_compile_logical(iseq, ret, and_node->left, NULL, else_label, src, popped, scope_node);
- cond = and_node->right;
- goto again;
- }
- case PM_OR_NODE: {
- pm_or_node_t *or_node = (pm_or_node_t *)cond;
- pm_compile_logical(iseq, ret, or_node->left, then_label, NULL, src, popped, scope_node);
- cond = or_node->right;
- goto again;
- }
- case PM_FALSE_NODE:
- case PM_NIL_NODE:
- ADD_INSNL(ret, &dummy_line_node, jump, else_label);
- return;
- case PM_FLOAT_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INTEGER_NODE:
- case PM_LAMBDA_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_TRUE_NODE:
- ADD_INSNL(ret, &dummy_line_node, jump, then_label);
- return;
- case PM_FLIP_FLOP_NODE:
- pm_compile_flip_flop((pm_flip_flop_node_t *)cond, else_label, then_label, iseq, lineno, ret, src, popped, scope_node);
- return;
- // TODO: Several more nodes in this case statement
- case PM_DEFINED_NODE: {
- pm_defined_node_t *defined_node = (pm_defined_node_t *)cond;
- pm_compile_defined_expr(iseq, defined_node->value, ret, src, popped, scope_node, dummy_line_node, lineno, true);
- break;
- }
- default: {
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
-
- pm_compile_node(iseq, cond, cond_seq, src, false, scope_node);
- ADD_SEQ(ret, cond_seq);
- break;
- }
- }
- ADD_INSNL(ret, &dummy_line_node, branchunless, else_label);
- ADD_INSNL(ret, &dummy_line_node, jump, then_label);
- return;
-}
-
-static void
-pm_compile_if(rb_iseq_t *iseq, const int line, pm_statements_node_t *node_body, pm_node_t *node_else, pm_node_t *predicate, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
-{
- NODE dummy_line_node = generate_dummy_line_node(line, line);
-
- DECL_ANCHOR(cond_seq);
-
- LABEL *then_label, *else_label, *end_label;
-
- INIT_ANCHOR(cond_seq);
- then_label = NEW_LABEL(line);
- else_label = NEW_LABEL(line);
- end_label = 0;
-
- pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, src, false, scope_node);
- ADD_SEQ(ret, cond_seq);
-
- if (then_label->refcnt) {
- ADD_LABEL(ret, then_label);
-
- DECL_ANCHOR(then_seq);
- INIT_ANCHOR(then_seq);
- if (node_body) {
- pm_compile_node(iseq, (pm_node_t *)node_body, then_seq, src, popped, scope_node);
- } else {
- PM_PUTNIL_UNLESS_POPPED;
- }
-
- if (else_label->refcnt) {
- end_label = NEW_LABEL(line);
- ADD_INSNL(then_seq, &dummy_line_node, jump, end_label);
- if (!popped) {
- ADD_INSN(then_seq, &dummy_line_node, pop);
- }
- }
- ADD_SEQ(ret, then_seq);
- }
-
- if (else_label->refcnt) {
- ADD_LABEL(ret, else_label);
-
- DECL_ANCHOR(else_seq);
- INIT_ANCHOR(else_seq);
- if (node_else) {
- pm_compile_node(iseq, (pm_node_t *)node_else, else_seq, src, popped, scope_node);
- }
- else {
- PM_PUTNIL_UNLESS_POPPED;
- }
-
- ADD_SEQ(ret, else_seq);
- }
-
- if (end_label) {
- ADD_LABEL(ret, end_label);
- }
-
- return;
-}
-
-static void
-pm_compile_while(rb_iseq_t *iseq, int lineno, pm_node_flags_t flags, enum pm_node_type type, pm_statements_node_t *statements, pm_node_t *predicate, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
-{
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
-
- LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
- LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
- LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
-
- // TODO: Deal with ensures in here
- LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(lineno); /* next */
- LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(lineno); /* redo */
- LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(lineno); /* break */
- LABEL *end_label = NEW_LABEL(lineno);
- LABEL *adjust_label = NEW_LABEL(lineno);
-
- LABEL *next_catch_label = NEW_LABEL(lineno);
- LABEL *tmp_label = NULL;
-
- // begin; end while true
- if (flags & PM_LOOP_FLAGS_BEGIN_MODIFIER) {
- tmp_label = NEW_LABEL(lineno);
- ADD_INSNL(ret, &dummy_line_node, jump, tmp_label);
- }
- else {
- // while true; end
- ADD_INSNL(ret, &dummy_line_node, jump, next_label);
- }
-
- ADD_LABEL(ret, adjust_label);
- PM_PUTNIL;
- ADD_LABEL(ret, next_catch_label);
- PM_POP;
- ADD_INSNL(ret, &dummy_line_node, jump, next_label);
- if (tmp_label) ADD_LABEL(ret, tmp_label);
-
- ADD_LABEL(ret, redo_label);
- if (statements) {
- PM_COMPILE_POPPED((pm_node_t *)statements);
- }
-
- ADD_LABEL(ret, next_label);
-
- if (type == PM_WHILE_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, src, popped, scope_node);
- } else if (type == PM_UNTIL_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, src, popped, scope_node);
- }
-
- ADD_LABEL(ret, end_label);
- ADD_ADJUST_RESTORE(ret, adjust_label);
-
- PM_PUTNIL;
-
- ADD_LABEL(ret, break_label);
-
- PM_POP_IF_POPPED;
-
- ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
- break_label);
- ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
- next_catch_label);
- ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
- ISEQ_COMPILE_DATA(iseq)->redo_label);
-
- ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
- ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
- ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
- return;
-}
-
-static void
-pm_interpolated_node_compile(pm_node_list_t parts, rb_iseq_t *iseq, NODE dummy_line_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, pm_parser_t *parser)
-{
- size_t parts_size = parts.size;
-
- if (parts_size > 0) {
- for (size_t index = 0; index < parts_size; index++) {
- pm_node_t *part = parts.nodes[index];
-
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- pm_string_node_t *string_node = (pm_string_node_t *) part;
- ADD_INSN1(ret, &dummy_line_node, putobject, parse_string(&string_node->unescaped, parser));
- }
- else {
- PM_COMPILE_NOT_POPPED(part);
- PM_DUP;
- ADD_INSN1(ret, &dummy_line_node, objtostring, new_callinfo(iseq, idTo_s, 0, VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE , NULL, FALSE));
- ADD_INSN(ret, &dummy_line_node, anytostring);
- }
- }
- }
- else {
- PM_PUTNIL;
- }
-}
-
-static int
-pm_lookup_local_index(rb_iseq_t *iseq, pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
-{
- st_data_t local_index;
-
- int num_params = ISEQ_BODY(iseq)->param.size;
-
- if (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
- rb_bug("This local does not exist");
- }
-
- return num_params - (int)local_index;
-}
-
-static int
-pm_lookup_local_index_with_depth(rb_iseq_t *iseq, pm_scope_node_t *scope_node, pm_constant_id_t constant_id, uint32_t depth)
-{
- for(uint32_t i = 0; i < depth; i++) {
- scope_node = scope_node->previous;
- iseq = (rb_iseq_t *)ISEQ_BODY(iseq)->parent_iseq;
- }
-
- return pm_lookup_local_index(iseq, scope_node, constant_id);
-}
-
-// This returns the CRuby ID which maps to the pm_constant_id_t
-//
-// Constant_ids in prism are indexes of the constants in prism's constant pool.
-// We add a constants mapping on the scope_node which is a mapping from
-// these constant_id indexes to the CRuby IDs that they represent.
-// This helper method allows easy access to those IDs
-static ID
-pm_constant_id_lookup(pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
-{
- if (constant_id < 1 || constant_id > scope_node->parser->constant_pool.size) {
- rb_raise(rb_eArgError, "[PRISM] constant_id out of range: %u", (unsigned int)constant_id);
- }
- return scope_node->constants[constant_id - 1];
-}
-
-static rb_iseq_t *
-pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t node, pm_parser_t *parser,
- VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
-{
- debugs("[new_child_iseq]> ---------------------------------------\n");
- int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
- rb_iseq_t * ret_iseq = pm_iseq_new_with_opt(&node, parser, name,
- rb_iseq_path(iseq), rb_iseq_realpath(iseq),
- line_no, parent,
- isolated_depth ? isolated_depth + 1 : 0,
- type, ISEQ_COMPILE_DATA(iseq)->option);
- debugs("[new_child_iseq]< ---------------------------------------\n");
- return ret_iseq;
-}
-
-static int
-pm_compile_class_path(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const pm_node_t *constant_path_node, const NODE *line_node, const uint8_t * src, bool popped, pm_scope_node_t *scope_node)
-{
- if (PM_NODE_TYPE_P(constant_path_node, PM_CONSTANT_PATH_NODE)) {
- pm_node_t *parent = ((pm_constant_path_node_t *)constant_path_node)->parent;
- if (parent) {
- /* Bar::Foo */
- PM_COMPILE(parent);
- return VM_DEFINECLASS_FLAG_SCOPED;
- }
- else {
- /* toplevel class ::Foo */
- ADD_INSN1(ret, line_node, putobject, rb_cObject);
- return VM_DEFINECLASS_FLAG_SCOPED;
- }
- }
- else {
- /* class at cbase Foo */
- ADD_INSN1(ret, line_node, putspecialobject,
- INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- return 0;
- }
-}
-
-static void
-pm_compile_call_and_or_write_node(bool and_node, pm_node_t *receiver, pm_node_t *value, pm_constant_id_t write_name, pm_constant_id_t read_name, LINK_ANCHOR *const ret, rb_iseq_t *iseq, int lineno, const uint8_t * src, bool popped, pm_scope_node_t *scope_node)
-{
- LABEL *call_end_label = NEW_LABEL(lineno);
- LABEL *end_label = NEW_LABEL(lineno);
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
-
- int flag = 0;
-
- if (PM_NODE_TYPE_P(receiver, PM_SELF_NODE)) {
- flag = VM_CALL_FCALL;
- }
-
- PM_COMPILE_NOT_POPPED(receiver);
-
- ID write_name_id = pm_constant_id_lookup(scope_node, write_name);
- ID read_name_id = pm_constant_id_lookup(scope_node, read_name);
- PM_DUP;
-
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, read_name_id, INT2FIX(0), INT2FIX(flag));
-
- PM_DUP_UNLESS_POPPED;
-
- if (and_node) {
- ADD_INSNL(ret, &dummy_line_node, branchunless, call_end_label);
- }
- else {
- // or_node
- ADD_INSNL(ret, &dummy_line_node, branchif, call_end_label);
- }
-
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(value);
- if (!popped) {
- PM_SWAP;
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
- }
- ID aid = rb_id_attrset(write_name_id);
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, aid, INT2FIX(1), INT2FIX(flag));
- ADD_INSNL(ret, &dummy_line_node, jump, end_label);
- ADD_LABEL(ret, call_end_label);
-
- if (!popped) {
- PM_SWAP;
- }
-
- ADD_LABEL(ret, end_label);
- PM_POP;
- return;
-}
-
-/**
- * In order to properly compile multiple-assignment, some preprocessing needs to
- * be performed in the case of call or constant path targets. This is when they
- * are read, the "parent" of each of these nodes should only be read once (the
- * receiver in the case of a call, the parent constant in the case of a constant
- * path).
- */
-static uint8_t
-pm_compile_multi_write_lhs(rb_iseq_t *iseq, NODE dummy_line_node, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, uint8_t pushed, bool nested)
-{
- switch (PM_NODE_TYPE(node)) {
- case PM_MULTI_TARGET_NODE: {
- pm_multi_target_node_t *cast = (pm_multi_target_node_t *) node;
- for (size_t index = 0; index < cast->lefts.size; index++) {
- pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->lefts.nodes[index], ret, scope_node, pushed, false);
- }
- break;
- }
- case PM_CONSTANT_PATH_TARGET_NODE: {
- pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *)node;
- if (cast->parent) {
- PM_PUTNIL;
- pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->parent, ret, scope_node, pushed, false);
- } else {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
- break;
- }
- case PM_CONSTANT_PATH_NODE: {
- pm_constant_path_node_t *cast = (pm_constant_path_node_t *) node;
- if (cast->parent) {
- pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->parent, ret, scope_node, pushed, false);
- } else {
- PM_POP;
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
- pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->child, ret, scope_node, pushed, cast->parent);
- break;
- }
- case PM_CONSTANT_READ_NODE: {
- pm_constant_read_node_t *cast = (pm_constant_read_node_t *) node;
- ADD_INSN1(ret, &dummy_line_node, putobject, RBOOL(!nested));
- ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(pm_constant_id_lookup(scope_node, cast->name)));
- pushed = pushed + 2;
- break;
- }
- default:
- break;
- }
-
- return pushed;
-}
-
-/**
- * Compile a pattern matching expression.
- */
-static int
-pm_compile_pattern(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, pm_scope_node_t *scope_node, LABEL *matched_label, LABEL *unmatched_label, bool in_alternation_pattern)
-{
- int lineno = (int) pm_newline_list_line_column(&scope_node->parser->newline_list, node->location.start).line;
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ARRAY_PATTERN_NODE:
- rb_bug("Array pattern matching not yet supported.");
- break;
- case PM_FIND_PATTERN_NODE:
- rb_bug("Find pattern matching not yet supported.");
- break;
- case PM_HASH_PATTERN_NODE:
- rb_bug("Hash pattern matching not yet supported.");
- break;
- case PM_CAPTURE_PATTERN_NODE:
- rb_bug("Capture pattern matching not yet supported.");
- break;
- case PM_IF_NODE: {
- // If guards can be placed on patterns to further limit matches based on
- // a dynamic predicate. This looks like:
- //
- // case foo
- // in bar if baz
- // end
- //
- pm_if_node_t *cast = (pm_if_node_t *) node;
-
- pm_compile_pattern(iseq, cast->statements->body.nodes[0], ret, src, scope_node, matched_label, unmatched_label, in_alternation_pattern);
- PM_COMPILE_NOT_POPPED(cast->predicate);
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, unmatched_label);
- ADD_INSNL(ret, &dummy_line_node, jump, matched_label);
- break;
- }
- case PM_UNLESS_NODE: {
- // Unless guards can be placed on patterns to further limit matches
- // based on a dynamic predicate. This looks like:
- //
- // case foo
- // in bar unless baz
- // end
- //
- pm_unless_node_t *cast = (pm_unless_node_t *) node;
-
- pm_compile_pattern(iseq, cast->statements->body.nodes[0], ret, src, scope_node, matched_label, unmatched_label, in_alternation_pattern);
- PM_COMPILE_NOT_POPPED(cast->predicate);
-
- ADD_INSNL(ret, &dummy_line_node, branchif, unmatched_label);
- ADD_INSNL(ret, &dummy_line_node, jump, matched_label);
- break;
- }
- case PM_LOCAL_VARIABLE_TARGET_NODE: {
- // Local variables can be targetted by placing identifiers in the place
- // of a pattern. For example, foo in bar. This results in the value
- // being matched being written to that local variable.
- pm_local_variable_target_node_t *cast = (pm_local_variable_target_node_t *) node;
- int index = pm_lookup_local_index(iseq, scope_node, cast->name);
-
- // If this local variable is being written from within an alternation
- // pattern, then it cannot actually be added to the local table since
- // it's ambiguous which value should be used. So instead we indicate
- // this with a compile error.
- if (in_alternation_pattern) {
- ID id = pm_constant_id_lookup(scope_node, cast->name);
- const char *name = rb_id2name(id);
-
- if (name && strlen(name) > 0 && name[0] != '_') {
- COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id));
- return COMPILE_NG;
- }
- }
-
- ADD_SETLOCAL(ret, &dummy_line_node, index, (int) cast->depth);
- ADD_INSNL(ret, &dummy_line_node, jump, matched_label);
- break;
- }
- case PM_ALTERNATION_PATTERN_NODE: {
- // Alternation patterns allow you to specify multiple patterns in a
- // single expression using the | operator.
- pm_alternation_pattern_node_t *cast = (pm_alternation_pattern_node_t *) node;
-
- LABEL *matched_left_label = NEW_LABEL(lineno);
- LABEL *unmatched_left_label = NEW_LABEL(lineno);
-
- // First, we're going to attempt to match against the left pattern. If
- // that pattern matches, then we'll skip matching the right pattern.
- PM_DUP;
- pm_compile_pattern(iseq, cast->left, ret, src, scope_node, matched_left_label, unmatched_left_label, true);
-
- // If we get here, then we matched on the left pattern. In this case we
- // should pop out the duplicate value that we preemptively added to
- // match against the right pattern and then jump to the match label.
- ADD_LABEL(ret, matched_left_label);
- PM_POP;
- ADD_INSNL(ret, &dummy_line_node, jump, matched_label);
- PM_PUTNIL;
-
- // If we get here, then we didn't match on the left pattern. In this
- // case we attempt to match against the right pattern.
- ADD_LABEL(ret, unmatched_left_label);
- pm_compile_pattern(iseq, cast->right, ret, src, scope_node, matched_label, unmatched_label, true);
- break;
- }
- case PM_ARRAY_NODE:
- case PM_CLASS_VARIABLE_READ_NODE:
- case PM_CONSTANT_PATH_NODE:
- case PM_CONSTANT_READ_NODE:
- case PM_FALSE_NODE:
- case PM_FLOAT_NODE:
- case PM_GLOBAL_VARIABLE_READ_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INSTANCE_VARIABLE_READ_NODE:
- case PM_INTEGER_NODE:
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- case PM_INTERPOLATED_STRING_NODE:
- case PM_INTERPOLATED_SYMBOL_NODE:
- case PM_INTERPOLATED_X_STRING_NODE:
- case PM_LAMBDA_NODE:
- case PM_LOCAL_VARIABLE_READ_NODE:
- case PM_NIL_NODE:
- case PM_RANGE_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SELF_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_TRUE_NODE:
- case PM_X_STRING_NODE:
- // These nodes are all simple patterns, which means we'll use the
- // checkmatch instruction to match against them, which is effectively a
- // VM-level === operator.
- PM_COMPILE_NOT_POPPED(node);
- ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
- ADD_INSNL(ret, &dummy_line_node, branchif, matched_label);
- ADD_INSNL(ret, &dummy_line_node, jump, unmatched_label);
- break;
- case PM_PINNED_VARIABLE_NODE: {
- // Pinned variables are a way to match against the value of a variable
- // without it looking like you're trying to write to the variable. This
- // looks like: foo in ^@bar. To compile these, we compile the variable
- // that they hold.
- pm_pinned_variable_node_t *cast = (pm_pinned_variable_node_t *) node;
- pm_compile_pattern(iseq, cast->variable, ret, src, scope_node, matched_label, unmatched_label, false);
- break;
- }
- case PM_PINNED_EXPRESSION_NODE: {
- // Pinned expressions are a way to match against the value of an
- // expression that should be evaluated at runtime. This looks like:
- // foo in ^(bar). To compile these, we compile the expression that they
- // hold.
- pm_pinned_expression_node_t *cast = (pm_pinned_expression_node_t *) node;
- pm_compile_pattern(iseq, cast->expression, ret, src, scope_node, matched_label, unmatched_label, false);
- break;
- }
- default:
- // If we get here, then we have a node type that should not be in this
- // position. This would be a bug in the parser, because a different node
- // type should never have been created in this position in the tree.
- rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- break;
- }
-
- return COMPILE_OK;
-}
-
-// Generate a scope node from the given node.
-void
-pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous, pm_parser_t *parser)
-{
- scope->base.type = PM_SCOPE_NODE;
- scope->base.location.start = node->location.start;
- scope->base.location.end = node->location.end;
-
- scope->previous = previous;
- scope->parser = parser;
- scope->ast_node = (pm_node_t *)node;
- scope->parameters = NULL;
- scope->body = NULL;
- scope->constants = NULL;
- if (previous) {
- scope->constants = previous->constants;
- }
- scope->index_lookup_table = NULL;
-
- pm_constant_id_list_init(&scope->locals);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_BLOCK_NODE: {
- pm_block_node_t *cast = (pm_block_node_t *) node;
- if (cast->parameters) scope->parameters = cast->parameters->parameters;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_CLASS_NODE: {
- pm_class_node_t *cast = (pm_class_node_t *) node;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_DEF_NODE: {
- pm_def_node_t *cast = (pm_def_node_t *) node;
- scope->parameters = cast->parameters;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_ENSURE_NODE: {
- pm_ensure_node_t *cast = (pm_ensure_node_t *)node;
- scope->body = (pm_node_t *)cast->statements;
- break;
- }
- case PM_FOR_NODE: {
- pm_for_node_t *cast = (pm_for_node_t *)node;
- scope->body = (pm_node_t *)cast->statements;
- break;
- }
- case PM_LAMBDA_NODE: {
- pm_lambda_node_t *cast = (pm_lambda_node_t *) node;
- if (cast->parameters) scope->parameters = cast->parameters->parameters;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_MODULE_NODE: {
- pm_module_node_t *cast = (pm_module_node_t *) node;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_POST_EXECUTION_NODE: {
- pm_post_execution_node_t *cast = (pm_post_execution_node_t *) node;
- scope->body = (pm_node_t *) cast->statements;
- break;
- }
- case PM_PROGRAM_NODE: {
- pm_program_node_t *cast = (pm_program_node_t *) node;
- scope->body = (pm_node_t *) cast->statements;
- scope->locals = cast->locals;
- break;
- }
- case PM_SINGLETON_CLASS_NODE: {
- pm_singleton_class_node_t *cast = (pm_singleton_class_node_t *) node;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_STATEMENTS_NODE: {
- pm_statements_node_t *cast = (pm_statements_node_t *) node;
- scope->body = (pm_node_t *)cast;
- break;
- }
- default:
- assert(false && "unreachable");
- break;
- }
-}
-
-void
-pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition, LABEL **lfinish)
-{
- // in_condition is the same as compile.c's needstr
- enum defined_type dtype = DEFINED_NOT_DEFINED;
- switch (PM_NODE_TYPE(node)) {
- case PM_NIL_NODE: {
- dtype = DEFINED_NIL;
- break;
- }
- case PM_SELF_NODE:
- dtype = DEFINED_SELF;
- break;
- case PM_TRUE_NODE:
- dtype = DEFINED_TRUE;
- break;
- case PM_FALSE_NODE:
- dtype = DEFINED_FALSE;
- break;
- case PM_ARRAY_NODE: {
- pm_array_node_t *array_node = (pm_array_node_t *) node;
- for (size_t index = 0; index < array_node->elements.size; index++) {
- pm_compile_defined_expr0(iseq, array_node->elements.nodes[index], ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish);
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(lineno);
- }
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
- }
- }
- case PM_STRING_NODE:
- case PM_AND_NODE:
- case PM_OR_NODE:
- dtype = DEFINED_EXPR;
- break;
- case PM_LOCAL_VARIABLE_READ_NODE:
- dtype = DEFINED_LVAR;
- break;
-#define PUSH_VAL(type) (in_condition ? Qtrue : rb_iseq_defined_string(type))
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- pm_instance_variable_read_node_t *instance_variable_read_node = (pm_instance_variable_read_node_t *)node;
- ID id = pm_constant_id_lookup(scope_node, instance_variable_read_node->name);
- ADD_INSN3(ret, &dummy_line_node, definedivar,
- ID2SYM(id), get_ivar_ic_value(iseq, id), PUSH_VAL(DEFINED_IVAR));
- return;
- }
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- pm_global_variable_read_node_t *glabal_variable_read_node = (pm_global_variable_read_node_t *)node;
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_GVAR),
- ID2SYM(pm_constant_id_lookup(scope_node, glabal_variable_read_node->name)), PUSH_VAL(DEFINED_GVAR));
- return;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- pm_class_variable_read_node_t *class_variable_read_node = (pm_class_variable_read_node_t *)node;
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CVAR),
- ID2SYM(pm_constant_id_lookup(scope_node, class_variable_read_node->name)), PUSH_VAL(DEFINED_CVAR));
-
- return;
- }
- case PM_CONSTANT_READ_NODE: {
- pm_constant_read_node_t *constant_node = (pm_constant_read_node_t *)node;
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST),
- ID2SYM(pm_constant_id_lookup(scope_node, constant_node->name)), PUSH_VAL(DEFINED_CONST));
- return;
- }
- case PM_CONSTANT_PATH_NODE: {
- pm_constant_path_node_t *constant_path_node = ((pm_constant_path_node_t *)node);
- if (constant_path_node->parent) {
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(lineno);
- }
- pm_compile_defined_expr0(iseq, constant_path_node->parent, ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish);
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
- PM_COMPILE(constant_path_node->parent);
- } else {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST_FROM),
- ID2SYM(pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t *)constant_path_node->child)->name)), PUSH_VAL(DEFINED_CONST));
- return;
- }
-
- case PM_YIELD_NODE:
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_YIELD), 0,
- PUSH_VAL(DEFINED_YIELD));
- return;
- case PM_SUPER_NODE:
- case PM_FORWARDING_SUPER_NODE:
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
- PUSH_VAL(DEFINED_ZSUPER));
- return;
- case PM_CONSTANT_WRITE_NODE:
- case PM_CONSTANT_OPERATOR_WRITE_NODE:
- case PM_CONSTANT_AND_WRITE_NODE:
- case PM_CONSTANT_OR_WRITE_NODE:
-
- case PM_GLOBAL_VARIABLE_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_AND_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_OR_WRITE_NODE:
-
- case PM_CLASS_VARIABLE_WRITE_NODE:
- case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_CLASS_VARIABLE_AND_WRITE_NODE:
- case PM_CLASS_VARIABLE_OR_WRITE_NODE:
-
- case PM_INSTANCE_VARIABLE_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_AND_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_OR_WRITE_NODE:
-
- case PM_LOCAL_VARIABLE_WRITE_NODE:
- case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_LOCAL_VARIABLE_AND_WRITE_NODE:
- case PM_LOCAL_VARIABLE_OR_WRITE_NODE:
-
- case PM_MULTI_WRITE_NODE:
- dtype = DEFINED_ASGN;
- break;
- default:
- assert(0 && "TODO");
- }
-
- assert(dtype != DEFINED_NOT_DEFINED);
-
- ADD_INSN1(ret, &dummy_line_node, putobject, PUSH_VAL(dtype));
-#undef PUSH_VAL
-}
-
-void
-pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition)
-{
- LABEL *lfinish[2];
- LINK_ELEMENT *last = ret->last;
-
- lfinish[0] = NEW_LABEL(lineno);
- lfinish[1] = 0;
-
- if (!popped) {
- pm_compile_defined_expr0(iseq, node, ret, src, popped, scope_node, dummy_line_node, lineno, in_condition, lfinish);
- }
-
- if (lfinish[1]) {
- ELEM_INSERT_NEXT(last, &new_insn_body(iseq, &dummy_line_node, BIN(putnil), 0)->link);
- ADD_INSN(ret, &dummy_line_node, swap);
- ADD_INSN(ret, &dummy_line_node, pop);
- ADD_LABEL(ret, lfinish[1]);
- }
- ADD_LABEL(ret, lfinish[0]);
-}
-
-static int
-pm_setup_args(pm_arguments_node_t *arguments_node, int *flags, struct rb_callinfo_kwarg **kw_arg, rb_iseq_t *iseq, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, pm_parser_t *parser)
-{
- int orig_argc = 0;
- if (arguments_node == NULL) {
- if (*flags & VM_CALL_FCALL) {
- *flags |= VM_CALL_VCALL;
- }
- }
- else {
- pm_node_list_t arguments_node_list = arguments_node->arguments;
-
- bool has_keyword_splat = (arguments_node->base.flags & PM_ARGUMENTS_NODE_FLAGS_KEYWORD_SPLAT);
- bool has_splat = false;
-
- // We count the number of elements post the splat node that are not keyword elements to
- // eventually pass as an argument to newarray
- int post_splat_counter = 0;
-
- for (size_t index = 0; index < arguments_node_list.size; index++) {
- pm_node_t *argument = arguments_node_list.nodes[index];
-
- switch (PM_NODE_TYPE(argument)) {
- // A keyword hash node contains all keyword arguments as AssocNodes and AssocSplatNodes
- case PM_KEYWORD_HASH_NODE: {
- pm_keyword_hash_node_t *keyword_arg = (pm_keyword_hash_node_t *)argument;
- size_t len = keyword_arg->elements.size;
-
- if (has_keyword_splat) {
- int cur_hash_size = 0;
- orig_argc++;
-
- bool new_hash_emitted = false;
- for (size_t i = 0; i < len; i++) {
- pm_node_t *cur_node = keyword_arg->elements.nodes[i];
-
- pm_node_type_t cur_type = PM_NODE_TYPE(cur_node);
-
- switch (PM_NODE_TYPE(cur_node)) {
- case PM_ASSOC_NODE: {
- pm_assoc_node_t *assoc = (pm_assoc_node_t *)cur_node;
-
- PM_COMPILE(assoc->key);
- PM_COMPILE(assoc->value);
- cur_hash_size++;
-
- // If we're at the last keyword arg, or the last assoc node of this "set",
- // then we want to either construct a newhash or merge onto previous hashes
- if (i == (len - 1) || !PM_NODE_TYPE_P(keyword_arg->elements.nodes[i + 1], cur_type)) {
- if (new_hash_emitted) {
- ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(cur_hash_size * 2 + 1));
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(cur_hash_size * 2));
- cur_hash_size = 0;
- new_hash_emitted = true;
- }
- }
-
- break;
- }
- case PM_ASSOC_SPLAT_NODE: {
- if (len > 1) {
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- if (i == 0) {
- ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(0));
- new_hash_emitted = true;
- }
- else {
- PM_SWAP;
- }
- }
-
- pm_assoc_splat_node_t *assoc_splat = (pm_assoc_splat_node_t *)cur_node;
- PM_COMPILE(assoc_splat->value);
-
- *flags |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
-
- if (len > 1) {
- ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_kwd, INT2FIX(2));
- }
-
- if ((i < len - 1) && !PM_NODE_TYPE_P(keyword_arg->elements.nodes[i + 1], cur_type)) {
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PM_SWAP;
- }
-
- cur_hash_size = 0;
- break;
- }
- default: {
- rb_bug("Unknown type");
- }
- }
- }
- break;
- }
- else {
- *kw_arg = rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- *flags |= VM_CALL_KWARG;
- (*kw_arg)->keyword_len += len;
-
- // TODO: Method callers like `foo(a => b)`
- for (size_t i = 0; i < len; i++) {
- pm_assoc_node_t *assoc = (pm_assoc_node_t *)keyword_arg->elements.nodes[i];
- (*kw_arg)->keywords[i] = pm_static_literal_value(assoc->key, scope_node, parser);
- PM_COMPILE(assoc->value);
- }
- }
- break;
- }
- case PM_SPLAT_NODE: {
- *flags |= VM_CALL_ARGS_SPLAT;
- pm_splat_node_t *splat_node = (pm_splat_node_t *)argument;
- if (splat_node->expression) {
- orig_argc++;
- PM_COMPILE_NOT_POPPED(splat_node->expression);
- }
-
- ADD_INSN1(ret, &dummy_line_node, splatarray, popped ? Qfalse : Qtrue);
-
- has_splat = true;
- post_splat_counter = 0;
-
- break;
- }
- case PM_FORWARDING_ARGUMENTS_NODE: {
- orig_argc++;
- *flags |= VM_CALL_ARGS_BLOCKARG | VM_CALL_ARGS_SPLAT;
- ADD_GETLOCAL(ret, &dummy_line_node, 3, 0);
- ADD_INSN1(ret, &dummy_line_node, splatarray, RBOOL(arguments_node_list.size > 1));
- ADD_INSN2(ret, &dummy_line_node, getblockparamproxy, INT2FIX(4), INT2FIX(0));
- break;
- }
- default: {
- orig_argc++;
- post_splat_counter++;
- PM_COMPILE_NOT_POPPED(argument);
-
- if (has_splat) {
- // If the next node starts the keyword section of parameters
- if ((index < arguments_node_list.size - 1) && PM_NODE_TYPE_P(arguments_node_list.nodes[index + 1], PM_KEYWORD_HASH_NODE)) {
-
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(post_splat_counter));
- ADD_INSN1(ret, &dummy_line_node, splatarray, Qfalse);
- ADD_INSN(ret, &dummy_line_node, concatarray);
- }
- // If it's the final node
- else if (index == arguments_node_list.size - 1) {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(post_splat_counter));
- ADD_INSN(ret, &dummy_line_node, concatarray);
- }
- }
- }
- }
- }
- }
- return orig_argc;
-}
-
-/*
- * Compiles a prism node into instruction sequences
- *
- * iseq - The current instruction sequence object (used for locals)
- * node - The prism node to compile
- * ret - The linked list of instructions to append instructions onto
- * popped - True if compiling something with no side effects, so instructions don't
- * need to be added
- * scope_node - Stores parser and local information
- */
-static void
-pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
-{
- pm_parser_t *parser = scope_node->parser;
- pm_newline_list_t newline_list = parser->newline_list;
- int lineno = (int)pm_newline_list_line_column(&newline_list, node->location.start).line;
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ALIAS_GLOBAL_VARIABLE_NODE: {
- pm_alias_global_variable_node_t *alias_node = (pm_alias_global_variable_node_t *) node;
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- ADD_INSN1(ret, &dummy_line_node, putobject, ID2SYM(parse_location_symbol(&alias_node->new_name->location, parser)));
- ADD_INSN1(ret, &dummy_line_node, putobject, ID2SYM(parse_location_symbol(&alias_node->old_name->location, parser)));
-
- ADD_SEND(ret, &dummy_line_node, id_core_set_variable_alias, INT2FIX(2));
-
- PM_POP_IF_POPPED;
- return;
- }
- case PM_ALIAS_METHOD_NODE: {
- pm_alias_method_node_t *alias_node = (pm_alias_method_node_t *) node;
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
-
- PM_COMPILE_NOT_POPPED(alias_node->new_name);
- PM_COMPILE_NOT_POPPED(alias_node->old_name);
-
- ADD_SEND(ret, &dummy_line_node, id_core_set_method_alias, INT2FIX(3));
-
- PM_POP_IF_POPPED;
-
- return;
- }
- case PM_AND_NODE: {
- pm_and_node_t *and_node = (pm_and_node_t *) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
- PM_COMPILE_NOT_POPPED(and_node->left);
- PM_DUP_UNLESS_POPPED;
- ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
-
- PM_POP_UNLESS_POPPED;
- PM_COMPILE(and_node->right);
- ADD_LABEL(ret, end_label);
- return;
- }
- case PM_ARGUMENTS_NODE: {
- pm_arguments_node_t *arguments_node = (pm_arguments_node_t *) node;
- pm_node_list_t node_list = arguments_node->arguments;
- for (size_t index = 0; index < node_list.size; index++) {
- PM_COMPILE(node_list.nodes[index]);
- }
- return;
- }
- case PM_ARRAY_NODE: {
- // If every node in the array is static, then we can compile the entire
- // array now instead of later.
- if (pm_static_literal_p(node)) {
- // We're only going to compile this node if it's not popped. If it
- // is popped, then we know we don't need to do anything since it's
- // statically known.
- if (!popped) {
- VALUE value = pm_static_literal_value(node, scope_node, parser);
- ADD_INSN1(ret, &dummy_line_node, duparray, value);
- RB_OBJ_WRITTEN(iseq, Qundef, value);
- }
- } else {
- // Here since we know there are possible side-effects inside the
- // array contents, we're going to build it entirely at runtime.
- // We'll do this by pushing all of the elements onto the stack and
- // then combining them with newarray.
- //
- // If this hash is popped, then this serves only to ensure we enact
- // all side-effects (like method calls) that are contained within
- // the hash contents.
- pm_array_node_t *cast = (pm_array_node_t *) node;
- pm_node_list_t *elements = &cast->elements;
-
- for (size_t index = 0; index < elements->size; index++) {
- PM_COMPILE(elements->nodes[index]);
- }
-
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(elements->size));
- }
- }
-
- return;
- }
- case PM_ASSOC_NODE: {
- pm_assoc_node_t *assoc_node = (pm_assoc_node_t *) node;
- PM_COMPILE(assoc_node->key);
- if (assoc_node->value) {
- PM_COMPILE(assoc_node->value);
- }
- return;
- }
- case PM_ASSOC_SPLAT_NODE: {
- pm_assoc_splat_node_t *assoc_splat_node = (pm_assoc_splat_node_t *)node;
-
- PM_COMPILE(assoc_splat_node->value);
- return;
- }
- case PM_BACK_REFERENCE_READ_NODE: {
- if (!popped) {
- // Since a back reference is `$<char>`, ruby represents the ID as the
- // an rb_intern on the value after the `$`.
- char *char_ptr = (char *)(node->location.start) + 1;
- ID backref_val = INT2FIX(rb_intern2(char_ptr, 1)) << 1 | 1;
- ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(1), backref_val);
- }
- return;
- }
- case PM_BEGIN_NODE: {
- pm_begin_node_t *begin_node = (pm_begin_node_t *) node;
- rb_iseq_t *child_iseq;
- LABEL *lstart = NEW_LABEL(lineno);
- LABEL *lend = NEW_LABEL(lineno);
-
- ADD_LABEL(ret, lstart);
- if (begin_node->statements) {
- PM_COMPILE((pm_node_t *)begin_node->statements);
- }
- else {
- PM_PUTNIL_UNLESS_POPPED;
- }
- ADD_LABEL(ret, lend);
-
- if (begin_node->ensure_clause) {
- DECL_ANCHOR(ensr);
-
- iseq_set_exception_local_table(iseq);
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)begin_node->ensure_clause, &next_scope_node, scope_node, parser);
-
- child_iseq = NEW_CHILD_ISEQ(next_scope_node,
- rb_str_new2("ensure in"),
- ISEQ_TYPE_ENSURE, lineno);
-
- LABEL *lcont = NEW_LABEL(lineno);
- struct ensure_range er;
- struct iseq_compile_data_ensure_node_stack enl;
- struct ensure_range *erange;
-
- INIT_ANCHOR(ensr);
- PM_COMPILE_INTO_ANCHOR(ensr, (pm_node_t *)&next_scope_node);
-
- er.begin = lstart;
- er.end = lend;
- er.next = 0;
- push_ensure_entry(iseq, &enl, &er, (void *)&next_scope_node);
-
- ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
- ADD_SEQ(ret, ensr);
- ADD_LABEL(ret, lcont);
- erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
- if (lstart->link.next != &lend->link) {
- while (erange) {
- ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end, child_iseq, lcont);
- erange = erange->next;
- }
- }
- PM_POP_UNLESS_POPPED;
- }
- return;
- }
- case PM_BLOCK_ARGUMENT_NODE: {
- pm_block_argument_node_t *block_argument_node = (pm_block_argument_node_t *) node;
- if (block_argument_node->expression) {
- PM_COMPILE(block_argument_node->expression);
- }
- return;
- }
- case PM_BREAK_NODE: {
- pm_break_node_t *break_node = (pm_break_node_t *) node;
- if (break_node->arguments) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)break_node->arguments);
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
-
- return;
- }
- case PM_CALL_NODE: {
- pm_call_node_t *call_node = (pm_call_node_t *) node;
-
- ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
- int flags = 0;
- struct rb_callinfo_kwarg *kw_arg = NULL;
-
- if (call_node->receiver == NULL) {
- PM_PUTSELF;
- } else {
- PM_COMPILE_NOT_POPPED(call_node->receiver);
- }
-
- int orig_argc = pm_setup_args(call_node->arguments, &flags, &kw_arg, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
-
- const rb_iseq_t *block_iseq = NULL;
- if (call_node->block != NULL && PM_NODE_TYPE_P(call_node->block, PM_BLOCK_NODE)) {
- // Scope associated with the block
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(call_node->block, &next_scope_node, scope_node, parser);
-
- block_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
- ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
- }
- else {
- if (node->flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) {
- flags |= VM_CALL_VCALL;
- }
-
- if (call_node->block != NULL) {
- PM_COMPILE_NOT_POPPED(call_node->block);
- flags |= VM_CALL_ARGS_BLOCKARG;
- }
-
- if (!flags) {
- flags |= VM_CALL_ARGS_SIMPLE;
- }
- }
-
- if (call_node->receiver == NULL) {
- flags |= VM_CALL_FCALL;
- }
-
- ADD_SEND_R(ret, &dummy_line_node, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
- PM_POP_IF_POPPED;
- return;
- }
- case PM_CALL_AND_WRITE_NODE: {
- pm_call_and_write_node_t *call_and_write_node = (pm_call_and_write_node_t*) node;
-
- pm_compile_call_and_or_write_node(true, call_and_write_node->receiver, call_and_write_node->value, call_and_write_node->write_name, call_and_write_node->read_name, ret, iseq, lineno, src, popped, scope_node);
-
- return;
- }
- case PM_CALL_OR_WRITE_NODE: {
- pm_call_or_write_node_t *call_or_write_node = (pm_call_or_write_node_t*) node;
-
- pm_compile_call_and_or_write_node(false, call_or_write_node->receiver, call_or_write_node->value, call_or_write_node->write_name, call_or_write_node->read_name, ret, iseq, lineno, src, popped, scope_node);
-
- return;
- }
- case PM_CALL_OPERATOR_WRITE_NODE: {
- pm_call_operator_write_node_t *call_operator_write_node = (pm_call_operator_write_node_t*) node;
-
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
-
- int flag = 0;
-
- if (PM_NODE_TYPE_P(call_operator_write_node->receiver, PM_SELF_NODE)) {
- flag = VM_CALL_FCALL;
- }
-
- PM_COMPILE_NOT_POPPED(call_operator_write_node->receiver);
-
- ID write_name_id = pm_constant_id_lookup(scope_node, call_operator_write_node->write_name);
- ID read_name_id = pm_constant_id_lookup(scope_node, call_operator_write_node->read_name);
- ID operator_id = pm_constant_id_lookup(scope_node, call_operator_write_node->operator);
- PM_DUP;
-
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, read_name_id, INT2FIX(0), INT2FIX(flag));
-
- PM_COMPILE_NOT_POPPED(call_operator_write_node->value);
- ADD_SEND(ret, &dummy_line_node, operator_id, INT2FIX(1));
-
- if (!popped) {
- PM_SWAP;
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
- }
-
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, write_name_id, INT2FIX(1), INT2FIX(flag));
- PM_POP;
-
- return;
- }
- case PM_CASE_NODE: {
- pm_case_node_t *case_node = (pm_case_node_t *)node;
- bool has_predicate = case_node->predicate;
- if (has_predicate) {
- PM_COMPILE_NOT_POPPED(case_node->predicate);
- }
- LABEL *end_label = NEW_LABEL(lineno);
-
- pm_node_list_t conditions = case_node->conditions;
-
- LABEL **conditions_labels = (LABEL **)ALLOC_N(VALUE, conditions.size + 1);
- LABEL *label;
-
- for (size_t i = 0; i < conditions.size; i++) {
- label = NEW_LABEL(lineno);
- conditions_labels[i] = label;
- if (has_predicate) {
- pm_when_node_t *when_node = (pm_when_node_t *)conditions.nodes[i];
-
- for (size_t i = 0; i < when_node->conditions.size; i++) {
- PM_COMPILE_NOT_POPPED(when_node->conditions.nodes[i]);
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idEqq, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
- ADD_INSNL(ret, &dummy_line_node, branchif, label);
- }
- }
- else {
- ADD_INSNL(ret, &dummy_line_node, jump, label);
- PM_PUTNIL;
- }
- }
-
- if (has_predicate) {
- PM_POP;
-
- if (case_node->consequent) {
- if (!popped || !PM_NODE_TYPE_P(((pm_node_t *)case_node->consequent), PM_ELSE_NODE)) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)case_node->consequent);
- }
- }
- else {
- PM_PUTNIL_UNLESS_POPPED;
- }
- }
-
- ADD_INSNL(ret, &dummy_line_node, jump, end_label);
-
- for (size_t i = 0; i < conditions.size; i++) {
- label = conditions_labels[i];
- ADD_LABEL(ret, label);
- if (has_predicate) {
- PM_POP;
- }
-
- pm_while_node_t *condition_node = (pm_while_node_t *)conditions.nodes[i];
- if (condition_node->statements) {
- PM_COMPILE((pm_node_t *)condition_node->statements);
- }
- else {
- PM_PUTNIL_UNLESS_POPPED;
- }
-
- ADD_INSNL(ret, &dummy_line_node, jump, end_label);
- }
-
- ADD_LABEL(ret, end_label);
- return;
- }
- case PM_CLASS_NODE: {
- pm_class_node_t *class_node = (pm_class_node_t *)node;
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)class_node, &next_scope_node, scope_node, parser);
-
- ID class_id = pm_constant_id_lookup(scope_node, class_node->name);
-
- VALUE class_name = rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(class_id)));
-
- const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(next_scope_node, class_name, ISEQ_TYPE_CLASS, lineno);
-
- // TODO: Once we merge constant path nodes correctly, fix this flag
- const int flags = VM_DEFINECLASS_TYPE_CLASS |
- (class_node->superclass ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
- pm_compile_class_path(ret, iseq, class_node->constant_path, &dummy_line_node, src, false, scope_node);
-
- if (class_node->superclass) {
- PM_COMPILE_NOT_POPPED(class_node->superclass);
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_INSN3(ret, &dummy_line_node, defineclass, ID2SYM(class_id), class_iseq, INT2FIX(flags));
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
-
- PM_POP_IF_POPPED;
- return;
- }
- case PM_CLASS_VARIABLE_AND_WRITE_NODE: {
- pm_class_variable_and_write_node_t *class_variable_and_write_node = (pm_class_variable_and_write_node_t*) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
-
- ID class_variable_name_id = pm_constant_id_lookup(scope_node, class_variable_and_write_node->name);
- VALUE class_variable_name_val = ID2SYM(class_variable_name_id);
-
- ADD_INSN2(ret, &dummy_line_node, getclassvariable,
- class_variable_name_val,
- get_cvar_ic_value(iseq, class_variable_name_id));
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(class_variable_and_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN2(ret, &dummy_line_node, setclassvariable,
- class_variable_name_val,
- get_cvar_ic_value(iseq, class_variable_name_id));
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_class_variable_operator_write_node_t *class_variable_operator_write_node = (pm_class_variable_operator_write_node_t*) node;
-
- ID class_variable_name_id = pm_constant_id_lookup(scope_node, class_variable_operator_write_node->name);
- VALUE class_variable_name_val = ID2SYM(class_variable_name_id);
-
- ADD_INSN2(ret, &dummy_line_node, getclassvariable,
- class_variable_name_val,
- get_cvar_ic_value(iseq, class_variable_name_id));
-
- PM_COMPILE_NOT_POPPED(class_variable_operator_write_node->value);
- ID method_id = pm_constant_id_lookup(scope_node, class_variable_operator_write_node->operator);
-
- int flags = VM_CALL_ARGS_SIMPLE;
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN2(ret, &dummy_line_node, setclassvariable,
- class_variable_name_val,
- get_cvar_ic_value(iseq, class_variable_name_id));
-
- return;
- }
- case PM_CLASS_VARIABLE_OR_WRITE_NODE: {
- pm_class_variable_or_write_node_t *class_variable_or_write_node = (pm_class_variable_or_write_node_t*) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
-
- ID class_variable_name_id = pm_constant_id_lookup(scope_node, class_variable_or_write_node->name);
- VALUE class_variable_name_val = ID2SYM(class_variable_name_id);
-
- ADD_INSN2(ret, &dummy_line_node, getclassvariable,
- class_variable_name_val,
- get_cvar_ic_value(iseq, class_variable_name_id));
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(class_variable_or_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN2(ret, &dummy_line_node, setclassvariable,
- class_variable_name_val,
- get_cvar_ic_value(iseq, class_variable_name_id));
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- if (!popped) {
- pm_class_variable_read_node_t *class_variable_read_node = (pm_class_variable_read_node_t *) node;
- ID cvar_name = pm_constant_id_lookup(scope_node, class_variable_read_node->name);
- ADD_INSN2(ret, &dummy_line_node, getclassvariable, ID2SYM(cvar_name), get_cvar_ic_value(iseq, cvar_name));
- }
- return;
- }
- case PM_CLASS_VARIABLE_TARGET_NODE: {
- pm_class_variable_target_node_t *write_node = (pm_class_variable_target_node_t *) node;
- ID cvar_name = pm_constant_id_lookup(scope_node, write_node->name);
- ADD_INSN2(ret, &dummy_line_node, setclassvariable, ID2SYM(cvar_name), get_cvar_ic_value(iseq, cvar_name));
- return;
- }
- case PM_CLASS_VARIABLE_WRITE_NODE: {
- pm_class_variable_write_node_t *write_node = (pm_class_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(write_node->value);
- PM_DUP_UNLESS_POPPED;
-
- ID cvar_name = pm_constant_id_lookup(scope_node, write_node->name);
- ADD_INSN2(ret, &dummy_line_node, setclassvariable, ID2SYM(cvar_name), get_cvar_ic_value(iseq, cvar_name));
- return;
- }
- case PM_CONSTANT_PATH_NODE: {
- pm_constant_path_node_t *constant_path_node = (pm_constant_path_node_t*) node;
- if (constant_path_node->parent) {
- PM_COMPILE_NOT_POPPED(constant_path_node->parent);
- } else {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
- ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
-
- assert(PM_NODE_TYPE_P(constant_path_node->child, PM_CONSTANT_READ_NODE));
- pm_constant_read_node_t *child = (pm_constant_read_node_t *) constant_path_node->child;
-
- ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(pm_constant_id_lookup(scope_node, child->name)));
- PM_POP_IF_POPPED;
- return;
- }
- case PM_CONSTANT_PATH_AND_WRITE_NODE: {
- pm_constant_path_and_write_node_t *constant_path_and_write_node = (pm_constant_path_and_write_node_t*) node;
-
- LABEL *lfin = NEW_LABEL(lineno);
-
- pm_constant_path_node_t *target = constant_path_and_write_node->target;
- PM_COMPILE_NOT_POPPED(target->parent);
-
- pm_constant_read_node_t *child = (pm_constant_read_node_t *)target->child;
- VALUE child_name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
-
- PM_DUP;
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSN1(ret, &dummy_line_node, getconstant, child_name);
-
- PM_DUP_UNLESS_POPPED;
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfin);
-
- PM_POP_UNLESS_POPPED;
- PM_COMPILE_NOT_POPPED(constant_path_and_write_node->value);
-
- if (popped) {
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, dupn, INT2FIX(2));
- PM_SWAP;
- }
-
- ADD_INSN1(ret, &dummy_line_node, setconstant, child_name);
- ADD_LABEL(ret, lfin);
-
- PM_SWAP_UNLESS_POPPED;
- PM_POP;
-
- return;
- }
- case PM_CONSTANT_PATH_OR_WRITE_NODE: {
- pm_constant_path_or_write_node_t *constant_path_or_write_node = (pm_constant_path_or_write_node_t*) node;
-
- LABEL *lassign = NEW_LABEL(lineno);
- LABEL *lfin = NEW_LABEL(lineno);
-
- pm_constant_path_node_t *target = constant_path_or_write_node->target;
- PM_COMPILE_NOT_POPPED(target->parent);
-
- pm_constant_read_node_t *child = (pm_constant_read_node_t *)target->child;
- VALUE child_name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
-
- PM_DUP;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST_FROM), child_name, Qtrue);
- ADD_INSNL(ret, &dummy_line_node, branchunless, lassign);
-
- PM_DUP;
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSN1(ret, &dummy_line_node, getconstant, child_name);
-
- PM_DUP_UNLESS_POPPED;
- ADD_INSNL(ret, &dummy_line_node, branchif, lfin);
-
- PM_POP_UNLESS_POPPED;
- ADD_LABEL(ret, lassign);
- PM_COMPILE_NOT_POPPED(constant_path_or_write_node->value);
-
- if (popped) {
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, dupn, INT2FIX(2));
- PM_SWAP;
- }
-
- ADD_INSN1(ret, &dummy_line_node, setconstant, child_name);
- ADD_LABEL(ret, lfin);
-
- PM_SWAP_UNLESS_POPPED;
- PM_POP;
-
- return;
- }
- case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE: {
- pm_constant_path_operator_write_node_t *constant_path_operator_write_node = (pm_constant_path_operator_write_node_t*) node;
-
- pm_constant_path_node_t *target = constant_path_operator_write_node->target;
- PM_COMPILE_NOT_POPPED(target->parent);
-
- PM_DUP;
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
-
- pm_constant_read_node_t *child = (pm_constant_read_node_t *)target->child;
- VALUE child_name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
- ADD_INSN1(ret, &dummy_line_node, getconstant, child_name);
-
- PM_COMPILE_NOT_POPPED(constant_path_operator_write_node->value);
- ID method_id = pm_constant_id_lookup(scope_node, constant_path_operator_write_node->operator);
- ADD_CALL(ret, &dummy_line_node, method_id, INT2FIX(1));
- PM_SWAP;
-
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
- PM_SWAP;
- }
-
- ADD_INSN1(ret, &dummy_line_node, setconstant, child_name);
- return ;
- }
- case PM_CONSTANT_PATH_TARGET_NODE: {
- pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *)node;
-
- if (cast->parent) {
- PM_COMPILE(cast->parent);
- }
-
- return;
- }
- case PM_CONSTANT_PATH_WRITE_NODE: {
- pm_constant_path_write_node_t *constant_path_write_node = (pm_constant_path_write_node_t*) node;
- if (constant_path_write_node->target->parent) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)constant_path_write_node->target->parent);
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
- PM_COMPILE_NOT_POPPED(constant_path_write_node->value);
- if (!popped) {
- PM_SWAP;
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
- }
- PM_SWAP;
- VALUE constant_name = ID2SYM(pm_constant_id_lookup(scope_node,
- ((pm_constant_read_node_t *)constant_path_write_node->target->child)->name));
- ADD_INSN1(ret, &dummy_line_node, setconstant, constant_name);
- return;
- }
- case PM_CONSTANT_READ_NODE: {
- pm_constant_read_node_t *constant_read_node = (pm_constant_read_node_t *) node;
- PM_PUTNIL;
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(pm_constant_id_lookup(scope_node, constant_read_node->name)));
- PM_POP_IF_POPPED;
- return;
- }
- case PM_CONSTANT_AND_WRITE_NODE: {
- pm_constant_and_write_node_t *constant_and_write_node = (pm_constant_and_write_node_t*) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
-
- VALUE constant_name = ID2SYM(pm_constant_id_lookup(scope_node, constant_and_write_node->name));
-
- PM_PUTNIL;
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSN1(ret, &dummy_line_node, getconstant, constant_name);
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(constant_and_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, &dummy_line_node, setconstant, constant_name);
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_CONSTANT_OPERATOR_WRITE_NODE: {
- pm_constant_operator_write_node_t *constant_operator_write_node = (pm_constant_operator_write_node_t*) node;
-
- ID constant_name = pm_constant_id_lookup(scope_node, constant_operator_write_node->name);
- PM_PUTNIL;
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(constant_name));
-
- PM_COMPILE_NOT_POPPED(constant_operator_write_node->value);
- ID method_id = pm_constant_id_lookup(scope_node, constant_operator_write_node->operator);
-
- int flags = VM_CALL_ARGS_SIMPLE;
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(constant_name));
-
- return;
- }
- case PM_CONSTANT_OR_WRITE_NODE: {
- pm_constant_or_write_node_t *constant_or_write_node = (pm_constant_or_write_node_t*) node;
-
- LABEL *set_label= NEW_LABEL(lineno);
- LABEL *end_label = NEW_LABEL(lineno);
-
- PM_PUTNIL;
- VALUE constant_name = ID2SYM(pm_constant_id_lookup(scope_node, constant_or_write_node->name));
-
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST), constant_name, Qtrue);
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, set_label);
-
- PM_PUTNIL;
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSN1(ret, &dummy_line_node, getconstant, constant_name);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- ADD_LABEL(ret, set_label);
- PM_COMPILE_NOT_POPPED(constant_or_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, &dummy_line_node, setconstant, constant_name);
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_CONSTANT_TARGET_NODE: {
- pm_constant_target_node_t *constant_write_node = (pm_constant_target_node_t *) node;
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(pm_constant_id_lookup(scope_node, constant_write_node->name)));
- return;
- }
- case PM_CONSTANT_WRITE_NODE: {
- pm_constant_write_node_t *constant_write_node = (pm_constant_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(constant_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(pm_constant_id_lookup(scope_node, constant_write_node->name)));
- return;
- }
- case PM_DEF_NODE: {
- pm_def_node_t *def_node = (pm_def_node_t *) node;
- ID method_name = pm_constant_id_lookup(scope_node, def_node->name);
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)def_node, &next_scope_node, scope_node, parser);
- rb_iseq_t *method_iseq = NEW_ISEQ(next_scope_node, rb_id2str(method_name), ISEQ_TYPE_METHOD, lineno);
-
- if (def_node->receiver) {
- PM_COMPILE_NOT_POPPED(def_node->receiver);
- ADD_INSN2(ret, &dummy_line_node, definesmethod, ID2SYM(method_name), method_iseq);
- }
- else {
- ADD_INSN2(ret, &dummy_line_node, definemethod, ID2SYM(method_name), method_iseq);
- }
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
-
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, putobject, ID2SYM(method_name));
- }
- return;
- }
- case PM_DEFINED_NODE: {
- pm_defined_node_t *defined_node = (pm_defined_node_t *)node;
- pm_compile_defined_expr(iseq, defined_node->value, ret, src, popped, scope_node, dummy_line_node, lineno, false);
- return;
- }
- case PM_EMBEDDED_STATEMENTS_NODE: {
- pm_embedded_statements_node_t *embedded_statements_node = (pm_embedded_statements_node_t *)node;
-
- if (embedded_statements_node->statements) {
- PM_COMPILE((pm_node_t *) (embedded_statements_node->statements));
- }
- else {
- PM_PUTNIL;
- }
-
- PM_POP_IF_POPPED;
- // TODO: Concatenate the strings that exist here
- return;
- }
- case PM_EMBEDDED_VARIABLE_NODE: {
- pm_embedded_variable_node_t *embedded_node = (pm_embedded_variable_node_t *)node;
- PM_COMPILE(embedded_node->variable);
- return;
- }
- case PM_FALSE_NODE:
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
- }
- return;
- case PM_ELSE_NODE: {
- pm_else_node_t *cast = (pm_else_node_t *)node;
- if (cast->statements) {
- PM_COMPILE((pm_node_t *)cast->statements);
- }
- else {
- PM_PUTNIL;
- }
- return;
- }
- case PM_FLIP_FLOP_NODE: {
- pm_flip_flop_node_t *flip_flop_node = (pm_flip_flop_node_t *)node;
-
- LABEL *final_label = NEW_LABEL(lineno);
- LABEL *then_label = NEW_LABEL(lineno);
- LABEL *else_label = NEW_LABEL(lineno);
-
- pm_compile_flip_flop(flip_flop_node, else_label, then_label, iseq, lineno, ret, src, popped, scope_node);
-
- ADD_LABEL(ret, then_label);
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSNL(ret, &dummy_line_node, jump, final_label);
- ADD_LABEL(ret, else_label);
- ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
- ADD_LABEL(ret, final_label);
- return;
- }
- case PM_FLOAT_NODE: {
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, putobject, parse_float(node));
- }
- return;
- }
- case PM_FOR_NODE: {
- pm_for_node_t *for_node = (pm_for_node_t *)node;
-
- const rb_iseq_t *child_iseq;
- const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
-
- LABEL *retry_label = NEW_LABEL(lineno);
- LABEL *retry_end_l = NEW_LABEL(lineno);
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)for_node, &next_scope_node, scope_node, parser);
-
- pm_constant_id_list_t locals;
- pm_constant_id_list_init(&locals);
- pm_constant_id_list_append(&locals, TEMP_CONSTANT_IDENTIFIER);
- next_scope_node.locals = locals;
-
- ADD_LABEL(ret, retry_label);
-
- PM_COMPILE_NOT_POPPED(for_node->collection);
-
- child_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
- ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
- ADD_SEND_WITH_BLOCK(ret, &dummy_line_node, idEach, INT2FIX(0), child_iseq);
-
- INSN *iobj;
- LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
- iobj = IS_INSN(last_elem) ? (INSN *)last_elem : (INSN *)get_prev_insn((INSN*)last_elem);
- while (INSN_OF(iobj) != BIN(send) &&
- INSN_OF(iobj) != BIN(invokesuper)) {
- iobj = (INSN *)get_prev_insn(iobj);
- }
- ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*)retry_end_l);
-
- PM_POP_IF_POPPED;
-
- ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
- ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
- return;
- }
- case PM_FORWARDING_ARGUMENTS_NODE: {
- rb_bug("Should never hit the forwarding arguments case directly\n");
- return;
- }
- case PM_FORWARDING_SUPER_NODE: {
- pm_forwarding_super_node_t *forwarding_super_node = (pm_forwarding_super_node_t *) node;
- const rb_iseq_t *block = NULL;
- PM_PUTSELF;
- int flag = VM_CALL_ZSUPER | VM_CALL_SUPER | VM_CALL_FCALL;
-
- if (forwarding_super_node->block) {
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)forwarding_super_node->block, &next_scope_node, scope_node, parser);
- block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
- }
-
- ADD_INSN2(ret, &dummy_line_node, invokesuper, new_callinfo(iseq, 0, 0, flag, NULL, block != NULL), block);
- PM_POP_IF_POPPED;
- return;
- }
- case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: {
- pm_global_variable_and_write_node_t *global_variable_and_write_node = (pm_global_variable_and_write_node_t*) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
-
- VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_and_write_node->name));
-
- ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(global_variable_and_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN1(ret, &dummy_line_node, setglobal, global_variable_name);
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_global_variable_operator_write_node_t *global_variable_operator_write_node = (pm_global_variable_operator_write_node_t*) node;
-
- VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_operator_write_node->name));
- ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
-
- PM_COMPILE_NOT_POPPED(global_variable_operator_write_node->value);
- ID method_id = pm_constant_id_lookup(scope_node, global_variable_operator_write_node->operator);
-
- int flags = VM_CALL_ARGS_SIMPLE;
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN1(ret, &dummy_line_node, setglobal, global_variable_name);
-
- return;
- }
- case PM_GLOBAL_VARIABLE_OR_WRITE_NODE: {
- pm_global_variable_or_write_node_t *global_variable_or_write_node = (pm_global_variable_or_write_node_t*) node;
-
- LABEL *set_label= NEW_LABEL(lineno);
- LABEL *end_label = NEW_LABEL(lineno);
-
- PM_PUTNIL;
- VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_or_write_node->name));
-
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_GVAR), global_variable_name, Qtrue);
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, set_label);
-
- ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- ADD_LABEL(ret, set_label);
- PM_COMPILE_NOT_POPPED(global_variable_or_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN1(ret, &dummy_line_node, setglobal, global_variable_name);
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- pm_global_variable_read_node_t *global_variable_read_node = (pm_global_variable_read_node_t *)node;
- VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_read_node->name));
- ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
- PM_POP_IF_POPPED;
- return;
- }
- case PM_GLOBAL_VARIABLE_TARGET_NODE: {
- pm_global_variable_target_node_t *write_node = (pm_global_variable_target_node_t *) node;
-
- ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
- ADD_INSN1(ret, &dummy_line_node, setglobal, ID2SYM(ivar_name));
- return;
- }
- case PM_GLOBAL_VARIABLE_WRITE_NODE: {
- pm_global_variable_write_node_t *write_node = (pm_global_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(write_node->value);
- PM_DUP_UNLESS_POPPED;
- ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
- ADD_INSN1(ret, &dummy_line_node, setglobal, ID2SYM(ivar_name));
- return;
- }
- case PM_HASH_NODE: {
- // If every node in the hash is static, then we can compile the entire
- // hash now instead of later.
- if (pm_static_literal_p(node)) {
- // We're only going to compile this node if it's not popped. If it
- // is popped, then we know we don't need to do anything since it's
- // statically known.
- if (!popped) {
- VALUE value = pm_static_literal_value(node, scope_node, parser);
- ADD_INSN1(ret, &dummy_line_node, duphash, value);
- RB_OBJ_WRITTEN(iseq, Qundef, value);
- }
- } else {
- // Here since we know there are possible side-effects inside the
- // hash contents, we're going to build it entirely at runtime. We'll
- // do this by pushing all of the key-value pairs onto the stack and
- // then combining them with newhash.
- //
- // If this hash is popped, then this serves only to ensure we enact
- // all side-effects (like method calls) that are contained within
- // the hash contents.
- pm_hash_node_t *cast = (pm_hash_node_t *) node;
- // Elements must be non-empty, otherwise it would be static literal
- pm_node_list_t *elements = &cast->elements;
-
- pm_node_t *cur_node = elements->nodes[0];
- pm_node_type_t cur_type = PM_NODE_TYPE(cur_node);
- int elements_of_cur_type = 0;
- int allocated_hashes = 0;
-
- if (!PM_NODE_TYPE_P(cur_node, PM_ASSOC_NODE) && !popped) {
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(0));
- allocated_hashes++;
- }
-
- for (size_t index = 0; index < elements->size; index++) {
- pm_node_t *cur_node = elements->nodes[index];
- if (!popped) {
- if (!PM_NODE_TYPE_P(cur_node, cur_type)) {
- if (!allocated_hashes) {
- ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements_of_cur_type * 2));
- }
- else {
- if (cur_type == PM_ASSOC_NODE) {
- ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(3));
- }
- else {
- ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_kwd, INT2FIX(2));
- }
- }
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PM_SWAP;
- PM_COMPILE(elements->nodes[index]);
-
- allocated_hashes++;
- elements_of_cur_type = 0;
- cur_type = PM_NODE_TYPE(cur_node);
- }
- else {
- elements_of_cur_type++;
- PM_COMPILE(elements->nodes[index]);
- }
- }
- else {
- PM_COMPILE(elements->nodes[index]);
- }
- }
-
- if (!popped) {
- if (!allocated_hashes) {
- ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements_of_cur_type * 2));
- }
- else {
- if (cur_type == PM_ASSOC_NODE) {
- ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(3));
- }
- else {
- ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_kwd, INT2FIX(2));
- }
- }
- }
- }
-
- return;
- }
- case PM_IF_NODE: {
- const int line = (int)pm_newline_list_line_column(&(parser->newline_list), node->location.start).line;
- pm_if_node_t *if_node = (pm_if_node_t *)node;
- pm_statements_node_t *node_body = if_node->statements;
- pm_node_t *node_else = if_node->consequent;
- pm_node_t *predicate = if_node->predicate;
-
- pm_compile_if(iseq, line, node_body, node_else, predicate, ret, src, popped, scope_node);
- return;
- }
- case PM_IMAGINARY_NODE: {
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, putobject, parse_imaginary((pm_imaginary_node_t *)node));
- }
- return;
- }
- case PM_IMPLICIT_NODE: {
- // Implicit nodes mark places in the syntax tree where explicit syntax
- // was omitted, but implied. For example,
- //
- // { foo: }
- //
- // In this case a method call/local variable read is implied by virtue
- // of the missing value. To compile these nodes, we simply compile the
- // value that is implied, which is helpfully supplied by the parser.
- pm_implicit_node_t *cast = (pm_implicit_node_t *)node;
- PM_COMPILE(cast->value);
- return;
- }
- case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: {
- pm_instance_variable_and_write_node_t *instance_variable_and_write_node = (pm_instance_variable_and_write_node_t*) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
- ID instance_variable_name_id = pm_constant_id_lookup(scope_node, instance_variable_and_write_node->name);
- VALUE instance_variable_name_val = ID2SYM(instance_variable_name_id);
-
- ADD_INSN2(ret, &dummy_line_node, getinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(instance_variable_and_write_node->value);
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN2(ret, &dummy_line_node, setinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_instance_variable_operator_write_node_t *instance_variable_operator_write_node = (pm_instance_variable_operator_write_node_t*) node;
-
- ID instance_variable_name_id = pm_constant_id_lookup(scope_node, instance_variable_operator_write_node->name);
- VALUE instance_variable_name_val = ID2SYM(instance_variable_name_id);
-
- ADD_INSN2(ret, &dummy_line_node, getinstancevariable,
- instance_variable_name_val,
- get_ivar_ic_value(iseq, instance_variable_name_id));
-
- PM_COMPILE_NOT_POPPED(instance_variable_operator_write_node->value);
- ID method_id = pm_constant_id_lookup(scope_node, instance_variable_operator_write_node->operator);
-
- int flags = VM_CALL_ARGS_SIMPLE;
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN2(ret, &dummy_line_node, setinstancevariable,
- instance_variable_name_val,
- get_ivar_ic_value(iseq, instance_variable_name_id));
-
- return;
- }
- case PM_INSTANCE_VARIABLE_OR_WRITE_NODE: {
- pm_instance_variable_or_write_node_t *instance_variable_or_write_node = (pm_instance_variable_or_write_node_t*) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
-
- ID instance_variable_name_id = pm_constant_id_lookup(scope_node, instance_variable_or_write_node->name);
- VALUE instance_variable_name_val = ID2SYM(instance_variable_name_id);
-
- ADD_INSN2(ret, &dummy_line_node, getinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(instance_variable_or_write_node->value);
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSN2(ret, &dummy_line_node, setinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- if (!popped) {
- pm_instance_variable_read_node_t *instance_variable_read_node = (pm_instance_variable_read_node_t *) node;
- ID ivar_name = pm_constant_id_lookup(scope_node, instance_variable_read_node->name);
- ADD_INSN2(ret, &dummy_line_node, getinstancevariable, ID2SYM(ivar_name), get_ivar_ic_value(iseq, ivar_name));
- }
- return;
- }
- case PM_INSTANCE_VARIABLE_TARGET_NODE: {
- pm_instance_variable_target_node_t *write_node = (pm_instance_variable_target_node_t *) node;
-
- ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
- ADD_INSN2(ret, &dummy_line_node, setinstancevariable, ID2SYM(ivar_name), get_ivar_ic_value(iseq, ivar_name));
- return;
- }
- case PM_INSTANCE_VARIABLE_WRITE_NODE: {
- pm_instance_variable_write_node_t *write_node = (pm_instance_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
- ADD_INSN2(ret, &dummy_line_node, setinstancevariable,
- ID2SYM(ivar_name),
- get_ivar_ic_value(iseq, ivar_name));
- return;
- }
- case PM_INTEGER_NODE: {
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, putobject, parse_integer((pm_integer_node_t *) node));
- }
- return;
- }
- case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: {
- pm_interpolated_match_last_line_node_t *cast = (pm_interpolated_match_last_line_node_t *) node;
- pm_interpolated_node_compile(cast->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
-
- ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags(node)), INT2FIX((int) (cast->parts.size)));
-
- ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(0), INT2FIX(0));
- ADD_SEND(ret, &dummy_line_node, idEqTilde, INT2NUM(1));
- PM_POP_IF_POPPED;
-
- return;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- pm_interpolated_regular_expression_node_t *cast = (pm_interpolated_regular_expression_node_t *) node;
- pm_interpolated_node_compile(cast->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
-
- ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags(node)), INT2FIX((int) (cast->parts.size)));
- PM_POP_IF_POPPED;
- return;
- }
- case PM_INTERPOLATED_STRING_NODE: {
- pm_interpolated_string_node_t *interp_string_node = (pm_interpolated_string_node_t *) node;
- pm_interpolated_node_compile(interp_string_node->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
-
- size_t parts_size = interp_string_node->parts.size;
- if (parts_size > 1) {
- ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX((int)(parts_size)));
- }
-
- PM_POP_IF_POPPED;
- return;
- }
- case PM_INTERPOLATED_SYMBOL_NODE: {
- pm_interpolated_symbol_node_t *interp_symbol_node = (pm_interpolated_symbol_node_t *) node;
- pm_interpolated_node_compile(interp_symbol_node->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
-
- size_t parts_size = interp_symbol_node->parts.size;
- if (parts_size > 1) {
- ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX((int)(parts_size)));
- }
-
- if (!popped) {
- ADD_INSN(ret, &dummy_line_node, intern);
- }
- else {
- PM_POP;
- }
-
- return;
- }
- case PM_INTERPOLATED_X_STRING_NODE: {
- pm_interpolated_x_string_node_t *interp_x_string_node = (pm_interpolated_x_string_node_t *) node;
- PM_PUTSELF;
- pm_interpolated_node_compile(interp_x_string_node->parts, iseq, dummy_line_node, ret, src, false, scope_node, parser);
-
- size_t parts_size = interp_x_string_node->parts.size;
- if (parts_size > 1) {
- ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX((int)(parts_size)));
- }
-
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
- PM_POP_IF_POPPED;
- return;
- }
- case PM_KEYWORD_HASH_NODE: {
- pm_keyword_hash_node_t *keyword_hash_node = (pm_keyword_hash_node_t *) node;
- pm_node_list_t elements = keyword_hash_node->elements;
-
- for (size_t index = 0; index < elements.size; index++) {
- PM_COMPILE(elements.nodes[index]);
- }
-
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements.size * 2));
- }
- return;
- }
- case PM_LAMBDA_NODE: {
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(node, &next_scope_node, scope_node, parser);
-
- const rb_iseq_t *block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
- VALUE argc = INT2FIX(0);
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_CALL_WITH_BLOCK(ret, &dummy_line_node, idLambda, argc, block);
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
-
- PM_POP_IF_POPPED;
- return;
- }
- case PM_LOCAL_VARIABLE_AND_WRITE_NODE: {
- pm_local_variable_and_write_node_t *local_variable_and_write_node = (pm_local_variable_and_write_node_t*) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
-
- pm_constant_id_t constant_id = local_variable_and_write_node->name;
- int depth = local_variable_and_write_node->depth;
- int local_index = pm_lookup_local_index_with_depth(iseq, scope_node, constant_id, depth);
- ADD_GETLOCAL(ret, &dummy_line_node, local_index, depth);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(local_variable_and_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_SETLOCAL(ret, &dummy_line_node, local_index, depth);
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_local_variable_operator_write_node_t *local_variable_operator_write_node = (pm_local_variable_operator_write_node_t*) node;
-
- pm_constant_id_t constant_id = local_variable_operator_write_node->name;
-
- int depth = local_variable_operator_write_node->depth;
- int local_index = pm_lookup_local_index_with_depth(iseq, scope_node, constant_id, depth);
- ADD_GETLOCAL(ret, &dummy_line_node, local_index, depth);
-
- PM_COMPILE_NOT_POPPED(local_variable_operator_write_node->value);
- ID method_id = pm_constant_id_lookup(scope_node, local_variable_operator_write_node->operator);
-
- int flags = VM_CALL_ARGS_SIMPLE | VM_CALL_FCALL | VM_CALL_VCALL;
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_SETLOCAL(ret, &dummy_line_node, local_index, depth);
-
- return;
- }
- case PM_LOCAL_VARIABLE_OR_WRITE_NODE: {
- pm_local_variable_or_write_node_t *local_variable_or_write_node = (pm_local_variable_or_write_node_t*) node;
-
- LABEL *set_label= NEW_LABEL(lineno);
- LABEL *end_label = NEW_LABEL(lineno);
-
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSNL(ret, &dummy_line_node, branchunless, set_label);
-
- pm_constant_id_t constant_id = local_variable_or_write_node->name;
- int depth = local_variable_or_write_node->depth;
- int local_index = pm_lookup_local_index_with_depth(iseq, scope_node, constant_id, depth);
- ADD_GETLOCAL(ret, &dummy_line_node, local_index, depth);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
-
- PM_POP_UNLESS_POPPED;
-
- ADD_LABEL(ret, set_label);
- PM_COMPILE_NOT_POPPED(local_variable_or_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- ADD_SETLOCAL(ret, &dummy_line_node, local_index, depth);
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *local_read_node = (pm_local_variable_read_node_t *) node;
-
- if (!popped) {
- int index = pm_lookup_local_index_with_depth(iseq, scope_node, local_read_node->name, local_read_node->depth);
- ADD_GETLOCAL(ret, &dummy_line_node, index, local_read_node->depth);
- }
- return;
- }
- case PM_LOCAL_VARIABLE_TARGET_NODE: {
- pm_local_variable_target_node_t *local_write_node = (pm_local_variable_target_node_t *) node;
-
- pm_constant_id_t constant_id = local_write_node->name;
- for (size_t index = 0; index < local_write_node->depth; index++) scope_node = scope_node->previous;
- int index = pm_lookup_local_index(iseq, scope_node, constant_id);
-
- ADD_SETLOCAL(ret, &dummy_line_node, (int)index, local_write_node->depth);
- return;
- }
- case PM_LOCAL_VARIABLE_WRITE_NODE: {
- pm_local_variable_write_node_t *local_write_node = (pm_local_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(local_write_node->value);
-
- PM_DUP_UNLESS_POPPED;
-
- pm_constant_id_t constant_id = local_write_node->name;
- int index = pm_lookup_local_index(iseq, scope_node, constant_id);
-
- ADD_SETLOCAL(ret, &dummy_line_node, (int)index, local_write_node->depth);
- return;
- }
- case PM_MATCH_LAST_LINE_NODE: {
- if (!popped) {
- pm_match_last_line_node_t *cast = (pm_match_last_line_node_t *) node;
-
- VALUE regex_str = parse_string(&cast->unescaped, parser);
- VALUE regex = rb_reg_new(RSTRING_PTR(regex_str), RSTRING_LEN(regex_str), pm_reg_flags(node));
-
- ADD_INSN1(ret, &dummy_line_node, putobject, regex);
- ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(0), INT2FIX(0));
- ADD_SEND(ret, &dummy_line_node, idEqTilde, INT2NUM(1));
- }
-
- return;
- }
- case PM_MATCH_PREDICATE_NODE: {
- pm_match_predicate_node_t *cast = (pm_match_predicate_node_t *) node;
-
- // First, allocate some stack space for the cached return value of any
- // calls to #deconstruct.
- PM_PUTNIL;
-
- // Next, compile the expression that we're going to match against.
- PM_COMPILE_NOT_POPPED(cast->value);
- PM_DUP;
-
- // Now compile the pattern that is going to be used to match against the
- // expression.
- LABEL *matched_label = NEW_LABEL(lineno);
- LABEL *unmatched_label = NEW_LABEL(lineno);
- LABEL *done_label = NEW_LABEL(lineno);
- pm_compile_pattern(iseq, cast->pattern, ret, src, scope_node, matched_label, unmatched_label, false);
-
- // If the pattern did not match, then compile the necessary instructions
- // to handle pushing false onto the stack, then jump to the end.
- ADD_LABEL(ret, unmatched_label);
- PM_POP;
- PM_POP;
-
- if (!popped) ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
- ADD_INSNL(ret, &dummy_line_node, jump, done_label);
- PM_PUTNIL;
-
- // If the pattern did match, then compile the necessary instructions to
- // handle pushing true onto the stack, then jump to the end.
- ADD_LABEL(ret, matched_label);
- ADD_INSN1(ret, &dummy_line_node, adjuststack, INT2FIX(2));
- if (!popped) ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- ADD_INSNL(ret, &dummy_line_node, jump, done_label);
-
- ADD_LABEL(ret, done_label);
- return;
- }
- case PM_MATCH_WRITE_NODE: {
- pm_match_write_node_t *cast = (pm_match_write_node_t *)node;
- LABEL *fail_label = NEW_LABEL(lineno);
- LABEL *end_label = NEW_LABEL(lineno);
- size_t capture_count = cast->locals.size;
- VALUE r;
-
- pm_constant_id_t *locals = ALLOCV_N(pm_constant_id_t, r, capture_count);
-
- for (size_t i = 0; i < capture_count; i++) {
- locals[i] = cast->locals.ids[i];
- }
-
- PM_COMPILE_NOT_POPPED((pm_node_t *)cast->call);
- VALUE global_variable_name = rb_id2sym(idBACKREF);
-
- ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
- PM_DUP;
- ADD_INSNL(ret, &dummy_line_node, branchunless, fail_label);
-
- if (capture_count == 1) {
- int local_index = pm_lookup_local_index(iseq, scope_node, *locals);
-
- DECL_ANCHOR(nom);
- INIT_ANCHOR(nom);
-
- ADD_INSNL(nom, &dummy_line_node, jump, end_label);
- ADD_LABEL(nom, fail_label);
- ADD_LABEL(nom, end_label);
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_id2sym(pm_constant_id_lookup(scope_node, *locals)));
- ADD_SEND(ret, &dummy_line_node, idAREF, INT2FIX(1));
- ADD_SETLOCAL(nom, &dummy_line_node, local_index, 0);
- PM_POP_IF_POPPED;
-
- ADD_SEQ(ret, nom);
- return;
- }
-
- for (size_t index = 0; index < capture_count; index++) {
- int local_index = pm_lookup_local_index(iseq, scope_node, locals[index]);
-
- if (index < (capture_count - 1)) {
- PM_DUP;
- }
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_id2sym(pm_constant_id_lookup(scope_node, locals[index])));
- ADD_SEND(ret, &dummy_line_node, idAREF, INT2FIX(1));
- ADD_SETLOCAL(ret, &dummy_line_node, local_index, 0);
- }
-
- ADD_INSNL(ret, &dummy_line_node, jump, end_label);
- ADD_LABEL(ret, fail_label);
- PM_POP_UNLESS_POPPED;
-
- for (size_t index = 0; index < capture_count; index++) {
- pm_constant_id_t constant = cast->locals.ids[index];
- int local_index = pm_lookup_local_index(iseq, scope_node, constant);
-
- PM_PUTNIL;
- ADD_SETLOCAL(ret, &dummy_line_node, local_index, 0);
- PM_POP_IF_POPPED;
- }
- ADD_LABEL(ret, end_label);
- return;
- }
- case PM_MISSING_NODE: {
- rb_bug("A pm_missing_node_t should not exist in prism's AST.");
- return;
- }
- case PM_MODULE_NODE: {
- pm_module_node_t *module_node = (pm_module_node_t *)node;
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)module_node, &next_scope_node, scope_node, parser);
-
- ID module_id = pm_constant_id_lookup(scope_node, module_node->name);
- VALUE module_name = rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(module_id)));
-
- const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(next_scope_node, module_name, ISEQ_TYPE_CLASS, lineno);
-
- const int flags = VM_DEFINECLASS_TYPE_MODULE |
- pm_compile_class_path(ret, iseq, module_node->constant_path, &dummy_line_node, src, false, scope_node);
-
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defineclass, ID2SYM(module_id), module_iseq, INT2FIX(flags));
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
-
- PM_POP_IF_POPPED;
- return;
- }
- case PM_MULTI_TARGET_NODE: {
- pm_multi_target_node_t *cast = (pm_multi_target_node_t *) node;
-
- if (cast->lefts.size) {
- int flag = (int) (bool) cast->rights.size;
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->lefts.size), INT2FIX(flag));
- for (size_t index = 0; index < cast->lefts.size; index++) {
- PM_COMPILE_NOT_POPPED(cast->lefts.nodes[index]);
- }
- }
-
- if (cast->rights.size) {
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->rights.size), INT2FIX(2));
- for (size_t index = 0; index < cast->rights.size; index++) {
- PM_COMPILE_NOT_POPPED(cast->rights.nodes[index]);
- }
- }
- return;
- }
- case PM_MULTI_WRITE_NODE: {
- pm_multi_write_node_t *multi_write_node = (pm_multi_write_node_t *)node;
- pm_node_list_t *lefts = &multi_write_node->lefts;
- pm_node_list_t *rights = &multi_write_node->rights;
-
- // pre-process the left hand side of multi-assignments.
- uint8_t pushed = 0;
- for (size_t index = 0; index < lefts->size; index++) {
- pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, lefts->nodes[index], ret, scope_node, pushed, false);
- }
-
- PM_COMPILE_NOT_POPPED(multi_write_node->value);
- PM_DUP_UNLESS_POPPED;
-
- if (lefts->size) {
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(lefts->size), INT2FIX((int) (bool) rights->size));
- for (size_t index = 0; index < lefts->size; index++) {
- pm_node_t *considered_node = lefts->nodes[index];
-
- if (PM_NODE_TYPE_P(considered_node, PM_CONSTANT_PATH_TARGET_NODE) && pushed > 0) {
- pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *) considered_node;
- ID name = pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t * ) cast->child)->name);
-
- pushed -= 2;
-
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(pushed));
- ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(name));
- } else {
- PM_COMPILE(lefts->nodes[index]);
- }
- }
- }
-
- if (pushed) {
- ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(pushed));
- for (uint8_t index = 0; index < pushed; index++) {
- PM_POP;
- }
- }
-
- if (multi_write_node->rest) {
- RUBY_ASSERT(PM_NODE_TYPE_P(multi_write_node->rest, PM_SPLAT_NODE));
-
- pm_splat_node_t *rest_splat = ((pm_splat_node_t *)multi_write_node->rest);
- if (rest_splat->expression) {
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(0), INT2FIX(1));
- PM_COMPILE(rest_splat->expression);
- }
- }
-
- if (rights->size) {
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(rights->size), INT2FIX(2));
- for (size_t index = 0; index < rights->size; index++) {
- PM_COMPILE(rights->nodes[index]);
- }
- }
-
- return;
- }
- case PM_NEXT_NODE: {
- pm_next_node_t *next_node = (pm_next_node_t *) node;
- if (next_node->arguments) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)next_node->arguments);
- }
- else {
- PM_PUTNIL;
- }
-
- PM_POP;
- ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
-
- return;
- }
- case PM_NIL_NODE:
- PM_PUTNIL_UNLESS_POPPED
- return;
- case PM_NO_KEYWORDS_PARAMETER_NODE: {
- ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg = TRUE;
- return;
- }
- case PM_NUMBERED_REFERENCE_READ_NODE: {
- if (!popped) {
- uint32_t reference_number = ((pm_numbered_reference_read_node_t *)node)->number;
- ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(1), INT2FIX(reference_number << 1));
- }
- return;
- }
- case PM_OR_NODE: {
- pm_or_node_t *or_node = (pm_or_node_t *) node;
-
- LABEL *end_label = NEW_LABEL(lineno);
- PM_COMPILE_NOT_POPPED(or_node->left);
-
- PM_DUP_UNLESS_POPPED;
- ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
-
- PM_POP_UNLESS_POPPED;
- PM_COMPILE(or_node->right);
- ADD_LABEL(ret, end_label);
-
- return;
- }
- case PM_OPTIONAL_PARAMETER_NODE: {
- pm_optional_parameter_node_t *optional_parameter_node = (pm_optional_parameter_node_t *)node;
- PM_COMPILE_NOT_POPPED(optional_parameter_node->value);
-
- int index = pm_lookup_local_index(iseq, scope_node, optional_parameter_node->name);
-
- ADD_SETLOCAL(ret, &dummy_line_node, index, 0);
-
- return;
- }
- case PM_PARAMETERS_NODE: {
- rb_bug("Should not ever enter a parameters node directly");
-
- return;
- }
- case PM_PARENTHESES_NODE: {
- pm_parentheses_node_t *parentheses_node = (pm_parentheses_node_t *) node;
-
- if (parentheses_node->body == NULL) {
- PM_PUTNIL_UNLESS_POPPED;
- } else {
- PM_COMPILE(parentheses_node->body);
- }
-
- return;
- }
- case PM_PRE_EXECUTION_NODE: {
- pm_pre_execution_node_t *pre_execution_node = (pm_pre_execution_node_t *) node;
-
- DECL_ANCHOR(pre_ex);
- INIT_ANCHOR(pre_ex);
-
- if (pre_execution_node->statements) {
- pm_node_list_t node_list = pre_execution_node->statements->body;
- for (size_t index = 0; index < node_list.size; index++) {
- pm_compile_node(iseq, node_list.nodes[index], pre_ex, src, true, scope_node);
- }
- }
-
- if (!popped) {
- ADD_INSN(pre_ex, &dummy_line_node, putnil);
- }
-
- pre_ex->last->next = ret->anchor.next;
- ret->anchor.next = pre_ex->anchor.next;
- ret->anchor.next->prev = pre_ex->anchor.next;
-
- if (ret->last == (LINK_ELEMENT *)ret) {
- ret->last = pre_ex->last;
- }
-
- return;
- }
- case PM_POST_EXECUTION_NODE: {
- const rb_iseq_t *child_iseq;
- const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(node, &next_scope_node, scope_node, parser);
-
- child_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
- ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
-
- int is_index = ISEQ_BODY(iseq)->ise_size++;
-
- ADD_INSN2(ret, &dummy_line_node, once, child_iseq, INT2FIX(is_index));
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)child_iseq);
-
- PM_POP_IF_POPPED;
-
- ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
-
- return;
- }
- case PM_PROGRAM_NODE: {
- rb_bug("Should not ever enter a program node directly");
-
- return;
- }
- case PM_RANGE_NODE: {
- pm_range_node_t *range_node = (pm_range_node_t *) node;
- bool exclusive = (range_node->operator_loc.end - range_node->operator_loc.start) == 3;
-
- if (pm_optimizable_range_item_p(range_node->left) && pm_optimizable_range_item_p(range_node->right)) {
- if (!popped) {
- pm_node_t *left = range_node->left;
- pm_node_t *right = range_node->right;
- VALUE val = rb_range_new(
- left && PM_NODE_TYPE_P(left, PM_INTEGER_NODE) ? parse_integer((pm_integer_node_t *) left) : Qnil,
- right && PM_NODE_TYPE_P(right, PM_INTEGER_NODE) ? parse_integer((pm_integer_node_t *) right) : Qnil,
- exclusive
- );
- ADD_INSN1(ret, &dummy_line_node, putobject, val);
- RB_OBJ_WRITTEN(iseq, Qundef, val);
- }
- }
- else {
- if (range_node->left == NULL) {
- PM_PUTNIL;
- } else {
- PM_COMPILE(range_node->left);
- }
-
- if (range_node->right == NULL) {
- PM_PUTNIL;
- } else {
- PM_COMPILE(range_node->right);
- }
-
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, newrange, INT2FIX(exclusive));
- }
- }
- return;
- }
- case PM_RATIONAL_NODE: {
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, putobject, parse_rational(node));
- }
- return;
- }
- case PM_REDO_NODE: {
- ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
- return;
- }
- case PM_REGULAR_EXPRESSION_NODE: {
- if (!popped) {
- pm_regular_expression_node_t *cast = (pm_regular_expression_node_t *) node;
-
- VALUE regex = pm_new_regex(cast, parser);
-
- ADD_INSN1(ret, &dummy_line_node, putobject, regex);
- }
- return;
- }
- case PM_RETURN_NODE: {
- pm_arguments_node_t *arguments = ((pm_return_node_t *)node)->arguments;
-
- if (arguments) {
- PM_COMPILE((pm_node_t *)arguments);
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_TRACE(ret, RUBY_EVENT_RETURN);
- ADD_INSN(ret, &dummy_line_node, leave);
-
- if (!popped) {
- PM_PUTNIL;
- }
- return;
- }
- case PM_SCOPE_NODE: {
- pm_scope_node_t *scope_node = (pm_scope_node_t *)node;
- pm_constant_id_list_t *locals = &scope_node->locals;
-
- pm_parameters_node_t *parameters_node = (pm_parameters_node_t *) scope_node->parameters;
- pm_node_list_t *keywords_list = NULL;
- pm_node_list_t *optionals_list = NULL;
- pm_node_list_t *posts_list = NULL;
- pm_node_list_t *requireds_list = NULL;
-
- struct rb_iseq_param_keyword *keyword;
-
- struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
-
- if (parameters_node) {
- optionals_list = &parameters_node->optionals;
- requireds_list = &parameters_node->requireds;
- keywords_list = &parameters_node->keywords;
- posts_list = &parameters_node->posts;
- } else if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
- body->param.lead_num = 1;
- body->param.opt_num = 0;
- } else {
- body->param.lead_num = 0;
- body->param.opt_num = 0;
- }
-
- size_t locals_size = locals->size;
-
- // Index lookup table buffer size is only the number of the locals
- st_table *index_lookup_table = st_init_numtable();
-
- VALUE idtmp = 0;
- rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + locals_size * sizeof(ID));
- tbl->size = (int) locals_size;
- body->param.size = (int) locals_size;
-
- for (size_t i = 0; i < locals_size; i++) {
- pm_constant_id_t constant_id = locals->ids[i];
- ID local;
- if (constant_id & TEMP_CONSTANT_IDENTIFIER) {
- local = rb_make_temporary_id(i);
- }
- else {
- local = pm_constant_id_lookup(scope_node, constant_id);
- }
- tbl->ids[i] = local;
- st_insert(index_lookup_table, constant_id, i);
- }
-
- scope_node->index_lookup_table = index_lookup_table;
-
- if (optionals_list && optionals_list->size) {
- body->param.opt_num = (int) optionals_list->size;
- LABEL **opt_table = (LABEL **)ALLOC_N(VALUE, optionals_list->size + 1);
- LABEL *label;
-
- // TODO: Should we make an api for NEW_LABEL where you can pass
- // a pointer to the label it should fill out? We already
- // have a list of labels allocated above so it seems wasteful
- // to do the copies.
- for (size_t i = 0; i < optionals_list->size; i++) {
- label = NEW_LABEL(lineno);
- opt_table[i] = label;
- ADD_LABEL(ret, label);
- pm_node_t *optional_node = optionals_list->nodes[i];
- PM_COMPILE_NOT_POPPED(optional_node);
- }
-
- // Set the last label
- label = NEW_LABEL(lineno);
- opt_table[optionals_list->size] = label;
- ADD_LABEL(ret, label);
-
- body->param.flags.has_opt = TRUE;
- body->param.opt_table = (const VALUE *)opt_table;
- }
-
- if (requireds_list && requireds_list->size) {
- body->param.lead_num = (int) requireds_list->size;
- body->param.flags.has_lead = true;
-
- for (size_t i = 0; i < requireds_list->size; i++) {
- pm_node_t *required_param = requireds_list->nodes[i];
- // TODO: Fix MultiTargetNodes
- if (PM_NODE_TYPE_P(required_param, PM_MULTI_TARGET_NODE)) {
- PM_COMPILE(required_param);
- }
- }
- }
-
- if (posts_list && posts_list->size) {
- body->param.post_num = (int) posts_list->size;
- body->param.post_start = body->param.lead_num + body->param.opt_num; // TODO
- body->param.flags.has_post = true;
- }
-
- // Keywords create an internal variable on the parse tree
- if (keywords_list && keywords_list->size) {
- body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
- keyword->num = (int) keywords_list->size;
-
- body->param.flags.has_kw = true;
- const VALUE default_values = rb_ary_hidden_new(1);
- const VALUE complex_mark = rb_str_tmp_new(0);
-
- ID *ids = calloc(keywords_list->size, sizeof(ID));
-
- for (size_t i = 0; i < keywords_list->size; i++) {
- pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
-
- switch PM_NODE_TYPE(keyword_parameter_node) {
- case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: {
- pm_node_t *value = ((pm_optional_keyword_parameter_node_t *)keyword_parameter_node)->value;
-
- if (pm_static_literal_p(value)) {
- rb_ary_push(default_values, pm_static_literal_value(value, scope_node, parser));
- }
- else {
- PM_COMPILE_POPPED(value);
- rb_ary_push(default_values, complex_mark);
- }
-
- break;
- }
- case PM_REQUIRED_KEYWORD_PARAMETER_NODE: {
- pm_required_keyword_parameter_node_t *cast = (pm_required_keyword_parameter_node_t *)keyword_parameter_node;
- ids[keyword->required_num] = pm_constant_id_lookup(scope_node, cast->name);
- keyword->required_num++;
- break;
- }
- default: {
- rb_bug("Unexpected keyword parameter node type");
- }
- }
- }
-
- VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
-
- for (int i = 0; i < RARRAY_LEN(default_values); i++) {
- VALUE dv = RARRAY_AREF(default_values, i);
- if (dv == complex_mark) dv = Qundef;
- if (!SPECIAL_CONST_P(dv)) {
- RB_OBJ_WRITTEN(iseq, Qundef, dv);
- }
- dvs[i] = dv;
- }
-
- keyword->default_values = dvs;
- keyword->table = ids;
- }
-
- if (parameters_node) {
- if (parameters_node->rest) {
- body->param.rest_start = body->param.lead_num + body->param.opt_num;
- body->param.flags.has_rest = true;
- }
-
- if (parameters_node->keyword_rest) {
- if (PM_NODE_TYPE_P(parameters_node->keyword_rest, PM_NO_KEYWORDS_PARAMETER_NODE)) {
- body->param.flags.accepts_no_kwarg = true;
- }
- else {
- if (!body->param.flags.has_kw) {
- body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
- }
- keyword->rest_start = (int) locals_size;
- body->param.flags.has_kwrest = true;
- }
- }
-
- if (parameters_node->block) {
- body->param.block_start = (int) locals_size - 1;
- body->param.flags.has_block = true;
- }
- }
-
- iseq_set_local_table(iseq, tbl);
-
- switch (body->type) {
- case ISEQ_TYPE_BLOCK: {
- LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
- LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
-
- start->rescued = LABEL_RESCUE_BEG;
- end->rescued = LABEL_RESCUE_END;
-
- ADD_TRACE(ret, RUBY_EVENT_B_CALL);
- NODE dummy_line_node = generate_dummy_line_node(body->location.first_lineno, -1);
- ADD_INSN (ret, &dummy_line_node, nop);
- ADD_LABEL(ret, start);
-
- if (scope_node->body) {
- switch (PM_NODE_TYPE(scope_node->ast_node)) {
- case PM_POST_EXECUTION_NODE: {
- pm_post_execution_node_t *post_execution_node = (pm_post_execution_node_t *)scope_node->ast_node;
-
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- // We create another ScopeNode from the statements within the PostExecutionNode
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)post_execution_node->statements, &next_scope_node, scope_node, parser);
-
- const rb_iseq_t *block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(body->parent_iseq), ISEQ_TYPE_BLOCK, lineno);
-
- ADD_CALL_WITH_BLOCK(ret, &dummy_line_node, id_core_set_postexe, INT2FIX(0), block);
- break;
- }
- case PM_FOR_NODE: {
- pm_for_node_t *for_node = (pm_for_node_t *)scope_node->ast_node;
-
- ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
- PM_COMPILE(for_node->index);
- ADD_INSN(ret, &dummy_line_node, nop);
- }
- default: {
- pm_compile_node(iseq, (pm_node_t *)(scope_node->body), ret, src, popped, scope_node);
- }
- }
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_LABEL(ret, end);
- ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
- ISEQ_COMPILE_DATA(iseq)->last_line = body->location.code_location.end_pos.lineno;
-
- /* wide range catch handler must put at last */
- ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
- ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
- break;
- }
- case ISEQ_TYPE_ENSURE: {
- iseq_set_exception_local_table(iseq);
- PM_COMPILE((pm_node_t *)scope_node->body);
- PM_POP;
-
- ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
- ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0));
-
- return;
- }
- default:
- if (scope_node->body) {
- PM_COMPILE((pm_node_t *)scope_node->body);
- }
- else {
- PM_PUTNIL;
- }
- }
-
- free(index_lookup_table);
-
- if (!PM_NODE_TYPE_P(scope_node->ast_node, PM_ENSURE_NODE)) {
- ADD_INSN(ret, &dummy_line_node, leave);
- }
- return;
- }
- case PM_SELF_NODE:
- if (!popped) {
- PM_PUTSELF;
- }
- return;
- case PM_SINGLETON_CLASS_NODE: {
- pm_singleton_class_node_t *singleton_class_node = (pm_singleton_class_node_t *)node;
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t *)singleton_class_node, &next_scope_node, scope_node, parser);
-
- const rb_iseq_t *singleton_class = NEW_ISEQ(next_scope_node, rb_fstring_lit("singleton class"), ISEQ_TYPE_CLASS, lineno);
-
- PM_COMPILE_NOT_POPPED(singleton_class_node->expression);
- PM_PUTNIL;
- ID singletonclass;
- CONST_ID(singletonclass, "singletonclass");
-
- ADD_INSN3(ret, &dummy_line_node, defineclass,
- ID2SYM(singletonclass), singleton_class,
- INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
- PM_POP_IF_POPPED;
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
-
- return;
- }
- case PM_SOURCE_ENCODING_NODE: {
- // Source encoding nodes are generated by the __ENCODING__ syntax. They
- // reference the encoding object corresponding to the encoding of the
- // source file, and can be changed by a magic encoding comment.
- if (!popped) {
- VALUE value = pm_static_literal_value(node, scope_node, parser);
- ADD_INSN1(ret, &dummy_line_node, putobject, value);
- RB_OBJ_WRITTEN(iseq, Qundef, value);
- }
- return;
- }
- case PM_SOURCE_FILE_NODE: {
- // Source file nodes are generated by the __FILE__ syntax. They
- // reference the file name of the source file.
- if (!popped) {
- VALUE value = pm_static_literal_value(node, scope_node, parser);
- ADD_INSN1(ret, &dummy_line_node, putstring, value);
- RB_OBJ_WRITTEN(iseq, Qundef, value);
- }
- return;
- }
- case PM_SOURCE_LINE_NODE: {
- // Source line nodes are generated by the __LINE__ syntax. They
- // reference the line number where they occur in the source file.
- if (!popped) {
- VALUE value = pm_static_literal_value(node, scope_node, parser);
- ADD_INSN1(ret, &dummy_line_node, putobject, value);
- RB_OBJ_WRITTEN(iseq, Qundef, value);
- }
- return;
- }
- case PM_SPLAT_NODE: {
- pm_splat_node_t *splat_node = (pm_splat_node_t *)node;
- if (splat_node->expression) {
- PM_COMPILE(splat_node->expression);
- }
-
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, splatarray, Qtrue);
- }
- return;
- }
- case PM_STATEMENTS_NODE: {
- pm_statements_node_t *statements_node = (pm_statements_node_t *) node;
- pm_node_list_t node_list = statements_node->body;
- if (node_list.size > 0) {
- for (size_t index = 0; index < node_list.size - 1; index++) {
- PM_COMPILE_POPPED(node_list.nodes[index]);
- }
- PM_COMPILE(node_list.nodes[node_list.size - 1]);
- }
- else {
- PM_PUTNIL;
- }
- return;
- }
- case PM_STRING_CONCAT_NODE: {
- pm_string_concat_node_t *str_concat_node = (pm_string_concat_node_t *)node;
- PM_COMPILE(str_concat_node->left);
- PM_COMPILE(str_concat_node->right);
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX(2));
- }
- return;
- }
- case PM_STRING_NODE: {
- if (!popped) {
- pm_string_node_t *string_node = (pm_string_node_t *) node;
- ADD_INSN1(ret, &dummy_line_node, putstring, parse_string(&string_node->unescaped, parser));
- }
- return;
- }
- case PM_SUPER_NODE: {
- pm_super_node_t *super_node = (pm_super_node_t *) node;
-
- DECL_ANCHOR(args);
-
- int flags = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
- const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
-
- INIT_ANCHOR(args);
- ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
-
- ADD_INSN(ret, &dummy_line_node, putself);
-
- int argc = pm_setup_args(super_node->arguments, &flags, &keywords, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
-
- flags |= VM_CALL_SUPER | VM_CALL_FCALL;
-
- if (super_node->block) {
- switch (PM_NODE_TYPE(super_node->block)) {
- case PM_BLOCK_ARGUMENT_NODE: {
- PM_COMPILE_NOT_POPPED(super_node->block);
- flags |= VM_CALL_ARGS_BLOCKARG;
- break;
- }
- case PM_BLOCK_NODE: {
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(super_node->block, &next_scope_node, scope_node, parser);
- parent_block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
- break;
- }
- default: {
- rb_bug("This node type should never occur on a SuperNode's block");
- }
- }
- }
-
- ADD_SEQ(ret, args);
- ADD_INSN2(ret, &dummy_line_node, invokesuper,
- new_callinfo(iseq, 0, argc, flags, keywords, parent_block != NULL),
- parent_block);
-
- PM_POP_IF_POPPED;
- return;
- }
- case PM_SYMBOL_NODE: {
- // Symbols nodes are symbol literals with no interpolation. They are
- // always marked as static literals.
- if (!popped) {
- VALUE value = pm_static_literal_value(node, scope_node, parser);
- ADD_INSN1(ret, &dummy_line_node, putobject, value);
- RB_OBJ_WRITTEN(iseq, Qundef, value);
- }
- return;
- }
- case PM_TRUE_NODE:
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
- }
- return;
- case PM_UNDEF_NODE: {
- pm_undef_node_t *undef_node = (pm_undef_node_t *) node;
-
- for (size_t index = 0; index < undef_node->names.size; index++) {
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
-
- PM_COMPILE_NOT_POPPED(undef_node->names.nodes[index]);
-
- ADD_SEND(ret, &dummy_line_node, id_core_undef_method, INT2NUM(2));
-
- if (index < undef_node->names.size - 1) {
- PM_POP;
- }
- }
-
- PM_POP_IF_POPPED;
-
- return;
- }
- case PM_UNLESS_NODE: {
- const int line = (int)pm_newline_list_line_column(&(parser->newline_list), node->location.start).line;
- pm_unless_node_t *unless_node = (pm_unless_node_t *)node;
- pm_node_t *node_body = (pm_node_t *)(unless_node->statements);
- pm_statements_node_t *node_else = NULL;
- if (unless_node->consequent != NULL) {
- node_else = ((pm_else_node_t *)unless_node->consequent)->statements;
- }
- pm_node_t *predicate = unless_node->predicate;
-
- pm_compile_if(iseq, line, node_else, node_body, predicate, ret, src, popped, scope_node);
- return;
- }
- case PM_UNTIL_NODE: {
- pm_until_node_t *until_node = (pm_until_node_t *)node;
- pm_statements_node_t *statements = until_node->statements;
- pm_node_t *predicate = until_node->predicate;
- pm_node_flags_t flags = node->flags;
-
- pm_compile_while(iseq, lineno, flags, node->type, statements, predicate, ret, src, popped, scope_node);
- return;
- }
- case PM_WHEN_NODE: {
- rb_bug("Should not ever enter a when node directly");
-
- return;
- }
- case PM_WHILE_NODE: {
- pm_while_node_t *while_node = (pm_while_node_t *)node;
- pm_statements_node_t *statements = while_node->statements;
- pm_node_t *predicate = while_node->predicate;
- pm_node_flags_t flags = node->flags;
-
- pm_compile_while(iseq, lineno, flags, node->type, statements, predicate, ret, src, popped, scope_node);
- return;
- }
- case PM_X_STRING_NODE: {
- pm_x_string_node_t *xstring_node = (pm_x_string_node_t *) node;
- PM_PUTSELF;
- ADD_INSN1(ret, &dummy_line_node, putobject, parse_string(&xstring_node->unescaped, parser));
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
-
- PM_POP_IF_POPPED;
- return;
- }
- case PM_YIELD_NODE: {
- pm_yield_node_t *yield_node = (pm_yield_node_t *)node;
-
- unsigned int flag = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
-
- int argc = 0;
-
- if (yield_node->arguments) {
- PM_COMPILE((pm_node_t *)yield_node->arguments);
-
- argc = (int) yield_node->arguments->arguments.size;
- }
-
- ADD_INSN1(ret, &dummy_line_node, invokeblock, new_callinfo(iseq, 0, argc, flag, keywords, FALSE));
-
- PM_POP_IF_POPPED;
-
- int level = 0;
- const rb_iseq_t *tmp_iseq = iseq;
- for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
- tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
- }
-
- if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
-
- return;
- }
- default:
- rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type_to_str(PM_NODE_TYPE(node)));
- return;
- }
-}
-
-static VALUE
-rb_translate_prism(pm_parser_t *parser, rb_iseq_t *iseq, pm_scope_node_t *scope_node, LINK_ANCHOR *const ret)
-{
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
-
- ID *constants = calloc(parser->constant_pool.size, sizeof(ID));
- rb_encoding *encoding = rb_enc_find(parser->encoding.name);
- for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
- pm_constant_t *constant = &parser->constant_pool.constants[index];
- constants[index] = rb_intern3((const char *) constant->start, constant->length, encoding);
- }
-
- st_table *index_lookup_table = st_init_numtable();
- pm_constant_id_list_t *locals = &scope_node->locals;
- for (size_t i = 0; i < locals->size; i++) {
- st_insert(index_lookup_table, locals->ids[i], i);
- }
- scope_node->constants = constants;
- scope_node->index_lookup_table = index_lookup_table;
-
- pm_compile_node(iseq, (pm_node_t *)scope_node, ret, scope_node->base.location.start, false, (pm_scope_node_t *)scope_node);
- iseq_set_sequence(iseq, ret);
-
- free(constants);
- return Qnil;
-}
-
-#undef NEW_ISEQ
-#define NEW_ISEQ OLD_ISEQ
-
-#undef NEW_CHILD_ISEQ
-#define NEW_CHILD_ISEQ OLD_CHILD_ISEQ
diff --git a/prism_compile.h b/prism_compile.h
deleted file mode 100644
index d307807b84..0000000000
--- a/prism_compile.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "prism/prism.h"
-
-// ScopeNodes are helper nodes, and will never be part of the AST. We manually
-// declare them here to avoid generating them.
-typedef struct pm_scope_node {
- pm_node_t base;
- struct pm_scope_node *previous;
- pm_node_t *ast_node;
- struct pm_parameters_node *parameters;
- pm_node_t *body;
- pm_constant_id_list_t locals;
- pm_parser_t *parser;
-
- ID *constants;
- st_table *index_lookup_table;
-} pm_scope_node_t;
-
-void pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous, pm_parser_t *parser);
diff --git a/prism_init.c b/prism_init.c
deleted file mode 100644
index ddc87fad85..0000000000
--- a/prism_init.c
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "prism/extension.h"
-
-void ruby_init_ext(const char *name, void (*init)(void));
-
-void
-Init_Prism(void)
-{
- ruby_init_ext("prism/prism.so", Init_prism);
-}
diff --git a/probes_helper.h b/probes_helper.h
index 16d81b9ffb..0003e96dd8 100644
--- a/probes_helper.h
+++ b/probes_helper.h
@@ -12,7 +12,9 @@ struct ruby_dtrace_method_hook_args {
volatile VALUE name;
};
+MJIT_SYMBOL_EXPORT_BEGIN
NOINLINE(int rb_dtrace_setup(rb_execution_context_t *, VALUE, ID, struct ruby_dtrace_method_hook_args *));
+MJIT_SYMBOL_EXPORT_END
#define RUBY_DTRACE_METHOD_HOOK(name, ec, klazz, id) \
do { \
diff --git a/proc.c b/proc.c
index 81a5261413..bb0ad89851 100644
--- a/proc.c
+++ b/proc.c
@@ -10,11 +10,12 @@
**********************************************************************/
#include "eval_intern.h"
+#include "gc.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/error.h"
#include "internal/eval.h"
-#include "internal/gc.h"
+#include "internal/hash.h"
#include "internal/object.h"
#include "internal/proc.h"
#include "internal/symbol.h"
@@ -56,6 +57,8 @@ static int method_arity(VALUE);
static int method_min_max_arity(VALUE, int *max);
static VALUE proc_binding(VALUE self);
+#define attached id__attached__
+
/* Proc */
#define IS_METHOD_PROC_IFUNC(ifunc) ((ifunc)->func == bmcall)
@@ -70,7 +73,7 @@ CLONESETUP(VALUE clone, VALUE obj)
RBIMPL_ASSERT_OR_ASSUME(! RB_SPECIAL_CONST_P(obj));
RBIMPL_ASSERT_OR_ASSUME(! RB_SPECIAL_CONST_P(clone));
- const VALUE flags = RUBY_FL_PROMOTED | RUBY_FL_FINALIZE;
+ const VALUE flags = RUBY_FL_PROMOTED0 | RUBY_FL_PROMOTED1 | RUBY_FL_FINALIZE;
rb_obj_setup(clone, rb_singleton_class_clone(obj),
RB_FL_TEST_RAW(obj, ~flags));
rb_singleton_class_attached(RBASIC_CLASS(clone), clone);
@@ -78,34 +81,63 @@ CLONESETUP(VALUE clone, VALUE obj)
}
static void
-block_mark_and_move(struct rb_block *block)
+block_mark(const struct rb_block *block)
+{
+ switch (vm_block_type(block)) {
+ case block_type_iseq:
+ case block_type_ifunc:
+ {
+ const struct rb_captured_block *captured = &block->as.captured;
+ RUBY_MARK_MOVABLE_UNLESS_NULL(captured->self);
+ RUBY_MARK_MOVABLE_UNLESS_NULL((VALUE)captured->code.val);
+ if (captured->ep && !UNDEF_P(captured->ep[VM_ENV_DATA_INDEX_ENV]) /* cfunc_proc_t */) {
+ rb_gc_mark(VM_ENV_ENVVAL(captured->ep));
+ }
+ }
+ break;
+ case block_type_symbol:
+ RUBY_MARK_MOVABLE_UNLESS_NULL(block->as.symbol);
+ break;
+ case block_type_proc:
+ RUBY_MARK_MOVABLE_UNLESS_NULL(block->as.proc);
+ break;
+ }
+}
+
+static void
+block_compact(struct rb_block *block)
{
switch (block->type) {
case block_type_iseq:
case block_type_ifunc:
{
struct rb_captured_block *captured = &block->as.captured;
- rb_gc_mark_and_move(&captured->self);
- rb_gc_mark_and_move(&captured->code.val);
- if (captured->ep) {
- rb_gc_mark_and_move((VALUE *)&captured->ep[VM_ENV_DATA_INDEX_ENV]);
- }
+ captured->self = rb_gc_location(captured->self);
+ captured->code.val = rb_gc_location(captured->code.val);
}
break;
case block_type_symbol:
- rb_gc_mark_and_move(&block->as.symbol);
+ block->as.symbol = rb_gc_location(block->as.symbol);
break;
case block_type_proc:
- rb_gc_mark_and_move(&block->as.proc);
+ block->as.proc = rb_gc_location(block->as.proc);
break;
}
}
static void
-proc_mark_and_move(void *ptr)
+proc_compact(void *ptr)
{
rb_proc_t *proc = ptr;
- block_mark_and_move((struct rb_block *)&proc->block);
+ block_compact((struct rb_block *)&proc->block);
+}
+
+static void
+proc_mark(void *ptr)
+{
+ rb_proc_t *proc = ptr;
+ block_mark(&proc->block);
+ RUBY_MARK_LEAVE("proc");
}
typedef struct {
@@ -125,10 +157,10 @@ proc_memsize(const void *ptr)
static const rb_data_type_t proc_data_type = {
"proc",
{
- proc_mark_and_move,
+ proc_mark,
RUBY_TYPED_DEFAULT_FREE,
proc_memsize,
- proc_mark_and_move,
+ proc_compact,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
@@ -152,16 +184,6 @@ proc_clone(VALUE self)
{
VALUE procval = rb_proc_dup(self);
CLONESETUP(procval, self);
- rb_check_funcall(procval, idInitialize_clone, 1, &self);
- return procval;
-}
-
-/* :nodoc: */
-static VALUE
-proc_dup(VALUE self)
-{
- VALUE procval = rb_proc_dup(self);
- rb_check_funcall(procval, idInitialize_dup, 1, &self);
return procval;
}
@@ -288,12 +310,23 @@ binding_free(void *ptr)
}
static void
-binding_mark_and_move(void *ptr)
+binding_mark(void *ptr)
{
rb_binding_t *bind = ptr;
- block_mark_and_move((struct rb_block *)&bind->block);
- rb_gc_mark_and_move((VALUE *)&bind->pathobj);
+ RUBY_MARK_ENTER("binding");
+ block_mark(&bind->block);
+ rb_gc_mark_movable(bind->pathobj);
+ RUBY_MARK_LEAVE("binding");
+}
+
+static void
+binding_compact(void *ptr)
+{
+ rb_binding_t *bind = ptr;
+
+ block_compact((struct rb_block *)&bind->block);
+ UPDATE_REFERENCE(bind->pathobj);
}
static size_t
@@ -305,10 +338,10 @@ binding_memsize(const void *ptr)
const rb_data_type_t ruby_binding_data_type = {
"binding",
{
- binding_mark_and_move,
+ binding_mark,
binding_free,
binding_memsize,
- binding_mark_and_move,
+ binding_compact,
},
0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
@@ -360,44 +393,16 @@ rb_binding_new(void)
* call-seq:
* binding -> a_binding
*
- * Returns a Binding object, describing the variable and
+ * Returns a +Binding+ object, describing the variable and
* method bindings at the point of call. This object can be used when
- * calling Binding#eval to execute the evaluated command in this
- * environment, or extracting its local variables.
- *
- * class User
- * def initialize(name, position)
- * @name = name
- * @position = position
- * end
- *
- * def get_binding
- * binding
- * end
- * end
- *
- * user = User.new('Joan', 'manager')
- * template = '{name: @name, position: @position}'
- *
- * # evaluate template in context of the object
- * eval(template, user.get_binding)
- * #=> {:name=>"Joan", :position=>"manager"}
- *
- * Binding#local_variable_get can be used to access the variables
- * whose names are reserved Ruby keywords:
+ * calling +eval+ to execute the evaluated command in this
+ * environment. See also the description of class +Binding+.
*
- * # This is valid parameter declaration, but `if` parameter can't
- * # be accessed by name, because it is a reserved word.
- * def validate(field, validation, if: nil)
- * condition = binding.local_variable_get('if')
- * return unless condition
- *
- * # ...Some implementation ...
+ * def get_binding(param)
+ * binding
* end
- *
- * validate(:name, :empty?, if: false) # skips validation
- * validate(:name, :empty?, if: true) # performs validation
- *
+ * b = get_binding("hello")
+ * eval("param", b) #=> "hello"
*/
static VALUE
@@ -748,19 +753,18 @@ rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int m
}
arity.argc.min = min_argc;
arity.argc.max = max_argc;
- rb_execution_context_t *ec = GET_EC();
- VALUE ret = rb_imemo_new(imemo_ifunc, (VALUE)func, (VALUE)data, arity.packed, (VALUE)rb_vm_svar_lep(ec, ec->cfp));
+ VALUE ret = rb_imemo_new(imemo_ifunc, (VALUE)func, (VALUE)data, arity.packed, 0);
return (struct vm_ifunc *)ret;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_func_proc_new(rb_block_call_func_t func, VALUE val)
{
struct vm_ifunc *ifunc = rb_vm_ifunc_proc_new(func, (void *)val);
return cfunc_proc_new(rb_cProc, (VALUE)ifunc);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc)
{
struct vm_ifunc *ifunc = rb_vm_ifunc_new(func, (void *)val, min_argc, max_argc);
@@ -770,7 +774,7 @@ rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_a
static const char proc_without_block[] = "tried to create Proc object without a block";
static VALUE
-proc_new(VALUE klass, int8_t is_lambda)
+proc_new(VALUE klass, int8_t is_lambda, int8_t kernel)
{
VALUE procval;
const rb_execution_context_t *ec = GET_EC();
@@ -803,8 +807,16 @@ proc_new(VALUE klass, int8_t is_lambda)
break;
case block_handler_type_ifunc:
- case block_handler_type_iseq:
return rb_vm_make_proc_lambda(ec, VM_BH_TO_CAPT_BLOCK(block_handler), klass, is_lambda);
+ case block_handler_type_iseq:
+ {
+ const struct rb_captured_block *captured = VM_BH_TO_CAPT_BLOCK(block_handler);
+ rb_control_frame_t *last_ruby_cfp = rb_vm_get_ruby_level_next_cfp(ec, cfp);
+ if (is_lambda && last_ruby_cfp && vm_cfp_forwarded_bh_p(last_ruby_cfp, block_handler)) {
+ is_lambda = false;
+ }
+ return rb_vm_make_proc_lambda(ec, captured, klass, is_lambda);
+ }
}
VM_UNREACHABLE(proc_new);
return Qnil;
@@ -827,7 +839,7 @@ proc_new(VALUE klass, int8_t is_lambda)
static VALUE
rb_proc_s_new(int argc, VALUE *argv, VALUE klass)
{
- VALUE block = proc_new(klass, FALSE);
+ VALUE block = proc_new(klass, FALSE, FALSE);
rb_obj_call_init_kw(block, argc, argv, RB_PASS_CALLED_KEYWORDS);
return block;
@@ -836,7 +848,7 @@ rb_proc_s_new(int argc, VALUE *argv, VALUE klass)
VALUE
rb_block_proc(void)
{
- return proc_new(rb_cProc, FALSE);
+ return proc_new(rb_cProc, FALSE, FALSE);
}
/*
@@ -849,44 +861,41 @@ rb_block_proc(void)
static VALUE
f_proc(VALUE _)
{
- return proc_new(rb_cProc, FALSE);
+ return proc_new(rb_cProc, FALSE, TRUE);
}
VALUE
rb_block_lambda(void)
{
- return proc_new(rb_cProc, TRUE);
+ return proc_new(rb_cProc, TRUE, FALSE);
}
static void
-f_lambda_filter_non_literal(void)
+f_lambda_warn(void)
{
rb_control_frame_t *cfp = GET_EC()->cfp;
VALUE block_handler = rb_vm_frame_block_handler(cfp);
- if (block_handler == VM_BLOCK_HANDLER_NONE) {
- // no block erorr raised else where
- return;
- }
-
- switch (vm_block_handler_type(block_handler)) {
- case block_handler_type_iseq:
- if (RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)->ep == VM_BH_TO_ISEQ_BLOCK(block_handler)->ep) {
- return;
- }
- break;
- case block_handler_type_symbol:
- return;
- case block_handler_type_proc:
- if (rb_proc_lambda_p(VM_BH_TO_PROC(block_handler))) {
+ if (block_handler != VM_BLOCK_HANDLER_NONE) {
+ switch (vm_block_handler_type(block_handler)) {
+ case block_handler_type_iseq:
+ if (RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)->ep == VM_BH_TO_ISEQ_BLOCK(block_handler)->ep) {
+ return;
+ }
+ break;
+ case block_handler_type_symbol:
return;
+ case block_handler_type_proc:
+ if (rb_proc_lambda_p(VM_BH_TO_PROC(block_handler))) {
+ return;
+ }
+ break;
+ case block_handler_type_ifunc:
+ break;
}
- break;
- case block_handler_type_ifunc:
- break;
}
- rb_raise(rb_eArgError, "the lambda method requires a literal block");
+ rb_warn_deprecated("lambda without a literal block", "the proc without lambda");
}
/*
@@ -900,7 +909,7 @@ f_lambda_filter_non_literal(void)
static VALUE
f_lambda(VALUE _)
{
- f_lambda_filter_non_literal();
+ f_lambda_warn();
return rb_block_lambda();
}
@@ -1364,7 +1373,7 @@ iseq_location(const rb_iseq_t *iseq)
return rb_ary_new4(2, loc);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_iseq_location(const rb_iseq_t *iseq)
{
return iseq_location(iseq);
@@ -1456,8 +1465,24 @@ rb_hash_proc(st_index_t hash, VALUE prc)
{
rb_proc_t *proc;
GetProcPtr(prc, proc);
- hash = rb_hash_uint(hash, (st_index_t)proc->block.as.captured.code.val);
- hash = rb_hash_uint(hash, (st_index_t)proc->block.as.captured.self);
+
+ switch (vm_block_type(&proc->block)) {
+ case block_type_iseq:
+ hash = rb_st_hash_uint(hash, (st_index_t)proc->block.as.captured.code.iseq->body);
+ break;
+ case block_type_ifunc:
+ hash = rb_st_hash_uint(hash, (st_index_t)proc->block.as.captured.code.ifunc->func);
+ break;
+ case block_type_symbol:
+ hash = rb_st_hash_uint(hash, rb_any_hash(proc->block.as.symbol));
+ break;
+ case block_type_proc:
+ hash = rb_st_hash_uint(hash, rb_any_hash(proc->block.as.proc));
+ break;
+ default:
+ rb_bug("rb_hash_proc: unknown block type %d", vm_block_type(&proc->block));
+ }
+
return rb_hash_uint(hash, (st_index_t)proc->block.as.captured.ep);
}
@@ -1476,7 +1501,7 @@ rb_hash_proc(st_index_t hash, VALUE prc)
*
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_sym_to_proc(VALUE sym)
{
static VALUE sym_proc_cache = Qfalse;
@@ -1587,14 +1612,25 @@ proc_to_proc(VALUE self)
}
static void
-bm_mark_and_move(void *ptr)
+bm_mark(void *ptr)
{
struct METHOD *data = ptr;
- rb_gc_mark_and_move((VALUE *)&data->recv);
- rb_gc_mark_and_move((VALUE *)&data->klass);
- rb_gc_mark_and_move((VALUE *)&data->iclass);
- rb_gc_mark_and_move((VALUE *)&data->owner);
- rb_gc_mark_and_move_ptr((rb_method_entry_t **)&data->me);
+ rb_gc_mark_movable(data->recv);
+ rb_gc_mark_movable(data->klass);
+ rb_gc_mark_movable(data->iclass);
+ rb_gc_mark_movable(data->owner);
+ rb_gc_mark_movable((VALUE)data->me);
+}
+
+static void
+bm_compact(void *ptr)
+{
+ struct METHOD *data = ptr;
+ UPDATE_REFERENCE(data->recv);
+ UPDATE_REFERENCE(data->klass);
+ UPDATE_REFERENCE(data->iclass);
+ UPDATE_REFERENCE(data->owner);
+ UPDATE_TYPED_REFERENCE(rb_method_entry_t *, data->me);
}
static size_t
@@ -1606,12 +1642,12 @@ bm_memsize(const void *ptr)
static const rb_data_type_t method_data_type = {
"method",
{
- bm_mark_and_move,
+ bm_mark,
RUBY_TYPED_DEFAULT_FREE,
bm_memsize,
- bm_mark_and_move,
+ bm_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
VALUE
@@ -1977,7 +2013,7 @@ rb_method_name_error(VALUE klass, VALUE str)
VALUE s = Qundef;
if (FL_TEST(c, FL_SINGLETON)) {
- VALUE obj = RCLASS_ATTACHED_OBJECT(klass);
+ VALUE obj = rb_ivar_get(klass, attached);
switch (BUILTIN_TYPE(obj)) {
case T_MODULE:
@@ -2101,9 +2137,10 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
VALUE klass = rb_singleton_class_get(obj);
ID id = rb_check_id(&vid);
- if (NIL_P(klass) ||
- NIL_P(klass = RCLASS_ORIGIN(klass)) ||
- !NIL_P(rb_special_singleton_class(obj))) {
+ if (NIL_P(klass)) {
+ /* goto undef; */
+ }
+ else if (NIL_P(klass = RCLASS_ORIGIN(klass))) {
/* goto undef; */
}
else if (! id) {
@@ -2362,17 +2399,7 @@ rb_obj_define_method(int argc, VALUE *argv, VALUE obj)
static VALUE
top_define_method(int argc, VALUE *argv, VALUE obj)
{
- rb_thread_t *th = GET_THREAD();
- VALUE klass;
-
- klass = th->top_wrapper;
- if (klass) {
- rb_warning("main.define_method in the wrapped load is effective only in wrapper module");
- }
- else {
- klass = rb_cObject;
- }
- return rb_mod_define_method(argc, argv, klass);
+ return rb_mod_define_method(argc, argv, rb_top_main_class("define_method"));
}
/*
@@ -3146,7 +3173,7 @@ method_inspect(VALUE method)
rb_str_buf_append(str, rb_inspect(defined_class));
}
else if (FL_TEST(mklass, FL_SINGLETON)) {
- VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
+ VALUE v = rb_ivar_get(mklass, attached);
if (UNDEF_P(data->recv)) {
rb_str_buf_append(str, rb_inspect(mklass));
@@ -3166,7 +3193,7 @@ method_inspect(VALUE method)
else {
mklass = data->klass;
if (FL_TEST(mklass, FL_SINGLETON)) {
- VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
+ VALUE v = rb_ivar_get(mklass, attached);
if (!(RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE))) {
do {
mklass = RCLASS_SUPER(mklass);
@@ -4268,7 +4295,7 @@ Init_Proc(void)
rb_define_method(rb_cProc, "to_proc", proc_to_proc, 0);
rb_define_method(rb_cProc, "arity", proc_arity, 0);
rb_define_method(rb_cProc, "clone", proc_clone, 0);
- rb_define_method(rb_cProc, "dup", proc_dup, 0);
+ rb_define_method(rb_cProc, "dup", rb_proc_dup, 0);
rb_define_method(rb_cProc, "hash", proc_hash, 0);
rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
rb_define_alias(rb_cProc, "inspect", "to_s");
diff --git a/process.c b/process.c
index 4e6d67e127..c317a4cc2c 100644
--- a/process.c
+++ b/process.c
@@ -103,20 +103,18 @@ int initgroups(const char *, rb_gid_t);
#include "internal/error.h"
#include "internal/eval.h"
#include "internal/hash.h"
-#include "internal/io.h"
#include "internal/numeric.h"
#include "internal/object.h"
#include "internal/process.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "internal/warnings.h"
-#include "rjit.h"
+#include "mjit.h"
#include "ruby/io.h"
#include "ruby/st.h"
#include "ruby/thread.h"
#include "ruby/util.h"
#include "vm_core.h"
-#include "vm_sync.h"
#include "ruby/ractor.h"
/* define system APIs */
@@ -361,8 +359,6 @@ static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
#endif
static ID id_hertz;
-static rb_pid_t cached_pid;
-
/* execv and execl are async-signal-safe since SUSv4 (POSIX.1-2008, XPG7) */
#if defined(__sun) && !defined(_XPG7) /* Solaris 10, 9, ... */
#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
@@ -498,32 +494,38 @@ parent_redirect_close(int fd)
#define parent_redirect_close(fd) close_unless_reserved(fd)
#endif
+/*
+ * Document-module: Process
+ *
+ * The module contains several groups of functionality for handling OS processes:
+ *
+ * * Low-level property introspection and management of the current process, like
+ * Process.argv0, Process.pid;
+ * * Low-level introspection of other processes, like Process.getpgid, Process.getpriority;
+ * * Management of the current process: Process.abort, Process.exit, Process.daemon, etc.
+ * (for convenience, most of those are also available as global functions
+ * and module functions of Kernel);
+ * * Creation and management of child processes: Process.fork, Process.spawn, and
+ * related methods;
+ * * Management of low-level system clock: Process.times and Process.clock_gettime,
+ * which could be important for proper benchmarking and other elapsed
+ * time measurement tasks.
+ */
+
static VALUE
get_pid(void)
{
- if (UNLIKELY(!cached_pid)) { /* 0 is not a valid pid */
- cached_pid = getpid();
- }
- /* pid should be likely POSFIXABLE() */
- return PIDT2NUM(cached_pid);
-}
-
-#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
-static void
-clear_pid_cache(void)
-{
- cached_pid = 0;
+ return PIDT2NUM(getpid());
}
-#endif
/*
* call-seq:
- * Process.pid -> integer
- *
- * Returns the process ID of the current process:
+ * Process.pid -> integer
*
- * Process.pid # => 15668
+ * Returns the process id of this process. Not available on all
+ * platforms.
*
+ * Process.pid #=> 27415
*/
static VALUE
@@ -540,19 +542,18 @@ get_ppid(void)
/*
* call-seq:
- * Process.ppid -> integer
+ * Process.ppid -> integer
*
- * Returns the process ID of the parent of the current process:
+ * Returns the process id of the parent of this process. Returns
+ * untrustworthy value on Win32/64. Not available on all platforms.
*
- * puts "Pid is #{Process.pid}."
- * fork { puts "Parent pid is #{Process.ppid}." }
+ * puts "I am #{Process.pid}"
+ * Process.fork { puts "Dad is #{Process.ppid}" }
*
- * Output:
+ * <em>produces:</em>
*
- * Pid is 271290.
- * Parent pid is 271290.
- *
- * May not return a trustworthy value on certain platforms.
+ * I am 27417
+ * Dad is 27417
*/
static VALUE
@@ -566,21 +567,30 @@ proc_get_ppid(VALUE _)
*
* Document-class: Process::Status
*
- * A Process::Status contains information about a system process.
- *
- * Thread-local variable <tt>$?</tt> is initially +nil+.
- * Some methods assign to it a Process::Status object
- * that represents a system process (either running or terminated):
- *
- * `ruby -e "exit 99"`
- * stat = $? # => #<Process::Status: pid 1262862 exit 99>
- * stat.class # => Process::Status
- * stat.to_i # => 25344
- * stat >> 8 # => 99
- * stat.stopped? # => false
- * stat.exited? # => true
- * stat.exitstatus # => 99
- *
+ * Process::Status encapsulates the information on the
+ * status of a running or terminated system process. The built-in
+ * variable <code>$?</code> is either +nil+ or a
+ * Process::Status object.
+ *
+ * fork { exit 99 } #=> 26557
+ * Process.wait #=> 26557
+ * $?.class #=> Process::Status
+ * $?.to_i #=> 25344
+ * $? >> 8 #=> 99
+ * $?.stopped? #=> false
+ * $?.exited? #=> true
+ * $?.exitstatus #=> 99
+ *
+ * Posix systems record information on processes using a 16-bit
+ * integer. The lower bits record the process status (stopped,
+ * exited, signaled) and the upper bits possibly contain additional
+ * information (for example the program's return code in the case of
+ * exited processes). Pre Ruby 1.8, these bits were exposed directly
+ * to the Ruby program. Ruby now encapsulates these in a
+ * Process::Status object. To maximize compatibility,
+ * however, these objects retain a bit-oriented interface. In the
+ * descriptions that follow, when we talk about the integer value of
+ * _stat_, we're referring to this 16 bit value.
*/
static VALUE rb_cProcessStatus;
@@ -616,25 +626,18 @@ rb_last_status_get(void)
/*
* call-seq:
- * Process.last_status -> Process::Status or nil
+ * Process.last_status -> Process::Status or nil
*
- * Returns a Process::Status object representing the most recently exited
- * child process in the current thread, or +nil+ if none:
+ * Returns the status of the last executed child process in the
+ * current thread.
*
- * Process.spawn('ruby', '-e', 'exit 13')
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 14396 exit 13>
+ * Process.wait Process.spawn("ruby", "-e", "exit 13")
+ * Process.last_status #=> #<Process::Status: pid 4825 exit 13>
*
- * Process.spawn('ruby', '-e', 'exit 14')
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 4692 exit 14>
- *
- * Process.spawn('ruby', '-e', 'exit 15')
- * # 'exit 15' has not been reaped by #wait.
- * Process.last_status # => #<Process::Status: pid 4692 exit 14>
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 1380 exit 15>
+ * If no child process has ever been executed in the current
+ * thread, this returns +nil+.
*
+ * Process.last_status #=> nil
*/
static VALUE
proc_s_last_status(VALUE mod)
@@ -685,16 +688,10 @@ rb_last_status_set(int status, rb_pid_t pid)
GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
}
-static void
-last_status_clear(rb_thread_t *th)
-{
- th->last_status = Qnil;
-}
-
void
rb_last_status_clear(void)
{
- last_status_clear(GET_THREAD());
+ GET_THREAD()->last_status = Qnil;
}
static rb_pid_t
@@ -713,12 +710,14 @@ pst_status(VALUE pst)
/*
* call-seq:
- * to_i -> integer
+ * stat.to_i -> integer
*
- * Returns the system-dependent integer status of +self+:
+ * Returns the bits in _stat_ as an Integer. Poking
+ * around in these bits is platform dependent.
*
- * `cat /nop`
- * $?.to_i # => 256
+ * fork { exit 0xab } #=> 26566
+ * Process.wait #=> 26566
+ * sprintf('%04x', $?.to_i) #=> "ab00"
*/
static VALUE
@@ -732,13 +731,13 @@ pst_to_i(VALUE self)
/*
* call-seq:
- * pid -> integer
- *
- * Returns the process ID of the process:
+ * stat.pid -> integer
*
- * system("false")
- * $?.pid # => 1247002
+ * Returns the process ID that this status object represents.
*
+ * fork { exit } #=> 26569
+ * Process.wait #=> 26569
+ * $?.pid #=> 26569
*/
static VALUE
@@ -794,13 +793,12 @@ pst_message_status(VALUE str, int status)
/*
* call-seq:
- * to_s -> string
- *
- * Returns a string representation of +self+:
+ * stat.to_s -> string
*
- * `cat /nop`
- * $?.to_s # => "pid 1262141 exit 1"
+ * Show pid and exit status as a string.
*
+ * system("false")
+ * p $?.to_s #=> "pid 12766 exit 1"
*
*/
@@ -822,12 +820,12 @@ pst_to_s(VALUE st)
/*
* call-seq:
- * inspect -> string
+ * stat.inspect -> string
*
- * Returns a string representation of +self+:
+ * Override the inspection method.
*
* system("false")
- * $?.inspect # => "#<Process::Status: pid 1303494 exit 1>"
+ * p $?.inspect #=> "#<Process::Status: pid 12861 exit 1>"
*
*/
@@ -853,15 +851,10 @@ pst_inspect(VALUE st)
/*
* call-seq:
- * stat == other -> true or false
- *
- * Returns whether the value of #to_i == +other+:
- *
- * `cat /nop`
- * stat = $? # => #<Process::Status: pid 1170366 exit 1>
- * sprintf('%x', stat.to_i) # => "100"
- * stat == 0x100 # => true
+ * stat == other -> true or false
*
+ * Returns +true+ if the integer value of _stat_
+ * equals <em>other</em>.
*/
static VALUE
@@ -874,51 +867,20 @@ pst_equal(VALUE st1, VALUE st2)
/*
* call-seq:
- * stat & mask -> integer
- *
- * This method is deprecated; use other attribute methods.
+ * stat & num -> integer
*
- * Returns the logical AND of the value of #to_i with +mask+:
+ * Logical AND of the bits in _stat_ with <em>num</em>.
*
- * `cat /nop`
- * stat = $? # => #<Process::Status: pid 1155508 exit 1>
- * sprintf('%x', stat.to_i) # => "100"
- * stat & 0x00 # => 0
- *
- * ArgumentError is raised if +mask+ is negative.
+ * fork { exit 0x37 }
+ * Process.wait
+ * sprintf('%04x', $?.to_i) #=> "3700"
+ * sprintf('%04x', $? & 0x1e00) #=> "1600"
*/
static VALUE
pst_bitand(VALUE st1, VALUE st2)
{
- int status = PST2INT(st1);
- int mask = NUM2INT(st2);
-
- if (mask < 0) {
- rb_raise(rb_eArgError, "negative mask value: %d", mask);
- }
-#define WARN_SUGGEST(suggest) \
- rb_warn_deprecated_to_remove_at(3.4, "Process::Status#&", suggest)
-
- switch (mask) {
- case 0x80:
- WARN_SUGGEST("Process::Status#coredump?");
- break;
- case 0x7f:
- WARN_SUGGEST("Process::Status#signaled? or Process::Status#termsig");
- break;
- case 0xff:
- WARN_SUGGEST("Process::Status#exited?, Process::Status#stopped? or Process::Status#coredump?");
- break;
- case 0xff00:
- WARN_SUGGEST("Process::Status#exitstatus or Process::Status#stopsig");
- break;
- default:
- WARN_SUGGEST("other Process::Status predicates");
- break;
- }
-#undef WARN_SUGGEST
- status &= mask;
+ int status = PST2INT(st1) & NUM2INT(st2);
return INT2NUM(status);
}
@@ -926,46 +888,20 @@ pst_bitand(VALUE st1, VALUE st2)
/*
* call-seq:
- * stat >> places -> integer
- *
- * This method is deprecated; use other predicate methods.
+ * stat >> num -> integer
*
- * Returns the value of #to_i, shifted +places+ to the right:
+ * Shift the bits in _stat_ right <em>num</em> places.
*
- * `cat /nop`
- * stat = $? # => #<Process::Status: pid 1155508 exit 1>
- * stat.to_i # => 256
- * stat >> 1 # => 128
- * stat >> 2 # => 64
- *
- * ArgumentError is raised if +places+ is negative.
+ * fork { exit 99 } #=> 26563
+ * Process.wait #=> 26563
+ * $?.to_i #=> 25344
+ * $? >> 8 #=> 99
*/
static VALUE
pst_rshift(VALUE st1, VALUE st2)
{
- int status = PST2INT(st1);
- int places = NUM2INT(st2);
-
- if (places < 0) {
- rb_raise(rb_eArgError, "negative shift value: %d", places);
- }
-#define WARN_SUGGEST(suggest) \
- rb_warn_deprecated_to_remove_at(3.4, "Process::Status#>>", suggest)
-
- switch (places) {
- case 7:
- WARN_SUGGEST("Process::Status#coredump?");
- break;
- case 8:
- WARN_SUGGEST("Process::Status#exitstatus or Process::Status#stopsig");
- break;
- default:
- WARN_SUGGEST("other Process::Status attributes");
- break;
- }
-#undef WARN_SUGGEST
- status >>= places;
+ int status = PST2INT(st1) >> NUM2INT(st2);
return INT2NUM(status);
}
@@ -973,11 +909,11 @@ pst_rshift(VALUE st1, VALUE st2)
/*
* call-seq:
- * stopped? -> true or false
+ * stat.stopped? -> true or false
*
- * Returns +true+ if this process is stopped,
- * and if the corresponding #wait call had the Process::WUNTRACED flag set,
- * +false+ otherwise.
+ * Returns +true+ if this process is stopped. This is only returned
+ * if the corresponding #wait call had the Process::WUNTRACED flag
+ * set.
*/
static VALUE
@@ -991,10 +927,10 @@ pst_wifstopped(VALUE st)
/*
* call-seq:
- * stopsig -> integer or nil
+ * stat.stopsig -> integer or nil
*
- * Returns the number of the signal that caused the process to stop,
- * or +nil+ if the process is not stopped.
+ * Returns the number of the signal that caused _stat_ to stop
+ * (or +nil+ if self is not stopped).
*/
static VALUE
@@ -1010,10 +946,10 @@ pst_wstopsig(VALUE st)
/*
* call-seq:
- * signaled? -> true or false
+ * stat.signaled? -> true or false
*
- * Returns +true+ if the process terminated because of an uncaught signal,
- * +false+ otherwise.
+ * Returns +true+ if _stat_ terminated because of
+ * an uncaught signal.
*/
static VALUE
@@ -1027,10 +963,11 @@ pst_wifsignaled(VALUE st)
/*
* call-seq:
- * termsig -> integer or nil
+ * stat.termsig -> integer or nil
*
- * Returns the number of the signal that caused the process to terminate
- * or +nil+ if the process was not terminated by an uncaught signal.
+ * Returns the number of the signal that caused _stat_ to
+ * terminate (or +nil+ if self was not terminated by an
+ * uncaught signal).
*/
static VALUE
@@ -1046,11 +983,11 @@ pst_wtermsig(VALUE st)
/*
* call-seq:
- * exited? -> true or false
+ * stat.exited? -> true or false
*
- * Returns +true+ if the process exited normally
- * (for example using an <code>exit()</code> call or finishing the
- * program), +false+ if not.
+ * Returns +true+ if _stat_ exited normally (for
+ * example using an <code>exit()</code> call or finishing the
+ * program).
*/
static VALUE
@@ -1064,15 +1001,20 @@ pst_wifexited(VALUE st)
/*
* call-seq:
- * exitstatus -> integer or nil
+ * stat.exitstatus -> integer or nil
*
- * Returns the least significant eight bits of the return code
- * of the process if it has exited;
- * +nil+ otherwise:
+ * Returns the least significant eight bits of the return code of
+ * _stat_. Only available if #exited? is +true+.
*
- * `exit 99`
- * $?.exitstatus # => 99
+ * fork { } #=> 26572
+ * Process.wait #=> 26572
+ * $?.exited? #=> true
+ * $?.exitstatus #=> 0
*
+ * fork { exit 99 } #=> 26573
+ * Process.wait #=> 26573
+ * $?.exited? #=> true
+ * $?.exitstatus #=> 99
*/
static VALUE
@@ -1088,14 +1030,10 @@ pst_wexitstatus(VALUE st)
/*
* call-seq:
- * success? -> true, false, or nil
- *
- * Returns:
- *
- * - +true+ if the process has completed successfully and exited.
- * - +false+ if the process has completed unsuccessfully and exited.
- * - +nil+ if the process has not exited.
+ * stat.success? -> true, false or nil
*
+ * Returns +true+ if _stat_ is successful, +false+ if not.
+ * Returns +nil+ if #exited? is not +true+.
*/
static VALUE
@@ -1111,12 +1049,10 @@ pst_success_p(VALUE st)
/*
* call-seq:
- * coredump? -> true or false
- *
- * Returns +true+ if the process generated a coredump
- * when it terminated, +false+ if not.
+ * stat.coredump? -> true or false
*
- * Not available on all platforms.
+ * Returns +true+ if _stat_ generated a coredump
+ * when it terminated. Not available on all platforms.
*/
static VALUE
@@ -1143,6 +1079,8 @@ do_waitpid(rb_pid_t pid, int *st, int flags)
#endif
}
+#define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
+
struct waitpid_state {
struct ccan_list_node wnode;
rb_execution_context_t *ec;
@@ -1154,6 +1092,129 @@ struct waitpid_state {
int errnum;
};
+int rb_sigwait_fd_get(const rb_thread_t *);
+void rb_sigwait_sleep(const rb_thread_t *, int fd, const rb_hrtime_t *);
+void rb_sigwait_fd_put(const rb_thread_t *, int fd);
+void rb_thread_sleep_interruptible(void);
+
+#if USE_MJIT
+static struct waitpid_state mjit_waitpid_state;
+
+// variables shared with thread.c
+// TODO: implement the same thing with postponed_job and obviate these variables
+bool mjit_waitpid_finished = false;
+int mjit_waitpid_status = 0;
+#endif
+
+static int
+waitpid_signal(struct waitpid_state *w)
+{
+ if (w->ec) { /* rb_waitpid */
+ rb_threadptr_interrupt(rb_ec_thread_ptr(w->ec));
+ return TRUE;
+ }
+#if USE_MJIT
+ else if (w == &mjit_waitpid_state && w->ret) { /* mjit_add_waiting_pid */
+ mjit_waitpid_finished = true;
+ mjit_waitpid_status = w->status;
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+// Used for VM memsize reporting. Returns the size of a list of waitpid_state
+// structs. Defined here because the struct definition lives here as well.
+size_t
+rb_vm_memsize_waiting_list(struct ccan_list_head *waiting_list)
+{
+ struct waitpid_state *waitpid = 0;
+ size_t size = 0;
+
+ ccan_list_for_each(waiting_list, waitpid, wnode) {
+ size += sizeof(struct waitpid_state);
+ }
+
+ return size;
+}
+
+/*
+ * When a thread is done using sigwait_fd and there are other threads
+ * sleeping on waitpid, we must kick one of the threads out of
+ * rb_native_cond_wait so it can switch to rb_sigwait_sleep
+ */
+static void
+sigwait_fd_migrate_sleeper(rb_vm_t *vm)
+{
+ struct waitpid_state *w = 0;
+
+ ccan_list_for_each(&vm->waiting_pids, w, wnode) {
+ if (waitpid_signal(w)) return;
+ }
+ ccan_list_for_each(&vm->waiting_grps, w, wnode) {
+ if (waitpid_signal(w)) return;
+ }
+}
+
+void
+rb_sigwait_fd_migrate(rb_vm_t *vm)
+{
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ sigwait_fd_migrate_sleeper(vm);
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+}
+
+#if RUBY_SIGCHLD
+extern volatile unsigned int ruby_nocldwait; /* signal.c */
+/* called by timer thread or thread which acquired sigwait_fd */
+static void
+waitpid_each(rb_vm_t *vm, struct ccan_list_head *head)
+{
+ struct waitpid_state *w = 0, *next;
+
+ ccan_list_for_each_safe(head, w, next, wnode) {
+ rb_pid_t ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+
+ if (!ret) continue;
+ if (ret == -1) w->errnum = errno;
+
+ if (w->pid <= 0) {
+ /* when waiting for a group of processes, make sure a waiter for a
+ * specific pid is given that event in preference */
+ struct waitpid_state *w_inner = 0, *next_inner;
+ ccan_list_for_each_safe(&vm->waiting_pids, w_inner, next_inner, wnode) {
+ if (w_inner->pid == ret) {
+ /* signal this one instead */
+ w = w_inner;
+ }
+ }
+ }
+
+ w->ret = ret;
+ ccan_list_del_init(&w->wnode);
+ waitpid_signal(w);
+ }
+}
+#else
+# define ruby_nocldwait 0
+#endif
+
+void
+ruby_waitpid_all(rb_vm_t *vm)
+{
+#if RUBY_SIGCHLD
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ waitpid_each(vm, &vm->waiting_pids);
+ waitpid_each(vm, &vm->waiting_grps);
+ /* emulate SA_NOCLDWAIT */
+ if (ccan_list_empty(&vm->waiting_pids) && ccan_list_empty(&vm->waiting_grps)) {
+ while (ruby_nocldwait && do_waitpid(-1, 0, WNOHANG) > 0)
+ ; /* keep looping */
+ }
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+#endif
+}
+
static void
waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options)
{
@@ -1164,6 +1225,99 @@ waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options)
w->status = 0;
}
+#if USE_MJIT
+/*
+ * must be called with vm->waitpid_lock held, this is not interruptible
+ */
+void
+mjit_add_waiting_pid(rb_vm_t *vm, rb_pid_t pid)
+{
+ waitpid_state_init(&mjit_waitpid_state, pid, 0);
+ mjit_waitpid_state.ec = 0; // switch the behavior of waitpid_signal
+ ccan_list_add(&vm->waiting_pids, &mjit_waitpid_state.wnode);
+}
+#endif
+
+static VALUE
+waitpid_sleep(VALUE x)
+{
+ struct waitpid_state *w = (struct waitpid_state *)x;
+
+ while (!w->ret) {
+ rb_thread_sleep_interruptible();
+ }
+
+ return Qfalse;
+}
+
+static VALUE
+waitpid_cleanup(VALUE x)
+{
+ struct waitpid_state *w = (struct waitpid_state *)x;
+
+ /*
+ * XXX w->ret is sometimes set but ccan_list_del is still needed, here,
+ * Not sure why, so we unconditionally do ccan_list_del here:
+ */
+ if (TRUE || w->ret == 0) {
+ rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
+
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ ccan_list_del(&w->wnode);
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+ }
+
+ return Qfalse;
+}
+
+#if RUBY_SIGCHLD
+static void
+waitpid_wait(struct waitpid_state *w)
+{
+ rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
+ int need_sleep = FALSE;
+
+ /*
+ * Lock here to prevent do_waitpid from stealing work from the
+ * ruby_waitpid_locked done by mjit workers since mjit works
+ * outside of GVL
+ */
+ rb_native_mutex_lock(&vm->waitpid_lock);
+
+ if (w->options & WNOHANG && w->pid <= 0) {
+ /* In the case of WNOHANG wait for a group, make sure there isn't a zombie child
+ * whose PID we are directly waiting for in another call to waitpid. If there is,
+ * we will reap it via a call to waitpid($pid) with this call to waitpid_each. */
+ waitpid_each(vm, &vm->waiting_pids);
+ /* _now_ it's safe to call do_waitpid, without risk of stealing the wait from
+ * another directed call. */
+ }
+
+ w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+
+ if (w->ret) {
+ if (w->ret == -1) w->errnum = errno;
+ }
+ else if (w->options & WNOHANG) {
+ }
+ else {
+ need_sleep = TRUE;
+ }
+
+ if (need_sleep) {
+ w->cond = 0;
+ /* order matters, favor specified PIDs rather than -1 or 0 */
+ ccan_list_add(w->pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w->wnode);
+ }
+
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+
+ if (need_sleep) {
+ rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
+ }
+}
+#endif
+
static void *
waitpid_blocking_no_SIGCHLD(void *x)
{
@@ -1182,7 +1336,8 @@ waitpid_no_SIGCHLD(struct waitpid_state *w)
}
else {
do {
- rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD, w, RUBY_UBF_PROCESS, 0);
+ rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD, w,
+ RUBY_UBF_PROCESS, 0);
} while (w->ret < 0 && errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
}
if (w->ret == -1)
@@ -1204,44 +1359,67 @@ rb_process_status_wait(rb_pid_t pid, int flags)
waitpid_state_init(&waitpid_state, pid, flags);
waitpid_state.ec = GET_EC();
+#if WAITPID_USE_SIGCHLD
+ waitpid_wait(&waitpid_state);
+#else
waitpid_no_SIGCHLD(&waitpid_state);
+#endif
if (waitpid_state.ret == 0) return Qnil;
+ if (waitpid_state.ret > 0 && ruby_nocldwait) {
+ waitpid_state.ret = -1;
+ waitpid_state.errnum = ECHILD;
+ }
+
return rb_process_status_new(waitpid_state.ret, waitpid_state.status, waitpid_state.errnum);
}
/*
* call-seq:
- * Process::Status.wait(pid = -1, flags = 0) -> Process::Status
+ * Process::Status.wait(pid=-1, flags=0) -> Process::Status
*
- * Like Process.wait, but returns a Process::Status object
- * (instead of an integer pid or nil);
- * see Process.wait for the values of +pid+ and +flags+.
+ * Waits for a child process to exit and returns a Process::Status object
+ * containing information on that process. Which child it waits on
+ * depends on the value of _pid_:
*
- * If there are child processes,
- * waits for a child process to exit and returns a Process::Status object
- * containing information on that process;
- * sets thread-local variable <tt>$?</tt>:
+ * > 0:: Waits for the child whose process ID equals _pid_.
*
- * Process.spawn('cat /nop') # => 1155880
- * Process::Status.wait # => #<Process::Status: pid 1155880 exit 1>
- * $? # => #<Process::Status: pid 1155508 exit 1>
+ * 0:: Waits for any child whose process group ID equals that of the
+ * calling process.
*
- * If there is no child process,
- * returns an "empty" Process::Status object
- * that does not represent an actual process;
- * does not set thread-local variable <tt>$?</tt>:
+ * -1:: Waits for any child process (the default if no _pid_ is
+ * given).
*
- * Process::Status.wait # => #<Process::Status: pid -1 exit 0>
- * $? # => #<Process::Status: pid 1155508 exit 1> # Unchanged.
+ * < -1:: Waits for any child whose process group ID equals the absolute
+ * value of _pid_.
*
- * May invoke the scheduler hook Fiber::Scheduler#process_wait.
+ * The _flags_ argument may be a logical or of the flag values
+ * Process::WNOHANG (do not block if no child available)
+ * or Process::WUNTRACED (return stopped children that
+ * haven't been reported). Not all flags are available on all
+ * platforms, but a flag value of zero will work on all platforms.
*
+ * Returns +nil+ if there are no child processes.
* Not available on all platforms.
+ *
+ * May invoke the scheduler hook _process_wait_.
+ *
+ * fork { exit 99 } #=> 27429
+ * Process::Status.wait #=> pid 27429 exit 99
+ * $? #=> nil
+ *
+ * pid = fork { sleep 3 } #=> 27440
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * Process::Status.wait(pid, Process::WNOHANG) #=> nil
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * Process::Status.wait(pid, 0) #=> pid 27440 exit 99
+ * Time.now #=> 2008-03-08 19:56:19 +0900
+ *
+ * This is an EXPERIMENTAL FEATURE.
*/
-static VALUE
+VALUE
rb_process_status_waitv(int argc, VALUE *argv, VALUE _)
{
rb_check_arity(argc, 0, 2);
@@ -1326,155 +1504,69 @@ proc_wait(int argc, VALUE *argv)
/*
* call-seq:
- * Process.wait(pid = -1, flags = 0) -> integer
- *
- * Waits for a suitable child process to exit, returns its process ID,
- * and sets <tt>$?</tt> to a Process::Status object
- * containing information on that process.
- * Which child it waits for depends on the value of the given +pid+:
- *
- * - Positive integer: Waits for the child process whose process ID is +pid+:
- *
- * pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866
- * pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891
- * Process.wait(pid0) # => 230866
- * $? # => #<Process::Status: pid 230866 exit 13>
- * Process.wait(pid1) # => 230891
- * $? # => #<Process::Status: pid 230891 exit 14>
- * Process.wait(pid0) # Raises Errno::ECHILD
- *
- * - <tt>0</tt>: Waits for any child process whose group ID
- * is the same as that of the current process:
- *
- * parent_pgpid = Process.getpgid(Process.pid)
- * puts "Parent process group ID is #{parent_pgpid}."
- * child0_pid = fork do
- * puts "Child 0 pid is #{Process.pid}"
- * child0_pgid = Process.getpgid(Process.pid)
- * puts "Child 0 process group ID is #{child0_pgid} (same as parent's)."
- * end
- * child1_pid = fork do
- * puts "Child 1 pid is #{Process.pid}"
- * Process.setpgid(0, Process.pid)
- * child1_pgid = Process.getpgid(Process.pid)
- * puts "Child 1 process group ID is #{child1_pgid} (different from parent's)."
- * end
- * retrieved_pid = Process.wait(0)
- * puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid."
- * begin
- * Process.wait(0)
- * rescue Errno::ECHILD => x
- * puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID."
- * end
- *
- * Output:
- *
- * Parent process group ID is 225764.
- * Child 0 pid is 225788
- * Child 0 process group ID is 225764 (same as parent's).
- * Child 1 pid is 225789
- * Child 1 process group ID is 225789 (different from parent's).
- * Process.wait(0) returned pid 225788, which is child 0 pid.
- * Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
- *
- * - <tt>-1</tt> (default): Waits for any child process:
- *
- * parent_pgpid = Process.getpgid(Process.pid)
- * puts "Parent process group ID is #{parent_pgpid}."
- * child0_pid = fork do
- * puts "Child 0 pid is #{Process.pid}"
- * child0_pgid = Process.getpgid(Process.pid)
- * puts "Child 0 process group ID is #{child0_pgid} (same as parent's)."
- * end
- * child1_pid = fork do
- * puts "Child 1 pid is #{Process.pid}"
- * Process.setpgid(0, Process.pid)
- * child1_pgid = Process.getpgid(Process.pid)
- * puts "Child 1 process group ID is #{child1_pgid} (different from parent's)."
- * sleep 3 # To force child 1 to exit later than child 0 exit.
- * end
- * child_pids = [child0_pid, child1_pid]
- * retrieved_pid = Process.wait(-1)
- * puts child_pids.include?(retrieved_pid)
- * retrieved_pid = Process.wait(-1)
- * puts child_pids.include?(retrieved_pid)
- *
- * Output:
- *
- * Parent process group ID is 228736.
- * Child 0 pid is 228758
- * Child 0 process group ID is 228736 (same as parent's).
- * Child 1 pid is 228759
- * Child 1 process group ID is 228759 (different from parent's).
- * true
- * true
- *
- * - Less than <tt>-1</tt>: Waits for any child whose process group ID is <tt>-pid</tt>:
- *
- * parent_pgpid = Process.getpgid(Process.pid)
- * puts "Parent process group ID is #{parent_pgpid}."
- * child0_pid = fork do
- * puts "Child 0 pid is #{Process.pid}"
- * child0_pgid = Process.getpgid(Process.pid)
- * puts "Child 0 process group ID is #{child0_pgid} (same as parent's)."
- * end
- * child1_pid = fork do
- * puts "Child 1 pid is #{Process.pid}"
- * Process.setpgid(0, Process.pid)
- * child1_pgid = Process.getpgid(Process.pid)
- * puts "Child 1 process group ID is #{child1_pgid} (different from parent's)."
- * end
- * sleep 1
- * retrieved_pid = Process.wait(-child1_pid)
- * puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid."
- * begin
- * Process.wait(-child1_pid)
- * rescue Errno::ECHILD => x
- * puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}."
- * end
- *
- * Output:
- *
- * Parent process group ID is 230083.
- * Child 0 pid is 230108
- * Child 0 process group ID is 230083 (same as parent's).
- * Child 1 pid is 230109
- * Child 1 process group ID is 230109 (different from parent's).
- * Process.wait(-child1_pid) returned pid 230109, which is child 1 pid.
- * Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
- *
- * Argument +flags+ should be given as one of the following constants,
- * or as the logical OR of both:
- *
- * - Process::WNOHANG: Does not block if no child process is available.
- * - Process:WUNTRACED: May return a stopped child process, even if not yet reported.
- *
- * Not all flags are available on all platforms.
- *
- * Raises Errno::ECHILD if there is no suitable child process.
- *
- * Not available on all platforms.
- *
- * Process.waitpid is an alias for Process.wait.
+ * Process.wait() -> integer
+ * Process.wait(pid=-1, flags=0) -> integer
+ * Process.waitpid(pid=-1, flags=0) -> integer
+ *
+ * Waits for a child process to exit, returns its process id, and
+ * sets <code>$?</code> to a Process::Status object
+ * containing information on that process. Which child it waits on
+ * depends on the value of _pid_:
+ *
+ * > 0:: Waits for the child whose process ID equals _pid_.
+ *
+ * 0:: Waits for any child whose process group ID equals that of the
+ * calling process.
+ *
+ * -1:: Waits for any child process (the default if no _pid_ is
+ * given).
+ *
+ * < -1:: Waits for any child whose process group ID equals the absolute
+ * value of _pid_.
+ *
+ * The _flags_ argument may be a logical or of the flag values
+ * Process::WNOHANG (do not block if no child available)
+ * or Process::WUNTRACED (return stopped children that
+ * haven't been reported). Not all flags are available on all
+ * platforms, but a flag value of zero will work on all platforms.
+ *
+ * Calling this method raises a SystemCallError if there are no child
+ * processes. Not available on all platforms.
+ *
+ * include Process
+ * fork { exit 99 } #=> 27429
+ * wait #=> 27429
+ * $?.exitstatus #=> 99
+ *
+ * pid = fork { sleep 3 } #=> 27440
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * waitpid(pid, Process::WNOHANG) #=> nil
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * waitpid(pid, 0) #=> 27440
+ * Time.now #=> 2008-03-08 19:56:19 +0900
*/
+
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
}
+
/*
* call-seq:
- * Process.wait2(pid = -1, flags = 0) -> [pid, status]
- *
- * Like Process.waitpid, but returns an array
- * containing the child process +pid+ and Process::Status +status+:
- *
- * pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581
- * Process.wait2(pid)
- * # => [309581, #<Process::Status: pid 309581 exit 13>]
- *
- * Process.waitpid2 is an alias for Process.waitpid.
+ * Process.wait2(pid=-1, flags=0) -> [pid, status]
+ * Process.waitpid2(pid=-1, flags=0) -> [pid, status]
+ *
+ * Waits for a child process to exit (see Process::waitpid for exact
+ * semantics) and returns an array containing the process id and the
+ * exit status (a Process::Status object) of that
+ * child. Raises a SystemCallError if there are no child processes.
+ *
+ * Process.fork { exit 99 } #=> 27437
+ * pid, status = Process.wait2
+ * pid #=> 27437
+ * status.exitstatus #=> 99
*/
static VALUE
@@ -1488,17 +1580,22 @@ proc_wait2(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * Process.waitall -> array
+ * Process.waitall -> [ [pid1,status1], ...]
*
- * Waits for all children, returns an array of 2-element arrays;
- * each subarray contains the integer pid and Process::Status status
- * for one of the reaped child processes:
+ * Waits for all children, returning an array of
+ * _pid_/_status_ pairs (where _status_ is a
+ * Process::Status object).
*
- * pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 325470
- * pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 325495
- * Process.waitall
- * # => [[325470, #<Process::Status: pid 325470 exit 13>], [325495, #<Process::Status: pid 325495 exit 14>]]
+ * fork { sleep 0.2; exit 2 } #=> 27432
+ * fork { sleep 0.1; exit 1 } #=> 27433
+ * fork { exit 0 } #=> 27434
+ * p Process.waitall
*
+ * <em>produces</em>:
+ *
+ * [[30982, #<Process::Status: pid 30982 exit 0>],
+ * [30979, #<Process::Status: pid 30979 exit 1>],
+ * [30976, #<Process::Status: pid 30976 exit 2>]]
*/
static VALUE
@@ -1556,41 +1653,48 @@ rb_detach_process(rb_pid_t pid)
/*
* call-seq:
- * Process.detach(pid) -> thread
- *
- * Avoids the potential for a child process to become a
- * {zombie process}[https://en.wikipedia.org/wiki/Zombie_process].
- * Process.detach prevents this by setting up a separate Ruby thread
- * whose sole job is to reap the status of the process _pid_ when it terminates.
+ * Process.detach(pid) -> thread
*
- * This method is needed only when the parent process will never wait
- * for the child process.
+ * Some operating systems retain the status of terminated child
+ * processes until the parent collects that status (normally using
+ * some variant of <code>wait()</code>). If the parent never collects
+ * this status, the child stays around as a <em>zombie</em> process.
+ * Process::detach prevents this by setting up a separate Ruby thread
+ * whose sole job is to reap the status of the process _pid_ when it
+ * terminates. Use #detach only when you do not intend to explicitly
+ * wait for the child to terminate.
*
- * This example does not reap the second child process;
- * that process appears as a zombie in the process status (+ps+) output:
+ * The waiting thread returns the exit status of the detached process
+ * when it terminates, so you can use Thread#join to
+ * know the result. If specified _pid_ is not a valid child process
+ * ID, the thread returns +nil+ immediately.
*
- * pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691
- * sleep(1)
- * # Find zombies.
- * system("ps -ho pid,state -p #{pid}")
+ * The waiting thread has #pid method which returns the pid.
*
- * Output:
+ * In this first example, we don't reap the first child process, so
+ * it appears as a zombie in the process status display.
*
- * 312716 Z
+ * p1 = fork { sleep 0.1 }
+ * p2 = fork { sleep 0.2 }
+ * Process.waitpid(p2)
+ * sleep 2
+ * system("ps -ho pid,state -p #{p1}")
*
- * This example also does not reap the second child process,
- * but it does detach the process so that it does not become a zombie:
+ * <em>produces:</em>
*
- * pid = Process.spawn('ruby', '-e', 'exit 13') # => 313213
- * thread = Process.detach(pid)
- * sleep(1)
- * # => #<Process::Waiter:0x00007f038f48b838 run>
- * system("ps -ho pid,state -p #{pid}") # Finds no zombies.
+ * 27389 Z
*
- * The waiting thread can return the pid of the detached child process:
+ * In the next example, Process::detach is used to reap
+ * the child automatically.
*
- * thread.join.pid # => 313262
+ * p1 = fork { sleep 0.1 }
+ * p2 = fork { sleep 0.2 }
+ * Process.detach(p1)
+ * Process.waitpid(p2)
+ * sleep 2
+ * system("ps -ho pid,state -p #{p1}")
*
+ * <em>(produces no output)</em>
*/
static VALUE
@@ -1660,13 +1764,26 @@ before_exec(void)
before_exec_async_signal_safe();
}
+/* This function should be async-signal-safe. Actually it is. */
static void
-after_exec(void)
+after_exec_async_signal_safe(void)
+{
+}
+
+static void
+after_exec_non_async_signal_safe(void)
{
rb_thread_reset_timer_thread();
rb_thread_start_timer_thread();
}
+static void
+after_exec(void)
+{
+ after_exec_async_signal_safe();
+ after_exec_non_async_signal_safe();
+}
+
#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
static void
before_fork_ruby(void)
@@ -1675,34 +1792,14 @@ before_fork_ruby(void)
}
static void
-after_fork_ruby(rb_pid_t pid)
+after_fork_ruby(void)
{
- rb_threadptr_pending_interrupt_clear(GET_THREAD());
- if (pid == 0) {
- // child
- clear_pid_cache();
- rb_thread_atfork();
- }
- else {
- // parent
- after_exec();
- }
+ after_exec();
}
#endif
#if defined(HAVE_WORKING_FORK)
-COMPILER_WARNING_PUSH
-#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
-COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
-#endif
-static inline rb_pid_t
-rb_fork(void)
-{
- return fork();
-}
-COMPILER_WARNING_POP
-
/* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
static void
@@ -3016,6 +3113,7 @@ rb_f_exec(int argc, const VALUE *argv)
execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
eargp = rb_execarg_get(execarg_obj);
+ if (mjit_enabled) mjit_finish(false); // avoid leaking resources, and do not leave files. XXX: JIT-ed handle can leak after exec error is rescued.
before_exec(); /* stop timer thread before redirects */
rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
@@ -3040,89 +3138,77 @@ NORETURN(static VALUE f_exec(int c, const VALUE *a, VALUE _));
/*
* call-seq:
- * exec([env, ] command_line, options = {})
- * exec([env, ] exe_path, *args, options = {})
- *
- * Replaces the current process by doing one of the following:
- *
- * - Passing string +command_line+ to the shell.
- * - Invoking the executable at +exe_path+.
- *
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
- * The new process is created using the
- * {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
- * it may inherit some of its environment from the calling program
- * (possibly including open file descriptors).
- *
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- *
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
- *
- * The first required argument is one of the following:
- *
- * - +command_line+ if it is a string,
- * and if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
- *
- * <b>Argument +command_line+</b>
- *
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
- *
- * exec('if true; then echo "Foo"; fi') # Shell reserved word.
- * exec('echo') # Built-in.
- * exec('date > date.tmp') # Contains meta character.
+ * exec([env,] command... [,options])
*
- * The command line may also contain arguments and options for the command:
+ * Replaces the current process by running the given external _command_, which
+ * can take one of the following forms:
*
- * exec('echo "Foo"')
+ * [<code>exec(commandline)</code>]
+ * command line string which is passed to the standard shell
+ * [<code>exec(cmdname, arg1, ...)</code>]
+ * command name and one or more arguments (no shell)
+ * [<code>exec([cmdname, argv0], arg1, ...)</code>]
+ * command name, +argv[0]+ and zero or more arguments (no shell)
*
- * Output:
+ * In the first form, the string is taken as a command line that is subject to
+ * shell expansion before being executed.
*
- * Foo
+ * The standard shell always means <code>"/bin/sh"</code> on Unix-like systems,
+ * otherwise, <code>ENV["RUBYSHELL"]</code> or <code>ENV["COMSPEC"]</code> on
+ * Windows and similar. The command is passed as an argument to the
+ * <code>"-c"</code> switch to the shell, except in the case of +COMSPEC+.
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * If the string from the first form (<code>exec("command")</code>) follows
+ * these simple rules:
*
- * Raises an exception if the new process could not execute.
+ * * no meta characters,
+ * * not starting with shell reserved word or special built-in,
*
- * <b>Argument +exe_path+</b>
+ * Ruby invokes the command directly without shell.
*
- * Argument +exe_path+ is one of the following:
+ * You can force shell invocation by adding ";" to the string (because ";" is
+ * a meta character).
*
- * - The string path to an executable to be called.
- * - A 2-element array containing the path to an executable
- * and the string to be used as the name of the executing process.
+ * Note that this behavior is observable by pid obtained
+ * (return value of spawn() and IO#pid for IO.popen) is the pid of the invoked
+ * command, not shell.
*
- * Example:
+ * In the second form (<code>exec("command1", "arg1", ...)</code>), the first
+ * is taken as a command name and the rest are passed as parameters to command
+ * with no shell expansion.
*
- * exec('/usr/bin/date')
+ * In the third form (<code>exec(["command", "argv0"], "arg1", ...)</code>),
+ * starting a two-element array at the beginning of the command, the first
+ * element is the command to be executed, and the second argument is used as
+ * the <code>argv[0]</code> value, which may show up in process listings.
*
- * Output:
+ * In order to execute the command, one of the <code>exec(2)</code> system
+ * calls are used, so the running command may inherit some of the environment
+ * of the original program (including open file descriptors).
*
- * Sat Aug 26 09:38:00 AM CDT 2023
+ * This behavior is modified by the given +env+ and +options+ parameters. See
+ * ::spawn for details.
*
- * Ruby invokes the executable directly, with no shell and no shell expansion:
+ * If the command fails to execute (typically Errno::ENOENT when
+ * it was not found) a SystemCallError exception is raised.
*
- * exec('doesnt_exist') # Raises Errno::ENOENT
+ * This method modifies process attributes according to given +options+ before
+ * <code>exec(2)</code> system call. See ::spawn for more details about the
+ * given +options+.
*
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
+ * The modified attributes may be retained when <code>exec(2)</code> system
+ * call fails.
*
- * exec('echo', 'C*')
- * exec('echo', 'hello', 'world')
+ * For example, hard resource limits are not restorable.
*
- * Output:
+ * Consider to create a child process using ::spawn or Kernel#system if this
+ * is not acceptable.
*
- * C*
- * hello world
+ * exec "echo *" # echoes list of files in current directory
+ * # never get here
*
- * Raises an exception if the new process could not execute.
+ * exec "echo", "*" # echoes an asterisk
+ * # never get here
*/
static VALUE
@@ -4085,10 +4171,16 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
volatile int try_gc = 1;
struct child_handler_disabler_state old;
int err;
+ rb_nativethread_lock_t *const volatile waitpid_lock_init =
+ (w && WAITPID_USE_SIGCHLD) ? &GET_VM()->waitpid_lock : 0;
while (1) {
+ rb_nativethread_lock_t *waitpid_lock = waitpid_lock_init;
prefork();
disable_child_handler_before_fork(&old);
+ if (waitpid_lock) {
+ rb_native_mutex_lock(waitpid_lock);
+ }
#ifdef HAVE_WORKING_VFORK
if (!has_privilege())
pid = vfork();
@@ -4113,6 +4205,14 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
#endif
}
err = errno;
+ waitpid_lock = waitpid_lock_init;
+ if (waitpid_lock) {
+ if (pid > 0 && w != WAITPID_LOCK_ONLY) {
+ w->pid = pid;
+ ccan_list_add(&GET_VM()->waiting_pids, &w->wnode);
+ }
+ rb_native_mutex_unlock(waitpid_lock);
+ }
disable_child_handler_fork_parent(&old);
if (0 < pid) /* fork succeed, parent process */
return pid;
@@ -4122,6 +4222,30 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
}
}
+#if USE_MJIT
+// This is used to create MJIT's child Ruby process
+pid_t
+rb_mjit_fork(void)
+{
+ struct child_handler_disabler_state old;
+ rb_vm_t *vm = GET_VM();
+ prefork();
+ disable_child_handler_before_fork(&old);
+ before_fork_ruby();
+
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ pid_t pid = rb_fork();
+ if (pid > 0) mjit_add_waiting_pid(vm, pid);
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+
+ after_fork_ruby();
+ disable_child_handler_fork_parent(&old);
+ if (pid == 0) rb_thread_atfork();
+
+ return pid;
+}
+#endif
+
static rb_pid_t
fork_check_err(struct rb_process_status *status, int (*chfunc)(void*, char *, size_t), void *charg,
VALUE fds, char *errmsg, size_t errmsg_buflen,
@@ -4157,12 +4281,13 @@ fork_check_err(struct rb_process_status *status, int (*chfunc)(void*, char *, si
int state = 0;
status->error = err;
- VM_ASSERT((w == 0) && "only used by extensions");
+ VM_ASSERT((w == 0 || w == WAITPID_LOCK_ONLY) &&
+ "only used by extensions");
rb_protect(proc_syswait, (VALUE)pid, &state);
status->status = state;
}
- else if (!w) {
+ else if (!w || w == WAITPID_LOCK_ONLY) {
rb_syswait(pid);
}
@@ -4177,7 +4302,7 @@ fork_check_err(struct rb_process_status *status, int (*chfunc)(void*, char *, si
* The "async_signal_safe" name is a lie, but it is used by pty.c and
* maybe other exts. fork() is not async-signal-safe due to pthread_atfork
* and future POSIX revisions will remove it from a list of signal-safe
- * functions. rb_waitpid is not async-signal-safe since RJIT, either.
+ * functions. rb_waitpid is not async-signal-safe since MJIT, either.
* For our purposes, we do not need async-signal-safety, here
*/
rb_pid_t
@@ -4207,21 +4332,22 @@ rb_fork_ruby2(struct rb_process_status *status)
while (1) {
prefork();
-
- before_fork_ruby();
+ if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child. Note: child_handler must be enabled to pause MJIT.
disable_child_handler_before_fork(&old);
- {
- pid = rb_fork();
- err = errno;
- if (status) {
- status->pid = pid;
- status->error = err;
- }
+ before_fork_ruby();
+ pid = rb_fork();
+ err = errno;
+ if (status) {
+ status->pid = pid;
+ status->error = err;
}
+ after_fork_ruby();
disable_child_handler_fork_parent(&old); /* yes, bad name */
- after_fork_ruby(pid);
+
+ if (mjit_enabled && pid > 0) mjit_resume(); /* child (pid == 0) is cared by rb_thread_atfork */
if (pid >= 0) { /* fork succeed */
+ if (pid == 0) rb_thread_atfork();
return pid;
}
@@ -4300,62 +4426,27 @@ rb_proc__fork(VALUE _obj)
/*
* call-seq:
- * Process.fork { ... } -> integer or nil
- * Process.fork -> integer or nil
- *
- * Creates a child process.
- *
- * With a block given, runs the block in the child process;
- * on block exit, the child terminates with a status of zero:
- *
- * puts "Before the fork: #{Process.pid}"
- * fork do
- * puts "In the child process: #{Process.pid}"
- * end # => 382141
- * puts "After the fork: #{Process.pid}"
- *
- * Output:
- *
- * Before the fork: 420496
- * After the fork: 420496
- * In the child process: 420520
- *
- * With no block given, the +fork+ call returns twice:
- *
- * - Once in the parent process, returning the pid of the child process.
- * - Once in the child process, returning +nil+.
- *
- * Example:
- *
- * puts "This is the first line before the fork (pid #{Process.pid})"
- * puts fork
- * puts "This is the second line after the fork (pid #{Process.pid})"
- *
- * Output:
- *
- * This is the first line before the fork (pid 420199)
- * 420223
- * This is the second line after the fork (pid 420199)
- *
- * This is the second line after the fork (pid 420223)
- *
- * In either case, the child process may exit using
- * Kernel.exit! to avoid the call to Kernel#at_exit.
- *
- * To avoid zombie processes, the parent process should call either:
- *
- * - Process.wait, to collect the termination statuses of its children.
- * - Process.detach, to register disinterest in their status.
- *
- * The thread calling +fork+ is the only thread in the created child process;
- * +fork+ doesn't copy other threads.
- *
- * Note that method +fork+ is available on some platforms,
- * but not on others:
- *
- * Process.respond_to?(:fork) # => true # Would be false on some.
- *
- * If not, you may use ::spawn instead of +fork+.
+ * Kernel.fork [{ block }] -> integer or nil
+ * Process.fork [{ block }] -> integer or nil
+ *
+ * Creates a subprocess. If a block is specified, that block is run
+ * in the subprocess, and the subprocess terminates with a status of
+ * zero. Otherwise, the +fork+ call returns twice, once in the
+ * parent, returning the process ID of the child, and once in the
+ * child, returning _nil_. The child process can exit using
+ * Kernel.exit! to avoid running any <code>at_exit</code>
+ * functions. The parent process should use Process.wait to collect
+ * the termination statuses of its children or use Process.detach to
+ * register disinterest in their status; otherwise, the operating
+ * system may accumulate zombie processes.
+ *
+ * The thread calling fork is the only thread in the created child process.
+ * fork doesn't copy other threads.
+ *
+ * If fork is not usable, Process.respond_to?(:fork) returns false.
+ *
+ * Note that fork(2) is not available on some platforms like Windows and NetBSD 4.
+ * Therefore you should use spawn() instead of fork().
*/
static VALUE
@@ -4407,18 +4498,13 @@ exit_status_code(VALUE status)
NORETURN(static VALUE rb_f_exit_bang(int argc, VALUE *argv, VALUE obj));
/*
* call-seq:
- * exit!(status = false)
- * Process.exit!(status = false)
+ * Process.exit!(status=false)
*
- * Exits the process immediately; no exit handlers are called.
- * Returns exit status +status+ to the underlying operating system.
+ * Exits the process immediately. No exit handlers are
+ * run. <em>status</em> is returned to the underlying system as the
+ * exit status.
*
* Process.exit!(true)
- *
- * Values +true+ and +false+ for argument +status+
- * indicate, respectively, success and failure;
- * The meanings of integer values are system-dependent.
- *
*/
static VALUE
@@ -4469,47 +4555,43 @@ rb_f_exit(int argc, const VALUE *argv)
NORETURN(static VALUE f_exit(int c, const VALUE *a, VALUE _));
/*
* call-seq:
- * exit(status = true)
- * Process.exit(status = true)
- *
- * Initiates termination of the Ruby script by raising SystemExit;
- * the exception may be caught.
- * Returns exit status +status+ to the underlying operating system.
- *
- * Values +true+ and +false+ for argument +status+
- * indicate, respectively, success and failure;
- * The meanings of integer values are system-dependent.
- *
- * Example:
- *
- * begin
- * exit
- * puts 'Never get here.'
- * rescue SystemExit
- * puts 'Rescued a SystemExit exception.'
- * end
- * puts 'After begin block.'
- *
- * Output:
- *
- * Rescued a SystemExit exception.
- * After begin block.
- *
- * Just prior to final termination,
- * Ruby executes any at-exit procedures (see Kernel::at_exit)
- * and any object finalizers (see ObjectSpace::define_finalizer).
- *
- * Example:
- *
- * at_exit { puts 'In at_exit function.' }
- * ObjectSpace.define_finalizer('string', proc { puts 'In finalizer.' })
- * exit
- *
- * Output:
- *
- * In at_exit function.
- * In finalizer.
- *
+ * exit(status=true)
+ * Kernel::exit(status=true)
+ * Process::exit(status=true)
+ *
+ * Initiates the termination of the Ruby script by raising the
+ * SystemExit exception. This exception may be caught. The
+ * optional parameter is used to return a status code to the invoking
+ * environment.
+ * +true+ and +FALSE+ of _status_ means success and failure
+ * respectively. The interpretation of other integer values are
+ * system dependent.
+ *
+ * begin
+ * exit
+ * puts "never get here"
+ * rescue SystemExit
+ * puts "rescued a SystemExit exception"
+ * end
+ * puts "after begin block"
+ *
+ * <em>produces:</em>
+ *
+ * rescued a SystemExit exception
+ * after begin block
+ *
+ * Just prior to termination, Ruby executes any <code>at_exit</code>
+ * functions (see Kernel::at_exit) and runs any object finalizers
+ * (see ObjectSpace::define_finalizer).
+ *
+ * at_exit { puts "at_exit function" }
+ * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
+ * exit
+ *
+ * <em>produces:</em>
+ *
+ * at_exit function
+ * in finalizer
*/
static VALUE
@@ -4548,16 +4630,13 @@ NORETURN(static VALUE f_abort(int c, const VALUE *a, VALUE _));
/*
* call-seq:
- * abort
- * Process.abort(msg = nil)
+ * abort
+ * Kernel::abort([msg])
+ * Process.abort([msg])
*
- * Terminates execution immediately, effectively by calling
- * <tt>Kernel.exit(false)</tt>.
- *
- * If string argument +msg+ is given,
- * it is written to STDERR prior to termination;
- * otherwise, if an exception was raised,
- * prints its message and backtrace.
+ * Terminate execution immediately, effectively by calling
+ * <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
+ * to STDERR prior to terminating.
*/
static VALUE
@@ -4641,7 +4720,7 @@ rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
rb_last_status_set((status & 0xff) << 8, pid);
# endif
- if (eargp->waitpid_state) {
+ if (eargp->waitpid_state && eargp->waitpid_state != WAITPID_LOCK_ONLY) {
eargp->waitpid_state->pid = pid;
}
@@ -4663,28 +4742,30 @@ static VALUE
do_spawn_process(VALUE arg)
{
struct spawn_args *argp = (struct spawn_args *)arg;
-
rb_execarg_parent_start1(argp->execarg);
-
return (VALUE)rb_spawn_process(DATA_PTR(argp->execarg),
argp->errmsg.ptr, argp->errmsg.buflen);
}
-NOINLINE(static rb_pid_t
- rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen));
-
static rb_pid_t
rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen)
{
struct spawn_args args;
+ struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
+
+ /*
+ * Prevent a race with MJIT where the compiler process where
+ * can hold an FD of ours in between vfork + execve
+ */
+ if (!eargp->waitpid_state && mjit_enabled) {
+ eargp->waitpid_state = WAITPID_LOCK_ONLY;
+ }
args.execarg = execarg_obj;
args.errmsg.ptr = errmsg;
args.errmsg.buflen = errmsg_buflen;
-
- rb_pid_t r = (rb_pid_t)rb_ensure(do_spawn_process, (VALUE)&args,
- execarg_parent_end, execarg_obj);
- return r;
+ return (rb_pid_t)rb_ensure(do_spawn_process, (VALUE)&args,
+ execarg_parent_end, execarg_obj);
}
static rb_pid_t
@@ -4710,131 +4791,68 @@ rb_spawn(int argc, const VALUE *argv)
/*
* call-seq:
- * system([env, ] command_line, options = {}, exception: false) -> true, false, or nil
- * system([env, ] exe_path, *args, options = {}, exception: false) -> true, false, or nil
- *
- * Creates a new child process by doing one of the following
- * in that process:
+ * system([env,] command... [,options], exception: false) -> true, false or nil
*
- * - Passing string +command_line+ to the shell.
- * - Invoking the executable at +exe_path+.
+ * Executes _command..._ in a subshell.
+ * _command..._ is one of following forms.
*
* This method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * Returns:
- *
- * - +true+ if the command exits with status zero.
- * - +false+ if the exit status is a non-zero integer.
- * - +nil+ if the command could not execute.
- *
- * Raises an exception (instead of returning +false+ or +nil+)
- * if keyword argument +exception+ is set to +true+.
- *
- * Assigns the command's error status to <tt>$?</tt>.
- *
- * The new process is created using the
- * {system system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/system.html];
- * it may inherit some of its environment from the calling program
- * (possibly including open file descriptors).
- *
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- *
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
- *
- * The first required argument is one of the following:
- *
- * - +command_line+ if it is a string,
- * and if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
+ * [<code>commandline</code>]
+ * command line string which is passed to the standard shell
+ * [<code>cmdname, arg1, ...</code>]
+ * command name and one or more arguments (no shell)
+ * [<code>[cmdname, argv0], arg1, ...</code>]
+ * command name, <code>argv[0]</code> and zero or more arguments (no shell)
*
- * <b>Argument +command_line+</b>
+ * system returns +true+ if the command gives zero exit status,
+ * +false+ for non zero exit status.
+ * Returns +nil+ if command execution fails.
+ * An error status is available in <code>$?</code>.
*
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
+ * If the <code>exception: true</code> argument is passed, the method
+ * raises an exception instead of returning +false+ or +nil+.
*
- * system('if true; then echo "Foo"; fi') # => true # Shell reserved word.
- * system('echo') # => true # Built-in.
- * system('date > /tmp/date.tmp') # => true # Contains meta character.
- * system('date > /nop/date.tmp') # => false
- * system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
+ * The arguments are processed in the same way as
+ * for Kernel#spawn.
*
- * Assigns the command's error status to <tt>$?</tt>:
+ * The hash arguments, env and options, are same as #exec and #spawn.
+ * See Kernel#spawn for details.
*
- * system('echo') # => true # Built-in.
- * $? # => #<Process::Status: pid 640610 exit 0>
- * system('date > /nop/date.tmp') # => false
- * $? # => #<Process::Status: pid 640742 exit 2>
+ * system("echo *")
+ * system("echo", "*")
*
- * The command line may also contain arguments and options for the command:
+ * <em>produces:</em>
*
- * system('echo "Foo"') # => true
+ * config.h main.rb
+ * *
*
- * Output:
+ * Error handling:
*
- * Foo
+ * system("cat nonexistent.txt")
+ * # => false
+ * system("catt nonexistent.txt")
+ * # => nil
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * system("cat nonexistent.txt", exception: true)
+ * # RuntimeError (Command failed with exit 1: cat)
+ * system("catt nonexistent.txt", exception: true)
+ * # Errno::ENOENT (No such file or directory - catt)
*
- * Raises an exception if the new process could not execute.
- *
- * <b>Argument +exe_path+</b>
- *
- * Argument +exe_path+ is one of the following:
- *
- * - The string path to an executable to be called.
- * - A 2-element array containing the path to an executable
- * and the string to be used as the name of the executing process.
- *
- * Example:
- *
- * system('/usr/bin/date') # => true # Path to date on Unix-style system.
- * system('foo') # => nil # Command failed.
- *
- * Output:
- *
- * Mon Aug 28 11:43:10 AM CDT 2023
- *
- * Assigns the command's error status to <tt>$?</tt>:
- *
- * system('/usr/bin/date') # => true
- * $? # => #<Process::Status: pid 645605 exit 0>
- * system('foo') # => nil
- * $? # => #<Process::Status: pid 645608 exit 127>
- *
- * Ruby invokes the executable directly, with no shell and no shell expansion:
- *
- * system('doesnt_exist') # => nil
- *
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
- *
- * system('echo', 'C*') # => true
- * system('echo', 'hello', 'world') # => true
- *
- * Output:
- *
- * C*
- * hello world
- *
- * Raises an exception if the new process could not execute.
+ * See Kernel#exec for the standard shell.
*/
static VALUE
rb_f_system(int argc, VALUE *argv, VALUE _)
{
- rb_thread_t *th = GET_THREAD();
VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
struct rb_process_status status = {0};
eargp->status = &status;
- last_status_clear(th);
+ rb_last_status_clear();
// This function can set the thread's last status.
// May be different from waitpid_state.pid on exec failure.
@@ -4842,10 +4860,12 @@ rb_f_system(int argc, VALUE *argv, VALUE _)
if (pid > 0) {
VALUE status = rb_process_status_wait(pid, 0);
+
struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
+
// Set the last status:
rb_obj_freeze(status);
- th->last_status = status;
+ GET_THREAD()->last_status = status;
if (data->status == EXIT_SUCCESS) {
return Qtrue;
@@ -4888,111 +4908,271 @@ rb_f_system(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * spawn([env, ] command_line, options = {}) -> pid
- * spawn([env, ] exe_path, *args, options = {}) -> pid
- *
- * Creates a new child process by doing one of the following
- * in that process:
- *
- * - Passing string +command_line+ to the shell.
- * - Invoking the executable at +exe_path+.
- *
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
- * Returns the process ID (pid) of the new process,
- * without waiting for it to complete.
- *
- * To avoid zombie processes, the parent process should call either:
- *
- * - Process.wait, to collect the termination statuses of its children.
- * - Process.detach, to register disinterest in their status.
- *
- * The new process is created using the
- * {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
- * it may inherit some of its environment from the calling program
- * (possibly including open file descriptors).
- *
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- *
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
- *
- * The first required argument is one of the following:
+ * spawn([env,] command... [,options]) -> pid
+ * Process.spawn([env,] command... [,options]) -> pid
+ *
+ * spawn executes specified command and return its pid.
+ *
+ * pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
+ * Process.wait pid
+ *
+ * pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
+ * Process.wait pid
+ *
+ * This method is similar to Kernel#system but it doesn't wait for the command
+ * to finish.
+ *
+ * The parent process should
+ * use Process.wait to collect
+ * the termination status of its child or
+ * use Process.detach to register
+ * disinterest in their status;
+ * otherwise, the operating system may accumulate zombie processes.
+ *
+ * spawn has bunch of options to specify process attributes:
+ *
+ * env: hash
+ * name => val : set the environment variable
+ * name => nil : unset the environment variable
+ *
+ * the keys and the values except for +nil+ must be strings.
+ * command...:
+ * commandline : command line string which is passed to the standard shell
+ * cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.)
+ * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
+ * options: hash
+ * clearing environment variables:
+ * :unsetenv_others => true : clear environment variables except specified by env
+ * :unsetenv_others => false : don't clear (default)
+ * process group:
+ * :pgroup => true or 0 : make a new process group
+ * :pgroup => pgid : join the specified process group
+ * :pgroup => nil : don't change the process group (default)
+ * create new process group: Windows only
+ * :new_pgroup => true : the new process is the root process of a new process group
+ * :new_pgroup => false : don't create a new process group (default)
+ * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
+ * :rlimit_resourcename => limit
+ * :rlimit_resourcename => [cur_limit, max_limit]
+ * umask:
+ * :umask => int
+ * redirection:
+ * key:
+ * FD : single file descriptor in child process
+ * [FD, FD, ...] : multiple file descriptor in child process
+ * value:
+ * FD : redirect to the file descriptor in parent process
+ * string : redirect to file with open(string, "r" or "w")
+ * [string] : redirect to file with open(string, File::RDONLY)
+ * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
+ * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
+ * [:child, FD] : redirect to the redirected file descriptor
+ * :close : close the file descriptor in child process
+ * FD is one of follows
+ * :in : the file descriptor 0 which is the standard input
+ * :out : the file descriptor 1 which is the standard output
+ * :err : the file descriptor 2 which is the standard error
+ * integer : the file descriptor of specified the integer
+ * io : the file descriptor specified as io.fileno
+ * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
+ * :close_others => false : inherit
+ * current directory:
+ * :chdir => str
+ *
+ * The <code>cmdname, arg1, ...</code> form does not use the shell.
+ * However, on different OSes, different things are provided as
+ * built-in commands. An example of this is +'echo'+, which is a
+ * built-in on Windows, but is a normal program on Linux and Mac OS X.
+ * This means that <code>Process.spawn 'echo', '%Path%'</code> will
+ * display the contents of the <tt>%Path%</tt> environment variable
+ * on Windows, but <code>Process.spawn 'echo', '$PATH'</code> prints
+ * the literal <tt>$PATH</tt>.
+ *
+ * If a hash is given as +env+, the environment is
+ * updated by +env+ before <code>exec(2)</code> in the child process.
+ * If a pair in +env+ has nil as the value, the variable is deleted.
+ *
+ * # set FOO as BAR and unset BAZ.
+ * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
+ *
+ * If a hash is given as +options+,
+ * it specifies
+ * process group,
+ * create new process group,
+ * resource limit,
+ * current directory,
+ * umask and
+ * redirects for the child process.
+ * Also, it can be specified to clear environment variables.
+ *
+ * The <code>:unsetenv_others</code> key in +options+ specifies
+ * to clear environment variables, other than specified by +env+.
+ *
+ * pid = spawn(command, :unsetenv_others=>true) # no environment variable
+ * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
+ *
+ * The <code>:pgroup</code> key in +options+ specifies a process group.
+ * The corresponding value should be true, zero, a positive integer, or nil.
+ * true and zero cause the process to be a process leader of a new process group.
+ * A non-zero positive integer causes the process to join the provided process group.
+ * The default value, nil, causes the process to remain in the same process group.
+ *
+ * pid = spawn(command, :pgroup=>true) # process leader
+ * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
+ *
+ * The <code>:new_pgroup</code> key in +options+ specifies to pass
+ * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
+ * Windows API. This option is only for Windows.
+ * true means the new process is the root process of the new process group.
+ * The new process has CTRL+C disabled. This flag is necessary for
+ * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
+ * :new_pgroup is false by default.
+ *
+ * pid = spawn(command, :new_pgroup=>true) # new process group
+ * pid = spawn(command, :new_pgroup=>false) # same process group
+ *
+ * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
+ * <em>foo</em> should be one of resource types such as <code>core</code>.
+ * The corresponding value should be an integer or an array which have one or
+ * two integers: same as cur_limit and max_limit arguments for
+ * Process.setrlimit.
+ *
+ * cur, max = Process.getrlimit(:CORE)
+ * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
+ * pid = spawn(command, :rlimit_core=>max) # enable core dump
+ * pid = spawn(command, :rlimit_core=>0) # never dump core.
+ *
+ * The <code>:umask</code> key in +options+ specifies the umask.
+ *
+ * pid = spawn(command, :umask=>077)
+ *
+ * The :in, :out, :err, an integer, an IO and an array key specifies a redirection.
+ * The redirection maps a file descriptor in the child process.
+ *
+ * For example, stderr can be merged into stdout as follows:
+ *
+ * pid = spawn(command, :err=>:out)
+ * pid = spawn(command, 2=>1)
+ * pid = spawn(command, STDERR=>:out)
+ * pid = spawn(command, STDERR=>STDOUT)
+ *
+ * The hash keys specifies a file descriptor in the child process
+ * started by #spawn.
+ * :err, 2 and STDERR specifies the standard error stream (stderr).
+ *
+ * The hash values specifies a file descriptor in the parent process
+ * which invokes #spawn.
+ * :out, 1 and STDOUT specifies the standard output stream (stdout).
+ *
+ * In the above example,
+ * the standard output in the child process is not specified.
+ * So it is inherited from the parent process.
+ *
+ * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
+ *
+ * A filename can be specified as a hash value.
+ *
+ * pid = spawn(command, :in=>"/dev/null") # read mode
+ * pid = spawn(command, :out=>"/dev/null") # write mode
+ * pid = spawn(command, :err=>"log") # write mode
+ * pid = spawn(command, [:out, :err]=>"/dev/null") # write mode
+ * pid = spawn(command, 3=>"/dev/null") # read mode
*
- * - +command_line+ if it is a string,
- * and if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
+ * For stdout and stderr (and combination of them),
+ * it is opened in write mode.
+ * Otherwise read mode is used.
*
- * <b>Argument +command_line+</b>
+ * For specifying flags and permission of file creation explicitly,
+ * an array is used instead.
*
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
+ * pid = spawn(command, :in=>["file"]) # read mode is assumed
+ * pid = spawn(command, :in=>["file", "r"])
+ * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
+ * pid = spawn(command, :out=>["log", "w", 0600])
+ * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
*
- * spawn('if true; then echo "Foo"; fi') # => 798847 # Shell reserved word.
- * Process.wait # => 798847
- * spawn('echo') # => 798848 # Built-in.
- * Process.wait # => 798848
- * spawn('date > /tmp/date.tmp') # => 798879 # Contains meta character.
- * Process.wait # => 798849
- * spawn('date > /nop/date.tmp') # => 798882 # Issues error message.
- * Process.wait # => 798882
+ * The array specifies a filename, flags and permission.
+ * The flags can be a string or an integer.
+ * If the flags is omitted or nil, File::RDONLY is assumed.
+ * The permission should be an integer.
+ * If the permission is omitted or nil, 0644 is assumed.
*
- * The command line may also contain arguments and options for the command:
+ * If an array of IOs and integers are specified as a hash key,
+ * all the elements are redirected.
*
- * spawn('echo "Foo"') # => 799031
- * Process.wait # => 799031
+ * # stdout and stderr is redirected to log file.
+ * # The file "log" is opened just once.
+ * pid = spawn(command, [:out, :err]=>["log", "w"])
*
- * Output:
+ * Another way to merge multiple file descriptors is [:child, fd].
+ * \[:child, fd] means the file descriptor in the child process.
+ * This is different from fd.
+ * For example, :err=>:out means redirecting child stderr to parent stdout.
+ * But :err=>[:child, :out] means redirecting child stderr to child stdout.
+ * They differ if stdout is redirected in the child process as follows.
*
- * Foo
+ * # stdout and stderr is redirected to log file.
+ * # The file "log" is opened just once.
+ * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
+ * In this case, IO.popen redirects stdout to a pipe in the child process
+ * and [:child, :out] refers the redirected stdout.
*
- * Raises an exception if the new process could not execute.
+ * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
+ * p io.read #=> "out\nerr\n"
*
- * <b>Argument +exe_path+</b>
+ * The <code>:chdir</code> key in +options+ specifies the current directory.
*
- * Argument +exe_path+ is one of the following:
+ * pid = spawn(command, :chdir=>"/var/tmp")
*
- * - The string path to an executable to be called:
+ * spawn closes all non-standard unspecified descriptors by default.
+ * The "standard" descriptors are 0, 1 and 2.
+ * This behavior is specified by :close_others option.
+ * :close_others doesn't affect the standard descriptors which are
+ * closed only if :close is specified explicitly.
*
- * spawn('/usr/bin/date') # Path to date on Unix-style system.
- * Process.wait
+ * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
+ * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
*
- * Output:
+ * :close_others is false by default for spawn and IO.popen.
*
- * Thu Aug 31 10:06:48 AM CDT 2023
+ * Note that fds which close-on-exec flag is already set are closed
+ * regardless of :close_others option.
*
- * - A 2-element array containing the path to an executable
- * and the string to be used as the name of the executing process:
+ * So IO.pipe and spawn can be used as IO.popen.
*
- * pid = spawn(['sleep', 'Hello!'], '1') # 2-element array.
- * p `ps -p #{pid} -o command=`
+ * # similar to r = IO.popen(command)
+ * r, w = IO.pipe
+ * pid = spawn(command, :out=>w) # r, w is closed in the child process.
+ * w.close
*
- * Output:
+ * :close is specified as a hash value to close a fd individually.
*
- * "Hello! 1\n"
+ * f = open(foo)
+ * system(command, f=>:close) # don't inherit f.
*
- * Ruby invokes the executable directly, with no shell and no shell expansion.
+ * If a file descriptor need to be inherited,
+ * io=>io can be used.
*
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
+ * # valgrind has --log-fd option for log destination.
+ * # log_w=>log_w indicates log_w.fileno inherits to child process.
+ * log_r, log_w = IO.pipe
+ * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
+ * log_w.close
+ * p log_r.read
*
- * spawn('echo', 'C*') # => 799392
- * Process.wait # => 799392
- * spawn('echo', 'hello', 'world') # => 799393
- * Process.wait # => 799393
+ * It is also possible to exchange file descriptors.
*
- * Output:
+ * pid = spawn(command, :out=>:err, :err=>:out)
*
- * C*
- * hello world
+ * The hash keys specify file descriptors in the child process.
+ * The hash values specifies file descriptors in the parent process.
+ * So the above specifies exchanging stdout and stderr.
+ * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
+ * file descriptor mapping.
*
- * Raises an exception if the new process could not execute.
+ * See Kernel.exec for the standard shell.
*/
static VALUE
@@ -5024,18 +5204,19 @@ rb_f_spawn(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * sleep(secs = nil) -> slept_secs
- *
- * Suspends execution of the current thread for the number of seconds
- * specified by numeric argument +secs+, or forever if +secs+ is +nil+;
- * returns the integer number of seconds suspended (rounded).
- *
- * Time.new # => 2008-03-08 19:56:19 +0900
- * sleep 1.2 # => 1
- * Time.new # => 2008-03-08 19:56:20 +0900
- * sleep 1.9 # => 2
- * Time.new # => 2008-03-08 19:56:22 +0900
- *
+ * sleep([duration]) -> integer
+ *
+ * Suspends the current thread for _duration_ seconds (which may be any number,
+ * including a +Float+ with fractional seconds). Returns the actual number of
+ * seconds slept (rounded), which may be less than that asked for if another
+ * thread calls Thread#run. Called without an argument, sleep()
+ * will sleep forever.
+ *
+ * Time.new #=> 2008-03-08 19:56:19 +0900
+ * sleep 1.2 #=> 1
+ * Time.new #=> 2008-03-08 19:56:20 +0900
+ * sleep 1.9 #=> 2
+ * Time.new #=> 2008-03-08 19:56:22 +0900
*/
static VALUE
@@ -5048,7 +5229,7 @@ rb_f_sleep(int argc, VALUE *argv, VALUE _)
rb_fiber_scheduler_kernel_sleepv(scheduler, argc, argv);
}
else {
- if (argc == 0 || (argc == 1 && NIL_P(argv[0]))) {
+ if (argc == 0) {
rb_thread_sleep_forever();
}
else {
@@ -5066,13 +5247,13 @@ rb_f_sleep(int argc, VALUE *argv, VALUE _)
#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
/*
* call-seq:
- * Process.getpgrp -> integer
- *
- * Returns the process group ID for the current process:
+ * Process.getpgrp -> integer
*
- * Process.getpgid(0) # => 25527
- * Process.getpgrp # => 25527
+ * Returns the process group ID for this process. Not available on
+ * all platforms.
*
+ * Process.getpgid(0) #=> 25527
+ * Process.getpgrp #=> 25527
*/
static VALUE
@@ -5098,11 +5279,10 @@ proc_getpgrp(VALUE _)
#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
/*
* call-seq:
- * Process.setpgrp -> 0
+ * Process.setpgrp -> 0
*
- * Equivalent to <tt>setpgid(0, 0)</tt>.
- *
- * Not available on all platforms.
+ * Equivalent to <code>setpgid(0,0)</code>. Not available on all
+ * platforms.
*/
static VALUE
@@ -5127,13 +5307,12 @@ proc_setpgrp(VALUE _)
#if defined(HAVE_GETPGID)
/*
* call-seq:
- * Process.getpgid(pid) -> integer
+ * Process.getpgid(pid) -> integer
*
- * Returns the process group ID for the given process ID +pid+:
- *
- * Process.getpgid(Process.ppid) # => 25527
+ * Returns the process group ID for the given process id. Not
+ * available on all platforms.
*
- * Not available on all platforms.
+ * Process.getpgid(Process.ppid()) #=> 25527
*/
static VALUE
@@ -5153,12 +5332,10 @@ proc_getpgid(VALUE obj, VALUE pid)
#ifdef HAVE_SETPGID
/*
* call-seq:
- * Process.setpgid(pid, pgid) -> 0
+ * Process.setpgid(pid, integer) -> 0
*
- * Sets the process group ID for the process given by process ID +pid+
- * to +pgid+.
- *
- * Not available on all platforms.
+ * Sets the process group ID of _pid_ (0 indicates this
+ * process) to <em>integer</em>. Not available on all platforms.
*/
static VALUE
@@ -5180,16 +5357,15 @@ proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
#ifdef HAVE_GETSID
/*
* call-seq:
- * Process.getsid(pid = nil) -> integer
+ * Process.getsid() -> integer
+ * Process.getsid(pid) -> integer
*
- * Returns the session ID of the given process ID +pid+,
- * or of the current process if not given:
+ * Returns the session ID for the given process id. If not given,
+ * return current process sid. Not available on all platforms.
*
- * Process.getsid # => 27422
- * Process.getsid(0) # => 27422
- * Process.getsid(Process.pid()) # => 27422
- *
- * Not available on all platforms.
+ * Process.getsid() #=> 27422
+ * Process.getsid(0) #=> 27422
+ * Process.getsid(Process.pid()) #=> 27422
*/
static VALUE
proc_getsid(int argc, VALUE *argv, VALUE _)
@@ -5216,15 +5392,13 @@ static rb_pid_t ruby_setsid(void);
#endif
/*
* call-seq:
- * Process.setsid -> integer
+ * Process.setsid -> integer
*
- * Establishes the current process as a new session and process group leader,
- * with no controlling tty;
- * returns the session ID:
- *
- * Process.setsid # => 27422
+ * Establishes this process as a new session and process group
+ * leader, with no controlling tty. Returns the session id. Not
+ * available on all platforms.
*
- * Not available on all platforms.
+ * Process.setsid #=> 27422
*/
static VALUE
@@ -5272,26 +5446,19 @@ ruby_setsid(void)
#ifdef HAVE_GETPRIORITY
/*
* call-seq:
- * Process.getpriority(kind, id) -> integer
- *
- * Returns the scheduling priority for specified process, process group,
- * or user.
- *
- * Argument +kind+ is one of:
- *
- * - Process::PRIO_PROCESS: return priority for process.
- * - Process::PRIO_PGRP: return priority for process group.
- * - Process::PRIO_USER: return priority for user.
- *
- * Argument +id+ is the ID for the process, process group, or user;
- * zero specified the current ID for +kind+.
- *
- * Examples:
- *
- * Process.getpriority(Process::PRIO_USER, 0) # => 19
- * Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
- *
- * Not available on all platforms.
+ * Process.getpriority(kind, integer) -> integer
+ *
+ * Gets the scheduling priority for specified process, process group,
+ * or user. <em>kind</em> indicates the kind of entity to find: one
+ * of Process::PRIO_PGRP,
+ * Process::PRIO_USER, or
+ * Process::PRIO_PROCESS. _integer_ is an id
+ * indicating the particular process, process group, or user (an id
+ * of 0 means _current_). Lower priorities are more favorable
+ * for scheduling. Not available on all platforms.
+ *
+ * Process.getpriority(Process::PRIO_USER, 0) #=> 19
+ * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
*/
static VALUE
@@ -5315,18 +5482,14 @@ proc_getpriority(VALUE obj, VALUE which, VALUE who)
#ifdef HAVE_GETPRIORITY
/*
* call-seq:
- * Process.setpriority(kind, integer, priority) -> 0
+ * Process.setpriority(kind, integer, priority) -> 0
*
* See Process.getpriority.
*
- * Examples:
- *
- * Process.setpriority(Process::PRIO_USER, 0, 19) # => 0
- * Process.setpriority(Process::PRIO_PROCESS, 0, 19) # => 0
- * Process.getpriority(Process::PRIO_USER, 0) # => 19
- * Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
- *
- * Not available on all platforms.
+ * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
+ * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
+ * Process.getpriority(Process::PRIO_USER, 0) #=> 19
+ * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
*/
static VALUE
@@ -5574,24 +5737,22 @@ rlimit_resource_value(VALUE rval)
#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
/*
* call-seq:
- * Process.getrlimit(resource) -> [cur_limit, max_limit]
- *
- * Returns a 2-element array of the current (soft) limit
- * and maximum (hard) limit for the given +resource+.
- *
- * Argument +resource+ specifies the resource whose limits are to be returned;
- * see Process.setrlimit.
- *
- * Each of the returned values +cur_limit+ and +max_limit+ is an integer;
- * see Process.setrlimit.
- *
- * Example:
- *
- * Process.getrlimit(:CORE) # => [0, 18446744073709551615]
- *
- * See Process.setrlimit.
- *
- * Not available on all platforms.
+ * Process.getrlimit(resource) -> [cur_limit, max_limit]
+ *
+ * Gets the resource limit of the process.
+ * _cur_limit_ means current (soft) limit and
+ * _max_limit_ means maximum (hard) limit.
+ *
+ * _resource_ indicates the kind of resource to limit.
+ * It is specified as a symbol such as <code>:CORE</code>,
+ * a string such as <code>"CORE"</code> or
+ * a constant such as Process::RLIMIT_CORE.
+ * See Process.setrlimit for details.
+ *
+ * _cur_limit_ and _max_limit_ may be Process::RLIM_INFINITY,
+ * Process::RLIM_SAVED_MAX or
+ * Process::RLIM_SAVED_CUR.
+ * See Process.setrlimit and the system getrlimit(2) manual for details.
*/
static VALUE
@@ -5611,54 +5772,54 @@ proc_getrlimit(VALUE obj, VALUE resource)
#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
/*
* call-seq:
- * Process.setrlimit(resource, cur_limit, max_limit = cur_limit) -> nil
- *
- * Sets limits for the current process for the given +resource+
- * to +cur_limit+ (soft limit) and +max_limit+ (hard limit);
- * returns +nil+.
- *
- * Argument +resource+ specifies the resource whose limits are to be set;
- * the argument may be given as a symbol, as a string, or as a constant
- * beginning with <tt>Process::RLIMIT_</tt>
- * (e.g., +:CORE+, <tt>'CORE'</tt>, or <tt>Process::RLIMIT_CORE</tt>.
- *
- * The resources available and supported are system-dependent,
- * and may include (here expressed as symbols):
- *
- * - +:AS+: Total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD except 4.4BSD-Lite).
- * - +:CORE+: Core size (bytes) (SUSv3).
- * - +:CPU+: CPU time (seconds) (SUSv3).
- * - +:DATA+: Data segment (bytes) (SUSv3).
- * - +:FSIZE+: File size (bytes) (SUSv3).
- * - +:MEMLOCK+: Total size for mlock(2) (bytes) (4.4BSD, GNU/Linux).
- * - +:MSGQUEUE+: Allocation for POSIX message queues (bytes) (GNU/Linux).
- * - +:NICE+: Ceiling on process's nice(2) value (number) (GNU/Linux).
- * - +:NOFILE+: File descriptors (number) (SUSv3).
- * - +:NPROC+: Number of processes for the user (number) (4.4BSD, GNU/Linux).
- * - +:NPTS+: Number of pseudo terminals (number) (FreeBSD).
- * - +:RSS+: Resident memory size (bytes) (4.2BSD, GNU/Linux).
- * - +:RTPRIO+: Ceiling on the process's real-time priority (number) (GNU/Linux).
- * - +:RTTIME+: CPU time for real-time process (us) (GNU/Linux).
- * - +:SBSIZE+: All socket buffers (bytes) (NetBSD, FreeBSD).
- * - +:SIGPENDING+: Number of queued signals allowed (signals) (GNU/Linux).
- * - +:STACK+: Stack size (bytes) (SUSv3).
- *
- * Arguments +cur_limit+ and +max_limit+ may be:
- *
- * - Integers (+max_limit+ should not be smaller than +cur_limit+).
- * - Symbol +:SAVED_MAX+, string <tt>'SAVED_MAX'</tt>,
- * or constant <tt>Process::RLIM_SAVED_MAX</tt>: saved maximum limit.
- * - Symbol +:SAVED_CUR+, string <tt>'SAVED_CUR'</tt>,
- * or constant <tt>Process::RLIM_SAVED_CUR</tt>: saved current limit.
- * - Symbol +:INFINITY+, string <tt>'INFINITY'</tt>,
- * or constant <tt>Process::RLIM_INFINITY</tt>: no limit on resource.
- *
- * This example raises the soft limit of core size to
- * the hard limit to try to make core dump possible:
+ * Process.setrlimit(resource, cur_limit, max_limit) -> nil
+ * Process.setrlimit(resource, cur_limit) -> nil
+ *
+ * Sets the resource limit of the process.
+ * _cur_limit_ means current (soft) limit and
+ * _max_limit_ means maximum (hard) limit.
+ *
+ * If _max_limit_ is not given, _cur_limit_ is used.
+ *
+ * _resource_ indicates the kind of resource to limit.
+ * It should be a symbol such as <code>:CORE</code>,
+ * a string such as <code>"CORE"</code> or
+ * a constant such as Process::RLIMIT_CORE.
+ * The available resources are OS dependent.
+ * Ruby may support following resources.
+ *
+ * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
+ * [CORE] core size (bytes) (SUSv3)
+ * [CPU] CPU time (seconds) (SUSv3)
+ * [DATA] data segment (bytes) (SUSv3)
+ * [FSIZE] file size (bytes) (SUSv3)
+ * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
+ * [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
+ * [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
+ * [NOFILE] file descriptors (number) (SUSv3)
+ * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
+ * [NPTS] number of pseudo terminals (number) (FreeBSD)
+ * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
+ * [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
+ * [RTTIME] CPU time for real-time process (us) (GNU/Linux)
+ * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
+ * [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
+ * [STACK] stack size (bytes) (SUSv3)
+ *
+ * _cur_limit_ and _max_limit_ may be
+ * <code>:INFINITY</code>, <code>"INFINITY"</code> or
+ * Process::RLIM_INFINITY,
+ * which means that the resource is not limited.
+ * They may be Process::RLIM_SAVED_MAX,
+ * Process::RLIM_SAVED_CUR and
+ * corresponding symbols and strings too.
+ * See system setrlimit(2) manual for details.
+ *
+ * The following example raises the soft limit of core size to
+ * the hard limit to try to make core dump possible.
*
* Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
*
- * Not available on all platforms.
*/
static VALUE
@@ -6237,14 +6398,13 @@ p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
/*
* call-seq:
- * Process.uid -> integer
- * Process::UID.rid -> integer
- * Process::Sys.getuid -> integer
- *
- * Returns the (real) user ID of the current process.
+ * Process.uid -> integer
+ * Process::UID.rid -> integer
+ * Process::Sys.getuid -> integer
*
- * Process.uid # => 1000
+ * Returns the (real) user ID of this process.
*
+ * Process.uid #=> 501
*/
static VALUE
@@ -6258,13 +6418,10 @@ proc_getuid(VALUE obj)
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
/*
* call-seq:
- * Process.uid = new_uid -> new_uid
+ * Process.uid= user -> numeric
*
- * Sets the (user) user ID for the current process to +new_uid+:
- *
- * Process.uid = 1000 # => 1000
- *
- * Not available on all platforms.
+ * Sets the (user) user ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -6639,14 +6796,13 @@ p_sys_issetugid(VALUE obj)
/*
* call-seq:
- * Process.gid -> integer
- * Process::GID.rid -> integer
- * Process::Sys.getgid -> integer
- *
- * Returns the (real) group ID for the current process:
+ * Process.gid -> integer
+ * Process::GID.rid -> integer
+ * Process::Sys.getgid -> integer
*
- * Process.gid # => 1000
+ * Returns the (real) group ID for this process.
*
+ * Process.gid #=> 500
*/
static VALUE
@@ -6660,12 +6816,9 @@ proc_getgid(VALUE obj)
#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
/*
* call-seq:
- * Process.gid = new_gid -> new_gid
- *
- * Sets the group ID for the current process to +new_gid+:
- *
- * Process.gid = 1000 # => 1000
+ * Process.gid= integer -> integer
*
+ * Sets the group ID for this process.
*/
static VALUE
@@ -6749,23 +6902,26 @@ maxgroups(void)
#ifdef HAVE_GETGROUPS
/*
* call-seq:
- * Process.groups -> array
+ * Process.groups -> array
*
- * Returns an array of the group IDs
- * in the supplemental group access list for the current process:
+ * Get an Array of the group IDs in the
+ * supplemental group access list for this process.
*
- * Process.groups # => [4, 24, 27, 30, 46, 122, 135, 136, 1000]
+ * Process.groups #=> [27, 6, 10, 11]
*
- * These properties of the returned array are system-dependent:
+ * Note that this method is just a wrapper of getgroups(2).
+ * This means that the following characteristics of
+ * the result completely depend on your system:
*
- * - Whether (and how) the array is sorted.
- * - Whether the array includes effective group IDs.
- * - Whether the array includes duplicate group IDs.
- * - Whether the array size exceeds the value of Process.maxgroups.
+ * - the result is sorted
+ * - the result includes effective GIDs
+ * - the result does not include duplicated GIDs
+ * - the result size does not exceed the value of Process.maxgroups
*
- * Use this call to get a sorted and unique array:
+ * You can make sure to get a sorted unique GID list of
+ * the current process by this expression:
*
- * Process.groups.uniq.sort
+ * Process.groups.uniq.sort
*
*/
@@ -6802,14 +6958,14 @@ proc_getgroups(VALUE obj)
#ifdef HAVE_SETGROUPS
/*
* call-seq:
- * Process.groups = new_groups -> new_groups
+ * Process.groups= array -> array
*
- * Sets the supplemental group access list to the given
- * array of group IDs.
+ * Set the supplemental group access list to the given
+ * Array of group IDs.
*
- * Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
- * Process.groups = [27, 6, 10, 11] # => [27, 6, 10, 11]
- * Process.groups # => [27, 6, 10, 11]
+ * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
+ * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
+ * Process.groups #=> [27, 6, 10, 11]
*
*/
@@ -6851,21 +7007,19 @@ proc_setgroups(VALUE obj, VALUE ary)
#ifdef HAVE_INITGROUPS
/*
* call-seq:
- * Process.initgroups(username, gid) -> array
- *
- * Sets the supplemental group access list;
- * the new list includes:
- *
- * - The group IDs of those groups to which the user given by +username+ belongs.
- * - The group ID +gid+.
+ * Process.initgroups(username, gid) -> array
*
- * Example:
+ * Initializes the supplemental group access list by reading the
+ * system group database and using all groups of which the given user
+ * is a member. The group with the specified _gid_ is also added to
+ * the list. Returns the resulting Array of the GIDs of all the
+ * groups in the supplementary group access list. Not available on
+ * all platforms.
*
- * Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
- * Process.initgroups('me', 30) # => [30, 6, 10, 11]
- * Process.groups # => [30, 6, 10, 11]
+ * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
+ * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
+ * Process.groups #=> [30, 6, 10, 11]
*
- * Not available on all platforms.
*/
static VALUE
@@ -6883,13 +7037,12 @@ proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
/*
* call-seq:
- * Process.maxgroups -> integer
- *
- * Returns the maximum number of group IDs allowed
- * in the supplemental group access list:
+ * Process.maxgroups -> integer
*
- * Process.maxgroups # => 32
+ * Returns the maximum number of GIDs allowed in the supplemental
+ * group access list.
*
+ * Process.maxgroups #=> 32
*/
static VALUE
@@ -6904,10 +7057,10 @@ proc_getmaxgroups(VALUE obj)
#ifdef HAVE_SETGROUPS
/*
* call-seq:
- * Process.maxgroups = new_max -> new_max
+ * Process.maxgroups= integer -> integer
*
- * Sets the maximum number of group IDs allowed
- * in the supplemental group access list.
+ * Sets the maximum number of GIDs allowed in the supplemental group
+ * access list.
*/
static VALUE
@@ -6938,22 +7091,16 @@ static int rb_daemon(int nochdir, int noclose);
/*
* call-seq:
- * Process.daemon(nochdir = nil, noclose = nil) -> 0
- *
- * Detaches the current process from its controlling terminal
- * and runs it in the background as system daemon;
- * returns zero.
- *
- * By default:
- *
- * - Changes the current working directory to the root directory.
- * - Redirects $stdin, $stdout, and $stderr to the null device.
- *
- * If optional argument +nochdir+ is +true+,
- * does not change the current working directory.
- *
- * If optional argument +noclose+ is +true+,
- * does not redirect $stdin, $stdout, or $stderr.
+ * Process.daemon() -> 0
+ * Process.daemon(nochdir=nil,noclose=nil) -> 0
+ *
+ * Detach the process from controlling terminal and run in
+ * the background as system daemon. Unless the argument
+ * nochdir is true (i.e. non false), it changes the current
+ * working directory to the root ("/"). Unless the argument
+ * noclose is true, daemon() will redirect standard input,
+ * standard output and standard error to /dev/null.
+ * Return zero on success, or raise one of Errno::*.
*/
static VALUE
@@ -6972,16 +7119,16 @@ proc_daemon(int argc, VALUE *argv, VALUE _)
return INT2FIX(n);
}
-extern const char ruby_null_device[];
-
static int
rb_daemon(int nochdir, int noclose)
{
int err = 0;
#ifdef HAVE_DAEMON
+ if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child.
before_fork_ruby();
err = daemon(nochdir, noclose);
- after_fork_ruby(0);
+ after_fork_ruby();
+ rb_thread_atfork(); /* calls mjit_resume() */
#else
int n;
@@ -6997,7 +7144,7 @@ rb_daemon(int nochdir, int noclose)
if (!nochdir)
err = chdir("/");
- if (!noclose && (n = rb_cloexec_open(ruby_null_device, O_RDWR, 0)) != -1) {
+ if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
rb_update_max_fd(n);
(void)dup2(n, 0);
(void)dup2(n, 1);
@@ -7210,14 +7357,13 @@ p_gid_change_privilege(VALUE obj, VALUE id)
/*
* call-seq:
- * Process.euid -> integer
- * Process::UID.eid -> integer
- * Process::Sys.geteuid -> integer
+ * Process.euid -> integer
+ * Process::UID.eid -> integer
+ * Process::Sys.geteuid -> integer
*
- * Returns the effective user ID for the current process.
- *
- * Process.euid # => 501
+ * Returns the effective user ID for this process.
*
+ * Process.euid #=> 501
*/
static VALUE
@@ -7253,11 +7399,10 @@ proc_seteuid(rb_uid_t uid)
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
/*
* call-seq:
- * Process.euid = new_euid -> new_euid
- *
- * Sets the effective user ID for the current process.
+ * Process.euid= user
*
- * Not available on all platforms.
+ * Sets the effective user ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -7335,15 +7480,14 @@ p_uid_grant_privilege(VALUE obj, VALUE id)
/*
* call-seq:
- * Process.egid -> integer
- * Process::GID.eid -> integer
- * Process::Sys.geteid -> integer
- *
- * Returns the effective group ID for the current process:
+ * Process.egid -> integer
+ * Process::GID.eid -> integer
+ * Process::Sys.geteid -> integer
*
- * Process.egid # => 500
+ * Returns the effective group ID for this process. Not available on
+ * all platforms.
*
- * Not available on all platforms.
+ * Process.egid #=> 500
*/
static VALUE
@@ -7357,11 +7501,10 @@ proc_getegid(VALUE obj)
#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
/*
* call-seq:
- * Process.egid = new_egid -> new_egid
- *
- * Sets the effective group ID for the current process.
+ * Process.egid = integer -> integer
*
- * Not available on all platforms.
+ * Sets the effective group ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -7834,15 +7977,14 @@ get_clk_tck(void)
/*
* call-seq:
- * Process.times -> process_tms
- *
- * Returns a Process::Tms structure that contains user and system CPU times
- * for the current process, and for its children processes:
+ * Process.times -> aProcessTms
*
- * Process.times
- * # => #<struct Process::Tms utime=55.122118, stime=35.533068, cutime=0.0, cstime=0.002846>
+ * Returns a <code>Tms</code> structure (see Process::Tms)
+ * that contains user and system CPU times for this process,
+ * and also for children processes.
*
- * The precision is platform-defined.
+ * t = Process.times
+ * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
*/
VALUE
@@ -8097,174 +8239,132 @@ ruby_real_ms_time(void)
# define NUM2CLOCKID(x) 0
#endif
-#define clock_failed(name, err, arg) do { \
- int clock_error = (err); \
- rb_syserr_fail_str(clock_error, rb_sprintf("clock_" name "(%+"PRIsVALUE")", (arg))); \
- } while (0)
-
/*
* call-seq:
- * Process.clock_gettime(clock_id, unit = :float_second) -> number
- *
- * Returns a clock time as determined by POSIX function
- * {clock_gettime()}[https://man7.org/linux/man-pages/man3/clock_gettime.3.html]:
- *
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID) # => 198.650379677
- *
- * Argument +clock_id+ should be a symbol or a constant that specifies
- * the clock whose time is to be returned;
- * see below.
- *
- * Optional argument +unit+ should be a symbol that specifies
- * the unit to be used in the returned clock time;
- * see below.
- *
- * <b>Argument +clock_id+</b>
- *
- * Argument +clock_id+ specifies the clock whose time is to be returned;
- * it may be a constant such as <tt>Process::CLOCK_REALTIME</tt>,
- * or a symbol shorthand such as +:CLOCK_REALTIME+.
- *
- * The supported clocks depend on the underlying operating system;
- * this method supports the following clocks on the indicated platforms
- * (raises Errno::EINVAL if called with an unsupported clock):
- *
- * - +:CLOCK_BOOTTIME+: Linux 2.6.39.
- * - +:CLOCK_BOOTTIME_ALARM+: Linux 3.0.
- * - +:CLOCK_MONOTONIC+: SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000.
- * - +:CLOCK_MONOTONIC_COARSE+: Linux 2.6.32.
- * - +:CLOCK_MONOTONIC_FAST+: FreeBSD 8.1.
- * - +:CLOCK_MONOTONIC_PRECISE+: FreeBSD 8.1.
- * - +:CLOCK_MONOTONIC_RAW+: Linux 2.6.28, macOS 10.12.
- * - +:CLOCK_MONOTONIC_RAW_APPROX+: macOS 10.12.
- * - +:CLOCK_PROCESS_CPUTIME_ID+: SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12.
- * - +:CLOCK_PROF+: FreeBSD 3.0, OpenBSD 2.1.
- * - +:CLOCK_REALTIME+: SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012.
- * Time.now is recommended over +:CLOCK_REALTIME:.
- * - +:CLOCK_REALTIME_ALARM+: Linux 3.0.
- * - +:CLOCK_REALTIME_COARSE+: Linux 2.6.32.
- * - +:CLOCK_REALTIME_FAST+: FreeBSD 8.1.
- * - +:CLOCK_REALTIME_PRECISE+: FreeBSD 8.1.
- * - +:CLOCK_SECOND+: FreeBSD 8.1.
- * - +:CLOCK_TAI+: Linux 3.10.
- * - +:CLOCK_THREAD_CPUTIME_ID+: SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12.
- * - +:CLOCK_UPTIME+: FreeBSD 7.0, OpenBSD 5.5.
- * - +:CLOCK_UPTIME_FAST+: FreeBSD 8.1.
- * - +:CLOCK_UPTIME_PRECISE+: FreeBSD 8.1.
- * - +:CLOCK_UPTIME_RAW+: macOS 10.12.
- * - +:CLOCK_UPTIME_RAW_APPROX+: macOS 10.12.
- * - +:CLOCK_VIRTUAL+: FreeBSD 3.0, OpenBSD 2.1.
+ * Process.clock_gettime(clock_id [, unit]) -> number
+ *
+ * Returns a time returned by POSIX clock_gettime() function.
+ *
+ * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ * #=> 896053.968060096
+ *
+ * +clock_id+ specifies a kind of clock.
+ * It is specified as a constant which begins with <code>Process::CLOCK_</code>
+ * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
+ *
+ * The supported constants depends on OS and version.
+ * Ruby provides following types of +clock_id+ if available.
+ *
+ * [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012
+ * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
+ * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
+ * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
+ * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
+ * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
+ * [CLOCK_REALTIME_FAST] FreeBSD 8.1
+ * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
+ * [CLOCK_REALTIME_COARSE] Linux 2.6.32
+ * [CLOCK_REALTIME_ALARM] Linux 3.0
+ * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
+ * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
+ * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
+ * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
+ * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
+ * [CLOCK_BOOTTIME] Linux 2.6.39
+ * [CLOCK_BOOTTIME_ALARM] Linux 3.0
+ * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
+ * [CLOCK_UPTIME_FAST] FreeBSD 8.1
+ * [CLOCK_UPTIME_RAW] macOS 10.12
+ * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
+ * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
+ * [CLOCK_SECOND] FreeBSD 8.1
+ * [CLOCK_TAI] Linux 3.10
*
* Note that SUS stands for Single Unix Specification.
* SUS contains POSIX and clock_gettime is defined in the POSIX part.
- * SUS defines +:CLOCK_REALTIME+ as mandatory but
- * +:CLOCK_MONOTONIC+, +:CLOCK_PROCESS_CPUTIME_ID+,
- * and +:CLOCK_THREAD_CPUTIME_ID+ are optional.
- *
- * Certain emulations are used when the given +clock_id+
- * is not supported directly:
- *
- * - Emulations for +:CLOCK_REALTIME+:
- *
- * - +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+:
- * Use gettimeofday() defined by SUS (deprecated in SUSv4).
- * The resolution is 1 microsecond.
- * - +:TIME_BASED_CLOCK_REALTIME+:
- * Use time() defined by ISO C.
- * The resolution is 1 second.
- *
- * - Emulations for +:CLOCK_MONOTONIC+:
- *
- * - +:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC+:
- * Use mach_absolute_time(), available on Darwin.
- * The resolution is CPU dependent.
- * - +:TIMES_BASED_CLOCK_MONOTONIC+:
- * Use the result value of times() defined by POSIX, thus:
- * >>>
- * Upon successful completion, times() shall return the elapsed real time,
- * in clock ticks, since an arbitrary point in the past
- * (for example, system start-up time).
- *
- * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
- * However, 4.4BSD uses gettimeofday() and it is not monotonic.
- * (FreeBSD uses +:CLOCK_MONOTONIC+ instead, though.)
- *
- * The resolution is the clock tick.
- * "getconf CLK_TCK" command shows the clock ticks per second.
- * (The clock ticks-per-second is defined by HZ macro in older systems.)
- * If it is 100 and clock_t is 32 bits integer type,
- * the resolution is 10 millisecond and cannot represent over 497 days.
- *
- * - Emulations for +:CLOCK_PROCESS_CPUTIME_ID+:
- *
- * - +:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID+:
- * Use getrusage() defined by SUS.
- * getrusage() is used with RUSAGE_SELF to obtain the time only for
- * the calling process (excluding the time for child processes).
- * The result is addition of user time (ru_utime) and system time (ru_stime).
- * The resolution is 1 microsecond.
- * - +:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID+:
- * Use times() defined by POSIX.
- * The result is addition of user time (tms_utime) and system time (tms_stime).
- * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
- * The resolution is the clock tick.
- * "getconf CLK_TCK" command shows the clock ticks per second.
- * (The clock ticks per second is defined by HZ macro in older systems.)
- * If it is 100, the resolution is 10 millisecond.
- * - +:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID+:
- * Use clock() defined by ISO C.
- * The resolution is <tt>1/CLOCKS_PER_SEC</tt>.
- * +CLOCKS_PER_SEC+ is the C-level macro defined by time.h.
- * SUS defines +CLOCKS_PER_SEC+ as 1000000;
- * other systems may define it differently.
- * If +CLOCKS_PER_SEC+ is 1000000 (as in SUS),
- * the resolution is 1 microsecond.
- * If +CLOCKS_PER_SEC+ is 1000000 and clock_t is a 32-bit integer type,
- * it cannot represent over 72 minutes.
- *
- * <b>Argument +unit+</b>
- *
- * Optional argument +unit+ (default +:float_second+)
- * specifies the unit for the returned value.
- *
- * - +:float_microsecond+: Number of microseconds as a float.
- * - +:float_millisecond+: Number of milliseconds as a float.
- * - +:float_second+: Number of seconds as a float.
- * - +:microsecond+: Number of microseconds as an integer.
- * - +:millisecond+: Number of milliseconds as an integer.
- * - +:nanosecond+: Number of nanoseconds as an integer.
- * - +::second+: Number of seconds as an integer.
- *
- * Examples:
- *
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond)
- * # => 203605054.825
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond)
- * # => 203643.696848
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_second)
- * # => 203.762181929
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :microsecond)
- * # => 204123212
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :millisecond)
- * # => 204298
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond)
- * # => 204602286036
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :second)
- * # => 204
+ * SUS defines CLOCK_REALTIME mandatory but
+ * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
+ *
+ * Also, several symbols are accepted as +clock_id+.
+ * There are emulations for clock_gettime().
+ *
+ * For example, Process::CLOCK_REALTIME is defined as
+ * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
+ *
+ * Emulations for +CLOCK_REALTIME+:
+ * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
+ * Use gettimeofday() defined by SUS.
+ * (SUSv4 obsoleted it, though.)
+ * The resolution is 1 microsecond.
+ * [:TIME_BASED_CLOCK_REALTIME]
+ * Use time() defined by ISO C.
+ * The resolution is 1 second.
+ *
+ * Emulations for +CLOCK_MONOTONIC+:
+ * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
+ * Use mach_absolute_time(), available on Darwin.
+ * The resolution is CPU dependent.
+ * [:TIMES_BASED_CLOCK_MONOTONIC]
+ * Use the result value of times() defined by POSIX.
+ * POSIX defines it as "times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time)".
+ * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
+ * However, 4.4BSD uses gettimeofday() and it is not monotonic.
+ * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
+ * The resolution is the clock tick.
+ * "getconf CLK_TCK" command shows the clock ticks per second.
+ * (The clock ticks per second is defined by HZ macro in older systems.)
+ * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
+ * cannot represent over 497 days.
+ *
+ * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
+ * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
+ * Use getrusage() defined by SUS.
+ * getrusage() is used with RUSAGE_SELF to obtain the time only for
+ * the calling process (excluding the time for child processes).
+ * The result is addition of user time (ru_utime) and system time (ru_stime).
+ * The resolution is 1 microsecond.
+ * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
+ * Use times() defined by POSIX.
+ * The result is addition of user time (tms_utime) and system time (tms_stime).
+ * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
+ * The resolution is the clock tick.
+ * "getconf CLK_TCK" command shows the clock ticks per second.
+ * (The clock ticks per second is defined by HZ macro in older systems.)
+ * If it is 100, the resolution is 10 millisecond.
+ * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
+ * Use clock() defined by ISO C.
+ * The resolution is 1/CLOCKS_PER_SEC.
+ * CLOCKS_PER_SEC is the C-level macro defined by time.h.
+ * SUS defines CLOCKS_PER_SEC is 1000000.
+ * Non-Unix systems may define it a different value, though.
+ * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
+ * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
+ *
+ * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
+ *
+ * +unit+ specifies a type of the return value.
+ *
+ * [:float_second] number of seconds as a float (default)
+ * [:float_millisecond] number of milliseconds as a float
+ * [:float_microsecond] number of microseconds as a float
+ * [:second] number of seconds as an integer
+ * [:millisecond] number of milliseconds as an integer
+ * [:microsecond] number of microseconds as an integer
+ * [:nanosecond] number of nanoseconds as an integer
*
* The underlying function, clock_gettime(), returns a number of nanoseconds.
* Float object (IEEE 754 double) is not enough to represent
- * the return value for +:CLOCK_REALTIME+.
+ * the return value for CLOCK_REALTIME.
* If the exact nanoseconds value is required, use +:nanosecond+ as the +unit+.
*
- * The origin (time zero) of the returned value is system-dependent,
- * and may be, for example, system start up time,
- * process start up time, the Epoch, etc.
+ * The origin (zero) of the returned value varies.
+ * For example, system start up time, process start up time, the Epoch, etc.
*
- * The origin in +:CLOCK_REALTIME+ is defined as the Epoch:
- * <tt>1970-01-01 00:00:00 UTC</tt>;
- * some systems count leap seconds and others don't,
- * so the result may vary across systems.
+ * The origin in CLOCK_REALTIME is defined as the Epoch
+ * (1970-01-01 00:00:00 UTC).
+ * But some systems count leap seconds and others doesn't.
+ * So the result can be interpreted differently across systems.
+ * Time.now is recommended over CLOCK_REALTIME.
*/
static VALUE
rb_clock_gettime(int argc, VALUE *argv, VALUE _)
@@ -8441,17 +8541,15 @@ rb_clock_gettime(int argc, VALUE *argv, VALUE _)
gettime:
ret = clock_gettime(c, &ts);
if (ret == -1)
- clock_failed("gettime", errno, clk_id);
+ rb_sys_fail("clock_gettime");
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
- else {
- rb_unexpected_type(clk_id, T_SYMBOL);
- }
- clock_failed("gettime", EINVAL, clk_id);
+ /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
+ rb_syserr_fail(EINVAL, 0);
success:
return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
@@ -8459,39 +8557,45 @@ rb_clock_gettime(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * Process.clock_getres(clock_id, unit = :float_second) -> number
+ * Process.clock_getres(clock_id [, unit]) -> number
+ *
+ * Returns an estimate of the resolution of a +clock_id+ using the POSIX
+ * <code>clock_getres()</code> function.
+ *
+ * Note the reported resolution is often inaccurate on most platforms due to
+ * underlying bugs for this function and therefore the reported resolution
+ * often differs from the actual resolution of the clock in practice.
+ * Inaccurate reported resolutions have been observed for various clocks including
+ * CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX
+ * platforms, when using ARM processors, or when using virtualization.
+ *
+ * +clock_id+ specifies a kind of clock.
+ * See the document of +Process.clock_gettime+ for details.
+ * +clock_id+ can be a symbol as for +Process.clock_gettime+.
*
- * Returns a clock resolution as determined by POSIX function
- * {clock_getres()}[https://man7.org/linux/man-pages/man3/clock_getres.3.html]:
+ * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
*
- * Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09
+ * +unit+ specifies the type of the return value.
+ * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
+ * The default value, +:float_second+, is also the same as
+ * +Process.clock_gettime+.
*
- * See Process.clock_gettime for the values of +clock_id+ and +unit+.
+ * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
+ * +:hertz+ means the reciprocal of +:float_second+.
*
- * Examples:
+ * +:hertz+ can be used to obtain the exact value of
+ * the clock ticks per second for the times() function and
+ * CLOCKS_PER_SEC for the clock() function.
*
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond) # => 0.001
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond) # => 1.0e-06
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 1.0e-09
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :microsecond) # => 0
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :millisecond) # => 0
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond) # => 1
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :second) # => 0
+ * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
+ * returns the clock ticks per second.
*
- * In addition to the values for +unit+ supported in Process.clock_gettime,
- * this method supports +:hertz+, the integer number of clock ticks per second
- * (which is the reciprocal of +:float_second+):
+ * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
+ * returns CLOCKS_PER_SEC.
*
- * Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz) # => 100.0
- * Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 0.01
+ * p Process.clock_getres(Process::CLOCK_MONOTONIC)
+ * #=> 1.0e-09
*
- * <b>Accuracy</b>:
- * Note that the returned resolution may be inaccurate on some platforms
- * due to underlying bugs.
- * Inaccurate resolutions have been reported for various clocks including
- * +:CLOCK_MONOTONIC+ and +:CLOCK_MONOTONIC_RAW+
- * on Linux, macOS, BSD or AIX platforms, when using ARM processors,
- * or when using virtualization.
*/
static VALUE
rb_clock_getres(int argc, VALUE *argv, VALUE _)
@@ -8612,17 +8716,15 @@ rb_clock_getres(int argc, VALUE *argv, VALUE _)
getres:
ret = clock_getres(c, &ts);
if (ret == -1)
- clock_failed("getres", errno, clk_id);
+ rb_sys_fail("clock_getres");
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
- else {
- rb_unexpected_type(clk_id, T_SYMBOL);
- }
- clock_failed("getres", EINVAL, clk_id);
+ /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
+ rb_syserr_fail(EINVAL, 0);
success:
if (unit == ID2SYM(id_hertz)) {
@@ -8647,82 +8749,38 @@ get_PROCESS_ID(ID _x, VALUE *_y)
/*
* call-seq:
- * Process.kill(signal, *ids) -> count
- *
- * Sends a signal to each process specified by +ids+
- * (which must specify at least one ID);
- * returns the count of signals sent.
- *
- * For each given +id+, if +id+ is:
- *
- * - Positive, sends the signal to the process whose process ID is +id+.
- * - Zero, send the signal to all processes in the current process group.
- * - Negative, sends the signal to a system-dependent collection of processes.
- *
- * Argument +signal+ specifies the signal to be sent;
- * the argument may be:
- *
- * - An integer signal number: e.g., +-29+, +0+, +29+.
- * - A signal name (string), with or without leading <tt>'SIG'</tt>,
- * and with or without a further prefixed minus sign (<tt>'-'</tt>):
- * e.g.:
- *
- * - <tt>'SIGPOLL'</tt>.
- * - <tt>'POLL'</tt>,
- * - <tt>'-SIGPOLL'</tt>.
- * - <tt>'-POLL'</tt>.
- *
- * - A signal symbol, with or without leading <tt>'SIG'</tt>,
- * and with or without a further prefixed minus sign (<tt>'-'</tt>):
- * e.g.:
- *
- * - +:SIGPOLL+.
- * - +:POLL+.
- * - <tt>:'-SIGPOLL'</tt>.
- * - <tt>:'-POLL'</tt>.
- *
- * If +signal+ is:
- *
- * - A non-negative integer, or a signal name or symbol
- * without prefixed <tt>'-'</tt>,
- * each process with process ID +id+ is signalled.
- * - A negative integer, or a signal name or symbol
- * with prefixed <tt>'-'</tt>,
- * each process group with group ID +id+ is signalled.
- *
- * Use method Signal.list to see which signals are supported
- * by Ruby on the underlying platform;
- * the method returns a hash of the string names
- * and non-negative integer values of the supported signals.
- * The size and content of the returned hash varies widely
- * among platforms.
- *
- * Additionally, signal +0+ is useful to determine if the process exists.
- *
- * Example:
- *
- * pid = fork do
- * Signal.trap('HUP') { puts 'Ouch!'; exit }
- * # ... do some work ...
- * end
- * # ...
- * Process.kill('HUP', pid)
- * Process.wait
- *
- * Output:
+ * Process.kill(signal, pid, *pids) -> integer
+ *
+ * Sends the given signal to the specified process id(s) if _pid_ is positive.
+ * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
+ * to the group ID of the process. If _pid_ is negative, results are dependent
+ * on the operating system. _signal_ may be an integer signal number or
+ * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
+ * negative (or starts with a minus sign), kills process groups instead of
+ * processes. Not all signals are available on all platforms.
+ * The keys and values of Signal.list are known signal names and numbers,
+ * respectively.
+ *
+ * pid = fork do
+ * Signal.trap("HUP") { puts "Ouch!"; exit }
+ * # ... do some work ...
+ * end
+ * # ...
+ * Process.kill("HUP", pid)
+ * Process.wait
+ *
+ * <em>produces:</em>
*
* Ouch!
*
- * Exceptions:
- *
- * - Raises Errno::EINVAL or RangeError if +signal+ is an integer
- * but invalid.
- * - Raises ArgumentError if +signal+ is a string or symbol
- * but invalid.
- * - Raises Errno::ESRCH or RangeError if one of +ids+ is invalid.
- * - Raises Errno::EPERM if needed permissions are not in force.
+ * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
+ * RangeError will be raised. Otherwise unless _signal_ is a String
+ * or a Symbol, and a known signal name, ArgumentError will be
+ * raised.
*
- * In the last two cases, signals may have been sent to some processes.
+ * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
+ * when failed because of no privilege, will be raised. In these
+ * cases, signals may have been sent to preceding processes.
*/
static VALUE
@@ -8736,363 +8794,10 @@ static VALUE rb_mProcUID;
static VALUE rb_mProcGID;
static VALUE rb_mProcID_Syscall;
-/*
- * call-seq:
- * Process.warmup -> true
- *
- * Notify the Ruby virtual machine that the boot sequence is finished,
- * and that now is a good time to optimize the application. This is useful
- * for long running applications.
- *
- * This method is expected to be called at the end of the application boot.
- * If the application is deployed using a pre-forking model, +Process.warmup+
- * should be called in the original process before the first fork.
- *
- * The actual optimizations performed are entirely implementation specific
- * and may change in the future without notice.
- *
- * On CRuby, +Process.warmup+:
- *
- * * Performs a major GC.
- * * Compacts the heap.
- * * Promotes all surviving objects to the old generation.
- * * Precomputes the coderange of all strings.
- * * Frees all empty heap pages and increments the allocatable pages counter
- * by the number of pages freed.
- * * Invoke +malloc_trim+ if available to free empty malloc pages.
- */
-
-static VALUE
-proc_warmup(VALUE _)
-{
- RB_VM_LOCK_ENTER();
- rb_gc_prepare_heap();
- RB_VM_LOCK_LEAVE();
- return Qtrue;
-}
/*
- * Document-module: Process
- *
- * \Module +Process+ represents a process in the underlying operating system.
- * Its methods support management of the current process and its child processes.
- *
- * == \Process Creation
- *
- * Each of the following methods executes a given command in a new process or subshell,
- * or multiple commands in new processes and/or subshells.
- * The choice of process or subshell depends on the form of the command;
- * see {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
- *
- * - Process.spawn, Kernel#spawn: Executes the command;
- * returns the new pid without waiting for completion.
- * - Process.exec: Replaces the current process by executing the command.
- *
- * In addition:
- *
- * - \Method Kernel#system executes a given command-line (string) in a subshell;
- * returns +true+, +false+, or +nil+.
- * - \Method Kernel#` executes a given command-line (string) in a subshell;
- * returns its $stdout string.
- * - \Module Open3 supports creating child processes
- * with access to their $stdin, $stdout, and $stderr streams.
- *
- * === Execution Environment
- *
- * Optional leading argument +env+ is a hash of name/value pairs,
- * where each name is a string and each value is a string or +nil+;
- * each name/value pair is added to ENV in the new process.
- *
- * Process.spawn( 'ruby -e "p ENV[\"Foo\"]"')
- * Process.spawn({'Foo' => '0'}, 'ruby -e "p ENV[\"Foo\"]"')
- *
- * Output:
- *
- * "0"
- *
- * The effect is usually similar to that of calling ENV#update with argument +env+,
- * where each named environment variable is created or updated
- * (if the value is non-+nil+),
- * or deleted (if the value is +nil+).
- *
- * However, some modifications to the calling process may remain
- * if the new process fails.
- * For example, hard resource limits are not restored.
- *
- * === Argument +command_line+ or +exe_path+
- *
- * The required string argument is one of the following:
- *
- * - +command_line+ if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
- *
- * <b>Argument +command_line+</b>
- *
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
- *
- * system('if true; then echo "Foo"; fi') # => true # Shell reserved word.
- * system('echo') # => true # Built-in.
- * system('date > /tmp/date.tmp') # => true # Contains meta character.
- * system('date > /nop/date.tmp') # => false
- * system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
- *
- * The command line may also contain arguments and options for the command:
- *
- * system('echo "Foo"') # => true
- *
- * Output:
- *
- * Foo
- *
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
- *
- * <b>Argument +exe_path+</b>
- *
- * Argument +exe_path+ is one of the following:
- *
- * - The string path to an executable to be called.
- * - A 2-element array containing the path to an executable to be called,
- * and the string to be used as the name of the executing process.
- *
- * Example:
- *
- * system('/usr/bin/date') # => true # Path to date on Unix-style system.
- * system('foo') # => nil # Command failed.
- *
- * Output:
- *
- * Mon Aug 28 11:43:10 AM CDT 2023
- *
- * === Execution Options
- *
- * Optional trailing argument +options+ is a hash of execution options.
- *
- * ==== Working Directory (+:chdir+)
- *
- * By default, the working directory for the new process is the same as
- * that of the current process:
- *
- * Dir.chdir('/var')
- * Process.spawn('ruby -e "puts Dir.pwd"')
- *
- * Output:
- *
- * /var
- *
- * Use option +:chdir+ to set the working directory for the new process:
- *
- * Process.spawn('ruby -e "puts Dir.pwd"', {chdir: '/tmp'})
- *
- * Output:
- *
- * /tmp
- *
- * The working directory of the current process is not changed:
- *
- * Dir.pwd # => "/var"
- *
- * ==== \File Redirection (\File Descriptor)
- *
- * Use execution options for file redirection in the new process.
- *
- * The key for such an option may be an integer file descriptor (fd),
- * specifying a source,
- * or an array of fds, specifying multiple sources.
- *
- * An integer source fd may be specified as:
- *
- * - _n_: Specifies file descriptor _n_.
- *
- * There are these shorthand symbols for fds:
- *
- * - +:in+: Specifies file descriptor 0 (STDIN).
- * - +:out+: Specifies file descriptor 1 (STDOUT).
- * - +:err+: Specifies file descriptor 2 (STDERR).
- *
- * The value given with a source is one of:
- *
- * - _n_:
- * Redirects to fd _n_ in the parent process.
- * - +filepath+:
- * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>,
- * where +mode+ is <tt>'r'</tt> for source +:in+,
- * or <tt>'w'</tt> for source +:out+ or +:err+.
- * - <tt>[filepath]</tt>:
- * Redirects from the file at +filepath+ via <tt>open(filepath, 'r', 0644)</tt>.
- * - <tt>[filepath, mode]</tt>:
- * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>.
- * - <tt>[filepath, mode, perm]</tt>:
- * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, perm)</tt>.
- * - <tt>[:child, fd]</tt>:
- * Redirects to the redirected +fd+.
- * - +:close+: Closes the file descriptor in child process.
- *
- * See {Access Modes}[rdoc-ref:File@Access+Modes]
- * and {File Permissions}[rdoc-ref:File@File+Permissions].
- *
- * ==== Environment Variables (+:unsetenv_others+)
- *
- * By default, the new process inherits environment variables
- * from the parent process;
- * use execution option key +:unsetenv_others+ with value +true+
- * to clear environment variables in the new process.
- *
- * Any changes specified by execution option +env+ are made after the new process
- * inherits or clears its environment variables;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- *
- * ==== \File-Creation Access (+:umask+)
- *
- * Use execution option +:umask+ to set the file-creation access
- * for the new process;
- * see {Access Modes}[rdoc-ref:File@Access+Modes]:
- *
- * command = 'ruby -e "puts sprintf(\"0%o\", File.umask)"'
- * options = {:umask => 0644}
- * Process.spawn(command, options)
- *
- * Output:
- *
- * 0644
- *
- * ==== \Process Groups (+:pgroup+ and +:new_pgroup+)
- *
- * By default, the new process belongs to the same
- * {process group}[https://en.wikipedia.org/wiki/Process_group]
- * as the parent process.
- *
- * To specify a different process group.
- * use execution option +:pgroup+ with one of the following values:
- *
- * - +true+: Create a new process group for the new process.
- * - _pgid_: Create the new process in the process group
- * whose id is _pgid_.
- *
- * On Windows only, use execution option +:new_pgroup+ with value +true+
- * to create a new process group for the new process.
- *
- * ==== Resource Limits
- *
- * Use execution options to set resource limits.
- *
- * The keys for these options are symbols of the form
- * <tt>:rlimit_<i>resource_name</i></tt>,
- * where _resource_name_ is the downcased form of one of the string
- * resource names described at method Process.setrlimit.
- * For example, key +:rlimit_cpu+ corresponds to resource limit <tt>'CPU'</tt>.
- *
- * The value for such as key is one of:
- *
- * - An integer, specifying both the current and maximum limits.
- * - A 2-element array of integers, specifying the current and maximum limits.
- *
- * ==== \File Descriptor Inheritance
- *
- * By default, the new process inherits file descriptors from the parent process.
- *
- * Use execution option <tt>:close_others => true</tt> to modify that inheritance
- * by closing non-standard fds (3 and greater) that are not otherwise redirected.
- *
- * === Execution Shell
- *
- * On a Unix-like system, the shell invoked is <tt>/bin/sh</tt>;
- * otherwise the shell invoked is determined by environment variable
- * <tt>ENV['RUBYSHELL']</tt>, if defined, or <tt>ENV['COMSPEC']</tt> otherwise.
- *
- * Except for the +COMSPEC+ case,
- * the entire string +command_line+ is passed as an argument
- * to {shell option -c}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/sh.html].
- *
- * The shell performs normal shell expansion on the command line:
- *
- * spawn('echo C*') # => 799139
- * Process.wait # => 799139
- *
- * Output:
- *
- * CONTRIBUTING.md COPYING COPYING.ja
- *
- * == What's Here
- *
- * === Current-Process Getters
- *
- * - ::argv0: Returns the process name as a frozen string.
- * - ::egid: Returns the effective group ID.
- * - ::euid: Returns the effective user ID.
- * - ::getpgrp: Return the process group ID.
- * - ::getrlimit: Returns the resource limit.
- * - ::gid: Returns the (real) group ID.
- * - ::pid: Returns the process ID.
- * - ::ppid: Returns the process ID of the parent process.
- * - ::uid: Returns the (real) user ID.
- *
- * === Current-Process Setters
- *
- * - ::egid=: Sets the effective group ID.
- * - ::euid=: Sets the effective user ID.
- * - ::gid=: Sets the (real) group ID.
- * - ::setproctitle: Sets the process title.
- * - ::setpgrp: Sets the process group ID of the process to zero.
- * - ::setrlimit: Sets a resource limit.
- * - ::setsid: Establishes the process as a new session and process group leader,
- * with no controlling tty.
- * - ::uid=: Sets the user ID.
- *
- * === Current-Process Execution
- *
- * - ::abort: Immediately terminates the process.
- * - ::daemon: Detaches the process from its controlling terminal
- * and continues running it in the background as system daemon.
- * - ::exec: Replaces the process by running a given external command.
- * - ::exit: Initiates process termination by raising exception SystemExit
- * (which may be caught).
- * - ::exit!: Immediately exits the process.
- * - ::warmup: Notifies the Ruby virtual machine that the boot sequence
- * for the application is completed,
- * and that the VM may begin optimizing the application.
- *
- * === Child Processes
- *
- * - ::detach: Guards against a child process becoming a zombie.
- * - ::fork: Creates a child process.
- * - ::kill: Sends a given signal to processes.
- * - ::spawn: Creates a child process.
- * - ::wait, ::waitpid: Waits for a child process to exit; returns its process ID.
- * - ::wait2, ::waitpid2: Waits for a child process to exit; returns its process ID and status.
- * - ::waitall: Waits for all child processes to exit;
- * returns their process IDs and statuses.
- *
- * === \Process Groups
- *
- * - ::getpgid: Returns the process group ID for a process.
- * - ::getpriority: Returns the scheduling priority
- * for a process, process group, or user.
- * - ::getsid: Returns the session ID for a process.
- * - ::groups: Returns an array of the group IDs
- * in the supplemental group access list for this process.
- * - ::groups=: Sets the supplemental group access list
- * to the given array of group IDs.
- * - ::initgroups: Initializes the supplemental group access list.
- * - ::last_status: Returns the status of the last executed child process
- * in the current thread.
- * - ::maxgroups: Returns the maximum number of group IDs allowed
- * in the supplemental group access list.
- * - ::maxgroups=: Sets the maximum number of group IDs allowed
- * in the supplemental group access list.
- * - ::setpgid: Sets the process group ID of a process.
- * - ::setpriority: Sets the scheduling priority
- * for a process, process group, or user.
- *
- * === Timing
- *
- * - ::clock_getres: Returns the resolution of a system clock.
- * - ::clock_gettime: Returns the time from a system clock.
- * - ::times: Returns a Process::Tms object containing times
- * for the current process and its child processes.
- *
+ * The Process module is a collection of methods used to
+ * manipulate processes.
*/
void
@@ -9193,8 +8898,6 @@ InitVM_process(void)
rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
- rb_define_module_function(rb_mProcess, "warmup", proc_warmup, 0);
-
#ifdef HAVE_GETPRIORITY
/* see Process.setpriority */
rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
diff --git a/ractor.c b/ractor.c
index db2d43e91e..8fb563fa11 100644
--- a/ractor.c
+++ b/ractor.c
@@ -5,22 +5,21 @@
#include "ruby/ractor.h"
#include "ruby/thread_native.h"
#include "vm_core.h"
-#include "eval_intern.h"
#include "vm_sync.h"
#include "ractor_core.h"
#include "internal/complex.h"
#include "internal/error.h"
-#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/rational.h"
#include "internal/struct.h"
#include "internal/thread.h"
#include "variable.h"
+#include "gc.h"
+#include "transient_heap.h"
#include "yjit.h"
-#include "rjit.h"
+#include "mjit.h"
VALUE rb_cRactor;
-static VALUE rb_cRactorSelector;
VALUE rb_eRactorUnsafeError;
VALUE rb_eRactorIsolationError;
@@ -32,13 +31,11 @@ static VALUE rb_cRactorMovedObject;
static void vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *r, const char *file, int line);
-// Ractor locking
-
static void
ASSERT_ractor_unlocking(rb_ractor_t *r)
{
#if RACTOR_CHECK_MODE > 0
- // GET_EC is NULL in an RJIT worker
+ // GET_EC is NULL in an MJIT worker
if (rb_current_execution_context(false) != NULL && r->sync.locked_by == rb_ractor_self(GET_RACTOR())) {
rb_bug("recursive ractor locking");
}
@@ -49,7 +46,7 @@ static void
ASSERT_ractor_locking(rb_ractor_t *r)
{
#if RACTOR_CHECK_MODE > 0
- // GET_EC is NULL in an RJIT worker
+ // GET_EC is NULL in an MJIT worker
if (rb_current_execution_context(false) != NULL && r->sync.locked_by != rb_ractor_self(GET_RACTOR())) {
rp(r->sync.locked_by);
rb_bug("ractor lock is not acquired.");
@@ -60,19 +57,18 @@ ASSERT_ractor_locking(rb_ractor_t *r)
static void
ractor_lock(rb_ractor_t *r, const char *file, int line)
{
- RUBY_DEBUG_LOG2(file, line, "locking r:%u%s", r->pub.id, rb_current_ractor_raw(false) == r ? " (self)" : "");
+ RUBY_DEBUG_LOG2(file, line, "locking r:%u%s", r->pub.id, GET_RACTOR() == r ? " (self)" : "");
ASSERT_ractor_unlocking(r);
rb_native_mutex_lock(&r->sync.lock);
#if RACTOR_CHECK_MODE > 0
- if (rb_current_execution_context(false) != NULL) { // GET_EC is NULL in an RJIT worker
- rb_ractor_t *cr = rb_current_ractor_raw(false);
- r->sync.locked_by = cr ? rb_ractor_self(cr) : Qundef;
+ if (rb_current_execution_context(false) != NULL) { // GET_EC is NULL in an MJIT worker
+ r->sync.locked_by = rb_ractor_self(GET_RACTOR());
}
#endif
- RUBY_DEBUG_LOG2(file, line, "locked r:%u%s", r->pub.id, rb_current_ractor_raw(false) == r ? " (self)" : "");
+ RUBY_DEBUG_LOG2(file, line, "locked r:%u%s", r->pub.id, GET_RACTOR() == r ? " (self)" : "");
}
static void
@@ -94,7 +90,7 @@ ractor_unlock(rb_ractor_t *r, const char *file, int line)
#endif
rb_native_mutex_unlock(&r->sync.lock);
- RUBY_DEBUG_LOG2(file, line, "r:%u%s", r->pub.id, rb_current_ractor_raw(false) == r ? " (self)" : "");
+ RUBY_DEBUG_LOG2(file, line, "r:%u%s", r->pub.id, GET_RACTOR() == r ? " (self)" : "");
}
static void
@@ -112,20 +108,20 @@ ractor_unlock_self(rb_ractor_t *cr, const char *file, int line)
#define RACTOR_LOCK_SELF(r) ractor_lock_self(r, __FILE__, __LINE__)
#define RACTOR_UNLOCK_SELF(r) ractor_unlock_self(r, __FILE__, __LINE__)
-void
-rb_ractor_lock_self(rb_ractor_t *r)
+static void
+ractor_cond_wait(rb_ractor_t *r)
{
- RACTOR_LOCK_SELF(r);
-}
+#if RACTOR_CHECK_MODE > 0
+ VALUE locked_by = r->sync.locked_by;
+ r->sync.locked_by = Qnil;
+#endif
+ rb_native_cond_wait(&r->sync.cond, &r->sync.lock);
-void
-rb_ractor_unlock_self(rb_ractor_t *r)
-{
- RACTOR_UNLOCK_SELF(r);
+#if RACTOR_CHECK_MODE > 0
+ r->sync.locked_by = locked_by;
+#endif
}
-// Ractor status
-
static const char *
ractor_status_str(enum ractor_status status)
{
@@ -162,7 +158,7 @@ ractor_status_set(rb_ractor_t *r, enum ractor_status status)
VM_ASSERT(status == ractor_running);
break;
case ractor_terminated:
- rb_bug("unreachable");
+ VM_ASSERT(0); // unreachable
break;
}
@@ -175,40 +171,31 @@ ractor_status_p(rb_ractor_t *r, enum ractor_status status)
return rb_ractor_status_p(r, status);
}
-// Ractor data/mark/free
-
-static struct rb_ractor_basket *ractor_queue_at(rb_ractor_t *r, struct rb_ractor_queue *rq, int i);
-static void ractor_local_storage_mark(rb_ractor_t *r);
-static void ractor_local_storage_free(rb_ractor_t *r);
+static struct rb_ractor_basket *ractor_queue_at(struct rb_ractor_queue *rq, int i);
static void
ractor_queue_mark(struct rb_ractor_queue *rq)
{
for (int i=0; i<rq->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(NULL, rq, i);
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
+ rb_gc_mark(b->v);
rb_gc_mark(b->sender);
-
- switch (b->type.e) {
- case basket_type_yielding:
- case basket_type_take_basket:
- case basket_type_deleted:
- case basket_type_reserved:
- // ignore
- break;
- default:
- rb_gc_mark(b->p.send.v);
- }
}
}
+static void ractor_local_storage_mark(rb_ractor_t *r);
+static void ractor_local_storage_free(rb_ractor_t *r);
+
static void
ractor_mark(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
- ractor_queue_mark(&r->sync.recv_queue);
- ractor_queue_mark(&r->sync.takers_queue);
-
+ ractor_queue_mark(&r->sync.incoming_queue);
+ rb_gc_mark(r->sync.wait.taken_basket.v);
+ rb_gc_mark(r->sync.wait.taken_basket.sender);
+ rb_gc_mark(r->sync.wait.yielded_basket.v);
+ rb_gc_mark(r->sync.wait.yielded_basket.sender);
rb_gc_mark(r->receiving_mutex);
rb_gc_mark(r->loc);
@@ -236,16 +223,19 @@ ractor_queue_free(struct rb_ractor_queue *rq)
}
static void
+ractor_waiting_list_free(struct rb_ractor_waiting_list *wl)
+{
+ free(wl->ractors);
+}
+
+static void
ractor_free(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
- RUBY_DEBUG_LOG("free r:%d", rb_ractor_id(r));
rb_native_mutex_destroy(&r->sync.lock);
-#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_destroy(&r->sync.cond);
-#endif
- ractor_queue_free(&r->sync.recv_queue);
- ractor_queue_free(&r->sync.takers_queue);
+ ractor_queue_free(&r->sync.incoming_queue);
+ ractor_waiting_list_free(&r->sync.taking_ractors);
ractor_local_storage_free(r);
rb_hook_list_free(&r->pub.hooks);
ruby_xfree(r);
@@ -258,14 +248,20 @@ ractor_queue_memsize(const struct rb_ractor_queue *rq)
}
static size_t
+ractor_waiting_list_memsize(const struct rb_ractor_waiting_list *wl)
+{
+ return sizeof(rb_ractor_t *) * wl->size;
+}
+
+static size_t
ractor_memsize(const void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
- // TODO: more correct?
+ // TODO
return sizeof(rb_ractor_t) +
- ractor_queue_memsize(&r->sync.recv_queue) +
- ractor_queue_memsize(&r->sync.takers_queue);
+ ractor_queue_memsize(&r->sync.incoming_queue) +
+ ractor_waiting_list_memsize(&r->sync.taking_ractors);
}
static const rb_data_type_t ractor_data_type = {
@@ -294,14 +290,16 @@ static inline rb_ractor_t *
RACTOR_PTR(VALUE self)
{
VM_ASSERT(rb_ractor_p(self));
+
rb_ractor_t *r = DATA_PTR(self);
+ // TODO: check
return r;
}
static rb_atomic_t ractor_last_id;
#if RACTOR_CHECK_MODE > 0
-uint32_t
+MJIT_FUNC_EXPORTED uint32_t
rb_ractor_current_id(void)
{
if (GET_THREAD()->ractor == NULL) {
@@ -313,8 +311,6 @@ rb_ractor_current_id(void)
}
#endif
-// Ractor queue
-
static void
ractor_queue_setup(struct rb_ractor_queue *rq)
{
@@ -325,23 +321,15 @@ ractor_queue_setup(struct rb_ractor_queue *rq)
}
static struct rb_ractor_basket *
-ractor_queue_head(rb_ractor_t *r, struct rb_ractor_queue *rq)
-{
- if (r != NULL) ASSERT_ractor_locking(r);
- return &rq->baskets[rq->start];
-}
-
-static struct rb_ractor_basket *
-ractor_queue_at(rb_ractor_t *r, struct rb_ractor_queue *rq, int i)
+ractor_queue_at(struct rb_ractor_queue *rq, int i)
{
- if (r != NULL) ASSERT_ractor_locking(r);
return &rq->baskets[(rq->start + i) % rq->size];
}
static void
-ractor_queue_advance(rb_ractor_t *r, struct rb_ractor_queue *rq)
+ractor_queue_advance(struct rb_ractor_queue *rq)
{
- ASSERT_ractor_locking(r);
+ ASSERT_ractor_locking(GET_RACTOR());
if (rq->reserved_cnt == 0) {
rq->cnt--;
@@ -349,16 +337,16 @@ ractor_queue_advance(rb_ractor_t *r, struct rb_ractor_queue *rq)
rq->serial++;
}
else {
- ractor_queue_at(r, rq, 0)->type.e = basket_type_deleted;
+ ractor_queue_at(rq, 0)->type = basket_type_deleted;
}
}
static bool
-ractor_queue_skip_p(rb_ractor_t *r, struct rb_ractor_queue *rq, int i)
+ractor_queue_skip_p(struct rb_ractor_queue *rq, int i)
{
- struct rb_ractor_basket *b = ractor_queue_at(r, rq, i);
- return basket_type_p(b, basket_type_deleted) ||
- basket_type_p(b, basket_type_reserved);
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
+ return b->type == basket_type_deleted ||
+ b->type == basket_type_reserved;
}
static void
@@ -366,8 +354,8 @@ ractor_queue_compact(rb_ractor_t *r, struct rb_ractor_queue *rq)
{
ASSERT_ractor_locking(r);
- while (rq->cnt > 0 && basket_type_p(ractor_queue_at(r, rq, 0), basket_type_deleted)) {
- ractor_queue_advance(r, rq);
+ while (rq->cnt > 0 && ractor_queue_at(rq, 0)->type == basket_type_deleted) {
+ ractor_queue_advance(rq);
}
}
@@ -383,7 +371,7 @@ ractor_queue_empty_p(rb_ractor_t *r, struct rb_ractor_queue *rq)
ractor_queue_compact(r, rq);
for (int i=0; i<rq->cnt; i++) {
- if (!ractor_queue_skip_p(r, rq, i)) {
+ if (!ractor_queue_skip_p(rq, i)) {
return false;
}
}
@@ -394,21 +382,28 @@ ractor_queue_empty_p(rb_ractor_t *r, struct rb_ractor_queue *rq)
static bool
ractor_queue_deq(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_basket *basket)
{
- ASSERT_ractor_locking(r);
-
- for (int i=0; i<rq->cnt; i++) {
- if (!ractor_queue_skip_p(r, rq, i)) {
- struct rb_ractor_basket *b = ractor_queue_at(r, rq, i);
- *basket = *b;
+ bool found = false;
- // remove from queue
- b->type.e = basket_type_deleted;
- ractor_queue_compact(r, rq);
- return true;
+ RACTOR_LOCK(r);
+ {
+ if (!ractor_queue_empty_p(r, rq)) {
+ for (int i=0; i<rq->cnt; i++) {
+ if (!ractor_queue_skip_p(rq, i)) {
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
+ *basket = *b;
+
+ // remove from queue
+ b->type = basket_type_deleted;
+ ractor_queue_compact(r, rq);
+ found = true;
+ break;
+ }
+ }
}
}
+ RACTOR_UNLOCK(r);
- return false;
+ return found;
}
static void
@@ -428,32 +423,32 @@ ractor_queue_enq(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_ba
}
static void
-ractor_queue_delete(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_basket *basket)
+ractor_basket_clear(struct rb_ractor_basket *b)
{
- basket->type.e = basket_type_deleted;
+ b->type = basket_type_none;
+ b->v = Qfalse;
+ b->sender = Qfalse;
}
-// Ractor basket
-
static VALUE ractor_reset_belonging(VALUE obj); // in this file
static VALUE
ractor_basket_value(struct rb_ractor_basket *b)
{
- switch (b->type.e) {
+ switch (b->type) {
case basket_type_ref:
break;
case basket_type_copy:
case basket_type_move:
case basket_type_will:
- b->type.e = basket_type_ref;
- b->p.send.v = ractor_reset_belonging(b->p.send.v);
+ b->type = basket_type_ref;
+ b->v = ractor_reset_belonging(b->v);
break;
default:
rb_bug("unreachable");
}
- return b->p.send.v;
+ return b->v;
}
static VALUE
@@ -461,69 +456,46 @@ ractor_basket_accept(struct rb_ractor_basket *b)
{
VALUE v = ractor_basket_value(b);
- if (b->p.send.exception) {
+ if (b->exception) {
VALUE cause = v;
VALUE err = rb_exc_new_cstr(rb_eRactorRemoteError, "thrown by remote Ractor.");
rb_ivar_set(err, rb_intern("@ractor"), b->sender);
+ ractor_basket_clear(b);
rb_ec_setup_exception(NULL, err, cause);
rb_exc_raise(err);
}
+ ractor_basket_clear(b);
return v;
}
-// Ractor synchronizations
-
-#if USE_RUBY_DEBUG_LOG
-static const char *
-wait_status_str(enum rb_ractor_wait_status wait_status)
+static void
+ractor_recursive_receive_if(rb_ractor_t *r)
{
- switch ((int)wait_status) {
- case wait_none: return "none";
- case wait_receiving: return "receiving";
- case wait_taking: return "taking";
- case wait_yielding: return "yielding";
- case wait_receiving|wait_taking: return "receiving|taking";
- case wait_receiving|wait_yielding: return "receiving|yielding";
- case wait_taking|wait_yielding: return "taking|yielding";
- case wait_receiving|wait_taking|wait_yielding: return "receiving|taking|yielding";
+ if (r->receiving_mutex && rb_mutex_owned_p(r->receiving_mutex)) {
+ rb_raise(rb_eRactorError, "can not call receive/receive_if recursively");
}
- rb_bug("unreachable");
}
-static const char *
-wakeup_status_str(enum rb_ractor_wakeup_status wakeup_status)
+static VALUE
+ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *r)
{
- switch (wakeup_status) {
- case wakeup_none: return "none";
- case wakeup_by_send: return "by_send";
- case wakeup_by_yield: return "by_yield";
- case wakeup_by_take: return "by_take";
- case wakeup_by_close: return "by_close";
- case wakeup_by_interrupt: return "by_interrupt";
- case wakeup_by_retry: return "by_retry";
+ struct rb_ractor_queue *rq = &r->sync.incoming_queue;
+ struct rb_ractor_basket basket;
+
+ ractor_recursive_receive_if(r);
+
+ if (ractor_queue_deq(r, rq, &basket) == false) {
+ if (r->sync.incoming_port_closed) {
+ rb_raise(rb_eRactorClosedError, "The incoming port is already closed");
+ }
+ else {
+ return Qundef;
+ }
}
- rb_bug("unreachable");
-}
-static const char *
-basket_type_name(enum rb_ractor_basket_type type)
-{
- switch (type) {
- case basket_type_none: return "none";
- case basket_type_ref: return "ref";
- case basket_type_copy: return "copy";
- case basket_type_move: return "move";
- case basket_type_will: return "will";
- case basket_type_deleted: return "deleted";
- case basket_type_reserved: return "reserved";
- case basket_type_take_basket: return "take_basket";
- case basket_type_yielding: return "yielding";
- }
- VM_ASSERT(0);
- return NULL;
+ return ractor_basket_accept(&basket);
}
-#endif // USE_RUBY_DEBUG_LOG
static bool
ractor_sleeping_by(const rb_ractor_t *r, enum rb_ractor_wait_status wait_status)
@@ -531,33 +503,18 @@ ractor_sleeping_by(const rb_ractor_t *r, enum rb_ractor_wait_status wait_status)
return (r->sync.wait.status & wait_status) && r->sync.wait.wakeup_status == wakeup_none;
}
-#ifdef RUBY_THREAD_PTHREAD_H
-// thread_*.c
-void rb_ractor_sched_wakeup(rb_ractor_t *r);
-#else
-
-static void
-rb_ractor_sched_wakeup(rb_ractor_t *r)
-{
- rb_native_cond_broadcast(&r->sync.cond);
-}
-#endif
-
-
static bool
ractor_wakeup(rb_ractor_t *r, enum rb_ractor_wait_status wait_status, enum rb_ractor_wakeup_status wakeup_status)
{
ASSERT_ractor_locking(r);
- RUBY_DEBUG_LOG("r:%u wait_by:%s -> wait:%s wakeup:%s",
- rb_ractor_id(r),
- wait_status_str(r->sync.wait.status),
- wait_status_str(wait_status),
- wakeup_status_str(wakeup_status));
+ // fprintf(stderr, "%s r:%p status:%s/%s wakeup_status:%s/%s\n", RUBY_FUNCTION_NAME_STRING, (void *)r,
+ // wait_status_str(r->sync.wait.status), wait_status_str(wait_status),
+ // wakeup_status_str(r->sync.wait.wakeup_status), wakeup_status_str(wakeup_status));
if (ractor_sleeping_by(r, wait_status)) {
r->sync.wait.wakeup_status = wakeup_status;
- rb_ractor_sched_wakeup(r);
+ rb_native_cond_signal(&r->sync.cond);
return true;
}
else {
@@ -565,6 +522,22 @@ ractor_wakeup(rb_ractor_t *r, enum rb_ractor_wait_status wait_status, enum rb_ra
}
}
+static void *
+ractor_sleep_wo_gvl(void *ptr)
+{
+ rb_ractor_t *cr = ptr;
+ RACTOR_LOCK_SELF(cr);
+ {
+ VM_ASSERT(cr->sync.wait.status != wait_none);
+ if (cr->sync.wait.wakeup_status == wakeup_none) {
+ ractor_cond_wait(cr);
+ }
+ cr->sync.wait.status = wait_none;
+ }
+ RACTOR_UNLOCK_SELF(cr);
+ return NULL;
+}
+
static void
ractor_sleep_interrupt(void *ptr)
{
@@ -577,175 +550,174 @@ ractor_sleep_interrupt(void *ptr)
RACTOR_UNLOCK(r);
}
-typedef void (*ractor_sleep_cleanup_function)(rb_ractor_t *cr, void *p);
-
-static void
-ractor_check_ints(rb_execution_context_t *ec, rb_ractor_t *cr, ractor_sleep_cleanup_function cf_func, void *cf_data)
+#if USE_RUBY_DEBUG_LOG
+static const char *
+wait_status_str(enum rb_ractor_wait_status wait_status)
{
- if (cr->sync.wait.status != wait_none) {
- enum rb_ractor_wait_status prev_wait_status = cr->sync.wait.status;
- cr->sync.wait.status = wait_none;
- cr->sync.wait.wakeup_status = wakeup_by_interrupt;
-
- RACTOR_UNLOCK(cr);
- {
- if (cf_func) {
- int state;
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- rb_thread_check_ints();
- }
- EC_POP_TAG();
-
- if (state) {
- (*cf_func)(cr, cf_data);
- EC_JUMP_TAG(ec, state);
- }
- }
- else {
- rb_thread_check_ints();
- }
- }
-
- // reachable?
- RACTOR_LOCK(cr);
- cr->sync.wait.status = prev_wait_status;
+ switch ((int)wait_status) {
+ case wait_none: return "none";
+ case wait_receiving: return "receiving";
+ case wait_taking: return "taking";
+ case wait_yielding: return "yielding";
+ case wait_receiving|wait_taking: return "receiving|taking";
+ case wait_receiving|wait_yielding: return "receiving|yielding";
+ case wait_taking|wait_yielding: return "taking|yielding";
+ case wait_receiving|wait_taking|wait_yielding: return "receiving|taking|yielding";
}
+ rb_bug("unreachable");
}
-#ifdef RUBY_THREAD_PTHREAD_H
-void rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf);
-#else
-
-// win32
-static void
-ractor_cond_wait(rb_ractor_t *r)
-{
-#if RACTOR_CHECK_MODE > 0
- VALUE locked_by = r->sync.locked_by;
- r->sync.locked_by = Qnil;
-#endif
- rb_native_cond_wait(&r->sync.cond, &r->sync.lock);
-
-#if RACTOR_CHECK_MODE > 0
- r->sync.locked_by = locked_by;
-#endif
-}
-
-static void *
-ractor_sleep_wo_gvl(void *ptr)
+static const char *
+wakeup_status_str(enum rb_ractor_wakeup_status wakeup_status)
{
- rb_ractor_t *cr = ptr;
- RACTOR_LOCK_SELF(cr);
- {
- VM_ASSERT(cr->sync.wait.status != wait_none);
- if (cr->sync.wait.wakeup_status == wakeup_none) {
- ractor_cond_wait(cr);
- }
- cr->sync.wait.status = wait_none;
+ switch (wakeup_status) {
+ case wakeup_none: return "none";
+ case wakeup_by_send: return "by_send";
+ case wakeup_by_yield: return "by_yield";
+ case wakeup_by_take: return "by_take";
+ case wakeup_by_close: return "by_close";
+ case wakeup_by_interrupt: return "by_interrupt";
+ case wakeup_by_retry: return "by_retry";
}
- RACTOR_UNLOCK_SELF(cr);
- return NULL;
+ rb_bug("unreachable");
}
+#endif // USE_RUBY_DEBUG_LOG
static void
-rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf)
+ractor_sleep(rb_execution_context_t *ec, rb_ractor_t *cr)
{
+ VM_ASSERT(GET_RACTOR() == cr);
+ VM_ASSERT(cr->sync.wait.status != wait_none);
+ // fprintf(stderr, "%s r:%p status:%s, wakeup_status:%s\n", RUBY_FUNCTION_NAME_STRING, (void *)cr,
+ // wait_status_str(cr->sync.wait.status), wakeup_status_str(cr->sync.wait.wakeup_status));
+
RACTOR_UNLOCK(cr);
{
rb_nogvl(ractor_sleep_wo_gvl, cr,
- ubf, cr,
+ ractor_sleep_interrupt, cr,
RB_NOGVL_UBF_ASYNC_SAFE | RB_NOGVL_INTR_FAIL);
}
RACTOR_LOCK(cr);
-}
-#endif
-
-static enum rb_ractor_wakeup_status
-ractor_sleep_with_cleanup(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_ractor_wait_status wait_status,
- ractor_sleep_cleanup_function cf_func, void *cf_data)
-{
- enum rb_ractor_wakeup_status wakeup_status;
- VM_ASSERT(GET_RACTOR() == cr);
-
- // TODO: multi-threads
- VM_ASSERT(cr->sync.wait.status == wait_none);
- VM_ASSERT(wait_status != wait_none);
- cr->sync.wait.status = wait_status;
- cr->sync.wait.wakeup_status = wakeup_none;
-
- // fprintf(stderr, "%s r:%p status:%s, wakeup_status:%s\n", RUBY_FUNCTION_NAME_STRING, (void *)cr,
- // wait_status_str(cr->sync.wait.status), wakeup_status_str(cr->sync.wait.wakeup_status));
- RUBY_DEBUG_LOG("sleep by %s", wait_status_str(wait_status));
+ // rb_nogvl() can be canceled by interrupts
+ if (cr->sync.wait.status != wait_none) {
+ cr->sync.wait.status = wait_none;
+ cr->sync.wait.wakeup_status = wakeup_by_interrupt;
- while (cr->sync.wait.wakeup_status == wakeup_none) {
- rb_ractor_sched_sleep(ec, cr, ractor_sleep_interrupt);
- ractor_check_ints(ec, cr, cf_func, cf_data);
+ RACTOR_UNLOCK(cr);
+ rb_thread_check_ints();
+ RACTOR_LOCK(cr); // reachable?
}
+}
- cr->sync.wait.status = wait_none;
+static void
+ractor_register_taking(rb_ractor_t *r, rb_ractor_t *cr)
+{
+ VM_ASSERT(cr == GET_RACTOR());
+ bool retry_try = false;
- // TODO: multi-thread
- wakeup_status = cr->sync.wait.wakeup_status;
- cr->sync.wait.wakeup_status = wakeup_none;
+ RACTOR_LOCK(r);
+ {
+ if (ractor_sleeping_by(r, wait_yielding)) {
+ // already waiting for yielding. retry try_take.
+ retry_try = true;
+ }
+ else {
+ // insert cr into taking list
+ struct rb_ractor_waiting_list *wl = &r->sync.taking_ractors;
+
+ for (int i=0; i<wl->cnt; i++) {
+ if (wl->ractors[i] == cr) {
+ // TODO: make it clean code.
+ rb_native_mutex_unlock(&r->sync.lock);
+ rb_raise(rb_eRuntimeError, "Already another thread of same ractor is waiting.");
+ }
+ }
- RUBY_DEBUG_LOG("wakeup %s", wakeup_status_str(wakeup_status));
+ if (wl->size == 0) {
+ wl->size = 1;
+ wl->ractors = malloc(sizeof(rb_ractor_t *) * wl->size);
+ if (wl->ractors == NULL) rb_bug("can't allocate buffer");
+ }
+ else if (wl->size <= wl->cnt + 1) {
+ wl->size *= 2;
+ wl->ractors = realloc(wl->ractors, sizeof(rb_ractor_t *) * wl->size);
+ if (wl->ractors == NULL) rb_bug("can't re-allocate buffer");
+ }
+ wl->ractors[wl->cnt++] = cr;
+ }
+ }
+ RACTOR_UNLOCK(r);
- return wakeup_status;
-}
+ if (retry_try) {
+ RACTOR_LOCK(cr);
+ {
+ if (cr->sync.wait.wakeup_status == wakeup_none) {
+ VM_ASSERT(cr->sync.wait.status != wait_none);
-static enum rb_ractor_wakeup_status
-ractor_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_ractor_wait_status wait_status)
-{
- return ractor_sleep_with_cleanup(ec, cr, wait_status, 0, NULL);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ cr->sync.wait.status = wait_none;
+ }
+ }
+ RACTOR_UNLOCK(cr);
+ }
}
-// Ractor.receive
-
static void
-ractor_recursive_receive_if(rb_ractor_t *r)
+ractor_waiting_list_del(rb_ractor_t *r, struct rb_ractor_waiting_list *wl, rb_ractor_t *wr)
{
- if (r->receiving_mutex && rb_mutex_owned_p(r->receiving_mutex)) {
- rb_raise(rb_eRactorError, "can not call receive/receive_if recursively");
+ RACTOR_LOCK(r);
+ {
+ int pos = -1;
+ for (int i=0; i<wl->cnt; i++) {
+ if (wl->ractors[i] == wr) {
+ pos = i;
+ break;
+ }
+ }
+ if (pos >= 0) { // found
+ wl->cnt--;
+ for (int i=pos; i<wl->cnt; i++) {
+ wl->ractors[i] = wl->ractors[i+1];
+ }
+ }
}
+ RACTOR_UNLOCK(r);
}
-static VALUE
-ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *rq)
+static rb_ractor_t *
+ractor_waiting_list_shift(rb_ractor_t *r, struct rb_ractor_waiting_list *wl)
{
- struct rb_ractor_basket basket;
- ractor_recursive_receive_if(cr);
- bool received = false;
-
- RACTOR_LOCK_SELF(cr);
- {
- RUBY_DEBUG_LOG("rq->cnt:%d", rq->cnt);
- received = ractor_queue_deq(cr, rq, &basket);
- }
- RACTOR_UNLOCK_SELF(cr);
+ ASSERT_ractor_locking(r);
+ VM_ASSERT(&r->sync.taking_ractors == wl);
- if (!received) {
- if (cr->sync.incoming_port_closed) {
- rb_raise(rb_eRactorClosedError, "The incoming port is already closed");
+ if (wl->cnt > 0) {
+ rb_ractor_t *tr = wl->ractors[0];
+ for (int i=1; i<wl->cnt; i++) {
+ wl->ractors[i-1] = wl->ractors[i];
}
- return Qundef;
+ wl->cnt--;
+ return tr;
}
else {
- return ractor_basket_accept(&basket);
+ return NULL;
}
}
static void
-ractor_wait_receive(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *rq)
+ractor_receive_wait(rb_execution_context_t *ec, rb_ractor_t *cr)
{
VM_ASSERT(cr == rb_ec_ractor_ptr(ec));
ractor_recursive_receive_if(cr);
RACTOR_LOCK(cr);
{
- while (ractor_queue_empty_p(cr, rq)) {
- ractor_sleep(ec, cr, wait_receiving);
+ if (ractor_queue_empty_p(cr, &cr->sync.incoming_queue)) {
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ cr->sync.wait.status = wait_receiving;
+ cr->sync.wait.wakeup_status = wakeup_none;
+ ractor_sleep(ec, cr);
+ cr->sync.wait.wakeup_status = wakeup_none;
}
}
RACTOR_UNLOCK(cr);
@@ -756,25 +728,41 @@ ractor_receive(rb_execution_context_t *ec, rb_ractor_t *cr)
{
VM_ASSERT(cr == rb_ec_ractor_ptr(ec));
VALUE v;
- struct rb_ractor_queue *rq = &cr->sync.recv_queue;
- while (UNDEF_P(v = ractor_try_receive(ec, cr, rq))) {
- ractor_wait_receive(ec, cr, rq);
+ while (UNDEF_P(v = ractor_try_receive(ec, cr))) {
+ ractor_receive_wait(ec, cr);
}
return v;
}
#if 0
+// for debug
+static const char *
+basket_type_name(enum rb_ractor_basket_type type)
+{
+ switch (type) {
+#define T(t) case basket_type_##t: return #t
+ T(none);
+ T(ref);
+ T(copy);
+ T(move);
+ T(will);
+ T(deleted);
+ T(reserved);
+ default: rb_bug("unreachable");
+ }
+}
+
static void
rq_dump(struct rb_ractor_queue *rq)
{
bool bug = false;
for (int i=0; i<rq->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(NULL, rq, i);
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
fprintf(stderr, "%d (start:%d) type:%s %p %s\n", i, rq->start, basket_type_name(b->type),
(void *)b, RSTRING_PTR(RARRAY_AREF(b->v, 1)));
- if (basket_type_p(b, basket_type_reserved) bug = true;
+ if (b->type == basket_type_reserved) bug = true;
}
if (bug) rb_bug("!!");
}
@@ -805,23 +793,22 @@ receive_if_body(VALUE ptr)
ractor_receive_if_lock(data->cr);
VALUE block_result = rb_yield(data->v);
- rb_ractor_t *cr = data->cr;
- RACTOR_LOCK_SELF(cr);
+ RACTOR_LOCK_SELF(data->cr);
{
- struct rb_ractor_basket *b = ractor_queue_at(cr, data->rq, data->index);
- VM_ASSERT(basket_type_p(b, basket_type_reserved));
+ struct rb_ractor_basket *b = ractor_queue_at(data->rq, data->index);
+ VM_ASSERT(b->type == basket_type_reserved);
data->rq->reserved_cnt--;
if (RTEST(block_result)) {
- ractor_queue_delete(cr, data->rq, b);
- ractor_queue_compact(cr, data->rq);
+ b->type = basket_type_deleted;
+ ractor_queue_compact(data->cr, data->rq);
}
else {
- b->type.e = basket_type_ref;
+ b->type = basket_type_ref;
}
}
- RACTOR_UNLOCK_SELF(cr);
+ RACTOR_UNLOCK_SELF(data->cr);
data->success = true;
@@ -837,20 +824,19 @@ static VALUE
receive_if_ensure(VALUE v)
{
struct receive_block_data *data = (struct receive_block_data *)v;
- rb_ractor_t *cr = data->cr;
if (!data->success) {
- RACTOR_LOCK_SELF(cr);
+ RACTOR_LOCK_SELF(data->cr);
{
- struct rb_ractor_basket *b = ractor_queue_at(cr, data->rq, data->index);
- VM_ASSERT(basket_type_p(b, basket_type_reserved));
- b->type.e = basket_type_deleted;
+ struct rb_ractor_basket *b = ractor_queue_at(data->rq, data->index);
+ VM_ASSERT(b->type == basket_type_reserved);
+ b->type = basket_type_deleted;
data->rq->reserved_cnt--;
}
- RACTOR_UNLOCK_SELF(cr);
+ RACTOR_UNLOCK_SELF(data->cr);
}
- rb_mutex_unlock(cr->receiving_mutex);
+ rb_mutex_unlock(data->cr->receiving_mutex);
return Qnil;
}
@@ -862,12 +848,12 @@ ractor_receive_if(rb_execution_context_t *ec, VALUE crv, VALUE b)
rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
unsigned int serial = (unsigned int)-1;
int index = 0;
- struct rb_ractor_queue *rq = &cr->sync.recv_queue;
+ struct rb_ractor_queue *rq = &cr->sync.incoming_queue;
while (1) {
VALUE v = Qundef;
- ractor_wait_receive(ec, cr, rq);
+ ractor_receive_wait(ec, cr);
RACTOR_LOCK_SELF(cr);
{
@@ -878,10 +864,10 @@ ractor_receive_if(rb_execution_context_t *ec, VALUE crv, VALUE b)
// check newer version
for (int i=index; i<rq->cnt; i++) {
- if (!ractor_queue_skip_p(cr, rq, i)) {
- struct rb_ractor_basket *b = ractor_queue_at(cr, rq, i);
+ if (!ractor_queue_skip_p(rq, i)) {
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
v = ractor_basket_value(b);
- b->type.e = basket_type_reserved;
+ b->type = basket_type_reserved;
rq->reserved_cnt++;
index = i;
break;
@@ -914,6 +900,7 @@ static void
ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_basket *b)
{
bool closed = false;
+ struct rb_ractor_queue *rq = &r->sync.incoming_queue;
RACTOR_LOCK(r);
{
@@ -921,8 +908,10 @@ ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_
closed = true;
}
else {
- ractor_queue_enq(r, &r->sync.recv_queue, b);
- ractor_wakeup(r, wait_receiving, wakeup_by_send);
+ ractor_queue_enq(r, rq, b);
+ if (ractor_wakeup(r, wait_receiving, wakeup_by_send)) {
+ RUBY_DEBUG_LOG("wakeup");
+ }
}
}
RACTOR_UNLOCK(r);
@@ -932,844 +921,429 @@ ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_
}
}
-// Ractor#send
-
static VALUE ractor_move(VALUE obj); // in this file
static VALUE ractor_copy(VALUE obj); // in this file
static void
-ractor_basket_prepare_contents(VALUE obj, VALUE move, volatile VALUE *pobj, enum rb_ractor_basket_type *ptype)
+ractor_basket_setup(rb_execution_context_t *ec, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc, bool is_will, bool is_yield)
{
- VALUE v;
- enum rb_ractor_basket_type type;
+ basket->sender = rb_ec_ractor_ptr(ec)->pub.self;
+ basket->exception = exc;
- if (rb_ractor_shareable_p(obj)) {
- type = basket_type_ref;
- v = obj;
+ if (is_will) {
+ basket->type = basket_type_will;
+ basket->v = obj;
+ }
+ else if (rb_ractor_shareable_p(obj)) {
+ basket->type = basket_type_ref;
+ basket->v = obj;
}
else if (!RTEST(move)) {
- v = ractor_copy(obj);
- type = basket_type_copy;
+ basket->v = ractor_copy(obj);
+ basket->type = basket_type_copy;
}
else {
- type = basket_type_move;
- v = ractor_move(obj);
- }
-
- *pobj = v;
- *ptype = type;
-}
-
-static void
-ractor_basket_fill_(rb_ractor_t *cr, struct rb_ractor_basket *basket, VALUE obj, bool exc)
-{
- VM_ASSERT(cr == GET_RACTOR());
+ basket->type = basket_type_move;
- basket->sender = cr->pub.self;
- basket->p.send.exception = exc;
- basket->p.send.v = obj;
-}
-
-static void
-ractor_basket_fill(rb_ractor_t *cr, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc)
-{
- VALUE v;
- enum rb_ractor_basket_type type;
- ractor_basket_prepare_contents(obj, move, &v, &type);
- ractor_basket_fill_(cr, basket, v, exc);
- basket->type.e = type;
-}
-
-static void
-ractor_basket_fill_will(rb_ractor_t *cr, struct rb_ractor_basket *basket, VALUE obj, bool exc)
-{
- ractor_basket_fill_(cr, basket, obj, exc);
- basket->type.e = basket_type_will;
+ if (is_yield) {
+ basket->v = obj; // call ractor_move() when yielding timing.
+ }
+ else {
+ basket->v = ractor_move(obj);
+ }
+ }
}
static VALUE
ractor_send(rb_execution_context_t *ec, rb_ractor_t *r, VALUE obj, VALUE move)
{
struct rb_ractor_basket basket;
- // TODO: Ractor local GC
- ractor_basket_fill(rb_ec_ractor_ptr(ec), &basket, obj, move, false);
+ ractor_basket_setup(ec, &basket, obj, move, false, false, false);
ractor_send_basket(ec, r, &basket);
return r->pub.self;
}
-// Ractor#take
-
-static bool
-ractor_take_has_will(rb_ractor_t *r)
-{
- ASSERT_ractor_locking(r);
-
- return basket_type_p(&r->sync.will_basket, basket_type_will);
-}
-
-static bool
-ractor_take_will(rb_ractor_t *r, struct rb_ractor_basket *b)
-{
- ASSERT_ractor_locking(r);
-
- if (ractor_take_has_will(r)) {
- *b = r->sync.will_basket;
- r->sync.will_basket.type.e = basket_type_none;
- return true;
- }
- else {
- VM_ASSERT(basket_type_p(&r->sync.will_basket, basket_type_none));
- return false;
- }
-}
-
-static bool
-ractor_take_will_lock(rb_ractor_t *r, struct rb_ractor_basket *b)
+static VALUE
+ractor_try_take(rb_execution_context_t *ec, rb_ractor_t *r)
{
- ASSERT_ractor_unlocking(r);
- bool taken;
-
- RACTOR_LOCK(r);
- {
- taken = ractor_take_will(r, b);
- }
- RACTOR_UNLOCK(r);
-
- return taken;
-}
-
-static bool
-ractor_register_take(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *take_basket,
- bool is_take, struct rb_ractor_selector_take_config *config, bool ignore_error)
-{
- struct rb_ractor_basket b = {
- .type.e = basket_type_take_basket,
- .sender = cr->pub.self,
- .p = {
- .take = {
- .basket = take_basket,
- .config = config,
- },
- },
+ struct rb_ractor_basket basket = {
+ .type = basket_type_none,
};
bool closed = false;
RACTOR_LOCK(r);
{
- if (is_take && ractor_take_will(r, take_basket)) {
- RUBY_DEBUG_LOG("take over a will of r:%d", rb_ractor_id(r));
- }
- else if (!is_take && ractor_take_has_will(r)) {
- RUBY_DEBUG_LOG("has_will");
- VM_ASSERT(config != NULL);
- config->closed = true;
+ if (ractor_sleeping_by(r, wait_yielding)) {
+ MAYBE_UNUSED(bool) wakeup_result;
+ VM_ASSERT(r->sync.wait.yielded_basket.type != basket_type_none);
+
+ if (r->sync.wait.yielded_basket.type == basket_type_move) {
+ wakeup_result = ractor_wakeup(r, wait_yielding, wakeup_by_retry);
+ }
+ else {
+ wakeup_result = ractor_wakeup(r, wait_yielding, wakeup_by_take);
+ basket = r->sync.wait.yielded_basket;
+ ractor_basket_clear(&r->sync.wait.yielded_basket);
+ }
+ VM_ASSERT(wakeup_result);
}
else if (r->sync.outgoing_port_closed) {
closed = true;
}
- else {
- RUBY_DEBUG_LOG("register in r:%d", rb_ractor_id(r));
- ractor_queue_enq(r, &r->sync.takers_queue, &b);
-
- if (basket_none_p(take_basket)) {
- ractor_wakeup(r, wait_yielding, wakeup_by_take);
- }
- }
}
RACTOR_UNLOCK(r);
- if (closed) {
- if (!ignore_error) rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
- return false;
- }
- else {
- return true;
- }
-}
-
-static bool
-ractor_deregister_take(rb_ractor_t *r, struct rb_ractor_basket *take_basket)
-{
- struct rb_ractor_queue *ts = &r->sync.takers_queue;
- bool deleted = false;
-
- RACTOR_LOCK(r);
- {
- if (r->sync.outgoing_port_closed) {
- // ok
+ if (basket.type == basket_type_none) {
+ if (closed) {
+ rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
}
else {
- for (int i=0; i<ts->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(r, ts, i);
- if (basket_type_p(b, basket_type_take_basket) && b->p.take.basket == take_basket) {
- ractor_queue_delete(r, ts, b);
- deleted = true;
- }
- }
- if (deleted) {
- ractor_queue_compact(r, ts);
- }
+ return Qundef;
}
}
- RACTOR_UNLOCK(r);
-
- return deleted;
+ else {
+ return ractor_basket_accept(&basket);
+ }
}
static VALUE
-ractor_try_take(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *take_basket)
+ractor_yield_move_body(VALUE v)
{
- bool taken;
-
- RACTOR_LOCK_SELF(cr);
- {
- if (basket_none_p(take_basket) || basket_type_p(take_basket, basket_type_yielding)) {
- taken = false;
- }
- else {
- taken = true;
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-
- if (taken) {
- RUBY_DEBUG_LOG("taken");
- if (basket_type_p(take_basket, basket_type_deleted)) {
- VM_ASSERT(r->sync.outgoing_port_closed);
- rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
- }
- return ractor_basket_accept(take_basket);
- }
- else {
- RUBY_DEBUG_LOG("not taken");
- return Qundef;
- }
+ return ractor_move(v);
}
-
-#if VM_CHECK_MODE > 0
static bool
-ractor_check_specific_take_basket_lock(rb_ractor_t *r, struct rb_ractor_basket *tb)
+ractor_try_yield(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_basket *basket)
{
- bool ret = false;
- struct rb_ractor_queue *ts = &r->sync.takers_queue;
-
- RACTOR_LOCK(r);
- {
- for (int i=0; i<ts->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(r, ts, i);
- if (basket_type_p(b, basket_type_take_basket) && b->p.take.basket == tb) {
- ret = true;
- break;
- }
- }
- }
- RACTOR_UNLOCK(r);
-
- return ret;
-}
-#endif
+ ASSERT_ractor_unlocking(cr);
+ VM_ASSERT(basket->type != basket_type_none);
-static void
-ractor_take_cleanup(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *tb)
-{
- retry:
- if (basket_none_p(tb)) { // not yielded yet
- if (!ractor_deregister_take(r, tb)) {
- // not in r's takers queue
- rb_thread_sleep(0);
- goto retry;
- }
- }
- else {
- VM_ASSERT(!ractor_check_specific_take_basket_lock(r, tb));
+ if (cr->sync.outgoing_port_closed) {
+ rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
}
-}
-struct take_wait_take_cleanup_data {
rb_ractor_t *r;
- struct rb_ractor_basket *tb;
-};
-
-static void
-ractor_wait_take_cleanup(rb_ractor_t *cr, void *ptr)
-{
- struct take_wait_take_cleanup_data *data = (struct take_wait_take_cleanup_data *)ptr;
- ractor_take_cleanup(cr, data->r, data->tb);
-}
-static void
-ractor_wait_take(rb_execution_context_t *ec, rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *take_basket)
-{
- struct take_wait_take_cleanup_data data = {
- .r = r,
- .tb = take_basket,
- };
-
- RACTOR_LOCK_SELF(cr);
+ retry_shift:
+ RACTOR_LOCK(cr);
{
- if (basket_none_p(take_basket) || basket_type_p(take_basket, basket_type_yielding)) {
- ractor_sleep_with_cleanup(ec, cr, wait_taking, ractor_wait_take_cleanup, &data);
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-}
-
-static VALUE
-ractor_take(rb_execution_context_t *ec, rb_ractor_t *r)
-{
- RUBY_DEBUG_LOG("from r:%u", rb_ractor_id(r));
- VALUE v;
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
-
- struct rb_ractor_basket take_basket = {
- .type.e = basket_type_none,
- .sender = 0,
- };
-
- ractor_register_take(cr, r, &take_basket, true, NULL, false);
-
- while (UNDEF_P(v = ractor_try_take(cr, r, &take_basket))) {
- ractor_wait_take(ec, cr, r, &take_basket);
- }
-
- VM_ASSERT(!basket_none_p(&take_basket));
- VM_ASSERT(!ractor_check_specific_take_basket_lock(r, &take_basket));
-
- return v;
-}
-
-// Ractor.yield
-
-static bool
-ractor_check_take_basket(rb_ractor_t *cr, struct rb_ractor_queue *rs)
-{
- ASSERT_ractor_locking(cr);
-
- for (int i=0; i<rs->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(cr, rs, i);
- if (basket_type_p(b, basket_type_take_basket) &&
- basket_none_p(b->p.take.basket)) {
- return true;
- }
+ r = ractor_waiting_list_shift(cr, &cr->sync.taking_ractors);
}
+ RACTOR_UNLOCK(cr);
- return false;
-}
-
-static bool
-ractor_deq_take_basket(rb_ractor_t *cr, struct rb_ractor_queue *rs, struct rb_ractor_basket *b)
-{
- ASSERT_ractor_unlocking(cr);
- struct rb_ractor_basket *first_tb = NULL;
- bool found = false;
+ if (r) {
+ bool retry_shift = false;
- RACTOR_LOCK_SELF(cr);
- {
- while (ractor_queue_deq(cr, rs, b)) {
- if (basket_type_p(b, basket_type_take_basket)) {
- struct rb_ractor_basket *tb = b->p.take.basket;
+ RACTOR_LOCK(r);
+ {
+ if (ractor_sleeping_by(r, wait_taking)) {
+ VM_ASSERT(r->sync.wait.taken_basket.type == basket_type_none);
+
+ if (basket->type == basket_type_move) {
+ enum rb_ractor_wait_status prev_wait_status = r->sync.wait.status;
+ r->sync.wait.status = wait_moving;
+
+ RACTOR_UNLOCK(r);
+ {
+ int state;
+ VALUE moved_value = rb_protect(ractor_yield_move_body, basket->v, &state);
+ if (state) {
+ r->sync.wait.status = prev_wait_status;
+ rb_jump_tag(state);
+ }
+ else {
+ basket->v = moved_value;
+ }
+ }
+ RACTOR_LOCK(r);
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_yielding) == basket_type_none) {
- found = true;
- break;
+ if (!ractor_wakeup(r, wait_moving, wakeup_by_yield)) {
+ // terminating?
+ }
}
else {
- ractor_queue_enq(cr, rs, b);
- if (first_tb == NULL) first_tb = tb;
- struct rb_ractor_basket *head = ractor_queue_head(cr, rs);
- VM_ASSERT(head != NULL);
- if (basket_type_p(head, basket_type_take_basket) && head->p.take.basket == first_tb) {
- break; // loop detected
- }
+ ractor_wakeup(r, wait_taking, wakeup_by_yield);
}
+ r->sync.wait.taken_basket = *basket;
}
else {
- VM_ASSERT(basket_none_p(b));
+ retry_shift = true;
}
}
+ RACTOR_UNLOCK(r);
- if (found && b->p.take.config && !b->p.take.config->oneshot) {
- ractor_queue_enq(cr, rs, b);
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-
- return found;
-}
-
-static bool
-ractor_try_yield(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *ts, volatile VALUE obj, VALUE move, bool exc, bool is_will)
-{
- ASSERT_ractor_unlocking(cr);
-
- struct rb_ractor_basket b;
-
- if (ractor_deq_take_basket(cr, ts, &b)) {
- VM_ASSERT(basket_type_p(&b, basket_type_take_basket));
- VM_ASSERT(basket_type_p(b.p.take.basket, basket_type_yielding));
-
- rb_ractor_t *tr = RACTOR_PTR(b.sender);
- struct rb_ractor_basket *tb = b.p.take.basket;
- enum rb_ractor_basket_type type;
-
- RUBY_DEBUG_LOG("basket from r:%u", rb_ractor_id(tr));
-
- if (is_will) {
- type = basket_type_will;
+ if (retry_shift) {
+ // get candidate take-waiting ractor, but already woke up by another reason.
+ // retry to check another ractor.
+ goto retry_shift;
}
else {
- int state;
-
- // begin
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- // TODO: Ractor local GC
- ractor_basket_prepare_contents(obj, move, &obj, &type);
- }
- EC_POP_TAG();
- // rescue
- if (state) {
- RACTOR_LOCK_SELF(cr);
- {
- b.p.take.basket->type.e = basket_type_none;
- ractor_queue_enq(cr, ts, &b);
- }
- RACTOR_UNLOCK_SELF(cr);
- EC_JUMP_TAG(ec, state);
- }
- }
-
- RACTOR_LOCK(tr);
- {
- VM_ASSERT(basket_type_p(tb, basket_type_yielding));
- // fill atomic
- RUBY_DEBUG_LOG("fill %sbasket from r:%u", is_will ? "will " : "", rb_ractor_id(tr));
- ractor_basket_fill_(cr, tb, obj, exc);
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_yielding, type) != basket_type_yielding) {
- rb_bug("unreachable");
- }
- ractor_wakeup(tr, wait_taking, wakeup_by_yield);
+ return true;
}
- RACTOR_UNLOCK(tr);
-
- return true;
}
else {
- RUBY_DEBUG_LOG("no take basket");
return false;
}
}
-static void
-ractor_wait_yield(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *ts)
-{
- RACTOR_LOCK_SELF(cr);
- {
- while (!ractor_check_take_basket(cr, ts)) {
- ractor_sleep(ec, cr, wait_yielding);
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-}
-
+// select(r1, r2, r3, receive: true, yield: obj)
static VALUE
-ractor_yield(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE obj, VALUE move)
-{
- struct rb_ractor_queue *ts = &cr->sync.takers_queue;
-
- while (!ractor_try_yield(ec, cr, ts, obj, move, false, false)) {
- ractor_wait_yield(ec, cr, ts);
- }
-
- return Qnil;
-}
-
-// Ractor::Selector
-
-struct rb_ractor_selector {
- rb_ractor_t *r;
- struct rb_ractor_basket take_basket;
- st_table *take_ractors; // rb_ractor_t * => (struct rb_ractor_selector_take_config *)
-};
-
-static int
-ractor_selector_mark_ractors_i(st_data_t key, st_data_t value, st_data_t data)
-{
- const rb_ractor_t *r = (rb_ractor_t *)key;
- rb_gc_mark(r->pub.self);
- return ST_CONTINUE;
-}
-
-static void
-ractor_selector_mark(void *ptr)
-{
- struct rb_ractor_selector *s = ptr;
-
- if (s->take_ractors) {
- st_foreach(s->take_ractors, ractor_selector_mark_ractors_i, 0);
- }
-
- switch (s->take_basket.type.e) {
- case basket_type_ref:
- case basket_type_copy:
- case basket_type_move:
- case basket_type_will:
- rb_gc_mark(s->take_basket.sender);
- rb_gc_mark(s->take_basket.p.send.v);
- break;
- default:
- break;
- }
-}
-
-static int
-ractor_selector_release_i(st_data_t key, st_data_t val, st_data_t data)
-{
- struct rb_ractor_selector *s = (struct rb_ractor_selector *)data;
- struct rb_ractor_selector_take_config *config = (struct rb_ractor_selector_take_config *)val;
-
- if (!config->closed) {
- ractor_deregister_take((rb_ractor_t *)key, &s->take_basket);
- }
- free(config);
- return ST_CONTINUE;
-}
-
-static void
-ractor_selector_free(void *ptr)
+ractor_select(rb_execution_context_t *ec, const VALUE *rs, const int rs_len, VALUE yielded_value, bool move, VALUE *ret_r)
{
- struct rb_ractor_selector *s = ptr;
- st_foreach(s->take_ractors, ractor_selector_release_i, (st_data_t)s);
- st_free_table(s->take_ractors);
- ruby_xfree(ptr);
-}
-
-static size_t
-ractor_selector_memsize(const void *ptr)
-{
- const struct rb_ractor_selector *s = ptr;
- return sizeof(struct rb_ractor_selector) +
- st_memsize(s->take_ractors) +
- s->take_ractors->num_entries * sizeof(struct rb_ractor_selector_take_config);
-}
-
-static const rb_data_type_t ractor_selector_data_type = {
- "ractor/selector",
- {
- ractor_selector_mark,
- ractor_selector_free,
- ractor_selector_memsize,
- NULL, // update
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
-};
-
-static struct rb_ractor_selector *
-RACTOR_SELECTOR_PTR(VALUE selv)
-{
- VM_ASSERT(rb_typeddata_is_kind_of(selv, &ractor_selector_data_type));
-
- return (struct rb_ractor_selector *)DATA_PTR(selv);
-}
-
-// Ractor::Selector.new
-
-static VALUE
-ractor_selector_create(VALUE crv)
-{
- struct rb_ractor_selector *s;
- VALUE selv = TypedData_Make_Struct(rb_cRactorSelector, struct rb_ractor_selector, &ractor_selector_data_type, s);
- s->take_basket.type.e = basket_type_reserved;
- s->take_ractors = st_init_numtable(); // ractor (ptr) -> take_config
- return selv;
-}
-
-// Ractor::Selector#add(r)
-
-static VALUE
-ractor_selector_add(rb_execution_context_t *ec, VALUE selv, VALUE rv)
-{
- if (!rb_ractor_p(rv)) {
- rb_raise(rb_eArgError, "Not a ractor object");
- }
-
- rb_ractor_t *r = RACTOR_PTR(rv);
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
-
- if (st_lookup(s->take_ractors, (st_data_t)r, NULL)) {
- rb_raise(rb_eArgError, "already added");
- }
-
- struct rb_ractor_selector_take_config *config = malloc(sizeof(struct rb_ractor_selector_take_config));
- VM_ASSERT(config != NULL);
- config->closed = false;
- config->oneshot = false;
-
- if (ractor_register_take(rb_ec_ractor_ptr(ec), r, &s->take_basket, false, config, true)) {
- st_insert(s->take_ractors, (st_data_t)r, (st_data_t)config);
- }
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VALUE crv = cr->pub.self;
+ VALUE ret = Qundef;
+ int i;
+ bool interrupted = false;
+ enum rb_ractor_wait_status wait_status = 0;
+ bool yield_p = !UNDEF_P(yielded_value) ? true : false;
+ const int alen = rs_len + (yield_p ? 1 : 0);
+
+ struct ractor_select_action {
+ enum ractor_select_action_type {
+ ractor_select_action_take,
+ ractor_select_action_receive,
+ ractor_select_action_yield,
+ } type;
+ VALUE v;
+ } *actions = ALLOCA_N(struct ractor_select_action, alen);
- return rv;
-}
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ VM_ASSERT(cr->sync.wait.wakeup_status == wakeup_none);
+ VM_ASSERT(cr->sync.wait.taken_basket.type == basket_type_none);
+ VM_ASSERT(cr->sync.wait.yielded_basket.type == basket_type_none);
-// Ractor::Selector#remove(r)
+ // setup actions
+ for (i=0; i<rs_len; i++) {
+ VALUE v = rs[i];
-static VALUE
-ractor_selector_remove(rb_execution_context_t *ec, VALUE selv, VALUE rv)
-{
- if (!rb_ractor_p(rv)) {
- rb_raise(rb_eArgError, "Not a ractor object");
+ if (v == crv) {
+ actions[i].type = ractor_select_action_receive;
+ actions[i].v = Qnil;
+ wait_status |= wait_receiving;
+ }
+ else if (rb_ractor_p(v)) {
+ actions[i].type = ractor_select_action_take;
+ actions[i].v = v;
+ wait_status |= wait_taking;
+ }
+ else {
+ rb_raise(rb_eArgError, "should be a ractor object, but %"PRIsVALUE, v);
+ }
}
+ rs = NULL;
- rb_ractor_t *r = RACTOR_PTR(rv);
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
-
- RUBY_DEBUG_LOG("r:%u", rb_ractor_id(r));
+ restart:
- if (!st_lookup(s->take_ractors, (st_data_t)r, NULL)) {
- rb_raise(rb_eArgError, "not added yet");
+ if (yield_p) {
+ actions[rs_len].type = ractor_select_action_yield;
+ actions[rs_len].v = Qundef;
+ wait_status |= wait_yielding;
+ ractor_basket_setup(ec, &cr->sync.wait.yielded_basket, yielded_value, move, false, false, true);
}
- ractor_deregister_take(r, &s->take_basket);
- struct rb_ractor_selector_take_config *config;
- st_delete(s->take_ractors, (st_data_t *)&r, (st_data_t *)&config);
- free(config);
-
- return rv;
-}
-
-// Ractor::Selector#clear
-
-struct ractor_selector_clear_data {
- VALUE selv;
- rb_execution_context_t *ec;
-};
-
-static int
-ractor_selector_clear_i(st_data_t key, st_data_t val, st_data_t data)
-{
- struct ractor_selector_clear_data *ptr = (struct ractor_selector_clear_data *)data;
- rb_ractor_t *r = (rb_ractor_t *)key;
- ractor_selector_remove(ptr->ec, ptr->selv, r->pub.self);
- return ST_CONTINUE;
-}
-
-static VALUE
-ractor_selector_clear(rb_execution_context_t *ec, VALUE selv)
-{
- struct ractor_selector_clear_data data = {
- .selv = selv,
- .ec = ec,
- };
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
-
- st_foreach(s->take_ractors, ractor_selector_clear_i, (st_data_t)&data);
- st_clear(s->take_ractors);
- return selv;
-}
-
-static VALUE
-ractor_selector_empty_p(rb_execution_context_t *ec, VALUE selv)
-{
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
- return s->take_ractors->num_entries == 0 ? Qtrue : Qfalse;
-}
+ // TODO: shuffle actions
-static int
-ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t dat)
-{
- rb_ractor_t *r = (rb_ractor_t *)key;
- struct rb_ractor_basket *tb = (struct rb_ractor_basket *)dat;
- int ret;
+ while (1) {
+ RUBY_DEBUG_LOG("try actions (%s)", wait_status_str(wait_status));
+
+ for (i=0; i<alen; i++) {
+ VALUE v, rv;
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ rv = actions[i].v;
+ v = ractor_try_take(ec, RACTOR_PTR(rv));
+ if (!UNDEF_P(v)) {
+ *ret_r = rv;
+ ret = v;
+ goto cleanup;
+ }
+ break;
+ case ractor_select_action_receive:
+ v = ractor_try_receive(ec, cr);
+ if (!UNDEF_P(v)) {
+ *ret_r = ID2SYM(rb_intern("receive"));
+ ret = v;
+ goto cleanup;
+ }
+ break;
+ case ractor_select_action_yield:
+ {
+ if (ractor_try_yield(ec, cr, &cr->sync.wait.yielded_basket)) {
+ *ret_r = ID2SYM(rb_intern("yield"));
+ ret = Qnil;
+ goto cleanup;
+ }
+ }
+ break;
+ }
+ }
- if (!basket_none_p(tb)) {
- RUBY_DEBUG_LOG("already taken:%s", basket_type_name(tb->type.e));
- return ST_STOP;
- }
+ RUBY_DEBUG_LOG("wait actions (%s)", wait_status_str(wait_status));
- RACTOR_LOCK(r);
- {
- if (basket_type_p(&r->sync.will_basket, basket_type_will)) {
- RUBY_DEBUG_LOG("r:%u has will", rb_ractor_id(r));
+ RACTOR_LOCK(cr);
+ {
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ cr->sync.wait.status = wait_status;
+ cr->sync.wait.wakeup_status = wakeup_none;
+ }
+ RACTOR_UNLOCK(cr);
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_will) == basket_type_none) {
- ractor_take_will(r, tb);
- ret = ST_STOP;
- }
- else {
- RUBY_DEBUG_LOG("has will, but already taken (%s)", basket_type_name(tb->type.e));
- ret = ST_CONTINUE;
+ // prepare waiting
+ for (i=0; i<alen; i++) {
+ rb_ractor_t *r;
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ r = RACTOR_PTR(actions[i].v);
+ ractor_register_taking(r, cr);
+ break;
+ case ractor_select_action_yield:
+ case ractor_select_action_receive:
+ break;
}
}
- else if (r->sync.outgoing_port_closed) {
- RUBY_DEBUG_LOG("r:%u is closed", rb_ractor_id(r));
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_deleted) == basket_type_none) {
- tb->sender = r->pub.self;
- ret = ST_STOP;
+ // wait
+ RACTOR_LOCK(cr);
+ {
+ if (cr->sync.wait.wakeup_status == wakeup_none) {
+ for (i=0; i<alen; i++) {
+ rb_ractor_t *r;
+
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ r = RACTOR_PTR(actions[i].v);
+ if (ractor_sleeping_by(r, wait_yielding)) {
+ RUBY_DEBUG_LOG("wakeup_none, but r:%u is waiting for yielding", r->pub.id);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ goto skip_sleep;
+ }
+ break;
+ case ractor_select_action_receive:
+ if (cr->sync.incoming_queue.cnt > 0) {
+ RUBY_DEBUG_LOG("wakeup_none, but incoming_queue has %u messages", cr->sync.incoming_queue.cnt);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ goto skip_sleep;
+ }
+ break;
+ case ractor_select_action_yield:
+ if (cr->sync.taking_ractors.cnt > 0) {
+ RUBY_DEBUG_LOG("wakeup_none, but %u taking_ractors are waiting", cr->sync.taking_ractors.cnt);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ goto skip_sleep;
+ }
+ else if (cr->sync.outgoing_port_closed) {
+ cr->sync.wait.wakeup_status = wakeup_by_close;
+ goto skip_sleep;
+ }
+ break;
+ }
+ }
+
+ RUBY_DEBUG_LOG("sleep %s", wait_status_str(cr->sync.wait.status));
+ ractor_sleep(ec, cr);
+ RUBY_DEBUG_LOG("awaken %s", wakeup_status_str(cr->sync.wait.wakeup_status));
}
else {
- RUBY_DEBUG_LOG("closed, but already taken (%s)", basket_type_name(tb->type.e));
- ret = ST_CONTINUE;
+ skip_sleep:
+ RUBY_DEBUG_LOG("no need to sleep %s->%s",
+ wait_status_str(cr->sync.wait.status),
+ wakeup_status_str(cr->sync.wait.wakeup_status));
+ cr->sync.wait.status = wait_none;
}
}
- else {
- RUBY_DEBUG_LOG("wakeup r:%u", rb_ractor_id(r));
- ractor_wakeup(r, wait_yielding, wakeup_by_take);
- ret = ST_CONTINUE;
- }
- }
- RACTOR_UNLOCK(r);
-
- return ret;
-}
-
-// Ractor::Selector#wait
-
-static void
-ractor_selector_wait_cleaup(rb_ractor_t *cr, void *ptr)
-{
- struct rb_ractor_basket *tb = (struct rb_ractor_basket *)ptr;
-
- RACTOR_LOCK_SELF(cr);
- {
- while (basket_type_p(tb, basket_type_yielding)) rb_thread_sleep(0);
- // if tb->type is not none, taking is succeeded, but interruption ignore it unfortunately.
- tb->type.e = basket_type_reserved;
- }
- RACTOR_UNLOCK_SELF(cr);
-}
-
-static VALUE
-ractor_selector_wait(rb_execution_context_t *ec, VALUE selv, VALUE do_receivev, VALUE do_yieldv, VALUE yield_value, VALUE move)
-{
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
- struct rb_ractor_basket *tb = &s->take_basket;
- struct rb_ractor_basket taken_basket;
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
- bool do_receive = !!RTEST(do_receivev);
- bool do_yield = !!RTEST(do_yieldv);
- VALUE ret_v, ret_r;
- enum rb_ractor_wait_status wait_status;
- struct rb_ractor_queue *rq = &cr->sync.recv_queue;
- struct rb_ractor_queue *ts = &cr->sync.takers_queue;
-
- RUBY_DEBUG_LOG("start");
-
- retry:
- RUBY_DEBUG_LOG("takers:%ld", s->take_ractors->num_entries);
-
- // setup wait_status
- wait_status = wait_none;
- if (s->take_ractors->num_entries > 0) wait_status |= wait_taking;
- if (do_receive) wait_status |= wait_receiving;
- if (do_yield) wait_status |= wait_yielding;
-
- RUBY_DEBUG_LOG("wait:%s", wait_status_str(wait_status));
-
- if (wait_status == wait_none) {
- rb_raise(rb_eRactorError, "no taking ractors");
- }
-
- // check recv_queue
- if (do_receive && (ret_v = ractor_try_receive(ec, cr, rq)) != Qundef) {
- ret_r = ID2SYM(rb_intern("receive"));
- goto success;
- }
-
- // check takers
- if (do_yield && ractor_try_yield(ec, cr, ts, yield_value, move, false, false)) {
- ret_v = Qnil;
- ret_r = ID2SYM(rb_intern("yield"));
- goto success;
- }
-
- // check take_basket
- VM_ASSERT(basket_type_p(&s->take_basket, basket_type_reserved));
- s->take_basket.type.e = basket_type_none;
- // kick all take target ractors
- st_foreach(s->take_ractors, ractor_selector_wait_i, (st_data_t)tb);
+ RACTOR_UNLOCK(cr);
- RACTOR_LOCK_SELF(cr);
- {
- retry_waiting:
- while (1) {
- if (!basket_none_p(tb)) {
- RUBY_DEBUG_LOG("taken:%s from r:%u", basket_type_name(tb->type.e),
- tb->sender ? rb_ractor_id(RACTOR_PTR(tb->sender)) : 0);
+ // cleanup waiting
+ for (i=0; i<alen; i++) {
+ rb_ractor_t *r;
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ r = RACTOR_PTR(actions[i].v);
+ ractor_waiting_list_del(r, &r->sync.taking_ractors, cr);
break;
- }
- if (do_receive && !ractor_queue_empty_p(cr, rq)) {
- RUBY_DEBUG_LOG("can receive (%d)", rq->cnt);
- break;
- }
- if (do_yield && ractor_check_take_basket(cr, ts)) {
- RUBY_DEBUG_LOG("can yield");
+ case ractor_select_action_receive:
+ case ractor_select_action_yield:
break;
}
-
- ractor_sleep_with_cleanup(ec, cr, wait_status, ractor_selector_wait_cleaup, tb);
}
- taken_basket = *tb;
-
- // ensure
- // tb->type.e = basket_type_reserved # do it atomic in the following code
- if (taken_basket.type.e == basket_type_yielding ||
- RUBY_ATOMIC_CAS(tb->type.atomic, taken_basket.type.e, basket_type_reserved) != taken_basket.type.e) {
+ // check results
+ enum rb_ractor_wakeup_status wakeup_status = cr->sync.wait.wakeup_status;
+ cr->sync.wait.wakeup_status = wakeup_none;
- if (basket_type_p(tb, basket_type_yielding)) {
- RACTOR_UNLOCK_SELF(cr);
- {
- rb_thread_sleep(0);
- }
- RACTOR_LOCK_SELF(cr);
- }
- goto retry_waiting;
+ switch (wakeup_status) {
+ case wakeup_none:
+ // OK. something happens.
+ // retry loop.
+ break;
+ case wakeup_by_retry:
+ // Retry request.
+ break;
+ case wakeup_by_send:
+ // OK.
+ // retry loop and try_receive will succss.
+ break;
+ case wakeup_by_yield:
+ // take was succeeded!
+ // cr.wait.taken_basket contains passed block
+ VM_ASSERT(cr->sync.wait.taken_basket.type != basket_type_none);
+ *ret_r = cr->sync.wait.taken_basket.sender;
+ VM_ASSERT(rb_ractor_p(*ret_r));
+ ret = ractor_basket_accept(&cr->sync.wait.taken_basket);
+ goto cleanup;
+ case wakeup_by_take:
+ *ret_r = ID2SYM(rb_intern("yield"));
+ ret = Qnil;
+ goto cleanup;
+ case wakeup_by_close:
+ // OK.
+ // retry loop and will get CloseError.
+ break;
+ case wakeup_by_interrupt:
+ ret = Qundef;
+ interrupted = true;
+ goto cleanup;
}
}
- RACTOR_UNLOCK_SELF(cr);
- // check the taken resutl
- switch (taken_basket.type.e) {
- case basket_type_none:
- VM_ASSERT(do_receive || do_yield);
- goto retry;
- case basket_type_yielding:
- rb_bug("unreachable");
- case basket_type_deleted: {
- ractor_selector_remove(ec, selv, taken_basket.sender);
-
- rb_ractor_t *r = RACTOR_PTR(taken_basket.sender);
- if (ractor_take_will_lock(r, &taken_basket)) {
- RUBY_DEBUG_LOG("has_will");
- }
- else {
- RUBY_DEBUG_LOG("no will");
- // rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
- // remove and retry wait
- goto retry;
- }
- break;
- }
- case basket_type_will:
- // no more messages
- ractor_selector_remove(ec, selv, taken_basket.sender);
- break;
- default:
- break;
+ cleanup:
+ RUBY_DEBUG_LOG("cleanup actions (%s)", wait_status_str(wait_status));
+
+ if (cr->sync.wait.yielded_basket.type != basket_type_none) {
+ ractor_basket_clear(&cr->sync.wait.yielded_basket);
+ }
+
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ VM_ASSERT(cr->sync.wait.wakeup_status == wakeup_none);
+ VM_ASSERT(cr->sync.wait.taken_basket.type == basket_type_none);
+ VM_ASSERT(cr->sync.wait.yielded_basket.type == basket_type_none);
+
+ if (interrupted) {
+ rb_vm_check_ints_blocking(ec);
+ interrupted = false;
+ goto restart;
}
- RUBY_DEBUG_LOG("taken_basket:%s", basket_type_name(taken_basket.type.e));
+ VM_ASSERT(!UNDEF_P(ret));
+ return ret;
+}
- ret_v = ractor_basket_accept(&taken_basket);
- ret_r = taken_basket.sender;
- success:
- return rb_ary_new_from_args(2, ret_r, ret_v);
+static VALUE
+ractor_yield(rb_execution_context_t *ec, rb_ractor_t *r, VALUE obj, VALUE move)
+{
+ VALUE ret_r;
+ ractor_select(ec, NULL, 0, obj, RTEST(move) ? true : false, &ret_r);
+ return Qnil;
}
-// Ractor#close_incoming
+static VALUE
+ractor_take(rb_execution_context_t *ec, rb_ractor_t *r)
+{
+ VALUE ret_r;
+ VALUE v = ractor_select(ec, &r->pub.self, 1, Qundef, false, &ret_r);
+ return v;
+}
static VALUE
ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
@@ -1782,7 +1356,7 @@ ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
prev = Qfalse;
r->sync.incoming_port_closed = true;
if (ractor_wakeup(r, wait_receiving, wakeup_by_close)) {
- VM_ASSERT(ractor_queue_empty_p(r, &r->sync.recv_queue));
+ VM_ASSERT(r->sync.incoming_queue.cnt == 0);
RUBY_DEBUG_LOG("cancel receiving");
}
}
@@ -1794,8 +1368,6 @@ ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
return prev;
}
-// Ractor#close_outgoing
-
static VALUE
ractor_close_outgoing(rb_execution_context_t *ec, rb_ractor_t *r)
{
@@ -1803,50 +1375,27 @@ ractor_close_outgoing(rb_execution_context_t *ec, rb_ractor_t *r)
RACTOR_LOCK(r);
{
- struct rb_ractor_queue *ts = &r->sync.takers_queue;
- rb_ractor_t *tr;
- struct rb_ractor_basket b;
-
if (!r->sync.outgoing_port_closed) {
prev = Qfalse;
r->sync.outgoing_port_closed = true;
}
else {
- VM_ASSERT(ractor_queue_empty_p(r, ts));
prev = Qtrue;
}
// wakeup all taking ractors
- while (ractor_queue_deq(r, ts, &b)) {
- if (basket_type_p(&b, basket_type_take_basket)) {
- tr = RACTOR_PTR(b.sender);
- struct rb_ractor_basket *tb = b.p.take.basket;
-
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_yielding) == basket_type_none) {
- b.p.take.basket->sender = r->pub.self;
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_yielding, basket_type_deleted) != basket_type_yielding) {
- rb_bug("unreachable");
- }
- RUBY_DEBUG_LOG("set delete for r:%u", rb_ractor_id(RACTOR_PTR(b.sender)));
- }
-
- if (b.p.take.config) {
- b.p.take.config->closed = true;
- }
-
- // TODO: deadlock-able?
- RACTOR_LOCK(tr);
- {
- ractor_wakeup(tr, wait_taking, wakeup_by_close);
- }
- RACTOR_UNLOCK(tr);
- }
+ rb_ractor_t *taking_ractor;
+ while ((taking_ractor = ractor_waiting_list_shift(r, &r->sync.taking_ractors)) != NULL) {
+ RACTOR_LOCK(taking_ractor);
+ ractor_wakeup(taking_ractor, wait_taking, wakeup_by_close);
+ RACTOR_UNLOCK(taking_ractor);
}
// raising yielding Ractor
- ractor_wakeup(r, wait_yielding, wakeup_by_close);
-
- VM_ASSERT(ractor_queue_empty_p(r, ts));
+ if (!r->yield_atexit &&
+ ractor_wakeup(r, wait_yielding, wakeup_by_close)) {
+ RUBY_DEBUG_LOG("cancel yielding");
+ }
}
RACTOR_UNLOCK(r);
return prev;
@@ -1883,6 +1432,7 @@ cancel_single_ractor_mode(void)
VALUE was_disabled = rb_gc_enable();
rb_gc_start();
+ rb_transient_heap_evacuate();
if (was_disabled) {
rb_gc_disable();
@@ -1994,7 +1544,7 @@ rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th)
}
#endif
-void rb_thread_sched_init(struct rb_thread_sched *, bool atfork);
+void rb_thread_sched_init(struct rb_thread_sched *);
void
rb_ractor_living_threads_init(rb_ractor_t *r)
@@ -2007,18 +1557,13 @@ rb_ractor_living_threads_init(rb_ractor_t *r)
static void
ractor_init(rb_ractor_t *r, VALUE name, VALUE loc)
{
- ractor_queue_setup(&r->sync.recv_queue);
- ractor_queue_setup(&r->sync.takers_queue);
+ ractor_queue_setup(&r->sync.incoming_queue);
rb_native_mutex_initialize(&r->sync.lock);
- rb_native_cond_initialize(&r->barrier_wait_cond);
-
-#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_initialize(&r->sync.cond);
rb_native_cond_initialize(&r->barrier_wait_cond);
-#endif
// thread management
- rb_thread_sched_init(&r->threads.sched, false);
+ rb_thread_sched_init(&r->threads.sched);
rb_ractor_living_threads_init(r);
// naming
@@ -2062,7 +1607,7 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
r->debug = cr->debug;
rb_yjit_before_ractor_spawn();
- rb_rjit_before_ractor_spawn();
+ rb_mjit_before_ractor_spawn();
rb_thread_create_ractor(r, args, block);
RB_GC_GUARD(rv);
@@ -2078,23 +1623,28 @@ ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool e
ASSERT_ractor_unlocking(cr);
- struct rb_ractor_queue *ts = &cr->sync.takers_queue;
+ struct rb_ractor_basket basket;
+ ractor_basket_setup(ec, &basket, v, Qfalse, exc, true, true /* this flag is ignored because move is Qfalse */);
retry:
- if (ractor_try_yield(ec, cr, ts, v, Qfalse, exc, true)) {
+ if (ractor_try_yield(ec, cr, &basket)) {
// OK.
}
else {
bool retry = false;
RACTOR_LOCK(cr);
{
- if (!ractor_check_take_basket(cr, ts)) {
+ if (cr->sync.taking_ractors.cnt == 0) {
+ cr->sync.wait.yielded_basket = basket;
+
VM_ASSERT(cr->sync.wait.status == wait_none);
- RUBY_DEBUG_LOG("leave a will");
- ractor_basket_fill_will(cr, &cr->sync.will_basket, v, exc);
+ cr->sync.wait.status = wait_yielding;
+ cr->sync.wait.wakeup_status = wakeup_none;
+
+ VM_ASSERT(cr->yield_atexit == false);
+ cr->yield_atexit = true;
}
else {
- RUBY_DEBUG_LOG("rare timing!");
retry = true; // another ractor is waiting for the yield.
}
}
@@ -2105,20 +1655,6 @@ ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool e
}
void
-rb_ractor_atexit(rb_execution_context_t *ec, VALUE result)
-{
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
- ractor_yield_atexit(ec, cr, result, false);
-}
-
-void
-rb_ractor_atexit_exception(rb_execution_context_t *ec)
-{
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
- ractor_yield_atexit(ec, cr, ec->errinfo, true);
-}
-
-void
rb_ractor_teardown(rb_execution_context_t *ec)
{
rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
@@ -2135,6 +1671,20 @@ rb_ractor_teardown(rb_execution_context_t *ec)
}
void
+rb_ractor_atexit(rb_execution_context_t *ec, VALUE result)
+{
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ ractor_yield_atexit(ec, cr, result, false);
+}
+
+void
+rb_ractor_atexit_exception(rb_execution_context_t *ec)
+{
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ ractor_yield_atexit(ec, cr, ec->errinfo, true);
+}
+
+void
rb_ractor_receive_parameters(rb_execution_context_t *ec, rb_ractor_t *r, int len, VALUE *ptr)
{
for (int i=0; i<len; i++) {
@@ -2151,7 +1701,7 @@ rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *r, VALUE args
}
}
-bool
+MJIT_FUNC_EXPORTED bool
rb_ractor_main_p_(void)
{
VM_ASSERT(rb_multi_ractor_p());
@@ -2173,24 +1723,35 @@ rb_ractor_living_thread_num(const rb_ractor_t *r)
return r->threads.cnt;
}
-// only for current ractor
VALUE
-rb_ractor_thread_list(void)
+rb_ractor_thread_list(rb_ractor_t *r)
{
- rb_ractor_t *r = GET_RACTOR();
rb_thread_t *th = 0;
- VALUE ary = rb_ary_new();
+ VALUE *ts;
+ int ts_cnt;
- ccan_list_for_each(&r->threads.set, th, lt_node) {
- switch (th->status) {
- case THREAD_RUNNABLE:
- case THREAD_STOPPED:
- case THREAD_STOPPED_FOREVER:
- rb_ary_push(ary, th->self);
- default:
- break;
+ RACTOR_LOCK(r);
+ {
+ ts = ALLOCA_N(VALUE, r->threads.cnt);
+ ts_cnt = 0;
+
+ ccan_list_for_each(&r->threads.set, th, lt_node) {
+ switch (th->status) {
+ case THREAD_RUNNABLE:
+ case THREAD_STOPPED:
+ case THREAD_STOPPED_FOREVER:
+ ts[ts_cnt++] = th->self;
+ default:
+ break;
+ }
}
}
+ RACTOR_UNLOCK(r);
+
+ VALUE ary = rb_ary_new();
+ for (int i=0; i<ts_cnt; i++) {
+ rb_ary_push(ary, ts[i]);
+ }
return ary;
}
@@ -2273,8 +1834,6 @@ ractor_check_blocking(rb_ractor_t *cr, unsigned int remained_thread_cnt, const c
}
}
-void rb_threadptr_remove(rb_thread_t *th);
-
void
rb_ractor_living_threads_remove(rb_ractor_t *cr, rb_thread_t *th)
{
@@ -2282,8 +1841,6 @@ rb_ractor_living_threads_remove(rb_ractor_t *cr, rb_thread_t *th)
RUBY_DEBUG_LOG("r->threads.cnt:%d--", cr->threads.cnt);
ractor_check_blocking(cr, cr->threads.cnt - 1, __FILE__, __LINE__);
- rb_threadptr_remove(th);
-
if (cr->threads.cnt == 1) {
vm_remove_ractor(th->vm, cr);
}
@@ -2379,31 +1936,23 @@ ractor_terminal_interrupt_all(rb_vm_t *vm)
rb_ractor_t *r = 0;
ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
if (r != vm->ractor.main_ractor) {
- RUBY_DEBUG_LOG("r:%d", rb_ractor_id(r));
rb_ractor_terminate_interrupt_main_thread(r);
}
}
}
}
-void rb_add_running_thread(rb_thread_t *th);
-void rb_del_running_thread(rb_thread_t *th);
-
void
rb_ractor_terminate_all(void)
{
rb_vm_t *vm = GET_VM();
rb_ractor_t *cr = vm->ractor.main_ractor;
- RUBY_DEBUG_LOG("ractor.cnt:%d", (int)vm->ractor.cnt);
-
VM_ASSERT(cr == GET_RACTOR()); // only main-ractor's main-thread should kick it.
if (vm->ractor.cnt > 1) {
RB_VM_LOCK();
- {
- ractor_terminal_interrupt_all(vm); // kill all ractors
- }
+ ractor_terminal_interrupt_all(vm); // kill all ractors
RB_VM_UNLOCK();
}
rb_thread_terminate_all(GET_THREAD()); // kill other threads in main-ractor and wait
@@ -2416,9 +1965,7 @@ rb_ractor_terminate_all(void)
// wait for 1sec
rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
- rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_cond_timedwait(vm, &vm->ractor.sync.terminate_cond, 1000 /* ms */);
- rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
ractor_terminal_interrupt_all(vm);
@@ -2558,9 +2105,6 @@ Init_Ractor(void)
rb_define_method(rb_cRactorMovedObject, "equal?", ractor_moved_missing, -1);
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
-
- rb_cRactorSelector = rb_define_class_under(rb_cRactor, "Selector", rb_cObject);
- rb_undef_alloc_func(rb_cRactorSelector);
}
void
@@ -2734,7 +2278,7 @@ obj_traverse_rec(struct obj_traverse_data *data)
{
if (UNLIKELY(!data->rec)) {
data->rec_hash = rb_ident_hash_new();
- data->rec = RHASH_ST_TABLE(data->rec_hash);
+ data->rec = rb_hash_st_table(data->rec_hash);
}
return data->rec;
}
@@ -2758,8 +2302,8 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
struct gen_ivtbl *ivtbl;
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
- for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
- VALUE val = ivtbl->as.shape.ivptr[i];
+ for (uint32_t i = 0; i < ivtbl->numiv; i++) {
+ VALUE val = ivtbl->ivptr[i];
if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
}
}
@@ -2987,7 +2531,10 @@ VALUE
rb_ractor_make_shareable_copy(VALUE obj)
{
VALUE copy = ractor_copy(obj);
- return rb_ractor_make_shareable(copy);
+ rb_obj_traverse(copy,
+ make_shareable_check_shareable,
+ null_leave, mark_shareable);
+ return copy;
}
VALUE
@@ -3030,7 +2577,7 @@ shareable_p_enter(VALUE obj)
return traverse_stop; // fail
}
-bool
+MJIT_FUNC_EXPORTED bool
rb_ractor_shareable_p_continue(VALUE obj)
{
if (rb_obj_traverse(obj,
@@ -3163,18 +2710,25 @@ obj_traverse_replace_rec(struct obj_traverse_replace_data *data)
{
if (UNLIKELY(!data->rec)) {
data->rec_hash = rb_ident_hash_new();
- data->rec = RHASH_ST_TABLE(data->rec_hash);
+ data->rec = rb_hash_st_table(data->rec_hash);
}
return data->rec;
}
+#if USE_TRANSIENT_HEAP
+void rb_ary_transient_heap_evacuate(VALUE ary, int promote);
+void rb_obj_transient_heap_evacuate(VALUE obj, int promote);
+void rb_hash_transient_heap_evacuate(VALUE hash, int promote);
+void rb_struct_transient_heap_evacuate(VALUE st, int promote);
+#endif
+
static void
obj_refer_only_shareables_p_i(VALUE obj, void *ptr)
{
int *pcnt = (int *)ptr;
if (!rb_ractor_shareable_p(obj)) {
- ++*pcnt;
+ *pcnt++;
}
}
@@ -3229,9 +2783,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
struct gen_ivtbl *ivtbl;
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
- for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
- if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
- CHECK_AND_REPLACE(ivtbl->as.shape.ivptr[i]);
+ for (uint32_t i = 0; i < ivtbl->numiv; i++) {
+ if (!UNDEF_P(ivtbl->ivptr[i])) {
+ CHECK_AND_REPLACE(ivtbl->ivptr[i]);
}
}
}
@@ -3265,6 +2819,10 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
(st_data_t)&d);
}
else {
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_obj_transient_heap_evacuate(obj, TRUE);
+#endif
+
uint32_t len = ROBJECT_IV_COUNT(obj);
VALUE *ptr = ROBJECT_IVPTR(obj);
@@ -3280,6 +2838,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_ARRAY:
{
rb_ary_cancel_sharing(obj);
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_ary_transient_heap_evacuate(obj, TRUE);
+#endif
for (int i = 0; i < RARRAY_LENINT(obj); i++) {
VALUE e = rb_ary_entry(obj, i);
@@ -3294,8 +2855,12 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
RB_GC_GUARD(obj);
}
break;
+
case T_HASH:
{
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_hash_transient_heap_evacuate(obj, TRUE);
+#endif
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
@@ -3320,6 +2885,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_STRUCT:
{
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_struct_transient_heap_evacuate(obj, TRUE);
+#endif
long len = RSTRUCT_LEN(obj);
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
diff --git a/ractor.rb b/ractor.rb
index 5620eeec38..1031fe499b 100644
--- a/ractor.rb
+++ b/ractor.rb
@@ -1,56 +1,51 @@
-# \Ractor is an Actor-model abstraction for Ruby that provides thread-safe parallel execution.
+# Ractor is an Actor-model abstraction for Ruby that provides thread-safe parallel execution.
#
-# Ractor.new makes a new \Ractor, which can run in parallel.
+# Ractor.new can make a new Ractor, and it will run in parallel.
#
# # The simplest ractor
# r = Ractor.new {puts "I am in Ractor!"}
# r.take # wait for it to finish
-# # Here, "I am in Ractor!" is printed
+# # here "I am in Ractor!" would be printed
#
-# Ractors do not share all objects with each other. There are two main benefits to this: across ractors, thread-safety
-# concerns such as data-races and race-conditions are not possible. The other benefit is parallelism.
+# Ractors do not share usual objects, so the same kinds of thread-safety concerns such as data-race,
+# race-conditions are not available on multi-ractor programming.
#
-# To achieve this, object sharing is limited across ractors.
-# For example, unlike in threads, ractors can't access all the objects available in other ractors. Even objects normally
-# available through variables in the outer scope are prohibited from being used across ractors.
+# To achieve this, ractors severely limit object sharing between different ractors.
+# For example, unlike threads, ractors can't access each other's objects, nor any objects through
+# variables of the outer scope.
#
# a = 1
# r = Ractor.new {puts "I am in Ractor! a=#{a}"}
# # fails immediately with
# # ArgumentError (can not isolate a Proc because it accesses outer variables (a).)
#
-# The object must be explicitly shared:
-# a = 1
-# r = Ractor.new(a) { |a1| puts "I am in Ractor! a=#{a1}"}
-#
# On CRuby (the default implementation), Global Virtual Machine Lock (GVL) is held per ractor, so
-# ractors can perform in parallel without locking each other. This is unlike the situation with threads
-# on CRuby.
+# ractors are performed in parallel without locking each other.
#
-# Instead of accessing shared state, objects should be passed to and from ractors by
-# sending and receiving them as messages.
+# Instead of accessing the shared state, the objects should be passed to and from ractors via
+# sending and receiving objects as messages.
#
# a = 1
# r = Ractor.new do
-# a_in_ractor = receive # receive blocks until somebody passes a message
+# a_in_ractor = receive # receive blocks till somebody will pass message
# puts "I am in Ractor! a=#{a_in_ractor}"
# end
# r.send(a) # pass it
# r.take
-# # Here, "I am in Ractor! a=1" is printed
+# # here "I am in Ractor! a=1" would be printed
#
# There are two pairs of methods for sending/receiving messages:
#
# * Ractor#send and Ractor.receive for when the _sender_ knows the receiver (push);
# * Ractor.yield and Ractor#take for when the _receiver_ knows the sender (pull);
#
-# In addition to that, any arguments passed to Ractor.new are passed to the block and available there
-# as if received by Ractor.receive, and the last block value is sent outside of the
+# In addition to that, an argument to Ractor.new would be passed to block and available there
+# as if received by Ractor.receive, and the last block value would be sent outside of the
# ractor as if sent by Ractor.yield.
#
-# A little demonstration of a classic ping-pong:
+# A little demonstration on a classic ping-pong:
#
-# server = Ractor.new(name: "server") do
+# server = Ractor.new do
# puts "Server starts: #{self.inspect}"
# puts "Server sends: ping"
# Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested
@@ -58,48 +53,44 @@
# puts "Server received: #{received}"
# end
#
-# client = Ractor.new(server) do |srv| # The server is sent to the client, and available as srv
+# client = Ractor.new(server) do |srv| # The server is sent inside client, and available as srv
# puts "Client starts: #{self.inspect}"
-# received = srv.take # The client takes a message from the server
+# received = srv.take # The Client takes a message specifically from the server
# puts "Client received from " \
# "#{srv.inspect}: #{received}"
# puts "Client sends to " \
# "#{srv.inspect}: pong"
-# srv.send 'pong' # The client sends a message to the server
+# srv.send 'pong' # The client sends a message specifically to the server
# end
#
-# [client, server].each(&:take) # Wait until they both finish
+# [client, server].each(&:take) # Wait till they both finish
#
-# This will output something like:
+# This will output:
#
-# Server starts: #<Ractor:#2 server test.rb:1 running>
+# Server starts: #<Ractor:#2 test.rb:1 running>
# Server sends: ping
# Client starts: #<Ractor:#3 test.rb:8 running>
-# Client received from #<Ractor:#2 server test.rb:1 blocking>: ping
-# Client sends to #<Ractor:#2 server test.rb:1 blocking>: pong
+# Client received from #<Ractor:#2 rac.rb:1 blocking>: ping
+# Client sends to #<Ractor:#2 rac.rb:1 blocking>: pong
# Server received: pong
#
-# Ractors receive their messages via the <em>incoming port</em>, and send them
+# It is said that Ractor receives messages via the <em>incoming port</em>, and sends them
# to the <em>outgoing port</em>. Either one can be disabled with Ractor#close_incoming and
-# Ractor#close_outgoing, respectively. When a ractor terminates, its ports are closed
+# Ractor#close_outgoing respectively. If a ractor terminated, its ports will be closed
# automatically.
#
# == Shareable and unshareable objects
#
-# When an object is sent to and from a ractor, it's important to understand whether the
-# object is shareable or unshareable. Most Ruby objects are unshareable objects. Even
-# frozen objects can be unshareable if they contain (through their instance variables) unfrozen
-# objects.
+# When the object is sent to and from the ractor, it is important to understand whether the
+# object is shareable or unshareable. Most of objects are unshareable objects.
#
-# Shareable objects are those which can be used by several threads without compromising
-# thread-safety, for example numbers, +true+ and +false+. Ractor.shareable? allows you to check this,
-# and Ractor.make_shareable tries to make the object shareable if it's not already, and gives an error
-# if it can't do it.
+# Shareable objects are basically those which can be used by several threads without compromising
+# thread-safety; e.g. immutable ones. Ractor.shareable? allows to check this, and Ractor.make_shareable
+# tries to make object shareable if it is not.
#
-# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
-# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
+# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are
+# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # freeze_string_literals: true
# Ractor.shareable?('foo'.freeze) #=> true
-# Ractor.shareable?([Object.new].freeze) #=> false, inner object is unfrozen
#
# ary = ['hello', 'world']
# ary.frozen? #=> false
@@ -109,10 +100,10 @@
# ary[0].frozen? #=> true
# ary[1].frozen? #=> true
#
-# When a shareable object is sent (via #send or Ractor.yield), no additional processing occurs
-# on it. It just becomes usable by both ractors. When an unshareable object is sent, it can be
-# either _copied_ or _moved_. The first is the default, and it copies the object fully by
-# deep cloning (Object#clone) the non-shareable parts of its structure.
+# When a shareable object is sent (via #send or Ractor.yield), no additional processing happens,
+# and it just becomes usable by both ractors. When an unshareable object is sent, it can be
+# either _copied_ or _moved_. The first is the default, and it makes the object's full copy by
+# deep cloning of non-shareable parts of its structure.
#
# data = ['foo', 'bar'.freeze]
# r = Ractor.new do
@@ -123,18 +114,18 @@
# r.take
# puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
#
-# This will output something like:
+# This will output:
#
# In ractor: 340, 360, 320
# Outside : 380, 400, 320
#
-# Note that the object ids of the array and the non-frozen string inside the array have changed in
-# the ractor because they are different objects. The second array's element, which is a
-# shareable frozen string, is the same object.
+# (Note that object id of both array and non-frozen string inside array have changed inside
+# the ractor, showing it is different objects. But the second array's element, which is a
+# shareable frozen string, has the same object_id.)
#
-# Deep cloning of objects may be slow, and sometimes impossible. Alternatively, <tt>move: true</tt> may
-# be used during sending. This will <em>move</em> the unshareable object to the receiving ractor, making it
-# inaccessible to the sending ractor.
+# Deep cloning of the objects may be slow, and sometimes impossible. Alternatively,
+# <tt>move: true</tt> may be used on sending. This will <em>move</em> the object to the
+# receiving ractor, making it inaccessible for a sending ractor.
#
# data = ['foo', 'bar']
# r = Ractor.new do
@@ -155,14 +146,13 @@
# Notice that even +inspect+ (and more basic methods like <tt>__id__</tt>) is inaccessible
# on a moved object.
#
-# Class and Module objects are shareable so the class/module definitions are shared between ractors.
-# \Ractor objects are also shareable. All operations on shareable objects are thread-safe, so the thread-safety property
+# Besides frozen objects, there are shareable objects. Class and Module objects are shareable so
+# the Class/Module definitions are shared between ractors. Ractor objects are also shareable objects.
+# All operations for the shareable mutable objects are thread-safe, so the thread-safety property
# will be kept. We can not define mutable shareable objects in Ruby, but C extensions can introduce them.
#
-# It is prohibited to access (get) instance variables of shareable objects in other ractors if the values of the
-# variables aren't shareable. This can occur because modules/classes are shareable, but they can have
-# instance variables whose values are not. In non-main ractors, it's also prohibited to set instance
-# variables on classes/modules (even if the value is shareable).
+# It is prohibited to access instance variables of mutable shareable objects (especially Modules and classes)
+# from ractors other than main:
#
# class C
# class << self
@@ -170,22 +160,21 @@
# end
# end
#
-# C.tricky = "unshareable".dup
+# C.tricky = 'test'
#
# r = Ractor.new(C) do |cls|
# puts "I see #{cls}"
# puts "I can't see #{cls.tricky}"
-# cls.tricky = true # doesn't get here, but this would also raise an error
# end
# r.take
# # I see C
# # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
#
-# Ractors can access constants if they are shareable. The main \Ractor is the only one that can
+# Ractors can access constants if they are shareable. The main Ractor is the only one that can
# access non-shareable constants.
#
# GOOD = 'good'.freeze
-# BAD = 'bad'.dup
+# BAD = 'bad'
#
# r = Ractor.new do
# puts "GOOD=#{GOOD}"
@@ -210,8 +199,8 @@
#
# == Ractors vs threads
#
-# Each ractor has its own main Thread. New threads can be created from inside ractors
-# (and, on CRuby, they share the GVL with other threads of this ractor).
+# Each ractor creates its own thread. New threads can be created from inside ractor
+# (and, on CRuby, sharing GVL with other threads of this ractor).
#
# r = Ractor.new do
# a = 1
@@ -222,15 +211,15 @@
#
# == Note on code examples
#
-# In the examples below, sometimes we use the following method to wait for ractors that
-# are not currently blocked to finish (or to make progress).
+# In examples below, sometimes we use the following method to wait till ractors that
+# are not currently blocked will finish (or process till next blocking) method.
#
# def wait
# sleep(0.1)
# end
#
# It is **only for demonstration purposes** and shouldn't be used in a real code.
-# Most of the time, #take is used to wait for ractors to finish.
+# Most of the times, just #take is used to wait till ractor will finish.
#
# == Reference
#
@@ -241,17 +230,17 @@ class Ractor
# call-seq:
# Ractor.new(*args, name: nil) {|*args| block } -> ractor
#
- # Create a new \Ractor with args and a block.
+ # Create a new Ractor with args and a block.
#
- # The given block (Proc) will be isolated (can't access any outer variables). +self+
- # inside the block will refer to the current \Ractor.
+ # A block (Proc) will be isolated (can't access to outer variables). +self+
+ # inside the block will refer to the current Ractor.
#
# r = Ractor.new { puts "Hi, I am #{self.inspect}" }
# r.take
# # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
#
- # Any +args+ passed are propagated to the block arguments by the same rules as
- # objects sent via #send/Ractor.receive. If an argument in +args+ is not shareable, it
+ # +args+ passed to the method would be propagated to block args by the same rules as
+ # objects passed through #send/Ractor.receive: if +args+ are not shareable, they
# will be copied (via deep cloning, which might be inefficient).
#
# arg = [1, 2, 3]
@@ -266,7 +255,7 @@ class Ractor
#
# Ractor's +name+ can be set for debugging purposes:
#
- # r = Ractor.new(name: 'my ractor') {}; r.take
+ # r = Ractor.new(name: 'my ractor') {}
# p r
# #=> #<Ractor:#3 my ractor test.rb:1 terminated>
#
@@ -291,13 +280,13 @@ class Ractor
}
end
- # Returns the number of Ractors currently running or blocking (waiting).
+ # Returns total count of Ractors currently running.
#
# Ractor.count #=> 1
# r = Ractor.new(name: 'example') { Ractor.yield(1) }
# Ractor.count #=> 2 (main + example ractor)
# r.take # wait for Ractor.yield(1)
- # r.take # wait until r will finish
+ # r.take # wait till r will finish
# Ractor.count #=> 1
def self.count
__builtin_cexpr! %q{
@@ -309,8 +298,8 @@ class Ractor
# call-seq:
# Ractor.select(*ractors, [yield_value:, move: false]) -> [ractor or symbol, obj]
#
- # Wait for any ractor to have something in its outgoing port, read from this ractor, and
- # then return that ractor and the object received.
+ # Waits for the first ractor to have something in its outgoing port, reads from this ractor, and
+ # returns that ractor and the object received.
#
# r1 = Ractor.new {Ractor.yield 'from 1'}
# r2 = Ractor.new {Ractor.yield 'from 2'}
@@ -319,10 +308,9 @@ class Ractor
#
# puts "received #{obj.inspect} from #{r.inspect}"
# # Prints: received "from 1" from #<Ractor:#2 test.rb:1 running>
- # # But could just as well print "from r2" here, either prints could be first.
#
- # If one of the given ractors is the current ractor, and it is selected, +r+ will contain
- # the +:receive+ symbol instead of the ractor object.
+ # If one of the given ractors is the current ractor, and it would be selected, +r+ will contain
+ # +:receive+ symbol instead of the ractor object.
#
# r1 = Ractor.new(Ractor.current) do |main|
# main.send 'to main'
@@ -334,10 +322,10 @@ class Ractor
#
# r, obj = Ractor.select(r1, r2, Ractor.current)
# puts "received #{obj.inspect} from #{r.inspect}"
- # # Could print: received "to main" from :receive
+ # # Prints: received "to main" from :receive
#
- # If +yield_value+ is provided, that value may be yielded if another ractor is calling #take.
- # In this case, the pair <tt>[:yield, nil]</tt> is returned:
+ # If +yield_value+ is provided, that value may be yielded if another Ractor is calling #take.
+ # In this case, the pair <tt>[:yield, nil]</tt> would be returned:
#
# r1 = Ractor.new(Ractor.current) do |main|
# puts "Received from main: #{main.take}"
@@ -354,141 +342,26 @@ class Ractor
# Received from main: 123
# Received nil from :yield
#
- # +move+ boolean flag defines whether yielded value will be copied (default) or moved.
+ # +move+ boolean flag defines whether yielded value should be copied (default) or moved.
def self.select(*ractors, yield_value: yield_unspecified = true, move: false)
raise ArgumentError, 'specify at least one ractor or `yield_value`' if yield_unspecified && ractors.empty?
- begin
- if ractors.delete Ractor.current
- do_receive = true
- else
- do_receive = false
- end
- selector = Ractor::Selector.new(*ractors)
-
- if yield_unspecified
- selector.wait receive: do_receive
- else
- selector.wait receive: do_receive, yield_value: yield_value, move: move
- end
- ensure
- selector.clear
- end
- end
-
- #
- # Ractor::Selector provides a functionality to wait multiple Ractor events.
- # Ractor::Selector#wait is more lightweight than Ractor.select()
- # because we don't have to specify all target ractors for each wait time.
- #
- # Ractor.select() uses Ractor::Selector internally to implement it.
- #
- class Selector
- # call-seq:
- # Ractor::Selector.new(*ractors)
- #
- # Creates a selector object.
- #
- # If a ractors parameter is given, it is same as the following code.
- #
- # selector = Ractor::Selector.new
- # ractors.each{|r| selector.add r}
- #
- def self.new(*rs)
- selector = __builtin_cexpr! %q{
- ractor_selector_create(self);
- }
- rs.each{|r| selector.add(r) }
- selector
- end
-
- # call-seq:
- # selector.add(ractor)
- #
- # Registers a ractor as a taking target by the selector.
- #
- def add r
- __builtin_ractor_selector_add r
- end
-
- # call-seq:
- # selector.remove(ractor)
- #
- # Deregisters a ractor as a taking target by the selector.
- #
- def remove r
- __builtin_ractor_selector_remove r
- end
-
- # call-seq:
- # selector.clear
- #
- # Deregisters all ractors.
- def clear
- __builtin_ractor_selector_clear
- end
-
- # call-seq:
- # selector.empty?
- #
- # Returns true if the number of ractors in the waiting set at the current time is zero.
- #
- # Note that even if <tt>#empty?</tt> returns false, the subsequent <tt>#wait</tt>
- # may raise an exception because other ractors may close the target ractors.
- #
- def empty?
- __builtin_ractor_selector_empty_p
- end
-
- # call-seq:
- # selector.wait(receive: false, yield_value: yield_value, move: false) -> [ractor or symbol, value]
- #
- # Waits Ractor events. It is lighter than Ractor.select() for many ractors.
- #
- # The simplest form is waiting for taking a value from one of
- # registerred ractors like that.
- #
- # selector = Ractor::Selector.new(r1, r2, r3)
- # r, v = selector.wait
- #
- # On this case, when r1, r2 or r3 is ready to take (yielding a value),
- # this method takes the value from the ready (yielded) ractor
- # and returns [the yielded ractor, the taking value].
- #
- # Note that if a take target ractor is closed, the ractor will be removed
- # automatically.
- #
- # If you also want to wait with receiving an object from other ractors,
- # you can specify receive: true keyword like:
- #
- # r, v = selector.wait receive: true
- #
- # On this case, wait for taking from r1, r2 or r3 and waiting for receving
- # a value from other ractors.
- # If it successes the receiving, it returns an array object [:receive, the received value].
- #
- # If you also want to wait with yielding a value, you can specify
- # :yield_value like:
- #
- # r, v = selector.wait yield_value: obj
- #
- # On this case wait for taking from r1, r2, or r3 and waiting for taking
- # yielding value (obj) by another ractor.
- # If antoher ractor takes the value (obj), it returns an array object [:yield, nil].
- #
- # You can specify a keyword parameter <tt>move: true</tt> like Ractor.yield(obj, move: true)
- #
- def wait receive: false, yield_value: yield_unspecified = true, move: false
- __builtin_ractor_selector_wait receive, !yield_unspecified, yield_value, move
- end
+ __builtin_cstmt! %q{
+ const VALUE *rs = RARRAY_CONST_PTR_TRANSIENT(ractors);
+ VALUE rv;
+ VALUE v = ractor_select(ec, rs, RARRAY_LENINT(ractors),
+ yield_unspecified == Qtrue ? Qundef : yield_value,
+ (bool)RTEST(move) ? true : false, &rv);
+ return rb_ary_new_from_args(2, rv, v);
+ }
end
#
# call-seq:
# Ractor.receive -> msg
#
- # Receive a message from the incoming port of the current ractor (which was
- # sent there by #send from another ractor).
+ # Receive an incoming message from the current Ractor's incoming port's queue, which was
+ # sent there by #send.
#
# r = Ractor.new do
# v1 = Ractor.receive
@@ -498,7 +371,7 @@ class Ractor
# r.take
# # Here will be printed: "Received: message1"
#
- # Alternatively, the private instance method +receive+ may be used:
+ # Alternatively, private instance method +receive+ may be used:
#
# r = Ractor.new do
# v1 = receive
@@ -506,7 +379,7 @@ class Ractor
# end
# r.send('message1')
# r.take
- # # This prints: "Received: message1"
+ # # Here will be printed: "Received: message1"
#
# The method blocks if the queue is empty.
#
@@ -534,7 +407,7 @@ class Ractor
# Received: message2
#
# If close_incoming was called on the ractor, the method raises Ractor::ClosedError
- # if there are no more messages in the incoming queue:
+ # if there are no more messages in incoming queue:
#
# Ractor.new do
# close_incoming
@@ -567,9 +440,8 @@ class Ractor
#
# Receive only a specific message.
#
- # Instead of Ractor.receive, Ractor.receive_if can be given a pattern (or any
- # filter) in a block and you can choose the messages to accept that are available in
- # your ractor's incoming queue.
+ # Instead of Ractor.receive, Ractor.receive_if can provide a pattern
+ # by a block and you can choose the receiving message.
#
# r = Ractor.new do
# p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3"
@@ -587,10 +459,10 @@ class Ractor
# bar1
# baz2
#
- # If the block returns a truthy value, the message is removed from the incoming queue
+ # If the block returns a truthy value, the message will be removed from the incoming queue
# and returned.
- # Otherwise, the message remains in the incoming queue and the next messages are checked
- # by the given block.
+ # Otherwise, the message remains in the incoming queue and the following received
+ # messages are checked by the given block.
#
# If there are no messages left in the incoming queue, the method will
# block until new messages arrive.
@@ -616,7 +488,7 @@ class Ractor
# Received successfully: [1, 2, 3]
#
# Note that you can not call receive/receive_if in the given block recursively.
- # You should not do any tasks in the block other than message filtration.
+ # It means that you should not do any tasks in the block.
#
# Ractor.current << true
# Ractor.receive_if{|msg| Ractor.receive}
@@ -626,7 +498,6 @@ class Ractor
Primitive.ractor_receive_if b
end
- # same as Ractor.receive_if
private def receive_if &b
Primitive.ractor_receive_if b
end
@@ -635,7 +506,7 @@ class Ractor
# call-seq:
# ractor.send(msg, move: false) -> self
#
- # Send a message to a Ractor's incoming queue to be accepted by Ractor.receive.
+ # Send a message to a Ractor's incoming queue to be consumed by Ractor.receive.
#
# r = Ractor.new do
# value = Ractor.receive
@@ -652,7 +523,7 @@ class Ractor
# puts "Sent successfully"
# # Prints: "Sent successfully" immediately
#
- # An attempt to send to a ractor which already finished its execution will raise Ractor::ClosedError.
+ # Attempt to send to ractor which already finished its execution will raise Ractor::ClosedError.
#
# r = Ractor.new {}
# r.take
@@ -670,11 +541,11 @@ class Ractor
# r.close_incoming
# r.send('test')
# # Ractor::ClosedError (The incoming-port is already closed)
- # # The error is raised immediately, not when the ractor tries to receive
+ # # The error would be raised immediately, not when ractor will try to receive
#
- # If the +obj+ is unshareable, by default it will be copied into the receiving ractor by deep cloning.
- # If <tt>move: true</tt> is passed, the object is _moved_ into the receiving ractor and becomes
- # inaccessible to the sender.
+ # If the +obj+ is unshareable, by default it would be copied into ractor by deep cloning.
+ # If the <tt>move: true</tt> is passed, object is _moved_ into ractor and becomes
+ # inaccessible to sender.
#
# r = Ractor.new {puts "Received: #{receive}"}
# msg = 'message'
@@ -687,7 +558,7 @@ class Ractor
# Received: message
# in `p': undefined method `inspect' for #<Ractor::MovedObject:0x000055c99b9b69b8>
#
- # All references to the object and its parts will become invalid to the sender.
+ # All references to the object and its parts will become invalid in sender.
#
# r = Ractor.new {puts "Received: #{receive}"}
# s = 'message'
@@ -705,7 +576,7 @@ class Ractor
# # Ractor::MovedError (can not send any methods to a moved object)
# # ...but its item was still a reference to `s`, which was moved
#
- # If the object is shareable, <tt>move: true</tt> has no effect on it:
+ # If the object was shareable, <tt>move: true</tt> has no effect on it:
#
# r = Ractor.new {puts "Received: #{receive}"}
# s = 'message'.freeze
@@ -723,13 +594,13 @@ class Ractor
# call-seq:
# Ractor.yield(msg, move: false) -> nil
#
- # Send a message to the current ractor's outgoing port to be accepted by #take.
+ # Send a message to the current ractor's outgoing port to be consumed by #take.
#
# r = Ractor.new {Ractor.yield 'Hello from ractor'}
# puts r.take
# # Prints: "Hello from ractor"
#
- # This method is blocking, and will return only when somebody consumes the
+ # The method is blocking, and will return only when somebody consumes the
# sent message.
#
# r = Ractor.new do
@@ -755,7 +626,7 @@ class Ractor
# wait
# # `yield': The outgoing-port is already closed (Ractor::ClosedError)
#
- # The meaning of the +move+ argument is the same as for #send.
+ # The meaning of +move+ argument is the same as for #send.
def self.yield(obj, move: false)
__builtin_cexpr! %q{
ractor_yield(ec, rb_ec_ractor_ptr(ec), obj, move)
@@ -766,8 +637,8 @@ class Ractor
# call-seq:
# ractor.take -> msg
#
- # Get a message from the ractor's outgoing port, which was put there by Ractor.yield or at ractor's
- # termination.
+ # Take a message from ractor's outgoing port, which was put there by Ractor.yield or at ractor's
+ # finalization.
#
# r = Ractor.new do
# Ractor.yield 'explicit yield'
@@ -777,9 +648,9 @@ class Ractor
# puts r.take #=> 'last value'
# puts r.take # Ractor::ClosedError (The outgoing-port is already closed)
#
- # The fact that the last value is also sent to the outgoing port means that +take+ can be used
- # as an analog of Thread#join ("just wait until ractor finishes"). However, it will raise if
- # somebody has already consumed that message.
+ # The fact that the last value is also put to outgoing port means that +take+ can be used
+ # as some analog of Thread#join ("just wait till ractor finishes"), but don't forget it
+ # will raise if somebody had already consumed everything ractor have produced.
#
# If the outgoing port was closed with #close_outgoing, the method will raise Ractor::ClosedError.
#
@@ -792,7 +663,7 @@ class Ractor
# # Ractor::ClosedError (The outgoing-port is already closed)
# # The error would be raised immediately, not when ractor will try to receive
#
- # If an uncaught exception is raised in the Ractor, it is propagated by take as a
+ # If an uncaught exception is raised in the Ractor, it is propagated on take as a
# Ractor::RemoteError.
#
# r = Ractor.new {raise "Something weird happened"}
@@ -805,8 +676,8 @@ class Ractor
# p e.cause # => #<RuntimeError: Something weird happened>
# end
#
- # Ractor::ClosedError is a descendant of StopIteration, so the termination of the ractor will break
- # out of any loops that receive this message without propagating the error:
+ # Ractor::ClosedError is a descendant of StopIteration, so the closing of the ractor will break
+ # the loops without propagating the error:
#
# r = Ractor.new do
# 3.times {|i| Ractor.yield "message #{i}"}
@@ -854,8 +725,9 @@ class Ractor
# call-seq:
# ractor.close_incoming -> true | false
#
- # Closes the incoming port and returns whether it was already closed. All further attempts
- # to Ractor.receive in the ractor, and #send to the ractor will fail with Ractor::ClosedError.
+ # Closes the incoming port and returns its previous state.
+ # All further attempts to Ractor.receive in the ractor, and #send to the ractor
+ # will fail with Ractor::ClosedError.
#
# r = Ractor.new {sleep(500)}
# r.close_incoming #=> false
@@ -872,8 +744,9 @@ class Ractor
# call-seq:
# ractor.close_outgoing -> true | false
#
- # Closes the outgoing port and returns whether it was already closed. All further attempts
- # to Ractor.yield in the ractor, and #take from the ractor will fail with Ractor::ClosedError.
+ # Closes the outgoing port and returns its previous state.
+ # All further attempts to Ractor.yield in the ractor, and #take from the ractor
+ # will fail with Ractor::ClosedError.
#
# r = Ractor.new {sleep(500)}
# r.close_outgoing #=> false
@@ -893,10 +766,10 @@ class Ractor
# Checks if the object is shareable by ractors.
#
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
- # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
+ # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # freeze_string_literals: true
# Ractor.shareable?('foo'.freeze) #=> true
#
- # See also the "Shareable and unshareable objects" section in the \Ractor class docs.
+ # See also the "Shareable and unshareable objects" section in the Ractor class docs.
def self.shareable? obj
__builtin_cexpr! %q{
RBOOL(rb_ractor_shareable_p(obj));
@@ -912,8 +785,8 @@ class Ractor
# +obj+ and all the objects it refers to will be frozen, unless they are
# already shareable.
#
- # If +copy+ keyword is +true+, it will copy objects before freezing them, and will not
- # modify +obj+ or its internal objects.
+ # If +copy+ keyword is +true+, the method will copy objects before freezing them
+ # This is safer option but it can take be slower.
#
# Note that the specification and implementation of this method are not
# mature and may be changed in the future.
diff --git a/ractor_core.h b/ractor_core.h
index 36c0e91c7a..968c12d291 100644
--- a/ractor_core.h
+++ b/ractor_core.h
@@ -1,4 +1,3 @@
-#include "internal/gc.h"
#include "ruby/ruby.h"
#include "ruby/ractor.h"
#include "vm_core.h"
@@ -10,66 +9,22 @@
#endif
enum rb_ractor_basket_type {
- // basket is empty
basket_type_none,
-
- // value is available
basket_type_ref,
basket_type_copy,
basket_type_move,
basket_type_will,
-
- // basket should be deleted
basket_type_deleted,
-
- // basket is reserved
basket_type_reserved,
-
- // take_basket is available
- basket_type_take_basket,
-
- // basket is keeping by yielding ractor
- basket_type_yielding,
-};
-
-// per ractor taking configuration
-struct rb_ractor_selector_take_config {
- bool closed;
- bool oneshot;
};
struct rb_ractor_basket {
- union {
- enum rb_ractor_basket_type e;
- rb_atomic_t atomic;
- } type;
+ bool exception;
+ enum rb_ractor_basket_type type;
+ VALUE v;
VALUE sender;
-
- union {
- struct {
- VALUE v;
- bool exception;
- } send;
-
- struct {
- struct rb_ractor_basket *basket;
- struct rb_ractor_selector_take_config *config;
- } take;
- } p; // payload
};
-static inline bool
-basket_type_p(struct rb_ractor_basket *b, enum rb_ractor_basket_type type)
-{
- return b->type.e == type;
-}
-
-static inline bool
-basket_none_p(struct rb_ractor_basket *b)
-{
- return basket_type_p(b, basket_type_none);
-}
-
struct rb_ractor_queue {
struct rb_ractor_basket *baskets;
int start;
@@ -79,6 +34,12 @@ struct rb_ractor_queue {
unsigned int reserved_cnt;
};
+struct rb_ractor_waiting_list {
+ int cnt;
+ int size;
+ rb_ractor_t **ractors;
+};
+
enum rb_ractor_wait_status {
wait_none = 0x00,
wait_receiving = 0x01,
@@ -103,28 +64,21 @@ struct rb_ractor_sync {
#if RACTOR_CHECK_MODE > 0
VALUE locked_by;
#endif
+ rb_nativethread_cond_t cond;
+
+ // communication
+ struct rb_ractor_queue incoming_queue;
+ struct rb_ractor_waiting_list taking_ractors;
bool incoming_port_closed;
bool outgoing_port_closed;
- // All sent messages will be pushed into recv_queue
- struct rb_ractor_queue recv_queue;
-
- // The following ractors waiting for the yielding by this ractor
- struct rb_ractor_queue takers_queue;
-
- // Enabled if the ractor already terminated and not taken yet.
- struct rb_ractor_basket will_basket;
-
struct ractor_wait {
enum rb_ractor_wait_status status;
enum rb_ractor_wakeup_status wakeup_status;
- rb_thread_t *waiting_thread;
+ struct rb_ractor_basket yielded_basket;
+ struct rb_ractor_basket taken_basket;
} wait;
-
-#ifndef RUBY_THREAD_PTHREAD_H
- rb_nativethread_cond_t cond;
-#endif
};
// created
@@ -153,6 +107,7 @@ struct rb_ractor_struct {
struct rb_ractor_sync sync;
VALUE receiving_mutex;
+ bool yield_atexit;
// vm wide barrier synchronization
rb_nativethread_cond_t barrier_wait_cond;
@@ -214,7 +169,7 @@ void rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *g, VALUE
VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c
int rb_ractor_living_thread_num(const rb_ractor_t *);
-VALUE rb_ractor_thread_list(void);
+VALUE rb_ractor_thread_list(rb_ractor_t *r);
bool rb_ractor_p(VALUE rv);
void rb_ractor_living_threads_init(rb_ractor_t *r);
@@ -285,10 +240,6 @@ rb_ractor_sleeper_thread_num(rb_ractor_t *r)
static inline void
rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th)
{
- RUBY_DEBUG_LOG("th:%d->%u%s",
- cr->threads.running_ec ? (int)rb_th_serial(cr->threads.running_ec->thread_ptr) : -1,
- rb_th_serial(th), cr->threads.running_ec == th->ec ? " (same)" : "");
-
if (cr->threads.running_ec != th->ec) {
if (0) {
ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
@@ -314,18 +265,16 @@ static inline void
rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const char *file, int line)
{
#ifdef RB_THREAD_LOCAL_SPECIFIER
-
-# ifdef __APPLE__
+ #ifdef __APPLE__
rb_current_ec_set(ec);
-# else
+ #else
ruby_current_ec = ec;
-# endif
-
+ #endif
#else
native_tls_set(ruby_current_ec_key, ec);
#endif
RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec);
- VM_ASSERT(ec == NULL || cr->threads.running_ec != ec);
+ VM_ASSERT(cr->threads.running_ec != ec);
cr->threads.running_ec = ec;
}
diff --git a/range.c b/range.c
index 7e72984dc7..dbc37c1410 100644
--- a/range.c
+++ b/range.c
@@ -607,10 +607,6 @@ double_as_int64(double d)
static int
is_integer_p(VALUE v)
{
- if (rb_integer_type_p(v)) {
- return true;
- }
-
ID id_integer_p;
VALUE is_int;
CONST_ID(id_integer_p, "integer?");
@@ -653,30 +649,27 @@ bsearch_integer_range(VALUE beg, VALUE end, int excl)
VALUE low = rb_to_int(beg);
VALUE high = rb_to_int(end);
- VALUE mid;
+ VALUE mid, org_high;
ID id_div;
CONST_ID(id_div, "div");
- if (!excl) high = rb_funcall(high, '+', 1, INT2FIX(1));
- low = rb_funcall(low, '-', 1, INT2FIX(1));
+ if (excl) high = rb_funcall(high, '-', 1, INT2FIX(1));
+ org_high = high;
- /*
- * This loop must continue while low + 1 < high.
- * Instead of checking low + 1 < high, check low < mid, where mid = (low + high) / 2.
- * This is to avoid the cost of calculating low + 1 on each iteration.
- * Note that this condition replacement is valid because Integer#div always rounds
- * towards negative infinity.
- */
- while (mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2)),
- rb_cmpint(rb_funcall(low, id_cmp, 1, mid), low, mid) < 0) {
+ while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) {
+ mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2));
BSEARCH_CHECK(mid);
if (smaller) {
high = mid;
}
else {
- low = mid;
+ low = rb_funcall(mid, '+', 1, INT2FIX(1));
}
}
+ if (rb_equal(low, org_high)) {
+ BSEARCH_CHECK(low);
+ if (!smaller) return Qnil;
+ }
return satisfied;
}
@@ -703,58 +696,52 @@ range_bsearch(VALUE range)
* by the mantissa. This is true with or without implicit bit.
*
* Finding the average of two ints needs to be careful about
- * potential overflow (since float to long can use 64 bits).
- *
- * The half-open interval (low, high] indicates where the target is located.
- * The loop continues until low and high are adjacent.
- *
- * -1/2 can be either 0 or -1 in C89. However, when low and high are not adjacent,
- * the rounding direction of mid = (low + high) / 2 does not affect the result of
- * the binary search.
+ * potential overflow (since float to long can use 64 bits)
+ * as well as the fact that -1/2 can be 0 or -1 in C89.
*
* Note that -0.0 is mapped to the same int as 0.0 as we don't want
* (-1...0.0).bsearch to yield -0.0.
*/
-#define BSEARCH(conv, excl) \
+#define BSEARCH(conv) \
do { \
RETURN_ENUMERATOR(range, 0, 0); \
- if (!(excl)) high++; \
- low--; \
- while (low + 1 < high) { \
+ if (EXCL(range)) high--; \
+ org_high = high; \
+ while (low < high) { \
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
- : (low + high) / 2; \
+ : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
BSEARCH_CHECK(conv(mid)); \
if (smaller) { \
high = mid; \
} \
else { \
- low = mid; \
+ low = mid + 1; \
} \
} \
+ if (low == org_high) { \
+ BSEARCH_CHECK(conv(low)); \
+ if (!smaller) return Qnil; \
+ } \
return satisfied; \
} while (0)
-#define BSEARCH_FIXNUM(beg, end, excl) \
- do { \
- long low = FIX2LONG(beg); \
- long high = FIX2LONG(end); \
- long mid; \
- BSEARCH(INT2FIX, (excl)); \
- } while (0)
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
- BSEARCH_FIXNUM(beg, end, EXCL(range));
+ long low = FIX2LONG(beg);
+ long high = FIX2LONG(end);
+ long mid, org_high;
+ BSEARCH(INT2FIX);
}
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
- int64_t mid;
- BSEARCH(int64_as_double_to_num, EXCL(range));
+ int64_t mid, org_high;
+ BSEARCH(int64_as_double_to_num);
}
#endif
else if (is_integer_p(beg) && is_integer_p(end)) {
@@ -768,15 +755,9 @@ range_bsearch(VALUE range)
VALUE mid = rb_funcall(beg, '+', 1, diff);
BSEARCH_CHECK(mid);
if (smaller) {
- if (FIXNUM_P(beg) && FIXNUM_P(mid)) {
- BSEARCH_FIXNUM(beg, mid, false);
- }
- else {
- return bsearch_integer_range(beg, mid, false);
- }
+ return bsearch_integer_range(beg, mid, 0);
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
- beg = mid;
}
}
else if (NIL_P(beg) && is_integer_p(end)) {
@@ -786,15 +767,9 @@ range_bsearch(VALUE range)
VALUE mid = rb_funcall(end, '+', 1, diff);
BSEARCH_CHECK(mid);
if (!smaller) {
- if (FIXNUM_P(mid) && FIXNUM_P(end)) {
- BSEARCH_FIXNUM(mid, end, false);
- }
- else {
- return bsearch_integer_range(mid, end, false);
- }
+ return bsearch_integer_range(mid, end, 0);
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
- end = mid;
}
}
else {
@@ -864,6 +839,7 @@ range_size(VALUE range)
* (1...4).to_a # => [1, 2, 3]
* ('a'..'d').to_a # => ["a", "b", "c", "d"]
*
+ * Range#entries is an alias for Range#to_a.
*/
static VALUE
@@ -1024,139 +1000,6 @@ range_each(VALUE range)
return range;
}
-RBIMPL_ATTR_NORETURN()
-static void
-range_reverse_each_bignum_beginless(VALUE end)
-{
- RUBY_ASSERT(RBIGNUM_NEGATIVE_P(end));
-
- for (;; end = rb_big_minus(end, INT2FIX(1))) {
- rb_yield(end);
- }
- UNREACHABLE;
-}
-
-static void
-range_reverse_each_bignum(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(RBIGNUM_POSITIVE_P(beg) == RBIGNUM_POSITIVE_P(end));
-
- VALUE c;
- while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) {
- rb_yield(end);
- if (c == INT2FIX(0)) break;
- end = rb_big_minus(end, INT2FIX(1));
- }
-}
-
-static void
-range_reverse_each_positive_bignum_section(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(!NIL_P(end));
-
- if (FIXNUM_P(end) || RBIGNUM_NEGATIVE_P(end)) return;
-
- if (NIL_P(beg) || FIXNUM_P(beg) || RBIGNUM_NEGATIVE_P(beg)) {
- beg = LONG2NUM(FIXNUM_MAX + 1);
- }
-
- range_reverse_each_bignum(beg, end);
-}
-
-static void
-range_reverse_each_fixnum_section(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(!NIL_P(end));
-
- if (!FIXNUM_P(beg)) {
- if (!NIL_P(beg) && RBIGNUM_POSITIVE_P(beg)) return;
-
- beg = LONG2FIX(FIXNUM_MIN);
- }
-
- if (!FIXNUM_P(end)) {
- if (RBIGNUM_NEGATIVE_P(end)) return;
-
- end = LONG2FIX(FIXNUM_MAX);
- }
-
- long b = FIX2LONG(beg);
- long e = FIX2LONG(end);
- for (long i = e; i >= b; --i) {
- rb_yield(LONG2FIX(i));
- }
-}
-
-static void
-range_reverse_each_negative_bignum_section(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(!NIL_P(end));
-
- if (FIXNUM_P(end) || RBIGNUM_POSITIVE_P(end)) {
- end = LONG2NUM(FIXNUM_MIN - 1);
- }
-
- if (NIL_P(beg)) {
- range_reverse_each_bignum_beginless(end);
- }
-
- if (FIXNUM_P(beg) || RBIGNUM_POSITIVE_P(beg)) return;
-
- range_reverse_each_bignum(beg, end);
-}
-
-/*
- * call-seq:
- * reverse_each {|element| ... } -> self
- * reverse_each -> an_enumerator
- *
- * With a block given, passes each element of +self+ to the block in reverse order:
- *
- * a = []
- * (1..4).reverse_each {|element| a.push(element) } # => 1..4
- * a # => [4, 3, 2, 1]
- *
- * a = []
- * (1...4).reverse_each {|element| a.push(element) } # => 1...4
- * a # => [3, 2, 1]
- *
- * With no block given, returns an enumerator.
- *
- */
-
-static VALUE
-range_reverse_each(VALUE range)
-{
- RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
-
- VALUE beg = RANGE_BEG(range);
- VALUE end = RANGE_END(range);
- int excl = EXCL(range);
-
- if (FIXNUM_P(beg) && FIXNUM_P(end)) {
- if (excl) {
- if (end == LONG2FIX(FIXNUM_MIN)) return range;
-
- end = rb_int_minus(end, INT2FIX(1));
- }
-
- range_reverse_each_fixnum_section(beg, end);
- }
- else if ((NIL_P(beg) || RB_INTEGER_TYPE_P(beg)) && RB_INTEGER_TYPE_P(end)) {
- if (excl) {
- end = rb_int_minus(end, INT2FIX(1));
- }
- range_reverse_each_positive_bignum_section(beg, end);
- range_reverse_each_fixnum_section(beg, end);
- range_reverse_each_negative_bignum_section(beg, end);
- }
- else {
- return rb_call_super(0, NULL);
- }
-
- return range;
-}
-
/*
* call-seq:
* self.begin -> object
@@ -1917,6 +1760,8 @@ range_eqq(VALUE range, VALUE val)
* ('a'..'d').cover?('cc') # => true
*
* Related: Range#cover?.
+ *
+ * Range#member? is an alias for Range#include?.
*/
static VALUE
@@ -2044,7 +1889,7 @@ static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
* r.cover?(0) # => false
* r.cover?(5) # => false
* r.cover?('foo') # => false
- *
+
* r = ('a'..'d')
* r.cover?('a') # => true
* r.cover?('d') # => true
@@ -2065,7 +1910,7 @@ static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
* r.cover?(0) # => false
* r.cover?(4) # => false
* r.cover?('foo') # => false
- *
+
* r = ('a'...'d')
* r.cover?('a') # => true
* r.cover?('c') # => true
@@ -2081,7 +1926,7 @@ static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
* r.cover?(0..4) # => false
* r.cover?(1..5) # => false
* r.cover?('a'..'d') # => false
- *
+
* r = (1...4)
* r.cover?(1..3) # => true
* r.cover?(1..4) # => false
@@ -2303,130 +2148,17 @@ range_count(int argc, VALUE *argv, VALUE range)
* Infinity. Just let it loop. */
return rb_call_super(argc, argv);
}
-
- VALUE beg = RANGE_BEG(range), end = RANGE_END(range);
-
- if (NIL_P(beg) || NIL_P(end)) {
+ else if (NIL_P(RANGE_END(range))) {
/* We are confident that the answer is Infinity. */
return DBL2NUM(HUGE_VAL);
}
-
- if (is_integer_p(beg)) {
- VALUE size = range_size(range);
- if (!NIL_P(size)) {
- return size;
- }
+ else if (NIL_P(RANGE_BEG(range))) {
+ /* We are confident that the answer is Infinity. */
+ return DBL2NUM(HUGE_VAL);
}
-
- return rb_call_super(argc, argv);
-}
-
-static bool
-empty_region_p(VALUE beg, VALUE end, int excl)
-{
- if (NIL_P(beg)) return false;
- if (NIL_P(end)) return false;
- int less = r_less(beg, end);
- /* empty range */
- if (less > 0) return true;
- if (excl && less == 0) return true;
- return false;
-}
-
-/*
- * call-seq:
- * overlap?(range) -> true or false
- *
- * Returns +true+ if +range+ overlaps with +self+, +false+ otherwise:
- *
- * (0..2).overlap?(1..3) #=> true
- * (0..2).overlap?(3..4) #=> false
- * (0..).overlap?(..0) #=> true
- *
- * With non-range argument, raises TypeError.
- *
- * (1..3).overlap?(1) # TypeError
- *
- * Returns +false+ if an internal call to <tt><=></tt> returns +nil+;
- * that is, the operands are not comparable.
- *
- * (1..3).overlap?('a'..'d') # => false
- *
- * Returns +false+ if +self+ or +range+ is empty. "Empty range" means
- * that its begin value is larger than, or equal for an exclusive
- * range, its end value.
- *
- * (4..1).overlap?(2..3) # => false
- * (4..1).overlap?(..3) # => false
- * (4..1).overlap?(2..) # => false
- * (2...2).overlap?(1..2) # => false
- *
- * (1..4).overlap?(3..2) # => false
- * (..4).overlap?(3..2) # => false
- * (1..).overlap?(3..2) # => false
- * (1..2).overlap?(2...2) # => false
- *
- * Returns +false+ if the begin value one of +self+ and +range+ is
- * larger than, or equal if the other is an exclusive range, the end
- * value of the other:
- *
- * (4..5).overlap?(2..3) # => false
- * (4..5).overlap?(2...4) # => false
- *
- * (1..2).overlap?(3..4) # => false
- * (1...3).overlap?(3..4) # => false
- *
- * Returns +false+ if the end value one of +self+ and +range+ is
- * larger than, or equal for an exclusive range, the end value of the
- * other:
- *
- * (4..5).overlap?(2..3) # => false
- * (4..5).overlap?(2...4) # => false
- *
- * (1..2).overlap?(3..4) # => false
- * (1...3).overlap?(3..4) # => false
- *
- * This method assumes that there is no minimum value because
- * Ruby lacks a standard method for determining minimum values.
- * This assumption is invalid.
- * For example, there is no value smaller than +-Float::INFINITY+,
- * making +(...-Float::INFINITY)+ an empty set.
- * Consequently, +(...-Float::INFINITY)+ has no elements in common with itself,
- * yet +(...-Float::INFINITY).overlap?((...-Float::INFINITY))+ returns
- * true due to this assumption.
- * In general, if +r = (...minimum); r.overlap?(r)+ returns +true+,
- * where +minimum+ is a value that no value is smaller than.
- * Such values include +-Float::INFINITY+, +[]+, +""+, and
- * classes without subclasses.
- *
- * Related: Range#cover?.
- */
-
-static VALUE
-range_overlap(VALUE range, VALUE other)
-{
- if (!rb_obj_is_kind_of(other, rb_cRange)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Range)",
- rb_class_name(rb_obj_class(other)));
+ else {
+ return rb_call_super(argc, argv);
}
-
- VALUE self_beg = RANGE_BEG(range);
- VALUE self_end = RANGE_END(range);
- int self_excl = EXCL(range);
- VALUE other_beg = RANGE_BEG(other);
- VALUE other_end = RANGE_END(other);
- int other_excl = EXCL(other);
-
- if (empty_region_p(self_beg, other_end, other_excl)) return Qfalse;
- if (empty_region_p(other_beg, self_end, self_excl)) return Qfalse;
-
- /* if both begin values are equal, no more comparisons needed */
- if (rb_equal(self_beg, other_beg)) return Qtrue;
-
- if (empty_region_p(self_beg, self_end, self_excl)) return Qfalse;
- if (empty_region_p(other_beg, other_end, other_excl)) return Qfalse;
-
- return Qtrue;
}
/* A \Range object represents a collection of values
@@ -2643,7 +2375,7 @@ range_overlap(VALUE range, VALUE other)
* - #%: Requires argument +n+; calls the block with each +n+-th element of +self+.
* - #each: Calls the block with each element of +self+.
* - #step: Takes optional argument +n+ (defaults to 1);
- * calls the block with each +n+-th element of +self+.
+ calls the block with each +n+-th element of +self+.
*
* === Methods for Converting
*
@@ -2675,7 +2407,6 @@ Init_Range(void)
rb_define_method(rb_cRange, "each", range_each, 0);
rb_define_method(rb_cRange, "step", range_step, -1);
rb_define_method(rb_cRange, "%", range_percent_step, 1);
- rb_define_method(rb_cRange, "reverse_each", range_reverse_each, 0);
rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
rb_define_method(rb_cRange, "begin", range_begin, 0);
rb_define_method(rb_cRange, "end", range_end, 0);
@@ -2696,5 +2427,4 @@ Init_Range(void)
rb_define_method(rb_cRange, "include?", range_include, 1);
rb_define_method(rb_cRange, "cover?", range_cover, 1);
rb_define_method(rb_cRange, "count", range_count, -1);
- rb_define_method(rb_cRange, "overlap?", range_overlap, 1);
}
diff --git a/rational.c b/rational.c
index c5ad7598f7..dfe2ad74eb 100644
--- a/rational.c
+++ b/rational.c
@@ -413,8 +413,7 @@ f_lcm(VALUE x, VALUE y)
inline static VALUE
nurat_s_new_internal(VALUE klass, VALUE num, VALUE den)
{
- NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL | (RGENGC_WB_PROTECTED_RATIONAL ? FL_WB_PROTECTED : 0),
- sizeof(struct RRational), 0);
+ NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL | (RGENGC_WB_PROTECTED_RATIONAL ? FL_WB_PROTECTED : 0));
RATIONAL_SET_NUM((VALUE)obj, num);
RATIONAL_SET_DEN((VALUE)obj, den);
@@ -1233,6 +1232,7 @@ nurat_negative_p(VALUE self)
* (1/2r).abs #=> (1/2)
* (-1/2r).abs #=> (1/2)
*
+ * Rational#magnitude is an alias for Rational#abs.
*/
VALUE
@@ -2104,12 +2104,9 @@ rb_float_denominator(VALUE self)
/*
* call-seq:
- * to_r -> (0/1)
- *
- * Returns zero as a Rational:
- *
- * nil.to_r # => (0/1)
+ * nil.to_r -> (0/1)
*
+ * Returns zero as a rational.
*/
static VALUE
nilclass_to_r(VALUE self)
@@ -2119,14 +2116,10 @@ nilclass_to_r(VALUE self)
/*
* call-seq:
- * rationalize(eps = nil) -> (0/1)
- *
- * Returns zero as a Rational:
- *
- * nil.rationalize # => (0/1)
- *
- * Argument +eps+ is ignored.
+ * nil.rationalize([eps]) -> (0/1)
*
+ * Returns zero as a rational. The optional argument +eps+ is always
+ * ignored.
*/
static VALUE
nilclass_rationalize(int argc, VALUE *argv, VALUE self)
diff --git a/re.c b/re.c
index 242b78a95f..f357d38c63 100644
--- a/re.c
+++ b/re.c
@@ -282,6 +282,7 @@ rb_memsearch(const void *x0, long m, const void *y0, long n, rb_encoding *enc)
return rb_memsearch_qs(x0, m, y0, n);
}
+#define REG_LITERAL FL_USER5
#define REG_ENCODING_NONE FL_USER6
#define KCODE_FIXED FL_USER4
@@ -538,7 +539,7 @@ static VALUE rb_reg_str_with_term(VALUE re, int term);
*
* The returned string may be used as an argument to Regexp.new,
* or as interpolated text for a
- * {Regexp interpolation}[rdoc-ref:regexp.rdoc@Interpolation+Mode]:
+ * {Regexp literal}[rdoc-ref:regexp.rdoc@Regexp+Literal]:
*
* r1 = Regexp.new(s0) # => /(?ix-m:ab+c)/
* r2 = /#{s0}/ # => /(?ix-m:ab+c)/
@@ -762,8 +763,8 @@ rb_reg_casefold_p(VALUE re)
* /foo/mix.options # => 7
*
* Note that additional bits may be set in the returned integer;
- * these are maintained internally in +self+, are ignored if passed
- * to Regexp.new, and may be ignored by the caller:
+ * these are maintained internally internally in +self+,
+ * are ignored if passed to Regexp.new, and may be ignored by the caller:
*
* Returns the set of bits corresponding to the options used when
* creating this regexp (see Regexp::new for details). Note that
@@ -961,13 +962,12 @@ VALUE rb_cMatch;
static VALUE
match_alloc(VALUE klass)
{
- size_t alloc_size = sizeof(struct RMatch) + sizeof(rb_matchext_t);
- VALUE flags = T_MATCH | (RGENGC_WB_PROTECTED_MATCH ? FL_WB_PROTECTED : 0);
- NEWOBJ_OF(match, struct RMatch, klass, flags, alloc_size, 0);
+ NEWOBJ_OF(match, struct RMatch, klass, T_MATCH);
- match->str = Qfalse;
- match->regexp = Qfalse;
- memset(RMATCH_EXT(match), 0, sizeof(rb_matchext_t));
+ match->str = 0;
+ match->rmatch = 0;
+ match->regexp = 0;
+ match->rmatch = ZALLOC(struct rmatch);
return (VALUE)match;
}
@@ -1002,7 +1002,7 @@ pair_byte_cmp(const void *pair1, const void *pair2)
static void
update_char_offset(VALUE match)
{
- rb_matchext_t *rm = RMATCH_EXT(match);
+ struct rmatch *rm = RMATCH(match)->rmatch;
struct re_registers *regs;
int i, num_regs, num_pos;
long c;
@@ -1080,23 +1080,23 @@ match_check(VALUE match)
static VALUE
match_init_copy(VALUE obj, VALUE orig)
{
- rb_matchext_t *rm;
+ struct rmatch *rm;
if (!OBJ_INIT_COPY(obj, orig)) return obj;
- RB_OBJ_WRITE(obj, &RMATCH(obj)->str, RMATCH(orig)->str);
- RB_OBJ_WRITE(obj, &RMATCH(obj)->regexp, RMATCH(orig)->regexp);
+ RMATCH(obj)->str = RMATCH(orig)->str;
+ RMATCH(obj)->regexp = RMATCH(orig)->regexp;
- rm = RMATCH_EXT(obj);
+ rm = RMATCH(obj)->rmatch;
if (rb_reg_region_copy(&rm->regs, RMATCH_REGS(orig)))
rb_memerror();
- if (RMATCH_EXT(orig)->char_offset_num_allocated) {
+ if (RMATCH(orig)->rmatch->char_offset_num_allocated) {
if (rm->char_offset_num_allocated < rm->regs.num_regs) {
REALLOC_N(rm->char_offset, struct rmatch_offset, rm->regs.num_regs);
rm->char_offset_num_allocated = rm->regs.num_regs;
}
- MEMCPY(rm->char_offset, RMATCH_EXT(orig)->char_offset,
+ MEMCPY(rm->char_offset, RMATCH(orig)->rmatch->char_offset,
struct rmatch_offset, rm->regs.num_regs);
RB_GC_GUARD(orig);
}
@@ -1125,7 +1125,7 @@ match_regexp(VALUE match)
if (NIL_P(regexp)) {
VALUE str = rb_reg_nth_match(0, match);
regexp = rb_reg_regcomp(rb_reg_quote(str));
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, regexp);
+ RMATCH(match)->regexp = regexp;
}
return regexp;
}
@@ -1170,6 +1170,8 @@ match_names(VALUE match)
* # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
* m.size # => 5
*
+ * MatchData#length is an alias for MatchData.size.
+ *
*/
static VALUE
@@ -1251,8 +1253,8 @@ match_offset(VALUE match, VALUE n)
return rb_assoc_new(Qnil, Qnil);
update_char_offset(match);
- return rb_assoc_new(LONG2NUM(RMATCH_EXT(match)->char_offset[i].beg),
- LONG2NUM(RMATCH_EXT(match)->char_offset[i].end));
+ return rb_assoc_new(LONG2NUM(RMATCH(match)->rmatch->char_offset[i].beg),
+ LONG2NUM(RMATCH(match)->rmatch->char_offset[i].end));
}
/*
@@ -1310,7 +1312,7 @@ match_begin(VALUE match, VALUE n)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].beg);
+ return LONG2NUM(RMATCH(match)->rmatch->char_offset[i].beg);
}
@@ -1336,7 +1338,7 @@ match_end(VALUE match, VALUE n)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].end);
+ return LONG2NUM(RMATCH(match)->rmatch->char_offset[i].end);
}
/*
@@ -1423,7 +1425,7 @@ match_nth_length(VALUE match, VALUE n)
update_char_offset(match);
const struct rmatch_offset *const ofs =
- &RMATCH_EXT(match)->char_offset[i];
+ &RMATCH(match)->rmatch->char_offset[i];
return LONG2NUM(ofs->end - ofs->beg);
}
@@ -1451,14 +1453,31 @@ rb_match_count(VALUE match)
return regs->num_regs;
}
+int
+rb_match_nth_defined(int nth, VALUE match)
+{
+ struct re_registers *regs;
+ if (NIL_P(match)) return FALSE;
+ regs = RMATCH_REGS(match);
+ if (!regs) return FALSE;
+ if (nth >= regs->num_regs) {
+ return FALSE;
+ }
+ if (nth < 0) {
+ nth += regs->num_regs;
+ if (nth <= 0) return FALSE;
+ }
+ return (BEG(nth) != -1);
+}
+
static void
match_set_string(VALUE m, VALUE string, long pos, long len)
{
struct RMatch *match = (struct RMatch *)m;
- rb_matchext_t *rmatch = RMATCH_EXT(match);
+ struct rmatch *rmatch = match->rmatch;
- RB_OBJ_WRITE(match, &RMATCH(match)->str, string);
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, Qnil);
+ match->str = string;
+ match->regexp = Qnil;
int err = onig_region_resize(&rmatch->regs, 1);
if (err) rb_memerror();
rmatch->regs.beg[0] = pos;
@@ -1576,8 +1595,9 @@ rb_reg_prepare_enc(VALUE re, VALUE str, int warn)
}
regex_t *
-rb_reg_prepare_re(VALUE re, VALUE str)
+rb_reg_prepare_re0(VALUE re, VALUE str, onig_errmsg_buffer err)
{
+ regex_t *reg = RREGEXP_PTR(re);
int r;
OnigErrorInfo einfo;
const char *pattern;
@@ -1585,13 +1605,12 @@ rb_reg_prepare_re(VALUE re, VALUE str)
rb_encoding *fixed_enc = 0;
rb_encoding *enc = rb_reg_prepare_enc(re, str, 1);
- regex_t *reg = RREGEXP_PTR(re);
if (reg->enc == enc) return reg;
rb_reg_check(re);
+ reg = RREGEXP_PTR(re);
pattern = RREGEXP_SRC_PTR(re);
- onig_errmsg_buffer err = "";
unescaped = rb_reg_preprocess(
pattern, pattern + RREGEXP_SRC_LEN(re), enc,
&fixed_enc, err, 0);
@@ -1606,30 +1625,9 @@ rb_reg_prepare_re(VALUE re, VALUE str)
const char *ptr;
long len;
RSTRING_GETMEM(unescaped, ptr, len);
-
- /* If there are no other users of this regex, then we can directly overwrite it. */
- if (RREGEXP(re)->usecnt == 0) {
- regex_t tmp_reg;
- r = onig_new_without_alloc(&tmp_reg, (UChar *)ptr, (UChar *)(ptr + len),
- reg->options, enc,
- OnigDefaultSyntax, &einfo);
-
- if (r) {
- /* There was an error so perform cleanups. */
- onig_free_body(&tmp_reg);
- }
- else {
- onig_free_body(reg);
- /* There are no errors so set reg to tmp_reg. */
- *reg = tmp_reg;
- }
- }
- else {
- r = onig_new(&reg, (UChar *)ptr, (UChar *)(ptr + len),
- reg->options, enc,
- OnigDefaultSyntax, &einfo);
- }
-
+ r = onig_new(&reg, (UChar *)ptr, (UChar *)(ptr + len),
+ reg->options, enc,
+ OnigDefaultSyntax, &einfo);
if (r) {
onig_error_code_to_str((UChar*)err, r, &einfo);
rb_reg_raise(pattern, RREGEXP_SRC_LEN(re), err, re);
@@ -1641,34 +1639,11 @@ rb_reg_prepare_re(VALUE re, VALUE str)
return reg;
}
-OnigPosition
-rb_reg_onig_match(VALUE re, VALUE str,
- OnigPosition (*match)(regex_t *reg, VALUE str, struct re_registers *regs, void *args),
- void *args, struct re_registers *regs)
+regex_t *
+rb_reg_prepare_re(VALUE re, VALUE str)
{
- regex_t *reg = rb_reg_prepare_re(re, str);
-
- bool tmpreg = reg != RREGEXP_PTR(re);
- if (!tmpreg) RREGEXP(re)->usecnt++;
-
- OnigPosition result = match(reg, str, regs, args);
-
- if (!tmpreg) RREGEXP(re)->usecnt--;
- if (tmpreg) {
- onig_free(reg);
- }
-
- if (result < 0) {
- onig_region_free(regs, 0);
-
- if (result != ONIG_MISMATCH) {
- onig_errmsg_buffer err = "";
- onig_error_code_to_str((UChar*)err, (int)result);
- rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re);
- }
- }
-
- return result;
+ onig_errmsg_buffer err = "";
+ return rb_reg_prepare_re0(re, str, err);
}
long
@@ -1702,55 +1677,68 @@ rb_reg_adjust_startpos(VALUE re, VALUE str, long pos, int reverse)
return pos;
}
-struct reg_onig_search_args {
- long pos;
- long range;
-};
-
-static OnigPosition
-reg_onig_search(regex_t *reg, VALUE str, struct re_registers *regs, void *args_ptr)
-{
- struct reg_onig_search_args *args = (struct reg_onig_search_args *)args_ptr;
- const char *ptr;
- long len;
- RSTRING_GETMEM(str, ptr, len);
-
- return onig_search(
- reg,
- (UChar *)ptr,
- (UChar *)(ptr + len),
- (UChar *)(ptr + args->pos),
- (UChar *)(ptr + args->range),
- regs,
- ONIG_OPTION_NONE);
-}
-
/* returns byte offset */
static long
rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_backref_str, VALUE *set_match)
{
- long len = RSTRING_LEN(str);
+ long result;
+ VALUE match;
+ struct re_registers regi, *regs = &regi;
+ char *start, *range;
+ long len;
+ regex_t *reg;
+ int tmpreg;
+ onig_errmsg_buffer err = "";
+
+ RSTRING_GETMEM(str, start, len);
+ range = start;
if (pos > len || pos < 0) {
rb_backref_set(Qnil);
return -1;
}
- struct reg_onig_search_args args = {
- .pos = pos,
- .range = reverse ? 0 : len,
- };
-
- VALUE match = match_alloc(rb_cMatch);
- struct re_registers *regs = RMATCH_REGS(match);
+ reg = rb_reg_prepare_re0(re, str, err);
+ tmpreg = reg != RREGEXP_PTR(re);
+ if (!tmpreg) RREGEXP(re)->usecnt++;
- OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, regs);
- if (result == ONIG_MISMATCH) {
- rb_backref_set(Qnil);
- return ONIG_MISMATCH;
+ MEMZERO(regs, struct re_registers, 1);
+ if (!reverse) {
+ range += len;
+ }
+ result = onig_search(reg,
+ (UChar*)start,
+ ((UChar*)(start + len)),
+ ((UChar*)(start + pos)),
+ ((UChar*)range),
+ regs, ONIG_OPTION_NONE);
+ if (!tmpreg) RREGEXP(re)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(re)->usecnt) {
+ onig_free(reg);
+ }
+ else {
+ onig_free(RREGEXP_PTR(re));
+ RREGEXP_PTR(re) = reg;
+ }
}
+ if (result < 0) {
+ if (regs == &regi)
+ onig_region_free(regs, 0);
+ if (result == ONIG_MISMATCH) {
+ rb_backref_set(Qnil);
+ return result;
+ }
+ else {
+ onig_error_code_to_str((UChar*)err, (int)result);
+ rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re);
+ }
+ }
+
+ match = match_alloc(rb_cMatch);
+ memcpy(RMATCH_REGS(match), regs, sizeof(struct re_registers));
if (set_backref_str) {
- RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
+ RMATCH(match)->str = rb_str_new4(str);
}
else {
/* Note that a MatchData object with RMATCH(match)->str == 0 is incomplete!
@@ -1760,7 +1748,7 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
rb_obj_hide(match);
}
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
+ RMATCH(match)->regexp = re;
rb_backref_set(match);
if (set_match) *set_match = match;
@@ -1779,39 +1767,74 @@ rb_reg_search(VALUE re, VALUE str, long pos, int reverse)
return rb_reg_search0(re, str, pos, reverse, 1);
}
-static OnigPosition
-reg_onig_match(regex_t *reg, VALUE str, struct re_registers *regs, void *_)
+bool
+rb_reg_start_with_p(VALUE re, VALUE str)
{
+ long result;
+ VALUE match;
+ struct re_registers regi, *regs = &regi;
+ regex_t *reg;
+ int tmpreg;
+ onig_errmsg_buffer err = "";
+
+ reg = rb_reg_prepare_re0(re, str, err);
+ tmpreg = reg != RREGEXP_PTR(re);
+ if (!tmpreg) RREGEXP(re)->usecnt++;
+
+ match = rb_backref_get();
+ if (!NIL_P(match)) {
+ if (FL_TEST(match, MATCH_BUSY)) {
+ match = Qnil;
+ }
+ else {
+ regs = RMATCH_REGS(match);
+ }
+ }
+ if (NIL_P(match)) {
+ MEMZERO(regs, struct re_registers, 1);
+ }
const char *ptr;
long len;
RSTRING_GETMEM(str, ptr, len);
+ result = onig_match(reg,
+ (UChar*)(ptr),
+ ((UChar*)(ptr + len)),
+ (UChar*)(ptr),
+ regs, ONIG_OPTION_NONE);
+ if (!tmpreg) RREGEXP(re)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(re)->usecnt) {
+ onig_free(reg);
+ }
+ else {
+ onig_free(RREGEXP_PTR(re));
+ RREGEXP_PTR(re) = reg;
+ }
+ }
+ if (result < 0) {
+ if (regs == &regi)
+ onig_region_free(regs, 0);
+ if (result == ONIG_MISMATCH) {
+ rb_backref_set(Qnil);
+ return false;
+ }
+ else {
+ onig_error_code_to_str((UChar*)err, (int)result);
+ rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re);
+ }
+ }
- return onig_match(
- reg,
- (UChar *)ptr,
- (UChar *)(ptr + len),
- (UChar *)ptr,
- regs,
- ONIG_OPTION_NONE);
-}
-
-bool
-rb_reg_start_with_p(VALUE re, VALUE str)
-{
- VALUE match = rb_backref_get();
- if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
+ if (NIL_P(match)) {
+ int err;
match = match_alloc(rb_cMatch);
+ err = rb_reg_region_copy(RMATCH_REGS(match), regs);
+ onig_region_free(regs, 0);
+ if (err) rb_memerror();
}
- struct re_registers *regs = RMATCH_REGS(match);
+ RMATCH(match)->str = rb_str_new4(str);
- if (rb_reg_onig_match(re, str, reg_onig_match, NULL, regs) == ONIG_MISMATCH) {
- rb_backref_set(Qnil);
- return false;
- }
-
- RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
+ RMATCH(match)->regexp = re;
rb_backref_set(match);
return true;
@@ -1933,37 +1956,21 @@ rb_reg_match_post(VALUE match)
return str;
}
-static int
-match_last_index(VALUE match)
+VALUE
+rb_reg_match_last(VALUE match)
{
int i;
struct re_registers *regs;
- if (NIL_P(match)) return -1;
+ if (NIL_P(match)) return Qnil;
match_check(match);
regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return -1;
+ if (BEG(0) == -1) return Qnil;
for (i=regs->num_regs-1; BEG(i) == -1 && i > 0; i--)
;
- return i;
-}
-
-VALUE
-rb_reg_match_last(VALUE match)
-{
- int i = match_last_index(match);
- if (i <= 0) return Qnil;
- struct re_registers *regs = RMATCH_REGS(match);
- return rb_str_subseq(RMATCH(match)->str, BEG(i), END(i) - BEG(i));
-}
-
-VALUE
-rb_reg_last_defined(VALUE match)
-{
- int i = match_last_index(match);
- if (i < 0) return Qnil;
- return RBOOL(i);
+ if (i == 0) return Qnil;
+ return rb_reg_nth_match(i, match);
}
static VALUE
@@ -2313,7 +2320,7 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
/*
* call-seq:
- * named_captures(symbolize_names: false) -> hash
+ * named_captures -> hash
*
* Returns a hash of the named captures;
* each key is a capture name; each value is its captured string or +nil+:
@@ -2334,17 +2341,10 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
* # => #<MatchData "01" a:"0" a:"1">
* m.named_captures #=> {"a" => "1"}
*
- * If keyword argument +symbolize_names+ is given
- * a true value, the keys in the resulting hash are Symbols:
- *
- * m = /(?<a>.)(?<a>.)/.match("01")
- * # => #<MatchData "01" a:"0" a:"1">
- * m.named_captures(symbolize_names: true) #=> {:a => "1"}
- *
*/
static VALUE
-match_named_captures(int argc, VALUE *argv, VALUE match)
+match_named_captures(VALUE match)
{
VALUE hash;
struct MEMO *memo;
@@ -2353,27 +2353,8 @@ match_named_captures(int argc, VALUE *argv, VALUE match)
if (NIL_P(RMATCH(match)->regexp))
return rb_hash_new();
- VALUE opt;
- VALUE symbolize_names = 0;
-
- rb_scan_args(argc, argv, "0:", &opt);
-
- if (!NIL_P(opt)) {
- static ID keyword_ids[1];
-
- VALUE symbolize_names_val;
-
- if (!keyword_ids[0]) {
- keyword_ids[0] = rb_intern_const("symbolize_names");
- }
- rb_get_kwargs(opt, keyword_ids, 0, 1, &symbolize_names_val);
- if (!UNDEF_P(symbolize_names_val) && RTEST(symbolize_names_val)) {
- symbolize_names = 1;
- }
- }
-
hash = rb_hash_new();
- memo = MEMO_NEW(hash, match, symbolize_names);
+ memo = MEMO_NEW(hash, match, 0);
onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, (void*)memo);
@@ -2390,7 +2371,7 @@ match_named_captures(int argc, VALUE *argv, VALUE match)
* m.deconstruct_keys([:hours, :minutes]) # => {:hours => "18", :minutes => "37"}
* m.deconstruct_keys(nil) # => {:hours => "18", :minutes => "37", :seconds => "22"}
*
- * Returns an empty hash if no named captures were defined:
+ * Returns an empty hash of no named captures were defined:
*
* m = /(\d{2}):(\d{2}):(\d{2})/.match("18:37:22")
* m.deconstruct_keys(nil) # => {}
@@ -2489,10 +2470,10 @@ match_inspect_name_iter(const OnigUChar *name, const OnigUChar *name_end,
}
/*
- * call-seq:
- * inspect -> string
+ * call-seq:
+ * inspect -> string
*
- * Returns a string representation of +self+:
+ * Returns a string representation of +self+:
*
* m = /.$/.match("foo")
* # => #<MatchData "o">
@@ -2507,6 +2488,7 @@ match_inspect_name_iter(const OnigUChar *name, const OnigUChar *name_end,
* m.inspect # => "#<MatchData \"fo\" 1:\"f\" 2:nil 3:\"o\">"
*
* Related: MatchData#to_s.
+ *
*/
static VALUE
@@ -3209,15 +3191,6 @@ rb_reg_preprocess_dregexp(VALUE ary, int options)
return result;
}
-static void
-rb_reg_initialize_check(VALUE obj)
-{
- rb_check_frozen(obj);
- if (RREGEXP_PTR(obj)) {
- rb_raise(rb_eTypeError, "already initialized regexp");
- }
-}
-
static int
rb_reg_initialize(VALUE obj, const char *s, long len, rb_encoding *enc,
int options, onig_errmsg_buffer err,
@@ -3228,7 +3201,12 @@ rb_reg_initialize(VALUE obj, const char *s, long len, rb_encoding *enc,
rb_encoding *fixed_enc = 0;
rb_encoding *a_enc = rb_ascii8bit_encoding();
- rb_reg_initialize_check(obj);
+ rb_check_frozen(obj);
+ if (FL_TEST(obj, REG_LITERAL))
+ rb_raise(rb_eSecurityError, "can't modify literal regexp");
+ if (re->ptr)
+ rb_raise(rb_eTypeError, "already initialized regexp");
+ re->ptr = 0;
if (rb_enc_dummy_p(enc)) {
errcpy(err, "can't make regexp with dummy encoding");
@@ -3305,7 +3283,7 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
static VALUE
rb_reg_s_alloc(VALUE klass)
{
- NEWOBJ_OF(re, struct RRegexp, klass, T_REGEXP | (RGENGC_WB_PROTECTED_REGEXP ? FL_WB_PROTECTED : 0), sizeof(struct RRegexp), 0);
+ NEWOBJ_OF(re, struct RRegexp, klass, T_REGEXP | (RGENGC_WB_PROTECTED_REGEXP ? FL_WB_PROTECTED : 0));
re->ptr = 0;
RB_OBJ_WRITE(re, &re->src, 0);
@@ -3352,7 +3330,7 @@ rb_reg_init_str_enc(VALUE re, VALUE s, rb_encoding *enc, int options)
return re;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_reg_new_ary(VALUE ary, int opt)
{
VALUE re = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
@@ -3391,6 +3369,7 @@ rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
rb_set_errinfo(rb_reg_error_desc(str, options, err));
return Qnil;
}
+ FL_SET(re, REG_LITERAL);
rb_obj_freeze(re);
return re;
}
@@ -3450,6 +3429,8 @@ reg_hash(VALUE re)
* /foo/ == Regexp.new('food') # => false
* /foo/ == Regexp.new("abc".force_encoding("euc-jp")) # => false
*
+ * Regexp#eql? is an alias for Regexp#==.
+ *
*/
VALUE
@@ -3500,6 +3481,9 @@ match_hash(VALUE match)
* Returns +true+ if +object+ is another \MatchData object
* whose target string, regexp, match, and captures
* are the same as +self+, +false+ otherwise.
+ *
+ * MatchData#eql? is an alias for MatchData#==.
+ *
*/
static VALUE
@@ -3564,7 +3548,7 @@ reg_match_pos(VALUE re, VALUE *strp, long pos, VALUE* set_match)
* Returns the integer index (in characters) of the first match
* for +self+ and +string+, or +nil+ if none;
* also sets the
- * {rdoc-ref:Regexp global variables}[rdoc-ref:Regexp@Global+Variables]:
+ * {rdoc-ref:Regexp Global Variables}[rdoc-ref:Regexp@Regexp+Global+Variables]:
*
* /at/ =~ 'input data' # => 7
* $~ # => #<MatchData "at">
@@ -3577,7 +3561,7 @@ reg_match_pos(VALUE re, VALUE *strp, long pos, VALUE* set_match)
* - Is a regexp literal;
* see {Regexp Literals}[rdoc-ref:literals.rdoc@Regexp+Literals].
* - Does not contain interpolations;
- * see {Regexp interpolation}[rdoc-ref:Regexp@Interpolation+Mode].
+ * see {Regexp Interpolation}[rdoc-ref:Regexp@Regexp+Interpolation].
* - Is at the left of the expression.
*
* Example:
@@ -3780,6 +3764,12 @@ rb_reg_match_m_p(int argc, VALUE *argv, VALUE re)
VALUE
rb_reg_match_p(VALUE re, VALUE str, long pos)
{
+ regex_t *reg;
+ onig_errmsg_buffer err = "";
+ OnigPosition result;
+ const UChar *start, *end;
+ int tmpreg;
+
if (NIL_P(str)) return Qfalse;
str = SYMBOL_P(str) ? rb_sym2str(str) : StringValue(str);
if (pos) {
@@ -3794,13 +3784,33 @@ rb_reg_match_p(VALUE re, VALUE str, long pos)
pos = beg - RSTRING_PTR(str);
}
}
-
- struct reg_onig_search_args args = {
- .pos = pos,
- .range = RSTRING_LEN(str),
- };
-
- return rb_reg_onig_match(re, str, reg_onig_search, &args, NULL) == ONIG_MISMATCH ? Qfalse : Qtrue;
+ reg = rb_reg_prepare_re0(re, str, err);
+ tmpreg = reg != RREGEXP_PTR(re);
+ if (!tmpreg) RREGEXP(re)->usecnt++;
+ start = ((UChar*)RSTRING_PTR(str));
+ end = start + RSTRING_LEN(str);
+ result = onig_search(reg, start, end, start + pos, end,
+ NULL, ONIG_OPTION_NONE);
+ if (!tmpreg) RREGEXP(re)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(re)->usecnt) {
+ onig_free(reg);
+ }
+ else {
+ onig_free(RREGEXP_PTR(re));
+ RREGEXP_PTR(re) = reg;
+ }
+ }
+ if (result < 0) {
+ if (result == ONIG_MISMATCH) {
+ return Qfalse;
+ }
+ else {
+ onig_error_code_to_str((UChar*)err, (int)result);
+ rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re);
+ }
+ }
+ return Qtrue;
}
/*
@@ -3838,24 +3848,6 @@ set_timeout(rb_hrtime_t *hrt, VALUE timeout)
double2hrtime(hrt, timeout_d);
}
-static VALUE
-reg_copy(VALUE copy, VALUE orig)
-{
- int r;
- regex_t *re;
-
- rb_reg_initialize_check(copy);
- if ((r = onig_reg_copy(&re, RREGEXP_PTR(orig))) != 0) {
- /* ONIGERR_MEMORY only */
- rb_raise(rb_eRegexpError, "%s", onig_error_code_to_format(r));
- }
- RREGEXP_PTR(copy) = re;
- RB_OBJ_WRITE(copy, &RREGEXP(copy)->src, RREGEXP(orig)->src);
- RREGEXP_PTR(copy)->timelimit = RREGEXP_PTR(orig)->timelimit;
- rb_enc_copy(copy, orig);
- return copy;
-}
-
struct reg_init_args {
VALUE str;
VALUE timeout;
@@ -3886,7 +3878,7 @@ void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const ch
* Regexp.new('foo', 'i') # => /foo/i
* Regexp.new('foo', 'im') # => /foo/im
*
- * - The bit-wise OR of one or more of the constants
+ * - The logical OR of one or more of the constants
* Regexp::EXTENDED, Regexp::IGNORECASE, Regexp::MULTILINE, and
* Regexp::NOENCODING:
*
@@ -3898,8 +3890,6 @@ void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const ch
* Regexp.new('foo', flags) # => /foo/mix
*
* - +nil+ or +false+, which is ignored.
- * - Any other truthy value, in which case the regexp will be
- * case-insensitive.
*
* If optional keyword argument +timeout+ is given,
* its float value overrides the timeout interval for the class,
@@ -3919,20 +3909,17 @@ void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const ch
* r3 = Regexp.new(r, timeout: 3.14) # => /foo/m
* r3.timeout # => 3.14
*
+ * Regexp.compile is an alias for Regexp.new.
+ *
*/
static VALUE
rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
{
struct reg_init_args args;
- VALUE re = reg_extract_args(argc, argv, &args);
- if (NIL_P(re)) {
- reg_init_args(self, args.str, args.enc, args.flags);
- }
- else {
- reg_copy(self, re);
- }
+ reg_extract_args(argc, argv, &args);
+ reg_init_args(self, args.str, args.enc, args.flags);
set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout);
@@ -3944,10 +3931,10 @@ reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
{
int flags = 0;
rb_encoding *enc = 0;
- VALUE str, src, opts = Qundef, kwargs;
+ VALUE str, src, opts = Qundef, n_flag = Qundef, kwargs;
VALUE re = Qnil;
- rb_scan_args(argc, argv, "11:", &src, &opts, &kwargs);
+ argc = rb_scan_args(argc, argv, "12:", &src, &opts, &n_flag, &kwargs);
args->timeout = Qnil;
if (!NIL_P(kwargs)) {
@@ -3958,6 +3945,10 @@ reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
rb_get_kwargs(kwargs, keywords, 0, 1, &args->timeout);
}
+ if (argc == 3) {
+ rb_warn_deprecated_to_remove("3.3", "3rd argument to Regexp.new", "2nd argument");
+ }
+
if (RB_TYPE_P(src, T_REGEXP)) {
re = src;
@@ -3969,13 +3960,20 @@ reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
str = RREGEXP_SRC(re);
}
else {
- if (!NIL_P(opts)) {
+ if (!UNDEF_P(opts)) {
int f;
if (FIXNUM_P(opts)) flags = FIX2INT(opts);
else if ((f = str_to_option(opts)) >= 0) flags = f;
- else if (rb_bool_expected(opts, "ignorecase", FALSE))
+ else if (!NIL_P(opts) && rb_bool_expected(opts, "ignorecase", FALSE))
flags = ONIG_OPTION_IGNORECASE;
}
+ if (!NIL_OR_UNDEF_P(n_flag)) {
+ char *kcode = StringValuePtr(n_flag);
+ if (kcode[0] == 'n' || kcode[0] == 'N') {
+ enc = rb_ascii8bit_encoding();
+ flags |= ARG_ENCODING_NONE;
+ }
+ }
str = StringValue(src);
}
args->str = str;
@@ -4106,6 +4104,8 @@ rb_reg_quote(VALUE str)
* r = Regexp.new(Regexp.escape(s)) # => /\\\\\\\*\\\?\\\{\\\}\\\./
* r.match(s) # => #<MatchData "\\\\\\*\\?\\{\\}\\.">
*
+ * Regexp.quote is an alias for Regexp.escape.
+ *
*/
static VALUE
@@ -4355,7 +4355,7 @@ rb_reg_init_copy(VALUE copy, VALUE re)
{
if (!OBJ_INIT_COPY(copy, re)) return copy;
rb_reg_check(re);
- return reg_copy(copy, re);
+ return rb_reg_init_str(copy, RREGEXP_SRC(re), rb_reg_options(re));
}
VALUE
@@ -4529,7 +4529,7 @@ match_setter(VALUE val, ID _x, VALUE *_y)
*
* With no argument, returns the value of <tt>$!</tt>,
* which is the result of the most recent pattern match
- * (see {Regexp global variables}[rdoc-ref:Regexp@Global+Variables]):
+ * (see {Regexp Global Variables}[rdoc-ref:Regexp@Regexp+Global+Variables]):
*
* /c(.)t/ =~ 'cat' # => 0
* Regexp.last_match # => #<MatchData "cat" 1:"a">
@@ -4786,7 +4786,7 @@ Init_Regexp(void)
rb_define_method(rb_cMatch, "[]", match_aref, -1);
rb_define_method(rb_cMatch, "captures", match_captures, 0);
rb_define_alias(rb_cMatch, "deconstruct", "captures");
- rb_define_method(rb_cMatch, "named_captures", match_named_captures, -1);
+ rb_define_method(rb_cMatch, "named_captures", match_named_captures, 0);
rb_define_method(rb_cMatch, "deconstruct_keys", match_deconstruct_keys, 1);
rb_define_method(rb_cMatch, "values_at", match_values_at, -1);
rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0);
diff --git a/regcomp.c b/regcomp.c
index aaf5dc9991..be85d85f93 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -195,7 +195,8 @@ unset_addr_list_init(UnsetAddrList* uslist, int size)
static void
unset_addr_list_end(UnsetAddrList* uslist)
{
- xfree(uslist->us);
+ if (IS_NOT_NULL(uslist->us))
+ xfree(uslist->us);
}
static int
@@ -1273,10 +1274,6 @@ compile_length_enclose_node(EncloseNode* node, regex_t* reg)
break;
case ENCLOSE_STOP_BACKTRACK:
- /* Disable POP_STOP_BT optimization for simple repeat under the match cache */
- /* optimization because the match cache optimization pushes an extra item to */
- /* the stack and it breaks the assumption for this optimization. */
-#ifndef USE_MATCH_CACHE
if (IS_ENCLOSE_STOP_BT_SIMPLE_REPEAT(node)) {
QtfrNode* qn = NQTFR(node->target);
tlen = compile_length_tree(qn->target, reg);
@@ -1286,11 +1283,8 @@ compile_length_enclose_node(EncloseNode* node, regex_t* reg)
+ SIZE_OP_PUSH + tlen + SIZE_OP_POP + SIZE_OP_JUMP;
}
else {
-#endif
len = SIZE_OP_PUSH_STOP_BT + tlen + SIZE_OP_POP_STOP_BT;
-#ifndef USE_MATCH_CACHE
}
-#endif
break;
case ENCLOSE_CONDITION:
@@ -1402,10 +1396,6 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
break;
case ENCLOSE_STOP_BACKTRACK:
- /* Disable POP_STOP_BT optimization for simple repeat under the match cache */
- /* optimization because the match cache optimization pushes an extra item to */
- /* the stack and it breaks the assumption for this optimization. */
-#ifndef USE_MATCH_CACHE
if (IS_ENCLOSE_STOP_BT_SIMPLE_REPEAT(node)) {
QtfrNode* qn = NQTFR(node->target);
r = compile_tree_n_times(qn->target, qn->lower, reg);
@@ -1424,15 +1414,12 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
-((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP + (int )SIZE_OP_JUMP));
}
else {
-#endif
r = add_opcode(reg, OP_PUSH_STOP_BT);
if (r) return r;
r = compile_tree(node->target, reg);
if (r) return r;
r = add_opcode(reg, OP_POP_STOP_BT);
-#ifndef USE_MATCH_CACHE
}
-#endif
break;
case ENCLOSE_CONDITION:
@@ -5662,12 +5649,12 @@ extern void
onig_free_body(regex_t* reg)
{
if (IS_NOT_NULL(reg)) {
- xfree(reg->p);
- xfree(reg->exact);
- xfree(reg->int_map);
- xfree(reg->int_map_backward);
- xfree(reg->repeat_range);
- onig_free(reg->chain);
+ if (IS_NOT_NULL(reg->p)) xfree(reg->p);
+ if (IS_NOT_NULL(reg->exact)) xfree(reg->exact);
+ if (IS_NOT_NULL(reg->int_map)) xfree(reg->int_map);
+ if (IS_NOT_NULL(reg->int_map_backward)) xfree(reg->int_map_backward);
+ if (IS_NOT_NULL(reg->repeat_range)) xfree(reg->repeat_range);
+ if (IS_NOT_NULL(reg->chain)) onig_free(reg->chain);
#ifdef USE_NAMED_GROUP
onig_names_free(reg);
@@ -5684,80 +5671,6 @@ onig_free(regex_t* reg)
}
}
-static void*
-dup_copy(const void *ptr, size_t size)
-{
- void *newptr = xmalloc(size);
- if (IS_NOT_NULL(newptr)) {
- memcpy(newptr, ptr, size);
- }
- return newptr;
-}
-
-extern int
-onig_reg_copy(regex_t** nreg, regex_t* oreg)
-{
- if (IS_NOT_NULL(oreg)) {
- regex_t *reg = *nreg = (regex_t* )xmalloc(sizeof(regex_t));
- if (IS_NULL(reg)) return ONIGERR_MEMORY;
-
- *reg = *oreg;
-
-# define COPY_FAILED(mem, size) IS_NULL(reg->mem = dup_copy(reg->mem, size))
-
- if (IS_NOT_NULL(reg->exact)) {
- size_t exact_size = reg->exact_end - reg->exact;
- if (COPY_FAILED(exact, exact_size))
- goto err;
- (reg)->exact_end = (reg)->exact + exact_size;
- }
-
- if (IS_NOT_NULL(reg->int_map)) {
- if (COPY_FAILED(int_map, sizeof(int) * ONIG_CHAR_TABLE_SIZE))
- goto err_int_map;
- }
- if (IS_NOT_NULL(reg->int_map_backward)) {
- if (COPY_FAILED(int_map_backward, sizeof(int) * ONIG_CHAR_TABLE_SIZE))
- goto err_int_map_backward;
- }
- if (IS_NOT_NULL(reg->p)) {
- if (COPY_FAILED(p, reg->alloc))
- goto err_p;
- }
- if (IS_NOT_NULL(reg->repeat_range)) {
- if (COPY_FAILED(repeat_range, reg->repeat_range_alloc * sizeof(OnigRepeatRange)))
- goto err_repeat_range;
- }
- if (IS_NOT_NULL(reg->name_table)) {
- if (onig_names_copy(reg, oreg))
- goto err_name_table;
- }
- if (IS_NOT_NULL(reg->chain)) {
- if (onig_reg_copy(&reg->chain, reg->chain))
- goto err_chain;
- }
- return 0;
-# undef COPY_FAILED
-
- err_chain:
- onig_names_free(reg);
- err_name_table:
- xfree(reg->repeat_range);
- err_repeat_range:
- xfree(reg->p);
- err_p:
- xfree(reg->int_map_backward);
- err_int_map_backward:
- xfree(reg->int_map);
- err_int_map:
- xfree(reg->exact);
- err:
- xfree(reg);
- return ONIGERR_MEMORY;
- }
- return 0;
-}
-
#ifdef RUBY
size_t
onig_memsize(const regex_t *reg)
@@ -6014,8 +5927,8 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
}
onig_node_free(root);
- xfree(scan_env.mem_nodes_dynamic);
-
+ if (IS_NOT_NULL(scan_env.mem_nodes_dynamic))
+ xfree(scan_env.mem_nodes_dynamic);
return r;
}
@@ -6087,15 +6000,20 @@ onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
OnigOptionType option, OnigEncoding enc, const OnigSyntaxType* syntax,
OnigErrorInfo* einfo)
{
+ int r;
+
*reg = (regex_t* )xmalloc(sizeof(regex_t));
if (IS_NULL(*reg)) return ONIGERR_MEMORY;
- int r = onig_new_without_alloc(*reg, pattern, pattern_end, option, enc, syntax, einfo);
+ r = onig_reg_init(*reg, option, ONIGENC_CASE_FOLD_DEFAULT, enc, syntax);
+ if (r) goto err;
+
+ r = onig_compile(*reg, pattern, pattern_end, einfo);
if (r) {
+ err:
onig_free(*reg);
*reg = NULL;
}
-
return r;
}
diff --git a/regenc.c b/regenc.c
index fc131d2533..eb523e1ae5 100644
--- a/regenc.c
+++ b/regenc.c
@@ -57,7 +57,7 @@ onigenc_mbclen(const OnigUChar* p,const OnigUChar* e, OnigEncoding enc)
int ret = ONIGENC_PRECISE_MBC_ENC_LEN(enc, p, e);
if (ONIGENC_MBCLEN_CHARFOUND_P(ret)) {
ret = ONIGENC_MBCLEN_CHARFOUND_LEN(ret);
- if (ret > (int)(e - p)) ret = (int)(e - p); // just for case
+ if (p + ret > e) ret = (int)(e - p); // just for case
return ret;
}
else if (ONIGENC_MBCLEN_NEEDMORE_P(ret)) {
diff --git a/regenc.h b/regenc.h
index 352a8d7980..4b4d21a715 100644
--- a/regenc.h
+++ b/regenc.h
@@ -118,6 +118,11 @@ typedef struct {
typedef struct {
short int len;
+#if defined(__has_attribute)
+# if __has_attribute(nonstring)
+ __attribute__((nonstring))
+# endif
+#endif
const UChar name[6];
int ctype;
} PosixBracketEntryType;
diff --git a/regexec.c b/regexec.c
index f841fbffb5..47fc88c9c2 100644
--- a/regexec.c
+++ b/regexec.c
@@ -231,45 +231,22 @@ onig_get_capture_tree(OnigRegion* region)
}
#endif /* USE_CAPTURE_HISTORY */
-#ifdef USE_MATCH_CACHE
+#ifdef USE_CACHE_MATCH_OPT
-/*
-Glossary for "match cache"
-
-"match cache" or "match cache optimization"
-The `Regexp#match` optimization by using a cache.
-
-"cache opcode"
-A cachable opcode (e.g. `OP_PUSH`, `OP_REPEAT`, etc).
-It is corresponding to some cache points.
-
-"cache point"
-A cachable point on matching.
-Usually, one-to-one corresponding between a cache opcode and a cache point exists,
-but cache opcodes between `OP_REPEAT` and `OP_REPEAT_INC` have some corresponding
-cache points depending on repetition counts.
-
-"match cache point"
-A pair of a cache point and a position on an input string.
-We encode a match cache point to an integer value by the following equation:
-"match cache point" = "position on input string" * "total number of cache points" + "cache point"
-
-"match cache buffer"
-A bit-array for memoizing (recording) match cache points once backtracked.
-*/
-
-/* count the total number of cache opcodes for allocating a match cache buffer. */
+/* count number of jump-like opcodes for allocation of cache memory. */
static OnigPosition
-count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
+count_num_cache_opcode(regex_t* reg, long* num, long* table_size)
{
UChar* p = reg->p;
UChar* pend = p + reg->used;
LengthType len;
- MemNumType repeat_mem;
+ MemNumType mem;
+ MemNumType current_mem = -1;
+ long current_mem_num = 0;
OnigEncoding enc = reg->enc;
- MemNumType current_repeat_mem = -1;
- long num_cache_opcodes = 0;
- int lookaround_nesting = 0;
+
+ *num = 0;
+ *table_size = 0;
while (p < pend) {
switch (*p++) {
@@ -283,7 +260,7 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
case OP_EXACT4: p += 4; break;
case OP_EXACT5: p += 5; break;
case OP_EXACTN:
- GET_LENGTH_INC(len, p); p += len; break;
+ GET_LENGTH_INC(len, p); p += len; break;
case OP_EXACTMB2N1: p += 2; break;
case OP_EXACTMB2N2: p += 4; break;
case OP_EXACTMB2N3: p += 6; break;
@@ -298,7 +275,7 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
GET_LENGTH_INC(len, p);
p += mb_len * len;
}
- break;
+ break;
case OP_EXACT1_IC:
len = enclen(enc, p, pend); p += len; break;
@@ -307,7 +284,7 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
case OP_CCLASS:
case OP_CCLASS_NOT:
- p += SIZE_BITSET; break;
+ p += SIZE_BITSET; break;
case OP_CCLASS_MB:
case OP_CCLASS_MB_NOT:
GET_LENGTH_INC(len, p); p += len; break;
@@ -323,10 +300,10 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
break;
case OP_ANYCHAR_STAR:
case OP_ANYCHAR_ML_STAR:
- num_cache_opcodes++; break;
+ *num += 1; *table_size += 1; break;
case OP_ANYCHAR_STAR_PEEK_NEXT:
case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
- p++; num_cache_opcodes++; break;
+ p++; *num += 1; *table_size += 1; break;
case OP_WORD:
case OP_NOT_WORD:
@@ -359,7 +336,7 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
case OP_BACKREF_MULTI:
case OP_BACKREF_MULTI_IC:
case OP_BACKREF_WITH_LEVEL:
- goto impossible;
+ goto fail;
case OP_MEMORY_START:
case OP_MEMORY_START_PUSH:
@@ -367,12 +344,7 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
case OP_MEMORY_END_PUSH_REC:
case OP_MEMORY_END:
case OP_MEMORY_END_REC:
- p += SIZE_MEMNUM;
- // A memory (capture) in look-around is found.
- if (lookaround_nesting != 0) {
- goto impossible;
- }
- break;
+ p += SIZE_MEMNUM; break;
case OP_KEEP:
break;
@@ -380,122 +352,91 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
case OP_FAIL:
break;
case OP_JUMP:
- p += SIZE_RELADDR;
+ p += SIZE_RELADDR;
break;
case OP_PUSH:
- p += SIZE_RELADDR;
- num_cache_opcodes++;
+ p += SIZE_RELADDR;
+ *num += 1;
+ *table_size += 1;
break;
case OP_POP:
break;
case OP_PUSH_OR_JUMP_EXACT1:
case OP_PUSH_IF_PEEK_NEXT:
- p += SIZE_RELADDR + 1; num_cache_opcodes++; break;
+ p += SIZE_RELADDR + 1; *num += 1; *table_size += 1; break;
case OP_REPEAT:
case OP_REPEAT_NG:
- if (current_repeat_mem != -1) {
+ if (current_mem != -1) {
// A nested OP_REPEAT is not yet supported.
- goto impossible;
+ goto fail;
}
- GET_MEMNUM_INC(repeat_mem, p);
+ GET_MEMNUM_INC(mem, p);
p += SIZE_RELADDR;
- if (reg->repeat_range[repeat_mem].lower == 0) {
- num_cache_opcodes++;
+ if (reg->repeat_range[mem].lower == 0) {
+ *num += 1;
+ *table_size += 1;
}
- current_repeat_mem = repeat_mem;
+ reg->repeat_range[mem].base_num = *num;
+ current_mem = mem;
+ current_mem_num = *num;
break;
case OP_REPEAT_INC:
case OP_REPEAT_INC_NG:
- GET_MEMNUM_INC(repeat_mem, p);
- if (repeat_mem != current_repeat_mem) {
+ GET_MEMNUM_INC(mem, p);
+ if (mem != current_mem) {
// A lone or invalid OP_REPEAT_INC is found.
- goto impossible;
+ goto fail;
}
{
- OnigRepeatRange *repeat_range = &reg->repeat_range[repeat_mem];
+ long inner_num = *num - current_mem_num;
+ OnigRepeatRange *repeat_range = &reg->repeat_range[mem];
+ repeat_range->inner_num = inner_num;
+ *num -= inner_num;
+ *num += inner_num * repeat_range->lower + (inner_num + 1) * (repeat_range->upper == 0x7fffffff ? 1 : repeat_range->upper - repeat_range->lower);
if (repeat_range->lower < repeat_range->upper) {
- num_cache_opcodes++;
+ *table_size += 1;
}
- current_repeat_mem = -1;
+ current_mem = -1;
+ current_mem_num = 0;
}
break;
case OP_REPEAT_INC_SG:
case OP_REPEAT_INC_NG_SG:
- goto impossible;
+ // TODO: Support nested OP_REPEAT.
+ goto fail;
case OP_NULL_CHECK_START:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END:
- case OP_NULL_CHECK_END_MEMST_PUSH:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END_MEMST:
- p += SIZE_MEMNUM;
- break;
+ case OP_NULL_CHECK_END_MEMST_PUSH:
+ p += SIZE_MEMNUM; break;
case OP_PUSH_POS:
- if (lookaround_nesting < 0) {
- // A look-around nested in a atomic grouping is found.
- goto impossible;
- }
- lookaround_nesting++;
- break;
- case OP_PUSH_POS_NOT:
- if (lookaround_nesting < 0) {
- // A look-around nested in a atomic grouping is found.
- goto impossible;
- }
- p += SIZE_RELADDR;
- lookaround_nesting++;
- break;
- case OP_PUSH_LOOK_BEHIND_NOT:
- if (lookaround_nesting < 0) {
- // A look-around nested in a atomic grouping is found.
- goto impossible;
- }
- p += SIZE_RELADDR;
- p += SIZE_LENGTH;
- lookaround_nesting++;
- break;
case OP_POP_POS:
+ case OP_PUSH_POS_NOT:
case OP_FAIL_POS:
- case OP_FAIL_LOOK_BEHIND_NOT:
- lookaround_nesting--;
- break;
case OP_PUSH_STOP_BT:
- if (lookaround_nesting != 0) {
- // A nested atomic grouping is found.
- goto impossible;
- }
- lookaround_nesting++;
- lookaround_nesting *= -1;
- break;
case OP_POP_STOP_BT:
- lookaround_nesting *= -1;
- lookaround_nesting--;
- break;
case OP_LOOK_BEHIND:
- p += SIZE_LENGTH;
- break;
-
+ case OP_PUSH_LOOK_BEHIND_NOT:
+ case OP_FAIL_LOOK_BEHIND_NOT:
case OP_PUSH_ABSENT_POS:
case OP_ABSENT_END:
case OP_ABSENT:
- goto impossible;
+ goto fail;
case OP_CALL:
case OP_RETURN:
- goto impossible;
+ goto fail;
case OP_CONDITION:
- goto impossible;
+ goto fail;
case OP_STATE_CHECK_PUSH:
case OP_STATE_CHECK_PUSH_OR_JUMP:
case OP_STATE_CHECK:
case OP_STATE_CHECK_ANYCHAR_STAR:
case OP_STATE_CHECK_ANYCHAR_ML_STAR:
- goto impossible;
+ goto fail;
case OP_SET_OPTION_PUSH:
case OP_SET_OPTION:
@@ -503,62 +444,32 @@ count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
- *num_cache_opcodes_ptr = num_cache_opcodes;
return 0;
-impossible:
- *num_cache_opcodes_ptr = NUM_CACHE_OPCODES_IMPOSSIBLE;
+fail:
+ *num = NUM_CACHE_OPCODE_FAIL;
return 0;
bytecode_error:
return ONIGERR_UNDEFINED_BYTECODE;
}
-/* collect cache opcodes from the given regex program, and compute the total number of cache points. */
static OnigPosition
-init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num_cache_points_ptr)
+init_cache_index_table(regex_t* reg, OnigCacheIndex *table)
{
UChar* pbegin;
UChar* p = reg->p;
UChar* pend = p + reg->used;
LengthType len;
- MemNumType repeat_mem;
+ MemNumType mem;
+ MemNumType current_mem = -1;
+ long num = 0;
+ long current_mem_num = 0;
OnigEncoding enc = reg->enc;
- MemNumType current_repeat_mem = -1;
- long cache_point = 0;
- long num_cache_points_at_repeat = 0;
- int lookaround_nesting = 0;
- const OnigCacheOpcode* cache_opcodes_begin = cache_opcodes;
- OnigCacheOpcode* cache_opcodes_at_repeat = NULL;
-
-# define INC_CACHE_OPCODES do {\
- cache_opcodes->addr = pbegin;\
- cache_opcodes->cache_point = cache_point - num_cache_points_at_repeat;\
- cache_opcodes->outer_repeat_mem = current_repeat_mem;\
- cache_opcodes->num_cache_points_at_outer_repeat = num_cache_points_at_repeat;\
- cache_opcodes->num_cache_points_in_outer_repeat = 0;\
- cache_opcodes->lookaround_nesting = lookaround_nesting;\
- cache_point += lookaround_nesting > 0 ? 2 : 1;\
- cache_opcodes++;\
- } while (0)
-
-# define INC_LOOKAROUND_NESTING lookaround_nesting++
-# define DEC_LOOKAROUND_NESTING do {\
- UChar* match_addr = p - 1;\
- OnigCacheOpcode* cache_opcodes_in_lookaround = cache_opcodes - 1;\
- while (\
- cache_opcodes_in_lookaround >= cache_opcodes_begin &&\
- cache_opcodes_in_lookaround->lookaround_nesting == lookaround_nesting\
- ) {\
- cache_opcodes_in_lookaround->match_addr = match_addr;\
- cache_opcodes_in_lookaround--;\
- }\
- lookaround_nesting--;\
- } while (0)
while (p < pend) {
pbegin = p;
@@ -573,7 +484,7 @@ init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num
case OP_EXACT4: p += 4; break;
case OP_EXACT5: p += 5; break;
case OP_EXACTN:
- GET_LENGTH_INC(len, p); p += len; break;
+ GET_LENGTH_INC(len, p); p += len; break;
case OP_EXACTMB2N1: p += 2; break;
case OP_EXACTMB2N2: p += 4; break;
case OP_EXACTMB2N3: p += 6; break;
@@ -588,7 +499,7 @@ init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num
GET_LENGTH_INC(len, p);
p += mb_len * len;
}
- break;
+ break;
case OP_EXACT1_IC:
len = enclen(enc, p, pend); p += len; break;
@@ -597,7 +508,7 @@ init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num
case OP_CCLASS:
case OP_CCLASS_NOT:
- p += SIZE_BITSET; break;
+ p += SIZE_BITSET; break;
case OP_CCLASS_MB:
case OP_CCLASS_MB_NOT:
GET_LENGTH_INC(len, p); p += len; break;
@@ -613,12 +524,20 @@ init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num
break;
case OP_ANYCHAR_STAR:
case OP_ANYCHAR_ML_STAR:
- INC_CACHE_OPCODES;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_ANYCHAR_STAR_PEEK_NEXT:
case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
p++;
- INC_CACHE_OPCODES;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_WORD:
@@ -660,11 +579,7 @@ init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num
case OP_MEMORY_END_PUSH_REC:
case OP_MEMORY_END:
case OP_MEMORY_END_REC:
- p += SIZE_MEMNUM;
- if (lookaround_nesting != 0) {
- goto unexpected_bytecode_error;
- }
- break;
+ p += SIZE_MEMNUM; break;
case OP_KEEP:
break;
@@ -672,96 +587,79 @@ init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num
case OP_FAIL:
break;
case OP_JUMP:
- p += SIZE_RELADDR;
+ p += SIZE_RELADDR;
break;
case OP_PUSH:
- p += SIZE_RELADDR;
- INC_CACHE_OPCODES;
+ p += SIZE_RELADDR;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_POP:
break;
case OP_PUSH_OR_JUMP_EXACT1:
case OP_PUSH_IF_PEEK_NEXT:
p += SIZE_RELADDR + 1;
- INC_CACHE_OPCODES;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_REPEAT:
case OP_REPEAT_NG:
- GET_MEMNUM_INC(repeat_mem, p);
+ GET_MEMNUM_INC(mem, p);
p += SIZE_RELADDR;
- if (reg->repeat_range[repeat_mem].lower == 0) {
- INC_CACHE_OPCODES;
+ if (reg->repeat_range[mem].lower == 0) {
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = -1;
+ num++;
+ table++;
}
- current_repeat_mem = repeat_mem;
- num_cache_points_at_repeat = cache_point;
- cache_opcodes_at_repeat = cache_opcodes;
+ current_mem = mem;
+ current_mem_num = num;
break;
case OP_REPEAT_INC:
case OP_REPEAT_INC_NG:
- GET_MEMNUM_INC(repeat_mem, p);
+ GET_MEMNUM_INC(mem, p);
{
- long num_cache_points_in_repeat = cache_point - num_cache_points_at_repeat;
- OnigRepeatRange *repeat_range = &reg->repeat_range[repeat_mem];
+ long inner_num = num - current_mem_num;
+ OnigRepeatRange *repeat_range = &reg->repeat_range[mem];
if (repeat_range->lower < repeat_range->upper) {
- INC_CACHE_OPCODES;
- cache_point--;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = mem;
+ table++;
}
- cache_point -= num_cache_points_in_repeat;
- int repeat_bounds = repeat_range->upper == 0x7fffffff ? 1 : repeat_range->upper - repeat_range->lower;
- cache_point += num_cache_points_in_repeat * repeat_range->lower + (num_cache_points_in_repeat + 1) * repeat_bounds;
- OnigCacheOpcode* cache_opcodes_in_repeat = cache_opcodes - 1;
- while (cache_opcodes_at_repeat <= cache_opcodes_in_repeat) {
- cache_opcodes_in_repeat->num_cache_points_in_outer_repeat = num_cache_points_in_repeat;
- cache_opcodes_in_repeat--;
- }
- current_repeat_mem = -1;
- num_cache_points_at_repeat = 0;
- cache_opcodes_at_repeat = NULL;
+ num -= inner_num;
+ num += inner_num * repeat_range->lower + (inner_num + 1) * (repeat_range->upper == 0x7fffffff ? 1 : repeat_range->upper - repeat_range->lower);
+ current_mem = -1;
+ current_mem_num = 0;
}
break;
case OP_REPEAT_INC_SG:
case OP_REPEAT_INC_NG_SG:
+ // TODO: support OP_REPEAT opcodes.
goto unexpected_bytecode_error;
case OP_NULL_CHECK_START:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END:
- case OP_NULL_CHECK_END_MEMST_PUSH:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END_MEMST:
- p += SIZE_MEMNUM;
- break;
+ case OP_NULL_CHECK_END_MEMST_PUSH:
+ p += SIZE_MEMNUM; break;
case OP_PUSH_POS:
- INC_LOOKAROUND_NESTING;
- break;
- case OP_PUSH_POS_NOT:
- p += SIZE_RELADDR;
- INC_LOOKAROUND_NESTING;
- break;
- case OP_PUSH_LOOK_BEHIND_NOT:
- p += SIZE_RELADDR;
- p += SIZE_LENGTH;
- INC_LOOKAROUND_NESTING;
- break;
case OP_POP_POS:
+ case OP_PUSH_POS_NOT:
case OP_FAIL_POS:
- case OP_FAIL_LOOK_BEHIND_NOT:
- DEC_LOOKAROUND_NESTING;
- break;
case OP_PUSH_STOP_BT:
- INC_LOOKAROUND_NESTING;
- lookaround_nesting *= -1;
- break;
case OP_POP_STOP_BT:
- lookaround_nesting *= -1;
- DEC_LOOKAROUND_NESTING;
- break;
case OP_LOOK_BEHIND:
- p += SIZE_LENGTH;
- break;
-
+ case OP_PUSH_LOOK_BEHIND_NOT:
+ case OP_FAIL_LOOK_BEHIND_NOT:
+ case OP_PUSH_ABSENT_POS:
case OP_ABSENT_END:
case OP_ABSENT:
goto unexpected_bytecode_error;
@@ -786,11 +684,10 @@ init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes, long* num
break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
- *num_cache_points_ptr = cache_point;
return 0;
unexpected_bytecode_error:
@@ -799,21 +696,21 @@ unexpected_bytecode_error:
bytecode_error:
return ONIGERR_UNDEFINED_BYTECODE;
}
-#else
+#else /* USE_MATCH_CACHE */
static OnigPosition
-count_num_cache_opcodes(regex_t* reg, long* num_cache_opcodes)
+count_num_cache_opcode(regex_t* reg, long* num, long* table_size)
{
- *num_cache_opcodes = NUM_CACHE_OPCODES_IMPOSSIBLE;
+ *num = NUM_CACHE_OPCODE_FAIL;
return 0;
}
-#endif /* USE_MATCH_CACHE */
+#endif
extern int
onig_check_linear_time(OnigRegexType* reg)
{
- long num_cache_opcodes = 0;
- count_num_cache_opcodes(reg, &num_cache_opcodes);
- return num_cache_opcodes != NUM_CACHE_OPCODES_IMPOSSIBLE;
+ long num = 0, table_size = 0;
+ count_num_cache_opcode(reg, &num, &table_size);
+ return num != NUM_CACHE_OPCODE_FAIL;
}
extern void
@@ -929,18 +826,14 @@ onig_region_free(OnigRegion* r, int free_self)
{
if (r) {
if (r->allocated > 0) {
- xfree(r->beg);
- xfree(r->end);
+ if (r->beg) xfree(r->beg);
+ if (r->end) xfree(r->end);
+ r->allocated = 0;
}
#ifdef USE_CAPTURE_HISTORY
history_root_free(r);
#endif
- if (free_self) {
- xfree(r);
- }
- else {
- memset(r, 0, sizeof(OnigRegion));
- }
+ if (free_self) xfree(r);
}
}
@@ -976,52 +869,48 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
/* stack type */
/* used by normal-POP */
-#define STK_ALT 0x0001
-#define STK_LOOK_BEHIND_NOT 0x0002
-#define STK_POS_NOT 0x0003
+#define STK_ALT 0x0001
+#define STK_LOOK_BEHIND_NOT 0x0002
+#define STK_POS_NOT 0x0003
/* handled by normal-POP */
-#define STK_MEM_START 0x0100
-#define STK_MEM_END 0x8200
-#define STK_REPEAT_INC 0x0300
-#define STK_STATE_CHECK_MARK 0x1000
+#define STK_MEM_START 0x0100
+#define STK_MEM_END 0x8200
+#define STK_REPEAT_INC 0x0300
+#define STK_STATE_CHECK_MARK 0x1000
/* avoided by normal-POP */
-#define STK_NULL_CHECK_START 0x3000
-#define STK_NULL_CHECK_END 0x5000 /* for recursive call */
-#define STK_MEM_END_MARK 0x8400
-#define STK_POS 0x0500 /* used when POP-POS */
-#define STK_STOP_BT 0x0600 /* mark for "(?>...)" */
-#define STK_REPEAT 0x0700
-#define STK_CALL_FRAME 0x0800
-#define STK_RETURN 0x0900
-#define STK_VOID 0x0a00 /* for fill a blank */
-#define STK_ABSENT_POS 0x0b00 /* for absent */
-#define STK_ABSENT 0x0c00 /* absent inner loop marker */
-#define STK_MATCH_CACHE_POINT 0x0d00 /* for the match cache optimization */
-#define STK_ATOMIC_MATCH_CACHE_POINT 0x0e00
+#define STK_NULL_CHECK_START 0x3000
+#define STK_NULL_CHECK_END 0x5000 /* for recursive call */
+#define STK_MEM_END_MARK 0x8400
+#define STK_POS 0x0500 /* used when POP-POS */
+#define STK_STOP_BT 0x0600 /* mark for "(?>...)" */
+#define STK_REPEAT 0x0700
+#define STK_CALL_FRAME 0x0800
+#define STK_RETURN 0x0900
+#define STK_VOID 0x0a00 /* for fill a blank */
+#define STK_ABSENT_POS 0x0b00 /* for absent */
+#define STK_ABSENT 0x0c00 /* absent inner loop marker */
/* stack type check mask */
-#define STK_MASK_POP_USED 0x00ff
-#define STK_MASK_TO_VOID_TARGET 0x10ff
-#define STK_MASK_MEM_END_OR_MARK 0x8000 /* MEM_END or MEM_END_MARK */
-
-#ifdef USE_MATCH_CACHE
-#define MATCH_ARG_INIT_MATCH_CACHE(msa) do {\
- (msa).match_cache_status = MATCH_CACHE_STATUS_UNINIT;\
- (msa).num_fails = 0;\
- (msa).num_cache_opcodes = NUM_CACHE_OPCODES_UNINIT;\
- (msa).cache_opcodes = (OnigCacheOpcode*)NULL;\
- (msa).num_cache_points = 0;\
- (msa).match_cache_buf = (uint8_t*)NULL;\
+#define STK_MASK_POP_USED 0x00ff
+#define STK_MASK_TO_VOID_TARGET 0x10ff
+#define STK_MASK_MEM_END_OR_MARK 0x8000 /* MEM_END or MEM_END_MARK */
+
+#ifdef USE_CACHE_MATCH_OPT
+#define MATCH_ARG_INIT_CACHE_MATCH_OPT(msa) do {\
+ (msa).enable_cache_match_opt = 0;\
+ (msa).num_fail = 0;\
+ (msa).num_cache_opcode = NUM_CACHE_OPCODE_UNINIT;\
+ (msa).num_cache_table = 0;\
+ (msa).cache_index_table = (OnigCacheIndex *)0;\
+ (msa).match_cache = (uint8_t *)0;\
} while(0)
-#define MATCH_ARG_FREE_MATCH_CACHE(msa) do {\
- xfree((msa).cache_opcodes);\
- xfree((msa).match_cache_buf);\
- (msa).cache_opcodes = (OnigCacheOpcode*)NULL;\
- (msa).match_cache_buf = (uint8_t*)NULL;\
+#define MATCH_ARG_FREE_CACHE_MATCH_OPT(msa) do {\
+ if ((msa).cache_index_table) xfree((msa).cache_index_table);\
+ if ((msa).match_cache) xfree((msa).match_cache);\
} while(0)
#else
-#define MATCH_ARG_INIT_MATCH_CACHE(msa)
-#define MATCH_ARG_FREE_MATCH_CACHE(msa)
+#define MATCH_ARG_INIT_CACHE_MATCH_OPT(msa)
+#define MATCH_ARG_FREE_CACHE_MATCH_OPT(msa)
#endif
#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
@@ -1034,7 +923,7 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
(msa).best_len = ONIG_MISMATCH;\
(msa).counter = 0;\
(msa).end_time = 0;\
- MATCH_ARG_INIT_MATCH_CACHE(msa);\
+ MATCH_ARG_INIT_CACHE_MATCH_OPT(msa);\
} while(0)
#else
# define MATCH_ARG_INIT(msa, arg_option, arg_region, arg_start, arg_gpos) do {\
@@ -1045,7 +934,7 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
(msa).gpos = (arg_gpos);\
(msa).counter = 0;\
(msa).end_time = 0;\
- MATCH_ARG_INIT_MATCH_CACHE(msa);\
+ MATCH_ARG_INIT_CACHE_MATCH_OPT(msa);\
} while(0)
#endif
@@ -1080,16 +969,16 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
} while(0)
# define MATCH_ARG_FREE(msa) do {\
- xfree((msa).stack_p);\
+ if ((msa).stack_p) xfree((msa).stack_p);\
if ((msa).state_check_buff_size >= STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE) { \
- xfree((msa).state_check_buff);\
+ if ((msa).state_check_buff) xfree((msa).state_check_buff);\
}\
- MATCH_ARG_FREE_MATCH_CACHE(msa);\
+ MATCH_ARG_FREE_CACHE_MATCH_OPT(msa);\
} while(0)
#else /* USE_COMBINATION_EXPLOSION_CHECK */
# define MATCH_ARG_FREE(msa) do {\
- xfree((msa).stack_p);\
- MATCH_ARG_FREE_MATCH_CACHE(msa);\
+ if ((msa).stack_p) xfree((msa).stack_p);\
+ MATCH_ARG_FREE_CACHE_MATCH_OPT(msa);\
} while (0)
#endif /* USE_COMBINATION_EXPLOSION_CHECK */
@@ -1200,7 +1089,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
int r = stack_double(&stk_base, &stk_end, &stk, stk_alloc, msa);\
if (r != 0) {\
STACK_SAVE;\
- xfree(xmalloc_base);\
+ if (xmalloc_base) xfree(xmalloc_base);\
return r;\
}\
}\
@@ -1306,6 +1195,129 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
#define STACK_PUSH_LOOK_BEHIND_NOT(pat,s,sprev,keep) \
STACK_PUSH(STK_LOOK_BEHIND_NOT,pat,s,sprev,keep)
+#ifdef USE_CACHE_MATCH_OPT
+
+#define DO_CACHE_MATCH_OPT(reg,stk,repeat_stk,enable,p,num_cache_table,num_cache_size,table,pos,match_cache) do {\
+ if (enable) {\
+ long cache_index = find_cache_index_table((reg), (stk), (repeat_stk), (table), (num_cache_table), (p));\
+ if (cache_index >= 0) {\
+ long key = (num_cache_size) * (long)(pos) + cache_index;\
+ long index = key >> 3;\
+ long mask = 1 << (key & 7);\
+ if ((match_cache)[index] & mask) {\
+ goto fail;\
+ }\
+ (match_cache)[index] |= mask;\
+ }\
+ }\
+} while (0)
+
+static long
+find_cache_index_table(regex_t* reg, OnigStackType *stk, OnigStackIndex *repeat_stk, OnigCacheIndex* table, long num_cache_table, UChar* p)
+{
+ long l = 0, r = num_cache_table - 1, m = 0;
+ OnigCacheIndex* item;
+ OnigRepeatRange* range;
+ OnigStackType *stkp;
+ int count = 0;
+ int is_inc = *p == OP_REPEAT_INC || *p == OP_REPEAT_INC_NG;
+
+ while (l <= r) {
+ m = (l + r) / 2;
+ if (table[m].addr == p) break;
+ if (table[m].addr < p) l = m + 1;
+ else r = m - 1;
+ }
+
+ if (!(0 <= m && m < num_cache_table && table[m].addr == p)) {
+ return -1;
+ }
+
+ item = &table[m];
+ if (item->outer_repeat == -1) {
+ return item->num;
+ }
+
+ range = &reg->repeat_range[item->outer_repeat];
+
+ stkp = &stk[repeat_stk[item->outer_repeat]];
+ count = is_inc ? stkp->u.repeat.count - 1 : stkp->u.repeat.count;
+
+ if (count < range->lower) {
+ return range->base_num + range->inner_num * count + item->num;
+ }
+
+ if (range->upper == 0x7fffffff) {
+ return range->base_num + range->inner_num * (range->lower - (is_inc ? 1 : 0)) + (is_inc ? 0 : 1) + item->num;
+ }
+
+ return range->base_num + range->inner_num * (range->lower - 1) + (range->inner_num + 1) * (count - range->lower + 1) + item->num;
+}
+
+static void
+reset_match_cache(regex_t* reg, UChar* pbegin, UChar* pend, long pos, uint8_t* match_cache, OnigCacheIndex *table, long num_cache_size, long num_cache_table)
+{
+ long l = 0, r = num_cache_table - 1, m1 = 0, m2 = 0;
+ int is_inc = *pend == OP_REPEAT_INC || *pend == OP_REPEAT_INC_NG;
+ OnigCacheIndex *item1, *item2;
+ long k1, k2, base;
+
+ while (l <= r) {
+ m1 = (l + r) / 2;
+ if (table[m1].addr == pbegin) break;
+ if (table[m1].addr < pbegin) l = m1 + 1;
+ else r = m1 - 1;
+ }
+
+ l = 0, r = num_cache_table - 1;
+ while (l <= r) {
+ m2 = (l + r) / 2;
+ if (table[m2].addr == pend) break;
+ if (table[m2].addr < pend) l = m2 + 1;
+ else r = m2 - 1;
+ }
+
+ if (table[m1].addr < pbegin && m1 + 1 < num_cache_table) m1++;
+ if (table[m2].addr > pend && m2 - 1 > 0) m2--;
+
+ item1 = &table[m1];
+ item2 = &table[m2];
+
+ if (item1->outer_repeat < 0) k1 = item1->num;
+ else k1 = reg->repeat_range[item1->outer_repeat].base_num + item1->num;
+
+ if (item2->outer_repeat < 0) k2 = item2->num;
+ else {
+ OnigRepeatRange *range = &reg->repeat_range[item2->outer_repeat];
+ if (range->upper == 0x7fffffff) k2 = range->base_num + range->inner_num * range->lower + (is_inc ? 0 : 1) + item2->num;
+ else k2 = range->base_num + range->inner_num * range->lower + (range->inner_num + 1) * (range->upper - range->lower - (is_inc ? 1 : 0)) + item2->num;
+ }
+
+ base = pos * num_cache_size;
+ k1 += base;
+ k2 += base;
+
+ if ((k1 >> 3) == (k2 >> 3)) {
+ match_cache[k1 >> 3] &= (((1 << (8 - (k2 & 7) - 1)) - 1) << ((k2 & 7) + 1)) | ((1 << (k1 & 7)) - 1);
+ } else {
+ long i = k1 >> 3;
+ if (k1 & 7) {
+ match_cache[k1 >> 3] &= (1 << ((k1 & 7) - 1)) - 1;
+ i++;
+ }
+ if (i < (k2 >> 3)) {
+ xmemset(&match_cache[i], 0, (k2 >> 3) - i);
+ if (k2 & 7) {
+ match_cache[k2 >> 3] &= (((1 << (8 - (k2 & 7) - 1)) - 1) << ((k2 & 7) + 1));
+ }
+ }
+ }
+}
+
+#else
+#define DO_CACHE_MATCH_OPT(reg,stk,repeat_stk,enable,p,num_cache_table,num_cache_size,table,pos,match_cache)
+#endif /* USE_CACHE_MATCH_OPT */
+
#define STACK_PUSH_REPEAT(id, pat) do {\
STACK_ENSURE(1);\
stk->type = STK_REPEAT;\
@@ -1432,15 +1444,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
STACK_INC;\
} while(0)
-#define STACK_PUSH_MATCH_CACHE_POINT(match_cache_point_index, match_cache_point_mask) do {\
- STACK_ENSURE(1);\
- stk->type = STK_MATCH_CACHE_POINT;\
- stk->null_check = stk == stk_base ? 0 : (stk-1)->null_check;\
- stk->u.match_cache_point.index = (match_cache_point_index);\
- stk->u.match_cache_point.mask = (match_cache_point_mask);\
- STACK_INC;\
-} while(0)
-
#ifdef ONIG_DEBUG
# define STACK_BASE_CHECK(p, at) \
@@ -1452,42 +1455,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
# define STACK_BASE_CHECK(p, at)
#endif
-#ifdef ONIG_DEBUG_MATCH_CACHE
-# define MATCH_CACHE_DEBUG_MEMOIZE(stkp) fprintf(stderr, "MATCH CACHE: memoize (index=%ld mask=%d)\n", stkp->u.match_cache_point.index, stkp->u.match_cache_point.mask);
-#else
-# define MATCH_CACHE_DEBUG_MEMOIZE(stkp) ((void) 0)
-#endif
-
-#ifdef USE_MATCH_CACHE
-# define INC_NUM_FAILS msa->num_fails++
-# define MEMOIZE_MATCH_CACHE_POINT do {\
- if (stk->type == STK_MATCH_CACHE_POINT) {\
- msa->match_cache_buf[stk->u.match_cache_point.index] |= stk->u.match_cache_point.mask;\
- MATCH_CACHE_DEBUG_MEMOIZE(stk);\
- } else if (stk->type == STK_ATOMIC_MATCH_CACHE_POINT) {\
- memoize_extended_match_cache_point(msa->match_cache_buf, stk->u.match_cache_point.index, stk->u.match_cache_point.mask);\
- MATCH_CACHE_DEBUG_MEMOIZE(stkp);\
- }\
- } while(0)
-# define MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT(stkp) do {\
- if (stkp->type == STK_MATCH_CACHE_POINT) {\
- stkp->type = STK_VOID;\
- memoize_extended_match_cache_point(msa->match_cache_buf, stkp->u.match_cache_point.index, stkp->u.match_cache_point.mask);\
- MATCH_CACHE_DEBUG_MEMOIZE(stkp);\
- }\
- } while(0)
-# define MEMOIZE_ATOMIC_MATCH_CACHE_POINT do {\
- if (stk->type == STK_MATCH_CACHE_POINT) {\
- memoize_extended_match_cache_point(msa->match_cache_buf, stk->u.match_cache_point.index, stk->u.match_cache_point.mask);\
- MATCH_CACHE_DEBUG_MEMOIZE(stkp);\
- }\
- } while(0)
-#else
-# define INC_NUM_FAILS ((void) 0)
-# define MEMOIZE_MATCH_CACHE_POINT ((void) 0)
-# define MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT ((void) 0)
-#endif
-
#define STACK_POP_ONE do {\
stk--;\
STACK_BASE_CHECK(stk, "STACK_POP_ONE"); \
@@ -1501,7 +1468,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
STACK_BASE_CHECK(stk, "STACK_POP"); \
if ((stk->type & STK_MASK_POP_USED) != 0) break;\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_MATCH_CACHE_POINT;\
}\
break;\
case STACK_POP_LEVEL_MEM_START:\
@@ -1514,7 +1480,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
mem_end_stk[stk->u.mem.num] = stk->u.mem.end;\
}\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_MATCH_CACHE_POINT;\
}\
break;\
default:\
@@ -1534,7 +1499,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
mem_end_stk[stk->u.mem.num] = stk->u.mem.end;\
}\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_MATCH_CACHE_POINT;\
}\
break;\
}\
@@ -1556,11 +1520,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
mem_start_stk[stk->u.mem.num] = stk->u.mem.start;\
mem_end_stk[stk->u.mem.num] = stk->u.mem.end;\
}\
- else if (IS_TO_VOID_TARGET(stk)) {\
- INC_NUM_FAILS;\
- }\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT(stk);\
}\
} while(0)
@@ -1617,14 +1577,12 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
k--;\
STACK_BASE_CHECK(k, "STACK_POS_END"); \
if (IS_TO_VOID_TARGET(k)) {\
- INC_NUM_FAILS;\
k->type = STK_VOID;\
}\
else if (k->type == STK_POS) {\
k->type = STK_VOID;\
break;\
}\
- MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT(k);\
}\
} while(0)
@@ -1634,28 +1592,12 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
k--;\
STACK_BASE_CHECK(k, "STACK_STOP_BT_END"); \
if (IS_TO_VOID_TARGET(k)) {\
- INC_NUM_FAILS;\
k->type = STK_VOID;\
}\
else if (k->type == STK_STOP_BT) {\
k->type = STK_VOID;\
break;\
}\
- else if (k->type == STK_MATCH_CACHE_POINT) {\
- k->type = STK_ATOMIC_MATCH_CACHE_POINT;\
- }\
- }\
-} while(0)
-
-#define STACK_STOP_BT_FAIL do {\
- while (1) {\
- stk--;\
- STACK_BASE_CHECK(stk, "STACK_STOP_BT_END"); \
- if (stk->type == STK_STOP_BT) {\
- stk->type = STK_VOID;\
- break;\
- }\
- MEMOIZE_ATOMIC_MATCH_CACHE_POINT;\
}\
} while(0)
@@ -1694,7 +1636,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
}\
} while(0)
-#define STACK_NULL_CHECK_MEMST(isnull,id,s,reg) do {\
+#define STACK_NULL_CHECK_MEMST(isnull,ischange,id,s,reg) do {\
OnigStackType* k = STACK_AT((stk-1)->null_check)+1;\
while (1) {\
k--;\
@@ -1711,14 +1653,14 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
while (k < stk) {\
if (k->type == STK_MEM_START) {\
if (k->u.mem.end == INVALID_STACK_INDEX) {\
- (isnull) = 0; break;\
+ (isnull) = 0; (ischange) = 1; break;\
}\
if (BIT_STATUS_AT(reg->bt_mem_end, k->u.mem.num))\
endp = STACK_AT(k->u.mem.end)->u.mem.pstr;\
else\
endp = (UChar* )k->u.mem.end;\
if (STACK_AT(k->u.mem.start)->u.mem.pstr != endp) {\
- (isnull) = 0; break;\
+ (isnull) = 0; (ischange) = 1; break;\
}\
else if (endp != s) {\
(isnull) = -1; /* empty, but position changed */ \
@@ -1890,6 +1832,19 @@ static int string_cmp_ic(OnigEncoding enc, int case_fold_flag,
# define ABSENT_END_POS end
#endif /* USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE */
+int onigenc_mbclen_approximate(const OnigUChar* p,const OnigUChar* e, const struct OnigEncodingTypeST* enc);
+
+static inline int
+enclen_approx(OnigEncoding enc, const OnigUChar* p, const OnigUChar* e)
+{
+ if (enc->max_enc_len == enc->min_enc_len) {
+ return (p < e ? enc->min_enc_len : 0);
+ }
+ else {
+ return onigenc_mbclen_approximate(p, e, enc);
+ }
+}
+
#ifdef USE_CAPTURE_HISTORY
static int
@@ -2101,7 +2056,7 @@ onig_print_statistics(FILE* f)
#ifdef ONIG_DEBUG_MATCH
-static const char *
+static char *
stack_type_str(int stack_type)
{
switch (stack_type) {
@@ -2123,97 +2078,10 @@ stack_type_str(int stack_type)
case STK_VOID: return "Void ";
case STK_ABSENT_POS: return "AbsPos";
case STK_ABSENT: return "Absent";
- case STK_MATCH_CACHE_POINT: return "MCache";
default: return " ";
}
}
#endif
-#ifdef USE_MATCH_CACHE
-
-static long
-bsearch_cache_opcodes(const OnigCacheOpcode *cache_opcodes, long num_cache_opcodes, const UChar* p)
-{
- long l = 0, r = num_cache_opcodes - 1, m = 0;
-
- while (l <= r) {
- m = (l + r) / 2;
- if (cache_opcodes[m].addr == p) break;
- if (cache_opcodes[m].addr < p) l = m + 1;
- else r = m - 1;
- }
- return m;
-}
-
-static long
-find_cache_point(regex_t* reg, const OnigCacheOpcode* cache_opcodes, long num_cache_opcodes, const UChar* p, const OnigStackType *stk, const OnigStackIndex *repeat_stk, const OnigCacheOpcode **cache_opcode_ptr)
-{
- long m;
- const OnigCacheOpcode* cache_opcode;
- const OnigRepeatRange* range;
- const OnigStackType *stkp;
- int count = 0;
- int is_inc = *p == OP_REPEAT_INC || *p == OP_REPEAT_INC_NG;
- long cache_point;
- long num_cache_points_at_outer_repeat;
- long num_cache_points_in_outer_repeat;
-
- m = bsearch_cache_opcodes(cache_opcodes, num_cache_opcodes, p);
-
- if (!(0 <= m && m < num_cache_opcodes && cache_opcodes[m].addr == p)) {
- return -1;
- }
-
- cache_opcode = &cache_opcodes[m];
- *cache_opcode_ptr = &cache_opcodes[m];
- cache_point = cache_opcode->cache_point;
- if (cache_opcode->outer_repeat_mem == -1) {
- return cache_point;
- }
-
- num_cache_points_at_outer_repeat = cache_opcode->num_cache_points_at_outer_repeat;
- num_cache_points_in_outer_repeat = cache_opcode->num_cache_points_in_outer_repeat;
-
- range = &reg->repeat_range[cache_opcode->outer_repeat_mem];
-
- stkp = &stk[repeat_stk[cache_opcode->outer_repeat_mem]];
- count = is_inc ? stkp->u.repeat.count - 1 : stkp->u.repeat.count;
-
- if (count < range->lower) {
- return num_cache_points_at_outer_repeat +
- num_cache_points_in_outer_repeat * count +
- cache_point;
- }
-
- if (range->upper == 0x7fffffff) {
- return num_cache_points_at_outer_repeat +
- num_cache_points_in_outer_repeat * (range->lower - (is_inc ? 1 : 0)) + (is_inc ? 0 : 1) +
- cache_point;
- }
-
- return num_cache_points_at_outer_repeat +
- num_cache_points_in_outer_repeat * (range->lower - 1) +
- (num_cache_points_in_outer_repeat + 1) * (count - range->lower + 1) +
- cache_point;
-}
-
-static int check_extended_match_cache_point(uint8_t *match_cache_buf, long match_cache_point_index, uint8_t match_cache_point_mask) {
- if (match_cache_point_mask & 0x80) {
- return (match_cache_buf[match_cache_point_index + 1] & 0x01) > 0;
- } else {
- return (match_cache_buf[match_cache_point_index] & (match_cache_point_mask << 1)) > 0;
- }
-}
-
-static void memoize_extended_match_cache_point(uint8_t *match_cache_buf, long match_cache_point_index, uint8_t match_cache_point_mask) {
- match_cache_buf[match_cache_point_index] |= match_cache_point_mask;
- if (match_cache_point_mask & 0x80) {
- match_cache_buf[match_cache_point_index + 1] |= 0x01;
- } else {
- match_cache_buf[match_cache_point_index] |= match_cache_point_mask << 1;
- }
-}
-
-#endif /* USE_MATCH_CACHE */
/* match data(str - end) from position (sstart). */
/* if sstart == str then set sprev to NULL. */
@@ -2522,47 +2390,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
# define OPCODE_EXEC_HOOK ((void) 0)
#endif
-#ifdef USE_MATCH_CACHE
-#ifdef ONIG_DEBUG_MATCH_CACHE
-#define MATCH_CACHE_DEBUG fprintf(stderr, "MATCH CACHE: cache %ld (p=%p index=%ld mask=%d)\n", match_cache_point, pbegin, match_cache_point_index, match_cache_point_mask)
-#define MATCH_CACHE_DEBUG_HIT fprintf(stderr, "MATCH CACHE: cache hit\n")
-#else
-#define MATCH_CACHE_DEBUG ((void) 0)
-#define MATCH_CACHE_DEBUG_HIT ((void) 0)
-#endif
-
-# define CHECK_MATCH_CACHE do {\
- if (msa->match_cache_status == MATCH_CACHE_STATUS_ENABLED) {\
- const OnigCacheOpcode *cache_opcode;\
- long cache_point = find_cache_point(reg, msa->cache_opcodes, msa->num_cache_opcodes, pbegin, stk_base, repeat_stk, &cache_opcode);\
- if (cache_point >= 0) {\
- long match_cache_point = msa->num_cache_points * (long)(s - str) + cache_point;\
- long match_cache_point_index = match_cache_point >> 3;\
- uint8_t match_cache_point_mask = 1 << (match_cache_point & 7);\
- MATCH_CACHE_DEBUG;\
- if (msa->match_cache_buf[match_cache_point_index] & match_cache_point_mask) {\
- MATCH_CACHE_DEBUG_HIT;\
- if (cache_opcode->lookaround_nesting == 0) goto fail;\
- else if (cache_opcode->lookaround_nesting < 0) {\
- if (check_extended_match_cache_point(msa->match_cache_buf, match_cache_point_index, match_cache_point_mask)) {\
- STACK_STOP_BT_FAIL;\
- goto fail;\
- } else goto fail;\
- } else {\
- if (check_extended_match_cache_point(msa->match_cache_buf, match_cache_point_index, match_cache_point_mask)) {\
- p = cache_opcode->match_addr;\
- MOP_OUT;\
- JUMP;\
- } else goto fail;\
- }\
- }\
- STACK_PUSH_MATCH_CACHE_POINT(match_cache_point_index, match_cache_point_mask);\
- }\
- }\
-} while (0)
-#else
-# define CHECK_MATCH_CACHE ((void) 0)
-#endif
VM_LOOP {
CASE(OP_END) MOP_IN(OP_END);
@@ -2868,7 +2695,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
int mb_len;
DATA_ENSURE(1);
- mb_len = enclen(encode, s, end);
+ mb_len = enclen_approx(encode, s, end);
DATA_ENSURE(mb_len);
ss = s;
s += mb_len;
@@ -2973,7 +2800,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR) MOP_IN(OP_ANYCHAR);
DATA_ENSURE(1);
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
s += n;
@@ -2982,7 +2809,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_ML) MOP_IN(OP_ANYCHAR_ML);
DATA_ENSURE(1);
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
DATA_ENSURE(n);
s += n;
MOP_OUT;
@@ -2990,9 +2817,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_STAR) MOP_IN(OP_ANYCHAR_STAR);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p, s, sprev, pkeep);
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
sprev = s;
@@ -3003,9 +2830,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_ML_STAR) MOP_IN(OP_ANYCHAR_ML_STAR);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p, s, sprev, pkeep);
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
if (n > 1) {
DATA_ENSURE(n);
sprev = s;
@@ -3021,17 +2848,17 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_STAR_PEEK_NEXT) MOP_IN(OP_ANYCHAR_STAR_PEEK_NEXT);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, end - s, msa->match_cache);
if (*p == *s) {
STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
} else {
-#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly. */
- /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR` simply in this case.*/
- msa->num_fails++;
+ /* We need to increment num_fail here, for invoking a cache optimization correctly. */
+ /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR` simply in this case.*/
+#ifdef USE_CACHE_MATCH_OPT
+ msa->num_fail++;
#endif
}
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
sprev = s;
@@ -3043,17 +2870,17 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_ML_STAR_PEEK_NEXT)MOP_IN(OP_ANYCHAR_ML_STAR_PEEK_NEXT);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
if (*p == *s) {
STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
} else {
-#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly. */
- /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR_ML` simply in this case.*/
- msa->num_fails++;
+ /* We need to increment num_fail here, for invoking a cache optimization correctly. */
+ /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR_ML` simply in this case.*/
+#ifdef USE_CACHE_MATCH_OPT
+ msa->num_fail++;
#endif
}
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
if (n > 1) {
DATA_ENSURE(n);
sprev = s;
@@ -3076,7 +2903,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
if (scv) goto fail;
STACK_PUSH_ALT_WITH_STATE_CHECK(p, s, sprev, mem, pkeep);
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
sprev = s;
@@ -3094,7 +2921,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
if (scv) goto fail;
STACK_PUSH_ALT_WITH_STATE_CHECK(p, s, sprev, mem, pkeep);
- n = enclen(encode, s, end);
+ n = enclen_approx(encode, s, end);
if (n > 1) {
DATA_ENSURE(n);
sprev = s;
@@ -3381,8 +3208,8 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_MEMORY_END_PUSH_REC) MOP_IN(OP_MEMORY_END_PUSH_REC);
GET_MEMNUM_INC(mem, p);
STACK_GET_MEM_START(mem, stkp); /* should be before push mem-end. */
- STACK_PUSH_MEM_END(mem, s);
mem_start_stk[mem] = GET_STACK_INDEX(stkp);
+ STACK_PUSH_MEM_END(mem, s);
MOP_OUT;
JUMP;
@@ -3436,7 +3263,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
DATA_ENSURE(n);
sprev = s;
STRING_CMP(pstart, s, n);
- while (sprev + (len = enclen(encode, sprev, end)) < s)
+ while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
sprev += len;
MOP_OUT;
@@ -3466,8 +3293,8 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
n = pend - pstart;
DATA_ENSURE(n);
sprev = s;
- STRING_CMP_IC(case_fold_flag, pstart, &s, (int)n, end);
- while (sprev + (len = enclen(encode, sprev, end)) < s)
+ STRING_CMP_IC(case_fold_flag, pstart, &s, n, end);
+ while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
sprev += len;
MOP_OUT;
@@ -3502,7 +3329,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STRING_CMP_VALUE(pstart, swork, n, is_fail);
if (is_fail) continue;
s = swork;
- while (sprev + (len = enclen(encode, sprev, end)) < s)
+ while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
sprev += len;
p += (SIZE_MEMNUM * (tlen - i - 1));
@@ -3637,9 +3464,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_NULL_CHECK_END_MEMST) MOP_IN(OP_NULL_CHECK_END_MEMST);
{
int isnull;
+ int ischanged = 0; // set 1 when a loop is empty but memory status is changed.
GET_MEMNUM_INC(mem, p); /* mem: null check id */
- STACK_NULL_CHECK_MEMST(isnull, mem, s, reg);
+ STACK_NULL_CHECK_MEMST(isnull, ischanged, mem, s, reg);
if (isnull) {
# ifdef ONIG_DEBUG_MATCH
fprintf(stderr, "NULL_CHECK_END_MEMST: skip id:%d, s:%"PRIuPTR" (%p)\n",
@@ -3648,6 +3476,29 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
if (isnull == -1) goto fail;
goto null_check_found;
}
+# ifdef USE_CACHE_MATCH_OPT
+ if (ischanged && msa->enable_cache_match_opt) {
+ RelAddrType rel;
+ OnigUChar *addr;
+ MemNumType mem;
+ UChar* tmp = p;
+ switch (*tmp++) {
+ case OP_JUMP:
+ case OP_PUSH:
+ GET_RELADDR_INC(rel, tmp);
+ addr = tmp + rel;
+ break;
+ case OP_REPEAT_INC:
+ case OP_REPEAT_INC_NG:
+ GET_MEMNUM_INC(mem, tmp);
+ addr = STACK_AT(repeat_stk[mem])->u.repeat.pcode;
+ break;
+ default:
+ goto unexpected_bytecode_error;
+ }
+ reset_match_cache(reg, addr, pbegin, (long)(s - str), msa->match_cache, msa->cache_index_table, msa->num_cache_opcode, msa->num_cache_table);
+ }
+# endif
}
MOP_OUT;
JUMP;
@@ -3690,7 +3541,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_PUSH) MOP_IN(OP_PUSH);
GET_RELADDR_INC(addr, p);
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
MOP_OUT;
JUMP;
@@ -3731,10 +3582,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_POP) MOP_IN(OP_POP);
STACK_POP_ONE;
-#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly, */
+ /* We need to increment num_fail here, for invoking a cache optimization correctly, */
/* because Onigmo makes a loop, which is pairwise disjoint to the following set, as atomic. */
- msa->num_fails++;
+#ifdef USE_CACHE_MATCH_OPT
+ msa->num_fail++;
#endif
MOP_OUT;
JUMP;
@@ -3744,7 +3595,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_RELADDR_INC(addr, p);
if (*p == *s && DATA_ENSURE_CHECK1) {
p++;
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
MOP_OUT;
JUMP;
@@ -3758,7 +3609,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_RELADDR_INC(addr, p);
if (*p == *s) {
p++;
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
MOP_OUT;
JUMP;
@@ -3777,7 +3628,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_PUSH_REPEAT(mem, p);
if (reg->repeat_range[mem].lower == 0) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, end - s, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
}
}
@@ -3794,7 +3645,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_PUSH_REPEAT(mem, p);
if (reg->repeat_range[mem].lower == 0) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p, s, sprev, pkeep);
p += addr;
}
@@ -3814,7 +3665,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
}
else if (stkp->u.repeat.count >= reg->repeat_range[mem].lower) {
if (*pbegin == OP_REPEAT_INC) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
}
STACK_PUSH_ALT(p, s, sprev, pkeep);
p = STACK_AT(si)->u.repeat.pcode; /* Don't use stkp after PUSH. */
@@ -3847,7 +3698,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_PUSH_REPEAT_INC(si);
if (*pbegin == OP_REPEAT_INC_NG) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
}
STACK_PUSH_ALT(pcode, s, sprev, pkeep);
}
@@ -4041,67 +3892,47 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
sprev = stk->u.state.pstr_prev;
pkeep = stk->u.state.pkeep;
-#ifdef USE_MATCH_CACHE
- if (
- msa->match_cache_status != MATCH_CACHE_STATUS_DISABLED &&
- ++msa->num_fails >= (long)(end - str) * msa->num_cache_opcodes
- ) {
- if (msa->match_cache_status == MATCH_CACHE_STATUS_UNINIT) {
- msa->match_cache_status = MATCH_CACHE_STATUS_INIT;
- OnigPosition r = count_num_cache_opcodes(reg, &msa->num_cache_opcodes);
- if (r < 0) goto bytecode_error;
- }
- if (msa->num_cache_opcodes == NUM_CACHE_OPCODES_IMPOSSIBLE || msa->num_cache_opcodes == 0) {
- msa->match_cache_status = MATCH_CACHE_STATUS_DISABLED;
- goto fail_match_cache;
+#ifdef USE_CACHE_MATCH_OPT
+ if (++msa->num_fail >= (long)(end - str) + 1 && msa->num_cache_opcode == NUM_CACHE_OPCODE_UNINIT) {
+ msa->enable_cache_match_opt = 1;
+ if (msa->num_cache_opcode == NUM_CACHE_OPCODE_UNINIT) {
+ OnigPosition r = count_num_cache_opcode(reg, &msa->num_cache_opcode, &msa->num_cache_table);
+ if (r < 0) goto bytecode_error;
}
- if (msa->num_fails < (long)(end - str) * msa->num_cache_opcodes) {
- goto fail_match_cache;
+ if (msa->num_cache_opcode == NUM_CACHE_OPCODE_FAIL || msa->num_cache_opcode == 0) {
+ msa->enable_cache_match_opt = 0;
+ goto fail_match_cache_opt;
}
- if (msa->cache_opcodes == NULL) {
- msa->match_cache_status = MATCH_CACHE_STATUS_ENABLED;
- OnigCacheOpcode* cache_opcodes = (OnigCacheOpcode*)xmalloc(msa->num_cache_opcodes * sizeof(OnigCacheOpcode));
- if (cache_opcodes == NULL) {
+ if (msa->cache_index_table == NULL) {
+ OnigCacheIndex *table = (OnigCacheIndex *)xmalloc(msa->num_cache_table * sizeof(OnigCacheIndex));
+ if (table == NULL) {
return ONIGERR_MEMORY;
}
- OnigPosition r = init_cache_opcodes(reg, cache_opcodes, &msa->num_cache_points);
- if (r < 0) {
- if (r == ONIGERR_UNEXPECTED_BYTECODE) goto unexpected_bytecode_error;
- else goto bytecode_error;
- }
- msa->cache_opcodes = cache_opcodes;
-#ifdef ONIG_DEBUG_MATCH_CACHE
- fprintf(stderr, "MATCH CACHE: #cache opcodes = %ld\n", msa->num_cache_opcodes);
- fprintf(stderr, "MATCH CACHE: #cache points = %ld\n", msa->num_cache_points);
- fprintf(stderr, "MATCH CACHE: cache opcodes (%p):\n", msa->cache_opcodes);
- for (int i = 0; i < msa->num_cache_opcodes; i++) {
- fprintf(stderr, "MATCH CACHE: [%p] cache_point=%ld outer_repeat_mem=%d num_cache_opcodes_at_outer_repeat=%ld num_cache_opcodes_in_outer_repeat=%ld lookaround_nesting=%d match_addr=%p\n", msa->cache_opcodes[i].addr, msa->cache_opcodes[i].cache_point, msa->cache_opcodes[i].outer_repeat_mem, msa->cache_opcodes[i].num_cache_points_at_outer_repeat, msa->cache_opcodes[i].num_cache_points_in_outer_repeat, msa->cache_opcodes[i].lookaround_nesting, msa->cache_opcodes[i].match_addr);
- }
-#endif
+ OnigPosition r = init_cache_index_table(reg, table);
+ if (r < 0) {
+ if (r == ONIGERR_UNEXPECTED_BYTECODE) goto unexpected_bytecode_error;
+ else goto bytecode_error;
+ }
+ msa->cache_index_table = table;
}
- if (msa->match_cache_buf == NULL) {
- size_t length = (end - str) + 1;
- size_t num_match_cache_points = (size_t)msa->num_cache_points * length;
-#ifdef ONIG_DEBUG_MATCH_CACHE
- fprintf(stderr, "MATCH CACHE: #match cache points = %ld (length = %zu)\n", num_match_cache_points, length);
-#endif
- /* Overflow check */
- if (num_match_cache_points / length != (size_t)msa->num_cache_points) {
- return ONIGERR_MEMORY;
- }
- if (num_match_cache_points >= LONG_MAX_LIMIT) {
- return ONIGERR_MEMORY;
- }
- size_t match_cache_buf_length = (num_match_cache_points >> 3) + (num_match_cache_points & 7 ? 1 : 0);
- uint8_t* match_cache_buf = (uint8_t*)xmalloc(match_cache_buf_length * sizeof(uint8_t));
- if (match_cache_buf == NULL) {
- return ONIGERR_MEMORY;
- }
- xmemset(match_cache_buf, 0, match_cache_buf_length * sizeof(uint8_t));
- msa->match_cache_buf = match_cache_buf;
+ size_t len = (end - str) + 1;
+ size_t match_cache_size8 = (size_t)msa->num_cache_opcode * len;
+ /* overflow check */
+ if (match_cache_size8 / len != (size_t)msa->num_cache_opcode) {
+ return ONIGERR_MEMORY;
+ }
+ /* Currently, int is used for the key of match_cache */
+ if (match_cache_size8 >= LONG_MAX_LIMIT) {
+ return ONIGERR_MEMORY;
+ }
+ size_t match_cache_size = (match_cache_size8 >> 3) + (match_cache_size8 & 7 ? 1 : 0);
+ msa->match_cache = (uint8_t*)xmalloc(match_cache_size * sizeof(uint8_t));
+ if (msa->match_cache == NULL) {
+ return ONIGERR_MEMORY;
}
+ xmemset(msa->match_cache, 0, match_cache_size * sizeof(uint8_t));
}
- fail_match_cache:
+ fail_match_cache_opt:
#endif
#ifdef USE_COMBINATION_EXPLOSION_CHECK
@@ -4121,24 +3952,24 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
finish:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return best_len;
#ifdef ONIG_DEBUG
stack_error:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return ONIGERR_STACK_BUG;
#endif
bytecode_error:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return ONIGERR_UNDEFINED_BYTECODE;
unexpected_bytecode_error:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return ONIGERR_UNEXPECTED_BYTECODE;
}
@@ -4840,12 +4671,17 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
UChar* range, UChar** low, UChar** high, UChar** low_prev)
{
UChar *p, *pprev = (UChar* )NULL;
+ size_t input_len = end - str;
#ifdef ONIG_DEBUG_SEARCH
fprintf(stderr, "forward_search_range: str: %"PRIuPTR" (%p), end: %"PRIuPTR" (%p), s: %"PRIuPTR" (%p), range: %"PRIuPTR" (%p)\n",
(uintptr_t )str, str, (uintptr_t )end, end, (uintptr_t )s, s, (uintptr_t )range, range);
#endif
+ if (reg->dmin > input_len) {
+ return 0;
+ }
+
p = s;
if (reg->dmin > 0) {
if (ONIGENC_IS_SINGLEBYTE(reg->enc)) {
@@ -4982,6 +4818,11 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end,
UChar** low, UChar** high)
{
UChar *p;
+ size_t input_len = end - str;
+
+ if (reg->dmin > input_len) {
+ return 0;
+ }
range += reg->dmin;
p = s;
diff --git a/regint.h b/regint.h
index 034a31426c..cee766ad6e 100644
--- a/regint.h
+++ b/regint.h
@@ -35,15 +35,19 @@
/* #define ONIG_DEBUG_COMPILE */
/* #define ONIG_DEBUG_SEARCH */
/* #define ONIG_DEBUG_MATCH */
-/* #define ONIG_DEBUG_MATCH_CACHE */
/* #define ONIG_DEBUG_MEMLEAK */
/* #define ONIG_DONT_OPTIMIZE */
/* for byte-code statistical data. */
/* #define ONIG_DEBUG_STATISTICS */
-/* enable the match optimization by using a cache. */
-#define USE_MATCH_CACHE
+/* enable matching optimization by using cache. */
+#define USE_CACHE_MATCH_OPT
+
+#ifdef USE_CACHE_MATCH_OPT
+# define NUM_CACHE_OPCODE_FAIL -1
+# define NUM_CACHE_OPCODE_UNINIT -2
+#endif
#if defined(ONIG_DEBUG_PARSE_TREE) || defined(ONIG_DEBUG_MATCH) || \
defined(ONIG_DEBUG_SEARCH) || defined(ONIG_DEBUG_COMPILE) || \
@@ -873,25 +877,15 @@ typedef struct _OnigStackType {
UChar *abs_pstr; /* absent start position */
const UChar *end_pstr; /* end position */
} absent_pos;
-#ifdef USE_MATCH_CACHE
- struct {
- long index; /* index of the match cache buffer */
- uint8_t mask; /* bit-mask for the match cache buffer */
- } match_cache_point;
-#endif
} u;
} OnigStackType;
-#ifdef USE_MATCH_CACHE
+#ifdef USE_CACHE_MATCH_OPT
typedef struct {
UChar *addr;
- long cache_point;
- int outer_repeat_mem;
- long num_cache_points_at_outer_repeat;
- long num_cache_points_in_outer_repeat;
- int lookaround_nesting;
- UChar *match_addr;
-} OnigCacheOpcode;
+ long num;
+ int outer_repeat;
+} OnigCacheIndex;
#endif
typedef struct {
@@ -916,23 +910,16 @@ typedef struct {
#else
uint64_t end_time;
#endif
-#ifdef USE_MATCH_CACHE
- int match_cache_status;
- long num_fails;
- long num_cache_opcodes;
- OnigCacheOpcode* cache_opcodes;
- long num_cache_points;
- uint8_t* match_cache_buf;
+#ifdef USE_CACHE_MATCH_OPT
+ long num_fail;
+ int enable_cache_match_opt;
+ long num_cache_opcode;
+ long num_cache_table;
+ OnigCacheIndex* cache_index_table;
+ uint8_t* match_cache;
#endif
} OnigMatchArg;
-#define NUM_CACHE_OPCODES_UNINIT 1
-#define NUM_CACHE_OPCODES_IMPOSSIBLE -1
-
-#define MATCH_CACHE_STATUS_UNINIT 1
-#define MATCH_CACHE_STATUS_INIT 2
-#define MATCH_CACHE_STATUS_DISABLED -1
-#define MATCH_CACHE_STATUS_ENABLED 0
#define IS_CODE_SB_WORD(enc,code) \
(ONIGENC_IS_CODE_ASCII(code) && ONIGENC_IS_CODE_WORD(enc,code))
diff --git a/regparse.c b/regparse.c
index 1ce15da8f5..33df0e06c7 100644
--- a/regparse.c
+++ b/regparse.c
@@ -142,7 +142,7 @@ static void
bbuf_free(BBuf* bbuf)
{
if (IS_NOT_NULL(bbuf)) {
- xfree(bbuf->p);
+ if (IS_NOT_NULL(bbuf->p)) xfree(bbuf->p);
xfree(bbuf);
}
}
@@ -251,7 +251,7 @@ bitset_copy(BitSetRef dest, BitSetRef bs)
#if defined(USE_NAMED_GROUP) && !defined(USE_ST_LIBRARY)
extern int
-onig_strncmp(const UChar* s1, const UChar* s2, size_t n)
+onig_strncmp(const UChar* s1, const UChar* s2, int n)
{
int x;
@@ -275,7 +275,7 @@ onig_strcpy(UChar* dest, const UChar* src, const UChar* end)
#ifdef USE_NAMED_GROUP
static UChar*
-strdup_with_null(OnigEncoding enc, const UChar* s, const UChar* end)
+strdup_with_null(OnigEncoding enc, UChar* s, UChar* end)
{
ptrdiff_t slen;
int term_len, i;
@@ -476,11 +476,8 @@ typedef st_data_t HashDataType; /* 1.6 st.h doesn't define st_data_t type */
# ifdef ONIG_DEBUG
static int
-i_print_name_entry(HashDataType key_, HashDataType e_, HashDataType arg_)
+i_print_name_entry(UChar* key, NameEntry* e, void* arg)
{
- UChar* key = (UChar *)key_;
- NameEntry* e = (NameEntry *)e_;
- void* arg = (void *)arg_;
int i;
FILE* fp = (FILE* )arg;
@@ -506,7 +503,7 @@ onig_print_names(FILE* fp, regex_t* reg)
if (IS_NOT_NULL(t)) {
fprintf(fp, "name table\n");
- onig_st_foreach(t, i_print_name_entry, (HashDataType )fp);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_print_name_entry, (HashDataType )fp);
fputs("\n", fp);
}
return 0;
@@ -514,12 +511,10 @@ onig_print_names(FILE* fp, regex_t* reg)
# endif /* ONIG_DEBUG */
static int
-i_free_name_entry(HashDataType key_, HashDataType e_, HashDataType arg_ ARG_UNUSED)
+i_free_name_entry(UChar* key, NameEntry* e, void* arg ARG_UNUSED)
{
- UChar* key = (UChar *)key_;
- NameEntry* e = (NameEntry *)e_;
xfree(e->name);
- xfree(e->back_refs);
+ if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
xfree(key);
xfree(e);
return ST_DELETE;
@@ -531,7 +526,7 @@ names_clear(regex_t* reg)
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
- onig_st_foreach(t, i_free_name_entry, 0);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_free_name_entry, 0);
}
return 0;
}
@@ -551,58 +546,6 @@ onig_names_free(regex_t* reg)
return 0;
}
-static int
-copy_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
- int back_num, int *back_refs, OnigRegex regex, void *arg)
-{
- NameTable *copy_table = (NameTable *)arg;
- NameEntry *entry_copy = (NameEntry* )xmalloc(sizeof(NameEntry));
- if (IS_NULL(entry_copy)) return -1;
-
- entry_copy->name_len = name_end - name;
- entry_copy->back_num = back_num;
- entry_copy->back_alloc = back_num;
- entry_copy->back_ref1 = back_refs[0];
- entry_copy->back_refs = xmalloc(back_num * (sizeof(int*)));
- if (IS_NULL(entry_copy->back_refs)) {
- xfree(entry_copy);
- return -1;
- }
- memcpy(entry_copy->back_refs, back_refs, back_num * sizeof(back_refs[0]));
-
- UChar *new_name = strdup_with_null(regex->enc, name, name_end);
- if (IS_NULL(new_name)) {
- xfree(entry_copy->back_refs);
- xfree(entry_copy);
- return -1;
- }
- entry_copy->name = new_name;
-
- if (onig_st_insert_strend(copy_table, new_name, (new_name + entry_copy->name_len), (hash_data_type)entry_copy)) {
- xfree(entry_copy->name);
- xfree(entry_copy->back_refs);
- xfree(entry_copy);
- return -1;
- }
- return 0;
-}
-
-extern int
-onig_names_copy(regex_t* reg, regex_t* oreg)
-{
- NameTable* table = oreg->name_table;
- if (table) {
- NameTable * t = onig_st_init_strend_table_with_size(onig_number_of_names(oreg));
- CHECK_NULL_RETURN_MEMERR(t);
- if (onig_foreach_name(oreg, copy_named_captures_iter, (void*)t)) {
- onig_st_free_table(t);
- return ONIGERR_MEMORY;
- }
- reg->name_table = t;
- }
- return 0;
-}
-
static NameEntry*
name_find(regex_t* reg, const UChar* name, const UChar* name_end)
{
@@ -625,10 +568,8 @@ typedef struct {
} INamesArg;
static int
-i_names(HashDataType key_ ARG_UNUSED, HashDataType e_, HashDataType arg_)
+i_names(UChar* key ARG_UNUSED, NameEntry* e, INamesArg* arg)
{
- NameEntry* e = (NameEntry *)e_;
- INamesArg* arg = (INamesArg *)arg_;
int r = (*(arg->func))(e->name,
e->name + e->name_len,
e->back_num,
@@ -654,16 +595,14 @@ onig_foreach_name(regex_t* reg,
narg.reg = reg;
narg.arg = arg;
narg.enc = reg->enc; /* should be pattern encoding. */
- onig_st_foreach(t, i_names, (HashDataType )&narg);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_names, (HashDataType )&narg);
}
return narg.ret;
}
static int
-i_renumber_name(HashDataType key_ ARG_UNUSED, HashDataType e_, HashDataType map_)
+i_renumber_name(UChar* key ARG_UNUSED, NameEntry* e, GroupNumRemap* map)
{
- NameEntry* e = (NameEntry *)e_;
- GroupNumRemap* map = (GroupNumRemap *)map_;
int i;
if (e->back_num > 1) {
@@ -684,7 +623,7 @@ onig_renumber_name_table(regex_t* reg, GroupNumRemap* map)
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
- onig_st_foreach(t, i_renumber_name, (HashDataType )map);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_renumber_name, (HashDataType )map);
}
return 0;
}
@@ -760,7 +699,7 @@ names_clear(regex_t* reg)
e->name_len = 0;
e->back_num = 0;
e->back_alloc = 0;
- xfree(e->back_refs);
+ if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
e->back_refs = (int* )NULL;
}
}
@@ -783,57 +722,15 @@ onig_names_free(regex_t* reg)
if (r) return r;
t = (NameTable* )reg->name_table;
- xfree(t);
+ if (IS_NOT_NULL(t)) xfree(t);
reg->name_table = NULL;
return 0;
}
-extern int
-onig_names_copy(regex_t* reg, regex_t* oreg)
-{
- NameTable* ot = oreg->name_table;
- if (ot) {
- OnigEncoding enc = oreg->enc;
- int i, num = ot->num;
- NameTable* t = xmalloc(sizeof(*t));
- CHECK_NULL_RETURN_MEMERR(t);
- *t = *ot;
- t->e = xmalloc(t->alloc * sizeof(t->e[0]));
- if (IS_NULL(t->e)) {
- xfree(t);
- return ONIGERR_MEMORY;
- }
- t->num = 0;
- reg->name_table = t;
- for (i = 0; i < num; t->num = ++i) {
- NameEntry* oe = &(ot->e[i]);
- NameEntry* e = &(t->e[i]);
- *e = *oe;
- e->name = NULL;
- e->back_refs = NULL;
- e->name = strdup_with_null(enc, oe->name, oe->name + e->name_len);
- if (IS_NULL(e->name)) {
- onig_names_free(reg);
- return ONIGERR_MEMORY;
- }
- e->back_refs = xmalloc(e->back_alloc * sizeof(e->back_refs[0]));
- if (IS_NULL(e->back_refs)) {
- xfree(e->name);
- onig_names_free(reg);
- return ONIGERR_MEMORY;
- }
- memcpy(e->back_refs, oe->back_refs, e->back_num * sizeof(e->back_refs[0]));
- e->back_ref1 = e->back_refs[0];
- }
- }
- return 0;
-}
-
static NameEntry*
name_find(regex_t* reg, const UChar* name, const UChar* name_end)
{
- int i;
- size_t len;
+ int i, len;
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
@@ -869,30 +766,6 @@ onig_foreach_name(regex_t* reg,
}
extern int
-onig_renumber_name_table(regex_t* reg, GroupNumRemap* map)
-{
- int i, j;
- NameEntry* e;
- NameTable* t = (NameTable* )reg->name_table;
-
- if (IS_NOT_NULL(t)) {
- for (i = 0; i < t->num; i++) {
- e = &(t->e[i]);
-
- if (e->back_num > 1) {
- for (j = 0; j < e->back_num; j++) {
- e->back_refs[j] = map[e->back_refs[j]].new_val;
- }
- }
- else if (e->back_num == 1) {
- e->back_ref1 = map[e->back_ref1].new_val;
- }
- }
- }
- return 0;
-}
-
-extern int
onig_number_of_names(const regex_t* reg)
{
NameTable* t = (NameTable* )reg->name_table;
@@ -1094,12 +967,6 @@ onig_number_of_names(const regex_t* reg)
{
return 0;
}
-
-extern int
-onig_names_copy(regex_t* reg, regex_t* oreg)
-{
- return 0;
-}
#endif /* else USE_NAMED_GROUP */
extern int
@@ -1231,24 +1098,29 @@ onig_node_free(Node* node)
{
CClassNode* cc = NCCLASS(node);
- bbuf_free(cc->mbuf);
+ if (cc->mbuf)
+ bbuf_free(cc->mbuf);
}
break;
case NT_QTFR:
- onig_node_free(NQTFR(node)->target);
+ if (NQTFR(node)->target)
+ onig_node_free(NQTFR(node)->target);
break;
case NT_ENCLOSE:
- onig_node_free(NENCLOSE(node)->target);
+ if (NENCLOSE(node)->target)
+ onig_node_free(NENCLOSE(node)->target);
break;
case NT_BREF:
- xfree(NBREF(node)->back_dynamic);
+ if (IS_NOT_NULL(NBREF(node)->back_dynamic))
+ xfree(NBREF(node)->back_dynamic);
break;
case NT_ANCHOR:
- onig_node_free(NANCHOR(node)->target);
+ if (NANCHOR(node)->target)
+ onig_node_free(NANCHOR(node)->target);
break;
}
@@ -6105,7 +5977,8 @@ node_extended_grapheme_cluster(Node** np, ScanEnv* env)
R_ERR(add_code_range(&(cc->mbuf), env, 0x000A, 0x000A)); /* CR */
R_ERR(add_code_range(&(cc->mbuf), env, 0x000D, 0x000D)); /* LF */
R_ERR(not_code_range_buf(env->enc, cc->mbuf, &inverted_buf, env));
- cc->mbuf = inverted_buf; /* TODO: check what to do with buffer before inversion */
+ bbuf_free(cc->mbuf);
+ cc->mbuf = inverted_buf;
env->warnings_flag &= dup_not_warned; /* TODO: fix false warning */
}
diff --git a/regparse.h b/regparse.h
index de980d0ac8..acdd3e2f5c 100644
--- a/regparse.h
+++ b/regparse.h
@@ -339,7 +339,7 @@ typedef struct {
extern int onig_renumber_name_table(regex_t* reg, GroupNumRemap* map);
#endif
-extern int onig_strncmp(const UChar* s1, const UChar* s2, size_t n);
+extern int onig_strncmp(const UChar* s1, const UChar* s2, int n);
extern void onig_strcpy(UChar* dest, const UChar* src, const UChar* end);
extern void onig_scan_env_set_error_string(ScanEnv* env, int ecode, UChar* arg, UChar* arg_end);
extern int onig_scan_unsigned_number(UChar** src, const UChar* end, OnigEncoding enc);
@@ -356,7 +356,6 @@ extern Node* onig_node_list_add(Node* list, Node* x);
extern Node* onig_node_new_alt(Node* left, Node* right);
extern void onig_node_str_clear(Node* node);
extern int onig_names_free(regex_t* reg);
-extern int onig_names_copy(regex_t* reg, regex_t* oreg);
extern int onig_parse_make_tree(Node** root, const UChar* pattern, const UChar* end, regex_t* reg, ScanEnv* env);
extern int onig_free_shared_cclass_table(void);
diff --git a/rjit.c b/rjit.c
deleted file mode 100644
index 4ce6af4d4b..0000000000
--- a/rjit.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/**********************************************************************
-
- rjit.c - Ruby JIT compiler functions
-
- Copyright (C) 2023 Takashi Kokubun <k0kubun@ruby-lang.org>.
-
-**********************************************************************/
-
-#include "rjit.h" // defines USE_RJIT
-
-#if USE_RJIT
-
-#include "constant.h"
-#include "id_table.h"
-#include "internal.h"
-#include "internal/class.h"
-#include "internal/cmdlineopt.h"
-#include "internal/cont.h"
-#include "internal/file.h"
-#include "internal/hash.h"
-#include "internal/process.h"
-#include "internal/warnings.h"
-#include "vm_sync.h"
-#include "ractor_core.h"
-
-#ifdef __sun
-#define __EXTENSIONS__ 1
-#endif
-
-#include "vm_core.h"
-#include "vm_callinfo.h"
-#include "rjit_c.h"
-#include "ruby_assert.h"
-#include "ruby/debug.h"
-#include "ruby/thread.h"
-#include "ruby/version.h"
-#include "builtin.h"
-#include "insns.inc"
-#include "insns_info.inc"
-#include "internal/compile.h"
-#include "internal/gc.h"
-
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <dlfcn.h>
-#include <errno.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif
-#include "dln.h"
-
-// For mmapp(), sysconf()
-#ifndef _WIN32
-#include <unistd.h>
-#include <sys/mman.h>
-#endif
-
-#include "ruby/util.h"
-
-// A copy of RJIT portion of MRI options since RJIT initialization. We
-// need them as RJIT threads still can work when the most MRI data were
-// freed.
-struct rb_rjit_options rb_rjit_opts;
-
-// true if RJIT is enabled.
-bool rb_rjit_enabled = false;
-// true if --rjit-stats (used before rb_rjit_opts is set)
-bool rb_rjit_stats_enabled = false;
-// true if --rjit-trace-exits (used before rb_rjit_opts is set)
-bool rb_rjit_trace_exits_enabled = false;
-// true if JIT-ed code should be called. When `ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS`
-// and `rb_rjit_call_p == false`, any JIT-ed code execution is cancelled as soon as possible.
-bool rb_rjit_call_p = false;
-// A flag to communicate that rb_rjit_call_p should be disabled while it's temporarily false.
-static bool rjit_cancel_p = false;
-
-// `rb_ec_ractor_hooks(ec)->events` is moved to this variable during compilation.
-rb_event_flag_t rb_rjit_global_events = 0;
-
-// Basically rb_rjit_opts.stats, but this becomes false during RJIT compilation.
-static bool rjit_stats_p = false;
-
-// RubyVM::RJIT
-static VALUE rb_mRJIT = 0;
-// RubyVM::RJIT::C
-static VALUE rb_mRJITC = 0;
-// RubyVM::RJIT::Compiler
-static VALUE rb_RJITCompiler = 0;
-// RubyVM::RJIT::CPointer::Struct_rb_iseq_t
-static VALUE rb_cRJITIseqPtr = 0;
-// RubyVM::RJIT::CPointer::Struct_rb_control_frame_t
-static VALUE rb_cRJITCfpPtr = 0;
-// RubyVM::RJIT::Hooks
-static VALUE rb_mRJITHooks = 0;
-
-// Frames for --rjit-trace-exits
-VALUE rb_rjit_raw_samples = 0;
-// Line numbers for --rjit-trace-exits
-VALUE rb_rjit_line_samples = 0;
-
-// A default threshold used to add iseq to JIT.
-#define DEFAULT_CALL_THRESHOLD 10
-// Size of executable memory block in MiB.
-#define DEFAULT_EXEC_MEM_SIZE 64
-
-#define opt_match_noarg(s, l, name) \
- opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --rjit-" name " is ignored"), 1) : 1)
-#define opt_match_arg(s, l, name) \
- opt_match(s, l, name) && (*(s) ? 1 : (rb_raise(rb_eRuntimeError, "--rjit-" name " needs an argument"), 0))
-
-void
-rb_rjit_setup_options(const char *s, struct rb_rjit_options *rjit_opt)
-{
- const size_t l = strlen(s);
- if (l == 0) {
- return;
- }
- else if (opt_match_arg(s, l, "call-threshold")) {
- rjit_opt->call_threshold = atoi(s + 1);
- }
- else if (opt_match_arg(s, l, "exec-mem-size")) {
- rjit_opt->exec_mem_size = atoi(s + 1);
- }
- else if (opt_match_noarg(s, l, "stats")) {
- rjit_opt->stats = true;
- }
- else if (opt_match_noarg(s, l, "trace-exits")) {
- rjit_opt->trace_exits = true;
- }
- else if (opt_match_noarg(s, l, "dump-disasm")) {
- rjit_opt->dump_disasm = true;
- }
- else if (opt_match_noarg(s, l, "verify-ctx")) {
- rjit_opt->verify_ctx = true;
- }
- // --rjit=pause is an undocumented feature for experiments
- else if (opt_match_noarg(s, l, "pause")) {
- rjit_opt->pause = true;
- }
- else {
- rb_raise(rb_eRuntimeError,
- "invalid RJIT option `%s' (--help will show valid RJIT options)", s);
- }
-}
-
-#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
-const struct ruby_opt_message rb_rjit_option_messages[] = {
- M("--rjit-stats", "", "Enable collecting RJIT statistics"),
-#if RJIT_STATS
- M("--rjit-trace-exits", "", "Trace side exit locations"),
-#endif
- M("--rjit-exec-mem-size=num", "", "Size of executable memory block in MiB (default: " STRINGIZE(DEFAULT_EXEC_MEM_SIZE) ")"),
- M("--rjit-call-threshold=num", "", "Number of calls to trigger JIT (default: " STRINGIZE(DEFAULT_CALL_THRESHOLD) ")"),
-#ifdef HAVE_LIBCAPSTONE
- M("--rjit-dump-disasm", "", "Dump all JIT code"),
-#endif
- {0}
-};
-#undef M
-
-struct rb_rjit_runtime_counters rb_rjit_counters = { 0 };
-
-#if RJIT_STATS
-void
-rb_rjit_collect_vm_usage_insn(int insn)
-{
- if (!rjit_stats_p) return;
- rb_rjit_counters.vm_insns_count++;
-}
-#endif // YJIT_STATS
-
-extern VALUE rb_gc_enable(void);
-extern VALUE rb_gc_disable(void);
-
-#define WITH_RJIT_ISOLATED(stmt) do { \
- VALUE was_disabled = rb_gc_disable(); \
- rb_hook_list_t *global_hooks = rb_ec_ractor_hooks(GET_EC()); \
- rb_rjit_global_events = global_hooks->events; \
- global_hooks->events = 0; \
- bool original_call_p = rb_rjit_call_p; \
- rjit_stats_p = false; \
- rb_rjit_call_p = false; \
- stmt; \
- rb_rjit_call_p = (rjit_cancel_p ? false : original_call_p); \
- rjit_stats_p = rb_rjit_opts.stats; \
- global_hooks->events = rb_rjit_global_events; \
- if (!was_disabled) rb_gc_enable(); \
-} while (0);
-
-void
-rb_rjit_cancel_all(const char *reason)
-{
- if (!rb_rjit_enabled)
- return;
-
- rb_rjit_call_p = false;
- rjit_cancel_p = true;
-}
-
-void
-rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop)
-{
- if (!rb_rjit_call_p) return;
- rb_rjit_call_p = false;
-}
-
-static void
-rjit_cme_invalidate(void *data)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_cme_invalidate"), 1, SIZET2NUM((size_t)data));
- });
-}
-
-extern int rb_workqueue_register(unsigned flags, rb_postponed_job_func_t func, void *data);
-
-void
-rb_rjit_cme_invalidate(rb_callable_method_entry_t *cme)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- // Asynchronously hook the Ruby code since running Ruby in the middle of cme invalidation is dangerous.
- rb_workqueue_register(0, rjit_cme_invalidate, (void *)cme);
-}
-
-void
-rb_rjit_before_ractor_spawn(void)
-{
- if (!rb_rjit_call_p) return;
- rb_rjit_call_p = false;
-}
-
-static void
-rjit_constant_state_changed(void *data)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_constant_state_changed"), 1, SIZET2NUM((size_t)data));
- });
-
- RB_VM_LOCK_LEAVE();
-}
-
-void
-rb_rjit_constant_state_changed(ID id)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- // Asynchronously hook the Ruby code since this is hooked during a "Ruby critical section".
- rb_workqueue_register(0, rjit_constant_state_changed, (void *)id);
-}
-
-void
-rb_rjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
-
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_constant_ic_update"), 3,
- SIZET2NUM((size_t)iseq), SIZET2NUM((size_t)ic), UINT2NUM(insn_idx));
- });
-
- RB_VM_LOCK_LEAVE();
-}
-
-void
-rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_tracing_invalidate_all"), 1, UINT2NUM(new_iseq_events));
- });
-}
-
-static void
-rjit_iseq_update_references(void *data)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_update_references"), 0);
- });
-}
-
-void
-rb_rjit_iseq_update_references(struct rb_iseq_constant_body *const body)
-{
- if (!rb_rjit_enabled) return;
-
- if (body->rjit_blocks) {
- body->rjit_blocks = rb_gc_location(body->rjit_blocks);
- }
-
- // Asynchronously hook the Ruby code to avoid allocation during GC.compact.
- // Using _one because it's too slow to invalidate all for each ISEQ. Thus
- // not giving an ISEQ pointer.
- rb_postponed_job_register_one(0, rjit_iseq_update_references, NULL);
-}
-
-void
-rb_rjit_iseq_mark(VALUE rjit_blocks)
-{
- if (!rb_rjit_enabled) return;
-
- // Note: This wasn't enough for some reason.
- // We actually rely on RubyVM::RJIT::GC_REFS to mark this.
- if (rjit_blocks) {
- rb_gc_mark_movable(rjit_blocks);
- }
-}
-
-// Called by rb_vm_mark()
-void
-rb_rjit_mark(void)
-{
- if (!rb_rjit_enabled)
- return;
- RUBY_MARK_ENTER("rjit");
-
- // Pin object pointers used in this file
- rb_gc_mark(rb_RJITCompiler);
- rb_gc_mark(rb_cRJITIseqPtr);
- rb_gc_mark(rb_cRJITCfpPtr);
- rb_gc_mark(rb_mRJITHooks);
- rb_gc_mark(rb_rjit_raw_samples);
- rb_gc_mark(rb_rjit_line_samples);
-
- RUBY_MARK_LEAVE("rjit");
-}
-
-void
-rb_rjit_free_iseq(const rb_iseq_t *iseq)
-{
- // TODO: implement this. GC_REFS should remove this iseq's mjit_blocks
-}
-
-// TODO: Use this in more places
-VALUE
-rb_rjit_iseq_new(rb_iseq_t *iseq)
-{
- return rb_funcall(rb_cRJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
-}
-
-void
-rb_rjit_compile(const rb_iseq_t *iseq)
-{
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- WITH_RJIT_ISOLATED({
- VALUE iseq_ptr = rb_funcall(rb_cRJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
- VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)GET_EC()->cfp));
- rb_funcall(rb_RJITCompiler, rb_intern("compile"), 2, iseq_ptr, cfp_ptr);
- });
-
- RB_VM_LOCK_LEAVE();
-}
-
-void *
-rb_rjit_entry_stub_hit(VALUE branch_stub)
-{
- VALUE result;
-
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- rb_control_frame_t *cfp = GET_EC()->cfp;
-
- WITH_RJIT_ISOLATED({
- VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)cfp));
- result = rb_funcall(rb_RJITCompiler, rb_intern("entry_stub_hit"), 2, branch_stub, cfp_ptr);
- });
-
- RB_VM_LOCK_LEAVE();
-
- return (void *)NUM2SIZET(result);
-}
-
-void *
-rb_rjit_branch_stub_hit(VALUE branch_stub, int sp_offset, int target0_p)
-{
- VALUE result;
-
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- rb_control_frame_t *cfp = GET_EC()->cfp;
- cfp->sp += sp_offset; // preserve stack values, also using the actual sp_offset to make jit.peek_at_stack work
-
- WITH_RJIT_ISOLATED({
- VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)cfp));
- result = rb_funcall(rb_RJITCompiler, rb_intern("branch_stub_hit"), 3, branch_stub, cfp_ptr, RBOOL(target0_p));
- });
-
- cfp->sp -= sp_offset; // reset for consistency with the code without the stub
-
- RB_VM_LOCK_LEAVE();
-
- return (void *)NUM2SIZET(result);
-}
-
-void
-rb_rjit_init(const struct rb_rjit_options *opts)
-{
- VM_ASSERT(rb_rjit_enabled);
-
- // Normalize options
- rb_rjit_opts = *opts;
- if (rb_rjit_opts.exec_mem_size == 0)
- rb_rjit_opts.exec_mem_size = DEFAULT_EXEC_MEM_SIZE;
- if (rb_rjit_opts.call_threshold == 0)
- rb_rjit_opts.call_threshold = DEFAULT_CALL_THRESHOLD;
-#ifndef HAVE_LIBCAPSTONE
- if (rb_rjit_opts.dump_disasm)
- rb_warn("libcapstone has not been linked. Ignoring --rjit-dump-disasm.");
-#endif
-
- // RJIT doesn't support miniruby, but it might reach here by RJIT_FORCE_ENABLE.
- rb_mRJIT = rb_const_get(rb_cRubyVM, rb_intern("RJIT"));
- if (!rb_const_defined(rb_mRJIT, rb_intern("Compiler"))) {
- rb_warn("Disabling RJIT because RubyVM::RJIT::Compiler is not defined");
- rb_rjit_enabled = false;
- return;
- }
- rb_mRJITC = rb_const_get(rb_mRJIT, rb_intern("C"));
- VALUE rb_cRJITCompiler = rb_const_get(rb_mRJIT, rb_intern("Compiler"));
- rb_RJITCompiler = rb_funcall(rb_cRJITCompiler, rb_intern("new"), 0);
- rb_cRJITIseqPtr = rb_funcall(rb_mRJITC, rb_intern("rb_iseq_t"), 0);
- rb_cRJITCfpPtr = rb_funcall(rb_mRJITC, rb_intern("rb_control_frame_t"), 0);
- rb_mRJITHooks = rb_const_get(rb_mRJIT, rb_intern("Hooks"));
- if (rb_rjit_opts.trace_exits) {
- rb_rjit_raw_samples = rb_ary_new();
- rb_rjit_line_samples = rb_ary_new();
- }
-
- // Enable RJIT and stats from here
- rb_rjit_call_p = !rb_rjit_opts.pause;
- rjit_stats_p = rb_rjit_opts.stats;
-}
-
-//
-// Primitive for rjit.rb
-//
-
-// Same as `rb_rjit_opts.stats`, but this is used before rb_rjit_opts is set.
-static VALUE
-rjit_stats_enabled_p(rb_execution_context_t *ec, VALUE self)
-{
- return RBOOL(rb_rjit_stats_enabled);
-}
-
-// Same as `rb_rjit_opts.trace_exits`, but this is used before rb_rjit_opts is set.
-static VALUE
-rjit_trace_exits_enabled_p(rb_execution_context_t *ec, VALUE self)
-{
- return RBOOL(rb_rjit_trace_exits_enabled);
-}
-
-// Disable anything that could impact stats. It ends up disabling JIT calls as well.
-static VALUE
-rjit_stop_stats(rb_execution_context_t *ec, VALUE self)
-{
- rb_rjit_call_p = false;
- rjit_stats_p = false;
- return Qnil;
-}
-
-#include "rjit.rbinc"
-
-#endif // USE_RJIT
diff --git a/rjit.h b/rjit.h
deleted file mode 100644
index 1efd4f3ae7..0000000000
--- a/rjit.h
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifndef RUBY_RJIT_H
-#define RUBY_RJIT_H 1
-/**********************************************************************
-
- rjit.h - Interface to RJIT
-
- Copyright (C) 2023 Takashi Kokubun <k0kubun@ruby-lang.org>.
-
-**********************************************************************/
-
-#include "ruby/internal/config.h" // defines USE_RJIT
-#include "ruby/internal/stdbool.h"
-#include "vm_core.h"
-
-# if USE_RJIT
-
-#ifndef RJIT_STATS
-# define RJIT_STATS RUBY_DEBUG
-#endif
-
-#include "ruby.h"
-#include "vm_core.h"
-
-// RJIT options which can be defined on the MRI command line.
-struct rb_rjit_options {
- // Converted from "rjit" feature flag to tell the enablement
- // information to ruby_show_version().
- bool on;
- // Number of calls to trigger JIT compilation.
- unsigned int call_threshold;
- // Size of executable memory block in MiB
- unsigned int exec_mem_size;
- // Collect RJIT statistics
- bool stats;
- // Trace side exit locations
- bool trace_exits;
- // Enable disasm of all JIT code
- bool dump_disasm;
- // Verify context objects
- bool verify_ctx;
- // [experimental] Do not start RJIT until RJIT.resume is called.
- bool pause;
-};
-
-RUBY_SYMBOL_EXPORT_BEGIN
-RUBY_EXTERN struct rb_rjit_options rb_rjit_opts;
-RUBY_EXTERN bool rb_rjit_call_p;
-
-#define rb_rjit_call_threshold() rb_rjit_opts.call_threshold
-
-extern void rb_rjit_compile(const rb_iseq_t *iseq);
-RUBY_SYMBOL_EXPORT_END
-
-extern void rb_rjit_cancel_all(const char *reason);
-extern void rb_rjit_init(const struct rb_rjit_options *opts);
-extern void rb_rjit_free_iseq(const rb_iseq_t *iseq);
-extern void rb_rjit_iseq_update_references(struct rb_iseq_constant_body *const body);
-extern void rb_rjit_mark(void);
-extern void rb_rjit_iseq_mark(VALUE rjit_blocks);
-extern void rjit_notify_waitpid(int exit_code);
-
-extern void rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
-extern void rb_rjit_cme_invalidate(rb_callable_method_entry_t *cme);
-extern void rb_rjit_before_ractor_spawn(void);
-extern void rb_rjit_constant_state_changed(ID id);
-extern void rb_rjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx);
-extern void rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events);
-
-extern void rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
-extern void rb_rjit_before_ractor_spawn(void);
-extern void rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events);
-extern void rb_rjit_collect_vm_usage_insn(int insn);
-
-extern bool rb_rjit_enabled;
-extern bool rb_rjit_stats_enabled;
-extern bool rb_rjit_trace_exits_enabled;
-
-# else // USE_RJIT
-
-static inline void rb_rjit_compile(const rb_iseq_t *iseq){}
-
-static inline void rb_rjit_cancel_all(const char *reason){}
-static inline void rb_rjit_free_iseq(const rb_iseq_t *iseq){}
-static inline void rb_rjit_mark(void){}
-
-static inline void rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
-static inline void rb_rjit_cme_invalidate(rb_callable_method_entry_t *cme) {}
-static inline void rb_rjit_before_ractor_spawn(void) {}
-static inline void rb_rjit_constant_state_changed(ID id) {}
-static inline void rb_rjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx) {}
-static inline void rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events) {}
-
-#define rb_rjit_enabled false
-#define rb_rjit_call_p false
-#define rb_rjit_stats_enabled false
-#define rb_rjit_trace_exits_enabled false
-
-#define rb_rjit_call_threshold() UINT_MAX
-
-static inline void rb_rjit_collect_vm_usage_insn(int insn) {}
-
-# endif // USE_RJIT
-#endif // RUBY_RJIT_H
diff --git a/rjit.rb b/rjit.rb
deleted file mode 100644
index ebad3529ef..0000000000
--- a/rjit.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-module RubyVM::RJIT
- # Return true if RJIT is enabled.
- def self.enabled?
- Primitive.cexpr! 'RBOOL(rb_rjit_enabled)'
- end
-
- # Start generating JITed code again after --rjit-pause.
- def self.resume
- Primitive.cstmt! %{
- rb_rjit_call_p = true;
- return Qnil;
- }
- end
-
- if Primitive.rjit_stats_enabled_p
- at_exit do
- Primitive.rjit_stop_stats
- print_stats
- end
- end
- if Primitive.rjit_trace_exits_enabled_p
- at_exit do
- Primitive.rjit_stop_stats
- dump_trace_exits
- end
- end
-end
-
-if RubyVM::RJIT.enabled?
- begin
- require 'fiddle'
- require 'fiddle/import'
- rescue LoadError
- return # miniruby doesn't support RJIT
- end
-
- require 'ruby_vm/rjit/c_type'
- require 'ruby_vm/rjit/compiler'
- require 'ruby_vm/rjit/hooks'
- require 'ruby_vm/rjit/stats'
-end
diff --git a/rjit_c.c b/rjit_c.c
deleted file mode 100644
index bdc9ce8072..0000000000
--- a/rjit_c.c
+++ /dev/null
@@ -1,541 +0,0 @@
-/**********************************************************************
-
- rjit_c.c - C helpers for RJIT
-
- Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
-
-**********************************************************************/
-
-#include "rjit.h" // defines USE_RJIT
-
-#if USE_RJIT
-
-#include "rjit_c.h"
-#include "include/ruby/assert.h"
-#include "include/ruby/debug.h"
-#include "internal.h"
-#include "internal/compile.h"
-#include "internal/fixnum.h"
-#include "internal/hash.h"
-#include "internal/sanitizers.h"
-#include "internal/gc.h"
-#include "internal/proc.h"
-#include "yjit.h"
-#include "vm_insnhelper.h"
-#include "probes.h"
-#include "probes_helper.h"
-
-#include "insns.inc"
-#include "insns_info.inc"
-
-// For mmapp(), sysconf()
-#ifndef _WIN32
-#include <unistd.h>
-#include <sys/mman.h>
-#endif
-
-#include <errno.h>
-
-#if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
-// Align the current write position to a multiple of bytes
-static uint8_t *
-align_ptr(uint8_t *ptr, uint32_t multiple)
-{
- // Compute the pointer modulo the given alignment boundary
- uint32_t rem = ((uint32_t)(uintptr_t)ptr) % multiple;
-
- // If the pointer is already aligned, stop
- if (rem == 0)
- return ptr;
-
- // Pad the pointer by the necessary amount to align it
- uint32_t pad = multiple - rem;
-
- return ptr + pad;
-}
-#endif
-
-// Address space reservation. Memory pages are mapped on an as needed basis.
-// See the Rust mm module for details.
-static uint8_t *
-rjit_reserve_addr_space(uint32_t mem_size)
-{
-#ifndef _WIN32
- uint8_t *mem_block;
-
- // On Linux
- #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
- uint32_t const page_size = (uint32_t)sysconf(_SC_PAGESIZE);
- uint8_t *const cfunc_sample_addr = (void *)&rjit_reserve_addr_space;
- uint8_t *const probe_region_end = cfunc_sample_addr + INT32_MAX;
- // Align the requested address to page size
- uint8_t *req_addr = align_ptr(cfunc_sample_addr, page_size);
-
- // Probe for addresses close to this function using MAP_FIXED_NOREPLACE
- // to improve odds of being in range for 32-bit relative call instructions.
- do {
- mem_block = mmap(
- req_addr,
- mem_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
- -1,
- 0
- );
-
- // If we succeeded, stop
- if (mem_block != MAP_FAILED) {
- break;
- }
-
- // +4MB
- req_addr += 4 * 1024 * 1024;
- } while (req_addr < probe_region_end);
-
- // On MacOS and other platforms
- #else
- // Try to map a chunk of memory as executable
- mem_block = mmap(
- (void *)rjit_reserve_addr_space,
- mem_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1,
- 0
- );
- #endif
-
- // Fallback
- if (mem_block == MAP_FAILED) {
- // Try again without the address hint (e.g., valgrind)
- mem_block = mmap(
- NULL,
- mem_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1,
- 0
- );
- }
-
- // Check that the memory mapping was successful
- if (mem_block == MAP_FAILED) {
- perror("ruby: yjit: mmap:");
- if(errno == ENOMEM) {
- // No crash report if it's only insufficient memory
- exit(EXIT_FAILURE);
- }
- rb_bug("mmap failed");
- }
-
- return mem_block;
-#else
- // Windows not supported for now
- return NULL;
-#endif
-}
-
-static VALUE
-mprotect_write(rb_execution_context_t *ec, VALUE self, VALUE rb_mem_block, VALUE rb_mem_size)
-{
- void *mem_block = (void *)NUM2SIZET(rb_mem_block);
- uint32_t mem_size = NUM2UINT(rb_mem_size);
- return RBOOL(mprotect(mem_block, mem_size, PROT_READ | PROT_WRITE) == 0);
-}
-
-static VALUE
-mprotect_exec(rb_execution_context_t *ec, VALUE self, VALUE rb_mem_block, VALUE rb_mem_size)
-{
- void *mem_block = (void *)NUM2SIZET(rb_mem_block);
- uint32_t mem_size = NUM2UINT(rb_mem_size);
- if (mem_size == 0) return Qfalse; // Some platforms return an error for mem_size 0.
-
- if (mprotect(mem_block, mem_size, PROT_READ | PROT_EXEC)) {
- rb_bug("Couldn't make JIT page (%p, %lu bytes) executable, errno: %s",
- mem_block, (unsigned long)mem_size, strerror(errno));
- }
- return Qtrue;
-}
-
-static VALUE
-rjit_optimized_call(VALUE *recv, rb_execution_context_t *ec, int argc, VALUE *argv, int kw_splat, VALUE block_handler)
-{
- rb_proc_t *proc;
- GetProcPtr(recv, proc);
- return rb_vm_invoke_proc(ec, proc, argc, argv, kw_splat, block_handler);
-}
-
-static VALUE
-rjit_str_neq_internal(VALUE str1, VALUE str2)
-{
- return rb_str_eql_internal(str1, str2) == Qtrue ? Qfalse : Qtrue;
-}
-
-static VALUE
-rjit_str_simple_append(VALUE str1, VALUE str2)
-{
- return rb_str_cat(str1, RSTRING_PTR(str2), RSTRING_LEN(str2));
-}
-
-static VALUE
-rjit_rb_ary_subseq_length(VALUE ary, long beg)
-{
- long len = RARRAY_LEN(ary);
- return rb_ary_subseq(ary, beg, len);
-}
-
-static VALUE
-rjit_build_kwhash(const struct rb_callinfo *ci, VALUE *sp)
-{
- const struct rb_callinfo_kwarg *kw_arg = vm_ci_kwarg(ci);
- int kw_len = kw_arg->keyword_len;
- VALUE hash = rb_hash_new_with_size(kw_len);
-
- for (int i = 0; i < kw_len; i++) {
- VALUE key = kw_arg->keywords[i];
- VALUE val = *(sp - kw_len + i);
- rb_hash_aset(hash, key, val);
- }
- return hash;
-}
-
-// The code we generate in gen_send_cfunc() doesn't fire the c_return TracePoint event
-// like the interpreter. When tracing for c_return is enabled, we patch the code after
-// the C method return to call into this to fire the event.
-static void
-rjit_full_cfunc_return(rb_execution_context_t *ec, VALUE return_value)
-{
- rb_control_frame_t *cfp = ec->cfp;
- RUBY_ASSERT_ALWAYS(cfp == GET_EC()->cfp);
- const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
-
- RUBY_ASSERT_ALWAYS(RUBYVM_CFUNC_FRAME_P(cfp));
- RUBY_ASSERT_ALWAYS(me->def->type == VM_METHOD_TYPE_CFUNC);
-
- // CHECK_CFP_CONSISTENCY("full_cfunc_return"); TODO revive this
-
- // Pop the C func's frame and fire the c_return TracePoint event
- // Note that this is the same order as vm_call_cfunc_with_frame().
- rb_vm_pop_frame(ec);
- EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, cfp->self, me->def->original_id, me->called_id, me->owner, return_value);
- // Note, this deviates from the interpreter in that users need to enable
- // a c_return TracePoint for this DTrace hook to work. A reasonable change
- // since the Ruby return event works this way as well.
- RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, me->owner, me->def->original_id);
-
- // Push return value into the caller's stack. We know that it's a frame that
- // uses cfp->sp because we are patching a call done with gen_send_cfunc().
- ec->cfp->sp[0] = return_value;
- ec->cfp->sp++;
-}
-
-static rb_proc_t *
-rjit_get_proc_ptr(VALUE procv)
-{
- rb_proc_t *proc;
- GetProcPtr(procv, proc);
- return proc;
-}
-
-// Use the same buffer size as Stackprof.
-#define BUFF_LEN 2048
-
-extern VALUE rb_rjit_raw_samples;
-extern VALUE rb_rjit_line_samples;
-
-static void
-rjit_record_exit_stack(const VALUE *exit_pc)
-{
- // Let Primitive.rjit_stop_stats stop this
- if (!rb_rjit_call_p) return;
-
- // Get the opcode from the encoded insn handler at this PC
- int insn = rb_vm_insn_addr2opcode((void *)*exit_pc);
-
- // Create 2 array buffers to be used to collect frames and lines.
- VALUE frames_buffer[BUFF_LEN] = { 0 };
- int lines_buffer[BUFF_LEN] = { 0 };
-
- // Records call frame and line information for each method entry into two
- // temporary buffers. Returns the number of times we added to the buffer (ie
- // the length of the stack).
- //
- // Call frame info is stored in the frames_buffer, line number information
- // in the lines_buffer. The first argument is the start point and the second
- // argument is the buffer limit, set at 2048.
- int stack_length = rb_profile_frames(0, BUFF_LEN, frames_buffer, lines_buffer);
- int samples_length = stack_length + 3; // 3: length, insn, count
-
- // If yjit_raw_samples is less than or equal to the current length of the samples
- // we might have seen this stack trace previously.
- int prev_stack_len_index = (int)RARRAY_LEN(rb_rjit_raw_samples) - samples_length;
- VALUE prev_stack_len_obj;
- if (RARRAY_LEN(rb_rjit_raw_samples) >= samples_length && FIXNUM_P(prev_stack_len_obj = RARRAY_AREF(rb_rjit_raw_samples, prev_stack_len_index))) {
- int prev_stack_len = NUM2INT(prev_stack_len_obj);
- int idx = stack_length - 1;
- int prev_frame_idx = 0;
- bool seen_already = true;
-
- // If the previous stack length and current stack length are equal,
- // loop and compare the current frame to the previous frame. If they are
- // not equal, set seen_already to false and break out of the loop.
- if (prev_stack_len == stack_length) {
- while (idx >= 0) {
- VALUE current_frame = frames_buffer[idx];
- VALUE prev_frame = RARRAY_AREF(rb_rjit_raw_samples, prev_stack_len_index + prev_frame_idx + 1);
-
- // If the current frame and previous frame are not equal, set
- // seen_already to false and break out of the loop.
- if (current_frame != prev_frame) {
- seen_already = false;
- break;
- }
-
- idx--;
- prev_frame_idx++;
- }
-
- // If we know we've seen this stack before, increment the counter by 1.
- if (seen_already) {
- int prev_idx = (int)RARRAY_LEN(rb_rjit_raw_samples) - 1;
- int prev_count = NUM2INT(RARRAY_AREF(rb_rjit_raw_samples, prev_idx));
- int new_count = prev_count + 1;
-
- rb_ary_store(rb_rjit_raw_samples, prev_idx, INT2NUM(new_count));
- rb_ary_store(rb_rjit_line_samples, prev_idx, INT2NUM(new_count));
- return;
- }
- }
- }
-
- rb_ary_push(rb_rjit_raw_samples, INT2NUM(stack_length));
- rb_ary_push(rb_rjit_line_samples, INT2NUM(stack_length));
-
- int idx = stack_length - 1;
-
- while (idx >= 0) {
- VALUE frame = frames_buffer[idx];
- int line = lines_buffer[idx];
-
- rb_ary_push(rb_rjit_raw_samples, frame);
- rb_ary_push(rb_rjit_line_samples, INT2NUM(line));
-
- idx--;
- }
-
- // Push the insn value into the yjit_raw_samples Vec.
- rb_ary_push(rb_rjit_raw_samples, INT2NUM(insn));
-
- // Push the current line onto the yjit_line_samples Vec. This
- // points to the line in insns.def.
- int line = (int)RARRAY_LEN(rb_rjit_line_samples) - 1;
- rb_ary_push(rb_rjit_line_samples, INT2NUM(line));
-
- // Push number of times seen onto the stack, which is 1
- // because it's the first time we've seen it.
- rb_ary_push(rb_rjit_raw_samples, INT2NUM(1));
- rb_ary_push(rb_rjit_line_samples, INT2NUM(1));
-}
-
-// For a given raw_sample (frame), set the hash with the caller's
-// name, file, and line number. Return the hash with collected frame_info.
-static void
-rjit_add_frame(VALUE hash, VALUE frame)
-{
- VALUE frame_id = SIZET2NUM(frame);
-
- if (RTEST(rb_hash_aref(hash, frame_id))) {
- return;
- }
- else {
- VALUE frame_info = rb_hash_new();
- // Full label for the frame
- VALUE name = rb_profile_frame_full_label(frame);
- // Absolute path of the frame from rb_iseq_realpath
- VALUE file = rb_profile_frame_absolute_path(frame);
- // Line number of the frame
- VALUE line = rb_profile_frame_first_lineno(frame);
-
- // If absolute path isn't available use the rb_iseq_path
- if (NIL_P(file)) {
- file = rb_profile_frame_path(frame);
- }
-
- rb_hash_aset(frame_info, ID2SYM(rb_intern("name")), name);
- rb_hash_aset(frame_info, ID2SYM(rb_intern("file")), file);
- rb_hash_aset(frame_info, ID2SYM(rb_intern("samples")), INT2NUM(0));
- rb_hash_aset(frame_info, ID2SYM(rb_intern("total_samples")), INT2NUM(0));
- rb_hash_aset(frame_info, ID2SYM(rb_intern("edges")), rb_hash_new());
- rb_hash_aset(frame_info, ID2SYM(rb_intern("lines")), rb_hash_new());
-
- if (line != INT2FIX(0)) {
- rb_hash_aset(frame_info, ID2SYM(rb_intern("line")), line);
- }
-
- rb_hash_aset(hash, frame_id, frame_info);
- }
-}
-
-static VALUE
-rjit_exit_traces(void)
-{
- int samples_len = (int)RARRAY_LEN(rb_rjit_raw_samples);
- RUBY_ASSERT(samples_len == RARRAY_LEN(rb_rjit_line_samples));
-
- VALUE result = rb_hash_new();
- VALUE raw_samples = rb_ary_new_capa(samples_len);
- VALUE line_samples = rb_ary_new_capa(samples_len);
- VALUE frames = rb_hash_new();
- int idx = 0;
-
- // While the index is less than samples_len, parse yjit_raw_samples and
- // yjit_line_samples, then add casted values to raw_samples and line_samples array.
- while (idx < samples_len) {
- int num = NUM2INT(RARRAY_AREF(rb_rjit_raw_samples, idx));
- int line_num = NUM2INT(RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
-
- rb_ary_push(raw_samples, SIZET2NUM(num));
- rb_ary_push(line_samples, INT2NUM(line_num));
-
- // Loop through the length of samples_len and add data to the
- // frames hash. Also push the current value onto the raw_samples
- // and line_samples array respectively.
- for (int o = 0; o < num; o++) {
- rjit_add_frame(frames, RARRAY_AREF(rb_rjit_raw_samples, idx));
- rb_ary_push(raw_samples, SIZET2NUM(RARRAY_AREF(rb_rjit_raw_samples, idx)));
- rb_ary_push(line_samples, RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
- }
-
- // insn BIN and lineno
- rb_ary_push(raw_samples, RARRAY_AREF(rb_rjit_raw_samples, idx));
- rb_ary_push(line_samples, RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
-
- // Number of times seen
- rb_ary_push(raw_samples, RARRAY_AREF(rb_rjit_raw_samples, idx));
- rb_ary_push(line_samples, RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
- }
-
- // Set add the raw_samples, line_samples, and frames to the results
- // hash.
- rb_hash_aset(result, ID2SYM(rb_intern("raw")), raw_samples);
- rb_hash_aset(result, ID2SYM(rb_intern("lines")), line_samples);
- rb_hash_aset(result, ID2SYM(rb_intern("frames")), frames);
-
- return result;
-}
-
-// An offsetof implementation that works for unnamed struct and union.
-// Multiplying 8 for compatibility with libclang's offsetof.
-#define OFFSETOF(ptr, member) RB_SIZE2NUM(((char *)&ptr.member - (char*)&ptr) * 8)
-
-#define SIZEOF(type) RB_SIZE2NUM(sizeof(type))
-#define SIGNED_TYPE_P(type) RBOOL((type)(-1) < (type)(1))
-
-// Insn side exit counters
-static size_t rjit_insn_exits[VM_INSTRUCTION_SIZE] = { 0 };
-
-// macOS: brew install capstone
-// Ubuntu/Debian: apt-get install libcapstone-dev
-// Fedora: dnf -y install capstone-devel
-#ifdef HAVE_LIBCAPSTONE
-#include <capstone/capstone.h>
-#endif
-
-// Return an array of [address, mnemonic, op_str]
-static VALUE
-dump_disasm(rb_execution_context_t *ec, VALUE self, VALUE from, VALUE to, VALUE test)
-{
- VALUE result = rb_ary_new();
-#ifdef HAVE_LIBCAPSTONE
- // Prepare for calling cs_disasm
- static csh handle;
- if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) {
- rb_raise(rb_eRuntimeError, "failed to make Capstone handle");
- }
- size_t from_addr = NUM2SIZET(from);
- size_t to_addr = NUM2SIZET(to);
-
- // Call cs_disasm and convert results to a Ruby array
- cs_insn *insns;
- size_t base_addr = RTEST(test) ? 0 : from_addr; // On tests, start from 0 for output stability.
- size_t count = cs_disasm(handle, (const uint8_t *)from_addr, to_addr - from_addr, base_addr, 0, &insns);
- for (size_t i = 0; i < count; i++) {
- VALUE vals = rb_ary_new_from_args(3, LONG2NUM(insns[i].address), rb_str_new2(insns[i].mnemonic), rb_str_new2(insns[i].op_str));
- rb_ary_push(result, vals);
- }
-
- // Free memory used by capstone
- cs_free(insns, count);
- cs_close(&handle);
-#endif
- return result;
-}
-
-// Same as `RubyVM::RJIT.enabled?`, but this is used before it's defined.
-static VALUE
-rjit_enabled_p(rb_execution_context_t *ec, VALUE self)
-{
- return RBOOL(rb_rjit_enabled);
-}
-
-static int
-for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
-{
- VALUE block = (VALUE)data;
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- void *ptr = asan_poisoned_object_p(v);
- asan_unpoison_object(v, false);
-
- if (rb_obj_is_iseq(v)) {
- extern VALUE rb_rjit_iseq_new(rb_iseq_t *iseq);
- rb_iseq_t *iseq = (rb_iseq_t *)v;
- rb_funcall(block, rb_intern("call"), 1, rb_rjit_iseq_new(iseq));
- }
-
- asan_poison_object_if(ptr, v);
- }
- return 0;
-}
-
-static VALUE
-rjit_for_each_iseq(rb_execution_context_t *ec, VALUE self, VALUE block)
-{
- rb_objspace_each_objects(for_each_iseq_i, (void *)block);
- return Qnil;
-}
-
-// bindgen funcs
-extern ID rb_get_symbol_id(VALUE name);
-extern VALUE rb_fix_aref(VALUE fix, VALUE idx);
-extern VALUE rb_str_getbyte(VALUE str, VALUE index);
-extern VALUE rb_vm_concat_array(VALUE ary1, VALUE ary2st);
-extern VALUE rb_vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, VALUE allow_nil);
-extern VALUE rb_vm_getclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID id, ICVARC ic);
-extern VALUE rb_vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
-extern VALUE rb_vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
-extern VALUE rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
-extern VALUE rb_vm_splat_array(VALUE flag, VALUE array);
-extern bool rb_simple_iseq_p(const rb_iseq_t *iseq);
-extern bool rb_vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE obj, VALUE v);
-extern bool rb_vm_ic_hit_p(IC ic, const VALUE *reg_ep);
-extern rb_event_flag_t rb_rjit_global_events;
-extern void rb_vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IVC ic);
-extern VALUE rb_vm_throw(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t throw_state, VALUE throwobj);
-extern VALUE rb_reg_new_ary(VALUE ary, int opt);
-extern void rb_vm_setclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID id, VALUE val, ICVARC ic);
-extern VALUE rb_str_bytesize(VALUE str);
-extern const rb_callable_method_entry_t *rb_callable_method_entry_or_negative(VALUE klass, ID mid);
-extern VALUE rb_vm_yield_with_cfunc(rb_execution_context_t *ec, const struct rb_captured_block *captured, int argc, const VALUE *argv);
-extern VALUE rb_vm_set_ivar_id(VALUE obj, ID id, VALUE val);
-extern VALUE rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary);
-extern void* rb_rjit_entry_stub_hit(VALUE branch_stub);
-extern void* rb_rjit_branch_stub_hit(VALUE branch_stub, int sp_offset, int target0_p);
-
-#include "rjit_c.rbinc"
-
-#endif // USE_RJIT
diff --git a/rjit_c.h b/rjit_c.h
deleted file mode 100644
index 518d336c00..0000000000
--- a/rjit_c.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// This file is parsed by tool/rjit/generate.rb to generate rjit_c.rb
-#ifndef RJIT_C_H
-#define RJIT_C_H
-
-#include "ruby/internal/config.h"
-#include "internal/string.h"
-#include "internal/struct.h"
-#include "internal/variable.h"
-#include "vm_core.h"
-#include "vm_callinfo.h"
-#include "builtin.h"
-#include "ccan/list/list.h"
-#include "rjit.h"
-#include "shape.h"
-
-extern uint8_t *rb_rjit_mem_block;
-
-#define RJIT_RUNTIME_COUNTERS(...) struct rb_rjit_runtime_counters { size_t __VA_ARGS__; };
-RJIT_RUNTIME_COUNTERS(
- vm_insns_count,
- rjit_insns_count,
-
- send_args_splat_kw_splat,
- send_args_splat,
- send_args_splat_not_array,
- send_args_splat_length_not_equal,
- send_args_splat_cfunc_var_args,
- send_args_splat_arity_error,
- send_args_splat_ruby2_hash,
- send_args_splat_cfunc_zuper,
- send_args_splat_cfunc_ruby2_keywords,
- send_kw_splat,
- send_kwarg,
- send_klass_megamorphic,
- send_missing_cme,
- send_private,
- send_protected_check_failed,
- send_tailcall,
- send_notimplemented,
- send_missing,
- send_bmethod,
- send_alias,
- send_undef,
- send_zsuper,
- send_refined,
- send_stackoverflow,
- send_arity,
- send_c_tracing,
- send_is_a_class_mismatch,
- send_instance_of_class_mismatch,
- send_keywords,
-
- send_blockiseq,
- send_block_handler,
- send_block_setup,
- send_block_not_nil,
- send_block_not_proxy,
- send_block_arg,
-
- send_iseq_kwparam,
- send_iseq_accepts_no_kwarg,
- send_iseq_has_opt,
- send_iseq_has_kwrest,
- send_iseq_ruby2_keywords,
- send_iseq_has_rest_and_captured,
- send_iseq_has_rest_and_kw_supplied,
- send_iseq_has_no_kw,
- send_iseq_zsuper,
- send_iseq_materialized_block,
- send_iseq_has_rest,
- send_iseq_block_arg0_splat,
- send_iseq_kw_call,
- send_iseq_splat,
- send_iseq_has_rest_and_optional,
- send_iseq_arity_error,
- send_iseq_missing_optional_kw,
- send_iseq_too_many_kwargs,
- send_iseq_kwargs_mismatch,
- send_iseq_splat_with_kw,
- send_iseq_splat_arity_error,
- send_iseq_has_rest_and_splat_not_equal,
-
- send_cfunc_variadic,
- send_cfunc_too_many_args,
- send_cfunc_ruby_array_varg,
- send_cfunc_splat_with_kw,
- send_cfunc_tracing,
- send_cfunc_argc_mismatch,
- send_cfunc_toomany_args,
-
- send_attrset_splat,
- send_attrset_kwarg,
- send_attrset_method,
-
- send_ivar_splat,
- send_ivar_opt_send,
-
- send_optimized_send_no_args,
- send_optimized_send_not_sym_or_str,
- send_optimized_send_mid_class_changed,
- send_optimized_send_mid_id_changed,
- send_optimized_send_null_mid,
- send_optimized_send_send,
- send_optimized_call_block,
- send_optimized_call_kwarg,
- send_optimized_call_splat,
- send_optimized_struct_aref_error,
-
- send_optimized_block_call,
- send_optimized_struct_aset,
-
- send_bmethod_not_iseq,
- send_bmethod_blockarg,
-
- invokesuper_me_changed,
- invokesuper_block,
-
- invokeblock_none,
- invokeblock_symbol,
- invokeblock_proc,
- invokeblock_tag_changed,
- invokeblock_iseq_block_changed,
- invokeblock_iseq_arity,
- invokeblock_iseq_arg0_splat,
- invokeblock_ifunc_args_splat,
- invokeblock_ifunc_kw_splat,
- invokeblock_iseq_arg0_args_splat,
- invokeblock_iseq_arg0_has_kw,
-
- getivar_megamorphic,
- getivar_not_heap,
- getivar_special_const,
- getivar_too_complex,
-
- optaref_arg_not_fixnum,
- optaref_argc_not_one,
- optaref_recv_not_array,
- optaref_recv_not_hash,
- optaref_send,
-
- optgetconst_not_cached,
- optgetconst_cref,
- optgetconst_cache_miss,
-
- setivar_frozen,
- setivar_not_heap,
- setivar_megamorphic,
- setivar_too_complex,
-
- expandarray_splat,
- expandarray_postarg,
- expandarray_not_array,
- expandarray_rhs_too_small,
-
- getblockpp_block_param_modified,
- getblockpp_block_handler_none,
- getblockpp_not_gc_guarded,
- getblockpp_not_iseq_block,
-
- compiled_block_count
-)
-#undef RJIT_RUNTIME_COUNTERS
-extern struct rb_rjit_runtime_counters rb_rjit_counters;
-
-#endif /* RJIT_C_H */
diff --git a/rjit_c.rb b/rjit_c.rb
deleted file mode 100644
index df30841d2b..0000000000
--- a/rjit_c.rb
+++ /dev/null
@@ -1,1691 +0,0 @@
-# frozen_string_literal: true
-# Part of this file is generated by tool/rjit/bindgen.rb.
-# Run `make rjit-bindgen` to update code between "RJIT bindgen begin" and "RJIT bindgen end".
-module RubyVM::RJIT # :nodoc: all
- #
- # Main: Used by RJIT
- #
- # This `class << C` section is for calling C functions with Primitive.
- # For importing variables or macros, use tool/rjit/bindgen.rb instead.
- class << C = Module.new
- def mmap(mem_size)
- Primitive.cexpr! 'SIZET2NUM((size_t)rjit_reserve_addr_space(NUM2UINT(mem_size)))'
- end
-
- def mprotect_write(mem_block, mem_size)
- Primitive.mprotect_write(mem_block, mem_size)
- end
-
- def mprotect_exec(mem_block, mem_size)
- Primitive.mprotect_exec(mem_block, mem_size)
- end
-
- def rjit_insn_exits
- addr = Primitive.cexpr! 'SIZET2NUM((size_t)rjit_insn_exits)'
- CType::Immediate.parse("size_t").new(addr)
- end
-
- def rb_rjit_counters
- addr = Primitive.cexpr! 'SIZET2NUM((size_t)&rb_rjit_counters)'
- rb_rjit_runtime_counters.new(addr)
- end
-
- # @param from [Integer] - From address
- # @param to [Integer] - To address
- def dump_disasm(from, to, test: false)
- Primitive.dump_disasm(from, to, test)
- end
-
- # Convert a Ruby object to a VALUE in Integer
- def to_value(obj)
- Primitive.cexpr! 'SIZET2NUM((size_t)obj)'
- end
-
- def BASIC_OP_UNREDEFINED_P(op, klass)
- Primitive.cexpr! 'RBOOL(BASIC_OP_UNREDEFINED_P(NUM2INT(op), NUM2INT(klass)))'
- end
-
- def rb_iseq_line_no(iseq, pos)
- _iseq_addr = iseq.to_i
- Primitive.cexpr! 'UINT2NUM(rb_iseq_line_no((const rb_iseq_t *)NUM2SIZET(_iseq_addr), NUM2SIZET(pos)))'
- end
-
- def rb_class_of(obj)
- Primitive.cexpr! 'rb_class_of(obj)'
- end
-
- def rb_callable_method_entry(klass, mid)
- cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_callable_method_entry(klass, NUM2UINT(mid)))'
- return nil if cme_addr == 0
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def METHOD_ENTRY_VISI(cme)
- _cme_addr = cme.to_i
- Primitive.cexpr! 'UINT2NUM(METHOD_ENTRY_VISI((const rb_callable_method_entry_t *)NUM2SIZET(_cme_addr)))'
- end
-
- def rb_simple_iseq_p(iseq)
- _iseq_addr = iseq.to_i
- Primitive.cexpr! 'RBOOL(rb_simple_iseq_p((rb_iseq_t *)NUM2SIZET(_iseq_addr)))'
- end
-
- def SPECIAL_CONST_P(obj)
- _value = to_value(obj)
- Primitive.cexpr! 'RBOOL(SPECIAL_CONST_P((VALUE)NUM2SIZET(_value)))'
- end
-
- def BUILTIN_TYPE(obj)
- _value = to_value(obj)
- Primitive.cexpr! 'INT2NUM(BUILTIN_TYPE((VALUE)NUM2SIZET(_value)))'
- end
-
- def RB_TYPE_P(obj, type)
- Primitive.cexpr! 'RBOOL(RB_TYPE_P(obj, NUM2UINT(type)))'
- end
-
- def rb_shape_get_shape_id(obj)
- _value = to_value(obj)
- Primitive.cexpr! 'UINT2NUM((unsigned int)rb_shape_get_shape_id((VALUE)NUM2SIZET(_value)))'
- end
-
- def rb_shape_id_offset
- Primitive.cexpr! 'INT2NUM(rb_shape_id_offset())'
- end
-
- def rb_shape_get_iv_index(shape_id, ivar_id)
- Primitive.cstmt! %{
- rb_shape_t *shape = rb_shape_get_shape_by_id((shape_id_t)NUM2SIZET(shape_id));
- attr_index_t index;
- bool found = rb_shape_get_iv_index(shape, (ID)NUM2SIZET(ivar_id), &index);
- return found ? UINT2NUM(index) : Qnil;
- }
- end
-
- def FL_TEST_RAW(obj, flags)
- Primitive.cexpr! 'RBOOL(FL_TEST_RAW(obj, (VALUE)NUM2SIZET(flags)))'
- end
-
- def FL_TEST(obj, flags)
- Primitive.cexpr! 'RBOOL(FL_TEST(obj, (VALUE)NUM2SIZET(flags)))'
- end
-
- def rjit_for_each_iseq(&block)
- Primitive.rjit_for_each_iseq(block)
- end
-
- def get_symbol_id(name)
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_get_symbol_id(name))'
- end
-
- def rb_vm_frame_method_entry(cfp)
- _cfp = cfp.to_i
- cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_vm_frame_method_entry((const rb_control_frame_t *)NUM2SIZET(_cfp)))'
- return nil if cme_addr == 0
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def rb_class_get_superclass(klass)
- Primitive.cexpr! 'rb_class_get_superclass(klass)'
- end
-
- def ID2SYM(id)
- Primitive.cexpr! 'ID2SYM((ID)NUM2SIZET(id))'
- end
-
- def obj_is_kind_of(obj, c)
- Primitive.cexpr! 'rb_obj_is_kind_of(obj, c)'
- end
-
- def imemo_type_p(ptr, type)
- _ptr = ptr.to_i
- Primitive.cexpr! 'RBOOL(imemo_type_p((VALUE)NUM2SIZET(_ptr), NUM2UINT(type)))'
- end
-
- def rb_iseq_only_optparam_p(iseq)
- _iseq = iseq.to_i
- Primitive.cstmt! %{
- extern bool rb_iseq_only_optparam_p(const rb_iseq_t *iseq);
- return RBOOL(rb_iseq_only_optparam_p((rb_iseq_t *)NUM2SIZET(_iseq)));
- }
- end
-
- def rb_iseq_only_kwparam_p(iseq)
- _iseq = iseq.to_i
- Primitive.cstmt! %{
- extern bool rb_iseq_only_kwparam_p(const rb_iseq_t *iseq);
- return RBOOL(rb_iseq_only_kwparam_p((rb_iseq_t *)NUM2SIZET(_iseq)));
- }
- end
-
- def rb_obj_frozen_p(obj)
- Primitive.cexpr! 'rb_obj_frozen_p(obj)'
- end
-
- def rb_intern(str)
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_intern(RSTRING_PTR(str)))'
- end
-
- def rb_method_entry_at(klass, mid)
- me_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_method_entry_at(klass, (ID)NUM2SIZET(mid)))'
- me_addr == 0 ? nil : rb_method_entry_t.new(me_addr)
- end
-
- def rb_shape_get_next(shape, obj, id)
- _shape = shape.to_i
- shape_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_shape_get_next((rb_shape_t *)NUM2SIZET(_shape), obj, (ID)NUM2SIZET(id)))'
- rb_shape_t.new(shape_addr)
- end
-
- def rb_shape_id(shape)
- _shape = shape.to_i
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_shape_id((rb_shape_t *)NUM2SIZET(_shape)))'
- end
-
- def rb_class_attached_object(klass)
- Primitive.cexpr! 'rb_class_attached_object(klass)'
- end
-
- def rb_singleton_class(obj)
- Primitive.cexpr! 'rb_singleton_class(obj)'
- end
-
- def rb_aliased_callable_method_entry(cme)
- _cme = cme.to_i
- cme_addr = Primitive.cstmt! %{
- extern const rb_callable_method_entry_t * rb_aliased_callable_method_entry(const rb_callable_method_entry_t *me);
- return SIZET2NUM((size_t)rb_aliased_callable_method_entry((const rb_callable_method_entry_t *)NUM2SIZET(_cme)));
- }
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def rb_yjit_get_proc_ptr(proc_addr)
- proc_t_addr = Primitive.cstmt! %{
- extern rb_proc_t * rjit_get_proc_ptr(VALUE procv);
- return SIZET2NUM((size_t)rjit_get_proc_ptr((VALUE)NUM2SIZET(proc_addr)));
- }
- rb_proc_t.new(proc_t_addr)
- end
-
- def rb_shape_get_shape_by_id(shape_id)
- _shape_id = shape_id.to_i
- shape_addr = Primitive.cexpr! 'SIZET2NUM((VALUE)rb_shape_get_shape_by_id((shape_id_t)NUM2UINT(_shape_id)))'
- rb_shape_t.new(shape_addr)
- end
-
- def rb_iseq_check(iseq)
- _iseq_addr = iseq.to_i
- iseq_addr = Primitive.cexpr! 'SIZET2NUM((VALUE)rb_iseq_check((rb_iseq_t *)NUM2SIZET(_iseq_addr)))'
- rb_iseq_t.new(iseq_addr)
- end
-
- def rb_iseq_path(iseq)
- _iseq_addr = iseq.to_i
- Primitive.cexpr! 'rb_iseq_path((rb_iseq_t *)NUM2SIZET(_iseq_addr))'
- end
-
- def vm_ci_argc(ci)
- _ci_addr = ci.to_i
- Primitive.cexpr! 'UINT2NUM(vm_ci_argc((CALL_INFO)NUM2SIZET(_ci_addr)))'
- end
-
- def vm_ci_flag(ci)
- _ci_addr = ci.to_i
- Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2SIZET(_ci_addr)))'
- end
-
- def vm_ci_kwarg(ci)
- _ci_addr = ci.to_i
- kwarg_addr = Primitive.cexpr! 'SIZET2NUM((size_t)vm_ci_kwarg((CALL_INFO)NUM2SIZET(_ci_addr)))'
- kwarg_addr == 0 ? nil : rb_callinfo_kwarg.new(kwarg_addr)
- end
-
- def vm_ci_mid(ci)
- _ci_addr = ci.to_i
- Primitive.cexpr! 'SIZET2NUM((size_t)vm_ci_mid((CALL_INFO)NUM2SIZET(_ci_addr)))'
- end
-
- def rjit_opts
- addr = Primitive.cexpr! 'SIZET2NUM((VALUE)&rb_rjit_opts)'
- rb_rjit_options.new(addr)
- end
-
- def rjit_cancel_all(reason)
- Primitive.cstmt! %{
- rb_rjit_cancel_all(RSTRING_PTR(reason));
- return Qnil;
- }
- end
-
- # Convert an encoded VM pointer to an insn BIN.
- def rb_vm_insn_decode(encoded)
- # Using rb_vm_insn_addr2opcode to return trace_ insns
- Primitive.cexpr! 'INT2NUM(rb_vm_insn_addr2opcode((void *)NUM2SIZET(encoded)))'
- end
-
- # Convert Integer VALUE to an actual Ruby object
- def to_ruby(value)
- Primitive.cexpr! '(VALUE)NUM2SIZET(value)'
- end
-
- def HAVE_LIBCAPSTONE
- Primitive.cstmt! %{
- #ifdef HAVE_LIBCAPSTONE
- return Qtrue;
- #else
- return Qfalse;
- #endif
- }
- end
-
- def rjit_exit_traces
- Primitive.cexpr! 'rjit_exit_traces()'
- end
-
- def rb_vm_ep_local_ep(ep)
- _ep = ep.to_i
- lep_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_vm_ep_local_ep((const VALUE *)NUM2SIZET(_ep)))'
- C.VALUE.new(lep_addr)
- end
-
- def rb_hash_keys(hash)
- Primitive.cexpr! 'rb_hash_keys(hash)'
- end
-
- def rb_hash_stlike_lookup(hash, key)
- Primitive.cstmt! %{
- VALUE result = Qnil;
- rb_hash_stlike_lookup(hash, key, &result);
- return result;
- }
- end
-
- def rb_obj_class(obj)
- Primitive.cexpr! 'rb_obj_class(obj)'
- end
-
- def rb_sym2id(sym)
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_sym2id(sym))'
- end
-
- def rb_callable_method_entry_or_negative(klass, mid)
- cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_callable_method_entry_or_negative(klass, (ID)NUM2SIZET(mid)))'
- return nil if cme_addr == 0
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def rb_method_basic_definition_p(klass, mid)
- Primitive.cexpr! 'RBOOL(rb_method_basic_definition_p(klass, (ID)NUM2SIZET(mid)))'
- end
-
- def UNDEFINED_METHOD_ENTRY_P(cme)
- _cme_addr = cme.to_i
- Primitive.cexpr! 'RBOOL(UNDEFINED_METHOD_ENTRY_P((const rb_callable_method_entry_t *)NUM2SIZET(_cme_addr)))'
- end
-
- def RCLASS_ORIGIN(klass)
- Primitive.cexpr! 'RCLASS_ORIGIN(klass)'
- end
- end
-
- #
- # Utilities: Not used by RJIT, but useful for debugging
- #
- class << C
- # Convert insn BINs to encoded VM pointers.
- def rb_vm_insn_encode(bin)
- Primitive.cexpr! 'SIZET2NUM((VALUE)rb_vm_get_insns_address_table()[NUM2INT(bin)])'
- end
-
- # Convert RubyVM::InstructionSequence to C.rb_iseq_t.
- def rb_iseqw_to_iseq(iseqw)
- iseq_addr = Primitive.cexpr! 'SIZET2NUM((VALUE)rb_iseqw_to_iseq(iseqw))'
- rb_iseq_t.new(iseq_addr)
- end
- end
-
- ### RJIT bindgen begin ###
-
- C::UNLIMITED_ARGUMENTS = Primitive.cexpr! %q{ LONG2NUM(UNLIMITED_ARGUMENTS) }
- C::VM_ENV_DATA_INDEX_ME_CREF = Primitive.cexpr! %q{ LONG2NUM(VM_ENV_DATA_INDEX_ME_CREF) }
- C::VM_ENV_DATA_INDEX_SPECVAL = Primitive.cexpr! %q{ LONG2NUM(VM_ENV_DATA_INDEX_SPECVAL) }
- C::ARRAY_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(ARRAY_REDEFINED_OP_FLAG) }
- C::BOP_AND = Primitive.cexpr! %q{ SIZET2NUM(BOP_AND) }
- C::BOP_AREF = Primitive.cexpr! %q{ SIZET2NUM(BOP_AREF) }
- C::BOP_EQ = Primitive.cexpr! %q{ SIZET2NUM(BOP_EQ) }
- C::BOP_EQQ = Primitive.cexpr! %q{ SIZET2NUM(BOP_EQQ) }
- C::BOP_FREEZE = Primitive.cexpr! %q{ SIZET2NUM(BOP_FREEZE) }
- C::BOP_GE = Primitive.cexpr! %q{ SIZET2NUM(BOP_GE) }
- C::BOP_GT = Primitive.cexpr! %q{ SIZET2NUM(BOP_GT) }
- C::BOP_LE = Primitive.cexpr! %q{ SIZET2NUM(BOP_LE) }
- C::BOP_LT = Primitive.cexpr! %q{ SIZET2NUM(BOP_LT) }
- C::BOP_MINUS = Primitive.cexpr! %q{ SIZET2NUM(BOP_MINUS) }
- C::BOP_MOD = Primitive.cexpr! %q{ SIZET2NUM(BOP_MOD) }
- C::BOP_OR = Primitive.cexpr! %q{ SIZET2NUM(BOP_OR) }
- C::BOP_PLUS = Primitive.cexpr! %q{ SIZET2NUM(BOP_PLUS) }
- C::BUILTIN_ATTR_LEAF = Primitive.cexpr! %q{ SIZET2NUM(BUILTIN_ATTR_LEAF) }
- C::BUILTIN_ATTR_NO_GC = Primitive.cexpr! %q{ SIZET2NUM(BUILTIN_ATTR_NO_GC) }
- C::HASH_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(HASH_REDEFINED_OP_FLAG) }
- C::INTEGER_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(INTEGER_REDEFINED_OP_FLAG) }
- C::INVALID_SHAPE_ID = Primitive.cexpr! %q{ SIZET2NUM(INVALID_SHAPE_ID) }
- C::METHOD_VISI_PRIVATE = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_PRIVATE) }
- C::METHOD_VISI_PROTECTED = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_PROTECTED) }
- C::METHOD_VISI_PUBLIC = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_PUBLIC) }
- C::METHOD_VISI_UNDEF = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_UNDEF) }
- C::OBJ_TOO_COMPLEX_SHAPE_ID = Primitive.cexpr! %q{ SIZET2NUM(OBJ_TOO_COMPLEX_SHAPE_ID) }
- C::OPTIMIZED_METHOD_TYPE_BLOCK_CALL = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_BLOCK_CALL) }
- C::OPTIMIZED_METHOD_TYPE_CALL = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_CALL) }
- C::OPTIMIZED_METHOD_TYPE_SEND = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_SEND) }
- C::OPTIMIZED_METHOD_TYPE_STRUCT_AREF = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_STRUCT_AREF) }
- C::OPTIMIZED_METHOD_TYPE_STRUCT_ASET = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_STRUCT_ASET) }
- C::RARRAY_EMBED_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RARRAY_EMBED_FLAG) }
- C::RARRAY_EMBED_LEN_MASK = Primitive.cexpr! %q{ SIZET2NUM(RARRAY_EMBED_LEN_MASK) }
- C::RARRAY_EMBED_LEN_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(RARRAY_EMBED_LEN_SHIFT) }
- C::RHASH_PASS_AS_KEYWORDS = Primitive.cexpr! %q{ SIZET2NUM(RHASH_PASS_AS_KEYWORDS) }
- C::RMODULE_IS_REFINEMENT = Primitive.cexpr! %q{ SIZET2NUM(RMODULE_IS_REFINEMENT) }
- C::ROBJECT_EMBED = Primitive.cexpr! %q{ SIZET2NUM(ROBJECT_EMBED) }
- C::RSTRUCT_EMBED_LEN_MASK = Primitive.cexpr! %q{ SIZET2NUM(RSTRUCT_EMBED_LEN_MASK) }
- C::RUBY_ENCODING_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_ENCODING_MASK) }
- C::RUBY_EVENT_CLASS = Primitive.cexpr! %q{ SIZET2NUM(RUBY_EVENT_CLASS) }
- C::RUBY_EVENT_C_CALL = Primitive.cexpr! %q{ SIZET2NUM(RUBY_EVENT_C_CALL) }
- C::RUBY_EVENT_C_RETURN = Primitive.cexpr! %q{ SIZET2NUM(RUBY_EVENT_C_RETURN) }
- C::RUBY_FIXNUM_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FIXNUM_FLAG) }
- C::RUBY_FLONUM_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_FLAG) }
- C::RUBY_FLONUM_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_MASK) }
- C::RUBY_FL_FREEZE = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FL_FREEZE) }
- C::RUBY_FL_SINGLETON = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FL_SINGLETON) }
- C::RUBY_IMMEDIATE_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_IMMEDIATE_MASK) }
- C::RUBY_SPECIAL_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SPECIAL_SHIFT) }
- C::RUBY_SYMBOL_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SYMBOL_FLAG) }
- C::RUBY_T_ARRAY = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_ARRAY) }
- C::RUBY_T_CLASS = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_CLASS) }
- C::RUBY_T_HASH = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_HASH) }
- C::RUBY_T_ICLASS = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_ICLASS) }
- C::RUBY_T_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_MASK) }
- C::RUBY_T_MODULE = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_MODULE) }
- C::RUBY_T_OBJECT = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_OBJECT) }
- C::RUBY_T_STRING = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_STRING) }
- C::RUBY_T_SYMBOL = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_SYMBOL) }
- C::SHAPE_CAPACITY_CHANGE = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_CAPACITY_CHANGE) }
- C::SHAPE_FLAG_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_FLAG_SHIFT) }
- C::SHAPE_FROZEN = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_FROZEN) }
- C::SHAPE_ID_NUM_BITS = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_ID_NUM_BITS) }
- C::SHAPE_IVAR = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_IVAR) }
- C::SHAPE_MASK = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_MASK) }
- C::SHAPE_ROOT = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_ROOT) }
- C::STRING_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(STRING_REDEFINED_OP_FLAG) }
- C::T_OBJECT = Primitive.cexpr! %q{ SIZET2NUM(T_OBJECT) }
- C::VM_BLOCK_HANDLER_NONE = Primitive.cexpr! %q{ SIZET2NUM(VM_BLOCK_HANDLER_NONE) }
- C::VM_CALL_ARGS_BLOCKARG = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_ARGS_BLOCKARG) }
- C::VM_CALL_ARGS_SPLAT = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_ARGS_SPLAT) }
- C::VM_CALL_FCALL = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_FCALL) }
- C::VM_CALL_KWARG = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KWARG) }
- C::VM_CALL_KW_SPLAT = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KW_SPLAT) }
- C::VM_CALL_KW_SPLAT_MUT = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KW_SPLAT_MUT) }
- C::VM_CALL_KW_SPLAT_bit = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KW_SPLAT_bit) }
- C::VM_CALL_OPT_SEND = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_OPT_SEND) }
- C::VM_CALL_TAILCALL = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_TAILCALL) }
- C::VM_CALL_TAILCALL_bit = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_TAILCALL_bit) }
- C::VM_CALL_ZSUPER = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_ZSUPER) }
- C::VM_ENV_DATA_INDEX_FLAGS = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_DATA_INDEX_FLAGS) }
- C::VM_ENV_DATA_SIZE = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_DATA_SIZE) }
- C::VM_ENV_FLAG_LOCAL = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_FLAG_LOCAL) }
- C::VM_ENV_FLAG_WB_REQUIRED = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_FLAG_WB_REQUIRED) }
- C::VM_FRAME_FLAG_BMETHOD = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_BMETHOD) }
- C::VM_FRAME_FLAG_CFRAME = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_CFRAME) }
- C::VM_FRAME_FLAG_CFRAME_KW = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_CFRAME_KW) }
- C::VM_FRAME_FLAG_LAMBDA = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_LAMBDA) }
- C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) }
- C::VM_FRAME_MAGIC_BLOCK = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_MAGIC_BLOCK) }
- C::VM_FRAME_MAGIC_CFUNC = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_MAGIC_CFUNC) }
- C::VM_FRAME_MAGIC_METHOD = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_MAGIC_METHOD) }
- C::VM_METHOD_TYPE_ALIAS = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ALIAS) }
- C::VM_METHOD_TYPE_ATTRSET = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ATTRSET) }
- C::VM_METHOD_TYPE_BMETHOD = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_BMETHOD) }
- C::VM_METHOD_TYPE_CFUNC = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_CFUNC) }
- C::VM_METHOD_TYPE_ISEQ = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ISEQ) }
- C::VM_METHOD_TYPE_IVAR = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_IVAR) }
- C::VM_METHOD_TYPE_MISSING = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_MISSING) }
- C::VM_METHOD_TYPE_NOTIMPLEMENTED = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_NOTIMPLEMENTED) }
- C::VM_METHOD_TYPE_OPTIMIZED = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_OPTIMIZED) }
- C::VM_METHOD_TYPE_REFINED = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_REFINED) }
- C::VM_METHOD_TYPE_UNDEF = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_UNDEF) }
- C::VM_METHOD_TYPE_ZSUPER = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ZSUPER) }
- C::VM_SPECIAL_OBJECT_VMCORE = Primitive.cexpr! %q{ SIZET2NUM(VM_SPECIAL_OBJECT_VMCORE) }
-
- def C.block_type_iseq
- Primitive.cexpr! %q{ SIZET2NUM(block_type_iseq) }
- end
-
- def C.idRespond_to_missing
- Primitive.cexpr! %q{ SIZET2NUM(idRespond_to_missing) }
- end
-
- def C.imemo_callinfo
- Primitive.cexpr! %q{ SIZET2NUM(imemo_callinfo) }
- end
-
- def C.imemo_iseq
- Primitive.cexpr! %q{ SIZET2NUM(imemo_iseq) }
- end
-
- def C.rb_block_param_proxy
- Primitive.cexpr! %q{ SIZET2NUM(rb_block_param_proxy) }
- end
-
- def C.rb_cArray
- Primitive.cexpr! %q{ SIZET2NUM(rb_cArray) }
- end
-
- def C.rb_cFalseClass
- Primitive.cexpr! %q{ SIZET2NUM(rb_cFalseClass) }
- end
-
- def C.rb_cFloat
- Primitive.cexpr! %q{ SIZET2NUM(rb_cFloat) }
- end
-
- def C.rb_cInteger
- Primitive.cexpr! %q{ SIZET2NUM(rb_cInteger) }
- end
-
- def C.rb_cNilClass
- Primitive.cexpr! %q{ SIZET2NUM(rb_cNilClass) }
- end
-
- def C.rb_cString
- Primitive.cexpr! %q{ SIZET2NUM(rb_cString) }
- end
-
- def C.rb_cSymbol
- Primitive.cexpr! %q{ SIZET2NUM(rb_cSymbol) }
- end
-
- def C.rb_cTrueClass
- Primitive.cexpr! %q{ SIZET2NUM(rb_cTrueClass) }
- end
-
- def C.rb_mRubyVMFrozenCore
- Primitive.cexpr! %q{ SIZET2NUM(rb_mRubyVMFrozenCore) }
- end
-
- def C.rb_rjit_global_events
- Primitive.cexpr! %q{ SIZET2NUM(rb_rjit_global_events) }
- end
-
- def C.rb_ary_clear
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_clear) }
- end
-
- def C.rb_ary_dup
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_dup) }
- end
-
- def C.rb_ary_entry_internal
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_entry_internal) }
- end
-
- def C.rb_ary_push
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_push) }
- end
-
- def C.rb_ary_resurrect
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_resurrect) }
- end
-
- def C.rb_ary_store
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_store) }
- end
-
- def C.rb_ary_tmp_new_from_values
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_tmp_new_from_values) }
- end
-
- def C.rb_ary_unshift_m
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_unshift_m) }
- end
-
- def C.rb_backref_get
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_backref_get) }
- end
-
- def C.rb_ec_ary_new_from_values
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ec_ary_new_from_values) }
- end
-
- def C.rb_ec_str_resurrect
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ec_str_resurrect) }
- end
-
- def C.rb_ensure_iv_list_size
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ensure_iv_list_size) }
- end
-
- def C.rb_fix_aref
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_aref) }
- end
-
- def C.rb_fix_div_fix
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_div_fix) }
- end
-
- def C.rb_fix_mod_fix
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_mod_fix) }
- end
-
- def C.rb_fix_mul_fix
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_mul_fix) }
- end
-
- def C.rb_gc_writebarrier
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_gc_writebarrier) }
- end
-
- def C.rb_get_symbol_id
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_get_symbol_id) }
- end
-
- def C.rb_gvar_get
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_gvar_get) }
- end
-
- def C.rb_hash_aref
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_aref) }
- end
-
- def C.rb_hash_aset
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_aset) }
- end
-
- def C.rb_hash_bulk_insert
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_bulk_insert) }
- end
-
- def C.rb_hash_new
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_new) }
- end
-
- def C.rb_hash_new_with_size
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_new_with_size) }
- end
-
- def C.rb_hash_resurrect
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_resurrect) }
- end
-
- def C.rb_ivar_defined
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ivar_defined) }
- end
-
- def C.rb_ivar_get
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ivar_get) }
- end
-
- def C.rb_obj_as_string_result
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_obj_as_string_result) }
- end
-
- def C.rb_obj_is_kind_of
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_obj_is_kind_of) }
- end
-
- def C.rb_range_new
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_range_new) }
- end
-
- def C.rb_reg_last_match
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_last_match) }
- end
-
- def C.rb_reg_match_last
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_match_last) }
- end
-
- def C.rb_reg_match_post
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_match_post) }
- end
-
- def C.rb_reg_match_pre
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_match_pre) }
- end
-
- def C.rb_reg_new_ary
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_new_ary) }
- end
-
- def C.rb_reg_nth_match
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_nth_match) }
- end
-
- def C.rb_rjit_branch_stub_hit
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_rjit_branch_stub_hit) }
- end
-
- def C.rb_rjit_entry_stub_hit
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_rjit_entry_stub_hit) }
- end
-
- def C.rb_str_buf_append
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_buf_append) }
- end
-
- def C.rb_str_bytesize
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_bytesize) }
- end
-
- def C.rb_str_concat_literals
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_concat_literals) }
- end
-
- def C.rb_str_dup
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_dup) }
- end
-
- def C.rb_str_eql_internal
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_eql_internal) }
- end
-
- def C.rb_str_getbyte
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_getbyte) }
- end
-
- def C.rb_str_intern
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_intern) }
- end
-
- def C.rb_sym_to_proc
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_sym_to_proc) }
- end
-
- def C.rb_vm_bh_to_procval
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_bh_to_procval) }
- end
-
- def C.rb_vm_concat_array
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_concat_array) }
- end
-
- def C.rb_vm_defined
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_defined) }
- end
-
- def C.rb_vm_get_ev_const
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_get_ev_const) }
- end
-
- def C.rb_vm_getclassvariable
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_getclassvariable) }
- end
-
- def C.rb_vm_ic_hit_p
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_ic_hit_p) }
- end
-
- def C.rb_vm_opt_newarray_hash
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_hash) }
- end
-
- def C.rb_vm_opt_newarray_max
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_max) }
- end
-
- def C.rb_vm_opt_newarray_min
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_min) }
- end
-
- def C.rb_vm_set_ivar_id
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_set_ivar_id) }
- end
-
- def C.rb_vm_setclassvariable
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_setclassvariable) }
- end
-
- def C.rb_vm_setinstancevariable
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_setinstancevariable) }
- end
-
- def C.rb_vm_splat_array
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_splat_array) }
- end
-
- def C.rb_vm_throw
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_throw) }
- end
-
- def C.rb_vm_yield_with_cfunc
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_yield_with_cfunc) }
- end
-
- def C.rjit_build_kwhash
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_build_kwhash) }
- end
-
- def C.rjit_full_cfunc_return
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_full_cfunc_return) }
- end
-
- def C.rjit_optimized_call
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_optimized_call) }
- end
-
- def C.rjit_rb_ary_subseq_length
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_rb_ary_subseq_length) }
- end
-
- def C.rjit_record_exit_stack
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_record_exit_stack) }
- end
-
- def C.rjit_str_neq_internal
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_str_neq_internal) }
- end
-
- def C.rjit_str_simple_append
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_str_simple_append) }
- end
-
- def C.CALL_DATA
- @CALL_DATA ||= self.rb_call_data
- end
-
- def C.IC
- @IC ||= self.iseq_inline_constant_cache
- end
-
- def C.ID
- @ID ||= CType::Immediate.parse("unsigned long")
- end
-
- def C.IVC
- @IVC ||= self.iseq_inline_iv_cache_entry
- end
-
- def C.RArray
- @RArray ||= CType::Struct.new(
- "RArray", Primitive.cexpr!("SIZEOF(struct RArray)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RArray *)NULL)), basic)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RArray *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RArray *)NULL)->as.heap)"),
- len: [CType::Immediate.parse("long"), Primitive.cexpr!("OFFSETOF(((struct RArray *)NULL)->as.heap, len)")],
- aux: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RArray *)NULL)->as.heap.aux)"),
- capa: CType::Immediate.parse("long"),
- shared_root: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF(((struct RArray *)NULL)->as.heap, aux)")],
- ptr: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct RArray *)NULL)->as.heap, ptr)")],
- ),
- ary: CType::Pointer.new { self.VALUE },
- ), Primitive.cexpr!("OFFSETOF((*((struct RArray *)NULL)), as)")],
- )
- end
-
- def C.RB_BUILTIN
- @RB_BUILTIN ||= self.rb_builtin_function
- end
-
- def C.RBasic
- @RBasic ||= CType::Struct.new(
- "RBasic", Primitive.cexpr!("SIZEOF(struct RBasic)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct RBasic *)NULL)), flags)")],
- klass: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct RBasic *)NULL)), klass)")],
- )
- end
-
- def C.RObject
- @RObject ||= CType::Struct.new(
- "RObject", Primitive.cexpr!("SIZEOF(struct RObject)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RObject *)NULL)), basic)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RObject *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RObject *)NULL)->as.heap)"),
- ivptr: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct RObject *)NULL)->as.heap, ivptr)")],
- iv_index_tbl: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF(((struct RObject *)NULL)->as.heap, iv_index_tbl)")],
- ),
- ary: CType::Pointer.new { self.VALUE },
- ), Primitive.cexpr!("OFFSETOF((*((struct RObject *)NULL)), as)")],
- )
- end
-
- def C.RString
- @RString ||= CType::Struct.new(
- "RString", Primitive.cexpr!("SIZEOF(struct RString)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RString *)NULL)), basic)")],
- len: [CType::Immediate.parse("long"), Primitive.cexpr!("OFFSETOF((*((struct RString *)NULL)), len)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as.heap)"),
- ptr: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF(((struct RString *)NULL)->as.heap, ptr)")],
- aux: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as.heap.aux)"),
- capa: CType::Immediate.parse("long"),
- shared: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF(((struct RString *)NULL)->as.heap, aux)")],
- ),
- embed: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as.embed)"),
- ary: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF(((struct RString *)NULL)->as.embed, ary)")],
- ),
- ), Primitive.cexpr!("OFFSETOF((*((struct RString *)NULL)), as)")],
- )
- end
-
- def C.RStruct
- @RStruct ||= CType::Struct.new(
- "RStruct", Primitive.cexpr!("SIZEOF(struct RStruct)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RStruct *)NULL)), basic)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RStruct *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RStruct *)NULL)->as.heap)"),
- len: [CType::Immediate.parse("long"), Primitive.cexpr!("OFFSETOF(((struct RStruct *)NULL)->as.heap, len)")],
- ptr: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct RStruct *)NULL)->as.heap, ptr)")],
- ),
- ary: CType::Pointer.new { self.VALUE },
- ), Primitive.cexpr!("OFFSETOF((*((struct RStruct *)NULL)), as)")],
- )
- end
-
- def C.attr_index_t
- @attr_index_t ||= CType::Immediate.parse("uint32_t")
- end
-
- def C.iseq_inline_constant_cache
- @iseq_inline_constant_cache ||= CType::Struct.new(
- "iseq_inline_constant_cache", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache)"),
- entry: [CType::Pointer.new { self.iseq_inline_constant_cache_entry }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), entry)")],
- segments: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), segments)")],
- )
- end
-
- def C.iseq_inline_constant_cache_entry
- @iseq_inline_constant_cache_entry ||= CType::Struct.new(
- "iseq_inline_constant_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache_entry)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), flags)")],
- value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), value)")],
- _unused1: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused1)")],
- _unused2: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused2)")],
- ic_cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), ic_cref)")],
- )
- end
-
- def C.iseq_inline_iv_cache_entry
- @iseq_inline_iv_cache_entry ||= CType::Struct.new(
- "iseq_inline_iv_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_iv_cache_entry)"),
- value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), value)")],
- iv_set_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), iv_set_name)")],
- )
- end
-
- def C.iseq_inline_storage_entry
- @iseq_inline_storage_entry ||= CType::Union.new(
- "iseq_inline_storage_entry", Primitive.cexpr!("SIZEOF(union iseq_inline_storage_entry)"),
- once: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((union iseq_inline_storage_entry *)NULL)->once)"),
- running_thread: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, running_thread)")],
- value: [self.VALUE, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, value)")],
- ),
- ic_cache: self.iseq_inline_constant_cache,
- iv_cache: self.iseq_inline_iv_cache_entry,
- )
- end
-
- def C.method_optimized_type
- @method_optimized_type ||= CType::Immediate.parse("int")
- end
-
- def C.rb_block
- @rb_block ||= CType::Struct.new(
- "rb_block", Primitive.cexpr!("SIZEOF(struct rb_block)"),
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_block *)NULL)->as)"),
- captured: self.rb_captured_block,
- symbol: self.VALUE,
- proc: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_block *)NULL)), as)")],
- type: [self.rb_block_type, Primitive.cexpr!("OFFSETOF((*((struct rb_block *)NULL)), type)")],
- )
- end
-
- def C.rb_block_type
- @rb_block_type ||= CType::Immediate.parse("int")
- end
-
- def C.rb_builtin_function
- @rb_builtin_function ||= CType::Struct.new(
- "rb_builtin_function", Primitive.cexpr!("SIZEOF(struct rb_builtin_function)"),
- func_ptr: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), func_ptr)")],
- argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), argc)")],
- index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), index)")],
- name: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), name)")],
- )
- end
-
- def C.rb_call_data
- @rb_call_data ||= CType::Struct.new(
- "rb_call_data", Primitive.cexpr!("SIZEOF(struct rb_call_data)"),
- ci: [CType::Pointer.new { self.rb_callinfo }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), ci)")],
- cc: [CType::Pointer.new { self.rb_callcache }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), cc)")],
- )
- end
-
- def C.rb_callable_method_entry_struct
- @rb_callable_method_entry_struct ||= CType::Struct.new(
- "rb_callable_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_callable_method_entry_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), flags)")],
- defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), defined_class)"), true],
- def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), def)")],
- called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), called_id)")],
- owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), owner)")],
- )
- end
-
- def C.rb_callable_method_entry_t
- @rb_callable_method_entry_t ||= CType::Struct.new(
- "rb_callable_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_callable_method_entry_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), flags)")],
- defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), defined_class)"), true],
- def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), def)")],
- called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), called_id)")],
- owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), owner)")],
- )
- end
-
- def C.rb_callcache
- @rb_callcache ||= CType::Struct.new(
- "rb_callcache", Primitive.cexpr!("SIZEOF(struct rb_callcache)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), flags)")],
- klass: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), klass)")],
- cme_: [CType::Pointer.new { self.rb_callable_method_entry_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), cme_)")],
- call_: [self.vm_call_handler, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), call_)")],
- aux_: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_)"),
- attr: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_.attr)"),
- value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF(((struct rb_callcache *)NULL)->aux_.attr, value)")],
- ),
- method_missing_reason: self.method_missing_reason,
- v: self.VALUE,
- bf: CType::Pointer.new { self.rb_builtin_function },
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), aux_)")],
- )
- end
-
- def C.rb_callinfo
- @rb_callinfo ||= CType::Struct.new(
- "rb_callinfo", Primitive.cexpr!("SIZEOF(struct rb_callinfo)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flags)")],
- kwarg: [CType::Pointer.new { self.rb_callinfo_kwarg }, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), kwarg)")],
- mid: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), mid)")],
- flag: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flag)")],
- argc: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), argc)")],
- )
- end
-
- def C.rb_callinfo_kwarg
- @rb_callinfo_kwarg ||= CType::Struct.new(
- "rb_callinfo_kwarg", Primitive.cexpr!("SIZEOF(struct rb_callinfo_kwarg)"),
- keyword_len: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo_kwarg *)NULL)), keyword_len)")],
- references: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo_kwarg *)NULL)), references)")],
- keywords: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo_kwarg *)NULL)), keywords)")],
- )
- end
-
- def C.rb_captured_block
- @rb_captured_block ||= CType::Struct.new(
- "rb_captured_block", Primitive.cexpr!("SIZEOF(struct rb_captured_block)"),
- self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_captured_block *)NULL)), self)")],
- ep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_captured_block *)NULL)), ep)")],
- code: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_captured_block *)NULL)->code)"),
- iseq: CType::Pointer.new { self.rb_iseq_t },
- ifunc: CType::Pointer.new { self.vm_ifunc },
- val: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_captured_block *)NULL)), code)")],
- )
- end
-
- def C.rb_control_frame_t
- @rb_control_frame_t ||= CType::Struct.new(
- "rb_control_frame_struct", Primitive.cexpr!("SIZEOF(struct rb_control_frame_struct)"),
- pc: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), pc)")],
- sp: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), sp)")],
- iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), iseq)")],
- self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), self)")],
- ep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), ep)")],
- block_code: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), block_code)")],
- jit_return: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), jit_return)")],
- )
- end
-
- def C.rb_cref_t
- @rb_cref_t ||= CType::Struct.new(
- "rb_cref_struct", Primitive.cexpr!("SIZEOF(struct rb_cref_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), flags)")],
- refinements: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), refinements)")],
- klass_or_self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), klass_or_self)")],
- next: [CType::Pointer.new { self.rb_cref_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), next)")],
- scope_visi: [self.rb_scope_visibility_t, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), scope_visi)")],
- )
- end
-
- def C.rb_execution_context_struct
- @rb_execution_context_struct ||= CType::Struct.new(
- "rb_execution_context_struct", Primitive.cexpr!("SIZEOF(struct rb_execution_context_struct)"),
- vm_stack: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack)")],
- vm_stack_size: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack_size)")],
- cfp: [CType::Pointer.new { self.rb_control_frame_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), cfp)")],
- tag: [CType::Pointer.new { self.rb_vm_tag }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), tag)")],
- interrupt_flag: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_flag)")],
- interrupt_mask: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_mask)")],
- fiber_ptr: [CType::Pointer.new { self.rb_fiber_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), fiber_ptr)")],
- thread_ptr: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), thread_ptr)")],
- local_storage: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage)")],
- local_storage_recursive_hash: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash)")],
- local_storage_recursive_hash_for_trace: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash_for_trace)")],
- storage: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), storage)")],
- root_lep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_lep)")],
- root_svar: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_svar)")],
- ensure_list: [CType::Pointer.new { self.rb_ensure_list_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), ensure_list)")],
- trace_arg: [CType::Pointer.new { self.rb_trace_arg_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), trace_arg)")],
- errinfo: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), errinfo)")],
- passed_block_handler: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), passed_block_handler)")],
- raised_flag: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), raised_flag)")],
- private_const_reference: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), private_const_reference)")],
- machine: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_execution_context_struct *)NULL)->machine)"),
- stack_start: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_start)")],
- stack_end: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_end)")],
- stack_maxsize: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_maxsize)")],
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), machine)")],
- )
- end
-
- def C.rb_execution_context_t
- @rb_execution_context_t ||= self.rb_execution_context_struct
- end
-
- def C.rb_iseq_constant_body
- @rb_iseq_constant_body ||= CType::Struct.new(
- "rb_iseq_constant_body", Primitive.cexpr!("SIZEOF(struct rb_iseq_constant_body)"),
- type: [self.rb_iseq_type, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), type)")],
- iseq_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_size)")],
- iseq_encoded: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_encoded)")],
- param: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param)"),
- flags: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param.flags)"),
- has_lead: [CType::BitField.new(1, 0), 0],
- has_opt: [CType::BitField.new(1, 1), 1],
- has_rest: [CType::BitField.new(1, 2), 2],
- has_post: [CType::BitField.new(1, 3), 3],
- has_kw: [CType::BitField.new(1, 4), 4],
- has_kwrest: [CType::BitField.new(1, 5), 5],
- has_block: [CType::BitField.new(1, 6), 6],
- ambiguous_param0: [CType::BitField.new(1, 7), 7],
- accepts_no_kwarg: [CType::BitField.new(1, 0), 8],
- ruby2_keywords: [CType::BitField.new(1, 1), 9],
- ), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, flags)")],
- size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, size)")],
- lead_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, lead_num)")],
- opt_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_num)")],
- rest_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, rest_start)")],
- post_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_start)")],
- post_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_num)")],
- block_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, block_start)")],
- opt_table: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_table)")],
- keyword: [CType::Pointer.new { self.rb_iseq_param_keyword }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, keyword)")],
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), param)")],
- location: [self.rb_iseq_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), location)")],
- insns_info: [self.iseq_insn_info, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), insns_info)")],
- local_table: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table)")],
- catch_table: [CType::Pointer.new { self.iseq_catch_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), catch_table)")],
- parent_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), parent_iseq)")],
- local_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_iseq)")],
- is_entries: [CType::Pointer.new { self.iseq_inline_storage_entry }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), is_entries)")],
- call_data: [CType::Pointer.new { self.rb_call_data }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), call_data)")],
- variable: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->variable)"),
- flip_count: [self.rb_snum_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, flip_count)")],
- script_lines: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, script_lines)")],
- coverage: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, coverage)")],
- pc2branchindex: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, pc2branchindex)")],
- original_iseq: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, original_iseq)")],
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), variable)")],
- local_table_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table_size)")],
- ic_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ic_size)")],
- ise_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ise_size)")],
- ivc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ivc_size)")],
- icvarc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), icvarc_size)")],
- ci_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ci_size)")],
- stack_max: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), stack_max)")],
- builtin_attrs: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), builtin_attrs)")],
- mark_bits: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->mark_bits)"),
- list: CType::Pointer.new { self.iseq_bits_t },
- single: self.iseq_bits_t,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mark_bits)")],
- outer_variables: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), outer_variables)")],
- mandatory_only_iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mandatory_only_iseq)")],
- jit_entry: [self.rb_jit_func_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_entry)")],
- jit_entry_calls: [CType::Immediate.parse("unsigned long"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_entry_calls)")],
- rjit_blocks: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), rjit_blocks)"), true],
- )
- end
-
- def C.rb_iseq_location_t
- @rb_iseq_location_t ||= CType::Struct.new(
- "rb_iseq_location_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_location_struct)"),
- pathobj: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), pathobj)"), true],
- base_label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), base_label)"), true],
- label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), label)"), true],
- first_lineno: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), first_lineno)")],
- node_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), node_id)")],
- code_location: [self.rb_code_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), code_location)")],
- )
- end
-
- def C.rb_iseq_param_keyword
- @rb_iseq_param_keyword ||= CType::Struct.new(
- "rb_iseq_param_keyword", Primitive.cexpr!("SIZEOF(struct rb_iseq_param_keyword)"),
- num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), num)")],
- required_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), required_num)")],
- bits_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), bits_start)")],
- rest_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), rest_start)")],
- table: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), table)")],
- default_values: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), default_values)")],
- )
- end
-
- def C.rb_iseq_struct
- @rb_iseq_struct ||= CType::Struct.new(
- "rb_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), flags)")],
- wrapper: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), wrapper)")],
- body: [CType::Pointer.new { self.rb_iseq_constant_body }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), body)")],
- aux: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux)"),
- compile_data: CType::Pointer.new { self.iseq_compile_data },
- loader: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.loader)"),
- obj: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, obj)")],
- index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, index)")],
- ),
- exec: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.exec)"),
- local_hooks: [CType::Pointer.new { self.rb_hook_list_struct }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, local_hooks)")],
- global_trace_events: [self.rb_event_flag_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, global_trace_events)")],
- ),
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), aux)")],
- )
- end
-
- def C.rb_iseq_t
- @rb_iseq_t ||= self.rb_iseq_struct
- end
-
- def C.rb_jit_func_t
- @rb_jit_func_t ||= CType::Immediate.parse("void *")
- end
-
- def C.rb_method_attr_t
- @rb_method_attr_t ||= CType::Struct.new(
- "rb_method_attr_struct", Primitive.cexpr!("SIZEOF(struct rb_method_attr_struct)"),
- id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_attr_struct *)NULL)), id)")],
- location: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_attr_struct *)NULL)), location)")],
- )
- end
-
- def C.rb_method_bmethod_t
- @rb_method_bmethod_t ||= CType::Struct.new(
- "rb_method_bmethod_struct", Primitive.cexpr!("SIZEOF(struct rb_method_bmethod_struct)"),
- proc: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_bmethod_struct *)NULL)), proc)")],
- hooks: [CType::Pointer.new { self.rb_hook_list_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_bmethod_struct *)NULL)), hooks)")],
- defined_ractor: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_bmethod_struct *)NULL)), defined_ractor)")],
- )
- end
-
- def C.rb_method_cfunc_t
- @rb_method_cfunc_t ||= CType::Struct.new(
- "rb_method_cfunc_struct", Primitive.cexpr!("SIZEOF(struct rb_method_cfunc_struct)"),
- func: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_cfunc_struct *)NULL)), func)")],
- invoker: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_cfunc_struct *)NULL)), invoker)")],
- argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_cfunc_struct *)NULL)), argc)")],
- )
- end
-
- def C.rb_method_definition_struct
- @rb_method_definition_struct ||= CType::Struct.new(
- "rb_method_definition_struct", Primitive.cexpr!("SIZEOF(struct rb_method_definition_struct)"),
- type: [CType::BitField.new(4, 0), 0],
- iseq_overload: [CType::BitField.new(1, 4), 4],
- no_redef_warning: [CType::BitField.new(1, 5), 5],
- aliased: [CType::BitField.new(1, 6), 6],
- reference_count: [CType::BitField.new(28, 0), 32],
- body: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_method_definition_struct *)NULL)->body)"),
- iseq: self.rb_method_iseq_t,
- cfunc: self.rb_method_cfunc_t,
- attr: self.rb_method_attr_t,
- alias: self.rb_method_alias_t,
- refined: self.rb_method_refined_t,
- bmethod: self.rb_method_bmethod_t,
- optimized: self.rb_method_optimized_t,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), body)")],
- original_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), original_id)")],
- method_serial: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), method_serial)")],
- )
- end
-
- def C.rb_method_entry_t
- @rb_method_entry_t ||= CType::Struct.new(
- "rb_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_method_entry_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), flags)")],
- defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), defined_class)")],
- def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), def)")],
- called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), called_id)")],
- owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), owner)")],
- )
- end
-
- def C.rb_method_iseq_t
- @rb_method_iseq_t ||= CType::Struct.new(
- "rb_method_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_method_iseq_struct)"),
- iseqptr: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), iseqptr)")],
- cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), cref)")],
- )
- end
-
- def C.rb_method_optimized_t
- @rb_method_optimized_t ||= CType::Struct.new(
- "rb_method_optimized", Primitive.cexpr!("SIZEOF(struct rb_method_optimized)"),
- type: [self.method_optimized_type, Primitive.cexpr!("OFFSETOF((*((struct rb_method_optimized *)NULL)), type)")],
- index: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_optimized *)NULL)), index)")],
- )
- end
-
- def C.rb_method_type_t
- @rb_method_type_t ||= CType::Immediate.parse("int")
- end
-
- def C.rb_proc_t
- @rb_proc_t ||= CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(rb_proc_t)"),
- block: [self.rb_block, Primitive.cexpr!("OFFSETOF((*((rb_proc_t *)NULL)), block)")],
- )
- end
-
- def C.rb_rjit_options
- @rb_rjit_options ||= CType::Struct.new(
- "rb_rjit_options", Primitive.cexpr!("SIZEOF(struct rb_rjit_options)"),
- on: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), on)")],
- call_threshold: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), call_threshold)")],
- exec_mem_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), exec_mem_size)")],
- stats: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), stats)")],
- trace_exits: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), trace_exits)")],
- dump_disasm: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), dump_disasm)")],
- verify_ctx: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), verify_ctx)")],
- pause: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), pause)")],
- )
- end
-
- def C.rb_rjit_runtime_counters
- @rb_rjit_runtime_counters ||= CType::Struct.new(
- "rb_rjit_runtime_counters", Primitive.cexpr!("SIZEOF(struct rb_rjit_runtime_counters)"),
- vm_insns_count: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), vm_insns_count)")],
- rjit_insns_count: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), rjit_insns_count)")],
- send_args_splat_kw_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_kw_splat)")],
- send_args_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat)")],
- send_args_splat_not_array: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_not_array)")],
- send_args_splat_length_not_equal: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_length_not_equal)")],
- send_args_splat_cfunc_var_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_cfunc_var_args)")],
- send_args_splat_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_arity_error)")],
- send_args_splat_ruby2_hash: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_ruby2_hash)")],
- send_args_splat_cfunc_zuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_cfunc_zuper)")],
- send_args_splat_cfunc_ruby2_keywords: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_cfunc_ruby2_keywords)")],
- send_kw_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_kw_splat)")],
- send_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_kwarg)")],
- send_klass_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_klass_megamorphic)")],
- send_missing_cme: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_missing_cme)")],
- send_private: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_private)")],
- send_protected_check_failed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_protected_check_failed)")],
- send_tailcall: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_tailcall)")],
- send_notimplemented: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_notimplemented)")],
- send_missing: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_missing)")],
- send_bmethod: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_bmethod)")],
- send_alias: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_alias)")],
- send_undef: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_undef)")],
- send_zsuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_zsuper)")],
- send_refined: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_refined)")],
- send_stackoverflow: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_stackoverflow)")],
- send_arity: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_arity)")],
- send_c_tracing: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_c_tracing)")],
- send_is_a_class_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_is_a_class_mismatch)")],
- send_instance_of_class_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_instance_of_class_mismatch)")],
- send_keywords: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_keywords)")],
- send_blockiseq: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_blockiseq)")],
- send_block_handler: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_handler)")],
- send_block_setup: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_setup)")],
- send_block_not_nil: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_not_nil)")],
- send_block_not_proxy: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_not_proxy)")],
- send_block_arg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_arg)")],
- send_iseq_kwparam: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kwparam)")],
- send_iseq_accepts_no_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_accepts_no_kwarg)")],
- send_iseq_has_opt: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_opt)")],
- send_iseq_has_kwrest: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_kwrest)")],
- send_iseq_ruby2_keywords: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_ruby2_keywords)")],
- send_iseq_has_rest_and_captured: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_captured)")],
- send_iseq_has_rest_and_kw_supplied: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_kw_supplied)")],
- send_iseq_has_no_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_no_kw)")],
- send_iseq_zsuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_zsuper)")],
- send_iseq_materialized_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_materialized_block)")],
- send_iseq_has_rest: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest)")],
- send_iseq_block_arg0_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_block_arg0_splat)")],
- send_iseq_kw_call: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kw_call)")],
- send_iseq_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat)")],
- send_iseq_has_rest_and_optional: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_optional)")],
- send_iseq_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_arity_error)")],
- send_iseq_missing_optional_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_missing_optional_kw)")],
- send_iseq_too_many_kwargs: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_too_many_kwargs)")],
- send_iseq_kwargs_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kwargs_mismatch)")],
- send_iseq_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_with_kw)")],
- send_iseq_splat_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_arity_error)")],
- send_iseq_has_rest_and_splat_not_equal: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_splat_not_equal)")],
- send_cfunc_variadic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_variadic)")],
- send_cfunc_too_many_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_too_many_args)")],
- send_cfunc_ruby_array_varg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_ruby_array_varg)")],
- send_cfunc_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_splat_with_kw)")],
- send_cfunc_tracing: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_tracing)")],
- send_cfunc_argc_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_argc_mismatch)")],
- send_cfunc_toomany_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_toomany_args)")],
- send_attrset_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_attrset_splat)")],
- send_attrset_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_attrset_kwarg)")],
- send_attrset_method: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_attrset_method)")],
- send_ivar_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_ivar_splat)")],
- send_ivar_opt_send: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_ivar_opt_send)")],
- send_optimized_send_no_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_no_args)")],
- send_optimized_send_not_sym_or_str: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_not_sym_or_str)")],
- send_optimized_send_mid_class_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_mid_class_changed)")],
- send_optimized_send_mid_id_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_mid_id_changed)")],
- send_optimized_send_null_mid: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_null_mid)")],
- send_optimized_send_send: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_send)")],
- send_optimized_call_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_call_block)")],
- send_optimized_call_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_call_kwarg)")],
- send_optimized_call_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_call_splat)")],
- send_optimized_struct_aref_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_struct_aref_error)")],
- send_optimized_block_call: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_block_call)")],
- send_optimized_struct_aset: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_struct_aset)")],
- send_bmethod_not_iseq: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_bmethod_not_iseq)")],
- send_bmethod_blockarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_bmethod_blockarg)")],
- invokesuper_me_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_me_changed)")],
- invokesuper_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_block)")],
- invokeblock_none: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_none)")],
- invokeblock_symbol: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_symbol)")],
- invokeblock_proc: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_proc)")],
- invokeblock_tag_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_tag_changed)")],
- invokeblock_iseq_block_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_block_changed)")],
- invokeblock_iseq_arity: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arity)")],
- invokeblock_iseq_arg0_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arg0_splat)")],
- invokeblock_ifunc_args_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_ifunc_args_splat)")],
- invokeblock_ifunc_kw_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_ifunc_kw_splat)")],
- invokeblock_iseq_arg0_args_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arg0_args_splat)")],
- invokeblock_iseq_arg0_has_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arg0_has_kw)")],
- getivar_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_megamorphic)")],
- getivar_not_heap: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_not_heap)")],
- getivar_special_const: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_special_const)")],
- getivar_too_complex: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_too_complex)")],
- optaref_arg_not_fixnum: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_arg_not_fixnum)")],
- optaref_argc_not_one: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_argc_not_one)")],
- optaref_recv_not_array: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_recv_not_array)")],
- optaref_recv_not_hash: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_recv_not_hash)")],
- optaref_send: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_send)")],
- optgetconst_not_cached: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optgetconst_not_cached)")],
- optgetconst_cref: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optgetconst_cref)")],
- optgetconst_cache_miss: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optgetconst_cache_miss)")],
- setivar_frozen: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_frozen)")],
- setivar_not_heap: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_not_heap)")],
- setivar_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_megamorphic)")],
- setivar_too_complex: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_too_complex)")],
- expandarray_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_splat)")],
- expandarray_postarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_postarg)")],
- expandarray_not_array: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_not_array)")],
- expandarray_rhs_too_small: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_rhs_too_small)")],
- getblockpp_block_param_modified: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_block_param_modified)")],
- getblockpp_block_handler_none: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_block_handler_none)")],
- getblockpp_not_gc_guarded: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_not_gc_guarded)")],
- getblockpp_not_iseq_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_not_iseq_block)")],
- compiled_block_count: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), compiled_block_count)")],
- )
- end
-
- def C.rb_serial_t
- @rb_serial_t ||= CType::Immediate.parse("unsigned long long")
- end
-
- def C.rb_shape
- @rb_shape ||= CType::Struct.new(
- "rb_shape", Primitive.cexpr!("SIZEOF(struct rb_shape)"),
- edges: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edges)")],
- edge_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edge_name)")],
- next_iv_index: [self.attr_index_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), next_iv_index)")],
- capacity: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), capacity)")],
- type: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), type)")],
- size_pool_index: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), size_pool_index)")],
- parent_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), parent_id)")],
- ancestor_index: [CType::Pointer.new { self.redblack_node_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), ancestor_index)")],
- )
- end
-
- def C.rb_shape_t
- @rb_shape_t ||= self.rb_shape
- end
-
- def C.rb_thread_struct
- @rb_thread_struct ||= CType::Struct.new(
- "rb_thread_struct", Primitive.cexpr!("SIZEOF(struct rb_thread_struct)"),
- lt_node: [self.ccan_list_node, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), lt_node)")],
- self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), self)")],
- ractor: [CType::Pointer.new { self.rb_ractor_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), ractor)")],
- vm: [CType::Pointer.new { self.rb_vm_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), vm)")],
- nt: [CType::Pointer.new { self.rb_native_thread }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), nt)")],
- ec: [CType::Pointer.new { self.rb_execution_context_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), ec)")],
- sched: [self.rb_thread_sched_item, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), sched)")],
- serial: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), serial)")],
- last_status: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), last_status)")],
- calling: [CType::Pointer.new { self.rb_calling_info }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), calling)")],
- top_self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), top_self)")],
- top_wrapper: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), top_wrapper)")],
- priority: [CType::Immediate.parse("int8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), priority)")],
- running_time_us: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), running_time_us)")],
- blocking_region_buffer: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), blocking_region_buffer)")],
- thgroup: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), thgroup)")],
- value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), value)")],
- pending_interrupt_queue: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), pending_interrupt_queue)")],
- pending_interrupt_mask_stack: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), pending_interrupt_mask_stack)")],
- interrupt_lock: [self.rb_nativethread_lock_t, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), interrupt_lock)")],
- unblock: [self.rb_unblock_callback, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), unblock)")],
- locking_mutex: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), locking_mutex)")],
- keeping_mutexes: [CType::Pointer.new { self.rb_mutex_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), keeping_mutexes)")],
- join_list: [CType::Pointer.new { self.rb_waiting_list }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), join_list)")],
- invoke_arg: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_thread_struct *)NULL)->invoke_arg)"),
- proc: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc)"),
- proc: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc, proc)")],
- args: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc, args)")],
- kw_splat: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc, kw_splat)")],
- ),
- func: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_thread_struct *)NULL)->invoke_arg.func)"),
- func: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.func, func)")],
- arg: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.func, arg)")],
- ),
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), invoke_arg)")],
- invoke_type: [self.thread_invoke_type, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), invoke_type)")],
- stat_insn_usage: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), stat_insn_usage)")],
- root_fiber: [CType::Pointer.new { self.rb_fiber_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), root_fiber)")],
- scheduler: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), scheduler)")],
- blocking: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), blocking)")],
- name: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), name)")],
- ext_config: [self.rb_ext_config, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), ext_config)")],
- )
- end
-
- def C.VALUE
- @VALUE ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(VALUE)"), Primitive.cexpr!("SIGNED_TYPE_P(VALUE)"))
- end
-
- def C.shape_id_t
- @shape_id_t ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(shape_id_t)"), Primitive.cexpr!("SIGNED_TYPE_P(shape_id_t)"))
- end
-
- def C.rb_id_table
- CType::Stub.new(:rb_id_table)
- end
-
- def C.vm_call_handler
- CType::Stub.new(:vm_call_handler)
- end
-
- def C.method_missing_reason
- CType::Stub.new(:method_missing_reason)
- end
-
- def C.vm_ifunc
- CType::Stub.new(:vm_ifunc)
- end
-
- def C.rb_cref_struct
- CType::Stub.new(:rb_cref_struct)
- end
-
- def C.rb_scope_visibility_t
- CType::Stub.new(:rb_scope_visibility_t)
- end
-
- def C.rb_vm_tag
- CType::Stub.new(:rb_vm_tag)
- end
-
- def C.rb_atomic_t
- CType::Stub.new(:rb_atomic_t)
- end
-
- def C.rb_fiber_t
- CType::Stub.new(:rb_fiber_t)
- end
-
- def C.rb_ensure_list_t
- CType::Stub.new(:rb_ensure_list_t)
- end
-
- def C.rb_trace_arg_struct
- CType::Stub.new(:rb_trace_arg_struct)
- end
-
- def C.rb_iseq_type
- CType::Stub.new(:rb_iseq_type)
- end
-
- def C.iseq_insn_info
- CType::Stub.new(:iseq_insn_info)
- end
-
- def C.iseq_catch_table
- CType::Stub.new(:iseq_catch_table)
- end
-
- def C.rb_snum_t
- CType::Stub.new(:rb_snum_t)
- end
-
- def C.iseq_bits_t
- CType::Stub.new(:iseq_bits_t)
- end
-
- def C.rb_code_location_t
- CType::Stub.new(:rb_code_location_t)
- end
-
- def C.iseq_compile_data
- CType::Stub.new(:iseq_compile_data)
- end
-
- def C.rb_hook_list_struct
- CType::Stub.new(:rb_hook_list_struct)
- end
-
- def C.rb_event_flag_t
- CType::Stub.new(:rb_event_flag_t)
- end
-
- def C.rb_method_alias_t
- CType::Stub.new(:rb_method_alias_t)
- end
-
- def C.rb_method_refined_t
- CType::Stub.new(:rb_method_refined_t)
- end
-
- def C._Bool
- CType::Bool.new
- end
-
- def C.redblack_node_t
- CType::Stub.new(:redblack_node_t)
- end
-
- def C.ccan_list_node
- CType::Stub.new(:ccan_list_node)
- end
-
- def C.rb_ractor_t
- CType::Stub.new(:rb_ractor_t)
- end
-
- def C.rb_vm_t
- CType::Stub.new(:rb_vm_t)
- end
-
- def C.rb_native_thread
- CType::Stub.new(:rb_native_thread)
- end
-
- def C.rb_thread_sched_item
- CType::Stub.new(:rb_thread_sched_item)
- end
-
- def C.rb_calling_info
- CType::Stub.new(:rb_calling_info)
- end
-
- def C.rb_nativethread_lock_t
- CType::Stub.new(:rb_nativethread_lock_t)
- end
-
- def C.rb_unblock_callback
- CType::Stub.new(:rb_unblock_callback)
- end
-
- def C.rb_mutex_struct
- CType::Stub.new(:rb_mutex_struct)
- end
-
- def C.rb_waiting_list
- CType::Stub.new(:rb_waiting_list)
- end
-
- def C.thread_invoke_type
- CType::Stub.new(:thread_invoke_type)
- end
-
- def C.rb_ext_config
- CType::Stub.new(:rb_ext_config)
- end
-
- ### RJIT bindgen end ###
-end if Primitive.rjit_enabled_p
diff --git a/ruby-runner.c b/ruby-runner.c
index 5731ea5287..e1a53d5236 100644
--- a/ruby-runner.c
+++ b/ruby-runner.c
@@ -9,6 +9,13 @@
#include "ruby-runner.h"
+#ifdef MAKE_MJIT_BUILD_DIR
+const char MJIT_HEADER[] = BUILDDIR "/" MJIT_MIN_HEADER;
+#else
+
+#define STRINGIZE(expr) STRINGIZE0(expr)
+#define STRINGIZE0(expr) #expr
+
static void
insert_env_path(const char *envname, const char *paths, size_t size, int prepend)
{
@@ -25,24 +32,12 @@ insert_env_path(const char *envname, const char *paths, size_t size, int prepend
char *e = malloc(size+n+1);
size_t pos = 0;
if (prepend) {
- if (size == n || (size < n && env[size] == PATH_SEP)) {
- if (strncmp(paths, env, size) == 0) {
- free(e);
- return;
- }
- }
memcpy(e, paths, pos = size-1);
e[pos++] = PATH_SEP;
}
memcpy(e+pos, env, n);
pos += n;
if (!prepend) {
- if (size == n || (size < n && env[n-size-1] == PATH_SEP)) {
- if (strncmp(paths, &env[n-size], size) == 0) {
- free(e);
- return;
- }
- }
e[pos++] = PATH_SEP;
memcpy(e+pos, paths, size-1);
pos += size-1;
@@ -69,6 +64,10 @@ main(int argc, char **argv)
PATH_SEPARATOR
EXTOUT_DIR"/"ARCH
;
+#ifndef LOAD_RELATIVE
+ static const char mjit_build_dir[] = BUILDDIR"/mjit_build_dir."SOEXT;
+ struct stat stbuf;
+#endif
const size_t dirsize = sizeof(builddir);
const size_t namesize = sizeof(rubypath) - dirsize;
const char *rubyname = rubypath + dirsize;
@@ -76,6 +75,12 @@ main(int argc, char **argv)
insert_env_path(LIBPATHENV, builddir, dirsize, 1);
insert_env_path("RUBYLIB", rubylib, sizeof(rubylib), 0);
+#ifndef LOAD_RELATIVE
+ if (PRELOADENV[0] && stat(mjit_build_dir, &stbuf) == 0) {
+ insert_env_path(PRELOADENV, mjit_build_dir, sizeof(mjit_build_dir), 1);
+ setenv("MJIT_SEARCH_BUILD_DIR", "true", 0);
+ }
+#endif
if (!(p = strrchr(arg0, '/'))) p = arg0; else p++;
if (strlen(p) < namesize - 1) {
@@ -89,3 +94,5 @@ main(int argc, char **argv)
perror(rubypath);
return -1;
}
+
+#endif /* MAKE_MJIT_BUILD_DIR */
diff --git a/ruby.c b/ruby.c
index 914a9bd3bd..09c81db86c 100644
--- a/ruby.c
+++ b/ruby.c
@@ -53,10 +53,9 @@
#include "internal/loadpath.h"
#include "internal/missing.h"
#include "internal/object.h"
-#include "internal/thread.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
+#include "internal/process.h"
#include "internal/variable.h"
-#include "prism_compile.h"
#include "ruby/encoding.h"
#include "ruby/thread.h"
#include "ruby/util.h"
@@ -106,7 +105,7 @@ void rb_warning_category_update(unsigned int mask, unsigned int bits);
SEP \
X(frozen_string_literal) \
SEP \
- X(rjit) \
+ X(mjit) \
SEP \
X(yjit) \
/* END OF FEATURES */
@@ -119,12 +118,12 @@ void rb_warning_category_update(unsigned int mask, unsigned int bits);
enum feature_flag_bits {
EACH_FEATURES(DEFINE_FEATURE, COMMA),
feature_debug_flag_first,
-#if defined(RJIT_FORCE_ENABLE) || !USE_YJIT
- DEFINE_FEATURE(jit) = feature_rjit,
+#if defined(MJIT_FORCE_ENABLE) || !USE_YJIT
+ DEFINE_FEATURE(jit) = feature_mjit,
#else
DEFINE_FEATURE(jit) = feature_yjit,
#endif
- feature_jit_mask = FEATURE_BIT(rjit) | FEATURE_BIT(yjit),
+ feature_jit_mask = FEATURE_BIT(mjit) | FEATURE_BIT(yjit),
feature_debug_flag_begin = feature_debug_flag_first - 1,
EACH_DEBUG_FEATURES(DEFINE_DEBUG_FEATURE, COMMA),
@@ -154,8 +153,6 @@ enum feature_flag_bits {
SEP \
X(parsetree_with_comment) \
SEP \
- X(prism_parsetree) \
- SEP \
X(insns) \
SEP \
X(insns_without_opt) \
@@ -169,7 +166,7 @@ enum dump_flag_bits {
DUMP_BIT(parsetree_with_comment)),
dump_exit_bits = (DUMP_BIT(yydebug) | DUMP_BIT(syntax) |
DUMP_BIT(parsetree) | DUMP_BIT(parsetree_with_comment) |
- DUMP_BIT(prism_parsetree) | DUMP_BIT(insns) | DUMP_BIT(insns_without_opt))
+ DUMP_BIT(insns) | DUMP_BIT(insns_without_opt))
};
static inline void
@@ -207,10 +204,6 @@ enum {
)
};
-#define BACKTRACE_LENGTH_LIMIT_VALID_P(n) ((n) >= -1)
-#define OPT_BACKTRACE_LENGTH_LIMIT_VALID_P(opt) \
- BACKTRACE_LENGTH_LIMIT_VALID_P((opt)->backtrace_length_limit)
-
static ruby_cmdline_options_t *
cmdline_options_init(ruby_cmdline_options_t *opt)
{
@@ -220,12 +213,11 @@ cmdline_options_init(ruby_cmdline_options_t *opt)
opt->ext.enc.index = -1;
opt->intern.enc.index = -1;
opt->features.set = DEFAULT_FEATURES;
-#ifdef RJIT_FORCE_ENABLE /* to use with: ./configure cppflags="-DRJIT_FORCE_ENABLE" */
- opt->features.set |= FEATURE_BIT(rjit);
+#ifdef MJIT_FORCE_ENABLE /* to use with: ./configure cppflags="-DMJIT_FORCE_ENABLE" */
+ opt->features.set |= FEATURE_BIT(mjit);
#elif defined(YJIT_FORCE_ENABLE)
opt->features.set |= FEATURE_BIT(yjit);
#endif
- opt->backtrace_length_limit = LONG_MIN;
return opt;
}
@@ -245,85 +237,35 @@ static const char esc_standout[] = "\n\033[1;7m";
static const char esc_bold[] = "\033[1m";
static const char esc_reset[] = "\033[0m";
static const char esc_none[] = "";
-#define USAGE_INDENT " " /* macro for concatenation */
static void
-show_usage_part(const char *str, const unsigned int namelen,
- const char *str2, const unsigned int secondlen,
- const char *desc,
- int help, int highlight, unsigned int w, int columns)
+show_usage_line(const char *str, unsigned int namelen, unsigned int secondlen, int help, int highlight, unsigned int w)
{
- static const int indent_width = (int)rb_strlen_lit(USAGE_INDENT);
const char *sb = highlight ? esc_bold : esc_none;
const char *se = highlight ? esc_reset : esc_none;
- unsigned int desclen = (unsigned int)strcspn(desc, "\n");
- if (help && (namelen + 1 > w) && /* a padding space */
- (int)(namelen + secondlen + indent_width) >= columns) {
- printf(USAGE_INDENT "%s" "%.*s" "%s\n", sb, namelen, str, se);
- if (secondlen > 0) {
- const int second_end = secondlen;
- int n = 0;
- if (str2[n] == ',') n++;
- if (str2[n] == ' ') n++;
- printf(USAGE_INDENT "%s" "%.*s" "%s\n", sb, second_end-n, str2+n, se);
- }
- printf("%-*s%.*s\n", w + indent_width, USAGE_INDENT, desclen, desc);
- }
- else {
- const int wrap = help && namelen + secondlen >= w;
- printf(USAGE_INDENT "%s%.*s%-*.*s%s%-*s%.*s\n", sb, namelen, str,
- (wrap ? 0 : w - namelen),
- (help ? secondlen : 0), str2, se,
- (wrap ? (int)(w + rb_strlen_lit("\n" USAGE_INDENT)) : 0),
- (wrap ? "\n" USAGE_INDENT : ""),
- desclen, desc);
- }
- if (help) {
- while (desc[desclen]) {
- desc += desclen + rb_strlen_lit("\n");
- desclen = (unsigned int)strcspn(desc, "\n");
- printf("%-*s%.*s\n", w + indent_width, USAGE_INDENT, desclen, desc);
- }
- }
-}
-
-static void
-show_usage_line(const struct ruby_opt_message *m,
- int help, int highlight, unsigned int w, int columns)
-{
- const char *str = m->str;
- const unsigned int namelen = m->namelen, secondlen = m->secondlen;
- const char *desc = str + namelen + secondlen;
- show_usage_part(str, namelen - 1, str + namelen, secondlen - 1, desc,
- help, highlight, w, columns);
-}
-
-void
-ruby_show_usage_line(const char *name, const char *secondary, const char *description,
- int help, int highlight, unsigned int width, int columns)
-{
- unsigned int namelen = (unsigned int)strlen(name);
- unsigned int secondlen = (secondary ? (unsigned int)strlen(secondary) : 0);
- show_usage_part(name, namelen, secondary, secondlen,
- description, help, highlight, width, columns);
+ const int wrap = help && namelen + secondlen - 1 > w;
+ printf(" %s%.*s%-*.*s%s%-*s%s\n", sb, namelen-1, str,
+ (wrap ? 0 : w - namelen + 1),
+ (help ? secondlen-1 : 0), str + namelen, se,
+ (wrap ? w + 3 : 0), (wrap ? "\n" : ""),
+ str + namelen + secondlen);
}
static void
usage(const char *name, int help, int highlight, int columns)
{
+ /* This message really ought to be max 23 lines.
+ * Removed -h because the user already knows that option. Others? */
+
#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
#if USE_YJIT
# define PLATFORM_JIT_OPTION "--yjit"
#else
-# define PLATFORM_JIT_OPTION "--rjit (experimental)"
+# define PLATFORM_JIT_OPTION "--mjit (experimental)"
#endif
-
- /* This message really ought to be max 23 lines.
- * Removed -h because the user already knows that option. Others? */
static const struct ruby_opt_message usage_msg[] = {
- M("-0[octal]", "", "specify record separator (\\0, if no argument)\n"
- "(-00 for paragraph mode, -0777 for slurp mode)"),
+ M("-0[octal]", "", "specify record separator (\\0, if no argument)"),
M("-a", "", "autosplit mode with -n or -p (splits $_ into $F)"),
M("-c", "", "check syntax only"),
M("-Cdirectory", "", "cd to directory before executing your script"),
@@ -344,19 +286,17 @@ usage(const char *name, int help, int highlight, int columns)
M("-W[level=2|:category]", "", "set warning level; 0=silence, 1=medium, 2=verbose"),
M("-x[directory]", "", "strip off text before #!ruby line and perhaps cd to directory"),
M("--jit", "", "enable JIT for the platform, same as " PLATFORM_JIT_OPTION),
+#if USE_MJIT
+ M("--mjit", "", "enable C compiler-based JIT compiler (experimental)"),
+#endif
#if USE_YJIT
M("--yjit", "", "enable in-process JIT compiler"),
#endif
-#if USE_RJIT
- M("--rjit", "", "enable pure-Ruby JIT compiler (experimental)"),
-#endif
M("-h", "", "show this message, --help for more info"),
};
- STATIC_ASSERT(usage_msg_size, numberof(usage_msg) < 25);
-
static const struct ruby_opt_message help_msg[] = {
M("--copyright", "", "print the copyright"),
- M("--dump={insns|parsetree|prism_parsetree|...}[,...]", "",
+ M("--dump={insns|parsetree|...}[,...]", "",
"dump debug information. see below for available dump list"),
M("--enable={jit|rubyopt|...}[,...]", ", --disable={jit|rubyopt|...}[,...]",
"enable or disable features. see below for available features"),
@@ -365,8 +305,6 @@ usage(const char *name, int help, int highlight, int columns)
M("--backtrace-limit=num", "", "limit the maximum length of backtrace"),
M("--verbose", "", "turn on verbose mode and disable script from stdin"),
M("--version", "", "print the version number, then exit"),
- M("--crash-report=TEMPLATE", "", "template of crash report files"),
- M("-y", ", --yydebug", "print log of parser. Backward compatibility is not guaranteed"),
M("--help", "", "show this message, -h for short message"),
};
static const struct ruby_opt_message dumps[] = {
@@ -375,7 +313,6 @@ usage(const char *name, int help, int highlight, int columns)
M("yydebug(+error-tolerant)", "", "yydebug of yacc parser generator"),
M("parsetree(+error-tolerant)","", "AST"),
M("parsetree_with_comment(+error-tolerant)", "", "AST with comments"),
- M("prism_parsetree", "", "Prism AST with comments"),
};
static const struct ruby_opt_message features[] = {
M("gems", "", "rubygems (only for debugging, default: "DEFAULT_RUBYGEMS_ENABLED")"),
@@ -384,27 +321,35 @@ usage(const char *name, int help, int highlight, int columns)
M("syntax_suggest", "", "syntax_suggest (default: "DEFAULT_RUBYGEMS_ENABLED")"),
M("rubyopt", "", "RUBYOPT environment variable (default: enabled)"),
M("frozen-string-literal", "", "freeze all string literals (default: disabled)"),
+#if USE_MJIT
+ M("mjit", "", "C compiler-based JIT compiler (default: disabled)"),
+#endif
#if USE_YJIT
M("yjit", "", "in-process JIT compiler (default: disabled)"),
#endif
-#if USE_RJIT
- M("rjit", "", "pure-Ruby JIT compiler (default: disabled)"),
-#endif
};
static const struct ruby_opt_message warn_categories[] = {
M("deprecated", "", "deprecated features"),
M("experimental", "", "experimental features"),
- M("performance", "", "performance issues"),
};
-#if USE_RJIT
- extern const struct ruby_opt_message rb_rjit_option_messages[];
+#if USE_MJIT
+ extern const struct ruby_opt_message mjit_option_messages[];
+#endif
+#if USE_YJIT
+ static const struct ruby_opt_message yjit_options[] = {
+ M("--yjit-stats", "", "Enable collecting YJIT statistics"),
+ M("--yjit-exec-mem-size=num", "", "Size of executable memory block in MiB (default: 64)"),
+ M("--yjit-call-threshold=num", "", "Number of calls to trigger JIT (default: 10)"),
+ M("--yjit-max-versions=num", "", "Maximum number of versions per basic block (default: 4)"),
+ M("--yjit-greedy-versioning", "", "Greedy versioning mode (default: disabled)"),
+ };
#endif
int i;
const char *sb = highlight ? esc_standout+1 : esc_none;
const char *se = highlight ? esc_reset : esc_none;
const int num = numberof(usage_msg) - (help ? 1 : 0);
unsigned int w = (columns > 80 ? (columns - 79) / 2 : 0) + 16;
-#define SHOW(m) show_usage_line(&(m), help, highlight, w, columns)
+#define SHOW(m) show_usage_line((m).str, (m).namelen, (m).secondlen, help, highlight, w)
printf("%sUsage:%s %s [switches] [--] [programfile] [arguments]\n", sb, se, name);
for (i = 0; i < num; ++i)
@@ -425,14 +370,15 @@ usage(const char *name, int help, int highlight, int columns)
printf("%s""Warning categories:%s\n", sb, se);
for (i = 0; i < numberof(warn_categories); ++i)
SHOW(warn_categories[i]);
+#if USE_MJIT
+ printf("%s""MJIT options (experimental):%s\n", sb, se);
+ for (i = 0; mjit_option_messages[i].str; ++i)
+ SHOW(mjit_option_messages[i]);
+#endif
#if USE_YJIT
printf("%s""YJIT options:%s\n", sb, se);
- rb_yjit_show_usage(help, highlight, w, columns);
-#endif
-#if USE_RJIT
- printf("%s""RJIT options (experimental):%s\n", sb, se);
- for (i = 0; rb_rjit_option_messages[i].str; ++i)
- SHOW(rb_rjit_option_messages[i]);
+ for (i = 0; i < numberof(yjit_options); ++i)
+ SHOW(yjit_options[i]);
#endif
}
@@ -572,6 +518,8 @@ translit_char_bin(char *p, int from, int to)
#endif
#ifdef _WIN32
+# undef chdir
+# define chdir rb_w32_uchdir
# define UTF8_PATH 1
#endif
@@ -603,8 +551,12 @@ static VALUE
runtime_libruby_path(void)
{
#if defined _WIN32 || defined __CYGWIN__
- DWORD ret;
- DWORD len = 32;
+ DWORD len, ret;
+#if USE_RVARGC
+ len = 32;
+#else
+ len = RSTRING_EMBED_LEN_MAX;
+#endif
VALUE path;
VALUE wsopath = rb_str_new(0, len*sizeof(WCHAR));
WCHAR *wlibpath;
@@ -834,10 +786,10 @@ toplevel_context(rb_binding_t *bind)
return &bind->block;
}
-static int
-process_sflag(int sflag)
+static void
+process_sflag(int *sflag)
{
- if (sflag > 0) {
+ if (*sflag > 0) {
long n;
const VALUE *args;
VALUE argv = rb_argv;
@@ -894,9 +846,8 @@ process_sflag(int sflag)
while (n--) {
rb_ary_shift(argv);
}
- return -1;
+ *sflag = -1;
}
- return sflag;
}
static long proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt);
@@ -910,26 +861,14 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
VALUE argstr, argary;
void *ptr;
- VALUE src_enc_name = opt->src.enc.name;
- VALUE ext_enc_name = opt->ext.enc.name;
- VALUE int_enc_name = opt->intern.enc.name;
- ruby_features_t feat = opt->features;
- ruby_features_t warn = opt->warn;
- long backtrace_length_limit = opt->backtrace_length_limit;
- const char *crash_report = opt->crash_report;
-
while (ISSPACE(*s)) s++;
if (!*s) return;
-
- opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0;
-
- const int hyphen = *s != '-';
- argstr = rb_str_tmp_new((len = strlen(s)) + hyphen);
+ argstr = rb_str_tmp_new((len = strlen(s)) + (envopt!=0));
argary = rb_str_tmp_new(0);
p = RSTRING_PTR(argstr);
- if (hyphen) *p = '-';
- memcpy(p + hyphen, s, len + 1);
+ if (envopt) *p++ = ' ';
+ memcpy(p, s, len + 1);
ap = 0;
rb_str_cat(argary, (char *)&ap, sizeof(ap));
while (*p) {
@@ -957,24 +896,6 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
}
}
- if (src_enc_name) {
- opt->src.enc.name = src_enc_name;
- }
- if (ext_enc_name) {
- opt->ext.enc.name = ext_enc_name;
- }
- if (int_enc_name) {
- opt->intern.enc.name = int_enc_name;
- }
- FEATURE_SET_RESTORE(opt->features, feat);
- FEATURE_SET_RESTORE(opt->warn, warn);
- if (BACKTRACE_LENGTH_LIMIT_VALID_P(backtrace_length_limit)) {
- opt->backtrace_length_limit = backtrace_length_limit;
- }
- if (crash_report) {
- opt->crash_report = crash_report;
- }
-
ruby_xfree(ptr);
/* get rid of GC */
rb_str_resize(argary, 0);
@@ -1038,7 +959,7 @@ feature_option(const char *str, int len, void *arg, const unsigned int enable)
goto found;
}
if (NAME_MATCH_P("all", str, len)) {
- // YJIT and RJIT cannot be enabled at the same time. We enable only one for --enable=all.
+ // YJIT and MJIT cannot be enabled at the same time. We enable only one for --enable=all.
mask &= ~feature_jit_mask | FEATURE_BIT(jit);
goto found;
}
@@ -1198,311 +1119,6 @@ setup_yjit_options(const char *s)
}
#endif
-/*
- * Following proc_*_option functions are tree kinds:
- *
- * - with a required argument, takes also `argc` and `argv`, and
- * returns the number of consumed argv including the option itself.
- *
- * - with a mandatory argument just after the option.
- *
- * - no required argument, this returns the address of
- * the next character after the last consumed character.
- */
-
-/* optional */
-static const char *
-proc_W_option(ruby_cmdline_options_t *opt, const char *s, int *warning)
-{
- if (s[1] == ':') {
- unsigned int bits = 0;
- static const char no_prefix[] = "no-";
- int enable = strncmp(s += 2, no_prefix, sizeof(no_prefix)-1) != 0;
- if (!enable) s += sizeof(no_prefix)-1;
- size_t len = strlen(s);
- if (NAME_MATCH_P("deprecated", s, len)) {
- bits = 1U << RB_WARN_CATEGORY_DEPRECATED;
- }
- else if (NAME_MATCH_P("experimental", s, len)) {
- bits = 1U << RB_WARN_CATEGORY_EXPERIMENTAL;
- }
- else if (NAME_MATCH_P("performance", s, len)) {
- bits = 1U << RB_WARN_CATEGORY_PERFORMANCE;
- }
- else {
- rb_warn("unknown warning category: `%s'", s);
- }
- if (bits) FEATURE_SET_TO(opt->warn, bits, enable ? bits : 0);
- return 0;
- }
- else {
- size_t numlen;
- int v = 2; /* -W as -W2 */
-
- if (*++s) {
- v = scan_oct(s, 1, &numlen);
- if (numlen == 0)
- v = 2;
- s += numlen;
- }
- if (!opt->warning) {
- switch (v) {
- case 0:
- ruby_verbose = Qnil;
- break;
- case 1:
- ruby_verbose = Qfalse;
- break;
- default:
- ruby_verbose = Qtrue;
- break;
- }
- }
- *warning = 1;
- switch (v) {
- case 0:
- FEATURE_SET_TO(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS, 0);
- break;
- case 1:
- FEATURE_SET_TO(opt->warn, 1U << RB_WARN_CATEGORY_DEPRECATED, 0);
- break;
- default:
- FEATURE_SET(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS);
- break;
- }
- return s;
- }
-}
-
-/* required */
-static long
-proc_e_option(ruby_cmdline_options_t *opt, const char *s, long argc, char **argv)
-{
- long n = 1;
- forbid_setid("-e");
- if (!*++s) {
- if (!--argc)
- rb_raise(rb_eRuntimeError, "no code specified for -e");
- s = *++argv;
- n++;
- }
- if (!opt->e_script) {
- opt->e_script = rb_str_new(0, 0);
- if (opt->script == 0)
- opt->script = "-e";
- }
- rb_str_cat2(opt->e_script, s);
- rb_str_cat2(opt->e_script, "\n");
- return n;
-}
-
-/* optional */
-static const char *
-proc_K_option(ruby_cmdline_options_t *opt, const char *s)
-{
- if (*++s) {
- const char *enc_name = 0;
- switch (*s) {
- case 'E': case 'e':
- enc_name = "EUC-JP";
- break;
- case 'S': case 's':
- enc_name = "Windows-31J";
- break;
- case 'U': case 'u':
- enc_name = "UTF-8";
- break;
- case 'N': case 'n': case 'A': case 'a':
- enc_name = "ASCII-8BIT";
- break;
- }
- if (enc_name) {
- opt->src.enc.name = rb_str_new2(enc_name);
- if (!opt->ext.enc.name)
- opt->ext.enc.name = opt->src.enc.name;
- }
- s++;
- }
- return s;
-}
-
-/* optional */
-static const char *
-proc_0_option(ruby_cmdline_options_t *opt, const char *s)
-{
- size_t numlen;
- int v;
- char c;
-
- v = scan_oct(s, 4, &numlen);
- s += numlen;
- if (v > 0377)
- rb_rs = Qnil;
- else if (v == 0 && numlen >= 2) {
- rb_rs = rb_str_new2("");
- }
- else {
- c = v & 0xff;
- rb_rs = rb_str_new(&c, 1);
- }
- return s;
-}
-
-/* mandatory */
-static void
-proc_encoding_option(ruby_cmdline_options_t *opt, const char *s, const char *opt_name)
-{
- char *p;
-# define set_encoding_part(type) \
- if (!(p = strchr(s, ':'))) { \
- set_##type##_encoding_once(opt, s, 0); \
- return; \
- } \
- else if (p > s) { \
- set_##type##_encoding_once(opt, s, p-s); \
- }
- set_encoding_part(external);
- if (!*(s = ++p)) return;
- set_encoding_part(internal);
- if (!*(s = ++p)) return;
-#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
- set_encoding_part(source);
- if (!*(s = ++p)) return;
-#endif
- rb_raise(rb_eRuntimeError, "extra argument for %s: %s", opt_name, s);
-# undef set_encoding_part
- UNREACHABLE;
-}
-
-static long
-proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **argv, int envopt)
-{
- size_t n;
- long argc0 = argc;
-# define is_option_end(c, allow_hyphen) \
- (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=')
-# define check_envopt(name, allow_envopt) \
- (((allow_envopt) || !envopt) ? (void)0 : \
- rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name))
-# define need_argument(name, s, needs_arg, next_arg) \
- ((*(s) ? !*++(s) : (next_arg) && (!argc || !((s) = argv[1]) || (--argc, ++argv, 0))) && (needs_arg) ? \
- rb_raise(rb_eRuntimeError, "missing argument for --" name) \
- : (void)0)
-# define is_option_with_arg(name, allow_hyphen, allow_envopt) \
- is_option_with_optarg(name, allow_hyphen, allow_envopt, Qtrue, Qtrue)
-# define is_option_with_optarg(name, allow_hyphen, allow_envopt, needs_arg, next_arg) \
- (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) && \
- (s[n] != '-' || s[n+1]) ? \
- (check_envopt(name, (allow_envopt)), s += n, \
- need_argument(name, s, needs_arg, next_arg), 1) : 0)
-
- if (strcmp("copyright", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(copyright);
- }
- else if (is_option_with_optarg("debug", Qtrue, Qtrue, Qfalse, Qfalse)) {
- if (s && *s) {
- ruby_each_words(s, debug_option, &opt->features);
- }
- else {
- ruby_debug = Qtrue;
- ruby_verbose = Qtrue;
- }
- }
- else if (is_option_with_arg("enable", Qtrue, Qtrue)) {
- ruby_each_words(s, enable_option, &opt->features);
- }
- else if (is_option_with_arg("disable", Qtrue, Qtrue)) {
- ruby_each_words(s, disable_option, &opt->features);
- }
- else if (is_option_with_arg("encoding", Qfalse, Qtrue)) {
- proc_encoding_option(opt, s, "--encoding");
- }
- else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) {
- set_internal_encoding_once(opt, s, 0);
- }
- else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) {
- set_external_encoding_once(opt, s, 0);
- }
-#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
- else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) {
- set_source_encoding_once(opt, s, 0);
- }
-#endif
- else if (strcmp("version", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(version);
- }
- else if (strcmp("verbose", s) == 0) {
- opt->verbose = 1;
- ruby_verbose = Qtrue;
- }
- else if (strcmp("jit", s) == 0) {
-#if !USE_RJIT
- rb_warn("Ruby was built without JIT support");
-#else
- FEATURE_SET(opt->features, FEATURE_BIT(jit));
-#endif
- }
- else if (is_option_with_optarg("rjit", '-', true, false, false)) {
-#if USE_RJIT
- extern void rb_rjit_setup_options(const char *s, struct rb_rjit_options *rjit_opt);
- FEATURE_SET(opt->features, FEATURE_BIT(rjit));
- rb_rjit_setup_options(s, &opt->rjit);
-#else
- rb_warn("RJIT support is disabled.");
-#endif
- }
- else if (is_option_with_optarg("yjit", '-', true, false, false)) {
-#if USE_YJIT
- FEATURE_SET(opt->features, FEATURE_BIT(yjit));
- setup_yjit_options(s);
-#else
- rb_warn("Ruby was built without YJIT support."
- " You may need to install rustc to build Ruby with YJIT.");
-#endif
- }
- else if (strcmp("yydebug", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(yydebug);
- }
- else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
- ruby_each_words(s, dump_option, &opt->dump);
- }
- else if (strcmp("help", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(help);
- return 0;
- }
- else if (is_option_with_arg("backtrace-limit", Qfalse, Qtrue)) {
- char *e;
- long n = strtol(s, &e, 10);
- if (errno == ERANGE || !BACKTRACE_LENGTH_LIMIT_VALID_P(n) || *e) {
- rb_raise(rb_eRuntimeError, "wrong limit for backtrace length");
- }
- else {
- opt->backtrace_length_limit = n;
- }
- }
- else if (is_option_with_arg("crash-report", true, true)) {
- opt->crash_report = s;
- }
- else {
- rb_raise(rb_eRuntimeError,
- "invalid option --%s (-h will show valid options)", s);
- }
- return argc0 - argc + 1;
-
- noenvopt_long:
- rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s);
-# undef is_option_end
-# undef check_envopt
-# undef need_argument
-# undef is_option_with_arg
-# undef is_option_with_optarg
- UNREACHABLE_RETURN(0);
-}
-
static long
proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
{
@@ -1561,12 +1177,65 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
warning = 1;
ruby_verbose = Qtrue;
}
- FEATURE_SET(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS);
+ FEATURE_SET(opt->warn, RB_WARN_CATEGORY_ALL_BITS);
s++;
goto reswitch;
case 'W':
- if (!(s = proc_W_option(opt, s, &warning))) break;
+ if (s[1] == ':') {
+ unsigned int bits = 0;
+ static const char no_prefix[] = "no-";
+ int enable = strncmp(s += 2, no_prefix, sizeof(no_prefix)-1) != 0;
+ if (!enable) s += sizeof(no_prefix)-1;
+ size_t len = strlen(s);
+ if (NAME_MATCH_P("deprecated", s, len)) {
+ bits = 1U << RB_WARN_CATEGORY_DEPRECATED;
+ }
+ else if (NAME_MATCH_P("experimental", s, len)) {
+ bits = 1U << RB_WARN_CATEGORY_EXPERIMENTAL;
+ }
+ else {
+ rb_warn("unknown warning category: `%s'", s);
+ }
+ if (bits) FEATURE_SET_TO(opt->warn, bits, enable ? bits : 0);
+ break;
+ }
+ {
+ size_t numlen;
+ int v = 2; /* -W as -W2 */
+
+ if (*++s) {
+ v = scan_oct(s, 1, &numlen);
+ if (numlen == 0)
+ v = 2;
+ s += numlen;
+ }
+ if (!opt->warning) {
+ switch (v) {
+ case 0:
+ ruby_verbose = Qnil;
+ break;
+ case 1:
+ ruby_verbose = Qfalse;
+ break;
+ default:
+ ruby_verbose = Qtrue;
+ break;
+ }
+ }
+ warning = 1;
+ switch (v) {
+ case 0:
+ FEATURE_SET_TO(opt->warn, RB_WARN_CATEGORY_ALL_BITS, 0);
+ break;
+ case 1:
+ FEATURE_SET_TO(opt->warn, 1U << RB_WARN_CATEGORY_DEPRECATED, 0);
+ break;
+ default:
+ FEATURE_SET(opt->warn, RB_WARN_CATEGORY_ALL_BITS);
+ break;
+ }
+ }
goto reswitch;
case 'c':
@@ -1603,10 +1272,19 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
case 'e':
if (envopt) goto noenvopt;
- if (!(n = proc_e_option(opt, s, argc, argv))) break;
- --n;
- argc -= n;
- argv += n;
+ forbid_setid("-e");
+ if (!*++s) {
+ if (!--argc)
+ rb_raise(rb_eRuntimeError, "no code specified for -e");
+ s = *++argv;
+ }
+ if (!opt->e_script) {
+ opt->e_script = rb_str_new(0, 0);
+ if (opt->script == 0)
+ opt->script = "-e";
+ }
+ rb_str_cat2(opt->e_script, s);
+ rb_str_cat2(opt->e_script, "\n");
break;
case 'r':
@@ -1658,8 +1336,7 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
if (!*++s && (!--argc || !(s = *++argv))) {
rb_raise(rb_eRuntimeError, "missing argument for -E");
}
- proc_encoding_option(opt, s, "-E");
- break;
+ goto encoding;
case 'U':
set_internal_encoding_once(opt, "UTF-8", 0);
@@ -1667,7 +1344,29 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
goto reswitch;
case 'K':
- if (!(s = proc_K_option(opt, s))) break;
+ if (*++s) {
+ const char *enc_name = 0;
+ switch (*s) {
+ case 'E': case 'e':
+ enc_name = "EUC-JP";
+ break;
+ case 'S': case 's':
+ enc_name = "Windows-31J";
+ break;
+ case 'U': case 'u':
+ enc_name = "UTF-8";
+ break;
+ case 'N': case 'n': case 'A': case 'a':
+ enc_name = "ASCII-8BIT";
+ break;
+ }
+ if (enc_name) {
+ opt->src.enc.name = rb_str_new2(enc_name);
+ if (!opt->ext.enc.name)
+ opt->ext.enc.name = opt->src.enc.name;
+ }
+ s++;
+ }
goto reswitch;
case 'I':
@@ -1682,7 +1381,23 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
case '0':
if (envopt) goto noenvopt;
- if (!(s = proc_0_option(opt, s))) break;
+ {
+ size_t numlen;
+ int v;
+ char c;
+
+ v = scan_oct(s, 4, &numlen);
+ s += numlen;
+ if (v > 0377)
+ rb_rs = Qnil;
+ else if (v == 0 && numlen >= 2) {
+ rb_rs = rb_str_new2("");
+ }
+ else {
+ c = v & 0xff;
+ rb_rs = rb_str_new(&c, 1);
+ }
+ }
goto reswitch;
case '-':
@@ -1692,10 +1407,133 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
}
s++;
- if (!(n = proc_long_options(opt, s, argc, argv, envopt))) goto switch_end;
- --n;
- argc -= n;
- argv += n;
+# define is_option_end(c, allow_hyphen) \
+ (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=')
+# define check_envopt(name, allow_envopt) \
+ (((allow_envopt) || !envopt) ? (void)0 : \
+ rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name))
+# define need_argument(name, s, needs_arg, next_arg) \
+ ((*(s) ? !*++(s) : (next_arg) && (!argc || !((s) = argv[1]) || (--argc, ++argv, 0))) && (needs_arg) ? \
+ rb_raise(rb_eRuntimeError, "missing argument for --" name) \
+ : (void)0)
+# define is_option_with_arg(name, allow_hyphen, allow_envopt) \
+ is_option_with_optarg(name, allow_hyphen, allow_envopt, Qtrue, Qtrue)
+# define is_option_with_optarg(name, allow_hyphen, allow_envopt, needs_arg, next_arg) \
+ (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) && \
+ (s[n] != '-' || s[n+1]) ? \
+ (check_envopt(name, (allow_envopt)), s += n, \
+ need_argument(name, s, needs_arg, next_arg), 1) : 0)
+
+ if (strcmp("copyright", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(copyright);
+ }
+ else if (is_option_with_optarg("debug", Qtrue, Qtrue, Qfalse, Qfalse)) {
+ if (s && *s) {
+ ruby_each_words(s, debug_option, &opt->features);
+ }
+ else {
+ ruby_debug = Qtrue;
+ ruby_verbose = Qtrue;
+ }
+ }
+ else if (is_option_with_arg("enable", Qtrue, Qtrue)) {
+ ruby_each_words(s, enable_option, &opt->features);
+ }
+ else if (is_option_with_arg("disable", Qtrue, Qtrue)) {
+ ruby_each_words(s, disable_option, &opt->features);
+ }
+ else if (is_option_with_arg("encoding", Qfalse, Qtrue)) {
+ char *p;
+ encoding:
+ do {
+# define set_encoding_part(type) \
+ if (!(p = strchr(s, ':'))) { \
+ set_##type##_encoding_once(opt, s, 0); \
+ break; \
+ } \
+ else if (p > s) { \
+ set_##type##_encoding_once(opt, s, p-s); \
+ }
+ set_encoding_part(external);
+ if (!*(s = ++p)) break;
+ set_encoding_part(internal);
+ if (!*(s = ++p)) break;
+#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
+ set_encoding_part(source);
+ if (!*(s = ++p)) break;
+#endif
+ rb_raise(rb_eRuntimeError, "extra argument for %s: %s",
+ (arg[1] == '-' ? "--encoding" : "-E"), s);
+# undef set_encoding_part
+ } while (0);
+ }
+ else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) {
+ set_internal_encoding_once(opt, s, 0);
+ }
+ else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) {
+ set_external_encoding_once(opt, s, 0);
+ }
+#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
+ else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) {
+ set_source_encoding_once(opt, s, 0);
+ }
+#endif
+ else if (strcmp("version", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(version);
+ }
+ else if (strcmp("verbose", s) == 0) {
+ opt->verbose = 1;
+ ruby_verbose = Qtrue;
+ }
+ else if (strcmp("jit", s) == 0) {
+#if !USE_MJIT
+ rb_warn("Ruby was built without JIT support");
+#else
+ FEATURE_SET(opt->features, FEATURE_BIT(jit));
+#endif
+ }
+ else if (is_option_with_optarg("mjit", '-', true, false, false)) {
+#if USE_MJIT
+ extern void mjit_setup_options(const char *s, struct mjit_options *mjit_opt);
+ FEATURE_SET(opt->features, FEATURE_BIT(mjit));
+ mjit_setup_options(s, &opt->mjit);
+#else
+ rb_warn("MJIT support is disabled.");
+#endif
+ }
+ else if (is_option_with_optarg("yjit", '-', true, false, false)) {
+#if USE_YJIT
+ FEATURE_SET(opt->features, FEATURE_BIT(yjit));
+ setup_yjit_options(s);
+#else
+ rb_warn("Ruby was built without YJIT support."
+ " You may need to install rustc to build Ruby with YJIT.");
+#endif
+ }
+ else if (strcmp("yydebug", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(yydebug);
+ }
+ else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
+ ruby_each_words(s, dump_option, &opt->dump);
+ }
+ else if (strcmp("help", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(help);
+ goto switch_end;
+ }
+ else if (is_option_with_arg("backtrace-limit", Qfalse, Qfalse)) {
+ char *e;
+ long n = strtol(s, &e, 10);
+ if (errno == ERANGE || n < 0 || *e) rb_raise(rb_eRuntimeError, "wrong limit for backtrace length");
+ rb_backtrace_length_limit = n;
+ }
+ else {
+ rb_raise(rb_eRuntimeError,
+ "invalid option --%s (-h will show valid options)", s);
+ }
break;
case '\r':
@@ -1703,9 +1541,11 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
break;
default:
- rb_raise(rb_eRuntimeError,
- "invalid option -%c (-h will show valid options)",
- (int)(unsigned char)*s);
+ {
+ rb_raise(rb_eRuntimeError,
+ "invalid option -%c (-h will show valid options)",
+ (int)(unsigned char)*s);
+ }
goto switch_end;
noenvopt:
@@ -1713,8 +1553,17 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: -%c", *s);
break;
+ noenvopt_long:
+ rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s);
+ break;
+
case 0:
break;
+# undef is_option_end
+# undef check_envopt
+# undef need_argument
+# undef is_option_with_arg
+# undef is_option_with_optarg
}
}
@@ -1764,21 +1613,10 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
rb_warning_category_update(opt->warn.mask, opt->warn.set);
- /* [Feature #19785] Warning for removed GC environment variable.
- * Remove this in Ruby 3.4. */
- if (getenv("RUBY_GC_HEAP_INIT_SLOTS")) {
- rb_warn_deprecated("The environment variable RUBY_GC_HEAP_INIT_SLOTS",
- "environment variables RUBY_GC_HEAP_%d_INIT_SLOTS");
- }
-
-#if USE_RJIT
- // rb_call_builtin_inits depends on RubyVM::RJIT.enabled?
- if (opt->rjit.on)
- rb_rjit_enabled = true;
- if (opt->rjit.stats)
- rb_rjit_stats_enabled = true;
- if (opt->rjit.trace_exits)
- rb_rjit_trace_exits_enabled = true;
+#if USE_MJIT
+ // rb_call_builtin_inits depends on RubyVM::MJIT.enabled?
+ if (opt->mjit.on)
+ mjit_enabled = true;
#endif
Init_ext(); /* load statically linked extensions before rubygems */
@@ -1787,14 +1625,19 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
ruby_init_prelude();
// Initialize JITs after prelude because JITing prelude is typically not optimal.
-#if USE_RJIT
- // Also, rb_rjit_init is safe only after rb_call_builtin_inits() defines RubyVM::RJIT::Compiler.
- if (opt->rjit.on)
- rb_rjit_init(&opt->rjit);
+#if USE_MJIT
+ // Also, mjit_init is safe only after rb_call_builtin_inits() defines RubyVM::MJIT::Compiler.
+ if (opt->mjit.on)
+ mjit_init(&opt->mjit);
#endif
#if USE_YJIT
- rb_yjit_init(opt->yjit);
+ if (opt->yjit)
+ rb_yjit_init();
#endif
+ // rb_threadptr_root_fiber_setup for the initial thread is called before rb_yjit_enabled_p()
+ // or mjit_enabled becomes true, meaning jit_cont_new is skipped for the initial root fiber.
+ // Therefore we need to call this again here to set the initial root fiber's jit_cont.
+ rb_jit_cont_init(); // must be after mjit_enabled = true and rb_yjit_init()
ruby_set_script_name(opt->script_name);
require_libraries(&opt->req_list);
@@ -1926,10 +1769,7 @@ rb_f_chomp(int argc, VALUE *argv, VALUE _)
static void
setup_pager_env(void)
{
- if (!getenv("LESS")) {
- // Output "raw" control characters, and move per sections.
- ruby_setenv("LESS", "-R +/^[A-Z].*");
- }
+ if (!getenv("LESS")) ruby_setenv("LESS", "-R"); // Output "raw" control characters.
}
#ifdef _WIN32
@@ -1980,8 +1820,6 @@ env_var_truthy(const char *name)
}
#endif
-rb_pid_t rb_fork_ruby(int *status);
-
static VALUE
process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
@@ -2018,7 +1856,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#ifdef HAVE_WORKING_FORK
int fds[2];
if (rb_pipe(fds) == 0) {
- rb_pid_t pid = rb_fork_ruby(NULL);
+ rb_pid_t pid = rb_fork();
if (pid > 0) {
/* exec PAGER with reading from child */
dup2(fds[0], 0);
@@ -2065,7 +1903,22 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
argv += i;
if (FEATURE_SET_P(opt->features, rubyopt) && (s = getenv("RUBYOPT"))) {
+ VALUE src_enc_name = opt->src.enc.name;
+ VALUE ext_enc_name = opt->ext.enc.name;
+ VALUE int_enc_name = opt->intern.enc.name;
+ ruby_features_t feat = opt->features;
+ ruby_features_t warn = opt->warn;
+
+ opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0;
moreswitches(s, opt, 1);
+ if (src_enc_name)
+ opt->src.enc.name = src_enc_name;
+ if (ext_enc_name)
+ opt->ext.enc.name = ext_enc_name;
+ if (int_enc_name)
+ opt->intern.enc.name = int_enc_name;
+ FEATURE_SET_RESTORE(opt->features, feat);
+ FEATURE_SET_RESTORE(opt->warn, warn);
}
if (opt->src.enc.name)
@@ -2082,13 +1935,13 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#endif
}
if (MULTI_BITS_P(FEATURE_SET_BITS(opt->features) & feature_jit_mask)) {
- rb_warn("RJIT and YJIT cannot both be enabled at the same time. Exiting");
+ rb_warn("MJIT and YJIT cannot both be enabled at the same time. Exiting");
return Qfalse;
}
-#if USE_RJIT
- if (FEATURE_SET_P(opt->features, rjit)) {
- opt->rjit.on = true; // set opt->rjit.on for Init_ruby_description() and calling rb_rjit_init()
+#if USE_MJIT
+ if (FEATURE_SET_P(opt->features, mjit)) {
+ opt->mjit.on = true; // set opt->mjit.on for Init_ruby_description() and calling mjit_init()
}
#endif
#if USE_YJIT
@@ -2096,10 +1949,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
opt->yjit = true; // set opt->yjit for Init_ruby_description() and calling rb_yjit_init()
}
#endif
-
- ruby_mn_threads_params();
Init_ruby_description(opt);
-
if (opt->dump & (DUMP_BIT(version) | DUMP_BIT(version_v))) {
ruby_show_version();
if (opt->dump & DUMP_BIT(version)) return Qtrue;
@@ -2254,7 +2104,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#undef SET_COMPILE_OPTION
}
ruby_set_argv(argc, argv);
- opt->sflag = process_sflag(opt->sflag);
+ process_sflag(&opt->sflag);
if (opt->e_script) {
VALUE progname = rb_progname;
@@ -2284,9 +2134,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
else {
VALUE f;
- int xflag = opt->xflag;
- f = open_load_file(script_name, &xflag);
- opt->xflag = xflag != 0;
+ f = open_load_file(script_name, &opt->xflag);
rb_parser_set_context(parser, 0, f == rb_stdin);
ast = load_file(parser, opt->script_name, f, 1, opt);
}
@@ -2318,7 +2166,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
return Qfalse;
}
- opt->sflag = process_sflag(opt->sflag);
+ process_sflag(&opt->sflag);
opt->xflag = 0;
if (dump & DUMP_BIT(syntax)) {
@@ -2334,36 +2182,6 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
rb_define_global_function("chomp", rb_f_chomp, -1);
}
- if (dump & (DUMP_BIT(prism_parsetree))) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- if (opt->e_script) {
- pm_string_constant_init(&input, RSTRING_PTR(opt->e_script), RSTRING_LEN(opt->e_script));
- pm_options_filepath_set(&options, "-e");
- } else {
- pm_string_mapped_init(&input, RSTRING_PTR(opt->script_name));
- pm_options_filepath_set(&options, RSTRING_PTR(opt->script_name));
- }
-
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_buffer_t output_buffer = { 0 };
-
- pm_prettyprint(&output_buffer, &parser, node);
- rb_io_write(rb_stdout, rb_str_new((const char *) output_buffer.value, output_buffer.length));
- rb_io_flush(rb_stdout);
-
- pm_buffer_free(&output_buffer);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- pm_string_free(&input);
- pm_options_free(&options);
- }
-
if (dump & (DUMP_BIT(parsetree)|DUMP_BIT(parsetree_with_comment))) {
rb_io_write(rb_stdout, rb_parser_dump_tree(ast->body.root, dump & DUMP_BIT(parsetree_with_comment)));
rb_io_flush(rb_stdout);
@@ -2404,10 +2222,6 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
if (opt->dump & dump_exit_bits) return Qtrue;
- if (OPT_BACKTRACE_LENGTH_LIMIT_VALID_P(opt)) {
- rb_backtrace_length_limit = opt->backtrace_length_limit;
- }
-
rb_define_readonly_boolean("$-p", opt->do_print);
rb_define_readonly_boolean("$-l", opt->do_line);
rb_define_readonly_boolean("$-a", opt->do_split);
@@ -2458,8 +2272,6 @@ struct load_file_arg {
VALUE f;
};
-VALUE rb_script_lines_for(VALUE path, bool add);
-
static VALUE
load_file_internal(VALUE argp_v)
{
@@ -2562,12 +2374,6 @@ load_file_internal(VALUE argp_v)
}
rb_parser_set_options(parser, opt->do_print, opt->do_loop,
opt->do_line, opt->do_split);
-
- VALUE lines = rb_script_lines_for(orig_fname, true);
- if (!NIL_P(lines)) {
- rb_parser_set_script_lines(parser, lines);
- }
-
if (NIL_P(f)) {
f = rb_str_new(0, 0);
rb_enc_associate(f, enc);
@@ -2731,9 +2537,7 @@ void *
rb_parser_load_file(VALUE parser, VALUE fname_v)
{
ruby_cmdline_options_t opt;
- int xflag = 0;
- VALUE f = open_load_file(fname_v, &xflag);
- cmdline_options_init(&opt)->xflag = xflag != 0;
+ VALUE f = open_load_file(fname_v, &cmdline_options_init(&opt)->xflag);
return load_file(parser, fname_v, f, 0, &opt);
}
@@ -2808,18 +2612,12 @@ external_str_new_cstr(const char *p)
#endif
}
-static void
-set_progname(VALUE name)
-{
- rb_orig_progname = rb_progname = name;
- rb_vm_set_progname(rb_progname);
-}
-
void
ruby_script(const char *name)
{
if (name) {
- set_progname(rb_str_freeze(external_str_new_cstr(name)));
+ rb_orig_progname = rb_progname = external_str_new_cstr(name);
+ rb_vm_set_progname(rb_progname);
}
}
@@ -2830,7 +2628,8 @@ ruby_script(const char *name)
void
ruby_set_script_name(VALUE name)
{
- set_progname(rb_str_new_frozen(name));
+ rb_orig_progname = rb_progname = rb_str_dup(name);
+ rb_vm_set_progname(rb_progname);
}
static void
@@ -2954,20 +2753,15 @@ ruby_process_options(int argc, char **argv)
origarg.argc = argc;
origarg.argv = argv;
}
- set_progname(external_str_new_cstr(script_name)); /* for the time being */
+ ruby_script(script_name); /* for the time being */
rb_argv0 = rb_str_new4(rb_progname);
rb_gc_register_mark_object(rb_argv0);
+ iseq = process_options(argc, argv, cmdline_options_init(&opt));
#ifndef HAVE_SETPROCTITLE
ruby_init_setproctitle(argc, argv);
#endif
- iseq = process_options(argc, argv, cmdline_options_init(&opt));
-
- if (opt.crash_report && *opt.crash_report) {
- void ruby_set_crash_report(const char *template);
- ruby_set_crash_report(opt.crash_report);
- }
return (void*)(struct RData*)iseq;
}
diff --git a/ruby_parser.c b/ruby_parser.c
deleted file mode 100644
index 17fc352bed..0000000000
--- a/ruby_parser.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/* This is a wrapper for parse.y */
-#ifdef UNIVERSAL_PARSER
-
-#include "internal.h"
-#include "internal/array.h"
-#include "internal/bignum.h"
-#include "internal/compile.h"
-#include "internal/complex.h"
-#include "internal/encoding.h"
-#include "internal/error.h"
-#include "internal/gc.h"
-#include "internal/hash.h"
-#include "internal/io.h"
-#include "internal/parse.h"
-#include "internal/rational.h"
-#include "internal/re.h"
-#include "internal/ruby_parser.h"
-#include "internal/string.h"
-#include "internal/symbol.h"
-#include "internal/thread.h"
-
-#include "ruby/ractor.h"
-#include "ruby/ruby.h"
-#include "ruby/util.h"
-#include "node.h"
-#include "internal.h"
-#include "vm_core.h"
-#include "symbol.h"
-
-struct ruby_parser {
- rb_parser_t *parser_params;
-};
-
-static void
-parser_mark(void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- rb_ruby_parser_mark(parser->parser_params);
-}
-
-static void
-parser_free(void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- rb_ruby_parser_free(parser->parser_params);
-}
-
-static size_t
-parser_memsize(const void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- return rb_ruby_parser_memsize(parser->parser_params);
-}
-
-static const rb_data_type_t ruby_parser_data_type = {
- "parser",
- {
- parser_mark,
- parser_free,
- parser_memsize,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-static void
-bignum_negate(VALUE b)
-{
- BIGNUM_NEGATE(b);
-}
-
-static int
-is_ascii_string2(VALUE str)
-{
- return is_ascii_string(str);
-}
-
-static void
-rational_set_num(VALUE r, VALUE n)
-{
- RATIONAL_SET_NUM(r, n);
-}
-
-static VALUE
-rational_get_num(VALUE obj)
-{
- return RRATIONAL(obj)->num;
-}
-
-static void
-rcomplex_set_real(VALUE cmp, VALUE r)
-{
- RCOMPLEX_SET_REAL(cmp, r);
-}
-
-static void
-rcomplex_set_imag(VALUE cmp, VALUE i)
-{
- RCOMPLEX_SET_IMAG(cmp, i);
-}
-
-static VALUE
-rcomplex_get_real(VALUE obj)
-{
- return RCOMPLEX(obj)->real;
-}
-
-static VALUE
-rcomplex_get_imag(VALUE obj)
-{
- return RCOMPLEX(obj)->imag;
-}
-
-RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
-static VALUE
-syntax_error_append(VALUE exc, VALUE file, int line, int column,
- void *enc, const char *fmt, va_list args)
-{
- return rb_syntax_error_append(exc, file, line, column, (rb_encoding *)enc, fmt, args);
-}
-
-static int
-local_defined(ID id, const void *p)
-{
- return rb_local_defined(id, (const rb_iseq_t *)p);
-}
-
-static int
-dvar_defined(ID id, const void *p)
-{
- return rb_dvar_defined(id, (const rb_iseq_t *)p);
-}
-
-static bool
-hash_literal_key_p(VALUE k)
-{
- switch (OBJ_BUILTIN_TYPE(k)) {
- case T_NODE:
- return false;
- default:
- return true;
- }
-}
-
-static int
-literal_cmp(VALUE val, VALUE lit)
-{
- if (val == lit) return 0;
- if (!hash_literal_key_p(val) || !hash_literal_key_p(lit)) return -1;
- return rb_iseq_cdhash_cmp(val, lit);
-}
-
-static st_index_t
-literal_hash(VALUE a)
-{
- if (!hash_literal_key_p(a)) return (st_index_t)a;
- return rb_iseq_cdhash_hash(a);
-}
-
-static int
-is_usascii_enc(void *enc)
-{
- return rb_is_usascii_enc((rb_encoding *)enc);
-}
-
-static int
-is_local_id2(ID id)
-{
- return is_local_id(id);
-}
-
-static int
-is_attrset_id2(ID id)
-{
- return is_attrset_id(id);
-}
-
-static int
-is_notop_id2(ID id)
-{
- return is_notop_id(id);
-}
-
-static VALUE
-enc_str_new(const char *ptr, long len, void *enc)
-{
- return rb_enc_str_new(ptr, len, (rb_encoding *)enc);
-}
-
-static int
-enc_isalnum(OnigCodePoint c, void *enc)
-{
- return rb_enc_isalnum(c, (rb_encoding *)enc);
-}
-
-static int
-enc_precise_mbclen(const char *p, const char *e, void *enc)
-{
- return rb_enc_precise_mbclen(p, e, (rb_encoding *)enc);
-}
-
-static int
-mbclen_charfound_p(int len)
-{
- return MBCLEN_CHARFOUND_P(len);
-}
-
-static const char *
-enc_name(void *enc)
-{
- return rb_enc_name((rb_encoding *)enc);
-}
-
-static char *
-enc_prev_char(const char *s, const char *p, const char *e, void *enc)
-{
- return rb_enc_prev_char(s, p, e, (rb_encoding *)enc);
-}
-
-static void *
-enc_get(VALUE obj)
-{
- return (void *)rb_enc_get(obj);
-}
-
-static int
-enc_asciicompat(void *enc)
-{
- return rb_enc_asciicompat((rb_encoding *)enc);
-}
-
-static void *
-utf8_encoding(void)
-{
- return (void *)rb_utf8_encoding();
-}
-
-static VALUE
-enc_associate(VALUE obj, void *enc)
-{
- return rb_enc_associate(obj, (rb_encoding *)enc);
-}
-
-static void *
-ascii8bit_encoding(void)
-{
- return (void *)rb_ascii8bit_encoding();
-}
-
-static int
-enc_codelen(int c, void *enc)
-{
- return rb_enc_codelen(c, (rb_encoding *)enc);
-}
-
-static VALUE
-enc_str_buf_cat(VALUE str, const char *ptr, long len, void *enc)
-{
- return rb_enc_str_buf_cat(str, ptr, len, (rb_encoding *)enc);
-}
-
-static int
-enc_mbcput(unsigned int c, void *buf, void *enc)
-{
- return rb_enc_mbcput(c, buf, (rb_encoding *)enc);
-}
-
-static void *
-enc_from_index(int idx)
-{
- return (void *)rb_enc_from_index(idx);
-}
-
-static int
-enc_isspace(OnigCodePoint c, void *enc)
-{
- return rb_enc_isspace(c, (rb_encoding *)enc);
-}
-
-static ID
-intern3(const char *name, long len, void *enc)
-{
- return rb_intern3(name, len, (rb_encoding *)enc);
-}
-
-static void *
-enc_compatible(VALUE str1, VALUE str2)
-{
- return (void *)rb_enc_compatible(str1, str2);
-}
-
-static VALUE
-enc_from_encoding(void *enc)
-{
- return rb_enc_from_encoding((rb_encoding *)enc);
-}
-
-static int
-encoding_get(VALUE obj)
-{
- return ENCODING_GET(obj);
-}
-
-static void
-encoding_set(VALUE obj, int encindex)
-{
- ENCODING_SET(obj, encindex);
-}
-
-static int
-encoding_is_ascii8bit(VALUE obj)
-{
- return ENCODING_IS_ASCII8BIT(obj);
-}
-
-static void *
-usascii_encoding(void)
-{
- return (void *)rb_usascii_encoding();
-}
-
-static int
-enc_symname_type(const char *name, long len, void *enc, unsigned int allowed_attrset)
-{
- return rb_enc_symname_type(name, len, (rb_encoding *)enc, allowed_attrset);
-}
-
-typedef struct {
- struct parser_params *parser;
- rb_encoding *enc;
- NODE *succ_block;
- const rb_code_location_t *loc;
-} reg_named_capture_assign_t;
-
-static int
-reg_named_capture_assign_iter(const OnigUChar *name, const OnigUChar *name_end,
- int back_num, int *back_refs, OnigRegex regex, void *arg0)
-{
- reg_named_capture_assign_t *arg = (reg_named_capture_assign_t*)arg0;
- struct parser_params* p = arg->parser;
- rb_encoding *enc = arg->enc;
- const rb_code_location_t *loc = arg->loc;
- long len = name_end - name;
- const char *s = (const char *)name;
-
- return rb_reg_named_capture_assign_iter_impl(p, s, len, (void *)enc, &arg->succ_block, loc);
-}
-
-static NODE *
-reg_named_capture_assign(struct parser_params* p, VALUE regexp, const rb_code_location_t *loc)
-{
- reg_named_capture_assign_t arg;
-
- arg.parser = p;
- arg.enc = rb_enc_get(regexp);
- arg.succ_block = 0;
- arg.loc = loc;
- onig_foreach_name(RREGEXP_PTR(regexp), reg_named_capture_assign_iter, &arg);
-
- if (!arg.succ_block) return 0;
- return RNODE_BLOCK(arg.succ_block)->nd_next;
-}
-
-static VALUE
-rbool(VALUE v)
-{
- return RBOOL(v);
-}
-
-static int
-undef_p(VALUE v)
-{
- return RB_UNDEF_P(v);
-}
-
-static int
-rtest(VALUE obj)
-{
- return (int)RB_TEST(obj);
-}
-
-static int
-nil_p(VALUE obj)
-{
- return (int)NIL_P(obj);
-}
-
-static int
-flonum_p(VALUE obj)
-{
- return (int)RB_FLONUM_P(obj);
-}
-
-static VALUE
-int2fix(long i)
-{
- return INT2FIX(i);
-}
-
-static VALUE
-syntax_error_new(void)
-{
- return rb_class_new_instance(0, 0, rb_eSyntaxError);
-}
-
-static int
-obj_frozen(VALUE obj)
-{
- return (int)RB_OBJ_FROZEN(obj);
-}
-
-static VALUE
-obj_write(VALUE old, VALUE *slot, VALUE young)
-{
- return RB_OBJ_WRITE(old, slot, young);
-}
-
-static VALUE
-obj_written(VALUE old, VALUE slot, VALUE young)
-{
- return RB_OBJ_WRITTEN(old, slot, young);
-}
-
-static VALUE
-default_rs(void)
-{
- return rb_default_rs;
-}
-
-static VALUE
-rational_raw1(VALUE x)
-{
- return rb_rational_raw1(x);
-}
-
-static void *
-memmove2(void *dest, const void *src, size_t t, size_t n)
-{
- return memmove(dest, src, rbimpl_size_mul_or_raise(t, n));
-}
-
-static void *
-nonempty_memcpy(void *dest, const void *src, size_t t, size_t n)
-{
- return ruby_nonempty_memcpy(dest, src, rbimpl_size_mul_or_raise(t, n));
-}
-
-static VALUE
-ruby_verbose2(void)
-{
- return ruby_verbose;
-}
-
-static int
-type_p(VALUE obj, int t)
-{
- return (int)RB_TYPE_P(obj, t);
-}
-
-static int
-fixnum_p(VALUE obj)
-{
- return (int)RB_FIXNUM_P(obj);
-}
-
-static int
-symbol_p(VALUE obj)
-{
- return (int)RB_SYMBOL_P(obj);
-}
-
-static void *
-zalloc(size_t elemsiz)
-{
- return ruby_xcalloc(1, elemsiz);
-}
-
-static void
-gc_guard(VALUE obj)
-{
- RB_GC_GUARD(obj);
-}
-
-static rb_imemo_tmpbuf_t *
-tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
-{
- return rb_imemo_tmpbuf_parser_heap(buf, old_heap, cnt);
-}
-
-static int
-special_const_p(VALUE obj)
-{
- return (int)RB_SPECIAL_CONST_P(obj);
-}
-
-static int
-builtin_type(VALUE obj)
-{
- return (int)RB_BUILTIN_TYPE(obj);
-}
-
-static rb_ast_t *
-ast_new(VALUE nb)
-{
- rb_ast_t *ast = (rb_ast_t *)rb_imemo_new(imemo_ast, 0, 0, 0, nb);
- return ast;
-}
-
-static VALUE
-static_id2sym(ID id)
-{
- return (((VALUE)(id)<<RUBY_SPECIAL_SHIFT)|SYMBOL_FLAG);
-}
-
-static long
-str_coderange_scan_restartable(const char *s, const char *e, void *enc, int *cr)
-{
- return rb_str_coderange_scan_restartable(s, e, (rb_encoding *)enc, cr);
-}
-
-VALUE rb_io_gets_internal(VALUE io);
-extern VALUE rb_mRubyVMFrozenCore;
-VALUE rb_node_case_when_optimizable_literal(const NODE *const node);
-
-void
-rb_parser_config_initialize(rb_parser_config_t *config)
-{
- config->counter = 0;
-
- config->malloc = ruby_xmalloc;
- config->calloc = ruby_xcalloc;
- config->realloc = ruby_xrealloc;
- config->free = ruby_xfree;
- config->alloc_n = ruby_xmalloc2;
- config->alloc = ruby_xmalloc;
- config->realloc_n = ruby_xrealloc2;
- config->zalloc = zalloc;
- config->rb_memmove = memmove2;
- config->nonempty_memcpy = nonempty_memcpy;
- config->xmalloc_mul_add = rb_xmalloc_mul_add;
-
- config->tmpbuf_parser_heap = tmpbuf_parser_heap;
- config->ast_new = ast_new;
-
- config->compile_callback = rb_suppress_tracing;
- config->reg_named_capture_assign = reg_named_capture_assign;
-
- config->obj_freeze = rb_obj_freeze;
- config->obj_hide = rb_obj_hide;
- config->obj_frozen = obj_frozen;
- config->type_p = type_p;
- config->obj_freeze_raw = OBJ_FREEZE_RAW;
-
- config->fixnum_p = fixnum_p;
- config->symbol_p = symbol_p;
-
- config->attr_get = rb_attr_get;
-
- config->ary_new = rb_ary_new;
- config->ary_push = rb_ary_push;
- config->ary_new_from_args = rb_ary_new_from_args;
- config->ary_pop = rb_ary_pop;
- config->ary_last = rb_ary_last;
- config->ary_unshift = rb_ary_unshift;
- config->ary_new2 = rb_ary_new2;
- config->ary_entry = rb_ary_entry;
- config->ary_join = rb_ary_join;
- config->ary_reverse = rb_ary_reverse;
- config->ary_clear = rb_ary_clear;
- config->array_len = rb_array_len;
- config->array_aref = RARRAY_AREF;
-
- config->sym_intern_ascii_cstr = rb_sym_intern_ascii_cstr;
- config->make_temporary_id = rb_make_temporary_id;
- config->is_local_id = is_local_id2;
- config->is_attrset_id = is_attrset_id2;
- config->is_global_name_punct = is_global_name_punct;
- config->id_type = id_type;
- config->id_attrset = rb_id_attrset;
- config->intern = rb_intern;
- config->intern2 = rb_intern2;
- config->intern3 = intern3;
- config->intern_str = rb_intern_str;
- config->is_notop_id = is_notop_id2;
- config->enc_symname_type = enc_symname_type;
- config->str_intern = rb_str_intern;
- config->id2name = rb_id2name;
- config->id2str = rb_id2str;
- config->id2sym = rb_id2sym;
- config->sym2id = rb_sym2id;
-
- config->str_catf = rb_str_catf;
- config->str_cat_cstr = rb_str_cat_cstr;
- config->str_subseq = rb_str_subseq;
- config->str_dup = rb_str_dup;
- config->str_new_frozen = rb_str_new_frozen;
- config->str_buf_new = rb_str_buf_new;
- config->str_buf_cat = rb_str_buf_cat;
- config->str_modify = rb_str_modify;
- config->str_set_len = rb_str_set_len;
- config->str_cat = rb_str_cat;
- config->str_resize = rb_str_resize;
- config->str_new = rb_str_new;
- config->str_new_cstr = rb_str_new_cstr;
- config->fstring = rb_fstring;
- config->is_ascii_string = is_ascii_string2;
- config->enc_str_new = enc_str_new;
- config->enc_str_buf_cat = enc_str_buf_cat;
- config->str_buf_append = rb_str_buf_append;
- config->str_vcatf = rb_str_vcatf;
- config->string_value_cstr = rb_string_value_cstr;
- config->rb_sprintf = rb_sprintf;
- config->rstring_ptr = RSTRING_PTR;
- config->rstring_end = RSTRING_END;
- config->rstring_len = RSTRING_LEN;
- config->filesystem_str_new_cstr = rb_filesystem_str_new_cstr;
- config->obj_as_string = rb_obj_as_string;
-
- config->hash_clear = rb_hash_clear;
- config->hash_new = rb_hash_new;
- config->hash_aset = rb_hash_aset;
- config->hash_lookup = rb_hash_lookup;
- config->hash_delete = rb_hash_delete;
- config->ident_hash_new = rb_ident_hash_new;
-
- config->int2fix = int2fix;
-
- config->bignum_negate = bignum_negate;
- config->big_norm = rb_big_norm;
- config->cstr_to_inum = rb_cstr_to_inum;
-
- config->float_new = rb_float_new;
- config->float_value = rb_float_value;
-
- config->num2int = rb_num2int_inline;
- config->int_positive_pow = rb_int_positive_pow;
- config->int2num = rb_int2num_inline;
- config->fix2long = rb_fix2long;
-
- config->rational_new = rb_rational_new;
- config->rational_raw1 = rational_raw1;
- config->rational_set_num = rational_set_num;
- config->rational_get_num = rational_get_num;
-
- config->complex_raw = rb_complex_raw;
- config->rcomplex_set_real = rcomplex_set_real;
- config->rcomplex_set_imag = rcomplex_set_imag;
- config->rcomplex_get_real = rcomplex_get_real;
- config->rcomplex_get_imag = rcomplex_get_imag;
-
- config->stderr_tty_p = rb_stderr_tty_p;
- config->write_error_str = rb_write_error_str;
- config->default_rs = default_rs;
- config->io_write = rb_io_write;
- config->io_flush = rb_io_flush;
- config->io_puts = rb_io_puts;
- config->io_gets_internal= rb_io_gets_internal;
-
- config->debug_output_stdout = rb_ractor_stdout;
- config->debug_output_stderr = rb_ractor_stderr;
-
- config->is_usascii_enc = is_usascii_enc;
- config->enc_isalnum = enc_isalnum;
- config->enc_precise_mbclen = enc_precise_mbclen;
- config->mbclen_charfound_p = mbclen_charfound_p;
- config->enc_name = enc_name;
- config->enc_prev_char = enc_prev_char;
- config->enc_get = enc_get;
- config->enc_asciicompat = enc_asciicompat;
- config->utf8_encoding = utf8_encoding;
- config->enc_associate = enc_associate;
- config->ascii8bit_encoding = ascii8bit_encoding;
- config->enc_codelen = enc_codelen;
- config->enc_mbcput = enc_mbcput;
- config->char_to_option_kcode = rb_char_to_option_kcode;
- config->ascii8bit_encindex = rb_ascii8bit_encindex;
- config->enc_find_index = rb_enc_find_index;
- config->enc_from_index = enc_from_index;
- config->enc_associate_index = rb_enc_associate_index;
- config->enc_isspace = enc_isspace;
- config->enc_coderange_7bit = ENC_CODERANGE_7BIT;
- config->enc_coderange_unknown = ENC_CODERANGE_UNKNOWN;
- config->enc_compatible = enc_compatible;
- config->enc_from_encoding = enc_from_encoding;
- config->encoding_get = encoding_get;
- config->encoding_set = encoding_set;
- config->encoding_is_ascii8bit = encoding_is_ascii8bit;
- config->usascii_encoding = usascii_encoding;
-
- config->ractor_make_shareable = rb_ractor_make_shareable;
-
- config->local_defined = local_defined;
- config->dvar_defined = dvar_defined;
-
- config->literal_cmp = literal_cmp;
- config->literal_hash = literal_hash;
-
- config->builtin_class_name = rb_builtin_class_name;
- config->syntax_error_append = syntax_error_append;
- config->raise = rb_raise;
- config->syntax_error_new = syntax_error_new;
-
- config->errinfo = rb_errinfo;
- config->set_errinfo = rb_set_errinfo;
- config->exc_raise = rb_exc_raise;
- config->make_exception = rb_make_exception;
-
- config->sized_xfree = ruby_sized_xfree;
- config->sized_realloc_n = ruby_sized_realloc_n;
- config->obj_write = obj_write;
- config->obj_written = obj_written;
- config->gc_register_mark_object = rb_gc_register_mark_object;
- config->gc_guard = gc_guard;
- config->gc_mark = rb_gc_mark;
- config->gc_mark_movable = rb_gc_mark_movable;
- config->gc_location = rb_gc_location;
-
- config->reg_compile = rb_reg_compile;
- config->reg_check_preprocess = rb_reg_check_preprocess;
- config->memcicmp = rb_memcicmp;
-
- config->compile_warn = rb_compile_warn;
- config->compile_warning = rb_compile_warning;
- config->bug = rb_bug;
- config->fatal = rb_fatal;
- config->verbose = ruby_verbose2;
-
- config->make_backtrace = rb_make_backtrace;
-
- config->scan_hex = ruby_scan_hex;
- config->scan_oct = ruby_scan_oct;
- config->scan_digits = ruby_scan_digits;
- config->strtod = ruby_strtod;
-
- config->rbool = rbool;
- config->undef_p = undef_p;
- config->rtest = rtest;
- config->nil_p = nil_p;
- config->flonum_p = flonum_p;
- config->qnil = Qnil;
- config->qtrue = Qtrue;
- config->qfalse = Qfalse;
- config->qundef = Qundef;
- config->eArgError = rb_eArgError;
- config->mRubyVMFrozenCore = rb_mRubyVMFrozenCore;
- config->long2int = rb_long2int;
- config->special_const_p = special_const_p;
- config->builtin_type = builtin_type;
-
- config->node_case_when_optimizable_literal = rb_node_case_when_optimizable_literal;
-
- /* For Ripper */
- config->static_id2sym = static_id2sym;
- config->str_coderange_scan_restartable = str_coderange_scan_restartable;
-}
-
-VALUE
-rb_parser_new(void)
-{
- struct ruby_parser *parser;
- rb_parser_config_t *config;
- rb_parser_t *parser_params;
-
- config = rb_ruby_parser_config_new(ruby_xmalloc);
- rb_parser_config_initialize(config);
-
- /*
- * Create parser_params ahead of vparser because
- * rb_ruby_parser_new can run GC so if create vparser
- * first, parser_mark tries to mark not initialized parser_params.
- */
- parser_params = rb_ruby_parser_new(config);
- VALUE vparser = TypedData_Make_Struct(0, struct ruby_parser,
- &ruby_parser_data_type, parser);
- parser->parser_params = parser_params;
-
- return vparser;
-}
-
-void
-rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_options(parser->parser_params, print, loop, chomp, split);
-}
-
-VALUE
-rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_context(parser->parser_params, base, main);
- return vparser;
-}
-
-void
-rb_parser_set_script_lines(VALUE vparser, VALUE lines)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_script_lines(parser->parser_params, lines);
-}
-
-void
-rb_parser_error_tolerant(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_error_tolerant(parser->parser_params);
-}
-
-rb_ast_t*
-rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
-{
- struct ruby_parser *parser;
- rb_ast_t *ast;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_file_path(parser->parser_params, fname, file, start);
- RB_GC_GUARD(vparser);
-
- return ast;
-}
-
-void
-rb_parser_keep_tokens(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_keep_tokens(parser->parser_params);
-}
-
-rb_ast_t*
-rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
-{
- struct ruby_parser *parser;
- rb_ast_t *ast;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_generic(parser->parser_params, lex_gets, fname, input, start);
- RB_GC_GUARD(vparser);
-
- return ast;
-}
-
-rb_ast_t*
-rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
-{
- struct ruby_parser *parser;
- rb_ast_t *ast;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_string(parser->parser_params, f, s, line);
- RB_GC_GUARD(vparser);
-
- return ast;
-}
-
-rb_ast_t*
-rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
-{
- struct ruby_parser *parser;
- rb_ast_t *ast;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- ast = rb_ruby_parser_compile_string_path(parser->parser_params, f, s, line);
- RB_GC_GUARD(vparser);
-
- return ast;
-}
-
-VALUE
-rb_parser_encoding(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- return rb_ruby_parser_encoding(parser->parser_params);
-}
-
-VALUE
-rb_parser_end_seen_p(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- return RBOOL(rb_ruby_parser_end_seen_p(parser->parser_params));
-}
-
-VALUE
-rb_parser_set_yydebug(VALUE vparser, VALUE flag)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_yydebug(parser->parser_params, RTEST(flag));
- return flag;
-}
-
-#else
-
-/* For "ISO C requires a translation unit to contain at least one declaration" */
-void
-rb_parser_dummy(void)
-{}
-#endif
diff --git a/rubyparser.h b/rubyparser.h
deleted file mode 100644
index d366227318..0000000000
--- a/rubyparser.h
+++ /dev/null
@@ -1,1403 +0,0 @@
-#ifndef RUBY_RUBYPARSER_H
-#define RUBY_RUBYPARSER_H 1
-/*
- * This is a header file for librubyparser interface
- */
-
-#include <stdarg.h> /* for va_list */
-#include <assert.h>
-
-#ifdef UNIVERSAL_PARSER
-
-#define rb_encoding void
-#define OnigCodePoint unsigned int
-#include "parser_st.h"
-#ifndef RUBY_RUBY_H
-#include "parser_value.h"
-#endif
-
-#else
-
-#include "ruby/encoding.h"
-
-#endif
-
-/*
- * AST Node
- */
-enum node_type {
- NODE_SCOPE,
- NODE_BLOCK,
- NODE_IF,
- NODE_UNLESS,
- NODE_CASE,
- NODE_CASE2,
- NODE_CASE3,
- NODE_WHEN,
- NODE_IN,
- NODE_WHILE,
- NODE_UNTIL,
- NODE_ITER,
- NODE_FOR,
- NODE_FOR_MASGN,
- NODE_BREAK,
- NODE_NEXT,
- NODE_REDO,
- NODE_RETRY,
- NODE_BEGIN,
- NODE_RESCUE,
- NODE_RESBODY,
- NODE_ENSURE,
- NODE_AND,
- NODE_OR,
- NODE_MASGN,
- NODE_LASGN,
- NODE_DASGN,
- NODE_GASGN,
- NODE_IASGN,
- NODE_CDECL,
- NODE_CVASGN,
- NODE_OP_ASGN1,
- NODE_OP_ASGN2,
- NODE_OP_ASGN_AND,
- NODE_OP_ASGN_OR,
- NODE_OP_CDECL,
- NODE_CALL,
- NODE_OPCALL,
- NODE_FCALL,
- NODE_VCALL,
- NODE_QCALL,
- NODE_SUPER,
- NODE_ZSUPER,
- NODE_LIST,
- NODE_ZLIST,
- NODE_HASH,
- NODE_RETURN,
- NODE_YIELD,
- NODE_LVAR,
- NODE_DVAR,
- NODE_GVAR,
- NODE_IVAR,
- NODE_CONST,
- NODE_CVAR,
- NODE_NTH_REF,
- NODE_BACK_REF,
- NODE_MATCH,
- NODE_MATCH2,
- NODE_MATCH3,
- NODE_LIT,
- NODE_STR,
- NODE_DSTR,
- NODE_XSTR,
- NODE_DXSTR,
- NODE_EVSTR,
- NODE_DREGX,
- NODE_ONCE,
- NODE_ARGS,
- NODE_ARGS_AUX,
- NODE_OPT_ARG,
- NODE_KW_ARG,
- NODE_POSTARG,
- NODE_ARGSCAT,
- NODE_ARGSPUSH,
- NODE_SPLAT,
- NODE_BLOCK_PASS,
- NODE_DEFN,
- NODE_DEFS,
- NODE_ALIAS,
- NODE_VALIAS,
- NODE_UNDEF,
- NODE_CLASS,
- NODE_MODULE,
- NODE_SCLASS,
- NODE_COLON2,
- NODE_COLON3,
- NODE_DOT2,
- NODE_DOT3,
- NODE_FLIP2,
- NODE_FLIP3,
- NODE_SELF,
- NODE_NIL,
- NODE_TRUE,
- NODE_FALSE,
- NODE_ERRINFO,
- NODE_DEFINED,
- NODE_POSTEXE,
- NODE_DSYM,
- NODE_ATTRASGN,
- NODE_LAMBDA,
- NODE_ARYPTN,
- NODE_HSHPTN,
- NODE_FNDPTN,
- NODE_ERROR,
- NODE_RIPPER,
- NODE_RIPPER_VALUES,
- NODE_LAST
-};
-
-#ifndef FLEX_ARY_LEN
-/* From internal/compilers.h */
-/* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
-# define FLEX_ARY_LEN /* VALUE ary[]; */
-#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
-# define FLEX_ARY_LEN 0 /* VALUE ary[0]; */
-#else
-# define FLEX_ARY_LEN 1 /* VALUE ary[1]; */
-#endif
-#endif
-
-typedef struct rb_ast_id_table {
- int size;
- ID ids[FLEX_ARY_LEN];
-} rb_ast_id_table_t;
-
-typedef struct rb_code_position_struct {
- int lineno;
- int column;
-} rb_code_position_t;
-
-typedef struct rb_code_location_struct {
- rb_code_position_t beg_pos;
- rb_code_position_t end_pos;
-} rb_code_location_t;
-
-/* Header part of AST Node */
-typedef struct RNode {
- VALUE flags;
- rb_code_location_t nd_loc;
- int node_id;
-} NODE;
-
-typedef struct RNode_SCOPE {
- NODE node;
-
- rb_ast_id_table_t *nd_tbl;
- struct RNode *nd_body;
- struct RNode_ARGS *nd_args;
-} rb_node_scope_t;
-
-typedef struct RNode_BLOCK {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_end;
- struct RNode *nd_next;
-} rb_node_block_t;
-
-typedef struct RNode_IF {
- NODE node;
-
- struct RNode *nd_cond;
- struct RNode *nd_body;
- struct RNode *nd_else;
-} rb_node_if_t;
-
-typedef struct RNode_UNLESS {
- NODE node;
-
- struct RNode *nd_cond;
- struct RNode *nd_body;
- struct RNode *nd_else;
-} rb_node_unless_t;
-
-typedef struct RNode_CASE {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_case_t;
-
-typedef struct RNode_CASE2 {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_case2_t;
-
-typedef struct RNode_CASE3 {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_case3_t;
-
-typedef struct RNode_WHEN {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- struct RNode *nd_next;
-} rb_node_when_t;
-
-typedef struct RNode_IN {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- struct RNode *nd_next;
-} rb_node_in_t;
-
-/* RNode_WHILE and RNode_UNTIL should be same structure */
-typedef struct RNode_WHILE {
- NODE node;
-
- struct RNode *nd_cond;
- struct RNode *nd_body;
- long nd_state;
-} rb_node_while_t;
-
-typedef struct RNode_UNTIL {
- NODE node;
-
- struct RNode *nd_cond;
- struct RNode *nd_body;
- long nd_state;
-} rb_node_until_t;
-
-/* RNode_ITER and RNode_FOR should be same structure */
-typedef struct RNode_ITER {
- NODE node;
-
- struct RNode *nd_body;
- struct RNode *nd_iter;
-} rb_node_iter_t;
-
-typedef struct RNode_FOR {
- NODE node;
-
- struct RNode *nd_body;
- struct RNode *nd_iter;
-} rb_node_for_t;
-
-typedef struct RNode_FOR_MASGN {
- NODE node;
-
- struct RNode *nd_var;
-} rb_node_for_masgn_t;
-
-/* RNode_BREAK, RNode_NEXT and RNode_RETURN should be same structure */
-typedef struct RNode_BREAK {
- NODE node;
-
- struct RNode *nd_chain;
- struct RNode *nd_stts;
-} rb_node_break_t;
-
-typedef struct RNode_NEXT {
- NODE node;
-
- struct RNode *nd_chain;
- struct RNode *nd_stts;
-} rb_node_next_t;
-
-typedef struct RNode_REDO {
- NODE node;
-
- struct RNode *nd_chain;
-} rb_node_redo_t;
-
-typedef struct RNode_RETRY {
- NODE node;
-} rb_node_retry_t;
-
-typedef struct RNode_BEGIN {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_begin_t;
-
-typedef struct RNode_RESCUE {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_resq;
- struct RNode *nd_else;
-} rb_node_rescue_t;
-
-typedef struct RNode_RESBODY {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- struct RNode *nd_args;
-} rb_node_resbody_t;
-
-typedef struct RNode_ENSURE {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_resq; /* Maybe not used other than reduce_nodes */
- struct RNode *nd_ensr;
-} rb_node_ensure_t;
-
-/* RNode_AND and RNode_OR should be same structure */
-typedef struct RNode_AND {
- NODE node;
-
- struct RNode *nd_1st;
- struct RNode *nd_2nd;
-} rb_node_and_t;
-
-typedef struct RNode_OR {
- NODE node;
-
- struct RNode *nd_1st;
- struct RNode *nd_2nd;
-} rb_node_or_t;
-
-typedef struct RNode_MASGN {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
- struct RNode *nd_args;
-} rb_node_masgn_t;
-
-typedef struct RNode_LASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_lasgn_t;
-
-typedef struct RNode_DASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_dasgn_t;
-
-typedef struct RNode_GASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_gasgn_t;
-
-typedef struct RNode_IASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_iasgn_t;
-
-typedef struct RNode_CDECL {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
- struct RNode *nd_else;
-} rb_node_cdecl_t;
-
-typedef struct RNode_CVASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_cvasgn_t;
-
-typedef struct RNode_OP_ASGN1 {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_index;
- struct RNode *nd_rvalue;
-} rb_node_op_asgn1_t;
-
-typedef struct RNode_OP_ASGN2 {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_value;
- ID nd_vid;
- ID nd_mid;
- bool nd_aid;
-} rb_node_op_asgn2_t;
-
-typedef struct RNode_OP_ASGN_AND {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
-} rb_node_op_asgn_and_t;
-
-typedef struct RNode_OP_ASGN_OR {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
-} rb_node_op_asgn_or_t;
-
-typedef struct RNode_OP_CDECL {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
- ID nd_aid;
-} rb_node_op_cdecl_t;
-
-typedef struct RNode_CALL {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_call_t;
-
-typedef struct RNode_OPCALL {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_opcall_t;
-
-typedef struct RNode_FCALL {
- NODE node;
-
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_fcall_t;
-
-typedef struct RNode_VCALL {
- NODE node;
-
- ID nd_mid;
-} rb_node_vcall_t;
-
-typedef struct RNode_QCALL {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_qcall_t;
-
-typedef struct RNode_SUPER {
- NODE node;
-
- struct RNode *nd_args;
-} rb_node_super_t;
-
-typedef struct RNode_ZSUPER {
- NODE node;
-} rb_node_zsuper_t;
-
-/*
-
- Structure of LIST:
-
- LIST +--> LIST
- * head --> element | * head
- * alen (length of list) | * nd_end (point to the last LIST)
- * next -----------------+ * next
-
-
- RNode_LIST and RNode_VALUES should be same structure
-*/
-typedef struct RNode_LIST {
- NODE node;
-
- struct RNode *nd_head; /* element */
- union {
- long nd_alen;
- struct RNode *nd_end; /* Second list node has this structure */
- } as;
- struct RNode *nd_next; /* next list node */
-} rb_node_list_t;
-
-typedef struct RNode_ZLIST {
- NODE node;
-} rb_node_zlist_t;
-
-typedef struct RNode_VALUES {
- NODE node;
-
- struct RNode *nd_head;
- long nd_alen;
- struct RNode *nd_next;
-} rb_node_values_t;
-
-typedef struct RNode_HASH {
- NODE node;
-
- struct RNode *nd_head;
- long nd_brace;
-} rb_node_hash_t;
-
-typedef struct RNode_RETURN {
- NODE node;
-
- struct RNode *nd_stts;
-} rb_node_return_t;
-
-typedef struct RNode_YIELD {
- NODE node;
-
- struct RNode *nd_head;
-} rb_node_yield_t;
-
-typedef struct RNode_LVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_lvar_t;
-
-typedef struct RNode_DVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_dvar_t;
-
-typedef struct RNode_GVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_gvar_t;
-
-typedef struct RNode_IVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_ivar_t;
-
-typedef struct RNode_CONST {
- NODE node;
-
- ID nd_vid;
-} rb_node_const_t;
-
-typedef struct RNode_CVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_cvar_t;
-
-typedef struct RNode_NTH_REF {
- NODE node;
-
- long nd_nth;
-} rb_node_nth_ref_t;
-
-typedef struct RNode_BACK_REF {
- NODE node;
-
- long nd_nth;
-} rb_node_back_ref_t;
-
-/* RNode_MATCH, RNode_LIT, RNode_STR and RNode_XSTR should be same structure */
-typedef struct RNode_MATCH {
- NODE node;
-
- VALUE nd_lit;
-} rb_node_match_t;
-
-typedef struct RNode_MATCH2 {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_value;
- struct RNode *nd_args;
-} rb_node_match2_t;
-
-typedef struct RNode_MATCH3 {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_value;
-} rb_node_match3_t;
-
-typedef struct RNode_LIT {
- NODE node;
-
- VALUE nd_lit;
-} rb_node_lit_t;
-
-typedef struct RNode_STR {
- NODE node;
-
- VALUE nd_lit;
-} rb_node_str_t;
-
-/* RNode_DSTR, RNode_DXSTR and RNode_DSYM should be same structure */
-typedef struct RNode_DSTR {
- NODE node;
-
- VALUE nd_lit;
- union {
- long nd_alen;
- struct RNode *nd_end; /* Second dstr node has this structure. See also RNode_LIST */
- } as;
- struct RNode_LIST *nd_next;
-} rb_node_dstr_t;
-
-typedef struct RNode_XSTR {
- NODE node;
-
- VALUE nd_lit;
-} rb_node_xstr_t;
-
-typedef struct RNode_DXSTR {
- NODE node;
-
- VALUE nd_lit;
- long nd_alen;
- struct RNode_LIST *nd_next;
-} rb_node_dxstr_t;
-
-typedef struct RNode_EVSTR {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_evstr_t;
-
-typedef struct RNode_DREGX {
- NODE node;
-
- VALUE nd_lit;
- ID nd_cflag;
- struct RNode_LIST *nd_next;
-} rb_node_dregx_t;
-
-typedef struct RNode_ONCE {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_once_t;
-
-struct rb_args_info {
- NODE *pre_init;
- NODE *post_init;
-
- int pre_args_num; /* count of mandatory pre-arguments */
- int post_args_num; /* count of mandatory post-arguments */
-
- ID first_post_arg;
-
- ID rest_arg;
- ID block_arg;
-
- struct RNode_KW_ARG *kw_args;
- NODE *kw_rest_arg;
-
- struct RNode_OPT_ARG *opt_args;
- unsigned int no_kwarg: 1;
- unsigned int ruby2_keywords: 1;
- unsigned int forwarding: 1;
-};
-
-typedef struct RNode_ARGS {
- NODE node;
-
- struct rb_args_info nd_ainfo;
-} rb_node_args_t;
-
-typedef struct RNode_ARGS_AUX {
- NODE node;
-
- ID nd_pid;
- long nd_plen;
- struct RNode *nd_next;
-} rb_node_args_aux_t;
-
-typedef struct RNode_OPT_ARG {
- NODE node;
-
- struct RNode *nd_body;
- struct RNode_OPT_ARG *nd_next;
-} rb_node_opt_arg_t;
-
-typedef struct RNode_KW_ARG {
- NODE node;
-
- struct RNode *nd_body;
- struct RNode_KW_ARG *nd_next;
-} rb_node_kw_arg_t;
-
-typedef struct RNode_POSTARG {
- NODE node;
-
- struct RNode *nd_1st;
- struct RNode *nd_2nd;
-} rb_node_postarg_t;
-
-typedef struct RNode_ARGSCAT {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_argscat_t;
-
-typedef struct RNode_ARGSPUSH {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_argspush_t;
-
-typedef struct RNode_SPLAT {
- NODE node;
-
- struct RNode *nd_head;
-} rb_node_splat_t;
-
-typedef struct RNode_BLOCK_PASS {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_block_pass_t;
-
-typedef struct RNode_DEFN {
- NODE node;
-
- ID nd_mid;
- struct RNode *nd_defn;
-} rb_node_defn_t;
-
-typedef struct RNode_DEFS {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_defn;
-} rb_node_defs_t;
-
-typedef struct RNode_ALIAS {
- NODE node;
-
- struct RNode *nd_1st;
- struct RNode *nd_2nd;
-} rb_node_alias_t;
-
-typedef struct RNode_VALIAS {
- NODE node;
-
- ID nd_alias;
- ID nd_orig;
-} rb_node_valias_t;
-
-typedef struct RNode_UNDEF {
- NODE node;
-
- struct RNode *nd_undef;
-} rb_node_undef_t;
-
-typedef struct RNode_CLASS {
- NODE node;
-
- struct RNode *nd_cpath;
- struct RNode *nd_body;
- struct RNode *nd_super;
-} rb_node_class_t;
-
-typedef struct RNode_MODULE {
- NODE node;
-
- struct RNode *nd_cpath;
- struct RNode *nd_body;
-} rb_node_module_t;
-
-typedef struct RNode_SCLASS {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_body;
-} rb_node_sclass_t;
-
-typedef struct RNode_COLON2 {
- NODE node;
-
- struct RNode *nd_head;
- ID nd_mid;
-} rb_node_colon2_t;
-
-typedef struct RNode_COLON3 {
- NODE node;
-
- ID nd_mid;
-} rb_node_colon3_t;
-
-/* RNode_DOT2, RNode_DOT3, RNode_FLIP2 and RNode_FLIP3 should be same structure */
-typedef struct RNode_DOT2 {
- NODE node;
-
- struct RNode *nd_beg;
- struct RNode *nd_end;
-} rb_node_dot2_t;
-
-typedef struct RNode_DOT3 {
- NODE node;
-
- struct RNode *nd_beg;
- struct RNode *nd_end;
-} rb_node_dot3_t;
-
-typedef struct RNode_FLIP2 {
- NODE node;
-
- struct RNode *nd_beg;
- struct RNode *nd_end;
-} rb_node_flip2_t;
-
-typedef struct RNode_FLIP3 {
- NODE node;
-
- struct RNode *nd_beg;
- struct RNode *nd_end;
-} rb_node_flip3_t;
-
-typedef struct RNode_SELF {
- NODE node;
-
- long nd_state; /* Default 1. See NEW_SELF. */
-} rb_node_self_t;
-
-typedef struct RNode_NIL {
- NODE node;
-} rb_node_nil_t;
-
-typedef struct RNode_TRUE {
- NODE node;
-} rb_node_true_t;
-
-typedef struct RNode_FALSE {
- NODE node;
-} rb_node_false_t;
-
-typedef struct RNode_ERRINFO {
- NODE node;
-} rb_node_errinfo_t;
-
-typedef struct RNode_DEFINED {
- NODE node;
-
- struct RNode *nd_head;
-} rb_node_defined_t;
-
-typedef struct RNode_POSTEXE {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_postexe_t;
-
-typedef struct RNode_DSYM {
- NODE node;
-
- VALUE nd_lit;
- long nd_alen;
- struct RNode_LIST *nd_next;
-} rb_node_dsym_t;
-
-typedef struct RNode_ATTRASGN {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_attrasgn_t;
-
-typedef struct RNode_LAMBDA {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_lambda_t;
-
-typedef struct RNode_ARYPTN {
- NODE node;
-
- struct RNode *nd_pconst;
- NODE *pre_args;
- NODE *rest_arg;
- NODE *post_args;
-} rb_node_aryptn_t;
-
-typedef struct RNode_HSHPTN {
- NODE node;
-
- struct RNode *nd_pconst;
- struct RNode *nd_pkwargs;
- struct RNode *nd_pkwrestarg;
-} rb_node_hshptn_t;
-
-typedef struct RNode_FNDPTN {
- NODE node;
-
- struct RNode *nd_pconst;
- NODE *pre_rest_arg;
- NODE *args;
- NODE *post_rest_arg;
-} rb_node_fndptn_t;
-
-typedef struct RNode_ERROR {
- NODE node;
-} rb_node_error_t;
-
-#define RNODE(obj) ((struct RNode *)(obj))
-
-#define RNODE_SCOPE(node) ((struct RNode_SCOPE *)(node))
-#define RNODE_BLOCK(node) ((struct RNode_BLOCK *)(node))
-#define RNODE_IF(node) ((struct RNode_IF *)(node))
-#define RNODE_UNLESS(node) ((struct RNode_UNLESS *)(node))
-#define RNODE_CASE(node) ((struct RNode_CASE *)(node))
-#define RNODE_CASE2(node) ((struct RNode_CASE2 *)(node))
-#define RNODE_CASE3(node) ((struct RNode_CASE3 *)(node))
-#define RNODE_WHEN(node) ((struct RNode_WHEN *)(node))
-#define RNODE_IN(node) ((struct RNode_IN *)(node))
-#define RNODE_WHILE(node) ((struct RNode_WHILE *)(node))
-#define RNODE_UNTIL(node) ((struct RNode_UNTIL *)(node))
-#define RNODE_ITER(node) ((struct RNode_ITER *)(node))
-#define RNODE_FOR(node) ((struct RNode_FOR *)(node))
-#define RNODE_FOR_MASGN(node) ((struct RNode_FOR_MASGN *)(node))
-#define RNODE_BREAK(node) ((struct RNode_BREAK *)(node))
-#define RNODE_NEXT(node) ((struct RNode_NEXT *)(node))
-#define RNODE_REDO(node) ((struct RNode_REDO *)(node))
-#define RNODE_RETRY(node) ((struct RNode_RETRY *)(node))
-#define RNODE_BEGIN(node) ((struct RNode_BEGIN *)(node))
-#define RNODE_RESCUE(node) ((struct RNode_RESCUE *)(node))
-#define RNODE_RESBODY(node) ((struct RNode_RESBODY *)(node))
-#define RNODE_ENSURE(node) ((struct RNode_ENSURE *)(node))
-#define RNODE_AND(node) ((struct RNode_AND *)(node))
-#define RNODE_OR(node) ((struct RNode_OR *)(node))
-#define RNODE_MASGN(node) ((struct RNode_MASGN *)(node))
-#define RNODE_LASGN(node) ((struct RNode_LASGN *)(node))
-#define RNODE_DASGN(node) ((struct RNode_DASGN *)(node))
-#define RNODE_GASGN(node) ((struct RNode_GASGN *)(node))
-#define RNODE_IASGN(node) ((struct RNode_IASGN *)(node))
-#define RNODE_CDECL(node) ((struct RNode_CDECL *)(node))
-#define RNODE_CVASGN(node) ((struct RNode_CVASGN *)(node))
-#define RNODE_OP_ASGN1(node) ((struct RNode_OP_ASGN1 *)(node))
-#define RNODE_OP_ASGN2(node) ((struct RNode_OP_ASGN2 *)(node))
-#define RNODE_OP_ASGN_AND(node) ((struct RNode_OP_ASGN_AND *)(node))
-#define RNODE_OP_ASGN_OR(node) ((struct RNode_OP_ASGN_OR *)(node))
-#define RNODE_OP_CDECL(node) ((struct RNode_OP_CDECL *)(node))
-#define RNODE_CALL(node) ((struct RNode_CALL *)(node))
-#define RNODE_OPCALL(node) ((struct RNode_OPCALL *)(node))
-#define RNODE_FCALL(node) ((struct RNode_FCALL *)(node))
-#define RNODE_VCALL(node) ((struct RNode_VCALL *)(node))
-#define RNODE_QCALL(node) ((struct RNode_QCALL *)(node))
-#define RNODE_SUPER(node) ((struct RNode_SUPER *)(node))
-#define RNODE_ZSUPER(node) ((struct RNode_ZSUPER *)(node))
-#define RNODE_LIST(node) ((struct RNode_LIST *)(node))
-#define RNODE_ZLIST(node) ((struct RNode_ZLIST *)(node))
-#define RNODE_HASH(node) ((struct RNode_HASH *)(node))
-#define RNODE_RETURN(node) ((struct RNode_RETURN *)(node))
-#define RNODE_YIELD(node) ((struct RNode_YIELD *)(node))
-#define RNODE_LVAR(node) ((struct RNode_LVAR *)(node))
-#define RNODE_DVAR(node) ((struct RNode_DVAR *)(node))
-#define RNODE_GVAR(node) ((struct RNode_GVAR *)(node))
-#define RNODE_IVAR(node) ((struct RNode_IVAR *)(node))
-#define RNODE_CONST(node) ((struct RNode_CONST *)(node))
-#define RNODE_CVAR(node) ((struct RNode_CVAR *)(node))
-#define RNODE_NTH_REF(node) ((struct RNode_NTH_REF *)(node))
-#define RNODE_BACK_REF(node) ((struct RNode_BACK_REF *)(node))
-#define RNODE_MATCH(node) ((struct RNode_MATCH *)(node))
-#define RNODE_MATCH2(node) ((struct RNode_MATCH2 *)(node))
-#define RNODE_MATCH3(node) ((struct RNode_MATCH3 *)(node))
-#define RNODE_LIT(node) ((struct RNode_LIT *)(node))
-#define RNODE_STR(node) ((struct RNode_STR *)(node))
-#define RNODE_DSTR(node) ((struct RNode_DSTR *)(node))
-#define RNODE_XSTR(node) ((struct RNode_XSTR *)(node))
-#define RNODE_DXSTR(node) ((struct RNode_DXSTR *)(node))
-#define RNODE_EVSTR(node) ((struct RNode_EVSTR *)(node))
-#define RNODE_DREGX(node) ((struct RNode_DREGX *)(node))
-#define RNODE_ONCE(node) ((struct RNode_ONCE *)(node))
-#define RNODE_ARGS(node) ((struct RNode_ARGS *)(node))
-#define RNODE_ARGS_AUX(node) ((struct RNode_ARGS_AUX *)(node))
-#define RNODE_OPT_ARG(node) ((struct RNode_OPT_ARG *)(node))
-#define RNODE_KW_ARG(node) ((struct RNode_KW_ARG *)(node))
-#define RNODE_POSTARG(node) ((struct RNode_POSTARG *)(node))
-#define RNODE_ARGSCAT(node) ((struct RNode_ARGSCAT *)(node))
-#define RNODE_ARGSPUSH(node) ((struct RNode_ARGSPUSH *)(node))
-#define RNODE_SPLAT(node) ((struct RNode_SPLAT *)(node))
-#define RNODE_BLOCK_PASS(node) ((struct RNode_BLOCK_PASS *)(node))
-#define RNODE_DEFN(node) ((struct RNode_DEFN *)(node))
-#define RNODE_DEFS(node) ((struct RNode_DEFS *)(node))
-#define RNODE_ALIAS(node) ((struct RNode_ALIAS *)(node))
-#define RNODE_VALIAS(node) ((struct RNode_VALIAS *)(node))
-#define RNODE_UNDEF(node) ((struct RNode_UNDEF *)(node))
-#define RNODE_CLASS(node) ((struct RNode_CLASS *)(node))
-#define RNODE_MODULE(node) ((struct RNode_MODULE *)(node))
-#define RNODE_SCLASS(node) ((struct RNode_SCLASS *)(node))
-#define RNODE_COLON2(node) ((struct RNode_COLON2 *)(node))
-#define RNODE_COLON3(node) ((struct RNode_COLON3 *)(node))
-#define RNODE_DOT2(node) ((struct RNode_DOT2 *)(node))
-#define RNODE_DOT3(node) ((struct RNode_DOT3 *)(node))
-#define RNODE_FLIP2(node) ((struct RNode_FLIP2 *)(node))
-#define RNODE_FLIP3(node) ((struct RNode_FLIP3 *)(node))
-#define RNODE_SELF(node) ((struct RNode_SELF *)(node))
-#define RNODE_NIL(node) ((struct RNode_NIL *)(node))
-#define RNODE_TRUE(node) ((struct RNode_TRUE *)(node))
-#define RNODE_FALSE(node) ((struct RNode_FALSE *)(node))
-#define RNODE_ERRINFO(node) ((struct RNode_ERRINFO *)(node))
-#define RNODE_DEFINED(node) ((struct RNode_DEFINED *)(node))
-#define RNODE_POSTEXE(node) ((struct RNode_POSTEXE *)(node))
-#define RNODE_DSYM(node) ((struct RNode_DSYM *)(node))
-#define RNODE_ATTRASGN(node) ((struct RNode_ATTRASGN *)(node))
-#define RNODE_LAMBDA(node) ((struct RNode_LAMBDA *)(node))
-#define RNODE_ARYPTN(node) ((struct RNode_ARYPTN *)(node))
-#define RNODE_HSHPTN(node) ((struct RNode_HSHPTN *)(node))
-#define RNODE_FNDPTN(node) ((struct RNode_FNDPTN *)(node))
-
-#ifdef RIPPER
-typedef struct RNode_RIPPER {
- NODE node;
-
- ID nd_vid;
- VALUE nd_rval;
- VALUE nd_cval;
-} rb_node_ripper_t;
-
-typedef struct RNode_RIPPER_VALUES {
- NODE node;
-
- VALUE nd_val1;
- VALUE nd_val2;
- VALUE nd_val3;
-} rb_node_ripper_values_t;
-
-#define RNODE_RIPPER(node) ((struct RNode_RIPPER *)(node))
-#define RNODE_RIPPER_VALUES(node) ((struct RNode_RIPPER_VALUES *)(node))
-#endif
-
-/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8: UNUSED, 9: UNUSED, 10: EXIVAR, 11: FREEZE */
-/* NODE_FL: 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: NODE_FL_NEWLINE,
- * 8..14: nd_type,
- * 15..: nd_line
- */
-#define NODE_FL_NEWLINE (((VALUE)1)<<7)
-
-#define NODE_TYPESHIFT 8
-#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT)
-
-#define nd_fl_newline(n) (n)->flags & NODE_FL_NEWLINE
-#define nd_set_fl_newline(n) (n)->flags |= NODE_FL_NEWLINE
-#define nd_unset_fl_newline(n) (n)->flags &= ~NODE_FL_NEWLINE
-
-#define nd_type(n) ((int) ((RNODE(n)->flags & NODE_TYPEMASK)>>NODE_TYPESHIFT))
-#define nd_set_type(n,t) \
- rb_node_set_type(n, t)
-#define nd_init_type(n,t) \
- (n)->flags=(((n)->flags&~NODE_TYPEMASK)|((((unsigned long)(t))<<NODE_TYPESHIFT)&NODE_TYPEMASK))
-
-typedef struct node_buffer_struct node_buffer_t;
-/* T_IMEMO/ast */
-typedef struct rb_ast_body_struct {
- const NODE *root;
- VALUE script_lines;
- // script_lines is either:
- // - a Fixnum that represents the line count of the original source, or
- // - an Array that contains the lines of the original source
- signed int frozen_string_literal:2; /* -1: not specified, 0: false, 1: true */
- signed int coverage_enabled:2; /* -1: not specified, 0: false, 1: true */
-} rb_ast_body_t;
-typedef struct rb_ast_struct {
- VALUE flags;
- node_buffer_t *node_buffer;
- rb_ast_body_t body;
-} rb_ast_t;
-
-
-
-/*
- * Parser Interface
- */
-
-
-typedef struct parser_params rb_parser_t;
-#ifndef INTERNAL_IMEMO_H
-typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
-#endif
-
-#ifdef UNIVERSAL_PARSER
-typedef struct rb_parser_config_struct {
- /*
- * Reference counter.
- * This is needed because both parser and ast refer
- * same config pointer.
- * We can remove this, once decuple parser and ast from Ruby GC.
- */
- int counter;
-
- /* Memory */
- void *(*malloc)(size_t size);
- void *(*calloc)(size_t number, size_t size);
- void *(*realloc)(void *ptr, size_t newsiz);
- void (*free)(void *ptr);
- void *(*alloc_n)(size_t nelems, size_t elemsiz);
- void *(*alloc)(size_t elemsiz);
- void *(*realloc_n)(void *ptr, size_t newelems, size_t newsiz);
- void *(*zalloc)(size_t elemsiz);
- void *(*rb_memmove)(void *dest, const void *src, size_t t, size_t n);
- void *(*nonempty_memcpy)(void *dest, const void *src, size_t t, size_t n);
- void *(*xmalloc_mul_add)(size_t x, size_t y, size_t z);
-
- /* imemo */
- rb_imemo_tmpbuf_t *(*tmpbuf_parser_heap)(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt);
- rb_ast_t *(*ast_new)(VALUE nb);
-
- // VALUE rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg);
- VALUE (*compile_callback)(VALUE (*func)(VALUE), VALUE arg);
- NODE *(*reg_named_capture_assign)(struct parser_params* p, VALUE regexp, const rb_code_location_t *loc);
-
- /* Object */
- VALUE (*obj_freeze)(VALUE obj);
- VALUE (*obj_hide)(VALUE obj);
- int (*obj_frozen)(VALUE obj);
- int (*type_p)(VALUE, int);
- void (*obj_freeze_raw)(VALUE obj);
-
- int (*fixnum_p)(VALUE);
- int (*symbol_p)(VALUE);
-
- /* Variable */
- VALUE (*attr_get)(VALUE obj, ID id);
-
- /* Array */
- VALUE (*ary_new)(void);
- VALUE (*ary_push)(VALUE ary, VALUE elem);
- VALUE (*ary_new_from_args)(long n, ...);
- VALUE (*ary_pop)(VALUE ary);
- VALUE (*ary_last)(int argc, const VALUE *argv, VALUE ary);
- VALUE (*ary_unshift)(VALUE ary, VALUE item);
- VALUE (*ary_new2)(long capa); // ary_new_capa
- VALUE (*ary_entry)(VALUE ary, long offset);
- VALUE (*ary_join)(VALUE ary, VALUE sep);
- VALUE (*ary_reverse)(VALUE ary);
- VALUE (*ary_clear)(VALUE ary);
- long (*array_len)(VALUE a);
- VALUE (*array_aref)(VALUE, long);
-
- /* Symbol */
- VALUE (*sym_intern_ascii_cstr)(const char *ptr);
- ID (*make_temporary_id)(size_t n);
- int (*is_local_id)(ID);
- int (*is_attrset_id)(ID);
- int (*is_global_name_punct)(const int c);
- int (*id_type)(ID id);
- ID (*id_attrset)(ID);
- ID (*intern)(const char *name);
- ID (*intern2)(const char *name, long len);
- ID (*intern3)(const char *name, long len, rb_encoding *enc);
- ID (*intern_str)(VALUE str);
- int (*is_notop_id)(ID);
- int (*enc_symname_type)(const char *name, long len, rb_encoding *enc, unsigned int allowed_attrset);
- VALUE (*str_intern)(VALUE str);
- const char *(*id2name)(ID id);
- VALUE (*id2str)(ID id);
- VALUE (*id2sym)(ID x);
- ID (*sym2id)(VALUE sym);
-
- /* String */
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
- VALUE (*str_catf)(VALUE str, const char *format, ...);
- VALUE (*str_cat_cstr)(VALUE str, const char *ptr);
- VALUE (*str_subseq)(VALUE str, long beg, long len);
- VALUE (*str_dup)(VALUE str);
- VALUE (*str_new_frozen)(VALUE orig);
- VALUE (*str_buf_new)(long capa);
- VALUE (*str_buf_cat)(VALUE, const char*, long);
- void (*str_modify)(VALUE str);
- void (*str_set_len)(VALUE str, long len);
- VALUE (*str_cat)(VALUE str, const char *ptr, long len);
- VALUE (*str_resize)(VALUE str, long len);
- VALUE (*str_new)(const char *ptr, long len);
- VALUE (*str_new_cstr)(const char *ptr);
- VALUE (*fstring)(VALUE);
- int (*is_ascii_string)(VALUE str);
- VALUE (*enc_str_new)(const char *ptr, long len, rb_encoding *enc);
- VALUE (*enc_str_buf_cat)(VALUE str, const char *ptr, long len, rb_encoding *enc);
- VALUE (*str_buf_append)(VALUE str, VALUE str2);
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 0)
- VALUE (*str_vcatf)(VALUE str, const char *fmt, va_list ap);
- char *(*string_value_cstr)(volatile VALUE *ptr);
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
- VALUE (*rb_sprintf)(const char *format, ...);
- char *(*rstring_ptr)(VALUE str);
- char *(*rstring_end)(VALUE str);
- long (*rstring_len)(VALUE str);
- VALUE (*filesystem_str_new_cstr)(const char *ptr);
- VALUE (*obj_as_string)(VALUE);
-
- /* Hash */
- VALUE (*hash_clear)(VALUE hash);
- VALUE (*hash_new)(void);
- VALUE (*hash_aset)(VALUE hash, VALUE key, VALUE val);
- VALUE (*hash_delete)(VALUE hash, VALUE key);
- VALUE (*hash_lookup)(VALUE hash, VALUE key);
- VALUE (*ident_hash_new)(void);
-
- /* Fixnum */
- VALUE (*int2fix)(long i);
-
- /* Bignum */
- void (*bignum_negate)(VALUE b);
- VALUE (*big_norm)(VALUE x);
- VALUE (*cstr_to_inum)(const char *str, int base, int badcheck);
-
- /* Float */
- VALUE (*float_new)(double d);
- double (*float_value)(VALUE v);
-
- /* Numeric */
- int (*num2int)(VALUE val);
- VALUE (*int_positive_pow)(long x, unsigned long y);
- VALUE (*int2num)(int v);
- long (*fix2long)(VALUE val);
-
- /* Rational */
- VALUE (*rational_new)(VALUE x, VALUE y);
- VALUE (*rational_raw1)(VALUE x);
- void (*rational_set_num)(VALUE r, VALUE n);
- VALUE (*rational_get_num)(VALUE obj);
-
- /* Complex */
- VALUE (*complex_raw)(VALUE x, VALUE y);
- void (*rcomplex_set_real)(VALUE cmp, VALUE r);
- void (*rcomplex_set_imag)(VALUE cmp, VALUE i);
- VALUE (*rcomplex_get_real)(VALUE obj);
- VALUE (*rcomplex_get_imag)(VALUE obj);
-
- /* IO */
- int (*stderr_tty_p)(void);
- void (*write_error_str)(VALUE mesg);
- VALUE (*default_rs)(void);
- VALUE (*io_write)(VALUE io, VALUE str);
- VALUE (*io_flush)(VALUE io);
- VALUE (*io_puts)(int argc, const VALUE *argv, VALUE out);
- VALUE (*io_gets_internal)(VALUE io);
-
- /* IO (Ractor) */
- VALUE (*debug_output_stdout)(void);
- VALUE (*debug_output_stderr)(void);
-
- /* Encoding */
- int (*is_usascii_enc)(rb_encoding *enc);
- int (*enc_isalnum)(OnigCodePoint c, rb_encoding *enc);
- int (*enc_precise_mbclen)(const char *p, const char *e, rb_encoding *enc);
- int (*mbclen_charfound_p)(int len);
- const char *(*enc_name)(rb_encoding *enc);
- char *(*enc_prev_char)(const char *s, const char *p, const char *e, rb_encoding *enc);
- rb_encoding* (*enc_get)(VALUE obj);
- int (*enc_asciicompat)(rb_encoding *enc);
- rb_encoding *(*utf8_encoding)(void);
- VALUE (*enc_associate)(VALUE obj, rb_encoding *enc);
- rb_encoding *(*ascii8bit_encoding)(void);
- int (*enc_codelen)(int c, rb_encoding *enc);
- int (*enc_mbcput)(unsigned int c, void *buf, rb_encoding *enc);
- int (*char_to_option_kcode)(int c, int *option, int *kcode);
- int (*ascii8bit_encindex)(void);
- int (*enc_find_index)(const char *name);
- rb_encoding *(*enc_from_index)(int idx);
- VALUE (*enc_associate_index)(VALUE obj, int encindex);
- int (*enc_isspace)(OnigCodePoint c, rb_encoding *enc);
- int enc_coderange_7bit;
- int enc_coderange_unknown;
- rb_encoding *(*enc_compatible)(VALUE str1, VALUE str2);
- VALUE (*enc_from_encoding)(rb_encoding *enc);
- int (*encoding_get)(VALUE obj);
- void (*encoding_set)(VALUE obj, int encindex);
- int (*encoding_is_ascii8bit)(VALUE obj);
- rb_encoding *(*usascii_encoding)(void);
-
- /* Ractor */
- VALUE (*ractor_make_shareable)(VALUE obj);
-
- /* Compile */
- // int rb_local_defined(ID id, const rb_iseq_t *iseq);
- int (*local_defined)(ID, const void*);
- // int rb_dvar_defined(ID id, const rb_iseq_t *iseq);
- int (*dvar_defined)(ID, const void*);
-
- /* Compile (parse.y) */
- int (*literal_cmp)(VALUE val, VALUE lit);
- parser_st_index_t (*literal_hash)(VALUE a);
-
- /* Error (Exception) */
- const char *(*builtin_class_name)(VALUE x);
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
- VALUE (*syntax_error_append)(VALUE, VALUE, int, int, rb_encoding*, const char*, va_list);
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
- void (*raise)(VALUE exc, const char *fmt, ...);
- VALUE (*syntax_error_new)(void);
-
- /* Eval */
- VALUE (*errinfo)(void);
- void (*set_errinfo)(VALUE err);
- void (*exc_raise)(VALUE mesg);
- VALUE (*make_exception)(int argc, const VALUE *argv);
-
- /* GC */
- void (*sized_xfree)(void *x, size_t size);
- void *(*sized_realloc_n)(void *ptr, size_t new_count, size_t element_size, size_t old_count);
- VALUE (*obj_write)(VALUE, VALUE *, VALUE);
- VALUE (*obj_written)(VALUE, VALUE, VALUE);
- void (*gc_register_mark_object)(VALUE object);
- void (*gc_guard)(VALUE);
- void (*gc_mark)(VALUE);
- void (*gc_mark_movable)(VALUE ptr);
- VALUE (*gc_location)(VALUE value);
-
- /* Re */
- VALUE (*reg_compile)(VALUE str, int options, const char *sourcefile, int sourceline);
- VALUE (*reg_check_preprocess)(VALUE str);
- int (*memcicmp)(const void *x, const void *y, long len);
-
- /* Error */
- void (*compile_warn)(const char *file, int line, const char *fmt, ...);
- void (*compile_warning)(const char *file, int line, const char *fmt, ...);
- void (*bug)(const char *fmt, ...);
- void (*fatal)(const char *fmt, ...);
- VALUE (*verbose)(void);
-
- /* VM */
- VALUE (*make_backtrace)(void);
-
- /* Util */
- unsigned long (*scan_hex)(const char *start, size_t len, size_t *retlen);
- unsigned long (*scan_oct)(const char *start, size_t len, size_t *retlen);
- unsigned long (*scan_digits)(const char *str, ssize_t len, int base, size_t *retlen, int *overflow);
- double (*strtod)(const char *s00, char **se);
-
- /* Misc */
- VALUE (*rbool)(VALUE);
- int (*undef_p)(VALUE);
- int (*rtest)(VALUE obj);
- int (*nil_p)(VALUE obj);
- int (*flonum_p)(VALUE obj);
- VALUE qnil;
- VALUE qtrue;
- VALUE qfalse;
- VALUE qundef;
- VALUE eArgError;
- VALUE mRubyVMFrozenCore;
- int (*long2int)(long);
- int (*special_const_p)(VALUE);
- int (*builtin_type)(VALUE);
-
- VALUE (*node_case_when_optimizable_literal)(const NODE *const node);
-
- /* For Ripper */
- VALUE (*static_id2sym)(ID id);
- long (*str_coderange_scan_restartable)(const char *s, const char *e, rb_encoding *enc, int *cr);
-} rb_parser_config_t;
-
-#undef rb_encoding
-#undef OnigCodePoint
-#endif /* UNIVERSAL_PARSER */
-
-RUBY_SYMBOL_EXPORT_BEGIN
-void rb_ruby_parser_free(void *ptr);
-rb_ast_t* rb_ruby_parser_compile_string(rb_parser_t *p, const char *f, VALUE s, int line);
-
-#ifdef UNIVERSAL_PARSER
-rb_parser_config_t *rb_ruby_parser_config_new(void *(*malloc)(size_t size));
-void rb_ruby_parser_config_free(rb_parser_config_t *config);
-rb_parser_t *rb_ruby_parser_allocate(rb_parser_config_t *config);
-rb_parser_t *rb_ruby_parser_new(rb_parser_config_t *config);
-#endif
-RUBY_SYMBOL_EXPORT_END
-
-#endif /* RUBY_RUBYPARSER_H */
diff --git a/sample/all-ruby-quine.rb b/sample/all-ruby-quine.rb
deleted file mode 100644
index 7686121468..0000000000
--- a/sample/all-ruby-quine.rb
+++ /dev/null
@@ -1,24 +0,0 @@
- eval($s=("t='eval($s=('+d=34.chr;s=3
- 2.chr+$s*i=8;v=$VERSION||eval('begin;v=V
- ERSION;rescue;v||RUBY_VERSION;end');f=('?'*8
- +'A|'+'?'*20+'G?c'+'?'*15+'A@CXx@~@_`OpGxCxp@~pO
- xS|O~G?c?q?xC`AP|q?x_|C_xC_xO@H@cG?G?qA|_|_`GCpOxC|H
-NFccqq@`_|OF@`?q?x_@x_x_`GB`O``O~G?C@qCxCxP@D@|G~C?pO|C?
- pO|C?AP|A~HNN`ccxC|Q@L@B"+"GpGpc@p?x_`GB`???_@FO|OB@
- xC|P`@?c?q?HPx@~@_`G@`????@L^`?q?x?xq@|_|O~GC`
- xA~@_@GBD').unpack('c*');w=4+v.length*u=
- 15;r=10.chr;j=0;while-24+w*u>i=1+i
- ;x=i%w;x>0||t=t+d+'+'+r+d;k=
- i/w%12>2&&x%u>3&&x%u+i
- /w*11-34+('-._'.
- index(c=v[
- x/u,1]
- )||c.hex +3)*99|
- |0; k=f [k/6 ][k%
- 6]; t=t +s[
- k*j =k+ j,1
- ]end;pr int (t+
- d+' ).s pli
- t.j oin [0,
- 609 ])# Y.E. '+r)
- ").split .join)#
diff --git a/sample/dir.rb b/sample/dir.rb
index 81257cd917..0c55078973 100644
--- a/sample/dir.rb
+++ b/sample/dir.rb
@@ -1,7 +1,12 @@
# directory access
# list all files but .*/*~/*.o
-Dir.foreach(".") do |file|
- unless file.start_with?('.') or file.end_with?('~', '.o')
- puts file
+dirp = Dir.open(".")
+for f in dirp
+ case f
+ when /\A\./, /~\z/, /\.o\z/
+ # do not print
+ else
+ print f, "\n"
end
end
+dirp.close
diff --git a/scheduler.c b/scheduler.c
index 022e8401e0..4be18e1799 100644
--- a/scheduler.c
+++ b/scheduler.c
@@ -161,6 +161,21 @@ verify_interface(VALUE scheduler)
}
}
+static VALUE
+fiber_scheduler_close(VALUE scheduler)
+{
+ return rb_fiber_scheduler_close(scheduler);
+}
+
+static VALUE
+fiber_scheduler_close_ensure(VALUE _thread)
+{
+ rb_thread_t *thread = (rb_thread_t*)_thread;
+ thread->scheduler = Qnil;
+
+ return Qnil;
+}
+
VALUE
rb_fiber_scheduler_set(VALUE scheduler)
{
@@ -178,7 +193,8 @@ rb_fiber_scheduler_set(VALUE scheduler)
// That way, we do not need to consider interactions, e.g., of a Fiber from
// the previous scheduler with the new scheduler.
if (thread->scheduler != Qnil) {
- rb_fiber_scheduler_close(thread->scheduler);
+ // rb_fiber_scheduler_close(thread->scheduler);
+ rb_ensure(fiber_scheduler_close, thread->scheduler, fiber_scheduler_close_ensure, (VALUE)thread);
}
thread->scheduler = scheduler;
@@ -387,7 +403,15 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
{
VM_ASSERT(rb_obj_is_fiber(fiber));
- return rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
+ // `rb_fiber_scheduler_unblock` can be called from points where `errno` is expected to be preserved. Therefore, we should save and restore it. For example `io_binwrite` calls `rb_fiber_scheduler_unblock` and if `errno` is reset to 0 by user code, it will break the error handling in `io_write`.
+ // If we explicitly preserve `errno` in `io_binwrite` and other similar functions (e.g. by returning it), this code is no longer needed. I hope in the future we will be able to remove it.
+ int saved_errno = errno;
+
+ VALUE result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
+
+ errno = saved_errno;
+
+ return result;
}
/*
@@ -458,15 +482,15 @@ VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
/*
* Document-method: Fiber::Scheduler#io_read
- * call-seq: io_read(io, buffer, length, offset) -> read length or -errno
+ * call-seq: io_read(io, buffer, minimum_length) -> read length or -errno
*
* Invoked by IO#read or IO#Buffer.read to read +length+ bytes from +io+ into a
- * specified +buffer+ (see IO::Buffer) at the given +offset+.
+ * specified +buffer+ (see IO::Buffer).
*
- * The +length+ argument is the "minimum length to be read". If the IO buffer
- * size is 8KiB, but the +length+ is +1024+ (1KiB), up to 8KiB might be read,
- * but at least 1KiB will be. Generally, the only case where less data than
- * +length+ will be read is if there is an error reading the data.
+ * The +minimum_length+ argument is the "minimum length to be read". If the IO
+ * buffer size is 8KiB, but the +length+ is +1024+ (1KiB), up to 8KiB might be
+ * read, but at least 1KiB will be. Generally, the only case where less data
+ * than +length+ will be read is if there is an error reading the data.
*
* Specifying a +length+ of 0 is valid and means try reading at least once and
* return any available data.
@@ -492,19 +516,13 @@ rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t lengt
return rb_check_funcall(scheduler, id_io_read, 4, arguments);
}
+
/*
* Document-method: Fiber::Scheduler#io_read
* call-seq: io_pread(io, buffer, from, length, offset) -> read length or -errno
*
- * Invoked by IO#pread or IO::Buffer#pread to read +length+ bytes from +io+
- * at offset +from+ into a specified +buffer+ (see IO::Buffer) at the given
- * +offset+.
+ * Invoked by IO::Buffer#pread. See that method for description of arguments.
*
- * This method is semantically the same as #io_read, but it allows to specify
- * the offset to read from and is often better for asynchronous IO on the same
- * file.
- *
- * The method should be considered _experimental_.
*/
VALUE
rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
@@ -518,16 +536,16 @@ rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buff
/*
* Document-method: Scheduler#io_write
- * call-seq: io_write(io, buffer, length, offset) -> written length or -errno
+ * call-seq: io_write(io, buffer, minimum_length) -> written length or -errno
*
* Invoked by IO#write or IO::Buffer#write to write +length+ bytes to +io+ from
- * from a specified +buffer+ (see IO::Buffer) at the given +offset+.
+ * from a specified +buffer+ (see IO::Buffer).
*
- * The +length+ argument is the "minimum length to be written". If the IO
- * buffer size is 8KiB, but the +length+ specified is 1024 (1KiB), at most 8KiB
- * will be written, but at least 1KiB will be. Generally, the only case where
- * less data than +length+ will be written is if there is an error writing the
- * data.
+ * The +minimum_length+ argument is the "minimum length to be written". If the
+ * IO buffer size is 8KiB, but the +length+ specified is 1024 (1KiB), at most
+ * 8KiB will be written, but at least 1KiB will be. Generally, the only case
+ * where less data than +minimum_length+ will be written is if there is an
+ * error writing the data.
*
* Specifying a +length+ of 0 is valid and means try writing at least once, as
* much data as possible.
@@ -558,15 +576,7 @@ rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t leng
* Document-method: Fiber::Scheduler#io_pwrite
* call-seq: io_pwrite(io, buffer, from, length, offset) -> written length or -errno
*
- * Invoked by IO#pwrite or IO::Buffer#pwrite to write +length+ bytes to +io+
- * at offset +from+ into a specified +buffer+ (see IO::Buffer) at the given
- * +offset+.
- *
- * This method is semantically the same as #io_write, but it allows to specify
- * the offset to write to and is often better for asynchronous IO on the same
- * file.
- *
- * The method should be considered _experimental_.
+ * Invoked by IO::Buffer#pwrite. See that method for description of arguments.
*
*/
VALUE
@@ -586,7 +596,8 @@ rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t
VALUE result = rb_fiber_scheduler_io_read(scheduler, io, buffer, length, 0);
- rb_io_buffer_free_locked(buffer);
+ rb_io_buffer_unlock(buffer);
+ rb_io_buffer_free(buffer);
return result;
}
@@ -598,31 +609,8 @@ rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base,
VALUE result = rb_fiber_scheduler_io_write(scheduler, io, buffer, length, 0);
- rb_io_buffer_free_locked(buffer);
-
- return result;
-}
-
-VALUE
-rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
-{
- VALUE buffer = rb_io_buffer_new(base, size, RB_IO_BUFFER_LOCKED);
-
- VALUE result = rb_fiber_scheduler_io_pread(scheduler, io, from, buffer, length, 0);
-
- rb_io_buffer_free_locked(buffer);
-
- return result;
-}
-
-VALUE
-rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
-{
- VALUE buffer = rb_io_buffer_new((void*)base, size, RB_IO_BUFFER_LOCKED|RB_IO_BUFFER_READONLY);
-
- VALUE result = rb_fiber_scheduler_io_pwrite(scheduler, io, from, buffer, length, 0);
-
- rb_io_buffer_free_locked(buffer);
+ rb_io_buffer_unlock(buffer);
+ rb_io_buffer_free(buffer);
return result;
}
diff --git a/shape.c b/shape.c
index ef08030ad4..1dc08dcb60 100644
--- a/shape.c
+++ b/shape.c
@@ -1,312 +1,72 @@
#include "vm_core.h"
#include "vm_sync.h"
#include "shape.h"
+#include "gc.h"
#include "symbol.h"
#include "id_table.h"
#include "internal/class.h"
-#include "internal/gc.h"
#include "internal/symbol.h"
#include "internal/variable.h"
-#include "internal/error.h"
#include "variable.h"
#include <stdbool.h>
-#ifndef _WIN32
-#include <sys/mman.h>
-#endif
-
#ifndef SHAPE_DEBUG
#define SHAPE_DEBUG (VM_CHECK_MODE > 0)
#endif
-#if SIZEOF_SHAPE_T == 4
-#if RUBY_DEBUG
-#define SHAPE_BUFFER_SIZE 0x8000
-#else
-#define SHAPE_BUFFER_SIZE 0x80000
-#endif
-#else
-#define SHAPE_BUFFER_SIZE 0x8000
-#endif
-
-#define REDBLACK_CACHE_SIZE (SHAPE_BUFFER_SIZE * 32)
-
-#define SINGLE_CHILD_TAG 0x1
-#define TAG_SINGLE_CHILD(x) (struct rb_id_table *)((uintptr_t)x | SINGLE_CHILD_TAG)
-#define SINGLE_CHILD_MASK (~((uintptr_t)SINGLE_CHILD_TAG))
-#define SINGLE_CHILD_P(x) (((uintptr_t)x) & SINGLE_CHILD_TAG)
-#define SINGLE_CHILD(x) (rb_shape_t *)((uintptr_t)x & SINGLE_CHILD_MASK)
-#define ANCESTOR_CACHE_THRESHOLD 10
-#define MAX_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
-#define ANCESTOR_SEARCH_MAX_DEPTH 2
-
static ID id_frozen;
static ID id_t_object;
static ID size_pool_edge_names[SIZE_POOL_COUNT];
-rb_shape_t * rb_shape_transition_shape_capa(rb_shape_t * shape);
-
-#define LEAF 0
-#define BLACK 0x0
-#define RED 0x1
-
-static redblack_node_t *
-redblack_left(redblack_node_t * node)
-{
- if (node->l == LEAF) {
- return LEAF;
- }
- else {
- RUBY_ASSERT(node->l < GET_SHAPE_TREE()->cache_size);
- redblack_node_t * left = &GET_SHAPE_TREE()->shape_cache[node->l - 1];
- return left;
- }
-}
-
-static redblack_node_t *
-redblack_right(redblack_node_t * node)
-{
- if (node->r == LEAF) {
- return LEAF;
- }
- else {
- RUBY_ASSERT(node->r < GET_SHAPE_TREE()->cache_size);
- redblack_node_t * right = &GET_SHAPE_TREE()->shape_cache[node->r - 1];
- return right;
- }
-}
-
-static redblack_node_t *
-redblack_find(redblack_node_t * tree, ID key)
-{
- if (tree == LEAF) {
- return LEAF;
- }
- else {
- if (tree->key == key) {
- return tree;
- }
- else {
- if (key < tree->key) {
- return redblack_find(redblack_left(tree), key);
- }
- else {
- return redblack_find(redblack_right(tree), key);
- }
- }
- }
-}
-
-static inline char
-redblack_color(redblack_node_t * node)
-{
- return node && ((uintptr_t)node->value & RED);
-}
-
-static inline bool
-redblack_red_p(redblack_node_t * node)
-{
- return redblack_color(node) == RED;
-}
-
-static inline rb_shape_t *
-redblack_value(redblack_node_t * node)
-{
- // Color is stored in the bottom bit of the shape pointer
- // Mask away the bit so we get the actual pointer back
- return (rb_shape_t *)((uintptr_t)node->value & (((uintptr_t)-1) - 1));
-}
-
-static redblack_id_t
-redblack_id_for(redblack_node_t * node)
-{
- RUBY_ASSERT(node || node == LEAF);
- if (node == LEAF) {
- return 0;
- }
- else {
- redblack_node_t * redblack_nodes = GET_SHAPE_TREE()->shape_cache;
- redblack_id_t id = (redblack_id_t)(node - redblack_nodes);
- return id + 1;
- }
-}
-
-static redblack_node_t *
-redblack_new(char color, ID key, rb_shape_t * value, redblack_node_t * left, redblack_node_t * right)
-{
- if (GET_SHAPE_TREE()->cache_size + 1 >= REDBLACK_CACHE_SIZE) {
- // We're out of cache, just quit
- return LEAF;
- }
- redblack_node_t * redblack_nodes = GET_SHAPE_TREE()->shape_cache;
- redblack_node_t * node = &redblack_nodes[(GET_SHAPE_TREE()->cache_size)++];
- node->key = key;
- node->value = (rb_shape_t *)((uintptr_t)value | color);
- node->l = redblack_id_for(left);
- node->r = redblack_id_for(right);
- return node;
-}
-
-static redblack_node_t *
-redblack_balance(char color, ID key, rb_shape_t * value, redblack_node_t * left, redblack_node_t * right)
-{
- if (color == BLACK) {
- ID z, y, x;
- rb_shape_t * z_, * y_, * x_;
- redblack_node_t * a, * b, * c, * d;
-
- if (redblack_red_p(left) && redblack_red_p(redblack_left(left))) {
- z = key;
- z_ = value;
- d = right;
-
- y = left->key;
- y_ = redblack_value(left);
- c = redblack_right(left);
-
- x = redblack_left(left)->key;
- x_ = redblack_value(redblack_left(left));
-
- a = redblack_left(redblack_left(left));
- b = redblack_right(redblack_left(left));
- }
- else if (redblack_red_p(left) && redblack_red_p(redblack_right(left))) {
- z = key;
- z_ = value;
- d = right;
-
- x = left->key;
- x_ = redblack_value(left);
- a = redblack_left(left);
-
- y = redblack_right(left)->key;
- y_ = redblack_value(redblack_right(left));
- b = redblack_left(redblack_right(left));
- c = redblack_right(redblack_right(left));
- }
- else if (redblack_red_p(right) && redblack_red_p(redblack_left(right))) {
- x = key;
- x_ = value;
- a = left;
-
- z = right->key;
- z_ = redblack_value(right);
- d = redblack_right(right);
-
- y = redblack_left(right)->key;
- y_ = redblack_value(redblack_left(right));
- b = redblack_left(redblack_left(right));
- c = redblack_right(redblack_left(right));
- }
- else if (redblack_red_p(right) && redblack_red_p(redblack_right(right))) {
- x = key;
- x_ = value;
- a = left;
-
- y = right->key;
- y_ = redblack_value(right);
- b = redblack_left(right);
-
- z = redblack_right(right)->key;
- z_ = redblack_value(redblack_right(right));
- c = redblack_left(redblack_right(right));
- d = redblack_right(redblack_right(right));
- }
- else {
- return redblack_new(color, key, value, left, right);
- }
- return redblack_new(
- RED, y, y_,
- redblack_new(BLACK, x, x_, a, b),
- redblack_new(BLACK, z, z_, c, d));
- }
-
- return redblack_new(color, key, value, left, right);
-}
-
-static redblack_node_t *
-redblack_insert_aux(redblack_node_t * tree, ID key, rb_shape_t * value)
-{
- if (tree == LEAF) {
- return redblack_new(RED, key, value, LEAF, LEAF);
- }
- else {
- if (key < tree->key) {
- return redblack_balance(redblack_color(tree),
- tree->key,
- redblack_value(tree),
- redblack_insert_aux(redblack_left(tree), key, value),
- redblack_right(tree));
- }
- else {
- if (key > tree->key) {
- return redblack_balance(redblack_color(tree),
- tree->key,
- redblack_value(tree),
- redblack_left(tree),
- redblack_insert_aux(redblack_right(tree), key, value));
- }
- else {
- return tree;
- }
- }
- }
-}
-
-static redblack_node_t *
-redblack_force_black(redblack_node_t * node)
-{
- node->value = redblack_value(node);
- return node;
-}
-
-static redblack_node_t *
-redblack_insert(redblack_node_t * tree, ID key, rb_shape_t * value)
-{
- redblack_node_t * root = redblack_insert_aux(tree, key, value);
-
- if (redblack_red_p(root)) {
- return redblack_force_black(root);
- }
- else {
- return root;
- }
-}
-
-rb_shape_tree_t *rb_shape_tree_ptr = NULL;
-
/*
* Shape getters
*/
rb_shape_t *
rb_shape_get_root_shape(void)
{
- return GET_SHAPE_TREE()->root_shape;
+ return GET_VM()->root_shape;
}
shape_id_t
rb_shape_id(rb_shape_t * shape)
{
- return (shape_id_t)(shape - GET_SHAPE_TREE()->shape_list);
+ return (shape_id_t)(shape - GET_VM()->shape_list);
+}
+
+bool
+rb_shape_root_shape_p(rb_shape_t* shape)
+{
+ return shape == rb_shape_get_root_shape();
}
void
rb_shape_each_shape(each_shape_callback callback, void *data)
{
rb_shape_t *cursor = rb_shape_get_root_shape();
- rb_shape_t *end = rb_shape_get_shape_by_id(GET_SHAPE_TREE()->next_shape_id);
+ rb_shape_t *end = rb_shape_get_shape_by_id(GET_VM()->next_shape_id);
while (cursor < end) {
callback(cursor, data);
cursor += 1;
}
}
-RUBY_FUNC_EXPORTED rb_shape_t*
+rb_shape_t*
rb_shape_get_shape_by_id(shape_id_t shape_id)
{
RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
- rb_shape_t *shape = &GET_SHAPE_TREE()->shape_list[shape_id];
+ rb_vm_t *vm = GET_VM();
+ rb_shape_t *shape = &vm->shape_list[shape_id];
+ return shape;
+}
+
+rb_shape_t*
+rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id)
+{
+ RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
+
+ rb_vm_t *vm = GET_VM();
+ rb_shape_t *shape = &vm->shape_list[shape_id];
return shape;
}
@@ -317,10 +77,17 @@ rb_shape_get_parent(rb_shape_t * shape)
}
#if !SHAPE_IN_BASIC_FLAGS
+shape_id_t
+rb_rclass_shape_id(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
+ return RCLASS_EXT(obj)->shape_id;
+}
+
shape_id_t rb_generic_shape_id(VALUE obj);
#endif
-RUBY_FUNC_EXPORTED shape_id_t
+shape_id_t
rb_shape_get_shape_id(VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) {
@@ -362,99 +129,8 @@ rb_shape_get_shape(VALUE obj)
return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj));
}
-static rb_shape_t *
-shape_alloc(void)
-{
- shape_id_t shape_id = GET_SHAPE_TREE()->next_shape_id;
- GET_SHAPE_TREE()->next_shape_id++;
-
- if (shape_id == (MAX_SHAPE_ID + 1)) {
- // TODO: Make an OutOfShapesError ??
- rb_bug("Out of shapes");
- }
-
- return &GET_SHAPE_TREE()->shape_list[shape_id];
-}
-
-static rb_shape_t *
-rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
-{
- rb_shape_t * shape = shape_alloc();
-
- shape->edge_name = edge_name;
- shape->next_iv_index = 0;
- shape->parent_id = parent_id;
- shape->edges = NULL;
-
- return shape;
-}
-
-static rb_shape_t *
-rb_shape_alloc(ID edge_name, rb_shape_t * parent, enum shape_type type)
-{
- rb_shape_t * shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent));
- shape->type = (uint8_t)type;
- shape->size_pool_index = parent->size_pool_index;
- shape->capacity = parent->capacity;
- shape->edges = 0;
- return shape;
-}
-
-#ifdef HAVE_MMAP
-static redblack_node_t *
-redblack_cache_ancestors(rb_shape_t * shape)
-{
- if (!(shape->ancestor_index || shape->parent_id == INVALID_SHAPE_ID)) {
- redblack_node_t * parent_index;
-
- parent_index = redblack_cache_ancestors(rb_shape_get_parent(shape));
-
- if (shape->type == SHAPE_IVAR) {
- shape->ancestor_index = redblack_insert(parent_index, shape->edge_name, shape);
- }
- else {
- shape->ancestor_index = parent_index;
- }
- }
-
- return shape->ancestor_index;
-}
-#else
-static redblack_node_t *
-redblack_cache_ancestors(rb_shape_t * shape)
-{
- return LEAF;
-}
-#endif
-
-static rb_shape_t *
-rb_shape_alloc_new_child(ID id, rb_shape_t * shape, enum shape_type shape_type)
-{
- rb_shape_t * new_shape = rb_shape_alloc(id, shape, shape_type);
-
- switch (shape_type) {
- case SHAPE_IVAR:
- new_shape->next_iv_index = shape->next_iv_index + 1;
- if (new_shape->next_iv_index > ANCESTOR_CACHE_THRESHOLD) {
- redblack_cache_ancestors(new_shape);
- }
- break;
- case SHAPE_CAPACITY_CHANGE:
- case SHAPE_FROZEN:
- case SHAPE_T_OBJECT:
- new_shape->next_iv_index = shape->next_iv_index;
- break;
- case SHAPE_OBJ_TOO_COMPLEX:
- case SHAPE_ROOT:
- rb_bug("Unreachable");
- break;
- }
-
- return new_shape;
-}
-
static rb_shape_t*
-get_next_shape_internal(rb_shape_t * shape, ID id, enum shape_type shape_type, bool * variation_created, bool new_variations_allowed)
+get_next_shape_internal(rb_shape_t * shape, ID id, enum shape_type shape_type, bool * variation_created, bool new_shapes_allowed)
{
rb_shape_t *res = NULL;
@@ -463,64 +139,56 @@ get_next_shape_internal(rb_shape_t * shape, ID id, enum shape_type shape_type, b
*variation_created = false;
- RB_VM_LOCK_ENTER();
- {
- // If the current shape has children
- if (shape->edges) {
- // Check if it only has one child
- if (SINGLE_CHILD_P(shape->edges)) {
- rb_shape_t * child = SINGLE_CHILD(shape->edges);
- // If the one child has a matching edge name, then great,
- // we found what we want.
- if (child->edge_name == id) {
- res = child;
- }
- }
- else {
- // If it has more than one child, do a hash lookup to find it.
- VALUE lookup_result;
- if (rb_id_table_lookup(shape->edges, id, &lookup_result)) {
- res = (rb_shape_t *)lookup_result;
- }
+ if (new_shapes_allowed) {
+ RB_VM_LOCK_ENTER();
+ {
+ bool had_edges = !!shape->edges;
+
+ if (!shape->edges) {
+ shape->edges = rb_id_table_create(0);
}
- }
- // If we didn't find the shape we're looking for we create it.
- if (!res) {
- // If we're not allowed to create a new variation, of if we're out of shapes
- // we return TOO_COMPLEX_SHAPE.
- if (!new_variations_allowed || GET_SHAPE_TREE()->next_shape_id > MAX_SHAPE_ID) {
- res = rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
+ // Lookup the shape in edges - if there's already an edge and a corresponding shape for it,
+ // we can return that. Otherwise, we'll need to get a new shape
+ VALUE lookup_result;
+ if (rb_id_table_lookup(shape->edges, id, &lookup_result)) {
+ res = (rb_shape_t *)lookup_result;
}
else {
- rb_shape_t * new_shape = rb_shape_alloc_new_child(id, shape, shape_type);
+ *variation_created = had_edges;
- if (!shape->edges) {
- // If the shape had no edge yet, we can directly set the new child
- shape->edges = TAG_SINGLE_CHILD(new_shape);
- }
- else {
- // If the edge was single child we need to allocate a table.
- if (SINGLE_CHILD_P(shape->edges)) {
- rb_shape_t * old_child = SINGLE_CHILD(shape->edges);
- shape->edges = rb_id_table_create(2);
- rb_id_table_insert(shape->edges, old_child->edge_name, (VALUE)old_child);
- }
-
- rb_id_table_insert(shape->edges, new_shape->edge_name, (VALUE)new_shape);
- *variation_created = true;
+ rb_shape_t * new_shape = rb_shape_alloc(id, shape);
+
+ new_shape->type = (uint8_t)shape_type;
+ new_shape->capacity = shape->capacity;
+
+ switch (shape_type) {
+ case SHAPE_IVAR:
+ new_shape->next_iv_index = shape->next_iv_index + 1;
+ break;
+ case SHAPE_CAPACITY_CHANGE:
+ case SHAPE_FROZEN:
+ case SHAPE_T_OBJECT:
+ new_shape->next_iv_index = shape->next_iv_index;
+ break;
+ case SHAPE_OBJ_TOO_COMPLEX:
+ case SHAPE_INITIAL_CAPACITY:
+ case SHAPE_ROOT:
+ rb_bug("Unreachable");
+ break;
}
+ rb_id_table_insert(shape->edges, id, (VALUE)new_shape);
+
res = new_shape;
}
}
+ RB_VM_LOCK_LEAVE();
}
- RB_VM_LOCK_LEAVE();
-
return res;
}
-int
+MJIT_FUNC_EXPORTED int
rb_shape_frozen_shape_p(rb_shape_t* shape)
{
return SHAPE_FROZEN == (enum shape_type)shape->type;
@@ -541,7 +209,7 @@ move_iv(VALUE obj, ID id, attr_index_t from, attr_index_t to)
default: {
struct gen_ivtbl *ivtbl;
rb_gen_ivtbl_get(obj, id, &ivtbl);
- ivtbl->as.shape.ivptr[to] = ivtbl->as.shape.ivptr[from];
+ ivtbl->ivptr[to] = ivtbl->ivptr[from];
break;
}
}
@@ -572,7 +240,7 @@ remove_shape_recursive(VALUE obj, ID id, rb_shape_t * shape, VALUE * removed)
default: {
struct gen_ivtbl *ivtbl;
rb_gen_ivtbl_get(obj, id, &ivtbl);
- *removed = ivtbl->as.shape.ivptr[index];
+ *removed = ivtbl->ivptr[index];
break;
}
}
@@ -585,16 +253,8 @@ remove_shape_recursive(VALUE obj, ID id, rb_shape_t * shape, VALUE * removed)
// We found a new parent. Create a child of the new parent that
// has the same attributes as this shape.
if (new_parent) {
- if (UNLIKELY(new_parent->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return new_parent;
- }
-
bool dont_care;
rb_shape_t * new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
- if (UNLIKELY(new_child->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return new_child;
- }
-
new_child->capacity = shape->capacity;
if (new_child->type == SHAPE_IVAR) {
move_iv(obj, id, shape->next_iv_index - 1, new_child->next_iv_index - 1);
@@ -611,25 +271,16 @@ remove_shape_recursive(VALUE obj, ID id, rb_shape_t * shape, VALUE * removed)
}
}
-bool
+void
rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE * removed)
{
- if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return false;
- }
-
rb_shape_t * new_shape = remove_shape_recursive(obj, id, shape, removed);
if (new_shape) {
- if (UNLIKELY(new_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return false;
- }
-
rb_shape_set_shape(obj, new_shape);
}
- return true;
}
-rb_shape_t *
+void
rb_shape_transition_shape_frozen(VALUE obj)
{
rb_shape_t* shape = rb_shape_get_shape(obj);
@@ -637,20 +288,21 @@ rb_shape_transition_shape_frozen(VALUE obj)
RUBY_ASSERT(RB_OBJ_FROZEN(obj));
if (rb_shape_frozen_shape_p(shape) || rb_shape_obj_too_complex(obj)) {
- return shape;
+ return;
}
rb_shape_t* next_shape;
if (shape == rb_shape_get_root_shape()) {
- return rb_shape_get_shape_by_id(SPECIAL_CONST_SHAPE_ID);
+ rb_shape_set_shape_id(obj, SPECIAL_CONST_SHAPE_ID);
+ return;
}
bool dont_care;
next_shape = get_next_shape_internal(shape, (ID)id_frozen, SHAPE_FROZEN, &dont_care, true);
RUBY_ASSERT(next_shape);
- return next_shape;
+ rb_shape_set_shape(obj, next_shape);
}
/*
@@ -669,9 +321,6 @@ rb_shape_t *
rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id)
{
RUBY_ASSERT(!is_instance_id(id) || RTEST(rb_sym2str(ID2SYM(id))));
- if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return shape;
- }
bool allow_new_shape = true;
@@ -680,17 +329,14 @@ rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id)
allow_new_shape = RCLASS_EXT(klass)->variation_count < SHAPE_MAX_VARIATIONS;
}
- if (UNLIKELY(shape->next_iv_index >= shape->capacity)) {
- RUBY_ASSERT(shape->next_iv_index == shape->capacity);
- shape = rb_shape_transition_shape_capa(shape);
- if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return shape;
- }
- }
-
bool variation_created = false;
rb_shape_t * new_shape = get_next_shape_internal(shape, id, SHAPE_IVAR, &variation_created, allow_new_shape);
+ if (!new_shape) {
+ RUBY_ASSERT(BUILTIN_TYPE(obj) == T_OBJECT);
+ new_shape = rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
+ }
+
// Check if we should update max_iv_count on the object's class
if (BUILTIN_TYPE(obj) == T_OBJECT) {
VALUE klass = rb_obj_class(obj);
@@ -700,101 +346,22 @@ rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id)
if (variation_created) {
RCLASS_EXT(klass)->variation_count++;
- if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_PERFORMANCE)) {
- if (RCLASS_EXT(klass)->variation_count >= SHAPE_MAX_VARIATIONS) {
- rb_category_warn(
- RB_WARN_CATEGORY_PERFORMANCE,
- "Maximum shapes variations (%d) reached by %"PRIsVALUE", instance variables accesses will be slower.",
- SHAPE_MAX_VARIATIONS,
- rb_class_path(klass)
- );
- }
- }
}
}
return new_shape;
}
-static inline rb_shape_t *
-rb_shape_transition_shape_capa_create(rb_shape_t* shape, size_t new_capacity)
+rb_shape_t *
+rb_shape_transition_shape_capa(rb_shape_t* shape, uint32_t new_capacity)
{
- RUBY_ASSERT(new_capacity < (size_t)MAX_IVARS);
-
ID edge_name = rb_make_temporary_id(new_capacity);
bool dont_care;
rb_shape_t * new_shape = get_next_shape_internal(shape, edge_name, SHAPE_CAPACITY_CHANGE, &dont_care, true);
- if (rb_shape_id(new_shape) != OBJ_TOO_COMPLEX_SHAPE_ID) {
- new_shape->capacity = (uint32_t)new_capacity;
- }
+ new_shape->capacity = new_capacity;
return new_shape;
}
-rb_shape_t *
-rb_shape_transition_shape_capa(rb_shape_t* shape)
-{
- if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return shape;
- }
- return rb_shape_transition_shape_capa_create(shape, rb_malloc_grow_capa(shape->capacity, sizeof(VALUE)));
-}
-
-// Same as rb_shape_get_iv_index, but uses a provided valid shape id and index
-// to return a result faster if branches of the shape tree are closely related.
-bool
-rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value, shape_id_t *shape_id_hint)
-{
- attr_index_t index_hint = *value;
- rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
- rb_shape_t *initial_shape = shape;
-
- if (*shape_id_hint == INVALID_SHAPE_ID) {
- *shape_id_hint = shape_id;
- return rb_shape_get_iv_index(shape, id, value);
- }
-
- rb_shape_t * shape_hint = rb_shape_get_shape_by_id(*shape_id_hint);
-
- // We assume it's likely shape_id_hint and shape_id have a close common
- // ancestor, so we check up to ANCESTOR_SEARCH_MAX_DEPTH ancestors before
- // eventually using the index, as in case of a match it will be faster.
- // However if the shape doesn't have an index, we walk the entire tree.
- int depth = INT_MAX;
- if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
- depth = ANCESTOR_SEARCH_MAX_DEPTH;
- }
-
- while (depth > 0 && shape->next_iv_index > index_hint) {
- while (shape_hint->next_iv_index > shape->next_iv_index) {
- shape_hint = rb_shape_get_parent(shape_hint);
- }
-
- if (shape_hint == shape) {
- // We've found a common ancestor so use the index hint
- *value = index_hint;
- *shape_id_hint = rb_shape_id(shape);
- return true;
- }
- if (shape->edge_name == id) {
- // We found the matching id before a common ancestor
- *value = shape->next_iv_index - 1;
- *shape_id_hint = rb_shape_id(shape);
- return true;
- }
-
- shape = rb_shape_get_parent(shape);
- depth--;
- }
-
- // If the original shape had an index but its ancestor doesn't
- // we switch back to the original one as it will be faster.
- if (!shape->ancestor_index && initial_shape->ancestor_index) {
- shape = initial_shape;
- }
- *shape_id_hint = shape_id;
- return rb_shape_get_iv_index(shape, id, value);
-}
-
bool
rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value)
{
@@ -803,36 +370,23 @@ rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value)
RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
while (shape->parent_id != INVALID_SHAPE_ID) {
- // Try the ancestor cache if it's available
- if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
- redblack_node_t * node = redblack_find(shape->ancestor_index, id);
- if (node) {
- rb_shape_t * shape = redblack_value(node);
+ if (shape->edge_name == id) {
+ enum shape_type shape_type;
+ shape_type = (enum shape_type)shape->type;
+
+ switch (shape_type) {
+ case SHAPE_IVAR:
+ RUBY_ASSERT(shape->next_iv_index > 0);
*value = shape->next_iv_index - 1;
return true;
- }
- else {
+ case SHAPE_CAPACITY_CHANGE:
+ case SHAPE_ROOT:
+ case SHAPE_INITIAL_CAPACITY:
+ case SHAPE_T_OBJECT:
return false;
- }
- }
- else {
- if (shape->edge_name == id) {
- enum shape_type shape_type;
- shape_type = (enum shape_type)shape->type;
-
- switch (shape_type) {
- case SHAPE_IVAR:
- RUBY_ASSERT(shape->next_iv_index > 0);
- *value = shape->next_iv_index - 1;
- return true;
- case SHAPE_CAPACITY_CHANGE:
- case SHAPE_ROOT:
- case SHAPE_T_OBJECT:
- return false;
- case SHAPE_OBJ_TOO_COMPLEX:
- case SHAPE_FROZEN:
- rb_bug("Ivar should not exist on transition");
- }
+ case SHAPE_OBJ_TOO_COMPLEX:
+ case SHAPE_FROZEN:
+ rb_bug("Ivar should not exist on transition\n");
}
}
shape = rb_shape_get_parent(shape);
@@ -840,7 +394,49 @@ rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value)
return false;
}
-void
+static rb_shape_t *
+shape_alloc(void)
+{
+ rb_vm_t *vm = GET_VM();
+ shape_id_t shape_id = vm->next_shape_id;
+ vm->next_shape_id++;
+
+ if (shape_id == MAX_SHAPE_ID) {
+ // TODO: Make an OutOfShapesError ??
+ rb_bug("Out of shapes\n");
+ }
+
+ return &GET_VM()->shape_list[shape_id];
+}
+
+rb_shape_t *
+rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
+{
+ rb_shape_t * shape = shape_alloc();
+
+ shape->edge_name = edge_name;
+ shape->next_iv_index = 0;
+ shape->parent_id = parent_id;
+
+ return shape;
+}
+
+rb_shape_t *
+rb_shape_alloc_with_size_pool_index(ID edge_name, rb_shape_t * parent, uint8_t size_pool_index)
+{
+ rb_shape_t * shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent));
+ shape->size_pool_index = size_pool_index;
+ return shape;
+}
+
+
+rb_shape_t *
+rb_shape_alloc(ID edge_name, rb_shape_t * parent)
+{
+ return rb_shape_alloc_with_size_pool_index(edge_name, parent, parent->size_pool_index);
+}
+
+MJIT_FUNC_EXPORTED void
rb_shape_set_shape(VALUE obj, rb_shape_t* shape)
{
rb_shape_set_shape_id(obj, rb_shape_id(shape));
@@ -873,30 +469,20 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap
}
VALUE lookup_result;
- if (SINGLE_CHILD_P(next_shape->edges)) {
- rb_shape_t * child = SINGLE_CHILD(next_shape->edges);
- if (child->edge_name == dest_shape->edge_name) {
- return child;
- }
- else {
- return NULL;
- }
+ if (rb_id_table_lookup(next_shape->edges, dest_shape->edge_name, &lookup_result)) {
+ next_shape = (rb_shape_t *)lookup_result;
}
else {
- if (rb_id_table_lookup(next_shape->edges, dest_shape->edge_name, &lookup_result)) {
- next_shape = (rb_shape_t *)lookup_result;
- }
- else {
- return NULL;
- }
+ return NULL;
}
break;
case SHAPE_ROOT:
case SHAPE_CAPACITY_CHANGE:
+ case SHAPE_INITIAL_CAPACITY:
case SHAPE_T_OBJECT:
break;
case SHAPE_OBJ_TOO_COMPLEX:
- rb_bug("Unreachable");
+ rb_bug("Unreachable\n");
break;
}
@@ -906,18 +492,12 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap
rb_shape_t *
rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape)
{
- RUBY_ASSERT(rb_shape_id(initial_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
- RUBY_ASSERT(rb_shape_id(dest_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
-
rb_shape_t * midway_shape;
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
if (dest_shape->type != initial_shape->type) {
midway_shape = rb_shape_rebuild_shape(initial_shape, rb_shape_get_parent(dest_shape));
- if (UNLIKELY(rb_shape_id(midway_shape) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
- return midway_shape;
- }
}
else {
midway_shape = initial_shape;
@@ -927,27 +507,26 @@ rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape)
case SHAPE_IVAR:
if (midway_shape->capacity <= midway_shape->next_iv_index) {
// There isn't enough room to write this IV, so we need to increase the capacity
- midway_shape = rb_shape_transition_shape_capa(midway_shape);
+ midway_shape = rb_shape_transition_shape_capa(midway_shape, midway_shape->capacity * 2);
}
- if (LIKELY(rb_shape_id(midway_shape) != OBJ_TOO_COMPLEX_SHAPE_ID)) {
- midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
- }
+ midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
break;
case SHAPE_ROOT:
case SHAPE_FROZEN:
case SHAPE_CAPACITY_CHANGE:
+ case SHAPE_INITIAL_CAPACITY:
case SHAPE_T_OBJECT:
break;
case SHAPE_OBJ_TOO_COMPLEX:
- rb_bug("Unreachable");
+ rb_bug("Unreachable\n");
break;
}
return midway_shape;
}
-RUBY_FUNC_EXPORTED bool
+bool
rb_shape_obj_too_complex(VALUE obj)
{
return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
@@ -956,6 +535,7 @@ rb_shape_obj_too_complex(VALUE obj)
void
rb_shape_set_too_complex(VALUE obj)
{
+ RUBY_ASSERT(BUILTIN_TYPE(obj) == T_OBJECT);
RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
}
@@ -964,12 +544,7 @@ size_t
rb_shape_edges_count(rb_shape_t *shape)
{
if (shape->edges) {
- if (SINGLE_CHILD_P(shape->edges)) {
- return 1;
- }
- else {
- return rb_id_table_size(shape->edges);
- }
+ return rb_id_table_size(shape->edges);
}
return 0;
}
@@ -978,7 +553,7 @@ size_t
rb_shape_memsize(rb_shape_t *shape)
{
size_t memsize = sizeof(rb_shape_t);
- if (shape->edges && !SINGLE_CHILD_P(shape->edges)) {
+ if (shape->edges) {
memsize += rb_id_table_memsize(shape->edges);
}
return memsize;
@@ -1049,13 +624,7 @@ rb_shape_edges(VALUE self)
VALUE hash = rb_hash_new();
if (shape->edges) {
- if (SINGLE_CHILD_P(shape->edges)) {
- rb_shape_t * child = SINGLE_CHILD(shape->edges);
- rb_edges_to_hash(child->edge_name, (VALUE)child, &hash);
- }
- else {
- rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash);
- }
+ rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash);
}
return hash;
@@ -1110,13 +679,6 @@ rb_shape_root_shape(VALUE self)
return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape());
}
-/* :nodoc: */
-static VALUE
-rb_shape_shapes_available(VALUE self)
-{
- return INT2NUM(MAX_SHAPE_ID - (GET_SHAPE_TREE()->next_shape_id - 1));
-}
-
VALUE rb_obj_shape(rb_shape_t* shape);
static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE value, void *ref)
@@ -1128,13 +690,8 @@ static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE va
static VALUE edges(struct rb_id_table* edges)
{
VALUE hash = rb_hash_new();
- if (SINGLE_CHILD_P(edges)) {
- rb_shape_t * child = SINGLE_CHILD(edges);
- collect_keys_and_values(child->edge_name, (VALUE)child, &hash);
- }
- else {
+ if (edges)
rb_id_table_foreach(edges, collect_keys_and_values, &hash);
- }
return hash;
}
@@ -1170,66 +727,38 @@ static VALUE
rb_shape_find_by_id(VALUE mod, VALUE id)
{
shape_id_t shape_id = NUM2UINT(id);
- if (shape_id >= GET_SHAPE_TREE()->next_shape_id) {
+ if (shape_id >= GET_VM()->next_shape_id) {
rb_raise(rb_eArgError, "Shape ID %d is out of bounds\n", shape_id);
}
return rb_shape_t_to_rb_cShape(rb_shape_get_shape_by_id(shape_id));
}
#endif
-#ifdef HAVE_MMAP
-#include <sys/mman.h>
-#endif
-
void
Init_default_shapes(void)
{
- rb_shape_tree_t *st = ruby_mimmalloc(sizeof(rb_shape_tree_t));
- memset(st, 0, sizeof(rb_shape_tree_t));
- rb_shape_tree_ptr = st;
-
-#ifdef HAVE_MMAP
- rb_shape_tree_ptr->shape_list = (rb_shape_t *)mmap(NULL, rb_size_mul_or_raise(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t), rb_eRuntimeError),
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (GET_SHAPE_TREE()->shape_list == MAP_FAILED) {
- GET_SHAPE_TREE()->shape_list = 0;
- }
-#else
- GET_SHAPE_TREE()->shape_list = xcalloc(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t));
-#endif
-
- if (!GET_SHAPE_TREE()->shape_list) {
- rb_memerror();
- }
-
id_frozen = rb_make_internal_id();
id_t_object = rb_make_internal_id();
-#ifdef HAVE_MMAP
- rb_shape_tree_ptr->shape_cache = (redblack_node_t *)mmap(NULL, rb_size_mul_or_raise(REDBLACK_CACHE_SIZE, sizeof(redblack_node_t), rb_eRuntimeError),
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- rb_shape_tree_ptr->cache_size = 0;
-#endif
-
// Shapes by size pool
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
size_pool_edge_names[i] = rb_make_internal_id();
}
// Root shape
- rb_shape_t *root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
- root->capacity = 0;
+ rb_shape_t * root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
+ root->capacity = (uint32_t)((rb_size_pool_slot_size(0) - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
root->type = SHAPE_ROOT;
root->size_pool_index = 0;
- GET_SHAPE_TREE()->root_shape = root;
- RUBY_ASSERT(rb_shape_id(GET_SHAPE_TREE()->root_shape) == ROOT_SHAPE_ID);
+ GET_VM()->root_shape = root;
+ RUBY_ASSERT(rb_shape_id(GET_VM()->root_shape) == ROOT_SHAPE_ID);
// Shapes by size pool
for (int i = 1; i < SIZE_POOL_COUNT; i++) {
- rb_shape_t *new_shape = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
- new_shape->type = SHAPE_ROOT;
+ uint32_t capa = (uint32_t)((rb_size_pool_slot_size(i) - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
+ rb_shape_t * new_shape = rb_shape_transition_shape_capa(root, capa);
+ new_shape->type = SHAPE_INITIAL_CAPACITY;
new_shape->size_pool_index = i;
- new_shape->ancestor_index = LEAF;
RUBY_ASSERT(rb_shape_id(new_shape) == (shape_id_t)i);
}
@@ -1239,9 +768,7 @@ Init_default_shapes(void)
bool dont_care;
rb_shape_t * t_object_shape =
get_next_shape_internal(shape, id_t_object, SHAPE_T_OBJECT, &dont_care, true);
- t_object_shape->capacity = (uint32_t)((rb_size_pool_slot_size(i) - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
t_object_shape->edges = rb_id_table_create(0);
- t_object_shape->ancestor_index = LEAF;
RUBY_ASSERT(rb_shape_id(t_object_shape) == (shape_id_t)(i + SIZE_POOL_COUNT));
}
@@ -1252,13 +779,13 @@ Init_default_shapes(void)
#endif
get_next_shape_internal(root, (ID)id_frozen, SHAPE_FROZEN, &dont_care, true);
RUBY_ASSERT(rb_shape_id(special_const_shape) == SPECIAL_CONST_SHAPE_ID);
- RUBY_ASSERT(SPECIAL_CONST_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
+ RUBY_ASSERT(SPECIAL_CONST_SHAPE_ID == (GET_VM()->next_shape_id - 1));
RUBY_ASSERT(rb_shape_frozen_shape_p(special_const_shape));
rb_shape_t * hash_fallback_shape = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
hash_fallback_shape->type = SHAPE_OBJ_TOO_COMPLEX;
hash_fallback_shape->size_pool_index = 0;
- RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
+ RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_VM()->next_shape_id - 1));
RUBY_ASSERT(rb_shape_id(hash_fallback_shape) == OBJ_TOO_COMPLEX_SHAPE_ID);
}
@@ -1289,15 +816,10 @@ Init_shape(void)
rb_define_const(rb_cShape, "SPECIAL_CONST_SHAPE_ID", INT2NUM(SPECIAL_CONST_SHAPE_ID));
rb_define_const(rb_cShape, "OBJ_TOO_COMPLEX_SHAPE_ID", INT2NUM(OBJ_TOO_COMPLEX_SHAPE_ID));
rb_define_const(rb_cShape, "SHAPE_MAX_VARIATIONS", INT2NUM(SHAPE_MAX_VARIATIONS));
- rb_define_const(rb_cShape, "SIZEOF_RB_SHAPE_T", INT2NUM(sizeof(rb_shape_t)));
- rb_define_const(rb_cShape, "SIZEOF_REDBLACK_NODE_T", INT2NUM(sizeof(redblack_node_t)));
- rb_define_const(rb_cShape, "SHAPE_BUFFER_SIZE", INT2NUM(sizeof(rb_shape_t) * SHAPE_BUFFER_SIZE));
- rb_define_const(rb_cShape, "REDBLACK_CACHE_SIZE", INT2NUM(sizeof(redblack_node_t) * REDBLACK_CACHE_SIZE));
rb_define_singleton_method(rb_cShape, "transition_tree", shape_transition_tree, 0);
rb_define_singleton_method(rb_cShape, "find_by_id", rb_shape_find_by_id, 1);
rb_define_singleton_method(rb_cShape, "of", rb_shape_debug_shape, 1);
rb_define_singleton_method(rb_cShape, "root_shape", rb_shape_root_shape, 0);
- rb_define_singleton_method(rb_cShape, "shapes_available", rb_shape_shapes_available, 0);
#endif
}
diff --git a/shape.h b/shape.h
index 6d4f3f9811..8f3451d492 100644
--- a/shape.h
+++ b/shape.h
@@ -3,43 +3,42 @@
#include "internal/gc.h"
-#if (SIZEOF_UINT64_T <= SIZEOF_VALUE)
-
+#if (SIZEOF_UINT64_T == SIZEOF_VALUE)
#define SIZEOF_SHAPE_T 4
#define SHAPE_IN_BASIC_FLAGS 1
typedef uint32_t attr_index_t;
-typedef uint32_t shape_id_t;
-typedef uint32_t redblack_id_t;
-# define SHAPE_ID_NUM_BITS 32
-
#else
-
#define SIZEOF_SHAPE_T 2
#define SHAPE_IN_BASIC_FLAGS 0
typedef uint16_t attr_index_t;
-typedef uint16_t shape_id_t;
-typedef uint16_t redblack_id_t;
-# define SHAPE_ID_NUM_BITS 16
-
#endif
#define MAX_IVARS (attr_index_t)(-1)
+#if SIZEOF_SHAPE_T == 4
+typedef uint32_t shape_id_t;
+# define SHAPE_ID_NUM_BITS 32
+#else
+typedef uint16_t shape_id_t;
+# define SHAPE_ID_NUM_BITS 16
+#endif
+
# define SHAPE_MASK (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
+# define SHAPE_BITMAP_SIZE 16384
+
# define SHAPE_MAX_VARIATIONS 8
+# define MAX_SHAPE_ID (SHAPE_MASK - 1)
# define INVALID_SHAPE_ID SHAPE_MASK
# define ROOT_SHAPE_ID 0x0
# define SPECIAL_CONST_SHAPE_ID (SIZE_POOL_COUNT * 2)
# define OBJ_TOO_COMPLEX_SHAPE_ID (SPECIAL_CONST_SHAPE_ID + 1)
-typedef struct redblack_node redblack_node_t;
-
struct rb_shape {
struct rb_id_table * edges; // id_table from ID (ivar) to next shape
ID edge_name; // ID (ivar) for transition from parent to rb_shape
@@ -48,54 +47,30 @@ struct rb_shape {
uint8_t type;
uint8_t size_pool_index;
shape_id_t parent_id;
- redblack_node_t * ancestor_index;
};
typedef struct rb_shape rb_shape_t;
-struct redblack_node {
- ID key;
- rb_shape_t * value;
- redblack_id_t l;
- redblack_id_t r;
-};
-
enum shape_type {
SHAPE_ROOT,
SHAPE_IVAR,
SHAPE_FROZEN,
SHAPE_CAPACITY_CHANGE,
+ SHAPE_INITIAL_CAPACITY,
SHAPE_T_OBJECT,
SHAPE_OBJ_TOO_COMPLEX,
};
-typedef struct {
- /* object shapes */
- rb_shape_t *shape_list;
- rb_shape_t *root_shape;
- shape_id_t next_shape_id;
-
- redblack_node_t *shape_cache;
- unsigned int cache_size;
-} rb_shape_tree_t;
-RUBY_EXTERN rb_shape_tree_t *rb_shape_tree_ptr;
-
-static inline rb_shape_tree_t *
-rb_current_shape_tree(void)
-{
- return rb_shape_tree_ptr;
-}
-#define GET_SHAPE_TREE() rb_current_shape_tree()
-
+#if SHAPE_IN_BASIC_FLAGS
static inline shape_id_t
-get_shape_id_from_flags(VALUE obj)
+RBASIC_SHAPE_ID(VALUE obj)
{
RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
return (shape_id_t)(SHAPE_MASK & ((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT));
}
static inline void
-set_shape_id_in_flags(VALUE obj, shape_id_t shape_id)
+RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
// Ractors are occupying the upper 32 bits of flags, but only in debug mode
// Object shapes are occupying top bits
@@ -103,66 +78,76 @@ set_shape_id_in_flags(VALUE obj, shape_id_t shape_id)
RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
}
-
-#if SHAPE_IN_BASIC_FLAGS
static inline shape_id_t
-RBASIC_SHAPE_ID(VALUE obj)
+ROBJECT_SHAPE_ID(VALUE obj)
{
- return get_shape_id_from_flags(obj);
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
+ return RBASIC_SHAPE_ID(obj);
}
static inline void
-RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
- set_shape_id_in_flags(obj, shape_id);
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
+ RBASIC_SET_SHAPE_ID(obj, shape_id);
}
-#endif
+
+static inline shape_id_t
+RCLASS_SHAPE_ID(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
+ return RBASIC_SHAPE_ID(obj);
+}
+
+#else
static inline shape_id_t
ROBJECT_SHAPE_ID(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- return get_shape_id_from_flags(obj);
+ return (shape_id_t)(SHAPE_MASK & (RBASIC(obj)->flags >> SHAPE_FLAG_SHIFT));
}
static inline void
ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
- RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- set_shape_id_in_flags(obj, shape_id);
+ RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
+ RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
}
-static inline shape_id_t
-RCLASS_SHAPE_ID(VALUE obj)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- return get_shape_id_from_flags(obj);
-}
+MJIT_SYMBOL_EXPORT_BEGIN
+shape_id_t rb_rclass_shape_id(VALUE obj);
+MJIT_SYMBOL_EXPORT_END
-static inline void
-RCLASS_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+static inline shape_id_t RCLASS_SHAPE_ID(VALUE obj)
{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- set_shape_id_in_flags(obj, shape_id);
+ return rb_rclass_shape_id(obj);
}
+#endif
+
+bool rb_shape_root_shape_p(rb_shape_t* shape);
rb_shape_t * rb_shape_get_root_shape(void);
+uint8_t rb_shape_id_num_bits(void);
int32_t rb_shape_id_offset(void);
+rb_shape_t* rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id);
rb_shape_t * rb_shape_get_parent(rb_shape_t * shape);
+MJIT_SYMBOL_EXPORT_BEGIN
rb_shape_t* rb_shape_get_shape_by_id(shape_id_t shape_id);
shape_id_t rb_shape_get_shape_id(VALUE obj);
rb_shape_t * rb_shape_get_next_iv_shape(rb_shape_t * shape, ID id);
bool rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t * value);
-bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t * value, shape_id_t *shape_id_hint);
bool rb_shape_obj_too_complex(VALUE obj);
+MJIT_SYMBOL_EXPORT_END
void rb_shape_set_shape(VALUE obj, rb_shape_t* shape);
rb_shape_t* rb_shape_get_shape(VALUE obj);
int rb_shape_frozen_shape_p(rb_shape_t* shape);
-rb_shape_t* rb_shape_transition_shape_frozen(VALUE obj);
-bool rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE * removed);
+void rb_shape_transition_shape_frozen(VALUE obj);
+void rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE * removed);
+rb_shape_t * rb_shape_transition_shape_capa(rb_shape_t * shape, uint32_t new_capacity);
rb_shape_t* rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id);
rb_shape_t * rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape);
@@ -173,7 +158,7 @@ ROBJECT_IV_CAPACITY(VALUE obj)
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
// Asking for capacity doesn't make sense when the object is using
// a hash table for storing instance variables
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) != OBJ_TOO_COMPLEX_SHAPE_ID);
return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->capacity;
}
@@ -181,15 +166,15 @@ static inline st_table *
ROBJECT_IV_HASH(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
return (st_table *)ROBJECT(obj)->as.heap.ivptr;
}
static inline void
-ROBJECT_SET_IV_HASH(VALUE obj, const st_table *tbl)
+ROBJECT_SET_IV_HASH(VALUE obj, const struct rb_id_table *tbl)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
ROBJECT(obj)->as.heap.ivptr = (VALUE *)tbl;
}
@@ -198,12 +183,12 @@ size_t rb_id_table_size(const struct rb_id_table *tbl);
static inline uint32_t
ROBJECT_IV_COUNT(VALUE obj)
{
- if (rb_shape_obj_too_complex(obj)) {
+ if (ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID) {
return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
}
else {
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) != OBJ_TOO_COMPLEX_SHAPE_ID);
return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->next_iv_index;
}
}
@@ -222,11 +207,16 @@ RCLASS_IV_COUNT(VALUE obj)
return ivc;
}
+rb_shape_t * rb_shape_alloc(ID edge_name, rb_shape_t * parent);
+rb_shape_t * rb_shape_alloc_with_size_pool_index(ID edge_name, rb_shape_t * parent, uint8_t size_pool_index);
+rb_shape_t * rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id);
+
rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *orig_shape);
bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
+VALUE rb_shape_flags_mask(void);
void rb_shape_set_too_complex(VALUE obj);
// For ext/objspace
diff --git a/signal.c b/signal.c
index fa7d25caf5..1072cb47f1 100644
--- a/signal.c
+++ b/signal.c
@@ -36,7 +36,6 @@
#include "debug_counter.h"
#include "eval_intern.h"
#include "internal.h"
-#include "internal/error.h"
#include "internal/eval.h"
#include "internal/sanitizers.h"
#include "internal/signal.h"
@@ -45,6 +44,7 @@
#include "ruby_atomic.h"
#include "vm_core.h"
#include "ractor_core.h"
+#include "ruby/internal/attr/nonstring.h"
#ifdef NEED_RUBY_ATOMIC_OPS
rb_atomic_t
@@ -133,7 +133,7 @@ static const struct signals {
#ifdef SIGCONT
{"CONT", SIGCONT},
#endif
-#ifdef RUBY_SIGCHLD
+#if RUBY_SIGCHLD
{"CHLD", RUBY_SIGCHLD },
{"CLD", RUBY_SIGCHLD },
#endif
@@ -509,6 +509,9 @@ static struct {
rb_atomic_t cnt[RUBY_NSIG];
rb_atomic_t size;
} signal_buff;
+#if RUBY_SIGCHLD
+volatile unsigned int ruby_nocldwait;
+#endif
#define sighandler_t ruby_sighandler_t
@@ -606,6 +609,27 @@ ruby_signal(int signum, sighandler_t handler)
#endif
switch (signum) {
+#if RUBY_SIGCHLD
+ case RUBY_SIGCHLD:
+ if (handler == SIG_IGN) {
+ ruby_nocldwait = 1;
+# ifdef USE_SIGALTSTACK
+ if (sigact.sa_flags & SA_SIGINFO) {
+ sigact.sa_sigaction = (ruby_sigaction_t*)sighandler;
+ }
+ else {
+ sigact.sa_handler = sighandler;
+ }
+# else
+ sigact.sa_handler = handler;
+ sigact.sa_flags = 0;
+# endif
+ }
+ else {
+ ruby_nocldwait = 0;
+ }
+ break;
+#endif
#if defined(SA_ONSTACK) && defined(USE_SIGALTSTACK)
case SIGSEGV:
#ifdef SIGBUS
@@ -628,7 +652,7 @@ ruby_signal(int signum, sighandler_t handler)
}
sighandler_t
-ruby_posix_signal(int signum, sighandler_t handler)
+posix_signal(int signum, sighandler_t handler)
{
return ruby_signal(signum, handler);
}
@@ -684,14 +708,35 @@ signal_enque(int sig)
ATOMIC_INC(signal_buff.size);
}
+#if RUBY_SIGCHLD
+static rb_atomic_t sigchld_hit;
+/* destructive getter than simple predicate */
+# define GET_SIGCHLD_HIT() ATOMIC_EXCHANGE(sigchld_hit, 0)
+#else
+# define GET_SIGCHLD_HIT() 0
+#endif
+
static void
sighandler(int sig)
{
int old_errnum = errno;
- signal_enque(sig);
- rb_thread_wakeup_timer_thread(sig);
+ /* the VM always needs to handle SIGCHLD for rb_waitpid */
+ if (sig == RUBY_SIGCHLD) {
+#if RUBY_SIGCHLD
+ rb_vm_t *vm = GET_VM();
+ ATOMIC_EXCHANGE(sigchld_hit, 1);
+ /* avoid spurious wakeup in main thread if and only if nobody uses trap(:CHLD) */
+ if (vm && ACCESS_ONCE(VALUE, vm->trap_list.cmd[sig])) {
+ signal_enque(sig);
+ }
+#endif
+ }
+ else {
+ signal_enque(sig);
+ }
+ rb_thread_wakeup_timer_thread(sig);
#if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
ruby_signal(sig, sighandler);
#endif
@@ -880,10 +925,10 @@ check_stack_overflow(int sig, const void *addr)
#endif
#if defined SIGSEGV || defined SIGBUS || defined SIGILL || defined SIGFPE
-NOINLINE(static void check_reserved_signal_(const char *name, size_t name_len, int signo));
+NOINLINE(static void check_reserved_signal_(const char *name, size_t name_len));
/* noinine to reduce stack usage in signal handers */
-#define check_reserved_signal(name) check_reserved_signal_(name, sizeof(name)-1, sig)
+#define check_reserved_signal(name) check_reserved_signal_(name, sizeof(name)-1)
#ifdef SIGBUS
@@ -955,38 +1000,33 @@ ruby_abort(void)
}
static void
-check_reserved_signal_(const char *name, size_t name_len, int signo)
+check_reserved_signal_(const char *name, size_t name_len)
{
const char *prev = ATOMIC_PTR_EXCHANGE(received_signal, name);
if (prev) {
ssize_t RB_UNUSED_VAR(err);
- static const int stderr_fd = 2;
-#define NOZ(name, str) name[sizeof(str)-1] = str
+#define NOZ(name, str) RBIMPL_ATTR_NONSTRING() name[sizeof(str)-1] = str
static const char NOZ(msg1, " received in ");
static const char NOZ(msg2, " handler\n");
#ifdef HAVE_WRITEV
struct iovec iov[4];
- int i = 0;
-# define W(str, len) \
- iov[i++] = (struct iovec){.iov_base = (void *)(str), .iov_len = (len)}
-#else
-# define W(str, len) err = write(stderr_fd, (str), (len))
-#endif
-#if __has_feature(address_sanitizer) || \
- __has_feature(memory_sanitizer) || \
- defined(HAVE_VALGRIND_MEMCHECK_H)
- ruby_posix_signal(signo, SIG_DFL);
-#endif
- W(name, name_len);
- W(msg1, sizeof(msg1));
- W(prev, strlen(prev));
- W(msg2, sizeof(msg2));
-# undef W
-#ifdef HAVE_WRITEV
- err = writev(stderr_fd, iov, i);
+ iov[0].iov_base = (void *)name;
+ iov[0].iov_len = name_len;
+ iov[1].iov_base = (void *)msg1;
+ iov[1].iov_len = sizeof(msg1);
+ iov[2].iov_base = (void *)prev;
+ iov[2].iov_len = strlen(prev);
+ iov[3].iov_base = (void *)msg2;
+ iov[3].iov_len = sizeof(msg2);
+ err = writev(2, iov, 4);
+#else
+ err = write(2, name, name_len);
+ err = write(2, msg1, sizeof(msg1));
+ err = write(2, prev, strlen(prev));
+ err = write(2, msg2, sizeof(msg2));
#endif
ruby_abort();
}
@@ -1046,6 +1086,16 @@ rb_vm_trap_exit(rb_vm_t *vm)
}
}
+void ruby_waitpid_all(rb_vm_t *); /* process.c */
+
+void
+ruby_sigchld_handler(rb_vm_t *vm)
+{
+ if (SIGCHLD_LOSSY || GET_SIGCHLD_HIT()) {
+ ruby_waitpid_all(vm);
+ }
+}
+
/* returns true if a trap handler was run, false otherwise */
int
rb_signal_exec(rb_thread_t *th, int sig)
@@ -1113,7 +1163,7 @@ default_handler(int sig)
#ifdef SIGUSR2
case SIGUSR2:
#endif
-#ifdef RUBY_SIGCHLD
+#if RUBY_SIGCHLD
case RUBY_SIGCHLD:
#endif
func = sighandler;
@@ -1181,6 +1231,9 @@ trap_handler(VALUE *cmd, int sig)
break;
case 14:
if (memcmp(cptr, "SYSTEM_DEFAULT", 14) == 0) {
+ if (sig == RUBY_SIGCHLD) {
+ goto sig_dfl;
+ }
func = SIG_DFL;
*cmd = 0;
}
@@ -1331,7 +1384,7 @@ reserved_signal_p(int signo)
* Signal.trap("CLD") { puts "Child died" }
* fork && Process.wait
*
- * <em>produces:</em>
+ * produces:
* Terminating: 27461
* Child died
* Terminating: 27460
@@ -1398,7 +1451,6 @@ sig_list(VALUE _)
if (reserved_signal_p(signum)) rb_bug(failed); \
perror(failed); \
} while (0)
-
static int
install_sighandler_core(int signum, sighandler_t handler, sighandler_t *old_handler)
{
@@ -1423,6 +1475,25 @@ install_sighandler_core(int signum, sighandler_t handler, sighandler_t *old_hand
# define force_install_sighandler(signum, handler, old_handler) \
INSTALL_SIGHANDLER(install_sighandler_core(signum, handler, old_handler), #signum, signum)
+#if RUBY_SIGCHLD
+static int
+init_sigchld(int sig)
+{
+ sighandler_t oldfunc;
+ sighandler_t func = sighandler;
+
+ oldfunc = ruby_signal(sig, SIG_DFL);
+ if (oldfunc == SIG_ERR) return -1;
+ ruby_signal(sig, func);
+ ACCESS_ONCE(VALUE, GET_VM()->trap_list.cmd[sig]) = 0;
+
+ return 0;
+}
+
+# define init_sigchld(signum) \
+ INSTALL_SIGHANDLER(init_sigchld(signum), #signum, signum)
+#endif
+
void
ruby_sig_finalize(void)
{
@@ -1434,6 +1505,7 @@ ruby_sig_finalize(void)
}
}
+
int ruby_enable_coredump = 0;
/*
@@ -1464,10 +1536,10 @@ int ruby_enable_coredump = 0;
* # ...
* Process.kill("TERM", pid)
*
- * <em>produces:</em>
+ * produces:
* Debug now: true
* Debug now: false
- * Terminating...
+ * Terminating...
*
* The list of available signal names and their interpretation is
* system dependent. Signal delivery semantics may also vary between
@@ -1530,8 +1602,8 @@ Init_signal(void)
install_sighandler(SIGSYS, sig_do_nothing);
#endif
-#ifdef RUBY_SIGCHLD
- install_sighandler(RUBY_SIGCHLD, sighandler);
+#if RUBY_SIGCHLD
+ init_sigchld(RUBY_SIGCHLD);
#endif
rb_enable_interrupt();
@@ -1552,5 +1624,33 @@ fake_grantfd(int masterfd)
int
rb_grantpt(int masterfd)
{
- return grantpt(masterfd);
+ if (RUBY_SIGCHLD) {
+ rb_vm_t *vm = GET_VM();
+ int ret, e;
+
+ /*
+ * Prevent waitpid calls from Ruby by taking waitpid_lock.
+ * Pedantically, grantpt(3) is undefined if a non-default
+ * SIGCHLD handler is defined, but preventing conflicting
+ * waitpid calls ought to be sufficient.
+ *
+ * We could install the default sighandler temporarily, but that
+ * could cause SIGCHLD to be missed by other threads. Blocking
+ * SIGCHLD won't work here, either, unless we stop and restart
+ * timer-thread (as only timer-thread sees SIGCHLD), but that
+ * seems like overkill.
+ */
+ rb_nativethread_lock_lock(&vm->waitpid_lock);
+ {
+ ret = grantpt(masterfd); /* may spawn `pt_chown' and wait on it */
+ if (ret < 0) e = errno;
+ }
+ rb_nativethread_lock_unlock(&vm->waitpid_lock);
+
+ if (ret < 0) errno = e;
+ return ret;
+ }
+ else {
+ return grantpt(masterfd);
+ }
}
diff --git a/siphash.c b/siphash.c
index 61b8604fc9..62de622778 100644
--- a/siphash.c
+++ b/siphash.c
@@ -140,6 +140,9 @@ xor64_to(uint64_t *v, const uint64_t s)
#endif
static const union {
+#if defined(__has_attribute) && __has_attribute(nonstring)
+ __attribute__((nonstring))
+#endif
char bin[32];
uint64_t u64[4];
} sip_init_state_bin = {"uespemos""modnarod""arenegyl""setybdet"};
diff --git a/spec/README.md b/spec/README.md
index 6a88c06e09..4fcf090759 100644
--- a/spec/README.md
+++ b/spec/README.md
@@ -91,24 +91,24 @@ To run all specs:
make test-spec
```
-Extra arguments can be added via `SPECOPTS`.
+Extra arguments can be added via `MSPECOPT`.
For instance, to show the help:
```bash
-make test-spec SPECOPTS=-h
+make test-spec MSPECOPT=-h
```
You can also run the specs in parallel, which is currently experimental.
It takes around 10s instead of 60s on a quad-core laptop.
```bash
-make test-spec SPECOPTS=-j
+make test-spec MSPECOPT=-j
```
To run a specific test, add its path to the command:
```bash
-make test-spec SPECOPTS=spec/ruby/language/for_spec.rb
+make test-spec MSPECOPT=spec/ruby/language/for_spec.rb
```
If ruby trunk is your current `ruby` in `$PATH`, you can also run `mspec` directly:
diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb
index f870007f5a..54fedc8568 100644
--- a/spec/bundler/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler/bundler_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Bundler do
end
it "loads simple structure" do
- simple_structure = { "name" => [:development] }
+ simple_structure = { "name" => [:abc] }
data = Marshal.dump(simple_structure)
expect(Bundler.safe_load_marshal(data)).to eq(simple_structure)
end
@@ -76,7 +76,7 @@ RSpec.describe Bundler do
context "with incorrect YAML file" do
before do
File.open(app_gemspec_path, "wb") do |f|
- f.write <<~GEMSPEC
+ f.write strip_whitespace(<<-GEMSPEC)
---
{:!00 ao=gu\g1= 7~f
GEMSPEC
@@ -99,7 +99,7 @@ RSpec.describe Bundler do
$VERBOSE = verbose
File.open(app_gemspec_path, "wb") do |file|
- file.puts <<~GEMSPEC
+ file.puts <<-GEMSPEC.gsub(/^\s+/, "")
# -*- encoding: utf-8 -*-
Gem::Specification.new do |gem|
gem.author = "André the Giant"
@@ -147,7 +147,7 @@ RSpec.describe Bundler do
context "with gemspec containing local variables" do
before do
File.open(app_gemspec_path, "wb") do |f|
- f.write <<~GEMSPEC
+ f.write strip_whitespace(<<-GEMSPEC)
must_not_leak = true
Gem::Specification.new do |gem|
gem.name = "leak check"
@@ -224,6 +224,24 @@ RSpec.describe Bundler do
end
end
+ describe "#rm_rf" do
+ context "the directory is world writable" do
+ let(:bundler_ui) { Bundler.ui }
+ it "should raise a friendly error" do
+ allow(File).to receive(:exist?).and_return(true)
+ allow(::Bundler::FileUtils).to receive(:remove_entry_secure).and_raise(ArgumentError)
+ allow(File).to receive(:world_writable?).and_return(true)
+ message = <<EOF
+It is a security vulnerability to allow your home directory to be world-writable, and bundler cannot continue.
+You should probably consider fixing this issue by running `chmod o-w ~` on *nix.
+Please refer to https://ruby-doc.org/stdlib-3.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details.
+EOF
+ expect(bundler_ui).to receive(:warn).with(message)
+ expect { Bundler.send(:rm_rf, bundled_app) }.to raise_error(Bundler::PathError)
+ end
+ end
+ end
+
describe "#mkdir_p" do
it "creates a folder at the given path" do
install_gemfile <<-G
diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb
index 64856863ed..59b958ae42 100644
--- a/spec/bundler/bundler/definition_spec.rb
+++ b/spec/bundler/bundler/definition_spec.rb
@@ -77,10 +77,6 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum "foo", "1.0"}
- #{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -136,10 +132,6 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum "foo", "1.0"}
- #{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -167,9 +159,6 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
only_java
- CHECKSUMS
- only_java (1.1-java)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -196,9 +185,6 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo1, "foo", "1.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
diff --git a/spec/bundler/bundler/dependency_spec.rb b/spec/bundler/bundler/dependency_spec.rb
index 1ef511f1aa..6e346c36c1 100644
--- a/spec/bundler/bundler/dependency_spec.rb
+++ b/spec/bundler/bundler/dependency_spec.rb
@@ -89,11 +89,8 @@ RSpec.describe Bundler::Dependency do
:windows_30 => Gem::Platform::WINDOWS,
:windows_31 => Gem::Platform::WINDOWS,
:windows_32 => Gem::Platform::WINDOWS,
- :windows_33 => Gem::Platform::WINDOWS }
- end
-
- let(:deprecated) do
- { :mswin => Gem::Platform::MSWIN,
+ :windows_33 => Gem::Platform::WINDOWS,
+ :mswin => Gem::Platform::MSWIN,
:mswin_18 => Gem::Platform::MSWIN,
:mswin_19 => Gem::Platform::MSWIN,
:mswin_20 => Gem::Platform::MSWIN,
@@ -154,7 +151,7 @@ RSpec.describe Bundler::Dependency do
# rubocop:enable Naming/VariableNumber
it "includes all platforms" do
- expect(subject).to eq(platforms.merge(deprecated))
+ expect(subject).to eq(platforms)
end
end
end
diff --git a/spec/bundler/bundler/digest_spec.rb b/spec/bundler/bundler/digest_spec.rb
index fd7b0c968e..841cc0259e 100644
--- a/spec/bundler/bundler/digest_spec.rb
+++ b/spec/bundler/bundler/digest_spec.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true
-require "openssl"
+require "digest"
require "bundler/digest"
RSpec.describe Bundler::Digest do
context "SHA1" do
subject { Bundler::Digest }
- let(:stdlib) { OpenSSL::Digest::SHA1 }
+ let(:stdlib) { ::Digest::SHA1 }
it "is compatible with stdlib" do
random_strings = ["foo", "skfjsdlkfjsdf", "3924m", "ldskfj"]
diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb
index 0fdcb560b7..a00489d0e5 100644
--- a/spec/bundler/bundler/env_spec.rb
+++ b/spec/bundler/bundler/env_spec.rb
@@ -139,7 +139,7 @@ RSpec.describe Bundler::Env do
context "when Gemfile contains a gemspec and print_gemspecs is true" do
let(:gemspec) do
- <<~GEMSPEC
+ strip_whitespace(<<-GEMSPEC)
Gem::Specification.new do |gem|
gem.name = "foo"
gem.author = "Fumofu"
@@ -178,7 +178,7 @@ RSpec.describe Bundler::Env do
allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
output = described_class.report(:print_gemspecs => true)
- expect(output).to include(<<~ENV)
+ expect(output).to include(strip_whitespace(<<-ENV))
## Gemfile
### Gemfile
diff --git a/spec/bundler/bundler/fetcher_spec.rb b/spec/bundler/bundler/fetcher_spec.rb
index 92790dc7d6..27a63c476d 100644
--- a/spec/bundler/bundler/fetcher_spec.rb
+++ b/spec/bundler/bundler/fetcher_spec.rb
@@ -189,70 +189,4 @@ RSpec.describe Bundler::Fetcher do
end
end
end
-
- describe "#specs_with_retry" do
- let(:downloader) { double(:downloader) }
- let(:remote) { double(:remote, :cache_slug => "slug", :uri => uri, :original_uri => nil, :anonymized_uri => uri) }
- let(:compact_index) { double(Bundler::Fetcher::CompactIndex, :available? => true, :api_fetcher? => true) }
- let(:dependency) { double(Bundler::Fetcher::Dependency, :available? => true, :api_fetcher? => true) }
- let(:index) { double(Bundler::Fetcher::Index, :available? => true, :api_fetcher? => false) }
-
- before do
- allow(Bundler::Fetcher::CompactIndex).to receive(:new).and_return(compact_index)
- allow(Bundler::Fetcher::Dependency).to receive(:new).and_return(dependency)
- allow(Bundler::Fetcher::Index).to receive(:new).and_return(index)
- end
-
- it "picks the first fetcher that works" do
- expect(compact_index).to receive(:specs).with("name").and_return([["name", "1.2.3", "ruby"]])
- expect(dependency).not_to receive(:specs)
- expect(index).not_to receive(:specs)
- fetcher.specs_with_retry("name", double(Bundler::Source::Rubygems))
- end
-
- context "when APIs are not available" do
- before do
- allow(compact_index).to receive(:available?).and_return(false)
- allow(dependency).to receive(:available?).and_return(false)
- end
-
- it "uses the index" do
- expect(compact_index).not_to receive(:specs)
- expect(dependency).not_to receive(:specs)
- expect(index).to receive(:specs).with("name").and_return([["name", "1.2.3", "ruby"]])
-
- fetcher.specs_with_retry("name", double(Bundler::Source::Rubygems))
- end
- end
- end
-
- describe "#api_fetcher?" do
- let(:downloader) { double(:downloader) }
- let(:remote) { double(:remote, :cache_slug => "slug", :uri => uri, :original_uri => nil, :anonymized_uri => uri) }
- let(:compact_index) { double(Bundler::Fetcher::CompactIndex, :available? => false, :api_fetcher? => true) }
- let(:dependency) { double(Bundler::Fetcher::Dependency, :available? => false, :api_fetcher? => true) }
- let(:index) { double(Bundler::Fetcher::Index, :available? => true, :api_fetcher? => false) }
-
- before do
- allow(Bundler::Fetcher::CompactIndex).to receive(:new).and_return(compact_index)
- allow(Bundler::Fetcher::Dependency).to receive(:new).and_return(dependency)
- allow(Bundler::Fetcher::Index).to receive(:new).and_return(index)
- end
-
- context "when an api fetcher is available" do
- before do
- allow(compact_index).to receive(:available?).and_return(true)
- end
-
- it "is truthy" do
- expect(fetcher).to be_api_fetcher
- end
- end
-
- context "when only the index fetcher is available" do
- it "is falsey" do
- expect(fetcher).not_to be_api_fetcher
- end
- end
- end
end
diff --git a/spec/bundler/bundler/installer/parallel_installer_spec.rb b/spec/bundler/bundler/installer/parallel_installer_spec.rb
new file mode 100644
index 0000000000..c8403a2e38
--- /dev/null
+++ b/spec/bundler/bundler/installer/parallel_installer_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require "bundler/installer/parallel_installer"
+
+RSpec.describe Bundler::ParallelInstaller do
+ let(:installer) { instance_double("Installer") }
+ let(:all_specs) { [] }
+ let(:size) { 1 }
+ let(:standalone) { false }
+ let(:force) { false }
+
+ subject { described_class.new(installer, all_specs, size, standalone, force) }
+
+ context "when the spec set is not a valid resolution" do
+ let(:all_specs) do
+ [
+ build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" },
+ build_spec("diff-lcs", "1.4.4"),
+ ].flatten
+ end
+
+ it "prints a warning" do
+ expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
+Your lockfile doesn't include a valid resolution.
+You can fix this by regenerating your lockfile or manually editing the bad locked gems to a version that satisfies all dependencies.
+The unmet dependencies are:
+* diff-lcs (< 1.4), dependency of cucumber-4.1.0, unsatisfied by diff-lcs-1.4.4
+ W
+ subject.check_for_unmet_dependencies
+ end
+ end
+
+ context "when the spec set is a valid resolution" do
+ let(:all_specs) do
+ [
+ build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" },
+ build_spec("diff-lcs", "1.3"),
+ ].flatten
+ end
+
+ it "doesn't print a warning" do
+ expect(Bundler.ui).not_to receive(:warn)
+ subject.check_for_unmet_dependencies
+ end
+ end
+end
diff --git a/spec/bundler/bundler/lockfile_parser_spec.rb b/spec/bundler/bundler/lockfile_parser_spec.rb
index 6d306da916..3a6d61336f 100644
--- a/spec/bundler/bundler/lockfile_parser_spec.rb
+++ b/spec/bundler/bundler/lockfile_parser_spec.rb
@@ -3,7 +3,7 @@
require "bundler/lockfile_parser"
RSpec.describe Bundler::LockfileParser do
- let(:lockfile_contents) { <<~L }
+ let(:lockfile_contents) { strip_whitespace(<<-L) }
GIT
remote: https://github.com/alloy/peiji-san.git
revision: eca485d8dc95f12aaec1a434b49d295c7e91844b
@@ -22,9 +22,6 @@ RSpec.describe Bundler::LockfileParser do
peiji-san!
rake
- CHECKSUMS
- rake (10.3.2) sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8
-
RUBY VERSION
ruby 2.1.3p242
@@ -36,13 +33,13 @@ RSpec.describe Bundler::LockfileParser do
it "returns the attributes" do
attributes = described_class.sections_in_lockfile(lockfile_contents)
expect(attributes).to contain_exactly(
- "BUNDLED WITH", "CHECKSUMS", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
+ "BUNDLED WITH", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
)
end
end
describe ".unknown_sections_in_lockfile" do
- let(:lockfile_contents) { <<~L }
+ let(:lockfile_contents) { strip_whitespace(<<-L) }
UNKNOWN ATTR
UNKNOWN ATTR 2
@@ -63,7 +60,7 @@ RSpec.describe Bundler::LockfileParser do
it "returns the same as > 1.0" do
expect(subject).to contain_exactly(
- described_class::BUNDLED, described_class::CHECKSUMS, described_class::RUBY, described_class::PLUGIN
+ described_class::BUNDLED, described_class::RUBY, described_class::PLUGIN
)
end
end
@@ -73,7 +70,7 @@ RSpec.describe Bundler::LockfileParser do
it "returns the same as for the release version" do
expect(subject).to contain_exactly(
- described_class::CHECKSUMS, described_class::RUBY, described_class::PLUGIN
+ described_class::RUBY, described_class::PLUGIN
)
end
end
@@ -118,13 +115,6 @@ RSpec.describe Bundler::LockfileParser do
let(:platforms) { [rb] }
let(:bundler_version) { Gem::Version.new("1.12.0.rc.2") }
let(:ruby_version) { "ruby 2.1.3p242" }
- let(:lockfile_path) { Bundler.default_lockfile.relative_path_from(Dir.pwd) }
- let(:rake_checksum) do
- Bundler::Checksum.from_lock(
- "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
- "#{lockfile_path}:20:17"
- )
- end
shared_examples_for "parsing" do
it "parses correctly" do
@@ -135,9 +125,6 @@ RSpec.describe Bundler::LockfileParser do
expect(subject.platforms).to eq platforms
expect(subject.bundler_version).to eq bundler_version
expect(subject.ruby_version).to eq ruby_version
- checksum = subject.sources.last.checksum_store.fetch(specs.last)
- expect(checksum).to be_match(rake_checksum)
- expect(checksum.sources.first.to_s).to match(/the lockfile CHECKSUMS at #{Regexp.escape(lockfile_path.to_s)}:\d+:\d+/)
end
end
@@ -162,57 +149,5 @@ RSpec.describe Bundler::LockfileParser do
let(:lockfile_contents) { super().sub("peiji-san!", "peiji-san!\n foo: bar") }
include_examples "parsing"
end
-
- context "when the checksum is urlsafe base64 encoded" do
- let(:lockfile_contents) do
- super().sub(
- "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
- "sha256=gUgow08TFdfnt-gpUYRXfMTpabrWFWrAadAtY_WNgug="
- )
- end
- include_examples "parsing"
- end
-
- context "when the checksum is of an unknown algorithm" do
- let(:lockfile_contents) do
- super().sub(
- "sha256=",
- "sha512=pVDn9GLmcFkz8vj1ueiVxj5uGKkAyaqYjEX8zG6L5O4BeVg3wANaKbQdpj/B82Nd/MHVszy6polHcyotUdwilQ==,sha256="
- )
- end
- include_examples "parsing"
-
- it "preserves the checksum as is" do
- checksum = subject.sources.last.checksum_store.fetch(specs.last, "sha512")
- expect(checksum.algo).to eq("sha512")
- end
- end
-
- context "when CHECKSUMS has duplicate checksums in the lockfile that don't match" do
- let(:bad_checksum) { "sha256=c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11" }
- let(:lockfile_contents) { super().split(/(?<=CHECKSUMS\n)/m).insert(1, " rake (10.3.2) #{bad_checksum}\n").join }
-
- it "raises a security error" do
- expect { subject }.to raise_error(Bundler::SecurityError) do |e|
- expect(e.message).to match <<~MESSAGE
- Bundler found mismatched checksums. This is a potential security risk.
- rake (10.3.2) #{bad_checksum}
- from the lockfile CHECKSUMS at #{lockfile_path}:20:17
- rake (10.3.2) #{rake_checksum.to_lock}
- from the lockfile CHECKSUMS at #{lockfile_path}:21:17
-
- To resolve this issue you can either:
- 1. remove the matching checksum in #{lockfile_path}:21:17
- 2. run `bundle install`
- or if you are sure that the new checksum from the lockfile CHECKSUMS at #{lockfile_path}:21:17 is correct:
- 1. remove the matching checksum in #{lockfile_path}:20:17
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- MESSAGE
- end
- end
- end
end
end
diff --git a/spec/bundler/bundler/plugin/api/source_spec.rb b/spec/bundler/bundler/plugin/api/source_spec.rb
index ae02e08bea..428ceb220a 100644
--- a/spec/bundler/bundler/plugin/api/source_spec.rb
+++ b/spec/bundler/bundler/plugin/api/source_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Bundler::Plugin::API::Source do
context "to_lock" do
it "returns the string with remote and type" do
- expected = <<~L
+ expected = strip_whitespace <<-L
PLUGIN SOURCE
remote: #{uri}
type: #{type}
@@ -67,7 +67,7 @@ RSpec.describe Bundler::Plugin::API::Source do
end
it "includes them" do
- expected = <<~L
+ expected = strip_whitespace <<-L
PLUGIN SOURCE
remote: #{uri}
type: #{type}
diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb
index 1731a2085e..d28479cf31 100644
--- a/spec/bundler/bundler/plugin_spec.rb
+++ b/spec/bundler/bundler/plugin_spec.rb
@@ -225,7 +225,7 @@ RSpec.describe Bundler::Plugin do
end
end
- describe "#from_lock" do
+ describe "#source_from_lock" do
it "returns instance of registered class initialized with locked opts" do
opts = { "type" => "l_source", "remote" => "xyz", "other" => "random" }
allow(index).to receive(:source_plugin).with("l_source") { "plugin_name" }
@@ -236,7 +236,7 @@ RSpec.describe Bundler::Plugin do
expect(SClass).to receive(:new).
with(hash_including("type" => "l_source", "uri" => "xyz", "other" => "random")) { s_instance }
- expect(subject.from_lock(opts)).to be(s_instance)
+ expect(subject.source_from_lock(opts)).to be(s_instance)
end
end
diff --git a/spec/bundler/bundler/ruby_dsl_spec.rb b/spec/bundler/bundler/ruby_dsl_spec.rb
index c91804d96a..0ba55e949f 100644
--- a/spec/bundler/bundler/ruby_dsl_spec.rb
+++ b/spec/bundler/bundler/ruby_dsl_spec.rb
@@ -21,13 +21,11 @@ RSpec.describe Bundler::RubyDsl do
:engine => engine,
:engine_version => engine_version }
end
- let(:project_root) { Pathname.new("/path/to/project") }
- before { allow(Bundler).to receive(:root).and_return(project_root) }
let(:invoke) do
proc do
args = []
- args << ruby_version_arg if ruby_version_arg
+ args << Array(ruby_version_arg) if ruby_version_arg
args << options
dsl.ruby(*args)
@@ -65,15 +63,6 @@ RSpec.describe Bundler::RubyDsl do
it_behaves_like "it stores the ruby version"
end
- context "with a preview version" do
- let(:ruby_version) { "3.3.0-preview2" }
-
- it "stores the version" do
- expect(subject.versions).to eq(Array("3.3.0.preview2"))
- expect(subject.gem_version.version).to eq("3.3.0.preview2")
- end
- end
-
context "with two requirements in the same string" do
let(:ruby_version) { ">= 2.0.0, < 3.0" }
it "raises an error" do
@@ -108,67 +97,22 @@ RSpec.describe Bundler::RubyDsl do
end
context "with a file option" do
- let(:file) { ".ruby-version" }
- let(:options) do
- { :file => file,
- :patchlevel => patchlevel,
- :engine => engine,
- :engine_version => engine_version }
- end
+ let(:options) { { :file => "foo" } }
+ let(:version) { "3.2.2" }
+ let(:ruby_version) { "3.2.2" }
let(:ruby_version_arg) { nil }
- let(:file_content) { "#{version}\n" }
-
- before do
- allow(Bundler).to receive(:read_file).with(project_root.join(file)).and_return(file_content)
- end
+ let(:engine_version) { version }
+ let(:patchlevel) { nil }
+ let(:engine) { "ruby" }
+ before { allow(Bundler).to receive(:read_file).with("foo").and_return("#{version}\n") }
it_behaves_like "it stores the ruby version"
- context "with the ruby- prefix in the file" do
- let(:file_content) { "ruby-#{version}\n" }
-
- it_behaves_like "it stores the ruby version"
- end
-
context "and a version" do
- let(:ruby_version_arg) { version }
+ let(:ruby_version_arg) { "2.0.0" }
it "raises an error" do
- expect { subject }.to raise_error(Bundler::GemfileError, "Do not pass version argument when using :file option")
- end
- end
-
- context "with a @gemset" do
- let(:file_content) { "ruby-#{version}@gemset\n" }
-
- it "raises an error" do
- expect { subject }.to raise_error(Gem::Requirement::BadRequirementError, "Illformed requirement [\"#{version}@gemset\"]")
- end
- end
-
- context "with a .tool-versions file format" do
- let(:file) { ".tool-versions" }
- let(:ruby_version_arg) { nil }
- let(:file_content) do
- <<~TOOLS
- nodejs 18.16.0
- ruby #{version} # This is a comment
- pnpm 8.6.12
- TOOLS
- end
-
- it_behaves_like "it stores the ruby version"
-
- context "with extra spaces and a very cozy comment" do
- let(:file_content) do
- <<~TOOLS
- nodejs 18.16.0
- ruby #{version}# This is a cozy comment
- pnpm 8.6.12
- TOOLS
- end
-
- it_behaves_like "it stores the ruby version"
+ expect { subject }.to raise_error(Bundler::GemfileError, "Cannot specify version when using the file option")
end
end
end
diff --git a/spec/bundler/bundler/settings/validator_spec.rb b/spec/bundler/bundler/settings/validator_spec.rb
index b252ba59a0..e4ffd89435 100644
--- a/spec/bundler/bundler/settings/validator_spec.rb
+++ b/spec/bundler/bundler/settings/validator_spec.rb
@@ -44,14 +44,14 @@ RSpec.describe Bundler::Settings::Validator do
validate!("without", "b:c", "BUNDLE_WITH" => "a")
end.not_to raise_error
- expect { validate!("with", "b:c", "BUNDLE_WITHOUT" => "c:d") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
+ expect { validate!("with", "b:c", "BUNDLE_WITHOUT" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
Setting `with` to "b:c" failed:
- a group cannot be in both `with` & `without` simultaneously
- `without` is current set to [:c, :d]
- the `c` groups conflict
EOS
- expect { validate!("without", "b:c", "BUNDLE_WITH" => "c:d") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
+ expect { validate!("without", "b:c", "BUNDLE_WITH" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
Setting `without` to "b:c" failed:
- a group cannot be in both `with` & `without` simultaneously
- `with` is current set to [:c, :d]
@@ -74,7 +74,7 @@ RSpec.describe Bundler::Settings::Validator do
describe "#fail!" do
it "raises with a helpful message" do
- expect { subject.fail!("key", "value", "reason1", "reason2") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
+ expect { subject.fail!("key", "value", "reason1", "reason2") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
Setting `key` to "value" failed:
- rule description
- reason1
diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb
index 917f22c10d..3c6536c4eb 100644
--- a/spec/bundler/bundler/shared_helpers_spec.rb
+++ b/spec/bundler/bundler/shared_helpers_spec.rb
@@ -242,7 +242,7 @@ RSpec.describe Bundler::SharedHelpers do
shared_examples_for "ENV['RUBYOPT'] gets set correctly" do
it "ensures -rbundler/setup is at the beginning of ENV['RUBYOPT']" do
subject.set_bundle_environment
- expect(ENV["RUBYOPT"].split(" ")).to start_with("-r#{install_path}/bundler/setup")
+ expect(ENV["RUBYOPT"].split(" ")).to start_with("-r#{source_lib_dir}/bundler/setup")
end
end
@@ -367,41 +367,20 @@ RSpec.describe Bundler::SharedHelpers do
end
end
- context "when bundler install path is standard" do
- let(:install_path) { source_lib_dir }
+ context "ENV['RUBYOPT'] does not exist" do
+ before { ENV.delete("RUBYOPT") }
- context "ENV['RUBYOPT'] does not exist" do
- before { ENV.delete("RUBYOPT") }
-
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
- end
-
- context "ENV['RUBYOPT'] exists without -rbundler/setup" do
- before { ENV["RUBYOPT"] = "-I/some_app_path/lib" }
-
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
- end
-
- context "ENV['RUBYOPT'] exists and contains -rbundler/setup" do
- before { ENV["RUBYOPT"] = "-rbundler/setup" }
-
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
- end
+ it_behaves_like "ENV['RUBYOPT'] gets set correctly"
end
- context "when bundler install path contains special characters" do
- let(:install_path) { "/opt/ruby3.3.0-preview2/lib/ruby/3.3.0+0" }
+ context "ENV['RUBYOPT'] exists without -rbundler/setup" do
+ before { ENV["RUBYOPT"] = "-I/some_app_path/lib" }
- before do
- ENV["RUBYOPT"] = "-r#{install_path}/bundler/setup"
- allow(File).to receive(:expand_path).and_return("#{install_path}/bundler/setup")
- allow(Gem).to receive(:bin_path).and_return("#{install_path}/bundler/setup")
- end
+ it_behaves_like "ENV['RUBYOPT'] gets set correctly"
+ end
- it "ensures -rbundler/setup is not duplicated" do
- subject.set_bundle_environment
- expect(ENV["RUBYOPT"].split(" ").grep(%r{-r.*/bundler/setup}).length).to eq(1)
- end
+ context "ENV['RUBYOPT'] exists and contains -rbundler/setup" do
+ before { ENV["RUBYOPT"] = "-rbundler/setup" }
it_behaves_like "ENV['RUBYOPT'] gets set correctly"
end
diff --git a/spec/bundler/bundler/source/git/git_proxy_spec.rb b/spec/bundler/bundler/source/git/git_proxy_spec.rb
index 457cbea4b6..c79dd8ff71 100644
--- a/spec/bundler/bundler/source/git/git_proxy_spec.rb
+++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb
@@ -3,84 +3,34 @@
RSpec.describe Bundler::Source::Git::GitProxy do
let(:path) { Pathname("path") }
let(:uri) { "https://github.com/rubygems/rubygems.git" }
- let(:ref) { nil }
- let(:branch) { nil }
- let(:tag) { nil }
- let(:options) { { "ref" => ref, "branch" => branch, "tag" => tag }.compact }
+ let(:ref) { "HEAD" }
let(:revision) { nil }
let(:git_source) { nil }
let(:clone_result) { double(Process::Status, :success? => true) }
let(:base_clone_args) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch"] }
- subject(:git_proxy) { described_class.new(path, uri, options, revision, git_source) }
-
- context "with explicit ref" do
- context "with branch only" do
- let(:branch) { "main" }
- it "sets explicit ref to branch" do
- expect(git_proxy.explicit_ref).to eq(branch)
- end
- end
-
- context "with ref only" do
- let(:ref) { "HEAD" }
- it "sets explicit ref to ref" do
- expect(git_proxy.explicit_ref).to eq(ref)
- end
- end
-
- context "with tag only" do
- let(:tag) { "v1.0" }
- it "sets explicit ref to ref" do
- expect(git_proxy.explicit_ref).to eq(tag)
- end
- end
-
- context "with tag and branch" do
- let(:tag) { "v1.0" }
- let(:branch) { "main" }
- it "raises error" do
- expect { git_proxy }.to raise_error(Bundler::Source::Git::AmbiguousGitReference)
- end
- end
-
- context "with tag and ref" do
- let(:tag) { "v1.0" }
- let(:ref) { "HEAD" }
- it "raises error" do
- expect { git_proxy }.to raise_error(Bundler::Source::Git::AmbiguousGitReference)
- end
- end
-
- context "with branch and ref" do
- let(:branch) { "main" }
- let(:ref) { "HEAD" }
- it "honors ref over branch" do
- expect(git_proxy.explicit_ref).to eq(ref)
- end
- end
- end
+ subject { described_class.new(path, uri, ref, revision, git_source) }
context "with configured credentials" do
it "adds username and password to URI" do
Bundler.settings.temporary(uri => "u:p") do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
it "adds username and password to URI for host" do
Bundler.settings.temporary("github.com" => "u:p") do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
it "does not add username and password to mismatched URI" do
Bundler.settings.temporary("https://u:p@github.com/rubygems/rubygems-mismatch.git" => "u:p") do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
@@ -88,10 +38,10 @@ RSpec.describe Bundler::Source::Git::GitProxy do
it "keeps original userinfo" do
Bundler.settings.temporary("github.com" => "u:p") do
original = "https://orig:info@github.com/rubygems/rubygems.git"
- git_proxy = described_class.new(Pathname("path"), original, options)
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", original, path.to_s], nil).and_return(["", "", clone_result])
- git_proxy.checkout
+ subject = described_class.new(Pathname("path"), original, "HEAD")
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", original, path.to_s], nil).and_return(["", "", clone_result])
+ subject.checkout
end
end
end
@@ -99,46 +49,46 @@ RSpec.describe Bundler::Source::Git::GitProxy do
describe "#version" do
context "with a normal version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3")
end
it "returns the git version number" do
- expect(git_proxy.version).to eq("1.2.3")
+ expect(subject.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create git_proxy.version }.not_to raise_error
+ expect { Gem::Version.create subject.version }.not_to raise_error
end
end
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
end
it "strips out OSX specific additions in the version string" do
- expect(git_proxy.version).to eq("1.2.3")
+ expect(subject.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create git_proxy.version }.not_to raise_error
+ expect { Gem::Version.create subject.version }.not_to raise_error
end
end
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3.msysgit.0")
end
it "strips out msysgit specific additions in the version string" do
- expect(git_proxy.version).to eq("1.2.3")
+ expect(subject.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create git_proxy.version }.not_to raise_error
+ expect { Gem::Version.create subject.version }.not_to raise_error
end
end
end
@@ -146,34 +96,34 @@ RSpec.describe Bundler::Source::Git::GitProxy do
describe "#full_version" do
context "with a normal version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3")
end
it "returns the git version number" do
- expect(git_proxy.full_version).to eq("1.2.3")
+ expect(subject.full_version).to eq("1.2.3")
end
end
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
end
it "does not strip out OSX specific additions in the version string" do
- expect(git_proxy.full_version).to eq("1.2.3 (Apple Git-BS)")
+ expect(subject.full_version).to eq("1.2.3 (Apple Git-BS)")
end
end
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3.msysgit.0")
end
it "does not strip out msysgit specific additions in the version string" do
- expect(git_proxy.full_version).to eq("1.2.3.msysgit.0")
+ expect(subject.full_version).to eq("1.2.3.msysgit.0")
end
end
end
diff --git a/spec/bundler/bundler/specifications/foo.gemspec b/spec/bundler/bundler/specifications/foo.gemspec
deleted file mode 100644
index 3628dafc29..0000000000
--- a/spec/bundler/bundler/specifications/foo.gemspec
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable Style/FrozenStringLiteralComment
-# stub: foo 1.0.0 ruby lib
-
-# The first line would be '# -*- encoding: utf-8 -*-' in a real stub gemspec
-
-Gem::Specification.new do |s|
- s.name = "foo"
- s.version = "1.0.0"
- s.loaded_from = __FILE__
- s.extensions = "ext/foo"
- s.required_ruby_version = ">= 2.6.0"
-end
-# rubocop:enable Style/FrozenStringLiteralComment
diff --git a/spec/bundler/bundler/stub_specification_spec.rb b/spec/bundler/bundler/stub_specification_spec.rb
index dae9f3cfba..fb612813c2 100644
--- a/spec/bundler/bundler/stub_specification_spec.rb
+++ b/spec/bundler/bundler/stub_specification_spec.rb
@@ -19,17 +19,6 @@ RSpec.describe Bundler::StubSpecification do
end
end
- describe "#gem_build_complete_path" do
- it "StubSpecification should have equal gem_build_complete_path as Specification" do
- spec_path = File.join(File.dirname(__FILE__), "specifications", "foo.gemspec")
- spec = Gem::Specification.load(spec_path)
- gem_stub = Gem::StubSpecification.new(spec_path, File.dirname(__FILE__),"","")
-
- stub = described_class.from_stub(gem_stub)
- expect(stub.gem_build_complete_path).to eq spec.gem_build_complete_path
- end
- end
-
describe "#manually_installed?" do
it "returns true if installed_by_version is nil or 0" do
stub = described_class.from_stub(with_bundler_stub_spec)
diff --git a/spec/bundler/bundler/yaml_serializer_spec.rb b/spec/bundler/bundler/yaml_serializer_spec.rb
index 913b0235b8..1241c74bbf 100644
--- a/spec/bundler/bundler/yaml_serializer_spec.rb
+++ b/spec/bundler/bundler/yaml_serializer_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Bundler::YAMLSerializer do
it "works for simple hash" do
hash = { "Q" => "Where does Thursday come before Wednesday? In the dictionary. :P" }
- expected = <<~YAML
+ expected = strip_whitespace <<-YAML
---
Q: "Where does Thursday come before Wednesday? In the dictionary. :P"
YAML
@@ -24,7 +24,7 @@ RSpec.describe Bundler::YAMLSerializer do
},
}
- expected = <<~YAML
+ expected = strip_whitespace <<-YAML
---
nice-one:
read_ahead: "All generalizations are false, including this one"
@@ -45,7 +45,7 @@ RSpec.describe Bundler::YAMLSerializer do
},
}
- expected = <<~YAML
+ expected = strip_whitespace <<-YAML
---
nested_hash:
contains_array:
@@ -57,24 +57,11 @@ RSpec.describe Bundler::YAMLSerializer do
expect(serializer.dump(hash)).to eq(expected)
end
-
- it "handles empty array" do
- hash = {
- "empty_array" => [],
- }
-
- expected = <<~YAML
- ---
- empty_array: []
- YAML
-
- expect(serializer.dump(hash)).to eq(expected)
- end
end
describe "#load" do
it "works for simple hash" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
---
Jon: "Air is free dude!"
Jack: "Yes.. until you buy a bag of chips!"
@@ -89,7 +76,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "works for nested hash" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
---
baa:
baa: "black sheep"
@@ -111,7 +98,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles colon in key/value" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/: http://rubygems-mirror.org
YAML
@@ -119,7 +106,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles arrays inside hashes" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
---
nested_hash:
contains_array:
@@ -140,7 +127,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles windows-style CRLF line endings" do
- yaml = <<~YAML.gsub("\n", "\r\n")
+ yaml = strip_whitespace(<<-YAML).gsub("\n", "\r\n")
---
nested_hash:
contains_array:
@@ -161,19 +148,6 @@ RSpec.describe Bundler::YAMLSerializer do
expect(serializer.load(yaml)).to eq(hash)
end
-
- it "handles empty array" do
- yaml = <<~YAML
- ---
- empty_array: []
- YAML
-
- hash = {
- "empty_array" => [],
- }
-
- expect(serializer.load(yaml)).to eq(hash)
- end
end
describe "against yaml lib" do
diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb
index 2f5da4e7e4..63c00eba01 100644
--- a/spec/bundler/cache/gems_spec.rb
+++ b/spec/bundler/cache/gems_spec.rb
@@ -281,30 +281,12 @@ RSpec.describe "bundle cache" do
build_gem "rack", "1.0.0",
:path => bundled_app("vendor/cache"),
:rubygems_version => "1.3.2"
- # This test is only really valid if the checksum isn't saved. It otherwise can't be the same gem. Tested below.
- bundled_app_lock.write remove_checksums_from_lockfile(bundled_app_lock.read, "rack (1.0.0)")
simulate_new_machine
bundle :install
expect(cached_gem("rack-1.0.0")).to exist
end
- it "raises an error when the gem file is altered and produces a different checksum" do
- cached_gem("rack-1.0.0").rmtree
- build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache")
- simulate_new_machine
-
- bundle :install, :raise_on_error => false
- expect(exitstatus).to eq(37)
- expect(err).to include("Bundler found mismatched checksums.")
- expect(err).to include("1. remove the gem at #{cached_gem("rack-1.0.0")}")
-
- expect(cached_gem("rack-1.0.0")).to exist
- cached_gem("rack-1.0.0").rmtree
- bundle :install
- expect(cached_gem("rack-1.0.0")).to exist
- end
-
it "handles directories and non .gem files in the cache" do
bundled_app("vendor/cache/foo").mkdir
File.open(bundled_app("vendor/cache/bar"), "w") {|f| f.write("not a gem") }
diff --git a/spec/bundler/commands/add_spec.rb b/spec/bundler/commands/add_spec.rb
index e1f79274aa..5a5b534e8d 100644
--- a/spec/bundler/commands/add_spec.rb
+++ b/spec/bundler/commands/add_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe "bundle add" do
build_gem "bar", "0.12.3"
build_gem "cat", "0.12.3.pre"
build_gem "dog", "1.1.3.pre"
- build_gem "lemur", "3.1.1.pre.2023.1.1"
end
build_git "foo", "2.0"
@@ -52,13 +51,6 @@ RSpec.describe "bundle add" do
expect(bundled_app_gemfile.read).to match(/gem "dog", "~> 1.1.pre"/)
expect(the_bundle).to include_gems "dog 1.1.3.pre"
end
-
- it "version requirement becomes ~> major.minor.pre.tail when resolved version has a very long tail pre version" do
- bundle "add 'lemur'"
- # the trailing pre purposely matches the release version to ensure that subbing the release doesn't change the pre.version"
- expect(bundled_app_gemfile.read).to match(/gem "lemur", "~> 3.1.pre.2023.1.1"/)
- expect(the_bundle).to include_gems "lemur 3.1.1.pre.2023.1.1"
- end
end
describe "with --version" do
@@ -71,7 +63,7 @@ RSpec.describe "bundle add" do
it "adds multiple version constraints when specified" do
requirements = ["< 3.0", "> 1.0"]
bundle "add 'foo' --version='#{requirements.join(", ")}'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", #{Gem::Requirement.new(requirements).as_list.map(&:dump).join(", ")}/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", #{Gem::Requirement.new(requirements).as_list.map(&:dump).join(', ')}/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -155,7 +147,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified github source", :realworld do
bundle "add rake --github=ruby/rake"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake"})
end
end
@@ -163,7 +155,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified github source and branch", :realworld do
bundle "add rake --github=ruby/rake --branch=master"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :branch => "master"})
end
end
@@ -171,7 +163,7 @@ RSpec.describe "bundle add" do
it "adds dependency with specified github source and ref", :realworld do
bundle "add rake --github=ruby/rake --ref=5c60da8"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :ref => "5c60da8"})
end
end
diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb
index a7ac6148f4..a9ed389233 100644
--- a/spec/bundler/commands/cache_spec.rb
+++ b/spec/bundler/commands/cache_spec.rb
@@ -211,17 +211,7 @@ RSpec.describe "bundle cache" do
end
context "with --all-platforms" do
- it "puts the gems in vendor/cache even for other rubies", :bundler => ">= 2.4.0" do
- gemfile <<-D
- source "#{file_uri_for(gem_repo1)}"
- gem 'rack', :platforms => [:ruby_20, :windows_20]
- D
-
- bundle "cache --all-platforms"
- expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
- end
-
- it "puts the gems in vendor/cache even for legacy windows rubies", :bundler => ">= 2.4.0" do
+ it "puts the gems in vendor/cache even for other rubies" do
gemfile <<-D
source "#{file_uri_for(gem_repo1)}"
gem 'rack', :platforms => [:ruby_20, :x64_mingw_20]
diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb
index dacbd6c45f..99a858e9e9 100644
--- a/spec/bundler/commands/check_spec.rb
+++ b/spec/bundler/commands/check_spec.rb
@@ -425,10 +425,6 @@ RSpec.describe "bundle check" do
DEPENDENCIES
depends_on_rack!
- CHECKSUMS
- depends_on_rack (1.0)
- rack (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -492,11 +488,6 @@ RSpec.describe "bundle check" do
bundle-check-issue!
dex-dispatch-engine!
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "awesome_print", "1.0"}
- bundle-check-issue (9999)
- #{checksum_for_repo_gem gem_repo2, "dex-dispatch-engine", "1.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb
index 62add30252..471cd6c354 100644
--- a/spec/bundler/commands/clean_spec.rb
+++ b/spec/bundler/commands/clean_spec.rb
@@ -905,7 +905,7 @@ RSpec.describe "bundle clean" do
bundle :lock
bundle "config set without development"
bundle "config set path vendor/bundle"
- bundle "install", :verbose => true
+ bundle "install"
bundle :clean
very_simple_binary_extensions_dir =
diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb
index 666b23a141..1afac00923 100644
--- a/spec/bundler/commands/doctor_spec.rb
+++ b/spec/bundler/commands/doctor_spec.rb
@@ -38,11 +38,6 @@ RSpec.describe "bundle doctor" do
allow(stat).to receive(:uid) { Process.uid }
allow(File).to receive(:writable?).with(unwritable_file) { true }
allow(File).to receive(:readable?).with(unwritable_file) { true }
-
- # The following lines are for `Gem::PathSupport#initialize`.
- allow(File).to receive(:exist?).with(Gem.default_dir)
- allow(File).to receive(:writable?).with(Gem.default_dir)
- allow(File).to receive(:writable?).with(File.expand_path("..", Gem.default_dir))
end
it "exits with no message if the installed gem has no C extensions" do
@@ -64,7 +59,7 @@ RSpec.describe "bundle doctor" do
expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"]
allow(Fiddle).to receive(:dlopen).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_raise(Fiddle::DLError)
- expect { doctor.run }.to raise_error(Bundler::ProductionError, <<~E.strip), @stdout.string
+ expect { doctor.run }.to raise_error(Bundler::ProductionError, strip_whitespace(<<-E).strip), @stdout.string
The following gems are missing OS dependencies:
* bundler: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
* rack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb
index 7217c9d61f..099cdb39fa 100644
--- a/spec/bundler/commands/exec_spec.rb
+++ b/spec/bundler/commands/exec_spec.rb
@@ -697,7 +697,7 @@ RSpec.describe "bundle exec" do
context "`load`ing a ruby file instead of `exec`ing" do
let(:path) { bundled_app("ruby_executable") }
let(:shebang) { "#!/usr/bin/env ruby" }
- let(:executable) { <<~RUBY.strip }
+ let(:executable) { <<-RUBY.gsub(/^ */, "").strip }
#{shebang}
require "rack"
@@ -1024,7 +1024,7 @@ __FILE__: #{path.to_s.inspect}
end
context "signals being trapped by bundler" do
- let(:executable) { <<~RUBY }
+ let(:executable) { strip_whitespace <<-RUBY }
#{shebang}
begin
Thread.new do
@@ -1051,7 +1051,7 @@ __FILE__: #{path.to_s.inspect}
end
context "signals not being trapped by bunder" do
- let(:executable) { <<~RUBY }
+ let(:executable) { strip_whitespace <<-RUBY }
#{shebang}
signals = #{test_signals.inspect}
diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb
index c2f55befc3..f572bdf176 100644
--- a/spec/bundler/commands/install_spec.rb
+++ b/spec/bundler/commands/install_spec.rb
@@ -514,6 +514,8 @@ RSpec.describe "bundle install with gem sources" do
end
describe "Ruby version in Gemfile.lock" do
+ include Bundler::GemHelpers
+
context "and using an unsupported Ruby version" do
it "prints an error" do
install_gemfile <<-G, :raise_on_error => false
@@ -543,8 +545,6 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -569,8 +569,6 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -792,71 +790,6 @@ RSpec.describe "bundle install with gem sources" do
end
end
- describe "when gem home does not have the writable bit set, yet it's still writable", :permissions do
- let(:gem_home) { bundled_app("vendor/#{Bundler.ruby_scope}") }
-
- before do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.write "CHANGELOG.md", "foo"
- end
- end
-
- gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem 'foo'
- G
- end
-
- it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
- bundle :install
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
-
- FileUtils.chmod("-w", gem_home)
-
- begin
- bundle "install --redownload"
- ensure
- FileUtils.chmod("+w", gem_home)
- end
-
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
- end
- end
-
- describe "when gems path is world writable (no sticky bit set)", :permissions do
- let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
-
- before do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.write "CHANGELOG.md", "foo"
- end
- end
-
- gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem 'foo'
- G
- end
-
- it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
- bundle :install
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
-
- FileUtils.chmod(0o777, gems_path)
-
- bundle "install --redownload", :raise_on_error => false
-
- expect(err).to include("The installation path is insecure. Bundler cannot continue.")
- end
- end
-
describe "when bundle cache path does not have write access", :permissions do
let(:cache_path) { bundled_app("vendor/#{Bundler.ruby_scope}/cache") }
@@ -957,16 +890,16 @@ RSpec.describe "bundle install with gem sources" do
context "with missing platform specific gems in lockfile" do
before do
build_repo4 do
- build_gem "racca", "1.5.2"
+ build_gem "racc", "1.5.2"
build_gem "nokogiri", "1.12.4" do |s|
s.platform = "x86_64-darwin"
- s.add_runtime_dependency "racca", "~> 1.4"
+ s.add_runtime_dependency "racc", "~> 1.4"
end
build_gem "nokogiri", "1.12.4" do |s|
s.platform = "x86_64-linux"
- s.add_runtime_dependency "racca", "~> 1.4"
+ s.add_runtime_dependency "racc", "~> 1.4"
end
build_gem "crass", "1.0.6"
@@ -985,13 +918,6 @@ RSpec.describe "bundle install with gem sources" do
gem "loofah", "~> 2.12.0"
G
- checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "crass", "1.0.6"
- c.repo_gem gem_repo4, "loofah", "2.12.0"
- c.repo_gem gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
- c.repo_gem gem_repo4, "racca", "1.5.2"
- end
-
lockfile <<-L
GEM
remote: https://gem.repo4/
@@ -1001,8 +927,8 @@ RSpec.describe "bundle install with gem sources" do
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
nokogiri (1.12.4-x86_64-darwin)
- racca (~> 1.4)
- racca (1.5.2)
+ racc (~> 1.4)
+ racc (1.5.2)
PLATFORMS
x86_64-darwin-20
@@ -1011,9 +937,6 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
loofah (~> 2.12.0)
- CHECKSUMS
- #{checksums}
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1029,14 +952,6 @@ RSpec.describe "bundle install with gem sources" do
bundle "install", :artifice => "compact_index"
end
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "crass", "1.0.6"
- c.repo_gem gem_repo4, "loofah", "2.12.0"
- c.repo_gem gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
- c.repo_gem gem_repo4, "nokogiri", "1.12.4", "x86_64-linux"
- c.repo_gem gem_repo4, "racca", "1.5.2"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo4/
@@ -1046,10 +961,10 @@ RSpec.describe "bundle install with gem sources" do
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
nokogiri (1.12.4-x86_64-darwin)
- racca (~> 1.4)
+ racc (~> 1.4)
nokogiri (1.12.4-x86_64-linux)
- racca (~> 1.4)
- racca (1.5.2)
+ racc (~> 1.4)
+ racc (1.5.2)
PLATFORMS
x86_64-darwin-20
@@ -1058,9 +973,6 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
loofah (~> 2.12.0)
- CHECKSUMS
- #{expected_checksums}
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1191,47 +1103,4 @@ RSpec.describe "bundle install with gem sources" do
expect(err).to include("Could not find compatible versions")
end
end
-
- context "when a lockfile has unmet dependencies, and the Gemfile has no resolution" do
- before do
- build_repo4 do
- build_gem "aaa", "0.2.0" do |s|
- s.add_dependency "zzz", "< 0.2.0"
- end
-
- build_gem "zzz", "0.2.0"
- end
-
- gemfile <<~G
- source "#{file_uri_for(gem_repo4)}"
-
- gem "aaa"
- gem "zzz"
- G
-
- lockfile <<~L
- GEM
- remote: #{file_uri_for(gem_repo4)}/
- specs:
- aaa (0.2.0)
- zzz (< 0.2.0)
- zzz (0.2.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- aaa!
- zzz!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "does not install, but raises a resolution error" do
- bundle "install", :raise_on_error => false
- expect(err).to include("Could not find compatible versions")
- end
- end
end
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index fd2462d4f3..491fa30949 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -1,6 +1,14 @@
# frozen_string_literal: true
RSpec.describe "bundle lock" do
+ def strip_lockfile(lockfile)
+ strip_whitespace(lockfile).sub(/\n\Z/, "")
+ end
+
+ def read_lockfile(file = "Gemfile.lock")
+ strip_lockfile bundled_app(file).read
+ end
+
let(:repo) { gem_repo1 }
before :each do
@@ -11,19 +19,7 @@ RSpec.describe "bundle lock" do
gem "foo"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem repo, "actionmailer", "2.3.2"
- c.repo_gem repo, "actionpack", "2.3.2"
- c.repo_gem repo, "activerecord", "2.3.2"
- c.repo_gem repo, "activeresource", "2.3.2"
- c.repo_gem repo, "activesupport", "2.3.2"
- c.repo_gem repo, "foo", "1.0"
- c.repo_gem repo, "rails", "2.3.2"
- c.repo_gem repo, "rake", "13.0.1"
- c.repo_gem repo, "weakling", "0.0.3"
- end
-
- @lockfile = <<~L
+ @lockfile = strip_lockfile(<<-L)
GEM
remote: #{file_uri_for(repo)}/
specs:
@@ -54,9 +50,6 @@ RSpec.describe "bundle lock" do
rails
weakling
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -65,9 +58,7 @@ RSpec.describe "bundle lock" do
it "prints a lockfile when there is no existing lockfile with --print" do
bundle "lock --print"
- # No checksums because no way to get them from a file uri source
- # + no existing lockfile that has them
- expect(out).to eq(remove_checksums_from_lockfile(@lockfile.chomp))
+ expect(out).to eq(@lockfile)
end
it "prints a lockfile when there is an existing lockfile with --print" do
@@ -75,15 +66,13 @@ RSpec.describe "bundle lock" do
bundle "lock --print"
- expect(out).to eq(@lockfile.chomp)
+ expect(out).to eq(@lockfile)
end
it "writes a lockfile when there is no existing lockfile" do
bundle "lock"
- # No checksums because no way to get them from a file uri source
- # + no existing lockfile that has them
- expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile))
+ expect(read_lockfile).to eq(@lockfile)
end
it "writes a lockfile when there is an outdated lockfile using --update" do
@@ -91,16 +80,7 @@ RSpec.describe "bundle lock" do
bundle "lock --update"
- expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile, "(2.3.2)"))
- end
-
- it "writes a lockfile when there is an outdated lockfile using a bundle is frozen" do
- lockfile @lockfile.gsub("2.3.2", "2.3.1")
-
- bundle "lock --update", :env => { "BUNDLE_FROZEN" => "true" }
-
- # No checksums for the updated gems
- expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile, "(2.3.2)"))
+ expect(read_lockfile).to eq(@lockfile)
end
it "does not fetch remote specs when using the --local option" do
@@ -114,7 +94,7 @@ RSpec.describe "bundle lock" do
source "#{file_uri_for(repo)}"
gem "foo"
G
- lockfile = <<~L
+ lockfile = strip_lockfile(<<-L)
GEM
remote: #{file_uri_for(repo)}/
specs:
@@ -126,9 +106,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
foo
- CHECKSUMS
- #{gem_no_checksum "foo", "1.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -143,7 +120,7 @@ RSpec.describe "bundle lock" do
bundle "lock --lockfile=lock"
expect(out).to match(/Writing lockfile to.+lock/)
- expect(read_lockfile("lock")).to eq(remove_checksums_from_lockfile(@lockfile))
+ expect(read_lockfile("lock")).to eq(@lockfile)
expect { read_lockfile }.to raise_error(Errno::ENOENT)
end
@@ -151,58 +128,8 @@ RSpec.describe "bundle lock" do
bundle "install"
bundle "lock --lockfile=lock"
- expected_checksums = checksum_section do |c|
- c.repo_gem repo, "actionmailer", "2.3.2"
- c.repo_gem repo, "actionpack", "2.3.2"
- c.repo_gem repo, "activerecord", "2.3.2"
- c.repo_gem repo, "activeresource", "2.3.2"
- c.repo_gem repo, "activesupport", "2.3.2"
- c.repo_gem repo, "foo", "1.0"
- c.repo_gem repo, "rails", "2.3.2"
- c.repo_gem repo, "rake", "13.0.1"
- c.repo_gem repo, "weakling", "0.0.3"
- end
-
- lockfile = <<~L
- GEM
- remote: #{file_uri_for(repo)}/
- specs:
- actionmailer (2.3.2)
- activesupport (= 2.3.2)
- actionpack (2.3.2)
- activesupport (= 2.3.2)
- activerecord (2.3.2)
- activesupport (= 2.3.2)
- activeresource (2.3.2)
- activesupport (= 2.3.2)
- activesupport (2.3.2)
- foo (1.0)
- rails (2.3.2)
- actionmailer (= 2.3.2)
- actionpack (= 2.3.2)
- activerecord (= 2.3.2)
- activeresource (= 2.3.2)
- rake (= 13.0.1)
- rake (13.0.1)
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
-
- CHECKSUMS
- #{expected_checksums}
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
expect(out).to match(/Writing lockfile to.+lock/)
- expect(read_lockfile("lock")).to eq(lockfile)
+ expect(read_lockfile("lock")).to eq(@lockfile)
end
it "update specific gems using --update" do
@@ -210,17 +137,7 @@ RSpec.describe "bundle lock" do
bundle "lock --update rails rake"
- expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile, "(2.3.2)", "(13.0.1)"))
- end
-
- it "preserves unknown checksum algorithms" do
- lockfile @lockfile.gsub(/(sha256=[a-f0-9]+)$/, "constant=true,\\1,xyz=123")
-
- previous_lockfile = read_lockfile
-
- bundle "lock"
-
- expect(read_lockfile).to eq(previous_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "does not unlock git sources when only uri shape changes" do
@@ -297,7 +214,7 @@ RSpec.describe "bundle lock" do
G
bundle "config set without test"
bundle "config set path vendor/bundle"
- bundle "lock", :verbose => true
+ bundle "lock"
expect(bundled_app("vendor/bundle")).not_to exist
end
@@ -380,47 +297,6 @@ RSpec.describe "bundle lock" do
end
end
- context "conservative updates when minor update adds a new dependency" do
- before do
- build_repo4 do
- build_gem "sequel", "5.71.0"
- build_gem "sequel", "5.72.0" do |s|
- s.add_dependency "bigdecimal", ">= 0"
- end
- build_gem "bigdecimal", %w[1.4.4 99.1.4]
- end
-
- gemfile <<~G
- source "#{file_uri_for(gem_repo4)}"
- gem 'sequel'
- G
-
- lockfile <<~L
- GEM
- remote: #{file_uri_for(gem_repo4)}/
- specs:
- sequel (5.71.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- sequel
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- end
-
- it "adds the latest version of the new dependency" do
- bundle "lock --minor --update sequel"
-
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[sequel-5.72.0 bigdecimal-99.1.4].sort)
- end
- end
-
it "updates the bundler version in the lockfile to the latest bundler version" do
build_repo4 do
build_gem "bundler", "55"
@@ -532,10 +408,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
nokogiri
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.12.0"}
- #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -556,9 +428,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
nokogiri
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -627,12 +496,6 @@ RSpec.describe "bundle lock" do
gssapi
mixlib-shellout
- CHECKSUMS
- #{gem_no_checksum "ffi", "1.9.14", "x86-mingw32"}
- #{gem_no_checksum "gssapi", "1.2.0"}
- #{gem_no_checksum "mixlib-shellout", "2.2.6", "universal-mingw32"}
- #{gem_no_checksum "win32-process", "0.8.3"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -662,14 +525,6 @@ RSpec.describe "bundle lock" do
gssapi
mixlib-shellout
- CHECKSUMS
- #{gem_no_checksum "ffi", "1.9.14"}
- #{gem_no_checksum "ffi", "1.9.14", "x86-mingw32"}
- #{gem_no_checksum "gssapi", "1.2.0"}
- #{gem_no_checksum "mixlib-shellout", "2.2.6"}
- #{gem_no_checksum "mixlib-shellout", "2.2.6", "universal-mingw32"}
- #{gem_no_checksum "win32-process", "0.8.3"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -748,10 +603,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
libv8
- CHECKSUMS
- #{gem_no_checksum "libv8", "8.4.255.0", "x86_64-darwin-19"}
- #{gem_no_checksum "libv8", "8.4.255.0", "x86_64-darwin-20"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -787,10 +638,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
libv8
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-19"}
- #{checksum_for_repo_gem gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -945,128 +792,26 @@ RSpec.describe "bundle lock" do
end
context "when an update is available" do
- let(:repo) do
- build_repo2 do
- build_gem "foo", "2.0"
- end
- gem_repo2
- end
+ let(:repo) { gem_repo2 }
before do
lockfile(@lockfile)
+ build_repo2 do
+ build_gem "foo", "2.0"
+ end
end
it "does not implicitly update" do
bundle "lock"
- expected_checksums = checksum_section do |c|
- c.repo_gem repo, "actionmailer", "2.3.2"
- c.repo_gem repo, "actionpack", "2.3.2"
- c.repo_gem repo, "activerecord", "2.3.2"
- c.repo_gem repo, "activeresource", "2.3.2"
- c.repo_gem repo, "activesupport", "2.3.2"
- c.repo_gem repo, "foo", "1.0"
- c.repo_gem repo, "rails", "2.3.2"
- c.repo_gem repo, "rake", "13.0.1"
- c.repo_gem repo, "weakling", "0.0.3"
- end
-
- expected_lockfile = <<~L
- GEM
- remote: #{file_uri_for(repo)}/
- specs:
- actionmailer (2.3.2)
- activesupport (= 2.3.2)
- actionpack (2.3.2)
- activesupport (= 2.3.2)
- activerecord (2.3.2)
- activesupport (= 2.3.2)
- activeresource (2.3.2)
- activesupport (= 2.3.2)
- activesupport (2.3.2)
- foo (1.0)
- rails (2.3.2)
- actionmailer (= 2.3.2)
- actionpack (= 2.3.2)
- activerecord (= 2.3.2)
- activeresource (= 2.3.2)
- rake (= 13.0.1)
- rake (13.0.1)
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
-
- CHECKSUMS
- #{expected_checksums}
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "accounts for changes in the gemfile" do
gemfile gemfile.gsub('"foo"', '"foo", "2.0"')
bundle "lock"
- expected_checksums = checksum_section do |c|
- c.repo_gem repo, "actionmailer", "2.3.2"
- c.repo_gem repo, "actionpack", "2.3.2"
- c.repo_gem repo, "activerecord", "2.3.2"
- c.repo_gem repo, "activeresource", "2.3.2"
- c.repo_gem repo, "activesupport", "2.3.2"
- c.no_checksum "foo", "2.0"
- c.repo_gem repo, "rails", "2.3.2"
- c.repo_gem repo, "rake", "13.0.1"
- c.repo_gem repo, "weakling", "0.0.3"
- end
-
- expected_lockfile = <<~L
- GEM
- remote: #{file_uri_for(repo)}/
- specs:
- actionmailer (2.3.2)
- activesupport (= 2.3.2)
- actionpack (2.3.2)
- activesupport (= 2.3.2)
- activerecord (2.3.2)
- activesupport (= 2.3.2)
- activeresource (2.3.2)
- activesupport (= 2.3.2)
- activesupport (2.3.2)
- foo (2.0)
- rails (2.3.2)
- actionmailer (= 2.3.2)
- actionpack (= 2.3.2)
- activerecord (= 2.3.2)
- activeresource (= 2.3.2)
- rake (= 13.0.1)
- rake (13.0.1)
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo (= 2.0)
- rails
- weakling
-
- CHECKSUMS
- #{expected_checksums}
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile.sub("foo (1.0)", "foo (2.0)").sub(/foo$/, "foo (= 2.0)"))
end
end
@@ -1111,8 +856,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
debug
- CHECKSUMS
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1136,10 +879,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
debug
- CHECKSUMS
- #{gem_no_checksum "debug", "1.6.3"}
- #{gem_no_checksum "irb", "1.5.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1443,10 +1182,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum "foo", "1.0"}
- #{gem_no_checksum "nokogiri", "1.14.2"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1530,12 +1265,6 @@ RSpec.describe "bundle lock" do
activesupport (= 7.0.4.3)
govuk_app_config
- CHECKSUMS
- #{gem_no_checksum "actionpack", "7.0.4.3"}
- #{gem_no_checksum "activesupport", "7.0.4.3"}
- #{gem_no_checksum "govuk_app_config", "4.13.0"}
- #{gem_no_checksum "railties", "7.0.4.3"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb
index 310306b21a..ede1ff6b8e 100644
--- a/spec/bundler/commands/newgem_spec.rb
+++ b/spec/bundler/commands/newgem_spec.rb
@@ -651,7 +651,7 @@ RSpec.describe "bundle gem" do
system_gems ["rake-13.0.1"]
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
task :default do
puts 'SUCCESS'
end
@@ -797,7 +797,7 @@ RSpec.describe "bundle gem" do
end
it "creates a default rake task to run the test suite" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -855,7 +855,7 @@ RSpec.describe "bundle gem" do
end
it "creates a default rake task to run the test suite" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -960,12 +960,6 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
-
- it "contained .gitlab-ci.yml into ignore list" do
- bundle "gem #{gem_name} --ci=github"
-
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .github appveyor")
- end
end
context "--ci set to gitlab" do
@@ -974,12 +968,6 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
end
-
- it "contained .gitlab-ci.yml into ignore list" do
- bundle "gem #{gem_name} --ci=gitlab"
-
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .gitlab-ci.yml appveyor")
- end
end
context "--ci set to circle" do
@@ -988,12 +976,6 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
end
-
- it "contained .circleci into ignore list" do
- bundle "gem #{gem_name} --ci=circle"
-
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .circleci appveyor")
- end
end
context "gem.ci setting set to none" do
@@ -1437,7 +1419,7 @@ RSpec.describe "bundle gem" do
end
it "depends on compile task for build" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -1445,9 +1427,7 @@ RSpec.describe "bundle gem" do
task build: :compile
- GEMSPEC = Gem::Specification.load("#{gem_name}.gemspec")
-
- Rake::ExtensionTask.new("#{gem_name}", GEMSPEC) do |ext|
+ Rake::ExtensionTask.new("#{gem_name}") do |ext|
ext.lib_dir = "lib/#{gem_name}"
end
@@ -1497,7 +1477,7 @@ RSpec.describe "bundle gem" do
end
it "depends on compile task for build" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -1505,9 +1485,7 @@ RSpec.describe "bundle gem" do
task build: :compile
- GEMSPEC = Gem::Specification.load("#{gem_name}.gemspec")
-
- RbSys::ExtensionTask.new("#{gem_name}", GEMSPEC) do |ext|
+ RbSys::ExtensionTask.new("#{gem_name}") do |ext|
ext.lib_dir = "lib/#{gem_name}"
end
@@ -1605,7 +1583,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
expect(bundled_app("foobar/spec/spec_helper.rb")).to exist
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
diff --git a/spec/bundler/commands/open_spec.rb b/spec/bundler/commands/open_spec.rb
index 6ec64dd842..e30ebfea5b 100644
--- a/spec/bundler/commands/open_spec.rb
+++ b/spec/bundler/commands/open_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe "bundle open" do
input.puts "2"
end
- expect(out).to match(%r{bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}/CHANGELOG\.md\z})
+ expect(out).to match(%r{bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}/CHANGELOG\.md\z})
end
it "opens deep subpath of the selected matching gem", :readline do
@@ -113,7 +113,7 @@ RSpec.describe "bundle open" do
input.puts "2"
end
- expect(out).to match(%r{bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/activerecord/version\.rb\z})
+ expect(out).to match(%r{bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}/lib/activerecord/version\.rb\z})
end
it "select the gem from many match gems", :readline do
@@ -122,7 +122,7 @@ RSpec.describe "bundle open" do
input.puts "2"
end
- expect(out).to match(/bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}\z/)
+ expect(out).to match(/bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}\z/)
end
it "allows selecting exit from many match gems", :readline do
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index 8e48758c04..84042709bf 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -290,17 +290,13 @@ RSpec.describe "bundle update" do
countries
country_select
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo4, "countries", "3.1.0")}
- #{checksum_for_repo_gem(gem_repo4, "country_select", "5.1.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
L
previous_lockfile = lockfile
- bundle "lock --update", :env => { "DEBUG" => "1" }, :verbose => true
+ bundle "lock --update"
expect(lockfile).to eq(previous_lockfile)
end
@@ -509,11 +505,6 @@ RSpec.describe "bundle update" do
original_lockfile = lockfile
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "activesupport", "6.0.4.1"
- c.repo_gem gem_repo4, "tzinfo", "1.2.9"
- end
-
expected_lockfile = <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
@@ -528,9 +519,6 @@ RSpec.describe "bundle update" do
DEPENDENCIES
activesupport (~> 6.0.0)
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -539,10 +527,6 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("activesupport 6.0.4.1", "tzinfo 1.2.9")
expect(lockfile).to eq(expected_lockfile)
- # needed because regressing to versions already present on the system
- # won't add a checksum
- expected_lockfile = remove_checksums_from_lockfile(expected_lockfile)
-
lockfile original_lockfile
bundle "update"
expect(the_bundle).to include_gems("activesupport 6.0.4.1", "tzinfo 1.2.9")
@@ -1144,8 +1128,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1177,8 +1159,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1219,8 +1199,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
ruby 2.1.4p222
@@ -1246,8 +1224,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1268,25 +1244,6 @@ RSpec.describe "bundle update --bundler" do
source "#{file_uri_for(gem_repo4)}"
gem "rack"
G
- expected_checksum = checksum_for_repo_gem(gem_repo4, "rack", "1.0")
- expect(lockfile).to eq <<~L
- GEM
- remote: #{file_uri_for(gem_repo4)}/
- specs:
- rack (1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- rack
-
- CHECKSUMS
- #{expected_checksum}
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
bundle :update, :bundler => true, :artifice => "compact_index", :verbose => true
@@ -1304,9 +1261,6 @@ RSpec.describe "bundle update --bundler" do
DEPENDENCIES
rack
- CHECKSUMS
- #{expected_checksum}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1342,9 +1296,6 @@ RSpec.describe "bundle update --bundler" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo4, "rack", "1.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1448,9 +1399,6 @@ RSpec.describe "bundle update --bundler" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo4, "rack", "1.0")}
-
BUNDLED WITH
2.3.0.dev
L
@@ -1471,7 +1419,7 @@ RSpec.describe "bundle update --bundler" do
gem "rack"
G
- bundle :update, :bundler => "2.3.9", :verbose => true
+ bundle :update, :bundler => "2.3.9", :raise_on_error => false, :verbose => true
expect(out).not_to include("Fetching gem metadata from https://rubygems.org/")
@@ -1490,9 +1438,6 @@ RSpec.describe "bundle update --bundler" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo4, "rack", "1.0")}
-
BUNDLED WITH
2.3.9
L
@@ -1683,8 +1628,6 @@ RSpec.describe "bundle update conservative" do
shared_owner_a
shared_owner_b
- CHECKSUMS
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1738,13 +1681,6 @@ RSpec.describe "bundle update conservative" do
shared_owner_a
shared_owner_b
- CHECKSUMS
- isolated_dep (2.0.1)
- isolated_owner (1.0.2)
- shared_dep (5.0.1)
- shared_owner_a (3.0.2)
- shared_owner_b (4.0.2)
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/commands/viz_spec.rb b/spec/bundler/commands/viz_spec.rb
index b25683bfb3..cf612397ab 100644
--- a/spec/bundler/commands/viz_spec.rb
+++ b/spec/bundler/commands/viz_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot"), :re
expect(out).to include("gem_graph.png")
bundle "viz", :format => "debug"
- expect(out).to eq(<<~DOT.strip)
+ expect(out).to eq(strip_whitespace(<<-DOT).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -50,7 +50,7 @@ RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot"), :re
expect(out).to include("gem_graph.png")
bundle "viz", :format => :debug, :version => true
- expect(out).to eq(<<~EOS.strip)
+ expect(out).to eq(strip_whitespace(<<-EOS).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -88,7 +88,7 @@ RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot"), :re
G
bundle "viz", :format => "debug"
- expect(out).to eq(<<~DOT.strip)
+ expect(out).to eq(strip_whitespace(<<-DOT).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
diff --git a/spec/bundler/install/allow_offline_install_spec.rb b/spec/bundler/install/allow_offline_install_spec.rb
index 75c7aa9085..4c6c77a61e 100644
--- a/spec/bundler/install/allow_offline_install_spec.rb
+++ b/spec/bundler/install/allow_offline_install_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
def break_git_remote_ops!
FileUtils.mkdir_p(tmp("broken_path"))
File.open(tmp("broken_path/git"), "w", 0o755) do |f|
- f.puts <<~RUBY
+ f.puts strip_whitespace(<<-RUBY)
#!/usr/bin/env ruby
fetch_args = %w(fetch --force --quiet)
clone_args = %w(clone --bare --no-hardlinks --quiet)
diff --git a/spec/bundler/install/bundler_spec.rb b/spec/bundler/install/bundler_spec.rb
index a0d5332e96..e7ec3bc7e7 100644
--- a/spec/bundler/install/bundler_spec.rb
+++ b/spec/bundler/install/bundler_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe "bundle install" do
gem "bundler", "0.9.1"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler = 0.9.1
@@ -56,7 +56,7 @@ RSpec.describe "bundle install" do
gem "bundler", "~> 0.8"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because rails >= 3.0 depends on bundler >= 0.9.0.pre
@@ -79,7 +79,7 @@ RSpec.describe "bundle install" do
gem "bundler", "0.9.2"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler = 0.9.2
@@ -149,7 +149,7 @@ RSpec.describe "bundle install" do
gem "rails_pinned_to_old_activesupport"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because every version of rails_pinned_to_old_activesupport depends on activesupport = 1.2.3
@@ -177,7 +177,7 @@ RSpec.describe "bundle install" do
gem "activesupport", "2.3.5"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because every version of rails_pinned_to_old_activesupport depends on activesupport = 1.2.3
diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb
index f7b41595be..2a88ed5b06 100644
--- a/spec/bundler/install/deploy_spec.rb
+++ b/spec/bundler/install/deploy_spec.rb
@@ -11,12 +11,12 @@ RSpec.describe "install in deployment or frozen mode" do
context "with CLI flags", :bundler => "< 3" do
it "fails without a lockfile and says that --deployment requires a lock" do
bundle "install --deployment", :raise_on_error => false
- expect(err).to include("The --deployment flag requires a lockfile")
+ expect(err).to include("The --deployment flag requires a Gemfile.lock")
end
it "fails without a lockfile and says that --frozen requires a lock" do
bundle "install --frozen", :raise_on_error => false
- expect(err).to include("The --frozen flag requires a lockfile")
+ expect(err).to include("The --frozen flag requires a Gemfile.lock")
end
it "disallows --deployment --system" do
@@ -506,15 +506,15 @@ RSpec.describe "install in deployment or frozen mode" do
G
run "require 'rack'", :raise_on_error => false
- expect(err).to include <<~E.strip
- The dependencies in your gemfile changed, but the lockfile can't be updated because frozen mode is set (Bundler::ProductionError)
+ expect(err).to include strip_whitespace(<<-E).strip
+The dependencies in your gemfile changed, but the lockfile can't be updated because frozen mode is set (Bundler::ProductionError)
- You have added to the Gemfile:
- * rack (= 1.0.0)
- * rack-obama
+You have added to the Gemfile:
+* rack (= 1.0.0)
+* rack-obama
- You have deleted from the Gemfile:
- * rack
+You have deleted from the Gemfile:
+* rack
E
end
end
diff --git a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
index dbdadb7faa..0e9f1f0292 100644
--- a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
+++ b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
@@ -114,33 +114,5 @@ RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
expect(the_bundle).to include_gems "depends_on_platform_specific 1.0.0 RUBY"
expect(the_bundle).to include_gems "platform_specific 1.0.0 #{Bundler.local_platform}"
end
-
- it "reinstalls the ruby variant when a platform specific variant is already installed, the lockile has only RUBY platform, and :force_ruby_platform is used in the Gemfile" do
- lockfile <<-L
- GEM
- remote: #{file_uri_for(gem_repo4)}
- specs:
- platform_specific (1.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- platform_specific
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- system_gems "platform_specific-1.0-#{Gem::Platform.local}", :path => default_bundle_path
-
- install_gemfile <<-G, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, :artifice => "compact_index"
- source "#{file_uri_for(gem_repo4)}"
-
- gem "platform_specific", :force_ruby_platform => true
- G
-
- expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
- end
end
end
diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb
index ae53130bf3..73f04f071d 100644
--- a/spec/bundler/install/gemfile/gemspec_spec.rb
+++ b/spec/bundler/install/gemfile/gemspec_spec.rb
@@ -28,16 +28,6 @@ RSpec.describe "bundle install from an existing gemspec" do
x64_mingw_archs.join("\n ")
end
- let(:x64_mingw_checksums) do
- x64_mingw_archs.map do |arch|
- if arch == "x64-mingw-ucrt"
- gem_no_checksum "platform_specific", "1.0", arch
- else
- checksum_for_repo_gem gem_repo2, "platform_specific", "1.0", arch
- end
- end.join("\n ")
- end
-
it "should install runtime and development dependencies" do
build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
@@ -95,7 +85,7 @@ RSpec.describe "bundle install from an existing gemspec" do
source "#{file_uri_for(gem_repo2)}"
gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are no gemspecs at #{tmp.join("foo")}/)
+ expect(err).to match(/There are no gemspecs at #{tmp.join('foo')}/)
end
it "should raise if there are too many gemspecs available" do
@@ -107,7 +97,7 @@ RSpec.describe "bundle install from an existing gemspec" do
source "#{file_uri_for(gem_repo2)}"
gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are multiple gemspecs at #{tmp.join("foo")}/)
+ expect(err).to match(/There are multiple gemspecs at #{tmp.join('foo')}/)
end
it "should pick a specific gemspec" do
@@ -458,8 +448,7 @@ RSpec.describe "bundle install from an existing gemspec" do
context "as a runtime dependency" do
it "keeps all platform dependencies in the lockfile" do
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
-
- expect(lockfile).to eq <<~L
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
@@ -481,12 +470,6 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
- #{checksum_for_repo_gem gem_repo2, "platform_specific", "1.0"}
- #{checksum_for_repo_gem gem_repo2, "platform_specific", "1.0", "java"}
- #{x64_mingw_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -498,8 +481,7 @@ RSpec.describe "bundle install from an existing gemspec" do
it "keeps all platform dependencies in the lockfile" do
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
-
- expect(lockfile).to eq <<~L
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
@@ -521,12 +503,6 @@ RSpec.describe "bundle install from an existing gemspec" do
foo!
platform_specific
- CHECKSUMS
- foo (1.0)
- #{checksum_for_repo_gem gem_repo2, "platform_specific", "1.0"}
- #{checksum_for_repo_gem gem_repo2, "platform_specific", "1.0", "java"}
- #{x64_mingw_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -539,8 +515,7 @@ RSpec.describe "bundle install from an existing gemspec" do
it "keeps all platform dependencies in the lockfile" do
expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY"
-
- expect(lockfile).to eq <<~L
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
@@ -564,13 +539,6 @@ RSpec.describe "bundle install from an existing gemspec" do
foo!
indirect_platform_specific
- CHECKSUMS
- foo (1.0)
- #{checksum_for_repo_gem gem_repo2, "indirect_platform_specific", "1.0"}
- #{checksum_for_repo_gem gem_repo2, "platform_specific", "1.0"}
- #{checksum_for_repo_gem gem_repo2, "platform_specific", "1.0", "java"}
- #{x64_mingw_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -655,11 +623,6 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
chef!
- CHECKSUMS
- chef (17.1.17)
- chef (17.1.17-universal-mingw32)
- #{checksum_for_repo_gem gem_repo4, "win32-api", "1.5.3", "universal-mingw32"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -717,11 +680,6 @@ RSpec.describe "bundle install from an existing gemspec" do
activeadmin!
jruby-openssl
- CHECKSUMS
- activeadmin (2.9.0)
- jruby-openssl (0.10.7-java)
- #{checksum_for_repo_gem gem_repo4, "railties", "6.1.4"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb
index b07afaaffb..910f96f4ab 100644
--- a/spec/bundler/install/gemfile/git_spec.rb
+++ b/spec/bundler/install/gemfile/git_spec.rb
@@ -572,7 +572,7 @@ RSpec.describe "bundle install with git sources" do
bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install, :raise_on_error => false
- expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path("local-rack").to_s)} does not exist/)
+ expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
solution = "config unset local.rack"
expect(err).to match(/Run `bundle #{solution}` to remove the local override/)
@@ -594,7 +594,7 @@ RSpec.describe "bundle install with git sources" do
bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install, :raise_on_error => false
- expect(err).to match(/Cannot use local override for rack-0.8 at #{Regexp.escape(lib_path("local-rack").to_s)} because :branch is not specified in Gemfile/)
+ expect(err).to match(/Cannot use local override for rack-0.8 at #{Regexp.escape(lib_path('local-rack').to_s)} because :branch is not specified in Gemfile/)
solution = "config unset local.rack"
expect(err).to match(/Specify a branch or run `bundle #{solution}` to remove the local override/)
diff --git a/spec/bundler/install/gemfile/install_if_spec.rb b/spec/bundler/install/gemfile/install_if_spec.rb
index c8ddb685ff..3d2d15a698 100644
--- a/spec/bundler/install/gemfile/install_if_spec.rb
+++ b/spec/bundler/install/gemfile/install_if_spec.rb
@@ -37,12 +37,6 @@ RSpec.describe "bundle install with install_if conditionals" do
rack
thin
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo1, "activesupport", "2.3.5"}
- #{gem_no_checksum "foo", "1.0"}
- #{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
- #{gem_no_checksum "thin", "1.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb
index 3af8412eab..a5207036c3 100644
--- a/spec/bundler/install/gemfile/path_spec.rb
+++ b/spec/bundler/install/gemfile/path_spec.rb
@@ -120,10 +120,6 @@ RSpec.describe "bundle install with explicit source paths" do
aaa!
demo!
- CHECKSUMS
- #{gem_no_checksum("aaa", "1.0")}
- #{gem_no_checksum("demo", "1.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -363,10 +359,6 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum("foo", "0.1.0")}
- #{checksum_for_repo_gem(gem_repo4, "graphql", "2.0.15")}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -691,10 +683,6 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum("foo", "1.0")}
- #{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -723,10 +711,6 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum("foo", "1.0")}
- #{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -761,10 +745,6 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum("foo", "1.0")}
- #{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -796,11 +776,6 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum("foo", "1.0")}
- #{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
- #{checksum_for_repo_gem(gem_repo1, "rake", "13.0.1")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -849,10 +824,6 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- CHECKSUMS
- #{gem_no_checksum("foo", "1.0")}
- #{gem_no_checksum("rack", "0.9.1")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb
index 918a49e1e1..219ae6c2f4 100644
--- a/spec/bundler/install/gemfile/platform_spec.rb
+++ b/spec/bundler/install/gemfile/platform_spec.rb
@@ -225,14 +225,6 @@ RSpec.describe "bundle install across platforms" do
empyrean (= 0.1.0)
pry
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "coderay", "1.1.2"}
- #{checksum_for_repo_gem gem_repo4, "empyrean", "0.1.0"}
- #{checksum_for_repo_gem gem_repo4, "ffi", "1.9.23", "java"}
- #{checksum_for_repo_gem gem_repo4, "method_source", "0.9.0"}
- #{checksum_for_repo_gem gem_repo4, "pry", "0.11.3", "java"}
- #{checksum_for_repo_gem gem_repo4, "spoon", "0.0.6"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -265,15 +257,6 @@ RSpec.describe "bundle install across platforms" do
empyrean (= 0.1.0)
pry
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "coderay", "1.1.2"}
- #{checksum_for_repo_gem gem_repo4, "empyrean", "0.1.0"}
- #{checksum_for_repo_gem gem_repo4, "ffi", "1.9.23", "java"}
- #{checksum_for_repo_gem gem_repo4, "method_source", "0.9.0"}
- pry (0.11.3)
- #{checksum_for_repo_gem gem_repo4, "pry", "0.11.3", "java"}
- #{checksum_for_repo_gem gem_repo4, "spoon", "0.0.6"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -307,14 +290,6 @@ RSpec.describe "bundle install across platforms" do
empyrean (= 0.1.0)
pry
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "coderay", "1.1.2"}
- #{checksum_for_repo_gem gem_repo4, "empyrean", "0.1.0"}
- #{checksum_for_repo_gem gem_repo4, "ffi", "1.9.23", "java"}
- #{checksum_for_repo_gem gem_repo4, "method_source", "0.9.0"}
- #{checksum_for_repo_gem gem_repo4, "pry", "0.11.3", "java"}
- #{checksum_for_repo_gem gem_repo4, "spoon", "0.0.6"}
-
BUNDLED WITH
1.16.1
L
@@ -424,10 +399,6 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
platform_specific
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo1, "platform_specific", "1.0")}
- #{gem_no_checksum "platform_specific", "1.0", "java"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -579,7 +550,7 @@ RSpec.describe "bundle install with platform conditionals" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :platform => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby]
+ gem "rack", :platform => [:windows, :mingw, :mswin, :x64_mingw, :jruby]
G
bundle "install"
@@ -597,8 +568,6 @@ RSpec.describe "bundle install with platform conditionals" do
DEPENDENCIES
rack
- CHECKSUMS
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index 64eed1a2f4..dd86187a6b 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -27,55 +27,18 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "refuses to install mismatched checksum because one gem has been tampered with", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do
+ bundle :install, :artifice => "compact_index"
- expect(exitstatus).to eq(37)
- expect(err).to eq <<~E.strip
- [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
- Bundler found mismatched checksums. This is a potential security risk.
- #{checksum_for_repo_gem(gem_repo1, "rack", "1.0.0")}
- from the API at https://gem.repo1/
- #{checksum_for_repo_gem(gem_repo3, "rack", "1.0.0")}
- from the API at https://gem.repo3/
-
- Mismatched checksums each have an authoritative source:
- 1. the API at https://gem.repo1/
- 2. the API at https://gem.repo3/
- You may need to alter your Gemfile sources to resolve this issue.
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(err).to include("Installed from: https://gem.repo1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
end
- context "when checksum validation is disabled" do
- before do
- bundle "config set --local disable_checksum_validation true"
- end
-
- it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
-
- expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
- end
-
- it "does not use the full index unnecessarily", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index", :verbose => true
-
- expect(out).to include("https://gem.repo1/versions")
- expect(out).to include("https://gem.repo3/versions")
- expect(out).not_to include("https://gem.repo1/quick/Marshal.4.8/")
- expect(out).not_to include("https://gem.repo3/quick/Marshal.4.8/")
- end
-
- it "fails", :bundler => "3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include("Each source after the first must include a block")
- expect(exitstatus).to eq(4)
- end
+ it "fails", :bundler => "3" do
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
+ expect(err).to include("Each source after the first must include a block")
+ expect(exitstatus).to eq(4)
end
end
@@ -106,34 +69,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "without source affinity, and a stdlib gem present in one of the sources", :ruby_repo do
- let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
-
- before do
- build_repo2 do
- build_gem "json", default_json_version
- end
-
- build_repo4 do
- build_gem "foo" do |s|
- s.add_dependency "json", default_json_version
- end
- end
-
- gemfile <<-G
- source "https://gem.repo2"
- source "https://gem.repo4"
-
- gem "foo"
- G
- end
-
- it "works in standalone mode", :bundler => "< 3" do
- gem_checksum = checksum_for_repo_gem(gem_repo4, "foo", "1.0").split(Bundler::Checksum::ALGO_SEPARATOR).last
- bundle "install --standalone", :artifice => "compact_index", :env => { "BUNDLER_SPEC_FOO_CHECKSUM" => gem_checksum }
- end
- end
-
context "with source affinity" do
context "with sources given by a block" do
before do
@@ -308,106 +243,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "fails when the two sources don't have the same checksum", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
-
- expect(err).to eq(<<~E.strip)
- [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
- Bundler found mismatched checksums. This is a potential security risk.
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
- from the API at https://gem.repo2/
- #{checksum_for_repo_gem(gem_repo1, "rack", "1.0.0")}
- from the API at https://gem.repo1/
-
- Mismatched checksums each have an authoritative source:
- 1. the API at https://gem.repo2/
- 2. the API at https://gem.repo1/
- You may need to alter your Gemfile sources to resolve this issue.
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
- expect(exitstatus).to eq(37)
- end
-
- it "fails when the two sources agree, but the local gem calculates a different checksum", :bundler => "< 3" do
- rack_checksum = "c0ffee11" * 8
- bundle :install, :artifice => "compact_index", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => rack_checksum }, :raise_on_error => false
-
- expect(err).to eq(<<~E.strip)
- [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
- Bundler found mismatched checksums. This is a potential security risk.
- rack (1.0.0) sha256=#{rack_checksum}
- from the API at https://gem.repo2/
- and the API at https://gem.repo1/
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
- from the gem at #{default_bundle_path("cache", "rack-1.0.0.gem")}
-
- If you trust the API at https://gem.repo2/, to resolve this issue you can:
- 1. remove the gem at #{default_bundle_path("cache", "rack-1.0.0.gem")}
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
- expect(exitstatus).to eq(37)
- end
-
- it "installs from the other source and warns about ambiguous gems when the sources have the same checksum", :bundler => "< 3" do
- gem_checksum = checksum_for_repo_gem(gem_repo2, "rack", "1.0.0").split(Bundler::Checksum::ALGO_SEPARATOR).last
- bundle :install, :artifice => "compact_index", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => gem_checksum, "DEBUG" => "1" }
-
- expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo2")
-
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo3, "depends_on_rack", "1.0.1"
- c.repo_gem gem_repo2, "rack", "1.0.0"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo1/
- remote: https://gem.repo2/
- specs:
- rack (1.0.0)
-
- GEM
- remote: https://gem.repo3/
- specs:
- depends_on_rack (1.0.1)
- rack
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- depends_on_rack!
-
- CHECKSUMS
- #{expected_checksums}
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- previous_lockfile = lockfile
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
- expect(lockfile).to eq(previous_lockfile)
- end
-
- it "installs from the other source and warns about ambiguous gems when checksum validation is disabled", :bundler => "< 3" do
- bundle "config set --local disable_checksum_validation true"
+ it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do
bundle :install, :artifice => "compact_index"
-
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: https://gem.repo2")
- expected_checksums = checksum_section do |c|
- c.no_checksum "depends_on_rack", "1.0.1"
- c.no_checksum "rack", "1.0.0"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo1/
@@ -427,9 +267,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
DEPENDENCIES
depends_on_rack!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -825,21 +662,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "activesupport", "6.0.3.4"
- c.repo_gem gem_repo2, "concurrent-ruby", "1.1.8"
- c.repo_gem gem_repo2, "connection_pool", "2.2.3"
- c.repo_gem gem_repo2, "i18n", "1.8.9"
- c.repo_gem gem_repo2, "minitest", "5.14.3"
- c.repo_gem gem_repo2, "rack", "2.2.3"
- c.repo_gem gem_repo2, "redis", "4.2.5"
- c.repo_gem gem_repo2, "sidekiq", "6.1.3"
- c.repo_gem gem_repo3, "sidekiq-pro", "5.2.1"
- c.repo_gem gem_repo2, "thread_safe", "0.3.6"
- c.repo_gem gem_repo2, "tzinfo", "1.2.9"
- c.repo_gem gem_repo2, "zeitwerk", "2.4.2"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -880,9 +702,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
activesupport
sidekiq-pro!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -928,20 +747,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "activesupport", "6.1.2.1"
- c.repo_gem gem_repo2, "concurrent-ruby", "1.1.9"
- c.repo_gem gem_repo2, "connection_pool", "2.2.3"
- c.repo_gem gem_repo2, "i18n", "1.8.9"
- c.repo_gem gem_repo2, "minitest", "5.14.3"
- c.repo_gem gem_repo2, "rack", "2.2.3"
- c.repo_gem gem_repo2, "redis", "4.2.5"
- c.repo_gem gem_repo2, "sidekiq", "6.1.3"
- c.repo_gem gem_repo3, "sidekiq-pro", "5.2.1"
- c.repo_gem gem_repo2, "tzinfo", "2.0.4"
- c.repo_gem gem_repo2, "zeitwerk", "2.4.2"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -981,9 +786,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
activesupport
sidekiq-pro!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1000,21 +802,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "activesupport", "6.0.3.4"
- c.repo_gem gem_repo2, "concurrent-ruby", "1.1.9"
- c.repo_gem gem_repo2, "connection_pool", "2.2.3"
- c.repo_gem gem_repo2, "i18n", "1.8.9"
- c.repo_gem gem_repo2, "minitest", "5.14.3"
- c.repo_gem gem_repo2, "rack", "2.2.3"
- c.repo_gem gem_repo2, "redis", "4.2.5"
- c.repo_gem gem_repo2, "sidekiq", "6.1.3"
- c.repo_gem gem_repo3, "sidekiq-pro", "5.2.1"
- c.repo_gem gem_repo2, "thread_safe", "0.3.6"
- c.repo_gem gem_repo2, "tzinfo", "1.2.9"
- c.repo_gem gem_repo2, "zeitwerk", "2.4.2"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -1055,9 +842,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
activesupport
sidekiq-pro!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1125,12 +909,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the default source without any warnings or errors and generates a proper lockfile" do
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo3, "handsoap", "0.2.5.5"
- c.repo_gem gem_repo2, "nokogiri", "1.11.1"
- c.repo_gem gem_repo2, "racca", "1.5.2"
- end
-
expected_lockfile = <<~L
GEM
remote: https://gem.repo2/
@@ -1152,9 +930,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
handsoap!
nokogiri
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1286,9 +1061,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
lockfile aggregate_gem_section_lockfile
end
- it "installs the existing lockfile but prints a warning when checksum validation is disabled", :bundler => "< 3" do
+ it "installs the existing lockfile but prints a warning", :bundler => "< 3" do
bundle "config set --local deployment true"
- bundle "config set --local disable_checksum_validation true"
bundle "install", :artifice => "compact_index"
@@ -1297,37 +1071,10 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3")
end
- it "prints a checksum warning when the checksums from both sources do not match", :bundler => "< 3" do
- bundle "config set --local deployment true"
-
- bundle "install", :artifice => "compact_index", :raise_on_error => false
-
- api_checksum1 = checksum_for_repo_gem(gem_repo1, "rack", "0.9.1").split("sha256=").last
- api_checksum3 = checksum_for_repo_gem(gem_repo3, "rack", "0.9.1").split("sha256=").last
-
- expect(exitstatus).to eq(37)
- expect(err).to eq(<<~E.strip)
- [DEPRECATED] Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.
- Bundler found mismatched checksums. This is a potential security risk.
- rack (0.9.1) sha256=#{api_checksum3}
- from the API at https://gem.repo3/
- rack (0.9.1) sha256=#{api_checksum1}
- from the API at https://gem.repo1/
-
- Mismatched checksums each have an authoritative source:
- 1. the API at https://gem.repo3/
- 2. the API at https://gem.repo1/
- You may need to alter your Gemfile sources to resolve this issue.
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
- end
-
it "refuses to install the existing lockfile and prints an error", :bundler => "3" do
bundle "config set --local deployment true"
- bundle "install", :artifice => "compact_index", :raise_on_error => false
+ bundle "install", :artifice => "compact_index", :raise_on_error =>false
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -1627,7 +1374,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
gem "thin"
end
G
- expect(err).to eq <<~EOS.strip
+ expect(err).to eq strip_whitespace(<<-EOS).strip
Warning: The gem 'rack' was found in multiple relevant sources.
* rubygems repository https://gem.repo1/
* rubygems repository https://gem.repo4/
@@ -1657,7 +1404,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
expect(last_command).to be_failure
- expect(err).to eq <<~EOS.strip
+ expect(err).to eq strip_whitespace(<<-EOS).strip
The gem 'rack' was found in multiple relevant sources.
* rubygems repository https://gem.repo1/
* rubygems repository https://gem.repo4/
@@ -1706,19 +1453,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
-
- CHECKSUMS
L
end
it "upgrades the lockfile correctly" do
bundle "lock --update", :artifice => "compact_index"
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "capybara", "2.5.0"
- c.repo_gem gem_repo4, "mime-types", "3.0.0"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -1738,9 +1478,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
capybara (~> 2.5.0)
mime-types (~> 3.0)!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1794,10 +1531,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
DEPENDENCIES
ruport (= 1.7.0.3)!
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "pdf-writer", "1.1.8"}
- #{checksum_for_repo_gem gem_repo2, "ruport", "1.7.0.3"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1833,11 +1566,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "handles that fine" do
bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "pdf-writer", "1.1.8"
- c.repo_gem gem_repo2, "ruport", "1.7.0.3"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://localgemserver.test/
@@ -1856,9 +1584,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
DEPENDENCIES
ruport (= 1.7.0.3)!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1888,10 +1613,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "handles that fine" do
bundle "install --verbose", :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "pdf-writer", "1.1.8"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://localgemserver.test/
@@ -1904,9 +1625,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
DEPENDENCIES
pdf-writer (= 1.1.8)
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb
index d4e2f25179..cab53a663a 100644
--- a/spec/bundler/install/gemfile/specific_platform_spec.rb
+++ b/spec/bundler/install/gemfile/specific_platform_spec.rb
@@ -79,9 +79,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
- CHECKSUMS
- google-protobuf (3.0.0.alpha.4.0)
-
BUNDLED WITH
2.1.4
L
@@ -104,9 +101,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
- CHECKSUMS
- google-protobuf (3.0.0.alpha.5.0.5.1)
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -528,13 +522,6 @@ RSpec.describe "bundle install with specific platforms" do
bundle "update"
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "sorbet", "0.5.10160"
- c.repo_gem gem_repo4, "sorbet-runtime", "0.5.10160"
- c.repo_gem gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
- c.repo_gem gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
@@ -553,9 +540,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static-and-runtime
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -625,10 +609,6 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
sorbet-static
- CHECKSUMS
- #{gem_no_checksum "nokogiri", "1.13.0", "x86_64-darwin"}
- #{gem_no_checksum "sorbet-static", "0.5.10601", "x86_64-darwin"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -682,13 +662,6 @@ RSpec.describe "bundle install with specific platforms" do
bundle "update"
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "sorbet", "0.5.10160"
- c.repo_gem gem_repo4, "sorbet-runtime", "0.5.10160"
- c.repo_gem gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
- c.repo_gem gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
@@ -707,86 +680,11 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static-and-runtime
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "automatically fixes the lockfile if multiple platforms locked, but no valid versions of direct dependencies for all of them" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "x86_64-linux"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "arm-linux"
- end
-
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<~G
- source "#{file_uri_for(gem_repo4)}"
-
- gem "nokogiri"
- gem "sorbet-static"
- G
-
- lockfile <<~L
- GEM
- remote: #{file_uri_for(gem_repo4)}/
- specs:
- nokogiri (1.14.0-arm-linux)
- nokogiri (1.14.0-x86_64-linux)
- sorbet-static (0.5.10696-x86_64-linux)
-
- PLATFORMS
- arm-linux
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sorbet-static
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "update"
-
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
- c.repo_gem gem_repo4, "sorbet-static", "0.5.10696", "x86_64-linux"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: #{file_uri_for(gem_repo4)}/
- specs:
- nokogiri (1.14.0-x86_64-linux)
- sorbet-static (0.5.10696-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sorbet-static
-
- CHECKSUMS
- #{expected_checksums}
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
it "automatically fixes the lockfile without removing other variants if it's missing platform gems, but they are installed locally" do
simulate_platform "x86_64-darwin-21" do
build_repo4 do
@@ -819,10 +717,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static (= 0.5.10549)
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-20"}
- #{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-21"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -842,10 +736,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static (= 0.5.10549)
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-20"}
- #{gem_no_checksum "sorbet-static", "0.5.10549", "universal-darwin-21"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -882,8 +772,6 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri
tzinfo (~> 1.2)
- CHECKSUMS
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -892,29 +780,7 @@ RSpec.describe "bundle install with specific platforms" do
bundle "lock --update"
- updated_lockfile = <<~L
- GEM
- remote: #{file_uri_for(gem_repo4)}/
- specs:
- nokogiri (1.13.8)
- nokogiri (1.13.8-#{Gem::Platform.local})
-
- PLATFORMS
- #{lockfile_platforms("ruby")}
-
- DEPENDENCIES
- nokogiri
- tzinfo (~> 1.2)
-
- CHECKSUMS
- #{gem_no_checksum "nokogiri", "1.13.8"}
- #{gem_no_checksum "nokogiri", "1.13.8", Gem::Platform.local}
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- expect(lockfile).to eq(updated_lockfile)
+ expect(lockfile).to eq(original_lockfile)
end
it "does not remove ruby when adding a new gem to the Gemfile" do
@@ -962,10 +828,6 @@ RSpec.describe "bundle install with specific platforms" do
concurrent-ruby
rack
- CHECKSUMS
- #{gem_no_checksum "concurrent-ruby", "1.2.2"}
- #{gem_no_checksum "rack", "3.0.7"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1058,9 +920,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri (= 1.14.0)
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.14.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb
index 305d253def..65be262748 100644
--- a/spec/bundler/install/gems/compact_index_spec.rb
+++ b/spec/bundler/install/gems/compact_index_spec.rb
@@ -289,7 +289,7 @@ The checksum of /versions does not match the checksum provided by the server! So
system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0], :gem_repo => gem_repo2
bundle "config set --local path.system true"
- ENV["BUNDLER_SPEC_ALL_REQUESTS"] = <<~EOS.strip
+ ENV["BUNDLER_SPEC_ALL_REQUESTS"] = strip_whitespace(<<-EOS).strip
#{source_uri}/versions
#{source_uri}/info/rack
EOS
@@ -876,47 +876,24 @@ The checksum of /versions does not match the checksum provided by the server! So
end
describe "checksum validation" do
- it "handles checksums from the server in base64" do
- api_checksum = checksum_for_repo_gem(gem_repo1, "rack", "1.0.0").split("sha256=").last
- rack_checksum = [[api_checksum].pack("H*")].pack("m0")
- install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => rack_checksum }
- source "#{source_uri}"
- gem "rack"
- G
-
- expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems("rack 1.0.0")
- end
-
it "raises when the checksum does not match" do
install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :raise_on_error => false
source "#{source_uri}"
gem "rack"
G
- api_checksum = checksum_for_repo_gem(gem_repo1, "rack", "1.0.0").split("sha256=").last
-
- gem_path = if Bundler.feature_flag.global_gem_cache?
- default_cache_path.dirname.join("cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "rack-1.0.0.gem")
- else
- default_cache_path.dirname.join("rack-1.0.0.gem")
- end
-
- expect(exitstatus).to eq(37)
- expect(err).to eq <<~E.strip
- Bundler found mismatched checksums. This is a potential security risk.
- rack (1.0.0) sha256=2222222222222222222222222222222222222222222222222222222222222222
- from the API at http://localgemserver.test/
- rack (1.0.0) sha256=#{api_checksum}
- from the gem at #{gem_path}
-
- If you trust the API at http://localgemserver.test/, to resolve this issue you can:
- 1. remove the gem at #{gem_path}
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
+ expect(exitstatus).to eq(19)
+ expect(err).
+ to include("Bundler cannot continue installing rack (1.0.0).").
+ and include("The checksum for the downloaded `rack-1.0.0.gem` does not match the checksum given by the server.").
+ and include("This means the contents of the downloaded gem is different from what was uploaded to the server, and could be a potential security issue.").
+ and include("To resolve this issue:").
+ and include("1. delete the downloaded gem located at: `#{default_bundle_path}/gems/rack-1.0.0/rack-1.0.0.gem`").
+ and include("2. run `bundle install`").
+ and include("If you wish to continue installing the downloaded gem, and are certain it does not pose a security issue despite the mismatching checksum, do the following:").
+ and include("1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification").
+ and include("2. run `bundle install`").
+ and match(/\(More info: The expected SHA256 checksum was "#{"ab" * 22}", but the checksum for the downloaded gem was ".+?"\.\)/)
end
it "raises when the checksum is the wrong length" do
@@ -924,8 +901,8 @@ The checksum of /versions does not match the checksum provided by the server! So
source "#{source_uri}"
gem "rack"
G
- expect(exitstatus).to eq(14)
- expect(err).to include('Invalid checksum for rack-0.9.1: "checksum!" is not a valid SHA256 hex or base64 digest')
+ expect(exitstatus).to eq(5)
+ expect(err).to include("The given checksum for rack-1.0.0 (\"checksum!\") is not a valid SHA256 hexdigest nor base64digest")
end
it "does not raise when disable_checksum_validation is set" do
@@ -972,6 +949,6 @@ Running `bundle update rails` should fix the problem.
G
gem_command "uninstall activemerchant"
bundle "update rails", :artifice => "compact_index"
- expect(lockfile.scan(/activemerchant \(/).size).to eq(2) # Once in the specs, and once in CHECKSUMS
+ expect(lockfile.scan(/activemerchant \(/).size).to eq(1)
end
end
diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb
index 484ec1f839..d5fa55be48 100644
--- a/spec/bundler/install/gems/flex_spec.rb
+++ b/spec/bundler/install/gems/flex_spec.rb
@@ -193,7 +193,7 @@ RSpec.describe "bundle flex_install" do
it "discards the locked gems when the Gemfile requires different versions than the lock" do
bundle "config set force_ruby_platform true"
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because rack-obama >= 2.0 depends on rack = 1.2
@@ -210,7 +210,7 @@ RSpec.describe "bundle flex_install" do
it "does not include conflicts with a single requirement tree, because that can't possibly be a conflict" do
bundle "config set force_ruby_platform true"
- bad_error = <<~E.strip
+ bad_error = <<-E.strip.gsub(/^ {8}/, "")
Bundler could not find compatible versions for gem "rack-obama":
In Gemfile:
rack-obama (= 2.0)
@@ -283,10 +283,6 @@ RSpec.describe "bundle flex_install" do
rack (= 0.9.1)
rack-obama
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo1, "rack", "0.9.1"}
- #{checksum_for_repo_gem gem_repo1, "rack-obama", "1.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -328,9 +324,6 @@ RSpec.describe "bundle flex_install" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb
index b9f928a0db..fb6dda2f88 100644
--- a/spec/bundler/install/gems/resolving_spec.rb
+++ b/spec/bundler/install/gems/resolving_spec.rb
@@ -106,7 +106,7 @@ RSpec.describe "bundle install with install-time dependencies" do
path = "#{gem_repo2}/#{Gem::MARSHAL_SPEC_DIR}/actionpack-2.3.2.gemspec.rz"
spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path)))
spec.dependencies.each do |d|
- d.instance_variable_set(:@type, "fail")
+ d.instance_variable_set(:@type, :fail)
end
File.open(path, "wb") do |f|
f.write Gem.deflate(Marshal.dump(spec))
@@ -288,9 +288,6 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
parallel_tests
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo2, "parallel_tests", "3.7.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -371,10 +368,6 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
rubocop
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo2, "rubocop", "1.28.2"}
- #{checksum_for_repo_gem gem_repo2, "rubocop-ast", "1.17.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -422,8 +415,8 @@ RSpec.describe "bundle install with install-time dependencies" do
bundle "install", :raise_on_error => false
end
- nice_error = <<~E.strip
- Could not find gems matching 'sorbet-static (= 0.5.10554)' valid for all resolution platforms (arm64-darwin-21, aarch64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
+ nice_error = strip_whitespace(<<-E).strip
+ Could not find gem 'sorbet-static (= 0.5.10554)' with platforms 'arm64-darwin-21', 'aarch64-linux' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
The source contains the following gems matching 'sorbet-static (= 0.5.10554)':
* sorbet-static-0.5.10554-universal-darwin-21
@@ -432,62 +425,6 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- context "when adding a new gem that does not resolve under all locked platforms" do
- before do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "x86_64-linux"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "arm-linux"
- end
-
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- lockfile <<~L
- GEM
- remote: #{file_uri_for(gem_repo4)}/
- specs:
- nokogiri (1.14.0-arm-linux)
- nokogiri (1.14.0-x86_64-linux)
-
- PLATFORMS
- arm-linux
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- gemfile <<~G
- source "#{file_uri_for(gem_repo4)}"
-
- gem "nokogiri"
- gem "sorbet-static"
- G
-
- bundle "lock", :raise_on_error => false
- end
- end
-
- it "raises a proper error" do
- nice_error = <<~E.strip
- Could not find gems matching 'sorbet-static' valid for all resolution platforms (arm-linux, x86_64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
-
- The source contains the following gems matching 'sorbet-static':
- * sorbet-static-0.5.10696-x86_64-linux
- E
- expect(err).to end_with(nice_error)
- end
- end
-
it "gives a meaningful error on ruby version mismatches between dependencies" do
build_repo4 do
build_gem "requires-old-ruby" do |s|
@@ -584,7 +521,7 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
- nice_error = <<~E.strip
+ nice_error = strip_whitespace(<<-E).strip
Could not find compatible versions
Because every version of require_ruby depends on Ruby > 9000
@@ -606,7 +543,7 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
- nice_error = <<~E.strip
+ nice_error = strip_whitespace(<<-E).strip
Could not find compatible versions
Because every version of require_ruby depends on Ruby > 9000
@@ -650,7 +587,7 @@ RSpec.describe "bundle install with install-time dependencies" do
G
expect(err).to_not include("Gem::InstallError: require_rubygems requires RubyGems version > 9000")
- nice_error = <<~E.strip
+ nice_error = strip_whitespace(<<-E).strip
Because every version of require_rubygems depends on RubyGems > 9000
and Gemfile depends on require_rubygems >= 0,
RubyGems > 9000 is required.
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb
index edb7a0e6bc..4d08752256 100644
--- a/spec/bundler/install/gems/standalone_spec.rb
+++ b/spec/bundler/install/gems/standalone_spec.rb
@@ -101,22 +101,6 @@ RSpec.shared_examples "bundle install --standalone" do
expect(out).to eq(expected_gems.values.join("\n"))
end
-
- it "skips activating gems" do
- testrb = String.new <<-RUBY
- $:.unshift File.expand_path("bundle")
- require "bundler/setup"
-
- gem "do_not_activate_me"
- RUBY
- expected_gems.each do |k, _|
- testrb << "\nrequire \"#{k}\""
- testrb << "\nputs #{k.upcase}"
- end
- sys_exec %(#{Gem.ruby} -w -e #{testrb.shellescape})
-
- expect(out).to eq(expected_gems.values.join("\n"))
- end
end
describe "with simple gems" do
diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb
index 954fd39efe..882f2a2d42 100644
--- a/spec/bundler/install/git_spec.rb
+++ b/spec/bundler/install/git_spec.rb
@@ -170,36 +170,5 @@ RSpec.describe "bundle install" do
expect(out).to include("Bundle complete!")
end
-
- it "allows older revisions of git source when clean true" do
- build_git "foo", "1.0", :path => lib_path("foo")
- rev = revision_for(lib_path("foo"))
-
- bundle "config set path vendor/bundle"
- bundle "config set clean true"
- install_gemfile <<-G, :verbose => true
- source "#{file_uri_for(gem_repo1)}"
- gem "foo", :git => "#{file_uri_for(lib_path("foo"))}"
- G
-
- expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{rev[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
-
- old_lockfile = lockfile
-
- update_git "foo", "2.0", :path => lib_path("foo"), :gemspec => true
- rev2 = revision_for(lib_path("foo"))
-
- bundle :update, :all => true, :verbose => true
- expect(out).to include("Using foo 2.0 (was 1.0) from #{file_uri_for(lib_path("foo"))} (at main@#{rev2[0..6]})")
- expect(out).to include("Removing foo (#{rev[0..11]})")
- expect(the_bundle).to include_gems "foo 2.0", :source => "git@#{lib_path("foo")}"
-
- lockfile(old_lockfile)
-
- bundle :install, :verbose => true
- expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{rev[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
- end
end
end
diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb
index 338a187472..dc054b50bb 100644
--- a/spec/bundler/install/yanked_spec.rb
+++ b/spec/bundler/install/yanked_spec.rb
@@ -160,10 +160,6 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
bar
foo
- CHECKSUMS
- #{gem_no_checksum "bar", "2.0.0"}
- #{gem_no_checksum "foo", "9.0.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb
index f81b34b6d3..ccf23a9e3c 100644
--- a/spec/bundler/lock/lockfile_spec.rb
+++ b/spec/bundler/lock/lockfile_spec.rb
@@ -24,9 +24,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -78,9 +75,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -146,9 +140,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{version}
L
@@ -174,9 +165,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{version}
G
@@ -214,9 +202,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (> 0)
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -264,9 +249,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{current_version}
G
@@ -279,11 +261,6 @@ RSpec.describe "the lockfile format" do
gem "rack-obama"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "rack", "1.0.0"
- c.repo_gem gem_repo2, "rack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -298,9 +275,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -313,11 +287,6 @@ RSpec.describe "the lockfile format" do
gem "rack-obama", ">= 1.0"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "rack", "1.0.0"
- c.repo_gem gem_repo2, "rack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -332,9 +301,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -355,11 +321,6 @@ RSpec.describe "the lockfile format" do
end
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "rack", "1.0.0"
- c.repo_gem gem_repo2, "rack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo1)}/
@@ -382,9 +343,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -396,11 +354,6 @@ RSpec.describe "the lockfile format" do
gem "net-sftp"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "net-sftp", "1.1.1"
- c.repo_gem gem_repo2, "net-ssh", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -415,9 +368,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
net-sftp
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -450,9 +400,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -524,9 +471,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -559,9 +503,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -594,9 +535,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -683,10 +621,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
ckeditor!
- CHECKSUMS
- #{gem_no_checksum "ckeditor", "4.0.8"}
- #{gem_no_checksum "orm_adapter", "0.4.1"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -716,9 +650,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -752,9 +683,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -797,11 +725,6 @@ RSpec.describe "the lockfile format" do
foo!
rack
- CHECKSUMS
- bar (1.0)
- foo (1.0)
- #{checksum_for_repo_gem gem_repo2, "rack", "1.0.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -814,10 +737,6 @@ RSpec.describe "the lockfile format" do
gem "rack", :source => "#{file_uri_for(gem_repo2)}/"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "rack", "1.0.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -830,9 +749,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack!
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -847,14 +763,6 @@ RSpec.describe "the lockfile format" do
gem "rack-obama"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "actionpack", "2.3.2"
- c.repo_gem gem_repo2, "activesupport", "2.3.2"
- c.repo_gem gem_repo2, "rack", "1.0.0"
- c.repo_gem gem_repo2, "rack-obama", "1.0"
- c.repo_gem gem_repo2, "thin", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -876,9 +784,6 @@ RSpec.describe "the lockfile format" do
rack-obama
thin
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -891,16 +796,6 @@ RSpec.describe "the lockfile format" do
gem "rails"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "actionmailer", "2.3.2"
- c.repo_gem gem_repo2, "actionpack", "2.3.2"
- c.repo_gem gem_repo2, "activerecord", "2.3.2"
- c.repo_gem gem_repo2, "activeresource", "2.3.2"
- c.repo_gem gem_repo2, "activesupport", "2.3.2"
- c.repo_gem gem_repo2, "rails", "2.3.2"
- c.repo_gem gem_repo2, "rake", "13.0.1"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -928,9 +823,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rails
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -952,11 +844,6 @@ RSpec.describe "the lockfile format" do
gem 'double_deps'
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "double_deps", "1.0"
- c.repo_gem gem_repo2, "net-ssh", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -972,9 +859,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
double_deps
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -987,11 +871,6 @@ RSpec.describe "the lockfile format" do
gem "rack-obama", ">= 1.0", :require => "rack/obama"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "rack", "1.0.0"
- c.repo_gem gem_repo2, "rack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -1006,9 +885,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1021,11 +897,6 @@ RSpec.describe "the lockfile format" do
gem "rack-obama", ">= 1.0", :group => :test
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "rack", "1.0.0"
- c.repo_gem gem_repo2, "rack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -1040,9 +911,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1074,9 +942,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1108,9 +973,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1142,9 +1004,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1174,9 +1033,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- CHECKSUMS
- foo (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1217,9 +1073,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1239,10 +1092,6 @@ RSpec.describe "the lockfile format" do
gem "platform_specific"
G
- expected_checksums = checksum_section do |c|
- c.repo_gem gem_repo2, "platform_specific", "1.0", "universal-java-16"
- end
-
expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -1255,9 +1104,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
platform_specific
- CHECKSUMS
- #{expected_checksums}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1289,10 +1135,6 @@ RSpec.describe "the lockfile format" do
activesupport
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "activesupport", "2.3.5")}
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1317,9 +1159,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1344,9 +1183,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (= 1.0)
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1371,9 +1207,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (= 1.0)
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "1.0.0")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1419,9 +1252,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (> 0.9, < 1.0)
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "0.9.1")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1446,9 +1276,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (> 0.9, < 1.0)
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo2, "rack", "0.9.1")}
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1526,10 +1353,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
direct_dependency
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo4, "direct_dependency", "4.5.6")}
- #{checksum_for_repo_gem(gem_repo4, "indirect_dependency", "1.2.3")}
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1584,10 +1407,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
minitest-bisect
- CHECKSUMS
- #{checksum_for_repo_gem(gem_repo4, "minitest-bisect", "1.6.0")}
- #{checksum_for_repo_gem(gem_repo4, "path_expander", "1.1.1")}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1654,10 +1473,6 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
minitest-bisect
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "minitest-bisect", "1.6.0"}
- #{checksum_for_repo_gem gem_repo4, "path_expander", "1.1.1"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb
index 993a890b6c..9d153b6063 100644
--- a/spec/bundler/plugins/source/example_spec.rb
+++ b/spec/bundler/plugins/source/example_spec.rb
@@ -87,9 +87,6 @@ RSpec.describe "real source plugins" do
DEPENDENCIES
a-path-gem!
- CHECKSUMS
- a-path-gem (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -357,9 +354,6 @@ RSpec.describe "real source plugins" do
DEPENDENCIES
ma-gitp-gem!
- CHECKSUMS
- ma-gitp-gem (1.0)
-
BUNDLED WITH
#{Bundler::VERSION}
G
diff --git a/spec/bundler/plugins/uninstall_spec.rb b/spec/bundler/plugins/uninstall_spec.rb
index 555c6a7002..8180241911 100644
--- a/spec/bundler/plugins/uninstall_spec.rb
+++ b/spec/bundler/plugins/uninstall_spec.rb
@@ -30,31 +30,6 @@ RSpec.describe "bundler plugin uninstall" do
plugin_should_not_be_installed("foo")
end
- it "doesn't wipe out path plugins" do
- build_lib "path_plugin" do |s|
- s.write "plugins.rb"
- end
- path = lib_path("path_plugin-1.0")
- expect(path).to be_a_directory
-
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
-
- install_gemfile <<-G
- source '#{file_uri_for(gem_repo2)}'
- plugin 'path_plugin', :path => "#{path}"
- gem 'rack', '1.0.0'
- G
-
- plugin_should_be_installed("path_plugin")
- expect(Bundler::Plugin.index.plugin_path("path_plugin")).to eq path
-
- bundle "plugin uninstall path_plugin"
- expect(out).to include("Uninstalled plugin path_plugin")
- plugin_should_not_be_installed("path_plugin")
- # the actual gem still exists though
- expect(path).to be_a_directory
- end
-
describe "with --all" do
it "uninstalls all installed plugins" do
bundle "plugin install foo kung-foo --source #{file_uri_for(gem_repo2)}"
diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb
index 6b010fe872..a98815158e 100644
--- a/spec/bundler/quality_spec.rb
+++ b/spec/bundler/quality_spec.rb
@@ -40,14 +40,16 @@ RSpec.describe "The library itself" do
"#{filename} has spaces on the EOL on lines #{failing_lines.join(", ")}"
end
- def check_for_extraneous_quotes(filename)
+ def check_for_straneous_quotes(filename)
+ return if File.expand_path(filename) == __FILE__
+
failing_lines = []
each_line(filename) do |line, number|
- failing_lines << number + 1 if /\u{2019}/.match?(line)
+ failing_lines << number + 1 if /’/.match?(line)
end
return if failing_lines.empty?
- "#{filename} has an extraneous quote on lines #{failing_lines.join(", ")}"
+ "#{filename} has an straneous quote on lines #{failing_lines.join(", ")}"
end
def check_for_expendable_words(filename)
@@ -94,12 +96,12 @@ RSpec.describe "The library itself" do
expect(error_messages.compact).to be_well_formed
end
- it "has no extraneous quotes" do
+ it "has no estraneous quotes" do
exempt = /vendor|vcr_cassettes|LICENSE|rbreadline\.diff/
error_messages = []
tracked_files.each do |filename|
next if filename&.match?(exempt)
- error_messages << check_for_extraneous_quotes(filename)
+ error_messages << check_for_straneous_quotes(filename)
end
expect(error_messages.compact).to be_well_formed
end
diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb
index 6c523556fb..2f465b7b25 100644
--- a/spec/bundler/realworld/edgecases_spec.rb
+++ b/spec/bundler/realworld/edgecases_spec.rb
@@ -8,10 +8,9 @@ RSpec.describe "real world edgecases", :realworld => true do
require "bundler/source/rubygems/remote"
require "bundler/fetcher"
rubygem = Bundler.ui.silence do
- remote = Bundler::Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org"))
- source = Bundler::Source::Rubygems.new
- fetcher = Bundler::Fetcher.new(remote)
- index = fetcher.specs([#{name.dump}], source)
+ source = Bundler::Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org"))
+ fetcher = Bundler::Fetcher.new(source)
+ index = fetcher.specs([#{name.dump}], nil)
requirement = Gem::Requirement.create(#{requirement.dump})
index.search(#{name.dump}).select {|spec| requirement.satisfied_by?(spec.version) }.last
end
@@ -324,7 +323,7 @@ RSpec.describe "real world edgecases", :realworld => true do
if Bundler.feature_flag.bundler_3_mode?
# Conflicts on bundler version, so we count attempts differently
bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }, :raise_on_error => false
- expect(out.split("\n").grep(/backtracking to/).count).to eq(8)
+ expect(out.split("\n").grep(/backtracking to/).count).to eq(16)
else
bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
expect(out).to include("Solution found after 7 attempts")
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
index 5b476f8df2..8f29bd341f 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
@@ -27,4 +27,4 @@ DEPENDENCIES
warbler (~> 2.0)
BUNDLED WITH
- 2.5.0.dev
+ 2.4.0.dev
diff --git a/spec/bundler/resolver/basic_spec.rb b/spec/bundler/resolver/basic_spec.rb
index 4a0dd37bf9..f739f8c02b 100644
--- a/spec/bundler/resolver/basic_spec.rb
+++ b/spec/bundler/resolver/basic_spec.rb
@@ -100,22 +100,13 @@ RSpec.describe "Resolving" do
end
it "raises an exception if a child dependency is not resolved" do
- @index = a_unresolvable_child_index
+ @index = a_unresovable_child_index
dep "chef_app_error"
expect do
resolve
end.to raise_error(Bundler::SolveFailure)
end
- it "does not try to re-resolve including prereleases if gems involved don't have prereleases" do
- @index = a_unresolvable_child_index
- dep "chef_app_error"
- expect(Bundler.ui).not_to receive(:debug).with("Retrying resolution...", any_args)
- expect do
- resolve
- end.to raise_error(Bundler::SolveFailure)
- end
-
it "raises an exception with the minimal set of conflicting dependencies" do
@index = build_index do
%w[0.9 1.0 2.0].each {|v| gem("a", v) }
@@ -356,27 +347,4 @@ RSpec.describe "Resolving" do
should_resolve_as %w[rack-3.0.0 standalone_migrations-1.0.13]
end
-
- it "does not ignore versions that incorrectly depend on themselves when dependency_api is not available" do
- @index = build_index do
- gem "rack", "3.0.0"
-
- gem "standalone_migrations", "7.1.0" do
- dep "rack", "~> 2.0"
- end
-
- gem "standalone_migrations", "2.0.4" do
- dep "standalone_migrations", ">= 2.0.5"
- end
-
- gem "standalone_migrations", "1.0.13" do
- dep "rack", ">= 0"
- end
- end
-
- dep "rack", "~> 3.0"
- dep "standalone_migrations"
-
- should_resolve_without_dependency_api %w[rack-3.0.0 standalone_migrations-2.0.4]
- end
end
diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb
index 31d93a559f..a9933f90e9 100644
--- a/spec/bundler/runtime/platform_spec.rb
+++ b/spec/bundler/runtime/platform_spec.rb
@@ -61,16 +61,16 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
build_repo4 do
build_gem "nokogiri", "1.11.1" do |s|
s.add_dependency "mini_portile2", "~> 2.5.0"
- s.add_dependency "racca", "~> 1.5.2"
+ s.add_dependency "racc", "~> 1.5.2"
end
build_gem "nokogiri", "1.11.1" do |s|
s.platform = Bundler.local_platform
- s.add_dependency "racca", "~> 1.4"
+ s.add_dependency "racc", "~> 1.4"
end
build_gem "mini_portile2", "2.5.0"
- build_gem "racca", "1.5.2"
+ build_gem "racc", "1.5.2"
end
good_lockfile = <<~L
@@ -80,10 +80,10 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
mini_portile2 (2.5.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
- racca (~> 1.5.2)
+ racc (~> 1.5.2)
nokogiri (1.11.1-#{Bundler.local_platform})
- racca (~> 1.4)
- racca (1.5.2)
+ racc (~> 1.4)
+ racc (1.5.2)
PLATFORMS
#{lockfile_platforms("ruby")}
@@ -91,12 +91,6 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
DEPENDENCIES
nokogiri (~> 1.11)
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo4, "mini_portile2", "2.5.0"}
- #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.11.1"}
- #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.11.1", Bundler.local_platform}
- #{checksum_for_repo_gem gem_repo4, "racca", "1.5.2"}
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -371,7 +365,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
simulate_windows do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "nokogiri", :platforms => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby]
+ gem "nokogiri", :platforms => [:mingw, :mswin, :x64_mingw, :jruby]
gem "platform_specific"
G
diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb
index 3e49db4f32..61cfc9b795 100644
--- a/spec/bundler/runtime/self_management_spec.rb
+++ b/spec/bundler/runtime/self_management_spec.rb
@@ -6,10 +6,6 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru
"2.3.0"
end
- let(:current_version) do
- "2.4.0"
- end
-
before do
build_repo2
@@ -96,7 +92,7 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru
end
it "shows a discrete message if locked bundler does not exist" do
- missing_minor = "#{Bundler::VERSION[0]}.999.999"
+ missing_minor ="#{Bundler::VERSION[0]}.999.999"
lockfile_bundled_with(missing_minor)
@@ -107,35 +103,6 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru
expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
end
- it "installs BUNDLE_VERSION version when using bundle config version x.y.z" do
- lockfile_bundled_with(current_version)
-
- bundle "config set --local version #{previous_minor}"
- bundle "install", :artifice => "vcr"
- expect(out).to include("Bundler #{Bundler::VERSION} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
-
- bundle "-v"
- expect(out).to eq(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
- end
-
- it "does not try to install when using bundle config version global" do
- lockfile_bundled_with(previous_minor)
-
- bundle "config set version system"
- bundle "install", :artifice => "vcr"
- expect(out).not_to match(/restarting using that version/)
-
- bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
- end
-
- it "ignores malformed lockfile version" do
- lockfile_bundled_with("2.3.")
-
- bundle "install --verbose"
- expect(out).to include("Using bundler #{Bundler::VERSION}")
- end
-
private
def lockfile_bundled_with(version)
diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb
index 3abbea449b..2d39d72937 100644
--- a/spec/bundler/runtime/setup_spec.rb
+++ b/spec/bundler/runtime/setup_spec.rb
@@ -144,7 +144,6 @@ RSpec.describe "Bundler.setup" do
ruby <<-RUBY
require 'bundler'
- gem "bundler", "#{Bundler::VERSION}" if #{ruby_core?}
Bundler.setup
puts $LOAD_PATH
RUBY
@@ -411,7 +410,7 @@ RSpec.describe "Bundler.setup" do
it "provides a useful exception when the git repo is not checked out yet" do
run "1", :raise_on_error => false
- expect(err).to match(/the git source #{lib_path("rack-1.0.0")} is not yet checked out. Please run `bundle install`/i)
+ expect(err).to match(/the git source #{lib_path('rack-1.0.0')} is not yet checked out. Please run `bundle install`/i)
end
it "does not hit the git binary if the lockfile is available and up to date" do
@@ -498,7 +497,7 @@ RSpec.describe "Bundler.setup" do
FileUtils.rm_rf(lib_path("local-rack"))
run "require 'rack'", :raise_on_error => false
- expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path("local-rack").to_s)} does not exist/)
+ expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
end
it "explodes if branch is not given on runtime" do
@@ -728,27 +727,6 @@ end
R
run <<-R
- File.open(File.join(Gem.dir, "specifications", "broken-ext.gemspec"), "w") do |f|
- f.write <<-RUBY
-# -*- encoding: utf-8 -*-
-# stub: broken-ext 1.0.0 ruby lib
-# stub: a.ext\\0b.ext
-
-Gem::Specification.new do |s|
- s.name = "broken-ext"
- s.version = "1.0.0"
- raise "BROKEN GEMSPEC EXT"
-end
- RUBY
- end
- # Need to write the gem.build_complete file,
- # otherwise the full spec is loaded to check the installed_by_version
- extensions_dir = Gem.default_ext_dir_for(Gem.dir) || File.join(Gem.dir, "extensions", Gem::Platform.local.to_s, Gem.extension_api_version)
- Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "broken-ext-1.0.0"))
- File.open(File.join(extensions_dir, "broken-ext-1.0.0", "gem.build_complete"), "w") {}
- R
-
- run <<-R
puts "WIN"
R
@@ -1227,9 +1205,6 @@ end
DEPENDENCIES
rack
-
- CHECKSUMS
- #{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
L
if ruby_version
@@ -1342,7 +1317,6 @@ end
exempts = %w[did_you_mean bundler]
exempts << "uri" if Gem.ruby_version >= Gem::Version.new("2.7")
exempts << "pathname" if Gem.ruby_version >= Gem::Version.new("3.0")
- exempts << "etc" if Gem.ruby_version < Gem::Version.new("3.2") && Gem.win_platform?
exempts << "set" unless Gem.rubygems_version >= Gem::Version.new("3.2.6")
exempts << "tsort" unless Gem.rubygems_version >= Gem::Version.new("3.2.31")
exempts << "error_highlight" # added in Ruby 3.1 as a default gem
@@ -1351,7 +1325,7 @@ end
exempts
end
- let(:activation_warning_hack) { <<~RUBY }
+ let(:activation_warning_hack) { strip_whitespace(<<-RUBY) }
require #{spec_dir.join("support/hax").to_s.dump}
Gem::Specification.send(:alias_method, :bundler_spec_activate, :activate)
@@ -1371,7 +1345,7 @@ end
"-r#{bundled_app("activation_warning_hack.rb")} #{ENV["RUBYOPT"]}"
end
- let(:code) { <<~RUBY }
+ let(:code) { strip_whitespace(<<-RUBY) }
require "pp"
loaded_specs = Gem.loaded_specs.dup
#{exemptions.inspect}.each {|s| loaded_specs.delete(s) }
diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb
index afbf053636..6a7e2891a6 100644
--- a/spec/bundler/spec_helper.rb
+++ b/spec/bundler/spec_helper.rb
@@ -17,7 +17,6 @@ require "rspec/support/differ"
require_relative "support/builders"
require_relative "support/build_metadata"
-require_relative "support/checksums"
require_relative "support/filters"
require_relative "support/helpers"
require_relative "support/indexes"
@@ -35,7 +34,6 @@ end
RSpec.configure do |config|
config.include Spec::Builders
- config.include Spec::Checksums
config.include Spec::Helpers
config.include Spec::Indexes
config.include Spec::Matchers
@@ -48,9 +46,6 @@ RSpec.configure do |config|
config.silence_filter_announcements = !ENV["TEST_ENV_NUMBER"].nil?
- config.backtrace_exclusion_patterns <<
- %r{./spec/(spec_helper\.rb|support/.+)}
-
config.disable_monkey_patching!
# Since failures cause us to keep a bunch of long strings in memory, stop
@@ -119,6 +114,6 @@ RSpec.configure do |config|
end
config.after :suite do
- FileUtils.rm_rf Spec::Path.pristine_system_gem_path
+ FileUtils.rm_r Spec::Path.pristine_system_gem_path
end
end
diff --git a/spec/bundler/support/activate.rb b/spec/bundler/support/activate.rb
deleted file mode 100644
index e19a6d0ed1..0000000000
--- a/spec/bundler/support/activate.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-require "rubygems"
-Gem.instance_variable_set(:@ruby, ENV["RUBY"]) if ENV["RUBY"]
-
-require_relative "path"
-bundler_gemspec = Spec::Path.loaded_gemspec
-bundler_gemspec.instance_variable_set(:@full_gem_path, Spec::Path.source_root)
-bundler_gemspec.activate if bundler_gemspec.respond_to?(:activate)
diff --git a/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb b/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
index 9bd2ca0a9d..acc13a56ff 100644
--- a/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
+++ b/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
@@ -7,8 +7,7 @@ class CompactIndexWrongGemChecksum < CompactIndexAPI
etag_response do
name = params[:name]
gem = gems.find {|g| g.name == name }
- # This generates the hexdigest "2222222222222222222222222222222222222222222222222222222222222222"
- checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "IiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiI=" }
+ checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "ab" * 22 }
versions = gem ? gem.versions : []
versions.each {|v| v.checksum = checksum }
CompactIndex.info(versions)
diff --git a/spec/bundler/support/artifice/fail.rb b/spec/bundler/support/artifice/fail.rb
index a6a8552893..6286e43fbd 100644
--- a/spec/bundler/support/artifice/fail.rb
+++ b/spec/bundler/support/artifice/fail.rb
@@ -17,7 +17,9 @@ class Fail < Net::HTTP
end
def exception(req)
- Errno::ENETUNREACH.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}")
+ name = ENV.fetch("BUNDLER_SPEC_EXCEPTION") { "Errno::ENETUNREACH" }
+ const = name.split("::").reduce(Object) {|mod, sym| mod.const_get(sym) }
+ const.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}")
end
end
diff --git a/spec/bundler/support/artifice/helpers/compact_index.rb b/spec/bundler/support/artifice/helpers/compact_index.rb
index dd9e94ef9b..4df47a9659 100644
--- a/spec/bundler/support/artifice/helpers/compact_index.rb
+++ b/spec/bundler/support/artifice/helpers/compact_index.rb
@@ -79,13 +79,11 @@ class CompactIndexAPI < Endpoint
reqs = d.requirement.requirements.map {|r| r.join(" ") }.join(", ")
CompactIndex::Dependency.new(d.name, reqs)
end
- begin
- checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") do
- Digest(:SHA256).file("#{gem_repo}/gems/#{spec.original_name}.gem").hexdigest
- end
- rescue StandardError
- checksum = nil
- end
+ checksum = begin
+ Digest(:SHA256).file("#{gem_repo}/gems/#{spec.original_name}.gem").base64digest
+ rescue StandardError
+ nil
+ end
CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil,
deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s)
end
diff --git a/spec/bundler/support/artifice/used_cassettes.txt b/spec/bundler/support/artifice/used_cassettes.txt
new file mode 100644
index 0000000000..a96efc790d
--- /dev/null
+++ b/spec/bundler/support/artifice/used_cassettes.txt
@@ -0,0 +1,20908 @@
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb
index 7b91aaef57..dfc7139523 100644
--- a/spec/bundler/support/builders.rb
+++ b/spec/bundler/support/builders.rb
@@ -621,7 +621,7 @@ module Spec
end
end
- TEST_CERT = <<~CERT
+ TEST_CERT = <<-CERT.gsub(/^\s*/, "")
-----BEGIN CERTIFICATE-----
MIIDMjCCAhqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAnMQwwCgYDVQQDDAN5b3Ux
FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTE1MDIwODAwMTIyM1oXDTQyMDYy
@@ -644,7 +644,7 @@ module Spec
-----END CERTIFICATE-----
CERT
- TEST_PKEY = <<~PKEY
+ TEST_PKEY = <<-PKEY.gsub(/^\s*/, "")
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2W8V2k3jdzgMxL0mjTqbRruTdtDcdZDXKtiFkyLvsXUXvc2k
GSdgcjMOS1CkafqGz/hAUlPibjM0QEXjtQuMdTmdMrmuORLeeIZhSO+HdkTNV6j3
diff --git a/spec/bundler/support/bundle.rb b/spec/bundler/support/bundle.rb
index 5d6d658040..5f808531ff 100644
--- a/spec/bundler/support/bundle.rb
+++ b/spec/bundler/support/bundle.rb
@@ -1,5 +1,10 @@
# frozen_string_literal: true
-require_relative "activate"
+require "rubygems"
+Gem.instance_variable_set(:@ruby, ENV["RUBY"]) if ENV["RUBY"]
+require_relative "path"
+bundler_gemspec = Spec::Path.loaded_gemspec
+bundler_gemspec.instance_variable_set(:@full_gem_path, Spec::Path.source_root)
+bundler_gemspec.activate if bundler_gemspec.respond_to?(:activate)
load File.expand_path("bundle", Spec::Path.bindir)
diff --git a/spec/bundler/support/checksums.rb b/spec/bundler/support/checksums.rb
deleted file mode 100644
index f0cac4219a..0000000000
--- a/spec/bundler/support/checksums.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# frozen_string_literal: true
-
-module Spec
- module Checksums
- class ChecksumsBuilder
- def initialize(&block)
- @checksums = {}
- yield self if block_given?
- end
-
- def repo_gem(repo, name, version, platform = Gem::Platform::RUBY)
- name_tuple = Gem::NameTuple.new(name, version, platform)
- gem_file = File.join(repo, "gems", "#{name_tuple.full_name}.gem")
- File.open(gem_file, "rb") do |f|
- @checksums[name_tuple] = Bundler::Checksum.from_gem(f, "#{gem_file} (via ChecksumsBuilder#repo_gem)")
- end
- end
-
- def no_checksum(name, version, platform = Gem::Platform::RUBY)
- name_tuple = Gem::NameTuple.new(name, version, platform)
- @checksums[name_tuple] = nil
- end
-
- def to_lock
- @checksums.map do |name_tuple, checksum|
- checksum &&= " #{checksum.to_lock}"
- " #{name_tuple.lock_name}#{checksum}\n"
- end.sort.join.strip
- end
- end
-
- def checksum_section(&block)
- ChecksumsBuilder.new(&block).to_lock
- end
-
- def checksum_for_repo_gem(*args)
- checksum_section do |c|
- c.repo_gem(*args)
- end
- end
-
- def gem_no_checksum(*args)
- checksum_section do |c|
- c.no_checksum(*args)
- end
- end
-
- # if prefixes is given, removes all checksums where the line
- # has any of the prefixes on the line before the checksum
- # otherwise, removes all checksums from the lockfile
- def remove_checksums_from_lockfile(lockfile, *prefixes)
- head, remaining = lockfile.split(/^CHECKSUMS$/, 2)
- checksums, tail = remaining.split("\n\n", 2)
-
- prefixes =
- if prefixes.empty?
- nil
- else
- /(#{prefixes.map {|p| Regexp.escape(p) }.join("|")})/
- end
-
- checksums = checksums.each_line.map do |line|
- if prefixes.nil? || line.match?(prefixes)
- line.gsub(/ sha256=[a-f0-9]{64}/i, "")
- else
- line
- end
- end
-
- head.concat(
- "CHECKSUMS",
- checksums.join,
- "\n\n",
- tail
- )
- end
- end
-end
diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb
index f4dd6fc89b..7b8c56b6ad 100644
--- a/spec/bundler/support/helpers.rb
+++ b/spec/bundler/support/helpers.rb
@@ -244,7 +244,7 @@ module Spec
contents = args.pop
if contents.nil?
- read_gemfile
+ File.open(bundled_app_gemfile, "r", &:read)
else
create_file(args.pop || "Gemfile", contents)
end
@@ -254,24 +254,12 @@ module Spec
contents = args.pop
if contents.nil?
- read_lockfile
+ File.open(bundled_app_lock, "r", &:read)
else
create_file(args.pop || "Gemfile.lock", contents)
end
end
- def read_gemfile(file = "Gemfile")
- read_bundled_app_file(file)
- end
-
- def read_lockfile(file = "Gemfile.lock")
- read_bundled_app_file(file)
- end
-
- def read_bundled_app_file(file)
- bundled_app(file).read
- end
-
def strip_whitespace(str)
# Trim the leading spaces
spaces = str[/\A\s+/, 0] || ""
@@ -293,29 +281,29 @@ module Spec
def system_gems(*gems)
gems = gems.flatten
options = gems.last.is_a?(Hash) ? gems.pop : {}
- install_dir = options.fetch(:path, system_gem_path)
+ path = options.fetch(:path, system_gem_path)
default = options.fetch(:default, false)
- with_gem_path_as(install_dir) do
+ with_gem_path_as(path) do
gem_repo = options.fetch(:gem_repo, gem_repo1)
gems.each do |g|
gem_name = g.to_s
if gem_name.start_with?("bundler")
version = gem_name.match(/\Abundler-(?<version>.*)\z/)[:version] if gem_name != "bundler"
- with_built_bundler(version) {|gem_path| install_gem(gem_path, install_dir, default) }
+ with_built_bundler(version) {|gem_path| install_gem(gem_path, default) }
elsif %r{\A(?:[a-zA-Z]:)?/.*\.gem\z}.match?(gem_name)
- install_gem(gem_name, install_dir, default)
+ install_gem(gem_name, default)
else
- install_gem("#{gem_repo}/gems/#{gem_name}.gem", install_dir, default)
+ install_gem("#{gem_repo}/gems/#{gem_name}.gem", default)
end
end
end
end
- def install_gem(path, install_dir, default = false)
+ def install_gem(path, default = false)
raise "OMG `#{path}` does not exist!" unless File.exist?(path)
- args = "--no-document --ignore-dependencies --verbose --local --install-dir #{install_dir}"
- args += " --default" if default
+ args = "--no-document --ignore-dependencies --verbose --local"
+ args += " --default --install-dir #{system_gem_path}" if default
gem_command "install #{args} '#{path}'"
end
diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb
index 5d9ea19343..78372302f1 100644
--- a/spec/bundler/support/indexes.rb
+++ b/spec/bundler/support/indexes.rb
@@ -14,9 +14,9 @@ module Spec
alias_method :platforms, :platform
- def resolve(args = [], dependency_api_available: true)
+ def resolve(args = [])
@platforms ||= ["ruby"]
- default_source = instance_double("Bundler::Source::Rubygems", :specs => @index, :to_s => "locally install gems", :dependency_api_available? => dependency_api_available)
+ default_source = instance_double("Bundler::Source::Rubygems", :specs => @index, :to_s => "locally install gems")
source_requirements = { :default => default_source }
base = args[0] || Bundler::SpecSet.new([])
base.each {|ls| ls.source = default_source }
@@ -41,12 +41,6 @@ module Spec
expect(got).to eq(specs.sort)
end
- def should_resolve_without_dependency_api(specs)
- got = resolve(:dependency_api_available => false)
- got = got.map(&:full_name).sort
- expect(got).to eq(specs.sort)
- end
-
def should_resolve_and_include(specs, args = [])
got = resolve(args)
got = got.map(&:full_name).sort
@@ -304,7 +298,7 @@ module Spec
end
end
- def a_unresolvable_child_index
+ def a_unresovable_child_index
build_index do
gem "json", %w[1.8.0]
diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb
index 240cfe7bc9..8b9c0e1290 100644
--- a/spec/bundler/support/path.rb
+++ b/spec/bundler/support/path.rb
@@ -42,8 +42,7 @@ module Spec
end
def dev_gemfile
- name = RUBY_VERSION.start_with?("2.6") ? "dev26_gems.rb" : "dev_gems.rb"
- @dev_gemfile ||= tool_dir.join(name)
+ @dev_gemfile ||= tool_dir.join("dev_gems.rb")
end
def bindir
@@ -292,11 +291,11 @@ module Spec
end
def rubocop_gemfile_basename
- tool_dir.join(RUBY_VERSION.start_with?("2.6") ? "rubocop26_gems.rb" : "rubocop_gems.rb")
+ tool_dir.join("rubocop_gems.rb")
end
def standard_gemfile_basename
- tool_dir.join(RUBY_VERSION.start_with?("2.6") ? "standard26_gems.rb" : "standard_gems.rb")
+ tool_dir.join("standard_gems.rb")
end
def tool_dir
diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb
index 936c82d08c..4553c0606e 100644
--- a/spec/bundler/support/rubygems_ext.rb
+++ b/spec/bundler/support/rubygems_ext.rb
@@ -118,7 +118,6 @@ module Spec
end
def gem_activate(gem_name)
- require_relative "activate"
require "bundler"
gem_requirement = Bundler::LockfileParser.new(File.read(dev_lockfile)).specs.find {|spec| spec.name == gem_name }.version
gem gem_name, gem_requirement
diff --git a/spec/bundler/update/git_spec.rb b/spec/bundler/update/git_spec.rb
index eeae4079ca..59e3d2f5fb 100644
--- a/spec/bundler/update/git_spec.rb
+++ b/spec/bundler/update/git_spec.rb
@@ -328,10 +328,6 @@ RSpec.describe "bundle update" do
foo!
rack
- CHECKSUMS
- foo (2.0)
- #{checksum_for_repo_gem gem_repo2, "rack", "1.0.0"}
-
BUNDLED WITH
#{Bundler::VERSION}
G
diff --git a/spec/bundler/update/redownload_spec.rb b/spec/bundler/update/redownload_spec.rb
index b55593d077..147be823f5 100644
--- a/spec/bundler/update/redownload_spec.rb
+++ b/spec/bundler/update/redownload_spec.rb
@@ -30,15 +30,5 @@ RSpec.describe "bundle update" do
bundle "update rack --no-color --redownload"
expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
-
- it "re-installs installed gems" do
- rack_lib = default_bundle_path("gems/rack-1.0.0/lib/rack.rb")
- rack_lib.open("w") {|f| f.write("blah blah blah") }
- bundle :update, :redownload => true
-
- expect(out).to include "Installing rack 1.0.0"
- expect(rack_lib.open(&:read)).to eq("RACK = '1.0.0'\n")
- expect(the_bundle).to include_gems "rack 1.0.0"
- end
end
end
diff --git a/spec/default.mspec b/spec/default.mspec
index e2ad19e117..0dba98306c 100644
--- a/spec/default.mspec
+++ b/spec/default.mspec
@@ -4,7 +4,6 @@ if (opt = ENV["RUBYOPT"]) and (opt = opt.dup).sub!(/(?:\A|\s)-w(?=\z|\s)/, '')
ENV["RUBYOPT"] = opt
end
require "./rbconfig" unless defined?(RbConfig)
-require_relative "../tool/test-coverage" if ENV.key?("COVERAGE")
load File.dirname(__FILE__) + '/ruby/default.mspec'
OBJDIR = File.expand_path("spec/ruby/optional/capi/ext")
class MSpecScript
@@ -26,10 +25,6 @@ class MSpecScript
--
]
end
-
- if ENV.key?("COVERAGE")
- set :excludes, ["Coverage"]
- end
end
module MSpecScript::JobServer
@@ -70,72 +65,3 @@ end
class MSpecScript
prepend JobServer
end
-
-require 'mspec/runner/formatters/dotted'
-
-class DottedFormatter
- prepend Module.new {
- BASE = __dir__ + "/ruby/"
-
- def initialize(out = nil)
- super
- if out
- @columns = nil
- else
- columns = ENV["COLUMNS"]&.to_i
- @columns = columns&.nonzero? || 80
- end
- @dotted = 0
- @loaded = false
- @count = 0
- end
-
- def register
- super
- MSpec.register :load, self
- MSpec.register :unload, self
- end
-
- def after(*)
- if @columns
- if @dotted == 0
- s = sprintf("%6d ", @count)
- print(s)
- @dotted += s.size
- end
- @count +=1
- end
- super
- if @columns and (@dotted += 1) >= @columns
- print "\n"
- @dotted = 0
- end
- end
-
- def load(*)
- file = MSpec.file || MSpec.files_array.first
- @loaded = true
- s = "#{file.delete_prefix(BASE)}:"
- print s
- if @columns
- if (@dotted += s.size) >= @columns
- print "\n"
- @dotted = 0
- else
- print " "
- @dotted += 1
- end
- end
- @count = 0
- end
-
- def unload
- super
- if @loaded
- print "\n" if @dotted > 0
- @dotted = 0
- @loaded = nil
- end
- end
- }
-end
diff --git a/spec/lib/formatter_overrides.rb b/spec/lib/formatter_overrides.rb
deleted file mode 100644
index 4a61d425d1..0000000000
--- a/spec/lib/formatter_overrides.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-module FormatterOverrides
- def example_pending(_); end
- def dump_pending(_); end
-end
-
-RSpec::Core::Formatters::ProgressFormatter.prepend FormatterOverrides
diff --git a/spec/lib/spec_coverage.rb b/spec/lib/spec_coverage.rb
deleted file mode 100644
index 34aed32f72..0000000000
--- a/spec/lib/spec_coverage.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative "../../tool/test-coverage" if ENV.key?('COVERAGE')
diff --git a/spec/mspec/lib/mspec/commands/mspec.rb b/spec/mspec/lib/mspec/commands/mspec.rb
index f5341c699d..9c38cebcda 100755
--- a/spec/mspec/lib/mspec/commands/mspec.rb
+++ b/spec/mspec/lib/mspec/commands/mspec.rb
@@ -38,6 +38,11 @@ class MSpecMain < MSpecScript
options.targets
+ options.on("--warnings", "Don't suppress warnings") do
+ config[:flags] << '-w'
+ ENV['OUTPUT_WARNINGS'] = '1'
+ end
+
options.on("-j", "--multi", "Run multiple (possibly parallel) subprocesses") do
config[:multi] = true
end
diff --git a/spec/mspec/lib/mspec/helpers/io.rb b/spec/mspec/lib/mspec/helpers/io.rb
index 2ad14f47a1..29c6c37a1a 100644
--- a/spec/mspec/lib/mspec/helpers/io.rb
+++ b/spec/mspec/lib/mspec/helpers/io.rb
@@ -7,7 +7,7 @@ class IOStub
end
def write(*str)
- self << str.join('')
+ self << str.join
end
def << str
@@ -16,7 +16,7 @@ class IOStub
end
def print(*str)
- write(str.join('') + $\.to_s)
+ write(str.join + $\.to_s)
end
def method_missing(name, *args, &block)
diff --git a/spec/mspec/lib/mspec/helpers/ruby_exe.rb b/spec/mspec/lib/mspec/helpers/ruby_exe.rb
index 2e499d6f9a..7fde001cda 100644
--- a/spec/mspec/lib/mspec/helpers/ruby_exe.rb
+++ b/spec/mspec/lib/mspec/helpers/ruby_exe.rb
@@ -140,44 +140,28 @@ def ruby_exe(code = :not_given, opts = {})
expected_status = opts.fetch(:exit_status, 0)
begin
- command = ruby_cmd(code, opts)
-
- # Try to avoid the extra shell for 2>&1
- # This is notably useful for TimeoutAction which can then signal the ruby subprocess and not the shell
- popen_options = []
- if command.end_with?(' 2>&1')
- command = command[0...-5]
- popen_options = [{ err: [:child, :out] }]
- end
-
- output = IO.popen(command, *popen_options) do |io|
- pid = io.pid
- MSpec.subprocesses << pid
- begin
- io.read
- ensure
- MSpec.subprocesses.delete(pid)
+ platform_is_not :opal do
+ command = ruby_cmd(code, opts)
+ output = `#{command}`
+ status = Process.last_status
+
+ exit_status = if status.exited?
+ status.exitstatus
+ elsif status.signaled?
+ signame = Signal.signame status.termsig
+ raise "No signal name?" unless signame
+ :"SIG#{signame}"
+ else
+ raise SpecExpectationNotMetError, "#{exit_status.inspect} is neither exited? nor signaled?"
+ end
+ if exit_status != expected_status
+ formatted_output = output.lines.map { |line| " #{line}" }.join
+ raise SpecExpectationNotMetError,
+ "Expected exit status is #{expected_status.inspect} but actual is #{exit_status.inspect} for command ruby_exe(#{command.inspect})\nOutput:\n#{formatted_output}"
end
- end
- status = Process.last_status
-
- exit_status = if status.exited?
- status.exitstatus
- elsif status.signaled?
- signame = Signal.signame status.termsig
- raise "No signal name?" unless signame
- :"SIG#{signame}"
- else
- raise SpecExpectationNotMetError, "#{exit_status.inspect} is neither exited? nor signaled?"
- end
- if exit_status != expected_status
- formatted_output = output.lines.map { |line| " #{line}" }.join
- raise SpecExpectationNotMetError,
- "Expected exit status is #{expected_status.inspect} but actual is #{exit_status.inspect} for command ruby_exe(#{command.inspect})\nOutput:\n#{formatted_output}"
+ output
end
-
- output
ensure
saved_env.each { |key, value| ENV[key] = value }
env.keys.each do |key|
diff --git a/spec/mspec/lib/mspec/matchers/complain.rb b/spec/mspec/lib/mspec/matchers/complain.rb
index 19310c0bbb..887e72b4b0 100644
--- a/spec/mspec/lib/mspec/matchers/complain.rb
+++ b/spec/mspec/lib/mspec/matchers/complain.rb
@@ -19,6 +19,7 @@ class ComplainMatcher
@verbose = $VERBOSE
err = IOStub.new
+ Thread.current[:in_mspec_complain_matcher] = true
$stderr = err
$VERBOSE = @options.key?(:verbose) ? @options[:verbose] : false
begin
@@ -26,6 +27,7 @@ class ComplainMatcher
ensure
$VERBOSE = @verbose
$stderr = @saved_err
+ Thread.current[:in_mspec_complain_matcher] = false
end
@warning = err.to_s
diff --git a/spec/mspec/lib/mspec/runner/actions/timeout.rb b/spec/mspec/lib/mspec/runner/actions/timeout.rb
index 499001c952..543b7366d7 100644
--- a/spec/mspec/lib/mspec/runner/actions/timeout.rb
+++ b/spec/mspec/lib/mspec/runner/actions/timeout.rb
@@ -3,8 +3,6 @@ class TimeoutAction
@timeout = timeout
@queue = Queue.new
@started = now
- @fail = false
- @error_message = "took longer than the configured timeout of #{@timeout}s"
end
def register
@@ -39,25 +37,15 @@ class TimeoutAction
elapsed = now - @started
if elapsed > @timeout
if @current_state
- STDERR.puts "\nExample #{@error_message}:"
+ STDERR.puts "\nExample took longer than the configured timeout of #{@timeout}s:"
STDERR.puts "#{@current_state.description}"
else
- STDERR.puts "\nSome code outside an example #{@error_message}"
+ STDERR.puts "\nSome code outside an example took longer than the configured timeout of #{@timeout}s"
end
STDERR.flush
show_backtraces
- if MSpec.subprocesses.empty?
- exit 2
- else
- # Do not exit but signal the subprocess so we can get their output
- MSpec.subprocesses.each do |pid|
- Process.kill :SIGTERM, pid
- end
- @fail = true
- @current_state = nil
- break # stop this thread, will fail in #after
- end
+ exit 2
end
end
end
@@ -77,11 +65,6 @@ class TimeoutAction
@queue << -> do
@current_state = nil
end
-
- if @fail
- STDERR.puts "\n\nThe last example #{@error_message}. See above for the subprocess stacktrace."
- exit 2
- end
end
def finish
@@ -90,38 +73,19 @@ class TimeoutAction
end
private def show_backtraces
- java_stacktraces = -> pid {
- if RUBY_ENGINE == 'truffleruby' || RUBY_ENGINE == 'jruby'
- STDERR.puts 'Java stacktraces:'
- Process.kill :SIGQUIT, pid
- sleep 1
- end
- }
-
- if MSpec.subprocesses.empty?
- java_stacktraces.call Process.pid
+ if RUBY_ENGINE == 'truffleruby'
+ STDERR.puts 'Java stacktraces:'
+ Process.kill :SIGQUIT, Process.pid
+ sleep 1
+ end
- STDERR.puts "\nRuby backtraces:"
- if defined?(Truffle::Debug.show_backtraces)
- Truffle::Debug.show_backtraces
- else
- Thread.list.each do |thread|
- unless thread == Thread.current
- STDERR.puts thread.inspect, thread.backtrace, ''
- end
- end
- end
+ STDERR.puts "\nRuby backtraces:"
+ if defined?(Truffle::Debug.show_backtraces)
+ Truffle::Debug.show_backtraces
else
- MSpec.subprocesses.each do |pid|
- STDERR.puts "\nFor subprocess #{pid}"
- java_stacktraces.call pid
-
- if RUBY_ENGINE == 'truffleruby'
- STDERR.puts "\nRuby backtraces:"
- Process.kill :SIGALRM, pid
- sleep 1
- else
- STDERR.puts "Don't know how to print backtraces of a subprocess on #{RUBY_ENGINE}"
+ Thread.list.each do |thread|
+ unless thread == Thread.current
+ STDERR.puts thread.inspect, thread.backtrace, ''
end
end
end
diff --git a/spec/mspec/lib/mspec/runner/mspec.rb b/spec/mspec/lib/mspec/runner/mspec.rb
index 97c3f365bc..889e085175 100644
--- a/spec/mspec/lib/mspec/runner/mspec.rb
+++ b/spec/mspec/lib/mspec/runner/mspec.rb
@@ -38,10 +38,9 @@ module MSpec
@expectation = nil
@expectations = false
@skips = []
- @subprocesses = []
class << self
- attr_reader :file, :include, :exclude, :skips, :subprocesses
+ attr_reader :file, :include, :exclude, :skips
attr_writer :repeat, :randomize
attr_accessor :formatter
end
@@ -396,7 +395,7 @@ module MSpec
desc = tag.escape(tag.description)
file = tags_file
if File.exist? file
- lines = File.readlines(file)
+ lines = IO.readlines(file)
File.open(file, "w:utf-8") do |f|
lines.each do |line|
line = line.chomp
diff --git a/spec/mspec/lib/mspec/utils/options.rb b/spec/mspec/lib/mspec/utils/options.rb
index 3b5962dbe6..612caf6771 100644
--- a/spec/mspec/lib/mspec/utils/options.rb
+++ b/spec/mspec/lib/mspec/utils/options.rb
@@ -477,7 +477,7 @@ class MSpecOptions
def debug
on("-d", "--debug",
- "Disable MSpec backtrace filtering") do
+ "Set MSpec debugging flag for more verbose output") do
$MSPEC_DEBUG = true
end
end
diff --git a/spec/mspec/lib/mspec/utils/warnings.rb b/spec/mspec/lib/mspec/utils/warnings.rb
index 23efc696a5..0d3d36fada 100644
--- a/spec/mspec/lib/mspec/utils/warnings.rb
+++ b/spec/mspec/lib/mspec/utils/warnings.rb
@@ -8,3 +8,46 @@ if Object.const_defined?(:Warning) and Warning.respond_to?(:[]=)
Warning[:deprecated] = true
Warning[:experimental] = false
end
+
+if Object.const_defined?(:Warning) and Warning.respond_to?(:warn)
+ def Warning.warn(message, category: nil)
+ # Suppress any warning inside the method to prevent recursion
+ verbose = $VERBOSE
+ $VERBOSE = nil
+
+ if Thread.current[:in_mspec_complain_matcher]
+ return $stderr.write(message)
+ end
+
+ case message
+ # $VERBOSE = true warnings
+ when /(.+\.rb):(\d+):.+possibly useless use of (<|<=|==|>=|>) in void context/
+ # Make sure there is a .should otherwise it is missing
+ line_nb = Integer($2)
+ unless File.exist?($1) and /\.should(_not)? (<|<=|==|>=|>)/ === File.readlines($1)[line_nb-1]
+ $stderr.write message
+ end
+ when /possibly useless use of (\+|-) in void context/
+ when /assigned but unused variable/
+ when /method redefined/
+ when /previous definition of/
+ when /instance variable @.+ not initialized/
+ when /statement not reached/
+ when /shadowing outer local variable/
+ when /setting Encoding.default_(in|ex)ternal/
+ when /unknown (un)?pack directive/
+ when /(un)?trust(ed\?)? is deprecated/
+ when /\.exists\? is a deprecated name/
+ when /Float .+ out of range/
+ when /passing a block to String#(bytes|chars|codepoints|lines) is deprecated/
+ when /core\/string\/modulo_spec\.rb:\d+: warning: too many arguments for format string/
+ when /regexp\/shared\/new_ascii(_8bit)?\.rb:\d+: warning: Unknown escape .+ is ignored/
+ else
+ $stderr.write message
+ end
+ ensure
+ $VERBOSE = verbose
+ end
+else
+ $VERBOSE = nil unless ENV['OUTPUT_WARNINGS']
+end
diff --git a/spec/mspec/spec/commands/mspec_spec.rb b/spec/mspec/spec/commands/mspec_spec.rb
index d19bebb2d6..82201c2075 100644
--- a/spec/mspec/spec/commands/mspec_spec.rb
+++ b/spec/mspec/spec/commands/mspec_spec.rb
@@ -92,6 +92,33 @@ RSpec.describe MSpecMain, "#run" do
end
end
+RSpec.describe "The --warnings option" do
+ before :each do
+ @options, @config = new_option
+ allow(MSpecOptions).to receive(:new).and_return(@options)
+ @script = MSpecMain.new
+ allow(@script).to receive(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ allow(@options).to receive(:on)
+ expect(@options).to receive(:on).with("--warnings", an_instance_of(String))
+ @script.options
+ end
+
+ it "sets flags to -w" do
+ @config[:flags] = []
+ @script.options ["--warnings"]
+ expect(@config[:flags]).to include("-w")
+ end
+
+ it "set OUTPUT_WARNINGS = '1' in the environment" do
+ ENV['OUTPUT_WARNINGS'] = '0'
+ @script.options ["--warnings"]
+ expect(ENV['OUTPUT_WARNINGS']).to eq('1')
+ end
+end
+
RSpec.describe "The -j, --multi option" do
before :each do
@options, @config = new_option
diff --git a/spec/mspec/spec/helpers/ruby_exe_spec.rb b/spec/mspec/spec/helpers/ruby_exe_spec.rb
index 56bade1ba9..61225a2756 100644
--- a/spec/mspec/spec/helpers/ruby_exe_spec.rb
+++ b/spec/mspec/spec/helpers/ruby_exe_spec.rb
@@ -145,7 +145,7 @@ RSpec.describe Object, "#ruby_exe" do
stub_const 'RUBY_EXE', 'ruby_spec_exe -w -Q'
@script = RubyExeSpecs.new
- allow(IO).to receive(:popen).and_return('OUTPUT')
+ allow(@script).to receive(:`).and_return('OUTPUT')
status_successful = double(Process::Status, exited?: true, exitstatus: 0)
allow(Process).to receive(:last_status).and_return(status_successful)
@@ -155,7 +155,7 @@ RSpec.describe Object, "#ruby_exe" do
code = "code"
options = {}
output = "output"
- expect(IO).to receive(:popen).and_return(output)
+ allow(@script).to receive(:`).and_return(output)
expect(@script.ruby_exe(code, options)).to eq output
end
@@ -168,7 +168,7 @@ RSpec.describe Object, "#ruby_exe" do
code = "code"
options = {}
expect(@script).to receive(:ruby_cmd).and_return("ruby_cmd")
- expect(IO).to receive(:popen).with("ruby_cmd")
+ expect(@script).to receive(:`).with("ruby_cmd")
@script.ruby_exe(code, options)
end
@@ -227,7 +227,7 @@ RSpec.describe Object, "#ruby_exe" do
expect(ENV).to receive(:[]=).with("ABC", "xyz")
expect(ENV).to receive(:[]=).with("ABC", "123")
- expect(IO).to receive(:popen).and_raise(Exception)
+ expect(@script).to receive(:`).and_raise(Exception)
expect do
@script.ruby_exe nil, :env => { :ABC => "xyz" }
end.to raise_error(Exception)
@@ -248,7 +248,7 @@ RSpec.describe Object, "#ruby_exe" do
it "does not raise exception when command ends with expected status" do
output = "output"
- expect(IO).to receive(:popen).and_return(output)
+ allow(@script).to receive(:`).and_return(output)
expect(@script.ruby_exe("path", exit_status: 4)).to eq output
end
diff --git a/spec/mspec/spec/runner/context_spec.rb b/spec/mspec/spec/runner/context_spec.rb
index 9ebc708c0c..a864428aec 100644
--- a/spec/mspec/spec/runner/context_spec.rb
+++ b/spec/mspec/spec/runner/context_spec.rb
@@ -914,7 +914,7 @@ RSpec.describe ContextState, "#it_should_behave_like" do
it "raises an Exception if unable to find the shared ContextState" do
expect(MSpec).to receive(:retrieve_shared).and_return(nil)
- expect { @state.it_should_behave_like :this }.to raise_error(Exception)
+ expect { @state.it_should_behave_like "this" }.to raise_error(Exception)
end
describe "for nested ContextState instances" do
diff --git a/spec/mspec/tool/check_require_spec_helper.rb b/spec/mspec/tool/check_require_spec_helper.rb
deleted file mode 100755
index 07126e68dc..0000000000
--- a/spec/mspec/tool/check_require_spec_helper.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env ruby
-
-# This script is used to check that each *_spec.rb file has
-# a relative_require for spec_helper which should live higher
-# up in the ruby/spec repo directory tree.
-#
-# Prints errors to $stderr and returns a non-zero exit code when
-# errors are found.
-#
-# Related to https://github.com/ruby/spec/pull/992
-
-def check_file(fn)
- File.foreach(fn) do |line|
- return $1 if line =~ /^\s*require_relative\s*['"](.*spec_helper)['"]/
- end
- nil
-end
-
-rootdir = ARGV[0] || "."
-fglob = File.join(rootdir, "**", "*_spec.rb")
-specfiles = Dir.glob(fglob)
-raise "No spec files found in #{fglob.inspect}. Give an argument to specify the root-directory of ruby/spec" if specfiles.empty?
-
-errors = 0
-specfiles.sort.each do |fn|
- result = check_file(fn)
- if result.nil?
- warn "Missing require_relative for *spec_helper for file: #{fn}"
- errors += 1
- end
-end
-
-puts "# Found #{errors} files with require_relative spec_helper issues."
-exit 1 if errors > 0
diff --git a/spec/mspec/tool/remove_old_guards.rb b/spec/mspec/tool/remove_old_guards.rb
index 3fd95e6b31..67485446bb 100644
--- a/spec/mspec/tool/remove_old_guards.rb
+++ b/spec/mspec/tool/remove_old_guards.rb
@@ -46,51 +46,6 @@ def remove_guards(guard, keep)
end
end
-def remove_empty_files
- each_spec_file do |file|
- unless file.include?("fixtures/")
- lines = File.readlines(file)
- if lines.all? { |line| line.chomp.empty? or line.start_with?('require', '#') }
- puts "Removing empty file #{file}"
- File.delete(file)
- end
- end
- end
-end
-
-def remove_unused_shared_specs
- shared_groups = {}
- # Dir["**/shared/**/*.rb"].each do |shared|
- each_spec_file do |shared|
- next if File.basename(shared) == 'constants.rb'
- contents = File.binread(shared)
- found = false
- contents.scan(/^\s*describe (:[\w_?]+), shared: true do$/) {
- shared_groups[$1] = 0
- found = true
- }
- if !found and shared.include?('shared/') and !shared.include?('fixtures/') and !shared.end_with?('/constants.rb')
- puts "no shared describe in #{shared} ?"
- end
- end
-
- each_spec_file do |file|
- contents = File.binread(file)
- contents.scan(/(?:it_behaves_like|it_should_behave_like) (:[\w_?]+)[,\s]/) do
- puts $1 unless shared_groups.key?($1)
- shared_groups[$1] += 1
- end
- end
-
- shared_groups.each_pair do |group, value|
- if value == 0
- puts "Shared describe #{group} seems unused"
- elsif value == 1
- puts "Shared describe #{group} seems used only once" if $VERBOSE
- end
- end
-end
-
def search(regexp)
each_spec_file do |file|
contents = File.binread(file)
@@ -109,11 +64,7 @@ version = Regexp.escape(ARGV.fetch(0))
version += "(?:\\.0)?" if version.count(".") < 2
remove_guards(/ruby_version_is (["'])#{version}\1 do/, true)
remove_guards(/ruby_version_is (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, false)
-remove_guards(/ruby_bug ["']#\d+["'], (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, true)
-
-remove_empty_files
-remove_unused_shared_specs
+remove_guards(/ruby_bug "#\d+", (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, true)
-puts "Search:"
search(/(["'])#{version}\1/)
search(/^\s*#.+#{version}/)
diff --git a/spec/mspec/tool/tag_from_output.rb b/spec/mspec/tool/tag_from_output.rb
index b6b4603855..a6e60945cd 100755
--- a/spec/mspec/tool/tag_from_output.rb
+++ b/spec/mspec/tool/tag_from_output.rb
@@ -3,8 +3,6 @@
# Adds tags based on error and failures output (e.g., from a CI log),
# without running any spec code.
-tag = ENV["TAG"] || "fails"
-
tags_dir = %w[
spec/tags
spec/tags/ruby
@@ -32,9 +30,9 @@ output.slice_before(NUMBER).select { |number, *rest|
if spec_file
spec_file = spec_file[SPEC_FILE, 1] or raise
else
- if error_line =~ /^([\w:]+)[#\.](\w+) /
- mod, method = $1, $2
- file = "#{mod.downcase.gsub('::', '/')}/#{method}_spec.rb"
+ if error_line =~ /^(\w+)[#\.](\w+) /
+ module_method = error_line.split(' ', 2).first
+ file = "#{$1.downcase}/#{$2}_spec.rb"
spec_file = ['spec/ruby/core', 'spec/ruby/library', *Dir.glob('spec/ruby/library/*')].find { |dir|
path = "#{dir}/#{file}"
break path if File.exist?(path)
@@ -56,7 +54,7 @@ output.slice_before(NUMBER).select { |number, *rest|
dir = File.dirname(tags_file)
Dir.mkdir(dir) unless Dir.exist?(dir)
- tag_line = "#{tag}:#{description}"
+ tag_line = "fails:#{description}"
lines = File.exist?(tags_file) ? File.readlines(tags_file, chomp: true) : []
unless lines.include?(tag_line)
puts tags_file
diff --git a/spec/ruby/.mspec.constants b/spec/ruby/.mspec.constants
index 6e09a44362..5dd477eb66 100644
--- a/spec/ruby/.mspec.constants
+++ b/spec/ruby/.mspec.constants
@@ -204,7 +204,6 @@ UserArray
UserCustomConstructorString
UserDefined
UserDefinedImmediate
-UserDefinedString
UserDefinedWithIvar
UserHash
UserHashInitParams
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml
index 9ad57dd51c..82733c4b4d 100644
--- a/spec/ruby/.rubocop.yml
+++ b/spec/ruby/.rubocop.yml
@@ -1,7 +1,7 @@
inherit_from: .rubocop_todo.yml
AllCops:
- TargetRubyVersion: 3.0
+ TargetRubyVersion: 2.7
DisplayCopNames: true
Exclude:
- command_line/fixtures/bad_syntax.rb
@@ -33,10 +33,6 @@ Lint/AssignmentInCondition:
Lint/BooleanSymbol:
Enabled: false
-Lint/DeprecatedOpenSSLConstant:
- Exclude:
- - library/openssl/digest/**/*.rb
-
Lint/InterpolationCheck:
Enabled: false
diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml
index a59e64bd58..ac9cfae2bf 100644
--- a/spec/ruby/.rubocop_todo.yml
+++ b/spec/ruby/.rubocop_todo.yml
@@ -98,7 +98,6 @@ Lint/RescueException:
- 'core/dir/fileno_spec.rb'
- 'core/exception/cause_spec.rb'
- 'core/exception/no_method_error_spec.rb'
- - 'core/fiber/kill_spec.rb'
- 'core/kernel/fixtures/autoload_frozen.rb'
- 'core/kernel/raise_spec.rb'
- 'core/module/autoload_spec.rb'
diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md
index c82eb5ea4f..adfc2fb0ca 100644
--- a/spec/ruby/CONTRIBUTING.md
+++ b/spec/ruby/CONTRIBUTING.md
@@ -138,12 +138,12 @@ Here is a list of the most commonly-used guards:
#### Version guards
```ruby
-ruby_version_is ""..."3.2" do
- # Specs for RUBY_VERSION < 3.2
+ruby_version_is ""..."2.6" do
+ # Specs for RUBY_VERSION < 2.6
end
-ruby_version_is "3.2" do
- # Specs for RUBY_VERSION >= 3.2
+ruby_version_is "2.6" do
+ # Specs for RUBY_VERSION >= 2.6
end
```
@@ -179,7 +179,6 @@ In case there is a bug in MRI and the fix will be backported to previous version
If it is not backported or not likely, use `ruby_version_is` instead.
First, file a bug at https://bugs.ruby-lang.org/.
The problem is `ruby_bug` would make non-MRI implementations fail this spec while MRI itself does not pass it, so it should only be used if the bug is/will be fixed and backported.
-Otherwise, non-MRI implementations would have to choose between being incompatible with the latest release of MRI to pass the spec or fail the spec, both which make no sense.
```ruby
ruby_bug '#13669', ''...'3.2' do
@@ -192,11 +191,11 @@ end
#### Combining guards
```ruby
-guard -> { platform_is :windows and ruby_version_is ""..."3.2" } do
- # Windows and RUBY_VERSION < 3.2
+guard -> { platform_is :windows and ruby_version_is ""..."2.6" } do
+ # Windows and RUBY_VERSION < 2.6
end
-guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do
+guard_not -> { platform_is :windows and ruby_version_is ""..."2.6" } do
# The opposite
end
```
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index 115392835f..018bf0ca3e 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -30,8 +30,8 @@ ruby/spec is known to be tested in these implementations for every commit:
* [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)
-ruby/spec describes the behavior of Ruby 3.0 and more recent Ruby versions.
-More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.0.x, 3.1.x, 3.2.x, etc), and those are tested in CI.
+ruby/spec describes the behavior of Ruby 2.7 and more recent Ruby versions.
+More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (2.7.x, 3.0.x, 3.1.x, etc), and those are tested in CI.
### Synchronization with Ruby Implementations
@@ -61,7 +61,6 @@ For older specs try these commits:
* Ruby 2.4.10 - [Suite](https://github.com/ruby/spec/commit/bce4f2b81d6c31db67cf4d023a0625ceadde59bd) using [MSpec](https://github.com/ruby/mspec/commit/e7eb8aa4c26495b7b461e687d950b96eb08b3ff2)
* Ruby 2.5.9 - [Suite](https://github.com/ruby/spec/commit/c503335d3d9f6ec6ef24de60a0716c34af69b64f) using [MSpec](https://github.com/ruby/mspec/commit/0091e8a62e954717cd54641f935eaf1403692041)
* Ruby 2.6.10 - [Suite](https://github.com/ruby/spec/commit/aaf998fb8c92c4e63ad423a2e7ca6e6921818c6e) using [MSpec](https://github.com/ruby/mspec/commit/5e36c684e9e2b92b1187589bba1df22c640a8661)
-* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
### Running the specs
@@ -128,12 +127,6 @@ MSpec can automatically add new top-level constants in this file with:
$ CHECK_LEAKS=save mspec ../mspec/bin/mspec file
-### Running Specs on S390x CPU Architecture
-
-Run the specs with `DFLTCC=0` if you see failing specs related to the zlib library on s390x CPU architecture. The failures can happen with the zlib library applying the patch madler/zlib#410 to enable the deflate algorithm producing a different compressed byte stream.
-
- $ DFLTCC=0 ../mspec/bin/mspec
-
### Contributing and Writing Specs
See [CONTRIBUTING.md](https://github.com/ruby/spec/blob/master/CONTRIBUTING.md) for documentation about contributing and writing specs (guards, matchers, etc).
diff --git a/spec/ruby/command_line/backtrace_limit_spec.rb b/spec/ruby/command_line/backtrace_limit_spec.rb
index bc40a542a0..56afa8efef 100644
--- a/spec/ruby/command_line/backtrace_limit_spec.rb
+++ b/spec/ruby/command_line/backtrace_limit_spec.rb
@@ -1,46 +1,48 @@
require_relative '../spec_helper'
-describe "The --backtrace-limit command line option" do
- it "limits top-level backtraces to a given number of entries" do
- file = fixture(__FILE__ , "backtrace.rb")
- out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1)
- out = out.gsub(__dir__, '')
+ruby_version_is "3.0" do
+ describe "The --backtrace-limit command line option" do
+ it "limits top-level backtraces to a given number of entries" do
+ file = fixture(__FILE__ , "backtrace.rb")
+ out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1)
+ out = out.gsub(__dir__, '')
- out.should == <<-MSG
+ out.should == <<-MSG
top
/fixtures/backtrace.rb:2:in `a': oops (RuntimeError)
\tfrom /fixtures/backtrace.rb:6:in `b'
\tfrom /fixtures/backtrace.rb:10:in `c'
\t ... 2 levels...
- MSG
- end
+ MSG
+ end
- it "affects Exception#full_message" do
- file = fixture(__FILE__ , "backtrace.rb")
- out = ruby_exe(file, options: "--backtrace-limit=2", args: "full_message 2>&1")
- out = out.gsub(__dir__, '')
+ it "affects Exception#full_message" do
+ file = fixture(__FILE__ , "backtrace.rb")
+ out = ruby_exe(file, options: "--backtrace-limit=2", args: "full_message 2>&1")
+ out = out.gsub(__dir__, '')
- out.should == <<-MSG
+ out.should == <<-MSG
full_message
/fixtures/backtrace.rb:2:in `a': oops (RuntimeError)
\tfrom /fixtures/backtrace.rb:6:in `b'
\tfrom /fixtures/backtrace.rb:10:in `c'
\t ... 2 levels...
- MSG
- end
+ MSG
+ end
- it "does not affect Exception#backtrace" do
- file = fixture(__FILE__ , "backtrace.rb")
- out = ruby_exe(file, options: "--backtrace-limit=2", args: "backtrace 2>&1")
- out = out.gsub(__dir__, '')
+ it "does not affect Exception#backtrace" do
+ file = fixture(__FILE__ , "backtrace.rb")
+ out = ruby_exe(file, options: "--backtrace-limit=2", args: "backtrace 2>&1")
+ out = out.gsub(__dir__, '')
- out.should == <<-MSG
+ out.should == <<-MSG
backtrace
/fixtures/backtrace.rb:2:in `a'
/fixtures/backtrace.rb:6:in `b'
/fixtures/backtrace.rb:10:in `c'
/fixtures/backtrace.rb:14:in `d'
/fixtures/backtrace.rb:29:in `<main>'
- MSG
+ MSG
+ end
end
end
diff --git a/spec/ruby/command_line/dash_a_spec.rb b/spec/ruby/command_line/dash_a_spec.rb
index 43d923ce16..9ea135dc76 100644
--- a/spec/ruby/command_line/dash_a_spec.rb
+++ b/spec/ruby/command_line/dash_a_spec.rb
@@ -6,13 +6,13 @@ describe "The -a command line option" do
end
it "runs the code in loop conditional on Kernel.gets()" do
- ruby_exe("puts $F.last", options: "-n -a",
+ ruby_exe("puts $F.last", options: "-n -a", escape: true,
args: " < #{@names}").should ==
"jones\nfield\ngrey\n"
end
it "sets $-a" do
- ruby_exe("puts $-a", options: "-n -a",
+ ruby_exe("puts $-a", options: "-n -a", escape: true,
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_l_spec.rb b/spec/ruby/command_line/dash_l_spec.rb
index 44a98445f3..5c1d3cf4cd 100644
--- a/spec/ruby/command_line/dash_l_spec.rb
+++ b/spec/ruby/command_line/dash_l_spec.rb
@@ -6,25 +6,25 @@ describe "The -l command line option" do
end
it "chomps lines with default separator" do
- ruby_exe('puts $_.end_with?("\n")', options: "-n -l",
+ ruby_exe('puts $_.end_with?("\n")', options: "-n -l", escape: true,
args: " < #{@names}").should ==
"false\nfalse\nfalse\n"
end
it "chomps last line based on $/" do
- ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l",
+ ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l", escape: true,
args: " < #{@names}").should ==
"alice j\nbob field\njames grey\n"
end
it "sets $\\ to the value of $/" do
- ruby_exe("puts $\\ == $/", options: "-W0 -n -l",
+ ruby_exe("puts $\\ == $/", options: "-W0 -n -l", escape: true,
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
it "sets $-l" do
- ruby_exe("puts $-l", options: "-n -l",
+ ruby_exe("puts $-l", options: "-n -l", escape: true,
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_n_spec.rb b/spec/ruby/command_line/dash_n_spec.rb
index 1dd9379259..9d331d6065 100644
--- a/spec/ruby/command_line/dash_n_spec.rb
+++ b/spec/ruby/command_line/dash_n_spec.rb
@@ -6,19 +6,19 @@ describe "The -n command line option" do
end
it "runs the code in loop conditional on Kernel.gets()" do
- ruby_exe("puts $_", options: "-n",
+ ruby_exe("puts $_", options: "-n", escape: true,
args: " < #{@names}").should ==
"alice\nbob\njames\n"
end
it "only evaluates BEGIN blocks once" do
- ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n",
+ ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n", escape: true,
args: " < #{@names}").should ==
"hi\nalice\nbob\njames\n"
end
it "only evaluates END blocks once" do
- ruby_exe("puts $_; END {puts \"bye\"}", options: "-n",
+ ruby_exe("puts $_; END {puts \"bye\"}", options: "-n", escape: true,
args: " < #{@names}").should ==
"alice\nbob\njames\nbye\n"
end
@@ -29,7 +29,7 @@ describe "The -n command line option" do
$total += 1
END { puts $total }
script
- ruby_exe(script, options: "-n",
+ ruby_exe(script, options: "-n", escape: true,
args: " < #{@names}").should ==
"3\n"
end
diff --git a/spec/ruby/command_line/dash_p_spec.rb b/spec/ruby/command_line/dash_p_spec.rb
index 967e3796de..39827c3868 100644
--- a/spec/ruby/command_line/dash_p_spec.rb
+++ b/spec/ruby/command_line/dash_p_spec.rb
@@ -6,13 +6,13 @@ describe "The -p command line option" do
end
it "runs the code in loop conditional on Kernel.gets() and prints $_" do
- ruby_exe("$_ = $_.upcase", options: "-p",
+ ruby_exe("$_ = $_.upcase", options: "-p", escape: true,
args: " < #{@names}").should ==
"ALICE\nBOB\nJAMES\n"
end
it "sets $-p" do
- ruby_exe("$_ = $-p", options: "-p",
+ ruby_exe("$_ = $-p", options: "-p", escape: true,
args: " < #{@names}").should ==
"truetruetrue"
end
diff --git a/spec/ruby/command_line/dash_upper_f_spec.rb b/spec/ruby/command_line/dash_upper_f_spec.rb
index 5c10a7140d..967acc2ece 100644
--- a/spec/ruby/command_line/dash_upper_f_spec.rb
+++ b/spec/ruby/command_line/dash_upper_f_spec.rb
@@ -6,7 +6,7 @@ describe "the -F command line option" do
end
it "specifies the field separator pattern for -a" do
- ruby_exe("puts $F[0]", options: "-naF:",
+ ruby_exe("puts $F[0]", options: "-naF:", escape: true,
args: " < #{@passwd}").should ==
"nobody\nroot\ndaemon\n"
end
diff --git a/spec/ruby/command_line/dash_upper_u_spec.rb b/spec/ruby/command_line/dash_upper_u_spec.rb
index 15854e7b73..d62718b095 100644
--- a/spec/ruby/command_line/dash_upper_u_spec.rb
+++ b/spec/ruby/command_line/dash_upper_u_spec.rb
@@ -6,13 +6,6 @@ describe "ruby -U" do
options: '-U').should == 'UTF-8'
end
- it "sets Encoding.default_internal to UTF-8 when RUBYOPT is empty or only spaces" do
- ruby_exe('p Encoding.default_internal',
- options: '-U', env: { 'RUBYOPT' => '' }).should == "#<Encoding:UTF-8>\n"
- ruby_exe('p Encoding.default_internal',
- options: '-U', env: { 'RUBYOPT' => ' ' }).should == "#<Encoding:UTF-8>\n"
- end
-
it "does nothing different if specified multiple times" do
ruby_exe('print Encoding.default_internal.name',
options: '-U -U').should == 'UTF-8'
diff --git a/spec/ruby/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb
index 9b570fa1eb..a4f4dcd051 100644
--- a/spec/ruby/command_line/dash_v_spec.rb
+++ b/spec/ruby/command_line/dash_v_spec.rb
@@ -8,6 +8,6 @@ describe "The -v command line option" do
it "prints version and ends" do
ruby_exe(nil, args: '-v').should include(RUBY_DESCRIPTION)
end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) ||
- (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?)
+ (defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?)
end
end
diff --git a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
index 1da779b1b9..c556bf0b71 100644
--- a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
+++ b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
@@ -1,3 +1,3 @@
@@@This line is not value Ruby
#!ruby
-puts 'success'
+puts 'success' \ No newline at end of file
diff --git a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
index df4b952c46..fa348d59e7 100644
--- a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
+++ b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
Binary files differ
diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb
index 734db8d519..bbea4d557d 100644
--- a/spec/ruby/command_line/rubyopt_spec.rb
+++ b/spec/ruby/command_line/rubyopt_spec.rb
@@ -11,14 +11,14 @@ describe "Processing RUBYOPT" do
it "adds the -I path to $LOAD_PATH" do
ENV["RUBYOPT"] = "-Ioptrubyspecincl"
- result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)")
+ result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)", escape: true)
result.chomp[-15..-1].should == "optrubyspecincl"
end
it "sets $DEBUG to true for '-d'" do
ENV["RUBYOPT"] = '-d'
command = %[puts "value of $DEBUG is \#{$DEBUG}"]
- result = ruby_exe(command, args: "2>&1")
+ result = ruby_exe(command, escape: true, args: "2>&1")
result.should =~ /value of \$DEBUG is true/
end
@@ -36,27 +36,27 @@ describe "Processing RUBYOPT" do
it "sets $VERBOSE to true for '-w'" do
ENV["RUBYOPT"] = '-w'
- ruby_exe("p $VERBOSE").chomp.should == "true"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
end
it "sets $VERBOSE to true for '-W'" do
ENV["RUBYOPT"] = '-W'
- ruby_exe("p $VERBOSE").chomp.should == "true"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
end
it "sets $VERBOSE to nil for '-W0'" do
ENV["RUBYOPT"] = '-W0'
- ruby_exe("p $VERBOSE").chomp.should == "nil"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "nil"
end
it "sets $VERBOSE to false for '-W1'" do
ENV["RUBYOPT"] = '-W1'
- ruby_exe("p $VERBOSE").chomp.should == "false"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "false"
end
it "sets $VERBOSE to true for '-W2'" do
ENV["RUBYOPT"] = '-W2'
- ruby_exe("p $VERBOSE").chomp.should == "true"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
end
it "suppresses deprecation warnings for '-W:no-deprecated'" do
diff --git a/spec/ruby/core/argf/bytes_spec.rb b/spec/ruby/core/argf/bytes_spec.rb
new file mode 100644
index 0000000000..bf35ded1db
--- /dev/null
+++ b/spec/ruby/core/argf/bytes_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_byte'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.bytes" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_byte, :bytes
+ end
+end
diff --git a/spec/ruby/core/argf/chars_spec.rb b/spec/ruby/core/argf/chars_spec.rb
new file mode 100644
index 0000000000..6af73cdabb
--- /dev/null
+++ b/spec/ruby/core/argf/chars_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_char'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.chars" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_char, :chars
+ end
+end
diff --git a/spec/ruby/core/argf/codepoints_spec.rb b/spec/ruby/core/argf/codepoints_spec.rb
new file mode 100644
index 0000000000..bb28c17fbb
--- /dev/null
+++ b/spec/ruby/core/argf/codepoints_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_codepoint'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.codepoints" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_codepoint, :codepoints
+ end
+end
diff --git a/spec/ruby/core/argf/lines_spec.rb b/spec/ruby/core/argf/lines_spec.rb
new file mode 100644
index 0000000000..e964dbd0d3
--- /dev/null
+++ b/spec/ruby/core/argf/lines_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_line'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.lines" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_line, :lines
+ end
+end
diff --git a/spec/ruby/core/argf/readpartial_spec.rb b/spec/ruby/core/argf/readpartial_spec.rb
index bbc8831131..5e284b3423 100644
--- a/spec/ruby/core/argf/readpartial_spec.rb
+++ b/spec/ruby/core/argf/readpartial_spec.rb
@@ -69,7 +69,7 @@ describe "ARGF.readpartial" do
print ARGF.readpartial(#{@stdin.size})
ARGF.readpartial(1) rescue print $!.class
STR
- stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}")
+ stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}", escape: true)
stdin.should == @stdin + "EOFError"
end
end
diff --git a/spec/ruby/core/array/all_spec.rb b/spec/ruby/core/array/all_spec.rb
deleted file mode 100644
index 680e8c26fa..0000000000
--- a/spec/ruby/core/array/all_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
-
-describe "Array#all?" do
- @value_to_return = -> _ { true }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :all?
-
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].all?(/bar/) { false }.should == true
- }.should complain(/given block not used/)
- end
-end
diff --git a/spec/ruby/core/array/any_spec.rb b/spec/ruby/core/array/any_spec.rb
index b51ce62f0f..09d949fe6e 100644
--- a/spec/ruby/core/array/any_spec.rb
+++ b/spec/ruby/core/array/any_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#any?" do
describe 'with no block given (a default block of { |x| x } is implicit)' do
@@ -20,9 +19,6 @@ describe "Array#any?" do
end
describe 'with a block given' do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :any?
-
it 'is false if the array is empty' do
empty_array = []
empty_array.any? {|v| 1 == 1 }.should == false
@@ -38,12 +34,4 @@ describe "Array#any?" do
array_with_members.any? {|v| v == 42 }.should == false
end
end
-
- describe 'when given a pattern argument' do
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].any?(/bar/) { false }.should == true
- }.should complain(/given block not used/)
- end
- end
end
diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb
index af95528281..f8479d763c 100644
--- a/spec/ruby/core/array/assoc_spec.rb
+++ b/spec/ruby/core/array/assoc_spec.rb
@@ -6,7 +6,7 @@ describe "Array#assoc" do
s1 = ["colors", "red", "blue", "green"]
s2 = [:letters, "a", "b", "c"]
s3 = [4]
- s4 = ["colors", "cyan", "yellow", "magenta"]
+ s4 = ["colors", "cyan", "yellow", "magenda"]
s5 = [:letters, "a", "i", "u"]
s_nil = [nil, nil]
a = [s1, s2, s3, s4, s5, s_nil]
diff --git a/spec/ruby/core/array/bsearch_index_spec.rb b/spec/ruby/core/array/bsearch_index_spec.rb
index 94d85b37f3..df2c7c098e 100644
--- a/spec/ruby/core/array/bsearch_index_spec.rb
+++ b/spec/ruby/core/array/bsearch_index_spec.rb
@@ -63,6 +63,10 @@ describe "Array#bsearch_index" do
@array.bsearch_index { |x| -1 }.should be_nil
end
+ it "returns the middle element when block always returns zero" do
+ @array.bsearch_index { |x| 0 }.should == 2
+ end
+
context "magnitude does not effect the result" do
it "returns the index of any matched elements where element is between 4n <= xn < 8n" do
[1, 2].should include(@array.bsearch_index { |x| (1 - x / 4) * (2**100) })
diff --git a/spec/ruby/core/array/count_spec.rb b/spec/ruby/core/array/count_spec.rb
index e778233c16..eaf275aeb7 100644
--- a/spec/ruby/core/array/count_spec.rb
+++ b/spec/ruby/core/array/count_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#count" do
it "returns the number of elements" do
@@ -13,14 +12,4 @@ describe "Array#count" do
it "returns the number of element for which the block evaluates to true" do
[:a, :b, :c].count { |s| s != :b }.should == 2
end
-
- it "ignores the block if there is an argument" do
- -> {
- [:a, :b, :b, :c].count(:b) { |e| e.size > 10 }.should == 2
- }.should complain(/given block not used/)
- end
-
- context "when a block argument given" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :count
- end
end
diff --git a/spec/ruby/core/array/delete_if_spec.rb b/spec/ruby/core/array/delete_if_spec.rb
index 10972eee0e..1459cc8d04 100644
--- a/spec/ruby/core/array/delete_if_spec.rb
+++ b/spec/ruby/core/array/delete_if_spec.rb
@@ -2,7 +2,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
require_relative 'shared/delete_if'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#delete_if" do
@@ -48,35 +47,6 @@ describe "Array#delete_if" do
-> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError)
end
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.delete_if { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "only removes elements for which the block returns true, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.delete_if do |e|
- case e
- when 2 then true
- when 3 then raise StandardError, 'Oops'
- else false
- end
- end
- rescue StandardError
- end
-
- a.should == [1, 3, 4]
- end
-
it_behaves_like :enumeratorized_with_origin_size, :delete_if, [1,2,3]
it_behaves_like :delete_if, :delete_if
-
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :delete_if
end
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb
index 0ea748e47d..f911fd9018 100644
--- a/spec/ruby/core/array/drop_spec.rb
+++ b/spec/ruby/core/array/drop_spec.rb
@@ -50,7 +50,15 @@ describe "Array#drop" do
-> { [1, 2].drop(obj) }.should raise_error(TypeError)
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array)
+ end
end
end
diff --git a/spec/ruby/core/array/drop_while_spec.rb b/spec/ruby/core/array/drop_while_spec.rb
index bd46e8b882..bb783d22a5 100644
--- a/spec/ruby/core/array/drop_while_spec.rb
+++ b/spec/ruby/core/array/drop_while_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#drop_while" do
- @value_to_return = -> _ { true }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :drop_while
-
it "removes elements from the start of the array while the block evaluates to true" do
[1, 2, 3, 4].drop_while { |n| n < 4 }.should == [4]
end
@@ -18,7 +14,15 @@ describe "Array#drop_while" do
[1, 2, 3, false, 5].drop_while { |n| n }.should == [false, 5]
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array)
+ end
end
end
diff --git a/spec/ruby/core/array/each_index_spec.rb b/spec/ruby/core/array/each_index_spec.rb
index 3a4bca9251..51af5842c4 100644
--- a/spec/ruby/core/array/each_index_spec.rb
+++ b/spec/ruby/core/array/each_index_spec.rb
@@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# https://blade.ruby-lang.org/ruby-core/23633
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
describe "Array#each_index" do
before :each do
@@ -40,19 +40,3 @@ describe "Array#each_index" do
it_behaves_like :enumeratorize, :each_index
it_behaves_like :enumeratorized_with_origin_size, :each_index, [1,2,3]
end
-
-describe "Array#each_index" do
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.each_index do |index|
- ScratchPad << index
- array << i if i < 100
- i += 1
- end
-
- ScratchPad.recorded.should == (0..102).to_a # element indices
- end
-end
diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb
index 57d6082f01..cf8e9da6d8 100644
--- a/spec/ruby/core/array/each_spec.rb
+++ b/spec/ruby/core/array/each_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
# Mutating the array while it is being iterated is discouraged as it can result in confusing behavior.
@@ -76,7 +75,3 @@ describe "Array#each" do
it_behaves_like :enumeratorize, :each
it_behaves_like :enumeratorized_with_origin_size, :each, [1,2,3]
end
-
-describe "Array#each" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :each
-end
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index 02360e550d..23728414be 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -52,9 +52,11 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 4 or more arguments are passed when no block given" do
- [].fill('a').should == []
- [].fill('a', 1).should == []
- [].fill('a', 1, 2).should == [nil, 'a', 'a']
+ -> { [].fill('a') }.should_not raise_error(ArgumentError)
+
+ -> { [].fill('a', 1) }.should_not raise_error(ArgumentError)
+
+ -> { [].fill('a', 1, 2) }.should_not raise_error(ArgumentError)
-> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError)
end
@@ -63,52 +65,12 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 3 or more arguments are passed when a block given" do
- [].fill() {|i|}.should == []
- [].fill(1) {|i|}.should == []
- [].fill(1, 2) {|i|}.should == [nil, nil, nil]
- -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
- end
-
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.fill { raise StandardError, 'Oops' }
- rescue
- end
+ -> { [].fill() {|i|} }.should_not raise_error(ArgumentError)
- a.should == [1, 2, 3]
- end
-
- it "only changes elements before error is raised, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.fill do |i|
- case i
- when 0 then -1
- when 1 then -2
- when 2 then raise StandardError, 'Oops'
- else 0
- end
- end
- rescue StandardError
- end
-
- a.should == [-1, -2, 3, 4]
- end
-
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
+ -> { [].fill(1) {|i|} }.should_not raise_error(ArgumentError)
- array.fill do |index|
- ScratchPad << index
- array << i if i < 100
- i++
- index
- end
-
- ScratchPad.recorded.should == [0, 1, 2]
+ -> { [].fill(1, 2) {|i|} }.should_not raise_error(ArgumentError)
+ -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
end
end
@@ -207,25 +169,25 @@ describe "Array#fill with (filler, index, length)" do
[1, 2, 3, 4, 5].fill(-2, -2, &@never_passed).should == [1, 2, 3, 4, 5]
end
- # See: https://blade.ruby-lang.org/ruby-core/17481
+ # See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17481
it "does not raise an exception if the given length is negative and its absolute value does not exceed the index" do
- [1, 2, 3, 4].fill('a', 3, -1).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -2).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -3).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill('a', 3, -1)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -2)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -3)}.should_not raise_error(ArgumentError)
- [1, 2, 3, 4].fill(3, -1, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -2, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -3, &@never_passed).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill(3, -1, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -2, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -3, &@never_passed)}.should_not raise_error(ArgumentError)
end
it "does not raise an exception even if the given length is negative and its absolute value exceeds the index" do
- [1, 2, 3, 4].fill('a', 3, -4).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -5).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -10000).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill('a', 3, -4)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -5)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -10000)}.should_not raise_error(ArgumentError)
- [1, 2, 3, 4].fill(3, -4, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -5, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -10000, &@never_passed).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill(3, -4, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -5, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -10000, &@never_passed)}.should_not raise_error(ArgumentError)
end
it "tries to convert the second and third arguments to Integers using #to_int" do
diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb
index 8596245fb8..aa5fecd96b 100644
--- a/spec/ruby/core/array/fixtures/classes.rb
+++ b/spec/ruby/core/array/fixtures/classes.rb
@@ -160,16 +160,6 @@ module ArraySpecs
end
end
- class ArrayMethodMissing
- def initialize(*values, &block)
- @values = values;
- end
-
- def method_missing(name, *args)
- @values
- end
- end
-
class SortSame
def <=>(other); 0; end
def ==(other); true; end
diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb
index 8c97000c79..1770b5389a 100644
--- a/spec/ruby/core/array/flatten_spec.rb
+++ b/spec/ruby/core/array/flatten_spec.rb
@@ -75,12 +75,24 @@ describe "Array#flatten" do
[[obj]].flatten(1)
end
- it "returns Array instance for Array subclasses" do
- ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
- [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instance for Array subclasses" do
+ ArraySpecs::MyArray[].flatten.should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == ArraySpecs::MyArray[1, 2, 3, 4]
+ [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns Array instance for Array subclasses" do
+ ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
+ [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
+ end
end
it "is not destructive" do
diff --git a/spec/ruby/core/array/initialize_spec.rb b/spec/ruby/core/array/initialize_spec.rb
index b9fa77b16e..a8deed2b84 100644
--- a/spec/ruby/core/array/initialize_spec.rb
+++ b/spec/ruby/core/array/initialize_spec.rb
@@ -53,9 +53,7 @@ describe "Array#initialize with no arguments" do
end
it "does not use the given block" do
- -> {
- -> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
- }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
+ ->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
end
end
diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb
index 62ac157278..b8c5b1e69a 100644
--- a/spec/ruby/core/array/intersect_spec.rb
+++ b/spec/ruby/core/array/intersect_spec.rb
@@ -1,66 +1,17 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
describe 'Array#intersect?' do
ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/15198
describe 'when at least one element in two Arrays is the same' do
it 'returns true' do
- [1, 2].intersect?([2, 3, 4]).should == true
- [2, 3, 4].intersect?([1, 2]).should == true
+ [1, 2].intersect?([2, 3]).should == true
end
end
describe 'when there are no elements in common between two Arrays' do
it 'returns false' do
- [0, 1, 2].intersect?([3, 4]).should == false
- [3, 4].intersect?([0, 1, 2]).should == false
- [3, 4].intersect?([]).should == false
- [].intersect?([0, 1, 2]).should == false
+ [1, 2].intersect?([3, 4]).should == false
end
end
-
- it "tries to convert the passed argument to an Array using #to_ary" do
- obj = mock('[1,2,3]')
- obj.should_receive(:to_ary).and_return([1, 2, 3])
-
- [1, 2].intersect?(obj).should == true
- end
-
- it "determines equivalence between elements in the sense of eql?" do
- obj1 = mock('1')
- obj2 = mock('2')
- obj1.stub!(:hash).and_return(0)
- obj2.stub!(:hash).and_return(0)
- obj1.stub!(:eql?).and_return(true)
- obj2.stub!(:eql?).and_return(true)
-
- [obj1].intersect?([obj2]).should == true
-
- obj1 = mock('3')
- obj2 = mock('4')
- obj1.stub!(:hash).and_return(0)
- obj2.stub!(:hash).and_return(0)
- obj1.stub!(:eql?).and_return(false)
- obj2.stub!(:eql?).and_return(false)
-
- [obj1].intersect?([obj2]).should == false
- end
-
- it "does not call to_ary on array subclasses" do
- [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
- end
-
- it "properly handles an identical item even when its #eql? isn't reflexive" do
- x = mock('x')
- x.stub!(:hash).and_return(42)
- x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
-
- [x].intersect?([x]).should == true
- end
-
- it "has semantic of !(a & b).empty?" do
- [].intersect?([]).should == false
- [nil].intersect?([nil]).should == true
- end
end
end
diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb
index eca51142fb..23d5c99f3a 100644
--- a/spec/ruby/core/array/multiply_spec.rb
+++ b/spec/ruby/core/array/multiply_spec.rb
@@ -76,10 +76,20 @@ describe "Array#* with an integer" do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- it "returns an Array instance" do
- (@array * 0).should be_an_instance_of(Array)
- (@array * 1).should be_an_instance_of(Array)
- (@array * 2).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance" do
+ (@array * 0).should be_an_instance_of(ArraySpecs::MyArray)
+ (@array * 1).should be_an_instance_of(ArraySpecs::MyArray)
+ (@array * 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns an Array instance" do
+ (@array * 0).should be_an_instance_of(Array)
+ (@array * 1).should be_an_instance_of(Array)
+ (@array * 2).should be_an_instance_of(Array)
+ end
end
it "does not call #initialize on the subclass instance" do
diff --git a/spec/ruby/core/array/new_spec.rb b/spec/ruby/core/array/new_spec.rb
index b50a4857b0..96ec6b8198 100644
--- a/spec/ruby/core/array/new_spec.rb
+++ b/spec/ruby/core/array/new_spec.rb
@@ -26,9 +26,7 @@ describe "Array.new with no arguments" do
end
it "does not use the given block" do
- -> {
- -> { Array.new { raise } }.should_not raise_error
- }.should complain(/warning: given block not used/, verbose: true)
+ ->{ Array.new { raise } }.should_not raise_error
end
end
diff --git a/spec/ruby/core/array/none_spec.rb b/spec/ruby/core/array/none_spec.rb
deleted file mode 100644
index 31cd8c46d6..0000000000
--- a/spec/ruby/core/array/none_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
-
-describe "Array#none?" do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :none?
-
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].none?(/baz/) { true }.should == true
- }.should complain(/given block not used/)
- end
-end
diff --git a/spec/ruby/core/array/one_spec.rb b/spec/ruby/core/array/one_spec.rb
deleted file mode 100644
index 0c61907881..0000000000
--- a/spec/ruby/core/array/one_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
-
-describe "Array#one?" do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :one?
-
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].one?(/foo/) { false }.should == true
- }.should complain(/given block not used/)
- end
-end
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index ac133ff9b6..be03551629 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -47,9 +47,7 @@ describe :array_pack_8bit, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
- end
+ [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
end
end
diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb
index 5e3eea55f9..65fdaa45d8 100644
--- a/spec/ruby/core/array/pack/shared/basic.rb
+++ b/spec/ruby/core/array/pack/shared/basic.rb
@@ -31,7 +31,7 @@ describe :array_pack_basic_non_float, shared: true do
# 2 additional directives ('a') are required for the X directive
[@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String)
end
-
+
ruby_version_is ""..."3.2" do
it "warns in verbose mode that a directive is unknown" do
# additional directive ('a') is required for the X directive
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index 1780d7635e..9510cffed7 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -27,9 +27,7 @@ describe :array_pack_float_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
end
end
@@ -107,9 +105,7 @@ describe :array_pack_float_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
end
end
@@ -179,9 +175,7 @@ describe :array_pack_double_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
end
end
@@ -250,9 +244,7 @@ describe :array_pack_double_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
end
end
diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb
index fd21b25b19..d3ce9b5792 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -43,10 +43,8 @@ describe :array_pack_16bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\xcd\xab"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\xcd\xab"
end
end
@@ -107,10 +105,8 @@ describe :array_pack_16bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x65\x78\xab\xcd"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x65\x78\xab\xcd"
end
end
@@ -171,10 +167,8 @@ describe :array_pack_32bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
end
end
@@ -235,10 +229,8 @@ describe :array_pack_32bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
end
end
@@ -359,10 +351,8 @@ describe :array_pack_64bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
- end
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
end
end
@@ -431,10 +421,8 @@ describe :array_pack_64bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
- end
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
end
end
diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb
index 4d8eaef323..130c447bb7 100644
--- a/spec/ruby/core/array/pack/shared/unicode.rb
+++ b/spec/ruby/core/array/pack/shared/unicode.rb
@@ -69,9 +69,7 @@ describe :array_pack_unicode, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack("U\x00U").should == "\x01\x02"
- end
+ [1, 2, 3].pack("U\x00U").should == "\x01\x02"
end
end
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index 48ed4496a5..e241d1519c 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -26,9 +26,7 @@ describe "Array#pack with format 'w'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack("w\x00w").should == "\x01\x02"
- end
+ [1, 2, 3].pack("w\x00w").should == "\x01\x02"
end
end
diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb
index 635bd131c9..3962b05c39 100644
--- a/spec/ruby/core/array/plus_spec.rb
+++ b/spec/ruby/core/array/plus_spec.rb
@@ -14,23 +14,10 @@ describe "Array#+" do
(ary + ary).should == [1, 2, 3, 1, 2, 3]
end
- describe "converts the passed argument to an Array using #to_ary" do
- it "successfully concatenates the resulting array from the #to_ary call" do
- obj = mock('["x", "y"]')
- obj.should_receive(:to_ary).and_return(["x", "y"])
- ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
- end
-
- it "raises a Typeerror if the given argument can't be converted to an array" do
- -> { [1, 2, 3] + nil }.should raise_error(TypeError)
- -> { [1, 2, 3] + "abc" }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
- obj = mock("hello")
- obj.should_receive(:to_ary).and_raise(NoMethodError)
- -> { [1, 2, 3] + obj }.should raise_error(NoMethodError)
- end
+ it "tries to convert the passed argument to an Array using #to_ary" do
+ obj = mock('["x", "y"]')
+ obj.should_receive(:to_ary).and_return(["x", "y"])
+ ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
end
it "properly handles recursive arrays" do
diff --git a/spec/ruby/core/array/product_spec.rb b/spec/ruby/core/array/product_spec.rb
index 6fb3818508..07d2880a96 100644
--- a/spec/ruby/core/array/product_spec.rb
+++ b/spec/ruby/core/array/product_spec.rb
@@ -9,11 +9,6 @@ describe "Array#product" do
ar.called.should == :to_ary
end
- it "returns converted arguments using :method_missing" do
- ar = ArraySpecs::ArrayMethodMissing.new(2,3)
- [1].product(ar).should == [[1,2],[1,3]]
- end
-
it "returns the expected result" do
[1,2].product([3,4,5],[6,8]).should == [[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
[2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]]
diff --git a/spec/ruby/core/array/reject_spec.rb b/spec/ruby/core/array/reject_spec.rb
index 81a467e364..fcf43fabde 100644
--- a/spec/ruby/core/array/reject_spec.rb
+++ b/spec/ruby/core/array/reject_spec.rb
@@ -2,7 +2,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
require_relative 'shared/delete_if'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#reject" do
@@ -48,10 +47,6 @@ describe "Array#reject" do
it_behaves_like :enumeratorized_with_origin_size, :reject, [1,2,3]
end
-describe "Array#reject" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject
-end
-
describe "Array#reject!" do
it "removes elements for which block is true" do
a = [3, 4, 5, 6, 7, 8, 9, 10, 11]
@@ -116,11 +111,6 @@ describe "Array#reject!" do
-> { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(FrozenError)
end
- it "raises a FrozenError on a frozen array only during iteration if called without a block" do
- enum = ArraySpecs.frozen_array.reject!
- -> { enum.each {} }.should raise_error(FrozenError)
- end
-
it "does not truncate the array is the block raises an exception" do
a = [1, 2, 3]
begin
@@ -151,8 +141,3 @@ describe "Array#reject!" do
it_behaves_like :enumeratorized_with_origin_size, :reject!, [1,2,3]
it_behaves_like :delete_if, :reject!
end
-
-describe "Array#reject!" do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject!
-end
diff --git a/spec/ruby/core/array/reverse_each_spec.rb b/spec/ruby/core/array/reverse_each_spec.rb
index 59dabcd33d..28b8bfcb34 100644
--- a/spec/ruby/core/array/reverse_each_spec.rb
+++ b/spec/ruby/core/array/reverse_each_spec.rb
@@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# https://blade.ruby-lang.org/ruby-core/23633
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
describe "Array#reverse_each" do
before :each do
@@ -38,20 +38,6 @@ describe "Array#reverse_each" do
[1, 2, 3].reverse_each.size.should == 3
end
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.reverse_each do |e|
- ScratchPad << e
- array.prepend i if i < 100
- i += 1
- end
-
- ScratchPad.recorded.should == [:c, :a, 1]
- end
-
it_behaves_like :enumeratorize, :reverse_each
it_behaves_like :enumeratorized_with_origin_size, :reverse_each, [1,2,3]
end
diff --git a/spec/ruby/core/array/rindex_spec.rb b/spec/ruby/core/array/rindex_spec.rb
index 13de88818c..175c7bcfe2 100644
--- a/spec/ruby/core/array/rindex_spec.rb
+++ b/spec/ruby/core/array/rindex_spec.rb
@@ -4,7 +4,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# https://blade.ruby-lang.org/ruby-core/23633
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
describe "Array#rindex" do
it "returns the first index backwards from the end where element == to object" do
@@ -68,21 +68,6 @@ describe "Array#rindex" do
seen.should == [3]
end
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.rindex do |e|
- ScratchPad << e
- array.prepend i if i < 100
- i += 1
- false
- end
-
- ScratchPad.recorded.should == [:c, :a, 1]
- end
-
describe "given no argument and no block" do
it "produces an Enumerator" do
enum = [4, 2, 1, 5, 1, 3].rindex
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index 6ef78594f0..5b3aac9aed 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -29,10 +29,6 @@ describe "Array#sample" do
[4].sample(random: Random.new(42)).should equal(4)
end
- it "returns a single value when not passed a count and a Random class is given" do
- [4].sample(random: Random).should equal(4)
- end
-
it "returns an empty Array when passed zero" do
[4].sample(0).should == []
end
diff --git a/spec/ruby/core/array/shared/collect.rb b/spec/ruby/core/array/shared/collect.rb
index 030302ced6..8d75f7db9a 100644
--- a/spec/ruby/core/array/shared/collect.rb
+++ b/spec/ruby/core/array/shared/collect.rb
@@ -1,5 +1,4 @@
require_relative '../../enumerable/shared/enumeratorized'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
describe :array_collect, shared: true do
it "returns a copy of array with each element replaced by the value returned by block" do
@@ -47,8 +46,6 @@ describe :array_collect, shared: true do
@object = [1, 2, 3, 4]
end
it_should_behave_like :enumeratorized_with_origin_size
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
describe :array_collect_b, shared: true do
@@ -105,37 +102,8 @@ describe :array_collect_b, shared: true do
end
end
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.send(@method) { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "only changes elements before error is raised, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.send(@method) do |e|
- case e
- when 1 then -1
- when 2 then -2
- when 3 then raise StandardError, 'Oops'
- else 0
- end
- end
- rescue StandardError
- end
-
- a.should == [-1, -2, 3, 4]
- end
-
before :all do
@object = [1, 2, 3, 4]
end
it_should_behave_like :enumeratorized_with_origin_size
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/index.rb b/spec/ruby/core/array/shared/index.rb
index a4a0adbab6..a9896554f2 100644
--- a/spec/ruby/core/array/shared/index.rb
+++ b/spec/ruby/core/array/shared/index.rb
@@ -1,5 +1,3 @@
-require_relative '../shared/iterable_and_tolerating_size_increasing'
-
describe :array_index, shared: true do
it "returns the index of the first element == to object" do
x = mock('3')
@@ -36,6 +34,4 @@ describe :array_index, shared: true do
[].send(@method).should be_an_instance_of(Enumerator)
end
end
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/intersection.rb b/spec/ruby/core/array/shared/intersection.rb
index 0b4166ab63..49849b08c2 100644
--- a/spec/ruby/core/array/shared/intersection.rb
+++ b/spec/ruby/core/array/shared/intersection.rb
@@ -11,8 +11,7 @@ describe :array_intersection, shared: true do
end
it "creates an array with elements in order they are first encountered" do
- [ 1, 2, 3, 2, 5, 6, 7, 8 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5] # array > other
- [ 5, 2, 3, 4 ].send(@method, [ 1, 2, 3, 2, 5, 6, 7, 8 ]).should == [5, 2, 3] # array < other
+ [ 1, 2, 3, 2, 5 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5]
end
it "does not modify the original Array" do
diff --git a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb b/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb
deleted file mode 100644
index 3e73bad44b..0000000000
--- a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-describe :array_iterable_and_tolerating_size_increasing, shared: true do
- before do
- @value_to_return ||= -> _ { nil }
- end
-
- it "tolerates increasing an array size during iteration" do
- # The goal is to trigger potential reallocation of internal array storage, so we:
- # - use elements of different types, starting with the less generic (Integer)
- # - add reasonably big number of new elements (~ 100)
- array = [1, 2, 3] # to test some methods we need several uniq elements
- array_to_join = [:a, :b, :c] + (4..100).to_a
-
- ScratchPad.record []
- i = 0
-
- array.send(@method) do |e|
- ScratchPad << e
- array << array_to_join[i] if i < array_to_join.size
- i += 1
- @value_to_return.call(e)
- end
-
- ScratchPad.recorded.should == [1, 2, 3] + array_to_join
- end
-end
diff --git a/spec/ruby/core/array/shared/keep_if.rb b/spec/ruby/core/array/shared/keep_if.rb
index 43a047c0a7..f26aff028c 100644
--- a/spec/ruby/core/array/shared/keep_if.rb
+++ b/spec/ruby/core/array/shared/keep_if.rb
@@ -1,5 +1,4 @@
require_relative '../../enumerable/shared/enumeratorized'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
describe :keep_if, shared: true do
it "deletes elements for which the block returns a false value" do
@@ -57,39 +56,5 @@ describe :keep_if, shared: true do
-> { @frozen.send(@method) { false } }.should raise_error(FrozenError)
end
end
-
- it "raises a FrozenError on a frozen array only during iteration if called without a block" do
- enum = @frozen.send(@method)
- -> { enum.each {} }.should raise_error(FrozenError)
- end
- end
-
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.send(@method) { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
end
-
- it "only changes elements before error is raised, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.send(@method) do |e|
- case e
- when 2 then false
- when 3 then raise StandardError, 'Oops'
- else true
- end
- end
- rescue StandardError
- end
-
- a.should == [1, 3, 4]
- end
-
- @value_to_return = -> _ { true }
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb
index 9c2cbf76c4..09101e8ab5 100644
--- a/spec/ruby/core/array/shared/select.rb
+++ b/spec/ruby/core/array/shared/select.rb
@@ -2,14 +2,11 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/enumeratorize'
require_relative '../shared/keep_if'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
require_relative '../../enumerable/shared/enumeratorized'
describe :array_select, shared: true do
it_should_behave_like :enumeratorize
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
-
before :each do
@object = [1,2,3]
end
diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb
index d2866970a5..8fb33738b9 100644
--- a/spec/ruby/core/array/shared/slice.rb
+++ b/spec/ruby/core/array/shared/slice.rb
@@ -397,28 +397,56 @@ describe :array_slice, shared: true do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- it "returns a Array instance with [n, m]" do
- @array.send(@method, 0, 2).should be_an_instance_of(Array)
- end
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance with [n, m]" do
+ @array.send(@method, 0, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [-n, m]" do
- @array.send(@method, -3, 2).should be_an_instance_of(Array)
- end
+ it "returns a subclass instance with [-n, m]" do
+ @array.send(@method, -3, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [n..m]" do
- @array.send(@method, 1..3).should be_an_instance_of(Array)
- end
+ it "returns a subclass instance with [n..m]" do
+ @array.send(@method, 1..3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [n...m]" do
- @array.send(@method, 1...3).should be_an_instance_of(Array)
- end
+ it "returns a subclass instance with [n...m]" do
+ @array.send(@method, 1...3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [-n..-m]" do
- @array.send(@method, -3..-1).should be_an_instance_of(Array)
+ it "returns a subclass instance with [-n..-m]" do
+ @array.send(@method, -3..-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n...-m]" do
+ @array.send(@method, -3...-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
end
- it "returns a Array instance with [-n...-m]" do
- @array.send(@method, -3...-1).should be_an_instance_of(Array)
+ ruby_version_is '3.0' do
+ it "returns a Array instance with [n, m]" do
+ @array.send(@method, 0, 2).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n, m]" do
+ @array.send(@method, -3, 2).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [n..m]" do
+ @array.send(@method, 1..3).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [n...m]" do
+ @array.send(@method, 1...3).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n..-m]" do
+ @array.send(@method, -3..-1).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n...-m]" do
+ @array.send(@method, -3...-1).should be_an_instance_of(Array)
+ end
end
it "returns an empty array when m == n with [m...n]" do
@@ -506,237 +534,239 @@ describe :array_slice, shared: true do
a.send(@method, eval("(-9...)")).should == nil
end
- describe "can be sliced with Enumerator::ArithmeticSequence" do
- before :each do
- @array = [0, 1, 2, 3, 4, 5]
- end
+ ruby_version_is "3.0" do
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ before :each do
+ @array = [0, 1, 2, 3, 4, 5]
+ end
- it "has endless range and positive steps" do
- @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
- @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
- @array.send(@method, eval("(0..).step(10)")).should == [0]
+ it "has endless range and positive steps" do
+ @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
+ @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
+ @array.send(@method, eval("(0..).step(10)")).should == [0]
- @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
- @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
- @array.send(@method, eval("(2..).step(10)")).should == [2]
+ @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
+ @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(2..).step(10)")).should == [2]
- @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
- @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
- @array.send(@method, eval("(-3..).step(10)")).should == [3]
- end
+ @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
+ @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
+ @array.send(@method, eval("(-3..).step(10)")).should == [3]
+ end
- it "has beginless range and positive steps" do
- # end with zero index
- @array.send(@method, (..0).step(1)).should == [0]
- @array.send(@method, (...0).step(1)).should == []
+ it "has beginless range and positive steps" do
+ # end with zero index
+ @array.send(@method, (..0).step(1)).should == [0]
+ @array.send(@method, (...0).step(1)).should == []
- @array.send(@method, (..0).step(2)).should == [0]
- @array.send(@method, (...0).step(2)).should == []
+ @array.send(@method, (..0).step(2)).should == [0]
+ @array.send(@method, (...0).step(2)).should == []
- @array.send(@method, (..0).step(10)).should == [0]
- @array.send(@method, (...0).step(10)).should == []
+ @array.send(@method, (..0).step(10)).should == [0]
+ @array.send(@method, (...0).step(10)).should == []
- # end with positive index
- @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3]
- @array.send(@method, (...3).step(1)).should == [0, 1, 2]
+ # end with positive index
+ @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3]
+ @array.send(@method, (...3).step(1)).should == [0, 1, 2]
- @array.send(@method, (..3).step(2)).should == [0, 2]
- @array.send(@method, (...3).step(2)).should == [0, 2]
+ @array.send(@method, (..3).step(2)).should == [0, 2]
+ @array.send(@method, (...3).step(2)).should == [0, 2]
- @array.send(@method, (..3).step(10)).should == [0]
- @array.send(@method, (...3).step(10)).should == [0]
+ @array.send(@method, (..3).step(10)).should == [0]
+ @array.send(@method, (...3).step(10)).should == [0]
- # end with negative index
- @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,]
- @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3]
+ # end with negative index
+ @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,]
+ @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3]
- @array.send(@method, (..-2).step(2)).should == [0, 2, 4]
- @array.send(@method, (...-2).step(2)).should == [0, 2]
+ @array.send(@method, (..-2).step(2)).should == [0, 2, 4]
+ @array.send(@method, (...-2).step(2)).should == [0, 2]
- @array.send(@method, (..-2).step(10)).should == [0]
- @array.send(@method, (...-2).step(10)).should == [0]
- end
+ @array.send(@method, (..-2).step(10)).should == [0]
+ @array.send(@method, (...-2).step(10)).should == [0]
+ end
- it "has endless range and negative steps" do
- @array.send(@method, eval("(0..).step(-1)")).should == [0]
- @array.send(@method, eval("(0..).step(-2)")).should == [0]
- @array.send(@method, eval("(0..).step(-10)")).should == [0]
+ it "has endless range and negative steps" do
+ @array.send(@method, eval("(0..).step(-1)")).should == [0]
+ @array.send(@method, eval("(0..).step(-2)")).should == [0]
+ @array.send(@method, eval("(0..).step(-10)")).should == [0]
- @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
- @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
+ @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
+ @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
- @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
- @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
- end
+ @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
+ @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
+ end
- it "has closed range and positive steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(1)")).should == [0]
- @array.send(@method, eval("(0...0).step(1)")).should == []
+ it "has closed range and positive steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(1)")).should == []
- @array.send(@method, eval("(0..0).step(2)")).should == [0]
- @array.send(@method, eval("(0...0).step(2)")).should == []
+ @array.send(@method, eval("(0..0).step(2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(2)")).should == []
- @array.send(@method, eval("(0..0).step(10)")).should == [0]
- @array.send(@method, eval("(0...0).step(10)")).should == []
+ @array.send(@method, eval("(0..0).step(10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(10)")).should == []
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
- @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
+ @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
- @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...3).step(2)")).should == [1]
+ @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...3).step(2)")).should == [1]
- @array.send(@method, eval("(1..3).step(10)")).should == [1]
- @array.send(@method, eval("(1...3).step(10)")).should == [1]
+ @array.send(@method, eval("(1..3).step(10)")).should == [1]
+ @array.send(@method, eval("(1...3).step(10)")).should == [1]
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
- @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
+ @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
- @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1..-2).step(10)")).should == [1]
- @array.send(@method, eval("(1...-2).step(10)")).should == [1]
+ @array.send(@method, eval("(1..-2).step(10)")).should == [1]
+ @array.send(@method, eval("(1...-2).step(10)")).should == [1]
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
- @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...4).step(2)")).should == [2]
+ @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...4).step(2)")).should == [2]
- @array.send(@method, eval("(-4..4).step(10)")).should == [2]
- @array.send(@method, eval("(-4...4).step(10)")).should == [2]
+ @array.send(@method, eval("(-4..4).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...4).step(10)")).should == [2]
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
- @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
+ @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
- @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
- @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
- end
+ @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
+ end
- it "has closed range and negative steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(-1)")).should == [0]
- @array.send(@method, eval("(0...0).step(-1)")).should == []
+ it "has closed range and negative steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(-1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-1)")).should == []
- @array.send(@method, eval("(0..0).step(-2)")).should == [0]
- @array.send(@method, eval("(0...0).step(-2)")).should == []
+ @array.send(@method, eval("(0..0).step(-2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-2)")).should == []
- @array.send(@method, eval("(0..0).step(-10)")).should == [0]
- @array.send(@method, eval("(0...0).step(-10)")).should == []
+ @array.send(@method, eval("(0..0).step(-10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-10)")).should == []
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(-1)")).should == []
- @array.send(@method, eval("(1...3).step(-1)")).should == []
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(-1)")).should == []
+ @array.send(@method, eval("(1...3).step(-1)")).should == []
- @array.send(@method, eval("(1..3).step(-2)")).should == []
- @array.send(@method, eval("(1...3).step(-2)")).should == []
+ @array.send(@method, eval("(1..3).step(-2)")).should == []
+ @array.send(@method, eval("(1...3).step(-2)")).should == []
- @array.send(@method, eval("(1..3).step(-10)")).should == []
- @array.send(@method, eval("(1...3).step(-10)")).should == []
+ @array.send(@method, eval("(1..3).step(-10)")).should == []
+ @array.send(@method, eval("(1...3).step(-10)")).should == []
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(-1)")).should == []
- @array.send(@method, eval("(1...-2).step(-1)")).should == []
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(-1)")).should == []
+ @array.send(@method, eval("(1...-2).step(-1)")).should == []
- @array.send(@method, eval("(1..-2).step(-2)")).should == []
- @array.send(@method, eval("(1...-2).step(-2)")).should == []
+ @array.send(@method, eval("(1..-2).step(-2)")).should == []
+ @array.send(@method, eval("(1...-2).step(-2)")).should == []
- @array.send(@method, eval("(1..-2).step(-10)")).should == []
- @array.send(@method, eval("(1...-2).step(-10)")).should == []
+ @array.send(@method, eval("(1..-2).step(-10)")).should == []
+ @array.send(@method, eval("(1...-2).step(-10)")).should == []
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(-1)")).should == []
- @array.send(@method, eval("(-4...4).step(-1)")).should == []
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(-1)")).should == []
+ @array.send(@method, eval("(-4...4).step(-1)")).should == []
- @array.send(@method, eval("(-4..4).step(-2)")).should == []
- @array.send(@method, eval("(-4...4).step(-2)")).should == []
+ @array.send(@method, eval("(-4..4).step(-2)")).should == []
+ @array.send(@method, eval("(-4...4).step(-2)")).should == []
- @array.send(@method, eval("(-4..4).step(-10)")).should == []
- @array.send(@method, eval("(-4...4).step(-10)")).should == []
+ @array.send(@method, eval("(-4..4).step(-10)")).should == []
+ @array.send(@method, eval("(-4...4).step(-10)")).should == []
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(-1)")).should == []
- @array.send(@method, eval("(-4...-2).step(-1)")).should == []
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(-1)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-1)")).should == []
- @array.send(@method, eval("(-4..-2).step(-2)")).should == []
- @array.send(@method, eval("(-4...-2).step(-2)")).should == []
+ @array.send(@method, eval("(-4..-2).step(-2)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-2)")).should == []
- @array.send(@method, eval("(-4..-2).step(-10)")).should == []
- @array.send(@method, eval("(-4...-2).step(-10)")).should == []
- end
+ @array.send(@method, eval("(-4..-2).step(-10)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-10)")).should == []
+ end
- it "has inverted closed range and positive steps" do
- # start and end with positive index
- @array.send(@method, eval("(3..1).step(1)")).should == []
- @array.send(@method, eval("(3...1).step(1)")).should == []
+ it "has inverted closed range and positive steps" do
+ # start and end with positive index
+ @array.send(@method, eval("(3..1).step(1)")).should == []
+ @array.send(@method, eval("(3...1).step(1)")).should == []
- @array.send(@method, eval("(3..1).step(2)")).should == []
- @array.send(@method, eval("(3...1).step(2)")).should == []
+ @array.send(@method, eval("(3..1).step(2)")).should == []
+ @array.send(@method, eval("(3...1).step(2)")).should == []
- @array.send(@method, eval("(3..1).step(10)")).should == []
- @array.send(@method, eval("(3...1).step(10)")).should == []
+ @array.send(@method, eval("(3..1).step(10)")).should == []
+ @array.send(@method, eval("(3...1).step(10)")).should == []
- # start with negative index, end with positive index
- @array.send(@method, eval("(-2..1).step(1)")).should == []
- @array.send(@method, eval("(-2...1).step(1)")).should == []
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-2..1).step(1)")).should == []
+ @array.send(@method, eval("(-2...1).step(1)")).should == []
- @array.send(@method, eval("(-2..1).step(2)")).should == []
- @array.send(@method, eval("(-2...1).step(2)")).should == []
+ @array.send(@method, eval("(-2..1).step(2)")).should == []
+ @array.send(@method, eval("(-2...1).step(2)")).should == []
- @array.send(@method, eval("(-2..1).step(10)")).should == []
- @array.send(@method, eval("(-2...1).step(10)")).should == []
+ @array.send(@method, eval("(-2..1).step(10)")).should == []
+ @array.send(@method, eval("(-2...1).step(10)")).should == []
- # start with positive index, end with negative index
- @array.send(@method, eval("(4..-4).step(1)")).should == []
- @array.send(@method, eval("(4...-4).step(1)")).should == []
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(4..-4).step(1)")).should == []
+ @array.send(@method, eval("(4...-4).step(1)")).should == []
- @array.send(@method, eval("(4..-4).step(2)")).should == []
- @array.send(@method, eval("(4...-4).step(2)")).should == []
+ @array.send(@method, eval("(4..-4).step(2)")).should == []
+ @array.send(@method, eval("(4...-4).step(2)")).should == []
- @array.send(@method, eval("(4..-4).step(10)")).should == []
- @array.send(@method, eval("(4...-4).step(10)")).should == []
+ @array.send(@method, eval("(4..-4).step(10)")).should == []
+ @array.send(@method, eval("(4...-4).step(10)")).should == []
- # start with negative index, end with negative index
- @array.send(@method, eval("(-2..-4).step(1)")).should == []
- @array.send(@method, eval("(-2...-4).step(1)")).should == []
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-2..-4).step(1)")).should == []
+ @array.send(@method, eval("(-2...-4).step(1)")).should == []
- @array.send(@method, eval("(-2..-4).step(2)")).should == []
- @array.send(@method, eval("(-2...-4).step(2)")).should == []
+ @array.send(@method, eval("(-2..-4).step(2)")).should == []
+ @array.send(@method, eval("(-2...-4).step(2)")).should == []
- @array.send(@method, eval("(-2..-4).step(10)")).should == []
- @array.send(@method, eval("(-2...-4).step(10)")).should == []
- end
+ @array.send(@method, eval("(-2..-4).step(10)")).should == []
+ @array.send(@method, eval("(-2...-4).step(10)")).should == []
+ end
- it "has range with bounds outside of array" do
- # end is equal to array's length
- @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
- -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
+ it "has range with bounds outside of array" do
+ # end is equal to array's length
+ @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
+ -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
- # end is greater than length with positive steps
- @array.send(@method, (1..6).step(2)).should == [1, 3, 5]
- @array.send(@method, (2..7).step(2)).should == [2, 4]
- -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
+ # end is greater than length with positive steps
+ @array.send(@method, (1..6).step(2)).should == [1, 3, 5]
+ @array.send(@method, (2..7).step(2)).should == [2, 4]
+ -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
- # begin is greater than length with negative steps
- @array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
- @array.send(@method, (7..2).step(-2)).should == [5, 3]
- -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
- end
+ # begin is greater than length with negative steps
+ @array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (7..2).step(-2)).should == [5, 3]
+ -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
+ end
- it "has endless range with start outside of array's bounds" do
- @array.send(@method, eval("(6..).step(1)")).should == []
- @array.send(@method, eval("(7..).step(1)")).should == nil
+ it "has endless range with start outside of array's bounds" do
+ @array.send(@method, eval("(6..).step(1)")).should == []
+ @array.send(@method, eval("(7..).step(1)")).should == nil
- @array.send(@method, eval("(6..).step(2)")).should == []
- -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
+ @array.send(@method, eval("(6..).step(2)")).should == []
+ -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
+ end
end
end
diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb
index 1d528c124f..b255147c75 100644
--- a/spec/ruby/core/array/shuffle_spec.rb
+++ b/spec/ruby/core/array/shuffle_spec.rb
@@ -47,10 +47,6 @@ describe "Array#shuffle" do
[1, 2].shuffle(random: random).should be_an_instance_of(Array)
end
- it "accepts a Random class for the value for random: argument" do
- [1, 2].shuffle(random: Random).should be_an_instance_of(Array)
- end
-
it "calls #to_int on the Object returned by #rand" do
value = mock("array_shuffle_random_value")
value.should_receive(:to_int).at_least(1).times.and_return(0)
@@ -97,14 +93,4 @@ describe "Array#shuffle!" do
-> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError)
-> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError)
end
-
- it "matches CRuby with random:" do
- %w[a b c].shuffle(random: Random.new(1)).should == %w[a c b]
- (0..10).to_a.shuffle(random: Random.new(10)).should == [2, 6, 8, 5, 7, 10, 3, 1, 0, 4, 9]
- end
-
- it "matches CRuby with srand" do
- srand(123)
- %w[a b c d e f g h i j k].shuffle.should == %w[a e f h i j d b g k c]
- end
end
diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb
index 731c129251..8e1499855a 100644
--- a/spec/ruby/core/array/slice_spec.rb
+++ b/spec/ruby/core/array/slice_spec.rb
@@ -187,28 +187,56 @@ describe "Array#slice!" do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- it "returns a Array instance with [n, m]" do
- @array.slice!(0, 2).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance with [n, m]" do
+ @array.slice!(0, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n, m]" do
+ @array.slice!(-3, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [n..m]" do
+ @array.slice!(1..3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [n...m]" do
+ @array.slice!(1...3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n..-m]" do
+ @array.slice!(-3..-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n...-m]" do
+ @array.slice!(-3...-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
end
- it "returns a Array instance with [-n, m]" do
- @array.slice!(-3, 2).should be_an_instance_of(Array)
- end
+ ruby_version_is '3.0' do
+ it "returns a Array instance with [n, m]" do
+ @array.slice!(0, 2).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n..m]" do
- @array.slice!(1..3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n, m]" do
+ @array.slice!(-3, 2).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n...m]" do
- @array.slice!(1...3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n..m]" do
+ @array.slice!(1..3).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n..-m]" do
- @array.slice!(-3..-1).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n...m]" do
+ @array.slice!(1...3).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n..-m]" do
+ @array.slice!(-3..-1).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n...-m]" do
- @array.slice!(-3...-1).should be_an_instance_of(Array)
+ it "returns a Array instance with [-n...-m]" do
+ @array.slice!(-3...-1).should be_an_instance_of(Array)
+ end
end
end
end
diff --git a/spec/ruby/core/array/sort_by_spec.rb b/spec/ruby/core/array/sort_by_spec.rb
index 0334f953f6..7cea6ec6d3 100644
--- a/spec/ruby/core/array/sort_by_spec.rb
+++ b/spec/ruby/core/array/sort_by_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#sort_by!" do
@@ -32,11 +31,6 @@ describe "Array#sort_by!" do
-> { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(FrozenError)
end
- it "raises a FrozenError on a frozen array only during iteration if called without a block" do
- enum = ArraySpecs.frozen_array.sort_by!
- -> { enum.each {} }.should raise_error(FrozenError)
- end
-
it "returns the specified value when it would break in the given block" do
[1, 2, 3].sort_by!{ break :a }.should == :a
end
@@ -54,32 +48,5 @@ describe "Array#sort_by!" do
[1].sort_by!(&:to_s).should == [1]
end
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.sort_by! { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "doesn't change array if error is raised" do
- a = [4, 3, 2, 1]
- begin
- a.sort_by! do |e|
- raise StandardError, 'Oops' if e == 1
- e
- end
- rescue StandardError
- end
-
- a.should == [4, 3, 2, 1]
- end
-
it_behaves_like :enumeratorized_with_origin_size, :sort_by!, [1,2,3]
end
-
-describe "Array#sort_by!" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :sort_by!
-end
diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb
index 06abe06135..8ca8353a67 100644
--- a/spec/ruby/core/array/sum_spec.rb
+++ b/spec/ruby/core/array/sum_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#sum" do
it "returns the sum of elements" do
@@ -10,12 +9,8 @@ describe "Array#sum" do
[1, 2, 3].sum { |i| i * 10 }.should == 60
end
- it "doesn't apply the block init" do
- [1, 2, 3].sum(1) { |i| i * 10 }.should == 61
- end
-
# https://bugs.ruby-lang.org/issues/12217
- # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214
+ # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214
it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do
floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5]
naive_sum = floats.reduce { |sum, e| sum + e }
@@ -73,18 +68,4 @@ describe "Array#sum" do
a.should_receive(:+).with(b).and_return(42)
[b].sum(a).should == 42
end
-
- ruby_bug '#19530', ''...'3.3' do
- it "calls + on the init value" do
- a = mock("a")
- b = mock("b")
- a.should_receive(:+).with(42).and_return(b)
- [42].sum(a).should == b
- end
- end
-end
-
-describe "Array#sum" do
- @value_to_return = -> _ { 1 }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :sum
end
diff --git a/spec/ruby/core/array/take_spec.rb b/spec/ruby/core/array/take_spec.rb
index c4f0ac9aa4..4fb6f0ce75 100644
--- a/spec/ruby/core/array/take_spec.rb
+++ b/spec/ruby/core/array/take_spec.rb
@@ -26,7 +26,15 @@ describe "Array#take" do
->{ [1].take(-3) }.should raise_error(ArgumentError)
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array)
+ end
end
end
diff --git a/spec/ruby/core/array/take_while_spec.rb b/spec/ruby/core/array/take_while_spec.rb
index 8f50260b42..363419b265 100644
--- a/spec/ruby/core/array/take_while_spec.rb
+++ b/spec/ruby/core/array/take_while_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#take_while" do
it "returns all elements until the block returns false" do
@@ -15,12 +14,15 @@ describe "Array#take_while" do
[1, 2, false, 4].take_while{ |element| element }.should == [1, 2]
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray)
+ end
end
-end
-describe "Array#take_while" do
- @value_to_return = -> _ { true }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :take_while
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array)
+ end
+ end
end
diff --git a/spec/ruby/core/array/to_h_spec.rb b/spec/ruby/core/array/to_h_spec.rb
index f4578211a1..f5a7e546e6 100644
--- a/spec/ruby/core/array/to_h_spec.rb
+++ b/spec/ruby/core/array/to_h_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#to_h" do
it "converts empty array to empty hash" do
@@ -78,8 +77,3 @@ describe "Array#to_h" do
end
end
end
-
-describe "Array#to_h" do
- @value_to_return = -> e { [e, e.to_s] }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :to_h
-end
diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb
index bea8815006..47b4722d80 100644
--- a/spec/ruby/core/array/try_convert_spec.rb
+++ b/spec/ruby/core/array/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Array.try_convert" do
it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(Object.new)
- -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)")
+ -> { Array.try_convert obj }.should raise_error(TypeError)
end
it "does not rescue exceptions raised by #to_ary" do
diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb
index d5d826db15..4461cae16b 100644
--- a/spec/ruby/core/array/uniq_spec.rb
+++ b/spec/ruby/core/array/uniq_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#uniq" do
it "returns an array with no duplicates" do
@@ -85,8 +84,16 @@ describe "Array#uniq" do
[false, nil, 42].uniq { :bar }.should == [false]
end
- it "returns Array instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instance on Array subclasses" do
+ ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns Array instance on Array subclasses" do
+ ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
+ end
end
it "properly handles an identical item even when its #eql? isn't reflexive" do
@@ -124,11 +131,6 @@ describe "Array#uniq" do
end
end
-describe "Array#uniq" do
- @value_to_return = -> e { e }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq
-end
-
describe "Array#uniq!" do
it "modifies the array in place" do
a = [ "a", "a", "b", "b", "c" ]
@@ -212,32 +214,4 @@ describe "Array#uniq!" do
a.uniq!
a.should == [x]
end
-
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.send(@method) { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "doesn't change array if error is raised" do
- a = [1, 1, 2, 2, 3, 3, 4, 4]
- begin
- a.send(@method) do |e|
- raise StandardError, 'Oops' if e == 3
- e
- end
- rescue StandardError
- end
-
- a.should == [1, 1, 2, 2, 3, 3, 4, 4]
- end
-end
-
-describe "Array#uniq!" do
- @value_to_return = -> e { e }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq!
end
diff --git a/spec/ruby/core/basicobject/fixtures/classes.rb b/spec/ruby/core/basicobject/fixtures/classes.rb
index ed5a2dda17..d1785afe31 100644
--- a/spec/ruby/core/basicobject/fixtures/classes.rb
+++ b/spec/ruby/core/basicobject/fixtures/classes.rb
@@ -15,231 +15,8 @@ module BasicObjectSpecs
include InstExec
end
- module InstEval
- module CVar
- module Get
- class ReceiverScope
- @@cvar = :value_defined_in_receiver_scope
- end
-
- class BlockDefinitionScope
- @@cvar = :value_defined_in_block_definition_scope
-
- def block
- -> * { @@cvar }
- end
- end
-
- class CallerScope
- @@cvar = :value_defined_in_caller_scope
-
- def get_class_variable_with_string(obj)
- obj.instance_eval("@@cvar")
- end
-
- def get_class_variable_with_block(obj, block)
- obj.instance_eval(&block)
- end
- end
-
- class CallerWithoutCVarScope
- def get_class_variable_with_string(obj)
- obj.instance_eval("@@cvar")
- end
- end
-
- ReceiverWithCVarDefinedInSingletonClass = Class.new.new.tap do |obj|
- obj.singleton_class.class_variable_set(:@@cvar, :value_defined_in_receiver_singleton_class)
- end
- end
-
- module Set
- class ReceiverScope
- end
-
- class BlockDefinitionScope
- def self.get_class_variable
- @@cvar
- end
-
- def block_to_assign(value)
- -> * { @@cvar = value }
- end
- end
-
- class CallerScope
- def self.get_class_variable
- @@cvar
- end
-
- def set_class_variable_with_string(obj, value)
- obj.instance_eval("@@cvar=#{value.inspect}")
- end
-
- def set_class_variable_with_block(obj, block)
- obj.instance_eval(&block)
- end
- end
- end
- end
- end
-
- module InstEval
- module Constants
- module ConstantInReceiverSingletonClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- FOO = :Receiver
-
- def initialize
- self.singleton_class.const_set(:FOO, :singleton_class)
- end
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- FOO = :Caller
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInReceiverClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- FOO = :Receiver
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- FOO = :Caller
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInCallerClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- # FOO is not declared in a receiver class
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- FOO = :Caller
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInCallerOuterScopes
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- # FOO is not declared in a receiver class
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- # FOO is not declared in a caller class
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInReceiverParentClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- # FOO is not declared in a receiver class
- end
- end
-
- module CallerScope
- # FOO is not declared in a caller outer scopes
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- # FOO is not declared in a caller class
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
- end
+ module InstEvalCVar
+ instance_eval { @@count = 2 }
end
class InstEvalConst
@@ -249,6 +26,7 @@ module BasicObjectSpecs
module InstEvalOuter
module Inner
obj = InstEvalConst.new
+ X_BY_STR = obj.instance_eval("INST_EVAL_CONST_X") rescue nil
X_BY_BLOCK = obj.instance_eval { INST_EVAL_CONST_X } rescue nil
end
end
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index 1f3a43f341..350b08a30e 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -84,30 +84,11 @@ describe "BasicObject#instance_eval" do
end
- ruby_version_is "3.3" do
- it "uses the caller location as default location" do
- f = Object.new
- f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
- end
-
it "has access to receiver's instance variables" do
BasicObjectSpecs::IVars.new.instance_eval { @secret }.should == 99
BasicObjectSpecs::IVars.new.instance_eval("@secret").should == 99
end
- it "raises TypeError for frozen objects when tries to set receiver's instance variables" do
- -> { nil.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen NilClass: nil")
- -> { true.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen TrueClass: true")
- -> { false.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen FalseClass: false")
- -> { 1.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Integer: 1")
- -> { :symbol.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Symbol: :symbol")
-
- obj = Object.new
- obj.freeze
- -> { obj.instance_eval { @foo = 42 } }.should raise_error(FrozenError)
- end
-
it "treats block-local variables as local to the block" do
prc = instance_eval <<-CODE
proc do |x, prc|
@@ -124,6 +105,11 @@ describe "BasicObject#instance_eval" do
prc.call(false, prc).should == 1
end
+ it "sets class variables in the receiver" do
+ BasicObjectSpecs::InstEvalCVar.class_variables.should include(:@@count)
+ BasicObjectSpecs::InstEvalCVar.send(:class_variable_get, :@@count).should == 2
+ end
+
it "makes the receiver metaclass the scoped class when used with a string" do
obj = Object.new
obj.instance_eval %{
@@ -133,52 +119,8 @@ describe "BasicObject#instance_eval" do
obj.singleton_class.const_get(:B).should be_an_instance_of(Class)
end
- describe "constants lookup when a String given" do
- it "looks in the receiver singleton class first" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :singleton_class
- end
-
- ruby_version_is ""..."3.1" do
- it "looks in the caller scope next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :Caller
- end
- end
-
- ruby_version_is "3.1" do
- it "looks in the receiver class next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :Receiver
- end
- end
-
- it "looks in the caller class next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :Caller
- end
-
- it "looks in the caller outer scopes next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :CallerScope
- end
-
- it "looks in the receiver class hierarchy next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :ReceiverParent
- end
+ it "gets constants in the receiver if a string given" do
+ BasicObjectSpecs::InstEvalOuter::Inner::X_BY_STR.should == 2
end
it "doesn't get constants in the receiver if a block given" do
@@ -194,51 +136,17 @@ describe "BasicObject#instance_eval" do
end.should raise_error(TypeError)
end
- describe "class variables lookup" do
- it "gets class variables in the caller class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new
-
- caller.get_class_variable_with_string(receiver).should == :value_defined_in_caller_scope
- end
-
- it "gets class variables in the block definition scope when called with a block" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new
- block = BasicObjectSpecs::InstEval::CVar::Get::BlockDefinitionScope.new.block
-
- caller.get_class_variable_with_block(receiver, block).should == :value_defined_in_block_definition_scope
- end
+quarantine! do # Not clean, leaves cvars lying around to break other specs
+ it "scopes class var accesses in the caller when called on an Integer" do
+ # Integer can take instance vars
+ Integer.class_eval "@@__tmp_instance_eval_spec = 1"
+ (defined? @@__tmp_instance_eval_spec).should be_nil
- it "sets class variables in the caller class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new
-
- caller.set_class_variable_with_string(receiver, 1)
- BasicObjectSpecs::InstEval::CVar::Set::CallerScope.get_class_variable.should == 1
- end
-
- it "sets class variables in the block definition scope when called with a block" do
- receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new
- block = BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.new.block_to_assign(1)
-
- caller.set_class_variable_with_block(receiver, block)
- BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.get_class_variable.should == 1
- end
-
- it "does not have access to class variables in the receiver class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
- -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
- end
-
- it "does not have access to class variables in the receiver's singleton class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverWithCVarDefinedInSingletonClass
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
- -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
- end
+ @@__tmp_instance_eval_spec = 2
+ 1.instance_eval { @@__tmp_instance_eval_spec }.should == 2
+ Integer.__send__(:remove_class_variable, :@@__tmp_instance_eval_spec)
end
+end
it "raises a TypeError when defining methods on numerics" do
-> do
diff --git a/spec/ruby/core/basicobject/method_missing_spec.rb b/spec/ruby/core/basicobject/method_missing_spec.rb
index a29d4375bc..b048780ee8 100644
--- a/spec/ruby/core/basicobject/method_missing_spec.rb
+++ b/spec/ruby/core/basicobject/method_missing_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/basicobject/method_missing'
describe "BasicObject#method_missing" do
diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb
index bb2036f739..4bb3da7a6c 100644
--- a/spec/ruby/core/binding/eval_spec.rb
+++ b/spec/ruby/core/binding/eval_spec.rb
@@ -23,29 +23,58 @@ describe "Binding#eval" do
bind2.local_variables.should == []
end
- it "starts with line 1 if single argument is given" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("__LINE__").should == 1
- end
+ ruby_version_is ""..."3.0" do
+ it "inherits __LINE__ from the enclosing scope" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
+ end
- it "preserves __LINE__ across multiple calls to eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("__LINE__").should == 1
- bind.eval("__LINE__").should == 1
- end
+ it "preserves __LINE__ across multiple calls to eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
+ suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
+ end
- it "increments __LINE__ on each line of a multiline eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("#foo\n__LINE__").should == 2
+ it "increments __LINE__ on each line of a multiline eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning {bind.eval("#foo\n__LINE__")}.should == obj.get_line_of_binding + 1
+ end
+
+ it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_with_send_and_line
+ suppress_warning {bind.eval("__LINE__")}.should == line
+ end
end
- it "starts with line 1 if the Binding is created with #send" do
- obj = BindingSpecs::Demo.new(1)
- bind, line = obj.get_binding_with_send_and_line
- bind.eval("__LINE__").should == 1
+ ruby_version_is "3.0" do
+ it "starts with line 1 if single argument is given" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("__LINE__").should == 1
+ end
+
+ it "preserves __LINE__ across multiple calls to eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("__LINE__").should == 1
+ bind.eval("__LINE__").should == 1
+ end
+
+ it "increments __LINE__ on each line of a multiline eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("#foo\n__LINE__").should == 2
+ end
+
+ it "starts with line 1 if the Binding is created with #send" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_with_send_and_line
+ bind.eval("__LINE__").should == 1
+ end
end
it "starts with a __LINE__ of 1 if a filename is passed" do
@@ -60,18 +89,32 @@ describe "Binding#eval" do
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
- ruby_version_is ""..."3.3" do
+ ruby_version_is ""..."3.0" do
+ it "inherits __FILE__ from the enclosing scope" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning { bind.eval("__FILE__") }.should == obj.get_file_of_binding
+ end
+
+ it "inherits __LINE__ from the enclosing scope" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_and_line
+ suppress_warning { bind.eval("__LINE__") }.should == line
+ end
+ end
+
+ ruby_version_is "3.0" do
it "uses (eval) as __FILE__ if single argument given" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__FILE__").should == '(eval)'
end
- end
- it "uses 1 as __LINE__" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- suppress_warning { bind.eval("__LINE__") }.should == 1
+ it "uses 1 as __LINE__" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning { bind.eval("__LINE__") }.should == 1
+ end
end
it "uses the __FILE__ that is passed in" do
@@ -106,10 +149,4 @@ describe "Binding#eval" do
bind.eval("'bar'.foo").should == "foo"
end
-
- ruby_version_is "3.3" do
- it "uses the caller location as default filename" do
- binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
- end
end
diff --git a/spec/ruby/core/binding/source_location_spec.rb b/spec/ruby/core/binding/source_location_spec.rb
index d1c8191ea8..d439c3e399 100644
--- a/spec/ruby/core/binding/source_location_spec.rb
+++ b/spec/ruby/core/binding/source_location_spec.rb
@@ -6,9 +6,4 @@ describe "Binding#source_location" do
b = BindingSpecs::LocationMethod::TEST_BINDING
b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4]
end
-
- it "works for eval with a given line" do
- b = eval('binding', nil, "foo", 100)
- b.source_location.should == ["foo", 100]
- end
end
diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb
index c09ed71b31..701fd72e19 100644
--- a/spec/ruby/core/class/dup_spec.rb
+++ b/spec/ruby/core/class/dup_spec.rb
@@ -61,7 +61,4 @@ describe "Class#dup" do
CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy"
end
- it "raises TypeError if called on BasicObject" do
- -> { BasicObject.dup }.should raise_error(TypeError, "can't copy the root class")
- end
end
diff --git a/spec/ruby/core/complex/inspect_spec.rb b/spec/ruby/core/complex/inspect_spec.rb
index 7a89ec6854..71aabde5be 100644
--- a/spec/ruby/core/complex/inspect_spec.rb
+++ b/spec/ruby/core/complex/inspect_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative '../numeric/fixtures/classes'
describe "Complex#inspect" do
it "returns (${real}+${image}i) for positive imaginary parts" do
@@ -14,22 +13,4 @@ describe "Complex#inspect" do
Complex(-1, -4).inspect.should == "(-1-4i)"
Complex(-7, -6.7).inspect.should == "(-7-6.7i)"
end
-
- it "calls #inspect on real and imaginary" do
- real = NumericSpecs::Subclass.new
- real.should_receive(:inspect).and_return("1")
- imaginary = NumericSpecs::Subclass.new
- imaginary.should_receive(:inspect).and_return("2")
- imaginary.should_receive(:<).any_number_of_times.and_return(false)
- Complex(real, imaginary).inspect.should == "(1+2i)"
- end
-
- it "adds an `*' before the `i' if the last character of the imaginary part is not numeric" do
- real = NumericSpecs::Subclass.new
- real.should_receive(:inspect).and_return("(1)")
- imaginary = NumericSpecs::Subclass.new
- imaginary.should_receive(:inspect).and_return("(2)")
- imaginary.should_receive(:<).any_number_of_times.and_return(false)
- Complex(real, imaginary).inspect.should == "((1)+(2)*i)"
- end
end
diff --git a/spec/ruby/core/complex/to_s_spec.rb b/spec/ruby/core/complex/to_s_spec.rb
index 7677dcd0b5..989a7ae0b7 100644
--- a/spec/ruby/core/complex/to_s_spec.rb
+++ b/spec/ruby/core/complex/to_s_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative '../numeric/fixtures/classes'
describe "Complex#to_s" do
describe "when self's real component is 0" do
@@ -42,13 +41,4 @@ describe "Complex#to_s" do
it "returns 1+NaN*i for Complex(1, NaN)" do
Complex(1, nan_value).to_s.should == "1+NaN*i"
end
-
- it "treats real and imaginary parts as strings" do
- real = NumericSpecs::Subclass.new
- real.should_receive(:to_s).and_return("1")
- imaginary = NumericSpecs::Subclass.new
- imaginary.should_receive(:to_s).and_return("2")
- imaginary.should_receive(:<).any_number_of_times.and_return(false)
- Complex(real, imaginary).to_s.should == "1+2i"
- end
end
diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb
index 2eb43d501e..d9d55b50f9 100644
--- a/spec/ruby/core/data/constants_spec.rb
+++ b/spec/ruby/core/data/constants_spec.rb
@@ -1,6 +1,20 @@
require_relative '../../spec_helper'
-ruby_version_is ''...'3.2' do
+ruby_version_is ''...'3.0' do
+ describe "Data" do
+ it "is a subclass of Object" do
+ suppress_warning do
+ Data.superclass.should == Object
+ end
+ end
+
+ it "is deprecated" do
+ -> { Data }.should complain(/constant ::Data is deprecated/)
+ end
+ end
+end
+
+ruby_version_is '3.0'...'3.2' do
describe "Data" do
it "does not exist anymore" do
Object.should_not have_constant(:Data)
diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb
deleted file mode 100644
index 2aa2c50d4c..0000000000
--- a/spec/ruby/core/data/define_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is "3.2" do
- describe "Data.define" do
- it "accepts no arguments" do
- empty_data = Data.define
- empty_data.members.should == []
- end
-
- it "accepts symbols" do
- movie = Data.define(:title, :year)
- movie.members.should == [:title, :year]
- end
-
- it "accepts strings" do
- movie = Data.define("title", "year")
- movie.members.should == [:title, :year]
- end
-
- it "accepts a mix of strings and symbols" do
- movie = Data.define("title", :year, "genre")
- movie.members.should == [:title, :year, :genre]
- end
-
- it "accepts a block" do
- movie = Data.define(:title, :year) do
- def title_with_year
- "#{title} (#{year})"
- end
- end
- movie.members.should == [:title, :year]
- movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
- end
- end
-end
diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb
deleted file mode 100644
index 46a6b48bb2..0000000000
--- a/spec/ruby/core/data/fixtures/classes.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module DataSpecs
- guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
- Measure = Data.define(:amount, :unit)
- end
-end
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
deleted file mode 100644
index 94470cd108..0000000000
--- a/spec/ruby/core/data/initialize_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is "3.2" do
- describe "Data#initialize" do
- it "accepts positional arguments" do
- data = DataSpecs::Measure.new(42, "km")
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "accepts alternative positional arguments" do
- data = DataSpecs::Measure[42, "km"]
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "accepts keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "accepts alternative keyword arguments" do
- data = DataSpecs::Measure[amount: 42, unit: "km"]
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "raises ArgumentError if no arguments are given" do
- -> {
- DataSpecs::Measure.new
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keywords: :amount, :unit")
- }
- end
-
- it "raises ArgumentError if at least one argument is missing" do
- -> {
- DataSpecs::Measure.new(unit: "km")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keyword: :amount")
- }
- end
-
- it "raises ArgumentError if unknown keyword is given" do
- -> {
- DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("unknown keyword: :system")
- }
- end
- end
-end
diff --git a/spec/ruby/core/dir/exist_spec.rb b/spec/ruby/core/dir/exist_spec.rb
index 9023de533f..43987b0f32 100644
--- a/spec/ruby/core/dir/exist_spec.rb
+++ b/spec/ruby/core/dir/exist_spec.rb
@@ -13,11 +13,3 @@ describe "Dir.exist?" do
it_behaves_like :dir_exist, :exist?
end
-
-ruby_version_is "3.2" do
- describe "Dir.exists?" do
- it "has been removed" do
- Dir.should_not.respond_to?(:exists?)
- end
- end
-end
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
deleted file mode 100644
index 429e569691..0000000000
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-
-ruby_version_is '3.3' do
- guard -> { Dir.respond_to? :fchdir } do
- describe "Dir.fchdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- before :each do
- @dirs = [Dir.new('.')]
- @original = @dirs.first.fileno
- end
-
- after :each do
- Dir.fchdir(@original)
- @dirs.each(&:close)
- end
-
- it "changes to the specified directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- @dirs << dir
- Dir.fchdir dir.fileno
- Dir.pwd.should == DirSpecs.mock_dir
- end
-
- it "returns 0 when successfully changing directory" do
- Dir.fchdir(@original).should == 0
- end
-
- it "returns the value of the block when a block is given" do
- Dir.fchdir(@original) { :block_value }.should == :block_value
- end
-
- it "changes to the specified directory for the duration of the block" do
- pwd = Dir.pwd
- dir = Dir.new(DirSpecs.mock_dir)
- @dirs << dir
- Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
- Dir.pwd.should == pwd
- end
-
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.fchdir(-1) }.should raise_error(SystemCallError)
- -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError)
- end
-
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError)
- -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError)
- end
- end
- end
-
- guard_not -> { Dir.respond_to? :fchdir } do
- describe "Dir.fchdir" do
- it "raises NotImplementedError" do
- -> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
- -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError)
- end
- end
- end
-end
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index 32f515c81d..06b52b90fb 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -106,11 +106,11 @@ describe "Dir.glob" do
ruby_version_is '3.1' do
it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
- nested/.
- nested/.dotsubir
- nested/.dotsubir/.dotfile
- nested/.dotsubir/nondotfile
- ]
+ nested/.
+ nested/.dotsubir
+ nested/.dotsubir/.dotfile
+ nested/.dotsubir/nondotfile
+ ]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
@@ -182,134 +182,6 @@ describe "Dir.glob" do
Dir.glob('**/**/**').should_not.empty?
end
- it "handles **/** with base keyword argument" do
- Dir.glob('**/**', base: "dir").should == ["filename_ordering"]
-
- expected = %w[
- nested
- nested/directory
- nested/directory/structure
- nested/directory/structure/bar
- nested/directory/structure/baz
- nested/directory/structure/file_one
- nested/directory/structure/file_one.ext
- nested/directory/structure/foo
- nondotfile
- ].sort
-
- Dir.glob('**/**', base: "deeply").sort.should == expected
- end
-
- it "handles **/ with base keyword argument" do
- expected = %w[
- /
- directory/
- directory/structure/
- ]
- Dir.glob('**/', base: "deeply/nested").sort.should == expected
- end
-
- it "handles **/nondotfile with base keyword argument" do
- expected = %w[
- deeply/nondotfile
- nondotfile
- subdir_one/nondotfile
- subdir_two/nondotfile
- ]
- Dir.glob('**/nondotfile', base: ".").sort.should == expected
- end
-
- it "handles **/nondotfile with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .dotsubdir/nondotfile
- deeply/nondotfile
- nested/.dotsubir/nondotfile
- nondotfile
- subdir_one/nondotfile
- subdir_two/nondotfile
- ]
- Dir.glob('**/nondotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
- end
-
- it "handles **/.dotfile with base keyword argument" do
- expected = %w[
- .dotfile
- deeply/.dotfile
- subdir_one/.dotfile
- ]
- Dir.glob('**/.dotfile', base: ".").sort.should == expected
- end
-
- it "handles **/.dotfile with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .dotfile
- .dotsubdir/.dotfile
- deeply/.dotfile
- nested/.dotsubir/.dotfile
- subdir_one/.dotfile
- ]
- Dir.glob('**/.dotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
- end
-
- it "handles **/.* with base keyword argument" do
- expected = %w[
- .dotfile.ext
- directory/structure/.ext
- ].sort
-
- Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
- end
-
- # < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
- ruby_version_is '3.1' do
- it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .
- .dotfile.ext
- directory/structure/.ext
- ].sort
-
- Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
-
- it "handles **/** with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .
- .dotfile.ext
- directory
- directory/structure
- directory/structure/.ext
- directory/structure/bar
- directory/structure/baz
- directory/structure/file_one
- directory/structure/file_one.ext
- directory/structure/foo
- ].sort
-
- Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
- end
-
- it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .dotfile.ext
- directory/structure/file_one
- directory/structure/file_one.ext
- ]
-
- Dir.glob('**/*file*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
-
- it "handles **/glob with base keyword argument and FNM_EXTGLOB" do
- expected = %w[
- directory/structure/bar
- directory/structure/file_one
- directory/structure/file_one.ext
- ]
-
- Dir.glob('**/*{file,bar}*', File::FNM_EXTGLOB, base: "deeply/nested").sort.should == expected
- end
-
it "handles simple filename patterns" do
Dir.glob('.dotfile').should == ['.dotfile']
end
diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb
index 3cf745ab46..bbe347ba9e 100644
--- a/spec/ruby/core/dir/home_spec.rb
+++ b/spec/ruby/core/dir/home_spec.rb
@@ -40,21 +40,22 @@ describe "Dir.home" do
home.should == "C:/rubyspäc/home"
home.encoding.should == Encoding::UTF_8
end
+ end
- it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
- old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
+ it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
+ old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
- Dir.home.should == old_dirs[1].gsub("\\", "/")
- ENV['HOMEDRIVE'] = "C:"
- ENV['HOMEPATH'] = "\\rubyspec\\home1"
- Dir.home.should == "C:/rubyspec/home1"
- ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
- Dir.home.should == "C:/rubyspec/home2"
- ENV['HOME'] = "C:\\rubyspec\\home3"
- Dir.home.should == "C:/rubyspec/home3"
- ensure
- ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
- end
+ Dir.home.should == old_dirs[1].gsub("\\", "/")
+ ENV['HOMEDRIVE'] = "C:"
+ ENV['HOMEPATH'] = "\\rubyspec\\home1"
+ Dir.home.should == "C:/rubyspec/home1"
+ ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
+ # https://bugs.ruby-lang.org/issues/19244
+ # Dir.home.should == "C:/rubyspec/home2"
+ ENV['HOME'] = "C:\\rubyspec\\home3"
+ Dir.home.should == "C:/rubyspec/home3"
+ ensure
+ ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
end
end
end
@@ -84,10 +85,4 @@ describe "Dir.home" do
it "raises an ArgumentError if the named user doesn't exist" do
-> { Dir.home('geuw2n288dh2k') }.should raise_error(ArgumentError)
end
-
- describe "when called with a nil user name" do
- it "returns the current user's home directory, reading $HOME first" do
- Dir.home(nil).should == "/rubyspec_home"
- end
- end
end
diff --git a/spec/ruby/core/dir/shared/chroot.rb b/spec/ruby/core/dir/shared/chroot.rb
index a8f7c10a19..8c0599fe3f 100644
--- a/spec/ruby/core/dir/shared/chroot.rb
+++ b/spec/ruby/core/dir/shared/chroot.rb
@@ -2,7 +2,7 @@ describe :dir_chroot_as_root, shared: true do
before :all do
DirSpecs.create_mock_dirs
- @real_root = "../" * (__dir__.count('/') - 1)
+ @real_root = "../" * (File.dirname(__FILE__).count('/') - 1)
@ref_dir = File.join("/", File.basename(Dir["/*"].first))
end
@@ -18,7 +18,7 @@ describe :dir_chroot_as_root, shared: true do
compilations_ci = ENV["GITHUB_WORKFLOW"] == "Compilations"
it "can be used to change the process' root directory" do
- -> { Dir.send(@method, __dir__) }.should_not raise_error
+ -> { Dir.send(@method, File.dirname(__FILE__)) }.should_not raise_error
File.should.exist?("/#{File.basename(__FILE__)}")
end unless compilations_ci
diff --git a/spec/ruby/core/dir/shared/exist.rb b/spec/ruby/core/dir/shared/exist.rb
index 2ea4f88a80..765d1b656c 100644
--- a/spec/ruby/core/dir/shared/exist.rb
+++ b/spec/ruby/core/dir/shared/exist.rb
@@ -1,6 +1,6 @@
describe :dir_exist, shared: true do
it "returns true if the given directory exists" do
- Dir.send(@method, __dir__).should be_true
+ Dir.send(@method, File.dirname(__FILE__)).should be_true
end
it "returns true for '.'" do
@@ -20,7 +20,7 @@ describe :dir_exist, shared: true do
end
it "understands relative paths" do
- Dir.send(@method, __dir__ + '/../').should be_true
+ Dir.send(@method, File.dirname(__FILE__) + '/../').should be_true
end
it "returns false if the given directory doesn't exist" do
@@ -28,7 +28,7 @@ describe :dir_exist, shared: true do
end
it "doesn't require the name to have a trailing slash" do
- dir = __dir__
+ dir = File.dirname(__FILE__)
dir.sub!(/\/$/,'')
Dir.send(@method, dir).should be_true
end
@@ -50,7 +50,7 @@ describe :dir_exist, shared: true do
it "calls #to_path on non String arguments" do
p = mock('path')
- p.should_receive(:to_path).and_return(__dir__)
+ p.should_receive(:to_path).and_return(File.dirname(__FILE__))
Dir.send(@method, p)
end
end
diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb
index 27ae0e3000..33b2828c27 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -27,22 +27,24 @@ describe :dir_glob, shared: true do
-> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/
end
- it "result is sorted by default" do
- result = Dir.send(@method, '*')
- result.should == result.sort
- end
+ ruby_version_is "3.0" do
+ it "result is sorted by default" do
+ result = Dir.send(@method, '*')
+ result.should == result.sort
+ end
- it "result is sorted with sort: true" do
- result = Dir.send(@method, '*', sort: true)
- result.should == result.sort
- end
+ it "result is sorted with sort: true" do
+ result = Dir.send(@method, '*', sort: true)
+ result.should == result.sort
+ end
- it "sort: false returns same files" do
- result = Dir.send(@method,'*', sort: false)
- result.sort.should == Dir.send(@method, '*').sort
+ it "sort: false returns same files" do
+ result = Dir.send(@method,'*', sort: false)
+ result.sort.should == Dir.send(@method, '*').sort
+ end
end
- ruby_version_is ""..."3.1" do
+ ruby_version_is "3.0"..."3.1" do
it "result is sorted with any non false value of sort:" do
result = Dir.send(@method, '*', sort: 0)
result.should == result.sort
diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
index ab34ebf33f..802d8e7cb1 100644
--- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
@@ -14,10 +14,6 @@ describe "Encoding::Converter#primitive_convert" do
-> { @ec.primitive_convert("","") }.should_not raise_error
end
- it "raises FrozenError when the destination buffer is a frozen String" do
- -> { @ec.primitive_convert("", "".freeze) }.should raise_error(FrozenError)
- end
-
it "accepts nil for the destination byte offset" do
-> { @ec.primitive_convert("","", nil) }.should_not raise_error
end
diff --git a/spec/ruby/core/encoding/default_external_spec.rb b/spec/ruby/core/encoding/default_external_spec.rb
index 9aae4976e0..682d49d37c 100644
--- a/spec/ruby/core/encoding/default_external_spec.rb
+++ b/spec/ruby/core/encoding/default_external_spec.rb
@@ -18,9 +18,11 @@ describe "Encoding.default_external" do
Encoding.default_external.should == Encoding::SHIFT_JIS
end
- platform_is :windows do
- it 'is UTF-8 by default on Windows' do
- Encoding.default_external.should == Encoding::UTF_8
+ ruby_version_is "3.0" do
+ platform_is :windows do
+ it 'is UTF-8 by default on Windows' do
+ Encoding.default_external.should == Encoding::UTF_8
+ end
end
end
end
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
index 2b15fc1a0f..f5fa6f55e3 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
index c2ed6de1d8..43be3ddd71 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#destination_encoding" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
index d2fc360dce..a8f7354b16 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#error_bytes" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
index 9866310c25..93823b5db4 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
index a9464114a8..bd3a51cbc5 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding_name" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
index 7fdc0a122b..f43d6d5830 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#source_encoding" do
diff --git a/spec/ruby/core/encoding/name_spec.rb b/spec/ruby/core/encoding/name_spec.rb
index dce9347978..5eadb1d2f5 100644
--- a/spec/ruby/core/encoding/name_spec.rb
+++ b/spec/ruby/core/encoding/name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/name'
describe "Encoding#name" do
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index 498d03581a..848415eeb4 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -67,14 +67,6 @@ describe "Encoding#replicate" do
end
end
- ruby_version_is "3.2"..."3.3" do
- it "warns about deprecation" do
- -> {
- Encoding::US_ASCII.replicate('MY-US-ASCII')
- }.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
- end
- end
-
ruby_version_is "3.3" do
it "has been removed" do
Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
diff --git a/spec/ruby/core/encoding/to_s_spec.rb b/spec/ruby/core/encoding/to_s_spec.rb
index bab394a888..82d282386b 100644
--- a/spec/ruby/core/encoding/to_s_spec.rb
+++ b/spec/ruby/core/encoding/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/name'
describe "Encoding#to_s" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
index a51a9f46a0..106fc7ecac 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#destination_encoding_name" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
index 905556407c..c6e24732fd 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#destination_encoding" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
index 9cb55e6d95..780d81c1ee 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#error_char" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
index d5e60e78db..3b697cb82f 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding_name" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
index de456a4b5a..9101d51e11 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding" do
diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb
index 160cd52628..0ded1e8eba 100644
--- a/spec/ruby/core/enumerable/all_spec.rb
+++ b/spec/ruby/core/enumerable/all_spec.rb
@@ -177,11 +177,5 @@ describe "Enumerable#all?" do
multi.all?(pattern).should == true
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).all?(String) { true }.should == false
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb
index 243f8735d5..355cd0c290 100644
--- a/spec/ruby/core/enumerable/any_spec.rb
+++ b/spec/ruby/core/enumerable/any_spec.rb
@@ -190,11 +190,5 @@ describe "Enumerable#any?" do
multi.any?(pattern).should == false
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).any?(String) { true }.should == false
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/chunk_spec.rb b/spec/ruby/core/enumerable/chunk_spec.rb
index ed6304307f..c5579d67fa 100644
--- a/spec/ruby/core/enumerable/chunk_spec.rb
+++ b/spec/ruby/core/enumerable/chunk_spec.rb
@@ -29,11 +29,6 @@ describe "Enumerable#chunk" do
result.should == [[1, [1, 2]], [0, [3]], [1, [2]], [0, [3]], [1, [2, 1]]]
end
- it "returns a partitioned Array of values" do
- e = EnumerableSpecs::Numerous.new(1,2,3)
- e.chunk { |x| x > 2 }.map(&:last).should == [[1, 2], [3]]
- end
-
it "returns elements for which the block returns :_alone in separate Arrays" do
e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1)
result = e.chunk { |x| x < 2 && :_alone }.to_a
diff --git a/spec/ruby/core/enumerable/grep_spec.rb b/spec/ruby/core/enumerable/grep_spec.rb
index 989358f01b..b81075291f 100644
--- a/spec/ruby/core/enumerable/grep_spec.rb
+++ b/spec/ruby/core/enumerable/grep_spec.rb
@@ -40,28 +40,43 @@ describe "Enumerable#grep" do
$~.should == nil
end
- it "does not set $~ when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep(/b/).should == ["abc"]
- $&.should == "z"
- end
+ ruby_version_is ""..."3.0.0" do
+ it "sets $~ to the last match when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep(/b/).should == ["abc"]
+
+ # Set by the failed match of "def"
+ $~.should == nil
- it "does not modify Regexp.last_match without block" do
- "z" =~ /z/ # Reset last match
- ["abc", "def"].grep(/b/).should == ["abc"]
- Regexp.last_match[0].should == "z"
+ ["abc", "def"].grep(/e/)
+ $&.should == "e"
+ end
end
- it "correctly handles non-string elements" do
- 'set last match' =~ /set last (.*)/
- [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c]
- $1.should == 'match'
+ ruby_version_is "3.0.0" do
+ it "does not set $~ when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep(/b/).should == ["abc"]
+ $&.should == "z"
+ end
- o = Object.new
- def o.to_str
- 'hello'
+ it "does not modify Regexp.last_match without block" do
+ "z" =~ /z/ # Reset last match
+ ["abc", "def"].grep(/b/).should == ["abc"]
+ Regexp.last_match[0].should == "z"
+ end
+
+ it "correctly handles non-string elements" do
+ 'set last match' =~ /set last (.*)/
+ [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c]
+ $1.should == 'match'
+
+ o = Object.new
+ def o.to_str
+ 'hello'
+ end
+ [o].grep(/ll/).first.should.equal?(o)
end
- [o].grep(/ll/).first.should.equal?(o)
end
describe "with a block" do
diff --git a/spec/ruby/core/enumerable/grep_v_spec.rb b/spec/ruby/core/enumerable/grep_v_spec.rb
index ba19216968..35fde27eb6 100644
--- a/spec/ruby/core/enumerable/grep_v_spec.rb
+++ b/spec/ruby/core/enumerable/grep_v_spec.rb
@@ -20,28 +20,43 @@ describe "Enumerable#grep_v" do
$&.should == "e"
end
- it "does not set $~ when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep_v(/e/).should == ["abc"]
- $&.should == "z"
- end
+ ruby_version_is ""..."3.0.0" do
+ it "sets $~ to the last match when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
- it "does not modify Regexp.last_match without block" do
- "z" =~ /z/ # Reset last match
- ["abc", "def"].grep_v(/e/).should == ["abc"]
- Regexp.last_match[0].should == "z"
+ # Set by the match of "def"
+ $&.should == "e"
+
+ ["abc", "def"].grep_v(/b/)
+ $&.should == nil
+ end
end
- it "correctly handles non-string elements" do
- 'set last match' =~ /set last (.*)/
- [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil]
- $1.should == 'match'
+ ruby_version_is "3.0.0" do
+ it "does not set $~ when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
+ $&.should == "z"
+ end
+
+ it "does not modify Regexp.last_match without block" do
+ "z" =~ /z/ # Reset last match
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
+ Regexp.last_match[0].should == "z"
+ end
+
+ it "correctly handles non-string elements" do
+ 'set last match' =~ /set last (.*)/
+ [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil]
+ $1.should == 'match'
- o = Object.new
- def o.to_str
- 'hello'
+ o = Object.new
+ def o.to_str
+ 'hello'
+ end
+ [o].grep_v(/mm/).first.should.equal?(o)
end
- [o].grep_v(/mm/).first.should.equal?(o)
end
describe "without block" do
diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb
index fb42f13386..99bb7f7a4e 100644
--- a/spec/ruby/core/enumerable/none_spec.rb
+++ b/spec/ruby/core/enumerable/none_spec.rb
@@ -143,11 +143,5 @@ describe "Enumerable#none?" do
multi.none?(pattern).should == true
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).none?(String) { true }.should == true
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb
index 4bf8623d2e..47bfd65a0f 100644
--- a/spec/ruby/core/enumerable/one_spec.rb
+++ b/spec/ruby/core/enumerable/one_spec.rb
@@ -83,6 +83,7 @@ describe "Enumerable#one?" do
end
end
+
describe 'when given a pattern argument' do
it "calls `===` on the pattern the return value " do
pattern = EnumerableSpecs::Pattern.new { |x| x == 1 }
@@ -144,11 +145,5 @@ describe "Enumerable#one?" do
multi.one?(pattern).should == false
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, "5").one?(String) { false }.should == true
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb
index 693d34d675..c5907f92d8 100644
--- a/spec/ruby/core/enumerable/shared/inject.rb
+++ b/spec/ruby/core/enumerable/shared/inject.rb
@@ -1,5 +1,3 @@
-require_relative '../../array/shared/iterable_and_tolerating_size_increasing'
-
describe :enumerable_inject, shared: true do
it "with argument takes a block with an accumulator (with argument as initial value) and the current element. Value of block becomes new accumulator" do
a = []
@@ -19,22 +17,8 @@ describe :enumerable_inject, shared: true do
end
it "ignores the block if two arguments" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-) { raise "we never get here"}.should == 4
- }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
-
- -> {
- [1, 2, 3].send(@method, 10, :-) { raise "we never get here"}.should == 4
- }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
- end
-
- it "does not warn when given a Symbol with $VERBOSE true" do
- -> {
- [1, 2].send(@method, 0, :+)
- [1, 2].send(@method, :+)
- EnumerableSpecs::Numerous.new(1, 2).send(@method, 0, :+)
- EnumerableSpecs::Numerous.new(1, 2).send(@method, :+)
- }.should_not complain(verbose: true)
+ EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-) { raise "we never get here"}.should == 4
+ [].send(@method, 3, :+) { raise "we never get here"}.should == 3
end
it "can take a symbol argument" do
@@ -47,10 +31,10 @@ describe :enumerable_inject, shared: true do
a.should == [[2, 5], [5, 3], [3, 6], [6, 1], [1, 4]]
end
- it "gathers whole arrays as elements when each yields multiple" do
- multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
- end
+ it "gathers whole arrays as elements when each yields multiple" do
+ multi = EnumerableSpecs::YieldsMulti.new
+ multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
+ end
it "with inject arguments(legacy rubycon)" do
# with inject argument
@@ -84,22 +68,6 @@ describe :enumerable_inject, shared: true do
EnumerableSpecs::EachDefiner.new().send(@method) {|acc,x| 999 }.should == nil
end
- it "tolerates increasing a collection size during iterating Array" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.send(@method, nil) do |_, e|
- ScratchPad << e
- array << i if i < 100
- i += 1
- end
-
- actual = ScratchPad.recorded
- expected = [:a, :b, :c] + (0..99).to_a
- actual.sort_by(&:to_s).should == expected.sort_by(&:to_s)
- end
-
ruby_bug '#18635', ''...'3.2' do
it "raises an ArgumentError when no parameters or block is given" do
-> { [1,2].send(@method) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/enumerable/sum_spec.rb b/spec/ruby/core/enumerable/sum_spec.rb
index 2eb74db6ac..fc173e4173 100644
--- a/spec/ruby/core/enumerable/sum_spec.rb
+++ b/spec/ruby/core/enumerable/sum_spec.rb
@@ -40,7 +40,7 @@ describe 'Enumerable#sum' do
end
# https://bugs.ruby-lang.org/issues/12217
- # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214
+ # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214
it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do
floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5].to_enum
naive_sum = floats.reduce { |sum, e| sum + e }
diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb
index e0edc8dc75..f09a8f533a 100644
--- a/spec/ruby/core/enumerable/tally_spec.rb
+++ b/spec/ruby/core/enumerable/tally_spec.rb
@@ -49,13 +49,6 @@ ruby_version_is "3.1" do
enum.tally(hash).should equal(hash)
end
- it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- object = Object.new
- def object.to_hash; { 'foo' => 1 }; end
- enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
- end
-
it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze
@@ -63,12 +56,6 @@ ruby_version_is "3.1" do
hash.should == { 'foo' => 1 }
end
- it "raises a FrozenError even if enumerable is empty" do
- enum = EnumerableSpecs::Numerous.new()
- hash = { 'foo' => 1 }.freeze
- -> { enum.tally(hash) }.should raise_error(FrozenError)
- end
-
it "does not call given block" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
diff --git a/spec/ruby/core/enumerator/chain/initialize_spec.rb b/spec/ruby/core/enumerator/chain/initialize_spec.rb
index daa30351d7..69484dfcb4 100644
--- a/spec/ruby/core/enumerator/chain/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/chain/initialize_spec.rb
@@ -22,10 +22,10 @@ describe "Enumerator::Chain#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
+ it "raises a RuntimeError" do
-> {
@uninitialized.freeze.send(:initialize)
- }.should raise_error(FrozenError)
+ }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/chain/inspect_spec.rb b/spec/ruby/core/enumerator/chain/inspect_spec.rb
index 9b5a442b75..a0450c808a 100644
--- a/spec/ruby/core/enumerator/chain/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/chain/inspect_spec.rb
@@ -11,8 +11,4 @@ describe "Enumerator::Chain#inspect" do
obj.should_receive(:inspect).and_return('some desc')
Enumerator::Chain.new(obj).inspect.should == "#<Enumerator::Chain: [some desc]>"
end
-
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator::Chain.allocate.inspect.should == "#<Enumerator::Chain: uninitialized>"
- end
end
diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb
index 3af16e5587..99ac3120af 100644
--- a/spec/ruby/core/enumerator/each_spec.rb
+++ b/spec/ruby/core/enumerator/each_spec.rb
@@ -10,41 +10,41 @@ describe "Enumerator#each" do
@enum_with_arguments = object_each_with_arguments.to_enum(:each_with_arguments, :arg0, :arg1, :arg2)
- @enum_with_yielder = Enumerator.new { |y| y.yield :ok }
+ @enum_with_yielder = Enumerator.new {|y| y.yield :ok}
end
it "yields each element of self to the given block" do
acc = []
- [1, 2, 3].to_enum.each { |e| acc << e }
- acc.should == [1, 2, 3]
+ [1,2,3].to_enum.each {|e| acc << e }
+ acc.should == [1,2,3]
end
it "calls #each on the object given in the constructor by default" do
each = mock('each')
each.should_receive(:each)
- each.to_enum.each { |e| e }
+ each.to_enum.each {|e| e }
end
it "calls #each on the underlying object until it's exhausted" do
each = mock('each')
each.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
acc = []
- each.to_enum.each { |e| acc << e }
- acc.should == [1, 2, 3]
+ each.to_enum.each {|e| acc << e }
+ acc.should == [1,2,3]
end
it "calls the method given in the constructor instead of #each" do
each = mock('peach')
each.should_receive(:peach)
- each.to_enum(:peach).each { |e| e }
+ each.to_enum(:peach).each {|e| e }
end
it "calls the method given in the constructor until it's exhausted" do
each = mock('peach')
each.should_receive(:peach).and_yield(1).and_yield(2).and_yield(3)
acc = []
- each.to_enum(:peach).each { |e| acc << e }
- acc.should == [1, 2, 3]
+ each.to_enum(:peach).each {|e| acc << e }
+ acc.should == [1,2,3]
end
it "raises a NoMethodError if the object doesn't respond to #each" do
diff --git a/spec/ruby/core/enumerator/generator/initialize_spec.rb b/spec/ruby/core/enumerator/generator/initialize_spec.rb
index acc1174253..f75c7d6f26 100644
--- a/spec/ruby/core/enumerator/generator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/generator/initialize_spec.rb
@@ -17,10 +17,10 @@ describe "Enumerator::Generator#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
+ it "raises a RuntimeError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
+ }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/initialize_spec.rb b/spec/ruby/core/enumerator/initialize_spec.rb
index 5e0256ca46..217af1d3bc 100644
--- a/spec/ruby/core/enumerator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/initialize_spec.rb
@@ -11,6 +11,14 @@ describe "Enumerator#initialize" do
Enumerator.should have_private_instance_method(:initialize, false)
end
+ ruby_version_is ''...'3.0' do
+ it "returns self when given an object" do
+ suppress_warning do
+ @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
+ end
+ end
+ end
+
it "returns self when given a block" do
@uninitialized.send(:initialize) {}.should equal(@uninitialized)
end
@@ -48,10 +56,10 @@ describe "Enumerator#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
+ it "raises a RuntimeError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
+ }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/inspect_spec.rb b/spec/ruby/core/enumerator/inspect_spec.rb
index 7e97864246..3bcf07e754 100644
--- a/spec/ruby/core/enumerator/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/inspect_spec.rb
@@ -14,9 +14,4 @@ describe "Enumerator#inspect" do
(1..3).each.each_slice(2).inspect.should == "#<Enumerator: #<Enumerator: 1..3:each>:each_slice(2)>"
end
end
-
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator.allocate.inspect.should == "#<Enumerator: uninitialized>"
- Enumerator::Lazy.allocate.inspect.should == "#<Enumerator::Lazy: uninitialized>"
- end
end
diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb
index e678bc71eb..80b6f9481d 100644
--- a/spec/ruby/core/enumerator/lazy/compact_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../../spec_helper'
-require_relative 'fixtures/classes'
ruby_version_is '3.1' do
describe "Enumerator::Lazy#compact" do
@@ -8,9 +7,5 @@ ruby_version_is '3.1' do
arr.should be_an_instance_of(Enumerator::Lazy)
arr.force.should == [1, 3, false, 5]
end
-
- it "sets #size to nil" do
- Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
- end
end
end
diff --git a/spec/ruby/core/enumerator/lazy/initialize_spec.rb b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
index e1e0b1d608..f23018d010 100644
--- a/spec/ruby/core/enumerator/lazy/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
@@ -56,8 +56,8 @@ describe "Enumerator::Lazy#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
- -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(FrozenError)
+ it "raises a RuntimeError" do
+ -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb
index 671912224f..c439469525 100644
--- a/spec/ruby/core/enumerator/new_spec.rb
+++ b/spec/ruby/core/enumerator/new_spec.rb
@@ -2,8 +2,51 @@ require_relative '../../spec_helper'
describe "Enumerator.new" do
context "no block given" do
- it "raises" do
- -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError)
+ ruby_version_is '3.0' do
+ it "raises" do
+ -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError)
+ end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "creates a new custom enumerator with the given object, iterator and arguments" do
+ enum = suppress_warning { Enumerator.new(1, :upto, 3) }
+ enum.should be_an_instance_of(Enumerator)
+ end
+
+ it "creates a new custom enumerator that responds to #each" do
+ enum = suppress_warning { Enumerator.new(1, :upto, 3) }
+ enum.respond_to?(:each).should == true
+ end
+
+ it "creates a new custom enumerator that runs correctly" do
+ suppress_warning { Enumerator.new(1, :upto, 3) }.map{ |x| x }.should == [1,2,3]
+ end
+
+ it "aliases the second argument to :each" do
+ suppress_warning { Enumerator.new(1..2) }.to_a.should ==
+ suppress_warning { Enumerator.new(1..2, :each) }.to_a
+ end
+
+ it "doesn't check for the presence of the iterator method" do
+ suppress_warning { Enumerator.new(nil) }.should be_an_instance_of(Enumerator)
+ end
+
+ it "uses the latest define iterator method" do
+ class StrangeEach
+ def each
+ yield :foo
+ end
+ end
+ enum = suppress_warning { Enumerator.new(StrangeEach.new) }
+ enum.to_a.should == [:foo]
+ class StrangeEach
+ def each
+ yield :bar
+ end
+ end
+ enum.to_a.should == [:bar]
+ end
end
end
diff --git a/spec/ruby/core/enumerator/product/each_spec.rb b/spec/ruby/core/enumerator/product/each_spec.rb
deleted file mode 100644
index 868a1ea6bf..0000000000
--- a/spec/ruby/core/enumerator/product/each_spec.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../../enumerable/shared/enumeratorized'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#each" do
- it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b])
-
- it "yields each element of Cartesian product of enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "calls #each_entry method on enumerators" do
- object1 = Object.new
- def object1.each_entry
- yield 1
- yield 2
- end
-
- object2 = Object.new
- def object2.each_entry
- yield :a
- yield :b
- end
-
- enum = Enumerator::Product.new(object1, object2)
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "raises a NoMethodError if the object doesn't respond to #each_entry" do
- -> {
- Enumerator::Product.new(Object.new).each {}
- }.should raise_error(NoMethodError, /undefined method `each_entry' for/)
- end
-
- it "returns enumerator if not given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.should.kind_of?(Enumerator)
-
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "returns self if given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each {}.should.equal?(enum)
- end
-
- it "doesn't accept arguments" do
- Enumerator::Product.instance_method(:each).arity.should == 0
- end
-
- it "yields each element to a block that takes multiple arguments" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
-
- acc = []
- enum.each { |x, y| acc << x }
- acc.should == [1, 1, 2, 2]
-
- acc = []
- enum.each { |x, y| acc << y }
- acc.should == [:a, :b, :a, :b]
-
- acc = []
- enum.each { |x, y, z| acc << z }
- acc.should == [nil, nil, nil, nil]
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
deleted file mode 100644
index 46e8421322..0000000000
--- a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize_copy" do
- it "replaces content of the receiver with content of the other object" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
-
- enum.send(:initialize_copy, enum2)
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "returns self" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
-
- enum.send(:initialize_copy, enum2).should.equal?(enum)
- end
-
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize_copy, false)
- end
-
- it "does nothing if the argument is the same as the receiver" do
- enum = Enumerator::Product.new(1..2)
- enum.send(:initialize_copy, enum).should.equal?(enum)
-
- enum.freeze
- enum.send(:initialize_copy, enum).should.equal?(enum)
- end
-
- it "raises FrozenError if the receiver is frozen" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.new(3..4)
-
- -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError)
- end
-
- it "raises TypeError if the objects are of different class" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Class.new(Enumerator::Product).new(3..4)
-
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- -> { enum2.send(:initialize_copy, enum) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- end
-
- it "raises ArgumentError if the argument is not initialized yet" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.allocate
-
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(ArgumentError, 'uninitialized product')
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/initialize_spec.rb b/spec/ruby/core/enumerator/product/initialize_spec.rb
deleted file mode 100644
index 4b60564240..0000000000
--- a/spec/ruby/core/enumerator/product/initialize_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize" do
- before :each do
- @uninitialized = Enumerator::Product.allocate
- end
-
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize, false)
- end
-
- it "returns self" do
- @uninitialized.send(:initialize).should equal(@uninitialized)
- end
-
- it "accepts many arguments" do
- @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
- end
-
- it "accepts arguments that are not Enumerable nor responding to :each_entry" do
- @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
- end
-
- describe "on frozen instance" do
- it "raises a FrozenError" do
- -> {
- @uninitialized.freeze.send(:initialize, 0..1)
- }.should raise_error(FrozenError)
- end
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/inspect_spec.rb b/spec/ruby/core/enumerator/product/inspect_spec.rb
deleted file mode 100644
index 1ea8e9c49b..0000000000
--- a/spec/ruby/core/enumerator/product/inspect_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#inspect" do
- it "returns a String including enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>"
- end
-
- it "represents a recursive element with '[...]'" do
- enum = [1, 2]
- enum_recursive = Enumerator::Product.new(enum)
-
- enum << enum_recursive
- enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>"
- end
-
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>"
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/rewind_spec.rb b/spec/ruby/core/enumerator/product/rewind_spec.rb
deleted file mode 100644
index e8ee730239..0000000000
--- a/spec/ruby/core/enumerator/product/rewind_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#rewind" do
- before :each do
- @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum)
- end
-
- it "resets the enumerator to its initial state" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "returns self" do
- @enum.rewind.should.equal? @enum
- end
-
- it "has no effect on a new enumerator" do
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "has no effect if called multiple, consecutive times" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "calls the enclosed object's rewind method if one exists" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
-
- obj.should_receive(:rewind)
- enum.rewind
- end
-
- it "does nothing if the object doesn't have a #rewind method" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
-
- enum.rewind.should == enum
- end
-
- it "calls a rewind method on each enumerable in direct order" do
- ScratchPad.record []
-
- object1 = Object.new
- def object1.rewind; ScratchPad << :object1; end
-
- object2 = Object.new
- def object2.rewind; ScratchPad << :object2; end
-
- object3 = Object.new
- def object3.rewind; ScratchPad << :object3; end
-
- enum = Enumerator::Product.new(object1, object2, object3)
- enum.rewind
-
- ScratchPad.recorded.should == [:object1, :object2, :object3]
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/size_spec.rb b/spec/ruby/core/enumerator/product/size_spec.rb
deleted file mode 100644
index fb0efdf748..0000000000
--- a/spec/ruby/core/enumerator/product/size_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#size" do
- it "returns the total size of the enumerator product calculated by multiplying the sizes of enumerables in the product" do
- product = Enumerator::Product.new(1..2, 1..3, 1..4)
- product.size.should == 24 # 2 * 3 * 4
- end
-
- it "returns nil if any enumerable reports its size as nil" do
- enum = Object.new
- def enum.size; nil; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns Float::INFINITY if any enumerable reports its size as Float::INFINITY" do
- enum = Object.new
- def enum.size; Float::INFINITY; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == Float::INFINITY
- end
-
- it "returns -Float::INFINITY if any enumerable reports its size as -Float::INFINITY" do
- enum = Object.new
- def enum.size; -Float::INFINITY; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == -Float::INFINITY
- end
-
- it "returns nil if any enumerable reports its size as Float::NAN" do
- enum = Object.new
- def enum.size; Float::NAN; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable doesn't respond to #size" do
- enum = Object.new
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable reports a not-convertible to Integer" do
- enum = Object.new
- def enum.size; :symbol; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable reports a non-Integer but convertible to Integer size" do
- enum = Object.new
- def enum.size; 1.0; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb
deleted file mode 100644
index 0fb00fc7ee..0000000000
--- a/spec/ruby/core/enumerator/product_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator.product" do
- it "returns a Cartesian product of enumerators" do
- enum = Enumerator.product(1..2, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
- end
-
- it "accepts a list of enumerators of any length" do
- enum = Enumerator.product(1..2)
- enum.to_a.should == [[1], [2]]
-
- enum = Enumerator.product(1..2, ["A"])
- enum.to_a.should == [[1, "A"], [2, "A"]]
-
- enum = Enumerator.product(1..2, ["A"], ["B"])
- enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
-
- enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
- enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
- end
-
- it "returns an enumerator with an empty array when no arguments passed" do
- enum = Enumerator.product
- enum.to_a.should == [[]]
- end
-
- it "returns an instance of Enumerator::Product" do
- enum = Enumerator.product
- enum.class.should == Enumerator::Product
- end
-
- it "accepts infinite enumerators and returns infinite enumerator" do
- enum = Enumerator.product(1.., ["A", "B"])
- enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
- enum.size.should == Float::INFINITY
- end
-
- it "accepts a block" do
- elems = []
- enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
-
- elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
- end
-
- it "returns nil when a block passed" do
- Enumerator.product(1..2) {}.should == nil
- end
-
- # https://bugs.ruby-lang.org/issues/19829
- it "reject keyword arguments" do
- -> {
- Enumerator.product(1..3, foo: 1, bar: 2)
- }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
- end
-
- it "calls only #each_entry method on arguments" do
- object = Object.new
- def object.each_entry
- yield 1
- yield 2
- end
-
- enum = Enumerator.product(object, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
- end
-
- it "raises NoMethodError when argument doesn't respond to #each_entry" do
- -> {
- Enumerator.product(Object.new).to_a
- }.should raise_error(NoMethodError, /undefined method `each_entry' for/)
- end
-
- it "calls #each_entry lazily" do
- Enumerator.product(Object.new).should be_kind_of(Enumerator)
- end
-
- it "iterates through consuming enumerator elements only once" do
- a = [1, 2, 3]
- i = 0
-
- enum = Enumerator.new do |y|
- while i < a.size
- y << a[i]
- i += 1
- end
- end
-
- Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/rewind_spec.rb b/spec/ruby/core/enumerator/rewind_spec.rb
index 6ba0edf174..a105f2c619 100644
--- a/spec/ruby/core/enumerator/rewind_spec.rb
+++ b/spec/ruby/core/enumerator/rewind_spec.rb
@@ -14,7 +14,7 @@ describe "Enumerator#rewind" do
end
it "returns self" do
- @enum.rewind.should.equal? @enum
+ @enum.rewind.should == @enum
end
it "has no effect on a new enumerator" do
@@ -49,7 +49,7 @@ describe "Enumerator#rewind" do
obj = mock('rewinder')
enum = obj.to_enum
obj.should_receive(:each).at_most(1)
- enum.rewind.should == enum
+ -> { enum.rewind.should == enum }.should_not raise_error
end
end
diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb
deleted file mode 100644
index 991e4e6774..0000000000
--- a/spec/ruby/core/env/clone_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "ENV#clone" do
- it "raises ArgumentError when keyword argument 'freeze' is neither nil nor boolean" do
- -> {
- ENV.clone(freeze: 1)
- }.should raise_error(ArgumentError)
- end
-
- it "raises ArgumentError when keyword argument is not 'freeze'" do
- -> {
- ENV.clone(foo: nil)
- }.should raise_error(ArgumentError)
- end
-
- ruby_version_is "3.2" do
- it "raises TypeError" do
- -> {
- ENV.clone
- }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
- end
- end
-end
diff --git a/spec/ruby/core/env/delete_spec.rb b/spec/ruby/core/env/delete_spec.rb
index f28ac97911..5e7891f74d 100644
--- a/spec/ruby/core/env/delete_spec.rb
+++ b/spec/ruby/core/env/delete_spec.rb
@@ -30,9 +30,11 @@ describe "ENV.delete" do
ScratchPad.recorded.should == "foo"
end
- it "returns the result of given block if the named environment variable does not exist" do
- ENV.delete("foo")
- ENV.delete("foo") { |name| "bar" }.should == "bar"
+ ruby_version_is "3.0" do
+ it "returns the result of given block if the named environment variable does not exist" do
+ ENV.delete("foo")
+ ENV.delete("foo") { |name| "bar" }.should == "bar"
+ end
end
it "does not evaluate the block if the environment variable exists" do
@@ -41,14 +43,6 @@ describe "ENV.delete" do
ENV["foo"].should == nil
end
- it "removes the variable coerced with #to_str" do
- ENV["foo"] = "bar"
- k = mock('key')
- k.should_receive(:to_str).and_return("foo")
- ENV.delete(k)
- ENV["foo"].should == nil
- end
-
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> { ENV.delete(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb
deleted file mode 100644
index 46d125aca8..0000000000
--- a/spec/ruby/core/env/dup_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "ENV#dup" do
- ruby_version_is "3.1" do
- it "raises TypeError" do
- -> {
- ENV.dup
- }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
- end
- end
-end
diff --git a/spec/ruby/core/env/except_spec.rb b/spec/ruby/core/env/except_spec.rb
index fb8f3b7536..cfe5865abe 100644
--- a/spec/ruby/core/env/except_spec.rb
+++ b/spec/ruby/core/env/except_spec.rb
@@ -1,34 +1,36 @@
require_relative 'spec_helper'
require_relative 'shared/to_hash'
-describe "ENV.except" do
- before do
- @orig_hash = ENV.to_hash
- end
+ruby_version_is "3.0" do
+ describe "ENV.except" do
+ before do
+ @orig_hash = ENV.to_hash
+ end
- after do
- ENV.replace @orig_hash
- end
+ after do
+ ENV.replace @orig_hash
+ end
- # Testing the method without arguments is covered via
- it_behaves_like :env_to_hash, :except
+ # Testing the method without arguments is covered via
+ it_behaves_like :env_to_hash, :except
- it "returns a hash without the requested subset" do
- ENV.clear
+ it "returns a hash without the requested subset" do
+ ENV.clear
- ENV['one'] = '1'
- ENV['two'] = '2'
- ENV['three'] = '3'
+ ENV['one'] = '1'
+ ENV['two'] = '2'
+ ENV['three'] = '3'
- ENV.except('one', 'three').should == { 'two' => '2' }
- end
+ ENV.except('one', 'three').should == { 'two' => '2' }
+ end
- it "ignores keys not present in the original hash" do
- ENV.clear
+ it "ignores keys not present in the original hash" do
+ ENV.clear
- ENV['one'] = '1'
- ENV['two'] = '2'
+ ENV['one'] = '1'
+ ENV['two'] = '2'
- ENV.except('one', 'three').should == { 'two' => '2' }
+ ENV.except('one', 'three').should == { 'two' => '2' }
+ end
end
end
diff --git a/spec/ruby/core/env/index_spec.rb b/spec/ruby/core/env/index_spec.rb
new file mode 100644
index 0000000000..301a66ab4e
--- /dev/null
+++ b/spec/ruby/core/env/index_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+require_relative 'shared/key'
+
+ruby_version_is ''...'3.0' do
+ describe "ENV.index" do
+ it_behaves_like :env_key, :index
+
+ it "warns about deprecation" do
+ -> do
+ ENV.index("foo")
+ end.should complain(/warning: ENV.index is deprecated; use ENV.key/)
+ end
+ end
+end
diff --git a/spec/ruby/core/env/indexes_spec.rb b/spec/ruby/core/env/indexes_spec.rb
new file mode 100644
index 0000000000..e724feaa39
--- /dev/null
+++ b/spec/ruby/core/env/indexes_spec.rb
@@ -0,0 +1 @@
+require_relative '../../spec_helper'
diff --git a/spec/ruby/core/env/indices_spec.rb b/spec/ruby/core/env/indices_spec.rb
new file mode 100644
index 0000000000..e724feaa39
--- /dev/null
+++ b/spec/ruby/core/env/indices_spec.rb
@@ -0,0 +1 @@
+require_relative '../../spec_helper'
diff --git a/spec/ruby/core/env/key_spec.rb b/spec/ruby/core/env/key_spec.rb
index cf70286409..82cfbefa39 100644
--- a/spec/ruby/core/env/key_spec.rb
+++ b/spec/ruby/core/env/key_spec.rb
@@ -1,39 +1,11 @@
require_relative '../../spec_helper'
require_relative 'shared/include'
+require_relative 'shared/key'
describe "ENV.key?" do
it_behaves_like :env_include, :key?
end
describe "ENV.key" do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "returns the index associated with the passed value" do
- ENV["foo"] = "bar"
- ENV.key("bar").should == "foo"
- end
-
- it "returns nil if the passed value is not found" do
- ENV.delete("foo")
- ENV.key("foo").should be_nil
- end
-
- it "coerces the key element with #to_str" do
- ENV["foo"] = "bar"
- k = mock('key')
- k.should_receive(:to_str).and_return("bar")
- ENV.key(k).should == "foo"
- end
-
- it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> {
- ENV.key(Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
+ it_behaves_like :env_key, :key
end
diff --git a/spec/ruby/core/env/shared/include.rb b/spec/ruby/core/env/shared/include.rb
index 70aa555301..3efcd523d6 100644
--- a/spec/ruby/core/env/shared/include.rb
+++ b/spec/ruby/core/env/shared/include.rb
@@ -17,13 +17,6 @@ describe :env_include, shared: true do
ENV.send(@method, "foo").should == false
end
- it "coerces the key with #to_str" do
- ENV["foo"] = "bar"
- k = mock('key')
- k.should_receive(:to_str).and_return("foo")
- ENV.send(@method, k).should == true
- end
-
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> { ENV.send(@method, Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/shared/key.rb b/spec/ruby/core/env/shared/key.rb
new file mode 100644
index 0000000000..93396d2aca
--- /dev/null
+++ b/spec/ruby/core/env/shared/key.rb
@@ -0,0 +1,31 @@
+describe :env_key, shared: true do
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "returns the index associated with the passed value" do
+ ENV["foo"] = "bar"
+ suppress_warning {
+ ENV.send(@method, "bar").should == "foo"
+ }
+ end
+
+ it "returns nil if the passed value is not found" do
+ ENV.delete("foo")
+ suppress_warning {
+ ENV.send(@method, "foo").should be_nil
+ }
+ end
+
+ it "raises TypeError if the argument is not a String and does not respond to #to_str" do
+ -> {
+ suppress_warning {
+ ENV.send(@method, Object.new)
+ }
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+end
diff --git a/spec/ruby/core/env/shared/value.rb b/spec/ruby/core/env/shared/value.rb
index c2b5025465..bef96b5fef 100644
--- a/spec/ruby/core/env/shared/value.rb
+++ b/spec/ruby/core/env/shared/value.rb
@@ -16,13 +16,6 @@ describe :env_value, shared: true do
ENV.send(@method, "foo").should == false
end
- it "coerces the value element with #to_str" do
- ENV["foo"] = "bar"
- v = mock('value')
- v.should_receive(:to_str).and_return("bar")
- ENV.send(@method, v).should == true
- end
-
it "returns nil if the argument is not a String and does not respond to #to_str" do
ENV.send(@method, Object.new).should == nil
end
diff --git a/spec/ruby/core/env/slice_spec.rb b/spec/ruby/core/env/slice_spec.rb
index 959239d2b2..e3b6020391 100644
--- a/spec/ruby/core/env/slice_spec.rb
+++ b/spec/ruby/core/env/slice_spec.rb
@@ -21,16 +21,6 @@ describe "ENV.slice" do
ENV.slice("foo", "boo", "bar").should == {"foo" => "0", "bar" => "1"}
end
- it "returns the values for the keys coerced with #to_str, but keeps the original objects as result keys" do
- foo = mock('key 1')
- foo.should_receive(:to_str).and_return("foo")
- boo = mock('key 2')
- boo.should_receive(:to_str).and_return("boo")
- bar = mock('key 3')
- bar.should_receive(:to_str).and_return("bar")
- ENV.slice(foo, boo, bar).should == {foo => "0", bar => "1"}
- end
-
it "raises TypeError if any argument is not a String and does not respond to #to_str" do
-> { ENV.slice(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/to_a_spec.rb b/spec/ruby/core/env/to_a_spec.rb
index 2b1649281f..39e3877b48 100644
--- a/spec/ruby/core/env/to_a_spec.rb
+++ b/spec/ruby/core/env/to_a_spec.rb
@@ -6,10 +6,7 @@ describe "ENV.to_a" do
a = ENV.to_a
a.is_a?(Array).should == true
a.size.should == ENV.size
- a.each { |k,v| ENV[k].should == v }
-
- a.first.should.is_a?(Array)
- a.first.size.should == 2
+ ENV.each_pair { |k, v| a.should include([k, v])}
end
it "returns the entries in the locale encoding" do
diff --git a/spec/ruby/core/exception/case_compare_spec.rb b/spec/ruby/core/exception/case_compare_spec.rb
index 5fd11ae741..87b9dee3ca 100644
--- a/spec/ruby/core/exception/case_compare_spec.rb
+++ b/spec/ruby/core/exception/case_compare_spec.rb
@@ -26,11 +26,13 @@ describe "SystemCallError.===" do
end
it "returns true if receiver is generic and arg is kind of SystemCallError" do
+ unknown_error_number = Errno.constants.size
e = SystemCallError.new('foo', @example_errno)
SystemCallError.===(e).should == true
end
it "returns false if receiver is generic and arg is not kind of SystemCallError" do
+ unknown_error_number = Errno.constants.size
e = Object.new
SystemCallError.===(e).should == false
end
diff --git a/spec/ruby/core/exception/detailed_message_spec.rb b/spec/ruby/core/exception/detailed_message_spec.rb
deleted file mode 100644
index fbe4443daa..0000000000
--- a/spec/ruby/core/exception/detailed_message_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-
-describe "Exception#detailed_message" do
- ruby_version_is "3.2" do
- it "returns decorated message" do
- RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
- end
-
- it "is called by #full_message to allow message customization" do
- exception = Exception.new("new error")
- def exception.detailed_message(**)
- "<prefix>#{message}<suffix>"
- end
- exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>"
- end
-
- it "accepts highlight keyword argument and adds escape control sequences" do
- RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
- end
-
- it "allows and ignores other keyword arguments" do
- RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
- end
-
- it "returns just a message if exception class is anonymous" do
- Class.new(RuntimeError).new("message").detailed_message.should == "message"
- end
-
- it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
- RuntimeError.new("").detailed_message.should == "unhandled exception"
- end
-
- it "returns just class name for an instance of RuntimeError subclass with empty message" do
- DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
- end
-
- it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
- klass = Class.new(RuntimeError)
- klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
- end
- end
-end
diff --git a/spec/ruby/core/exception/equal_value_spec.rb b/spec/ruby/core/exception/equal_value_spec.rb
index e8f3ce0f8d..7f2065511a 100644
--- a/spec/ruby/core/exception/equal_value_spec.rb
+++ b/spec/ruby/core/exception/equal_value_spec.rb
@@ -22,18 +22,18 @@ describe "Exception#==" do
it "returns true if both exceptions have the same class, the same message, and the same backtrace" do
one = TypeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
two = TypeError.new("message")
- two.set_backtrace [__dir__]
+ two.set_backtrace [File.dirname(__FILE__)]
one.should == two
end
it "returns false if the two exceptions inherit from Exception but have different classes" do
one = RuntimeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
one.should be_kind_of(Exception)
two = TypeError.new("message")
- two.set_backtrace [__dir__]
+ two.set_backtrace [File.dirname(__FILE__)]
two.should be_kind_of(Exception)
one.should_not == two
end
@@ -52,7 +52,7 @@ describe "Exception#==" do
it "returns false if the two exceptions differ only in their backtrace" do
one = RuntimeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
two = RuntimeError.new("message")
two.set_backtrace nil
one.should_not == two
@@ -60,9 +60,9 @@ describe "Exception#==" do
it "returns false if the two exceptions differ only in their message" do
one = RuntimeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
two = RuntimeError.new("message2")
- two.set_backtrace [__dir__]
+ two.set_backtrace [File.dirname(__FILE__)]
one.should_not == two
end
end
diff --git a/spec/ruby/core/exception/fixtures/common.rb b/spec/ruby/core/exception/fixtures/common.rb
index 1e243098bd..0ffb3ed855 100644
--- a/spec/ruby/core/exception/fixtures/common.rb
+++ b/spec/ruby/core/exception/fixtures/common.rb
@@ -93,7 +93,3 @@ class NameErrorSpecs
end
end
end
-
-module DetailedMessageSpec
- C = Class.new(RuntimeError)
-end
diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb
deleted file mode 100644
index c109ec6247..0000000000
--- a/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-ready = false
-t = Thread.new do
- f = Fiber.new do
- begin
- Fiber.yield
- ensure
- STDERR.puts "suspended fiber ensure"
- end
- end
- f.resume
-
- begin
- ready = true
- sleep
- ensure
- STDERR.puts "current fiber ensure"
- end
-end
-
-Thread.pass until ready && t.stop?
-
-# let the program end, it's the same as #exit or an exception for this behavior
diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb
deleted file mode 100644
index 3364ed06d0..0000000000
--- a/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-ready = false
-t = Thread.new do
- f = Fiber.new do
- begin
- Fiber.yield
- ensure
- STDERR.puts "suspended fiber ensure"
- end
- end
- f.resume
-
- f2 = Fiber.new do
- begin
- ready = true
- sleep
- ensure
- STDERR.puts "current fiber ensure"
- end
- end
- f2.resume
-end
-
-Thread.pass until ready && t.stop?
-
-# let the program end, it's the same as #exit or an exception for this behavior
diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb
index e15649ca75..9757a2f407 100644
--- a/spec/ruby/core/exception/full_message_spec.rb
+++ b/spec/ruby/core/exception/full_message_spec.rb
@@ -103,53 +103,4 @@ describe "Exception#full_message" do
exception.full_message.should include "intermediate exception"
exception.full_message.should include "origin exception"
end
-
- ruby_version_is "3.2" do
- it "relies on #detailed_message" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" }
-
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
- end
-
- it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do
- e = RuntimeError.new("new error")
- options_passed = nil
- e.define_singleton_method(:detailed_message) do |**options|
- options_passed = options
- "DETAILED MESSAGE"
- end
-
- e.full_message(foo: "bar")
- options_passed.should == { foo: "bar", highlight: Exception.to_tty? }
- end
-
- it "converts #detailed_message returned value to String if it isn't a String" do
- message = Object.new
- def message.to_str; "DETAILED MESSAGE"; end
-
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| message }
-
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
- end
-
- it "uses class name if #detailed_message returns nil" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| nil }
-
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
- end
-
- it "uses class name if exception object doesn't respond to #detailed_message" do
- e = RuntimeError.new("new error")
- class << e
- undef :detailed_message
- end
-
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
- end
- end
end
diff --git a/spec/ruby/core/exception/no_method_error_spec.rb b/spec/ruby/core/exception/no_method_error_spec.rb
index 4621e36f44..8428ba0382 100644
--- a/spec/ruby/core/exception/no_method_error_spec.rb
+++ b/spec/ruby/core/exception/no_method_error_spec.rb
@@ -62,49 +62,26 @@ describe "NoMethodError#message" do
NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method
rescue Exception => e
e.should be_kind_of(NoMethodError)
- e.message.lines[0].should =~ /private method `a_private_method' called for /
+ e.message.lines[0].should =~ /private method `a_private_method' called for #<NoMethodErrorSpecs::NoMethodErrorC:0x[\h]+>/
end
end
- ruby_version_is ""..."3.3" do
- it "calls receiver.inspect only when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- "<inspect>"
- end
- end
- instance = test_class.new
- begin
- instance.bar
- rescue Exception => e
- e.name.should == :bar
- ScratchPad.recorded.should == []
- e.message.should =~ /undefined method.+\bbar\b/
- ScratchPad.recorded.should == [:inspect_called]
+ it "calls receiver.inspect only when calling Exception#message" do
+ ScratchPad.record []
+ test_class = Class.new do
+ def inspect
+ ScratchPad << :inspect_called
+ "<inspect>"
end
end
- end
-
- ruby_version_is "3.3" do
- it "does not call receiver.inspect even when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- "<inspect>"
- end
- end
- instance = test_class.new
- begin
- instance.bar
- rescue Exception => e
- e.name.should == :bar
- ScratchPad.recorded.should == []
- e.message.should =~ /undefined method.+\bbar\b/
- ScratchPad.recorded.should == []
- end
+ instance = test_class.new
+ begin
+ instance.bar
+ rescue Exception => e
+ e.name.should == :bar
+ ScratchPad.recorded.should == []
+ e.message.should =~ /undefined method.+\bbar\b/
+ ScratchPad.recorded.should == [:inspect_called]
end
end
@@ -125,19 +102,21 @@ describe "NoMethodError#message" do
end
end
- it "uses #name to display the receiver if it is a class or a module" do
- klass = Class.new { def self.name; "MyClass"; end }
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should =~ /^undefined method `foo' for /
- end
+ ruby_version_is "3.0" do
+ it "uses #name to display the receiver if it is a class or a module" do
+ klass = Class.new { def self.name; "MyClass"; end }
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.lines.first.chomp.should == "undefined method `foo' for MyClass:Class"
+ end
- mod = Module.new { def self.name; "MyModule"; end }
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should =~ /^undefined method `foo' for /
+ mod = Module.new { def self.name; "MyModule"; end }
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.lines.first.chomp.should == "undefined method `foo' for MyModule:Module"
+ end
end
end
end
diff --git a/spec/ruby/core/exception/top_level_spec.rb b/spec/ruby/core/exception/top_level_spec.rb
index bcd09205b6..b47648425e 100644
--- a/spec/ruby/core/exception/top_level_spec.rb
+++ b/spec/ruby/core/exception/top_level_spec.rb
@@ -42,16 +42,4 @@ describe "An Exception reaching the top level" do
EOS
end
end
-
- describe "kills all threads and fibers, ensure clauses are only run for threads current fibers, not for suspended fibers" do
- it "with ensure on the root fiber" do
- file = fixture(__FILE__, "thread_fiber_ensure.rb")
- ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n"
- end
-
- it "with ensure on non-root fiber" do
- file = fixture(__FILE__, "thread_fiber_ensure_non_root_fiber.rb")
- ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n"
- end
- end
end
diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb
deleted file mode 100644
index 738794b46c..0000000000
--- a/spec/ruby/core/false/singleton_method_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "FalseClass#singleton_method" do
- ruby_version_is '3.3' do
- it "raises regardless of whether FalseClass defines the method" do
- -> { false.singleton_method(:foo) }.should raise_error(NameError)
- begin
- def (false).foo; end
- -> { false.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- FalseClass.send(:remove_method, :foo)
- end
- end
- end
-end
diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb
index ebefa116af..eeee5a71c1 100644
--- a/spec/ruby/core/fiber/blocking_spec.rb
+++ b/spec/ruby/core/fiber/blocking_spec.rb